diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index d0c89b90946b..9a2332445f69 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -181,6 +181,7 @@ void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { CheckFlag("fsverity", fs_verity); CheckFlag("metadata_csum", ext_meta_csum); CheckFlag("fscompress", fs_compress); + CheckFlag("wrappedkey", wrapped_key); #undef CheckFlag diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index f33768b9d674..0d1e935c0e41 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -86,6 +86,7 @@ struct FstabEntry { bool fs_verity : 1; bool ext_meta_csum : 1; bool fs_compress : 1; + bool wrapped_key : 1; } fs_mgr_flags = {}; bool is_encryptable() const { diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp index 1da71176c862..49333a13b2eb 100644 --- a/fs_mgr/libfs_avb/fs_avb.cpp +++ b/fs_mgr/libfs_avb/fs_avb.cpp @@ -433,16 +433,6 @@ AvbUniquePtr AvbHandle::Open() { // Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version". avb_handle->avb_version_ = StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR); - // Verifies vbmeta structs against the digest passed from bootloader in kernel cmdline. - std::unique_ptr avb_verifier = AvbVerifier::Create(); - if (!avb_verifier || !avb_verifier->VerifyVbmetaImages(avb_handle->vbmeta_images_)) { - LERROR << "Failed to verify vbmeta digest"; - if (!allow_verification_error) { - LERROR << "vbmeta digest error isn't allowed "; - return nullptr; - } - } - // Checks whether FLAGS_VERIFICATION_DISABLED is set: // - Only the top-level vbmeta struct is read. // - vbmeta struct in other partitions are NOT processed, including AVB HASH descriptor(s) @@ -453,16 +443,26 @@ AvbUniquePtr AvbHandle::Open() { bool verification_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED); - // Checks whether FLAGS_HASHTREE_DISABLED is set. - // - vbmeta struct in all partitions are still processed, just disable - // dm-verity in the user space. - bool hashtree_disabled = - ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED); - if (verification_disabled) { avb_handle->status_ = AvbHandleStatus::kVerificationDisabled; - } else if (hashtree_disabled) { - avb_handle->status_ = AvbHandleStatus::kHashtreeDisabled; + } else { + // Verifies vbmeta structs against the digest passed from bootloader in kernel cmdline. + std::unique_ptr avb_verifier = AvbVerifier::Create(); + if (!avb_verifier) { + LERROR << "Failed to create AvbVerifier"; + return nullptr; + } + if (!avb_verifier->VerifyVbmetaImages(avb_handle->vbmeta_images_)) { + LERROR << "VerifyVbmetaImages failed"; + return nullptr; + } + + // Checks whether FLAGS_HASHTREE_DISABLED is set. + bool hashtree_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags & + AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED); + if (hashtree_disabled) { + avb_handle->status_ = AvbHandleStatus::kHashtreeDisabled; + } } LINFO << "Returning avb_handle with status: " << avb_handle->status_; diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index 15882b382302..9bf5db18ed55 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -399,6 +399,7 @@ class SnapshotManager final : public ISnapshotManager { FRIEND_TEST(SnapshotTest, MergeFailureCode); FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot); FRIEND_TEST(SnapshotTest, UpdateBootControlHal); + FRIEND_TEST(SnapshotUpdateTest, AddPartition); FRIEND_TEST(SnapshotUpdateTest, DaemonTransition); FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback); FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery); diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 0e36da151949..4c94da28fcc1 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -518,6 +518,13 @@ bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name, break; } + if (mode == SnapshotStorageMode::Persistent && status.state() == SnapshotState::MERGING) { + LOG(ERROR) << "Snapshot: " << name + << " has snapshot status Merging but mode set to Persistent." + << " Changing mode to Snapshot-Merge."; + mode = SnapshotStorageMode::Merge; + } + DmTable table; table.Emplace(0, snapshot_sectors, base_device, cow_device, mode, kSnapshotChunkSize); @@ -886,6 +893,10 @@ bool SnapshotManager::QuerySnapshotStatus(const std::string& dm_name, std::strin if (target_type) { *target_type = DeviceMapper::GetTargetType(target.spec); } + if (!status->error.empty()) { + LOG(ERROR) << "Snapshot: " << dm_name << " returned error code: " << status->error; + return false; + } return true; } @@ -1456,7 +1467,7 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition, std::vector* snapuserd_argv) { LOG(INFO) << "Performing transition for snapuserd."; - // Don't use EnsuerSnapuserdConnected() because this is called from init, + // Don't use EnsureSnapuserdConnected() because this is called from init, // and attempting to do so will deadlock. if (!snapuserd_client_ && transition != InitTransition::SELINUX_DETACH) { snapuserd_client_ = SnapuserdClient::Connect(kSnapuserdSocket, 10s); @@ -1513,8 +1524,15 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition, continue; } + std::string source_device_name; + if (snapshot_status.old_partition_size() > 0) { + source_device_name = GetSourceDeviceName(snapshot); + } else { + source_device_name = GetBaseDeviceName(snapshot); + } + std::string source_device; - if (!dm.GetDmDevicePathByName(GetSourceDeviceName(snapshot), &source_device)) { + if (!dm.GetDmDevicePathByName(source_device_name, &source_device)) { LOG(ERROR) << "Could not get device path for " << GetSourceDeviceName(snapshot); continue; } @@ -2091,14 +2109,18 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock, if (live_snapshot_status->compression_enabled()) { // Get the source device (eg the view of the partition from before it was resized). std::string source_device_path; - if (!MapSourceDevice(lock, params.GetPartitionName(), remaining_time, - &source_device_path)) { - LOG(ERROR) << "Could not map source device for: " << cow_name; - return false; - } + if (live_snapshot_status->old_partition_size() > 0) { + if (!MapSourceDevice(lock, params.GetPartitionName(), remaining_time, + &source_device_path)) { + LOG(ERROR) << "Could not map source device for: " << cow_name; + return false; + } - auto source_device = GetSourceDeviceName(params.GetPartitionName()); - created_devices.EmplaceBack(&dm, source_device); + auto source_device = GetSourceDeviceName(params.GetPartitionName()); + created_devices.EmplaceBack(&dm, source_device); + } else { + source_device_path = base_path; + } if (!WaitForDevice(source_device_path, remaining_time)) { return false; diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 60186434ae46..7630efe3f8ad 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -963,7 +963,7 @@ class SnapshotUpdateTest : public SnapshotTest { } AssertionResult UnmapAll() { - for (const auto& name : {"sys", "vnd", "prd"}) { + for (const auto& name : {"sys", "vnd", "prd", "dlkm"}) { if (!dm_.DeleteDeviceIfExists(name + "_a"s)) { return AssertionFailure() << "Cannot unmap " << name << "_a"; } @@ -2026,6 +2026,80 @@ TEST_F(SnapshotUpdateTest, LowSpace) { ASSERT_LT(res.required_size(), 40_MiB); } +TEST_F(SnapshotUpdateTest, AddPartition) { + // OTA client blindly unmaps all partitions that are possibly mapped. + for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) { + ASSERT_TRUE(sm->UnmapUpdateSnapshot(name)); + } + + group_->add_partition_names("dlkm"); + + auto dlkm = manifest_.add_partitions(); + dlkm->set_partition_name("dlkm"); + dlkm->set_estimate_cow_size(2_MiB); + SetSize(dlkm, 3_MiB); + + // Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs + // fit in super, but not |prd|. + constexpr uint64_t partition_size = 3788_KiB; + SetSize(sys_, partition_size); + SetSize(vnd_, partition_size); + SetSize(prd_, partition_size); + SetSize(dlkm, partition_size); + + AddOperationForPartitions({sys_, vnd_, prd_, dlkm}); + + // Execute the update. + ASSERT_TRUE(sm->BeginUpdate()); + ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_)); + + // Write some data to target partitions. + for (const auto& name : {"sys_b", "vnd_b", "prd_b", "dlkm_b"}) { + ASSERT_TRUE(WriteSnapshotAndHash(name)); + } + + // Assert that source partitions aren't affected. + for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) { + ASSERT_TRUE(IsPartitionUnchanged(name)); + } + + ASSERT_TRUE(sm->FinishedSnapshotWrites(false)); + + // Simulate shutting down the device. + ASSERT_TRUE(UnmapAll()); + + // After reboot, init does first stage mount. + auto init = NewManagerForFirstStageMount("_b"); + ASSERT_NE(init, nullptr); + + ASSERT_TRUE(init->EnsureSnapuserdConnected()); + init->set_use_first_stage_snapuserd(true); + + ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount()); + ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_)); + + // Check that the target partitions have the same content. + std::vector partitions = {"sys_b", "vnd_b", "prd_b", "dlkm_b"}; + for (const auto& name : partitions) { + ASSERT_TRUE(IsPartitionUnchanged(name)); + } + + ASSERT_TRUE(init->PerformInitTransition(SnapshotManager::InitTransition::SECOND_STAGE)); + for (const auto& name : partitions) { + ASSERT_TRUE(init->snapuserd_client()->WaitForDeviceDelete(name + "-user-cow-init")); + } + + // Initiate the merge and wait for it to be completed. + ASSERT_TRUE(init->InitiateMerge()); + ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState()); + + // Check that the target partitions have the same content after the merge. + for (const auto& name : {"sys_b", "vnd_b", "prd_b", "dlkm_b"}) { + ASSERT_TRUE(IsPartitionUnchanged(name)) + << "Content of " << name << " changes after the merge"; + } +} + class AutoKill final { public: explicit AutoKill(pid_t pid) : pid_(pid) {} diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index 377acb75e48e..b4b853507618 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -190,12 +190,14 @@ BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String {"USB", ANDROID_POWER_SUPPLY_TYPE_USB}, {"USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC}, {"USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC}, + {"USB_HVDCP_3", ANDROID_POWER_SUPPLY_TYPE_AC}, {"USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC}, {"USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC}, {"USB_C", ANDROID_POWER_SUPPLY_TYPE_AC}, {"USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC}, {"USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB}, {"Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS}, + {"DASH", ANDROID_POWER_SUPPLY_TYPE_AC}, {NULL, 0}, }; std::string buf; @@ -204,10 +206,8 @@ BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN; auto ret = mapSysfsString(buf.c_str(), supplyTypeMap); - if (!ret) { - KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str()); + if (!ret) *ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN; - } return static_cast(*ret); } @@ -301,6 +301,40 @@ void BatteryMonitor::updateValues(void) { double MaxPower = 0; + // Rescan for the available charger types + std::unique_ptr dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir); + if (dir == NULL) { + KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH); + } else { + struct dirent* entry; + String8 path; + + mChargerNames.clear(); + + while ((entry = readdir(dir.get()))) { + const char* name = entry->d_name; + + if (!strcmp(name, ".") || !strcmp(name, "..")) + continue; + + // Look for "type" file in each subdirectory + path.clear(); + path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name); + switch(BatteryMonitor::readPowerSupplyType(path)) { + case ANDROID_POWER_SUPPLY_TYPE_AC: + case ANDROID_POWER_SUPPLY_TYPE_USB: + case ANDROID_POWER_SUPPLY_TYPE_WIRELESS: + path.clear(); + path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); + if (access(path.string(), R_OK) == 0) + mChargerNames.add(String8(name)); + break; + default: + break; + } + } + } + for (size_t i = 0; i < mChargerNames.size(); i++) { String8 path; path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, diff --git a/init/Android.bp b/init/Android.bp index 7eeafa24b8b0..69f8815ed80d 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -89,6 +89,14 @@ init_host_sources = [ "host_init_verifier.cpp", ] +cc_library_static { + name: "vendor_init", + recovery_available: true, + srcs: [ + "vendor_init.cpp", + ], +} + cc_defaults { name: "init_defaults", sanitize: { @@ -182,6 +190,7 @@ cc_library_static { defaults: [ "init_defaults", "selinux_policy_version", + "vendor_init_defaults", ], srcs: init_common_sources + init_device_sources, generated_sources: [ diff --git a/init/NOTICE b/init/NOTICE index c5b1efa7aac7..383d0f5418a6 100644 --- a/init/NOTICE +++ b/init/NOTICE @@ -188,3 +188,29 @@ END OF TERMS AND CONDITIONS +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/init/property_service.cpp b/init/property_service.cpp index 2d67bf5d7722..40ba4e16f03b 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -73,6 +73,7 @@ #include "subcontext.h" #include "system/core/init/property_service.pb.h" #include "util.h" +#include "vendor_init.h" using namespace std::literals; @@ -117,6 +118,8 @@ struct PropertyAuditData { const char* name; }; +static bool weaken_prop_override_security = false; + static int PropertyAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) { auto* d = reinterpret_cast(data); @@ -187,8 +190,8 @@ static uint32_t PropertySet(const std::string& name, const std::string& value, s prop_info* pi = (prop_info*) __system_property_find(name.c_str()); if (pi != nullptr) { - // ro.* properties are actually "write-once". - if (StartsWith(name, "ro.")) { + // ro.* properties are actually "write-once", unless the system decides to + if (StartsWith(name, "ro.") && !weaken_prop_override_security) { *error = "Read-only property was already set"; return PROP_ERROR_READ_ONLY_PROPERTY; } @@ -794,6 +797,84 @@ static void load_override_properties() { } } +static const char *snet_prop_key[] = { + "ro.boot.vbmeta.device_state", + "ro.boot.verifiedbootstate", + "ro.boot.flash.locked", + "ro.boot.selinux", + "ro.boot.veritymode", + "ro.boot.warranty_bit", + "ro.warranty_bit", + "ro.debuggable", + "ro.secure", + "ro.build.type", + "ro.system.build.type", + "ro.system_ext.build.type", + "ro.vendor.build.type", + "ro.product.build.type", + "ro.odm.build.type", + "ro.build.keys", + "ro.build.tags", + "ro.system.build.tags", + "ro.vendor.boot.warranty_bit", + "ro.vendor.warranty_bit", + "vendor.boot.vbmeta.device_state", + "vendor.boot.verifiedbootstate", + NULL +}; + +static const char *snet_prop_value[] = { + "locked", // ro.boot.vbmeta.device_state + "green", // ro.boot.verifiedbootstate + "1", // ro.boot.flash.locked + "enforcing", // ro.boot.selinux + "enforcing", // ro.boot.veritymode + "0", // ro.boot.warranty_bit + "0", // ro.warranty_bit + "0", // ro.debuggable + "1", // ro.secure + "user", // ro.build.type + "user", // ro.system.build.type + "user", // ro.system_ext.build.type + "user", // ro.vendor.build.type + "user", // ro.product.build.type + "user", // ro.odm.build.type + "release-keys", // ro.build.keys + "release-keys", // ro.build.tags + "release-keys", // ro.system.build.tags + "0", // ro.vendor.boot.warranty_bit + "0", // ro.vendor.warranty_bit + "locked", // vendor.boot.vbmeta.device_state + "green", // vendor.boot.verifiedbootstate + NULL +}; + +static void workaround_snet_properties() { + std::string build_type = android::base::GetProperty("ro.build.type", ""); + + // Weaken property override security to set safetynet props + weaken_prop_override_security = true; + + std::string error; + + // Hide all sensitive props if not eng build + if (build_type != "eng") { + LOG(INFO) << "snet: Hiding sensitive props"; + for (int i = 0; snet_prop_key[i]; ++i) { + PropertySet(snet_prop_key[i], snet_prop_value[i], &error); + } + } + + // Extra pops + std::string build_flavor_key = "ro.build.flavor"; + std::string build_flavor_value = android::base::GetProperty(build_flavor_key, ""); + build_flavor_value = android::base::StringReplace(build_flavor_value, "userdebug", "user", false); + PropertySet(build_flavor_key, build_flavor_value, &error); + + // Restore the normal property override security after safetynet props have been set + weaken_prop_override_security = false; +} + // If the ro.product.[brand|device|manufacturer|model|name] properties have not been explicitly // set, derive them from ro.product.${partition}.* properties static void property_initialize_ro_product_props() { @@ -1097,6 +1178,9 @@ void PropertyLoadBootDefaults() { } } + // Update with vendor-specific property runtime overrides + vendor_load_properties(); + property_initialize_ro_product_props(); property_initialize_build_id(); property_derive_build_fingerprint(); @@ -1104,6 +1188,11 @@ void PropertyLoadBootDefaults() { property_initialize_ro_cpu_abilist(); update_sys_usb_config(); + + // Workaround SafetyNet + if (!IsRecoveryMode()) { + workaround_snet_properties(); + } } bool LoadPropertyInfoFromFile(const std::string& filename, diff --git a/init/service.cpp b/init/service.cpp index c3069f5b2b59..8c8aebd94d07 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -88,13 +88,16 @@ static Result ComputeContextFromExecutable(const std::string& servi free(new_con); } if (rc == 0 && computed_context == mycon.get()) { - return Error() << "File " << service_path << "(labeled \"" << filecon.get() - << "\") has incorrect label or no domain transition from " << mycon.get() - << " to another SELinux domain defined. Have you configured your " - "service correctly? https://source.android.com/security/selinux/" - "device-policy#label_new_services_and_address_denials. Note: this " - "error shows up even in permissive mode in order to make auditing " - "denials possible."; + std::string error = StringPrintf( + "File %s (labeled \"%s\") has incorrect label or no domain transition from %s to " + "another SELinux domain defined. Have you configured your " + "service correctly? https://source.android.com/security/selinux/" + "device-policy#label_new_services_and_address_denials", + service_path.c_str(), filecon.get(), mycon.get()); + if (selinux_status_getenforce() > 0) { + return Error() << error; + } + LOG(ERROR) << error; } if (rc < 0) { return Error() << "Could not get process context"; diff --git a/init/vendor_init.cpp b/init/vendor_init.cpp new file mode 100644 index 000000000000..d3fd5ffe2be9 --- /dev/null +++ b/init/vendor_init.cpp @@ -0,0 +1,37 @@ +/* +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "vendor_init.h" + +/* init vendor override stubs */ + +__attribute__ ((weak)) +void vendor_load_properties() +{ +} diff --git a/init/vendor_init.h b/init/vendor_init.h new file mode 100644 index 000000000000..9afb449be013 --- /dev/null +++ b/init/vendor_init.h @@ -0,0 +1,33 @@ +/* +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __INIT_VENDOR__H__ +#define __INIT_VENDOR__H__ +extern void vendor_load_properties(void); +#endif /* __INIT_VENDOR__H__ */