diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-01-10 00:27:28 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-01-10 00:27:28 +0000 |
commit | 21056d928eee3f91db5c019e47cc35850fa7a892 (patch) | |
tree | bdbf69cf21cd64d60215785023da955942ba3a74 | |
parent | 24ef68efb15ccb4cc0ddc86de2f3bb4ff37011d2 (diff) | |
parent | d2c816eb179071a39247c6fdcf3e4de278f9231b (diff) | |
download | apex-android13-qpr3-s4-release.tar.gz |
Snap for 9470583 from d2c816eb179071a39247c6fdcf3e4de278f9231b to tm-qpr3-releaseandroid-13.0.0_r83android-13.0.0_r79android-13.0.0_r78android-13.0.0_r77android-13.0.0_r76android-13.0.0_r75android-13.0.0_r71android-13.0.0_r70android-13.0.0_r69android-13.0.0_r68android-13.0.0_r67android-13.0.0_r63android-13.0.0_r62android-13.0.0_r61android-13.0.0_r56android-13.0.0_r54android-13.0.0_r53android-13.0.0_r52android-13.0.0_r51android-13.0.0_r50android13-qpr3-s9-releaseandroid13-qpr3-s8-releaseandroid13-qpr3-s7-releaseandroid13-qpr3-s6-releaseandroid13-qpr3-s5-releaseandroid13-qpr3-s4-releaseandroid13-qpr3-s3-releaseandroid13-qpr3-s2-releaseandroid13-qpr3-s14-releaseandroid13-qpr3-s13-releaseandroid13-qpr3-s12-releaseandroid13-qpr3-s11-releaseandroid13-qpr3-s10-releaseandroid13-qpr3-s1-releaseandroid13-qpr3-release
Change-Id: Ic633d825bf4a07c9ae849e72bbaeb8fac359e6de
-rw-r--r-- | apexd/Android.bp | 18 | ||||
-rw-r--r-- | apexd/apex_file_repository.cpp | 23 | ||||
-rw-r--r-- | apexd/apex_file_repository.h | 10 | ||||
-rw-r--r-- | apexd/apex_file_repository_test.cpp | 7 | ||||
-rw-r--r-- | apexd/apexd.cpp | 14 | ||||
-rw-r--r-- | apexd/apexd_loop.cpp | 6 | ||||
-rw-r--r-- | apexd/apexd_loop.h | 4 | ||||
-rw-r--r-- | apexd/apexd_test.cpp | 112 | ||||
-rw-r--r-- | shim/build/Android.bp | 36 | ||||
-rw-r--r-- | shim/build/AndroidManifestInstallConstraints_empty.xml | 8 | ||||
-rw-r--r-- | shim/build/AndroidManifestInstallConstraints_invalid_fingerprint.xml | 9 | ||||
-rw-r--r-- | shim/build/AndroidManifestInstallConstraints_no_value.xml | 15 |
12 files changed, 223 insertions, 39 deletions
diff --git a/apexd/Android.bp b/apexd/Android.bp index ce5d170b..bf4bce34 100644 --- a/apexd/Android.bp +++ b/apexd/Android.bp @@ -73,8 +73,19 @@ cc_defaults { ], } +soong_config_module_type { + name: "apexd_cc_defaults", + module_type: "cc_defaults", + config_namespace: "ANDROID", + bool_variables: [ + "target_board_auto", + ], + properties: [ + "cppflags", + ], +} -cc_defaults { +apexd_cc_defaults { name: "libapexd-deps", defaults: ["libapex-deps"], shared_libs: [ @@ -93,6 +104,11 @@ cc_defaults { "libxml2", ], whole_static_libs: ["com.android.sysprop.apex"], + soong_config_variables: { + target_board_auto: { + cppflags: ["-DDISABLE_LOOP_IO_CONFIG"], + }, + }, } aidl_interface { diff --git a/apexd/apex_file_repository.cpp b/apexd/apex_file_repository.cpp index e82feb4c..834eef53 100644 --- a/apexd/apex_file_repository.cpp +++ b/apexd/apex_file_repository.cpp @@ -279,20 +279,17 @@ Result<int> ApexFileRepository::AddBlockApex( if (overrides.last_update_seconds.has_value() || overrides.block_apex_root_digest.has_value()) { - block_apex_overrides_.emplace(name, std::move(overrides)); + block_apex_overrides_.emplace(apex_path, std::move(overrides)); } - // APEX should be unique. - for (const auto* store : {&pre_installed_store_, &data_store_}) { - auto it = store->find(name); - if (it != store->end()) { - return Error() << "duplicate of " << name << " found in " - << it->second.GetPath(); - } - } // Depending on whether the APEX was a factory version in the host or not, // put it to different stores. auto& store = apex_config.is_factory() ? pre_installed_store_ : data_store_; + // We want "uniqueness" in each store. + if (auto it = store.find(name); it != store.end()) { + return Error() << "duplicate of " << name << " found in " + << it->second.GetPath(); + } store.emplace(name, std::move(*apex_file)); ret++; @@ -415,8 +412,8 @@ Result<const std::string> ApexFileRepository::GetDataPath( } std::optional<std::string> ApexFileRepository::GetBlockApexRootDigest( - const std::string& name) const { - auto it = block_apex_overrides_.find(name); + const std::string& path) const { + auto it = block_apex_overrides_.find(path); if (it == block_apex_overrides_.end()) { return std::nullopt; } @@ -424,8 +421,8 @@ std::optional<std::string> ApexFileRepository::GetBlockApexRootDigest( } std::optional<int64_t> ApexFileRepository::GetBlockApexLastUpdateSeconds( - const std::string& name) const { - auto it = block_apex_overrides_.find(name); + const std::string& path) const { + auto it = block_apex_overrides_.find(path); if (it == block_apex_overrides_.end()) { return std::nullopt; } diff --git a/apexd/apex_file_repository.h b/apexd/apex_file_repository.h index 1a1cf946..f90dcbc7 100644 --- a/apexd/apex_file_repository.h +++ b/apexd/apex_file_repository.h @@ -104,13 +104,13 @@ class ApexFileRepository final { android::base::Result<const std::string> GetDataPath( const std::string& name) const; - // Returns root digest of an apex with the given |name| for block apexes. + // Returns root digest of an apex with the given |path| for block apexes. std::optional<std::string> GetBlockApexRootDigest( - const std::string& name) const; + const std::string& path) const; - // Returns timestamp to be used for the block apex of the given |name|. + // Returns timestamp to be used for the block apex of the given |path|. std::optional<int64_t> GetBlockApexLastUpdateSeconds( - const std::string& name) const; + const std::string& path) const; // Checks whether there is a pre-installed version of an apex with the given // |name|. @@ -203,6 +203,8 @@ class ApexFileRepository final { std::optional<int64_t> last_update_seconds; }; + // Use "path" as key instead of APEX name because there can be multiple + // versions of sharedlibs APEXes. std::unordered_map<std::string, BlockApexOverride> block_apex_overrides_; }; diff --git a/apexd/apex_file_repository_test.cpp b/apexd/apex_file_repository_test.cpp index bf730923..272979f4 100644 --- a/apexd/apex_file_repository_test.cpp +++ b/apexd/apex_file_repository_test.cpp @@ -740,8 +740,7 @@ TEST_F(ApexFileRepositoryTestAddBlockApex, GetBlockApexRootDigest) { auto status = instance.AddBlockApex(metadata_partition_path); ASSERT_TRUE(IsOk(status)); - ASSERT_EQ(hex_root_digest, - instance.GetBlockApexRootDigest("com.android.apex.test_package")); + ASSERT_EQ(hex_root_digest, instance.GetBlockApexRootDigest(apex_foo_path)); } TEST_F(ApexFileRepositoryTestAddBlockApex, GetBlockApexLastUpdateSeconds) { @@ -767,8 +766,8 @@ TEST_F(ApexFileRepositoryTestAddBlockApex, GetBlockApexLastUpdateSeconds) { auto status = instance.AddBlockApex(metadata_partition_path); ASSERT_TRUE(IsOk(status)); - ASSERT_EQ(last_update_seconds, instance.GetBlockApexLastUpdateSeconds( - "com.android.apex.test_package")); + ASSERT_EQ(last_update_seconds, + instance.GetBlockApexLastUpdateSeconds(apex_foo_path)); } TEST_F(ApexFileRepositoryTestAddBlockApex, VerifyPublicKeyWhenAddingBlockApex) { diff --git a/apexd/apexd.cpp b/apexd/apexd.cpp index ff60ed72..5cf19ad7 100644 --- a/apexd/apexd.cpp +++ b/apexd/apexd.cpp @@ -538,8 +538,7 @@ Result<MountedApexData> MountPackageImpl(const ApexFile& apex, << ": " << verity_data.error(); } if (instance.IsBlockApex(apex)) { - auto root_digest = - instance.GetBlockApexRootDigest(apex.GetManifest().name()); + auto root_digest = instance.GetBlockApexRootDigest(apex.GetPath()); if (root_digest.has_value() && root_digest.value() != verity_data->root_digest) { return Error() << "Failed to verify Apex Verity data for " << full_path @@ -1232,6 +1231,15 @@ Result<void> ResumeRevertIfNeeded() { } Result<void> ActivateSharedLibsPackage(const std::string& mount_point) { + // Having static mutex here is not great, but since this function is called + // only twice during boot we can probably live with that. In U+ we will have + // a proper solution implemented. + static std::mutex mtx; + // ActivateSharedLibsPackage can be called concurrently from multiple threads. + // Since this function mutates the shared state in /apex/sharedlibs hold the + // mutex to avoid potential race conditions. + std::lock_guard guard(mtx); + for (const auto& lib_path : {"lib", "lib64"}) { std::string apex_lib_path = mount_point + "/" + lib_path; auto lib_dir = PathExists(apex_lib_path); @@ -3429,7 +3437,7 @@ void CollectApexInfoList(std::ostream& os, } std::optional<int64_t> mtime = - instance.GetBlockApexLastUpdateSeconds(apex.GetManifest().name()); + instance.GetBlockApexLastUpdateSeconds(apex.GetPath()); if (!mtime.has_value()) { struct stat stat_buf; if (stat(apex.GetPath().c_str(), &stat_buf) == 0) { diff --git a/apexd/apexd_loop.cpp b/apexd/apexd_loop.cpp index 36521b05..2f8d8f28 100644 --- a/apexd/apexd_loop.cpp +++ b/apexd/apexd_loop.cpp @@ -158,7 +158,7 @@ static std::string BlockdevName(dev_t dev) { // /dev/block/dm-9 (system-verity; dm-verity) // -> /dev/block/dm-1 (system_b; dm-linear) // -> /dev/sda26 -static Result<uint32_t> BlockDeviceQueueDepth(const std::string& file_path) { +Result<uint32_t> BlockDeviceQueueDepth(const std::string& file_path) { struct stat statbuf; int res = stat(file_path.c_str(), &statbuf); if (res < 0) { @@ -511,6 +511,9 @@ Result<LoopbackDeviceUniqueFd> CreateAndConfigureLoopDevice( return loop_device.error(); } + // We skip confiruing scheduler and queue depth for automotive products. + // See: b/241473698. +#ifndef DISABLE_LOOP_IO_CONFIG Result<void> sched_status = ConfigureScheduler(loop_device->name); if (!sched_status.ok()) { LOG(WARNING) << "Configuring I/O scheduler failed: " @@ -521,6 +524,7 @@ Result<LoopbackDeviceUniqueFd> CreateAndConfigureLoopDevice( if (!qd_status.ok()) { LOG(WARNING) << qd_status.error(); } +#endif Result<void> read_ahead_status = ConfigureReadAhead(loop_device->name); if (!read_ahead_status.ok()) { diff --git a/apexd/apexd_loop.h b/apexd/apexd_loop.h index 3c356d94..330eff3c 100644 --- a/apexd/apexd_loop.h +++ b/apexd/apexd_loop.h @@ -55,6 +55,10 @@ struct LoopbackDeviceUniqueFd { int Get() { return device_fd.get(); } }; +// Exposed only for testing +android::base::Result<uint32_t> BlockDeviceQueueDepth( + const std::string& file_path); + android::base::Result<LoopbackDeviceUniqueFd> WaitForDevice(int num); android::base::Result<void> ConfigureQueueDepth( diff --git a/apexd/apexd_test.cpp b/apexd/apexd_test.cpp index cc6d0721..732e23fb 100644 --- a/apexd/apexd_test.cpp +++ b/apexd/apexd_test.cpp @@ -17,6 +17,7 @@ #include "apexd.h" #include <android-base/file.h> +#include <android-base/parseint.h> #include <android-base/properties.h> #include <android-base/result-gmock.h> #include <android-base/scopeguard.h> @@ -54,10 +55,12 @@ namespace fs = std::filesystem; using MountedApexData = MountedApexDatabase::MountedApexData; using android::apex::testing::ApexFileEq; +using android::base::Basename; using android::base::GetExecutableDirectory; using android::base::GetProperty; using android::base::Join; using android::base::make_scope_guard; +using android::base::ParseUint; using android::base::ReadFileToString; using android::base::ReadFully; using android::base::RemoveFileIfExists; @@ -211,10 +214,11 @@ class ApexdUnitTest : public ::testing::Test { std::string AddBlockApex(const std::string& apex_name, const std::string& public_key = "", - const std::string& root_digest = "") { - auto apex_path = vm_payload_disk_ + "2"; // second partition + const std::string& root_digest = "", + bool is_factory = true) { + auto apex_path = vm_payload_disk_ + std::to_string(block_device_index_++); auto apex_file = GetTestFile(apex_name); - WriteMetadata(apex_file, public_key, root_digest); + AddToMetadata(apex_name, public_key, root_digest, is_factory); // loop_devices_ will be disposed after each test loop_devices_.push_back(*WriteBlockApex(apex_file, apex_path)); return apex_path; @@ -267,24 +271,23 @@ class ApexdUnitTest : public ::testing::Test { DeleteDirContent(ApexSession::GetSessionsDir()); } - void WriteMetadata(const std::string& apex_file, + void AddToMetadata(const std::string& apex_name, const std::string& public_key, - const std::string& root_digest) { + const std::string& root_digest, bool is_factory) { android::microdroid::Metadata metadata; + // The first partition is metadata partition + auto metadata_partition = vm_payload_disk_ + "1"; + if (access(metadata_partition.c_str(), F_OK) == 0) { + metadata = *android::microdroid::ReadMetadata(metadata_partition); + } auto apex = metadata.add_apexes(); - apex->set_name("apex"); + apex->set_name(apex_name); apex->set_public_key(public_key); apex->set_root_digest(root_digest); - // In this test, block apeses are assumed as "factory". - // ApexFileRepositoryTestAddBlockApex tests non-factory cases. - apex->set_is_factory(true); + apex->set_is_factory(is_factory); - // The first partition is metadata partition - auto metadata_partition = vm_payload_disk_ + "1"; - LOG(INFO) << "Writing metadata to " << metadata_partition; std::ofstream out(metadata_partition); - android::microdroid::WriteMetadata(metadata, out); } @@ -306,6 +309,7 @@ class ApexdUnitTest : public ::testing::Test { std::string metadata_sepolicy_staged_dir_; ApexdConfig config_; std::vector<loop::LoopbackDeviceUniqueFd> loop_devices_; // to be cleaned up + int block_device_index_ = 2; // "1" is reserved for metadata; }; // Apex that does not have pre-installed version, does not get selected @@ -4058,6 +4062,57 @@ TEST_F(ApexdMountTest, OnStartInVmModeFailsWithDuplicateNames) { ASSERT_EQ(1, OnStartInVmMode()); } +TEST_F(ApexdMountTest, OnStartInVmSupportsMultipleSharedLibsApexes) { + MockCheckpointInterface checkpoint_interface; + InitializeVold(&checkpoint_interface); + SetBlockApexEnabled(true); + + auto path1 = + AddBlockApex("apex.apexd_test.apex", + /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/true); + auto path2 = + AddBlockApex("apex.apexd_test_v2.apex", + /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/false); + + ASSERT_EQ(0, OnStartInVmMode()); + UnmountOnTearDown(path1); + UnmountOnTearDown(path2); +} + +TEST_F(ApexdMountTest, OnStartInVmShouldRejectInDuplicateFactoryApexes) { + MockCheckpointInterface checkpoint_interface; + InitializeVold(&checkpoint_interface); + SetBlockApexEnabled(true); + + auto path1 = + AddBlockApex("apex.apexd_test.apex", + /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/true); + auto path2 = + AddBlockApex("apex.apexd_test_v2.apex", + /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/true); + + ASSERT_EQ(1, OnStartInVmMode()); + UnmountOnTearDown(path1); + UnmountOnTearDown(path2); +} + +TEST_F(ApexdMountTest, OnStartInVmShouldRejectInDuplicateNonFactoryApexes) { + MockCheckpointInterface checkpoint_interface; + InitializeVold(&checkpoint_interface); + SetBlockApexEnabled(true); + + auto path1 = + AddBlockApex("apex.apexd_test.apex", + /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/false); + auto path2 = + AddBlockApex("apex.apexd_test_v2.apex", + /*public_key=*/"", /*root_digest=*/"", /*is_factory=*/false); + + ASSERT_EQ(1, OnStartInVmMode()); + UnmountOnTearDown(path1); + UnmountOnTearDown(path2); +} + TEST_F(ApexdMountTest, OnStartInVmModeFailsWithWrongPubkey) { MockCheckpointInterface checkpoint_interface; // Need to call InitializeVold before calling OnStart @@ -4859,5 +4914,36 @@ TEST_F(ApexdMountTest, FailsToActivateApexFallbacksToSystemOne) { ASSERT_TRUE(IsActiveApexChanged(*apex_file)); } +TEST_F(ApexdMountTest, LoopIoConfig) { + std::string file_path = AddPreInstalledApex("apex.apexd_test_nocode.apex"); + ApexFileRepository::GetInstance().AddPreInstalledApex({GetBuiltInDir()}); + + ASSERT_THAT(ActivatePackage(file_path), Ok()); + UnmountOnTearDown(file_path); + + std::optional<std::string> loop_device; + auto& db = GetApexDatabaseForTesting(); + // Check that upgraded APEX is mounted on top of dm-verity device. + db.ForallMountedApexes("com.android.apex.test_package", + [&](const MountedApexData& data, bool /*latest*/) { + loop_device.emplace(data.loop_name); + }); + + ASSERT_TRUE(loop_device.has_value()); + const std::string sysfs_path = StringPrintf("/sys/block/%s/queue/nr_requests", + (Basename(*loop_device)).c_str()); + std::string actual_str; + ASSERT_TRUE(ReadFileToString(sysfs_path, &actual_str)) + << "Failed to read " << sysfs_path; + actual_str = android::base::Trim(actual_str); + uint32_t actual = 0; + ASSERT_TRUE(ParseUint(actual_str.c_str(), &actual)) + << "Failed to parse " << actual_str; + + auto expected = loop::BlockDeviceQueueDepth("/data"); + ASSERT_THAT(expected, Ok()); + ASSERT_EQ(*expected, actual); +} + } // namespace apex } // namespace android diff --git a/shim/build/Android.bp b/shim/build/Android.bp index 99121d21..801899e4 100644 --- a/shim/build/Android.bp +++ b/shim/build/Android.bp @@ -267,6 +267,9 @@ genrule { ":com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p", ":com.android.apex.cts.shim.v2_apk_in_apex_upgrades", ":com.android.apex.cts.shim.v2_rebootless", + ":com.android.apex.cts.shim.v2_install_constraints_empty", + ":com.android.apex.cts.shim.v2_install_constraints_invalid_fingerprint", + ":com.android.apex.cts.shim.v2_install_constraints_no_value", ":com.android.apex.cts.shim.v3", ":com.android.apex.cts.shim.v3_rebootless", ":com.android.apex.cts.shim.v3_signed_bob", @@ -596,3 +599,36 @@ apex { installable: false, updatable: false, } + +apex { + name: "com.android.apex.cts.shim.v2_install_constraints_empty", + manifest: "manifest_v2.json", + androidManifest: "AndroidManifestInstallConstraints_empty.xml", + file_contexts: ":apex.test-file_contexts", + key: "com.android.apex.cts.shim.key", + prebuilts: ["hash_of_dev_null"], + installable: false, + updatable: false, +} + +apex { + name: "com.android.apex.cts.shim.v2_install_constraints_invalid_fingerprint", + manifest: "manifest_v2.json", + androidManifest: "AndroidManifestInstallConstraints_invalid_fingerprint.xml", + file_contexts: ":apex.test-file_contexts", + key: "com.android.apex.cts.shim.key", + prebuilts: ["hash_of_dev_null"], + installable: false, + updatable: false, +} + +apex { + name: "com.android.apex.cts.shim.v2_install_constraints_no_value", + manifest: "manifest_v2.json", + androidManifest: "AndroidManifestInstallConstraints_no_value.xml", + file_contexts: ":apex.test-file_contexts", + key: "com.android.apex.cts.shim.key", + prebuilts: ["hash_of_dev_null"], + installable: false, + updatable: false, +} diff --git a/shim/build/AndroidManifestInstallConstraints_empty.xml b/shim/build/AndroidManifestInstallConstraints_empty.xml new file mode 100644 index 00000000..9c04d748 --- /dev/null +++ b/shim/build/AndroidManifestInstallConstraints_empty.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.apex.cts.shim"> + <!-- APEX does not have classes.dex --> + <application android:hasCode="false"/> + <install-constraints> + </install-constraints> +</manifest> diff --git a/shim/build/AndroidManifestInstallConstraints_invalid_fingerprint.xml b/shim/build/AndroidManifestInstallConstraints_invalid_fingerprint.xml new file mode 100644 index 00000000..c0cda96f --- /dev/null +++ b/shim/build/AndroidManifestInstallConstraints_invalid_fingerprint.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.apex.cts.shim"> + <!-- APEX does not have classes.dex --> + <application android:hasCode="false"/> + <install-constraints> + <fingerprint-prefix android:value="does/not/exist"/> + </install-constraints> +</manifest> diff --git a/shim/build/AndroidManifestInstallConstraints_no_value.xml b/shim/build/AndroidManifestInstallConstraints_no_value.xml new file mode 100644 index 00000000..e2e6bc84 --- /dev/null +++ b/shim/build/AndroidManifestInstallConstraints_no_value.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.apex.cts.shim"> + <!-- APEX does not have classes.dex --> + <application android:hasCode="false"/> + <install-constraints> + <!-- PackageManager will allow installation if at least one of the fingerprint-prefixes + matches the build fingerprint of a device. + Since one of them is an empty string, the apex with these constraints can be installed + on all devices as long as the packagename is allowlisted by the system. + --> + <fingerprint-prefix android:value="does/not/exist"/> + <fingerprint-prefix android:value=""/> + </install-constraints> +</manifest> |