Allow using reserved package IDs
Pre-O, the platform treats negative resource IDs [those with
a package ID of 0x80 or higher] as invalid. In order to work
around this limitation, we allow the use of traditionally
reserved resource IDs [those between 0x02 and 0x7E].
Bug: 78041707
Test: ./out/host/linux-x86/nativetest64/aapt2_tests/aapt2_tests
Test: ./out/host/linux-x86/nativetest/libandroidfw_tests/libandroidfw_tests
Test: Manual. Create a feature split with a package ID of 0x7E and see it runs and can reference base resources.
Change-Id: I3d9782cc05d3a55e1a2467bf39566788847e1160
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 6f213e1..34b46c5 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -117,8 +117,7 @@
bool Reference::Flatten(android::Res_value* out_value) const {
const ResourceId resid = id.value_or_default(ResourceId(0));
- const bool dynamic = resid.is_valid_dynamic() && resid.package_id() != kFrameworkPackageId &&
- resid.package_id() < kAppPackageId;
+ const bool dynamic = resid.is_valid_dynamic() && is_dynamic;
if (reference_type == Reference::Type::kResource) {
if (dynamic) {
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index 6371c4c..168ad61 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -157,6 +157,7 @@
Maybe<ResourceId> id;
Reference::Type reference_type;
bool private_reference = false;
+ bool is_dynamic = false;
Reference();
explicit Reference(const ResourceNameRef& n, Type type = Type::kResource);
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index a3b7664..ea59722 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -129,6 +129,12 @@
// Stable ID options.
std::unordered_map<ResourceName, ResourceId> stable_id_map;
Maybe<std::string> resource_id_map_path;
+
+ // When 'true', allow reserved package IDs to be used for applications. Pre-O, the platform
+ // treats negative resource IDs [those with a package ID of 0x80 or higher] as invalid.
+ // In order to work around this limitation, we allow the use of traditionally reserved
+ // resource IDs [those between 0x02 and 0x7E].
+ bool allow_reserved_package_id = false;
};
class LinkContext : public IAaptContext {
@@ -895,9 +901,7 @@
// Capture the shared libraries so that the final resource table can be properly flattened
// with support for shared libraries.
for (auto& entry : asset_source->GetAssignedPackageIds()) {
- if (entry.first > kFrameworkPackageId && entry.first < kAppPackageId) {
- final_table_.included_packages_[entry.first] = entry.second;
- } else if (entry.first == kAppPackageId) {
+ if (entry.first == kAppPackageId) {
// Capture the included base feature package.
included_feature_base_ = entry.second;
} else if (entry.first == kFrameworkPackageId) {
@@ -911,6 +915,8 @@
// android:versionCode from the framework AndroidManifest.xml.
ExtractCompileSdkVersions(asset_source->GetAssetManager());
}
+ } else if (asset_source->IsPackageDynamic(entry.first)) {
+ final_table_.included_packages_[entry.first] = entry.second;
}
}
@@ -1595,7 +1601,15 @@
// If required, the package name is modifed before flattening, and then modified back
// to its original name.
ResourceTablePackage* package_to_rewrite = nullptr;
- if (context_->GetPackageId() > kAppPackageId &&
+ // Pre-O, the platform treats negative resource IDs [those with a package ID of 0x80
+ // or higher] as invalid. In order to work around this limitation, we allow the use
+ // of traditionally reserved resource IDs [those between 0x02 and 0x7E]. Allow the
+ // definition of what a valid "split" package ID is to account for this.
+ const bool isSplitPackage = (options_.allow_reserved_package_id &&
+ context_->GetPackageId() != kAppPackageId &&
+ context_->GetPackageId() != kFrameworkPackageId)
+ || (!options_.allow_reserved_package_id && context_->GetPackageId() > kAppPackageId);
+ if (isSplitPackage &&
included_feature_base_ == make_value(context_->GetCompilationPackage())) {
// The base APK is included, and this is a feature split. If the base package is
// the same as this package, then we are building an old style Android Instant Apps feature
@@ -2139,6 +2153,10 @@
"Generates a text file containing the resource symbols of the R class in\n"
"the specified folder.",
&options.generate_text_symbols_path)
+ .OptionalSwitch("--allow-reserved-package-id",
+ "Allows the use of a reserved package ID. This should on be used for\n"
+ "packages with a pre-O min-sdk\n",
+ &options.allow_reserved_package_id)
.OptionalSwitch("--auto-add-overlay",
"Allows the addition of new resources in overlays without\n"
"<add-resource> tags.",
@@ -2238,7 +2256,9 @@
}
const uint32_t package_id_int = maybe_package_id_int.value();
- if (package_id_int < kAppPackageId || package_id_int > std::numeric_limits<uint8_t>::max()) {
+ if (package_id_int > std::numeric_limits<uint8_t>::max()
+ || package_id_int == kFrameworkPackageId
+ || (!options.allow_reserved_package_id && package_id_int < kAppPackageId)) {
context.GetDiagnostics()->Error(
DiagMessage() << StringPrintf(
"invalid package ID 0x%02x. Must be in the range 0x7f-0xff.", package_id_int));
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 9aaaa69..3a5d585 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -340,6 +340,7 @@
// against libraries without assigned IDs.
// Ex: Linking against own resources when building a static library.
reference->id = s->id;
+ reference->is_dynamic = s->is_dynamic;
return true;
}
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 2e97a2f..fc4c9b5 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -227,6 +227,10 @@
return package_map;
}
+bool AssetManagerSymbolSource::IsPackageDynamic(uint32_t packageId) const {
+ return assets_.getResources(false).isPackageDynamic(packageId);
+}
+
static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable(
const android::ResTable& table, ResourceId id) {
// Try as a bag.
@@ -330,6 +334,7 @@
} else {
s = util::make_unique<SymbolTable::Symbol>();
s->id = res_id;
+ s->is_dynamic = table.isResourceDynamic(res_id.id);
}
if (s) {
@@ -354,7 +359,6 @@
// Exit early and avoid the error logs from AssetManager.
return {};
}
-
const android::ResTable& table = assets_.getResources(false);
Maybe<ResourceName> maybe_name = GetResourceName(table, id);
if (!maybe_name) {
@@ -370,6 +374,7 @@
} else {
s = util::make_unique<SymbolTable::Symbol>();
s->id = id;
+ s->is_dynamic = table.isResourceDynamic(id.id);
}
if (s) {
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index b676efb..51a2e37 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -68,6 +68,7 @@
Maybe<ResourceId> id;
std::shared_ptr<Attribute> attribute;
bool is_public = false;
+ bool is_dynamic = false;
};
SymbolTable(NameMangler* mangler);
@@ -192,6 +193,7 @@
bool AddAssetPath(const android::StringPiece& path);
std::map<size_t, std::string> GetAssignedPackageIds() const;
+ bool IsPackageDynamic(uint32_t packageId) const;
std::unique_ptr<SymbolTable::Symbol> FindByName(
const ResourceName& name) override;