Merge tag 'android-13.0.0_r32' into int/13/fp3
Android 13.0.0 release 32
* tag 'android-13.0.0_r32':
Use block apex path as key for rootdigest overrides
AddBlockApex checks uniqueness for "factory" apexes
Don't configure queue depth & IO scheduler for auto products
Change-Id: Ia0b8a2c934eb744cfcf3314d2cf097024513f495
diff --git a/apexd/Android.bp b/apexd/Android.bp
index ce5d170..bf4bce3 100644
--- a/apexd/Android.bp
+++ b/apexd/Android.bp
@@ -73,8 +73,19 @@
],
}
+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 @@
"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 e82feb4..834eef5 100644
--- a/apexd/apex_file_repository.cpp
+++ b/apexd/apex_file_repository.cpp
@@ -279,20 +279,17 @@
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 @@
}
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<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 1a1cf94..f90dcbc 100644
--- a/apexd/apex_file_repository.h
+++ b/apexd/apex_file_repository.h
@@ -104,13 +104,13 @@
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 @@
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 bf73092..272979f 100644
--- a/apexd/apex_file_repository_test.cpp
+++ b/apexd/apex_file_repository_test.cpp
@@ -740,8 +740,7 @@
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 @@
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 b777f1f..5cf19ad 100644
--- a/apexd/apexd.cpp
+++ b/apexd/apexd.cpp
@@ -538,8 +538,7 @@
<< ": " << 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
@@ -3438,7 +3437,7 @@
}
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 36521b0..2f8d8f2 100644
--- a/apexd/apexd_loop.cpp
+++ b/apexd/apexd_loop.cpp
@@ -158,7 +158,7 @@
// /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 @@
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 @@
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 3c356d9..330eff3 100644
--- a/apexd/apexd_loop.h
+++ b/apexd/apexd_loop.h
@@ -55,6 +55,10 @@
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 cc6d072..732e23f 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 @@
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 @@
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 @@
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;
-
- auto apex = metadata.add_apexes();
- apex->set_name("apex");
- 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);
-
// 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);
+ if (access(metadata_partition.c_str(), F_OK) == 0) {
+ metadata = *android::microdroid::ReadMetadata(metadata_partition);
+ }
+ auto apex = metadata.add_apexes();
+ apex->set_name(apex_name);
+ apex->set_public_key(public_key);
+ apex->set_root_digest(root_digest);
+ apex->set_is_factory(is_factory);
+
+ std::ofstream out(metadata_partition);
android::microdroid::WriteMetadata(metadata, out);
}
@@ -306,6 +309,7 @@
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 @@
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 @@
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