apexd: use "APEX select" instead of "Multi-install"
APEX Select property can be used even for a single install case now.
Minor refactoring around ApexFileRepository constructor and tests. We
can always check partitions even in tests. So, no need for "enforce"
flag which was used for testing only.
Bug: 417632996
Test: ApexTestCases
Change-Id: I67e2c4d6fd00fcd105ad360e6225e8634b2e0c06
diff --git a/apexd/apex_constants.h b/apexd/apex_constants.h
index 1be9898..370d2f4 100644
--- a/apexd/apex_constants.h
+++ b/apexd/apex_constants.h
@@ -81,14 +81,13 @@
static constexpr const char* kApexStatusActivated = "activated";
static constexpr const char* kApexStatusReady = "ready";
-static constexpr const char* kMultiApexSelectPersistPrefix =
- "persist.vendor.apex.";
-static constexpr const char* kMultiApexSelectBootconfigPrefix =
+static constexpr const char* kApexSelectPersistPrefix = "persist.vendor.apex.";
+static constexpr const char* kApexSelectBootconfigPrefix =
"ro.boot.vendor.apex.";
-static const std::vector<std::string> kMultiApexSelectPrefix = {
+static const std::vector<std::string> kApexSelectPrefix = {
// Check persist props first, to allow users to override bootconfig.
- kMultiApexSelectPersistPrefix,
- kMultiApexSelectBootconfigPrefix,
+ kApexSelectPersistPrefix,
+ kApexSelectBootconfigPrefix,
};
static constexpr const char* kVmPayloadMetadataPartitionProp =
diff --git a/apexd/apex_file_repository.cpp b/apexd/apex_file_repository.cpp
index 2d40fc5..9fdbbdb 100644
--- a/apexd/apex_file_repository.cpp
+++ b/apexd/apex_file_repository.cpp
@@ -71,16 +71,16 @@
ApexPartition partition) {
const std::string& name = apex_file.GetManifest().name();
- // Check if this APEX name is treated as a multi-install APEX.
+ // Check if this APEX name is selected or not.
//
// Note: apexd is a oneshot service which runs at boot, but can be
// restarted when needed (such as staging an APEX update). If a
- // multi-install select property changes between boot and when apexd
+ // APEX select property changes between boot and when apexd
// restarts, the LOG messages below will report the version that will be
// activated on next reboot, which may differ from the currently-active
// version.
std::string select_filename =
- GetApexSelectFilenameFromProp(multi_install_select_prop_prefixes_, name);
+ GetApexSelectFilenameFromProp(apex_select_prop_prefixes_, name);
if (!select_filename.empty()) {
std::string path;
if (!android::base::Realpath(apex_file.GetPath(), &path)) {
@@ -88,10 +88,9 @@
<< apex_file.GetPath();
return;
}
- if (enforce_multi_install_partition_ &&
- partition != ApexPartition::Vendor && partition != ApexPartition::Odm) {
- LOG(ERROR) << "Multi-install APEX " << path
- << " can only be preinstalled on /{odm,vendor}/apex/.";
+ if (partition != ApexPartition::Vendor && partition != ApexPartition::Odm) {
+ LOG(ERROR) << "APEX-select property is supported on /{odm,vendor}/apex/ :"
+ << path;
return;
}
@@ -116,23 +115,13 @@
return;
}
- if (ConsumeApexPackageSuffix(android::base::Basename(path)) ==
+ if (ConsumeApexPackageSuffix(android::base::Basename(path)) !=
select_filename) {
- LOG(INFO) << "Found APEX at path " << path << " for multi-install APEX "
- << name;
- // A copy is needed because apex_file is moved here
- const std::string apex_name = name;
- // Add the APEX file to the store if its filename matches the
- // property.
- pre_installed_store_.emplace(apex_name, std::move(apex_file));
- partition_store_.emplace(apex_name, partition);
- } else {
LOG(INFO) << "Skipping APEX at path " << path
<< " because it does not match expected multi-install"
<< " APEX property for " << name;
+ return;
}
-
- return;
}
auto it = pre_installed_store_.find(name);
@@ -256,7 +245,6 @@
StorePreInstalledApex(std::move(*apex_file), apex_path.partition);
}
- multi_install_public_keys_.clear();
return {};
}
@@ -271,7 +259,6 @@
for (auto&& [apex_file, partition] : apex_file_and_partition) {
StorePreInstalledApex(std::move(apex_file), partition);
}
- multi_install_public_keys_.clear();
return {};
}
diff --git a/apexd/apex_file_repository.h b/apexd/apex_file_repository.h
index ea29e4b..da86b92 100644
--- a/apexd/apex_file_repository.h
+++ b/apexd/apex_file_repository.h
@@ -53,13 +53,11 @@
public:
// c-tors and d-tor are exposed for testing.
explicit ApexFileRepository(
- const std::string& decompression_dir = kApexDecompressedDir)
- : decompression_dir_(decompression_dir) {}
- explicit ApexFileRepository(
- bool enforce_multi_install_partition,
- const std::vector<std::string>& multi_install_select_prop_prefixes)
- : multi_install_select_prop_prefixes_(multi_install_select_prop_prefixes),
- enforce_multi_install_partition_(enforce_multi_install_partition) {}
+ const std::string& decompression_dir = kApexDecompressedDir,
+ const std::vector<std::string>& apex_select_prop_prefixes =
+ kApexSelectPrefix)
+ : decompression_dir_(decompression_dir),
+ apex_select_prop_prefixes_(apex_select_prop_prefixes) {}
// Returns a singletone instance of this class.
static ApexFileRepository& GetInstance();
@@ -236,19 +234,6 @@
// Map from trusted public keys for brand-new APEX to their holding partition.
std::unordered_map<std::string, ApexPartition> brand_new_apex_pubkeys_;
- // Multi-installed APEX name -> all encountered public keys for this APEX.
- std::unordered_map<std::string, std::unordered_set<std::string>>
- multi_install_public_keys_;
-
- // Prefixes used when looking for multi-installed APEX sysprops.
- // Order matters: the first non-empty prop value is returned.
- std::vector<std::string> multi_install_select_prop_prefixes_ =
- kMultiApexSelectPrefix;
-
- // Allows multi-install APEXes outside of expected partitions.
- // Only set false in tests.
- bool enforce_multi_install_partition_ = true;
-
// Disallows installation of brand-new APEX by default.
inline static bool enable_brand_new_apex_ = false;
@@ -273,6 +258,18 @@
// versions of sharedlibs APEXes.
std::unordered_map<std::string, BlockApexOverride> block_apex_overrides_;
+ // Prefixes used when looking for APEX select sysprops. APEX select sysprop
+ // can be used to install multiple instances of the same package, and select
+ // only one of them. Order matters: the first non-empty prop value is
+ // returned.
+ std::vector<std::string> apex_select_prop_prefixes_;
+
+ // When there are multiple instances of the same package, they should share
+ // the same public key. To ensure that, keep the map of package name to all
+ // encountered public keys for this APEX.
+ std::unordered_map<std::string, std::unordered_set<std::string>>
+ multi_install_public_keys_;
+
// for tests to access ApexFileRepository's private data
friend class ApexFileRepositoryAccessor;
};
diff --git a/apexd/apex_file_repository_test.cpp b/apexd/apex_file_repository_test.cpp
index 9c7a1f9..bf76537 100644
--- a/apexd/apex_file_repository_test.cpp
+++ b/apexd/apex_file_repository_test.cpp
@@ -190,7 +190,7 @@
"");
}
-TEST(ApexFileRepositoryTest, InitializeMultiInstalledSuccess) {
+TEST(ApexFileRepositoryTest, ApexSelectWithMultiApexSuccess) {
// Prepare test data.
TemporaryDir td;
std::string apex_file = GetTestFile("apex.apexd_test.apex");
@@ -201,13 +201,13 @@
std::string persist_prefix = "debug.apexd.test.persistprefix.";
std::string bootconfig_prefix = "debug.apexd.test.bootconfigprefix.";
- ApexFileRepository instance(/*enforce_multi_install_partition=*/false,
- /*multi_install_select_prop_prefixes=*/{
- persist_prefix, bootconfig_prefix});
+ ApexFileRepository instance(
+ kApexDecompressedDir,
+ /*apex_select_prop_prefixes=*/{persist_prefix, bootconfig_prefix});
auto test_fn = [&](const std::string& selected_filename) {
ASSERT_RESULT_OK(
- instance.AddPreInstalledApex({{ApexPartition::System, td.path}}));
+ instance.AddPreInstalledApex({{ApexPartition::Vendor, td.path}}));
auto ret = instance.GetPreinstalledPath(apex->GetManifest().name());
ASSERT_RESULT_OK(ret);
ASSERT_EQ(StringPrintf("%s/%s", td.path, selected_filename.c_str()), *ret);
@@ -239,8 +239,8 @@
{
ApexFileRepository instance(
- /*enforce_multi_install_partition=*/true,
- /*multi_install_select_prop_prefixes=*/{apex_select_prop_prefix});
+ kApexDecompressedDir,
+ /*apex_select_prop_prefixes=*/{apex_select_prop_prefix});
ASSERT_THAT(
instance.AddPreInstalledApex({{ApexPartition::Vendor, td.path}}), Ok());
ASSERT_THAT(instance.GetPreInstalledApex(apex_name), Optional(_));
@@ -249,15 +249,15 @@
{
android::base::SetProperty(apex_select_prop_prefix + apex_name, "none");
ApexFileRepository instance(
- /*enforce_multi_install_partition=*/true,
- /*multi_install_select_prop_prefixes=*/{apex_select_prop_prefix});
+ kApexDecompressedDir,
+ /*apex_select_prop_prefixes=*/{apex_select_prop_prefix});
ASSERT_THAT(
instance.AddPreInstalledApex({{ApexPartition::Vendor, td.path}}), Ok());
ASSERT_THAT(instance.GetPreInstalledApex(apex_name), Eq(std::nullopt));
}
}
-TEST(ApexFileRepositoryTest, InitializeMultiInstalledSkipsForDifferingKeys) {
+TEST(ApexFileRepositoryTest, ApexSelectSkipsForDifferingKeys) {
// Prepare test data.
TemporaryDir td;
fs::copy(GetTestFile("apex.apexd_test.apex"),
@@ -270,11 +270,10 @@
std::string prop = prop_prefix + apex_name;
android::base::SetProperty(prop, "version_a.apex");
- ApexFileRepository instance(
- /*enforce_multi_install_partition=*/false,
- /*multi_install_select_prop_prefixes=*/{prop_prefix});
+ ApexFileRepository instance(kApexDecompressedDir,
+ /*apex_select_prop_prefixes=*/{prop_prefix});
ASSERT_RESULT_OK(
- instance.AddPreInstalledApex({{ApexPartition::System, td.path}}));
+ instance.AddPreInstalledApex({{ApexPartition::Vendor, td.path}}));
// Neither version should be have been installed.
ASSERT_THAT(instance.GetPreinstalledPath(apex->GetManifest().name()),
Not(Ok()));
@@ -282,7 +281,7 @@
android::base::SetProperty(prop, "");
}
-TEST(ApexFileRepositoryTest, InitializeMultiInstalledSkipsForInvalidPartition) {
+TEST(ApexFileRepositoryTest, ApexSelectSkipsForInvalidPartition) {
// Prepare test data.
TemporaryDir td;
// Note: These test files are on /data, which is not a valid partition for
@@ -297,9 +296,8 @@
std::string prop = prop_prefix + apex_name;
android::base::SetProperty(prop, "version_a.apex");
- ApexFileRepository instance(
- /*enforce_multi_install_partition=*/true,
- /*multi_install_select_prop_prefixes=*/{prop_prefix});
+ ApexFileRepository instance(kApexDecompressedDir,
+ /*apex_select_prop_prefixes=*/{prop_prefix});
ASSERT_RESULT_OK(
instance.AddPreInstalledApex({{ApexPartition::System, td.path}}));
// Neither version should be have been installed.