diff --git a/tests/FeatureSplit/base/Android.mk b/tests/FeatureSplit/base/Android.mk index 93f6d7a5f52be..6da1b38773ed1 100644 --- a/tests/FeatureSplit/base/Android.mk +++ b/tests/FeatureSplit/base/Android.mk @@ -17,6 +17,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_USE_AAPT2 := true LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FeatureSplitBase LOCAL_EXPORT_PACKAGE_RESOURCES := true diff --git a/tests/FeatureSplit/feature1/res/values/values.xml b/tests/FeatureSplit/feature1/res/values/values.xml index 10dbd97338894..7d58865b546ea 100644 --- a/tests/FeatureSplit/feature1/res/values/values.xml +++ b/tests/FeatureSplit/feature1/res/values/values.xml @@ -20,7 +20,7 @@ 200 #00ff00 - @*string/app_title + @string/app_title diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp index a5ddc524c3f5f..0fe1a1f9ddcca 100644 --- a/tools/aapt2/ResourceValues.cpp +++ b/tools/aapt2/ResourceValues.cpp @@ -95,7 +95,7 @@ bool Reference::Equals(const Value* value) const { 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; + resid.package_id() < kAppPackageId; if (reference_type == Reference::Type::kResource) { if (dynamic) { diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index fea11ed70bbee..5fc35b8112132 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -754,6 +754,9 @@ class LinkCommand { 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) { + // Capture the included base feature package. + included_feature_base_ = entry.second; } } @@ -1408,17 +1411,53 @@ class LinkCommand { return false; } - if (context_->GetPackageType() == PackageType::kStaticLib) { - if (!FlattenTableToPb(table, writer)) { - return false; - } - } else { - if (!FlattenTable(table, writer)) { - context_->GetDiagnostics()->Error(DiagMessage() << "failed to write resources.arsc"); - return false; + // Hack to fix b/68820737. + // We need to modify the ResourceTable's package name, but that should NOT affect + // anything else being generated, which includes the Java classes. + // 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 && + 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 + // split and must apply this workaround to avoid requiring namespaces support. + package_to_rewrite = table->FindPackage(context_->GetCompilationPackage()); + if (package_to_rewrite != nullptr) { + CHECK_EQ(1u, table->packages.size()) << "can't change name of package when > 1 package"; + + std::string new_package_name = + StringPrintf("%s.%s", package_to_rewrite->name.c_str(), + app_info_.split_name.value_or_default("feature").c_str()); + + if (context_->IsVerbose()) { + context_->GetDiagnostics()->Note( + DiagMessage() << "rewriting resource package name for feature split to '" + << new_package_name << "'"); + } + package_to_rewrite->name = new_package_name; } } - return true; + + bool success; + if (context_->GetPackageType() == PackageType::kStaticLib) { + success = FlattenTableToPb(table, writer); + } else { + success = FlattenTable(table, writer); + } + + if (package_to_rewrite != nullptr) { + // Change the name back. + package_to_rewrite->name = context_->GetCompilationPackage(); + if (package_to_rewrite->id) { + table->included_packages_.erase(package_to_rewrite->id.value()); + } + } + + if (!success) { + context_->GetDiagnostics()->Error(DiagMessage() << "failed to write resource table"); + } + return success; } int Run(const std::vector& input_files) { @@ -1447,8 +1486,8 @@ class LinkCommand { return 1; } - const AppInfo& app_info = maybe_app_info.value(); - context_->SetMinSdkVersion(app_info.min_sdk_version.value_or_default(0)); + app_info_ = maybe_app_info.value(); + context_->SetMinSdkVersion(app_info_.min_sdk_version.value_or_default(0)); context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()}); @@ -1647,7 +1686,7 @@ class LinkCommand { // Generate an AndroidManifest.xml for each split. std::unique_ptr split_manifest = - GenerateSplitManifest(app_info, *split_constraints_iter); + GenerateSplitManifest(app_info_, *split_constraints_iter); XmlReferenceLinker linker; if (!linker.Consume(context_, split_manifest.get())) { @@ -1815,6 +1854,8 @@ class LinkCommand { LinkContext* context_; ResourceTable final_table_; + AppInfo app_info_; + std::unique_ptr table_merger_; // A pointer to the FileCollection representing the filesystem (not archives). @@ -1830,6 +1871,9 @@ class LinkCommand { // The set of shared libraries being used, mapping their assigned package ID to package name. std::map shared_libs_; + + // The package name of the base application, if it is included. + Maybe included_feature_base_; }; int Link(const std::vector& args, IDiagnostics* diagnostics) { diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp index 14b776b1bd994..32924215ab4e6 100644 --- a/tools/aapt2/flatten/TableFlattener.cpp +++ b/tools/aapt2/flatten/TableFlattener.cpp @@ -23,6 +23,7 @@ #include "android-base/logging.h" #include "android-base/macros.h" +#include "android-base/stringprintf.h" #include "ResourceTable.h" #include "ResourceValues.h" @@ -572,14 +573,6 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) { ResTable_header* table_header = table_writer.StartChunk(RES_TABLE_TYPE); table_header->packageCount = util::HostToDevice32(table->packages.size()); - // Write a self mapping entry for this package if the ID is non-standard (0x7f). - if (context->GetPackageType() == PackageType::kApp) { - const uint8_t package_id = context->GetPackageId(); - if (package_id != kFrameworkPackageId && package_id != kAppPackageId) { - table->included_packages_[package_id] = context->GetCompilationPackage(); - } - } - // Flatten the values string pool. StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool); @@ -587,6 +580,22 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) { // Flatten each package. for (auto& package : table->packages) { + if (context->GetPackageType() == PackageType::kApp) { + // Write a self mapping entry for this package if the ID is non-standard (0x7f). + const uint8_t package_id = package->id.value(); + if (package_id != kFrameworkPackageId && package_id != kAppPackageId) { + auto result = table->included_packages_.insert({package_id, package->name}); + if (!result.second && result.first->second != package->name) { + // A mapping for this package ID already exists, and is a different package. Error! + context->GetDiagnostics()->Error( + DiagMessage() << android::base::StringPrintf( + "can't map package ID %02x to '%s'. Already mapped to '%s'", package_id, + package->name.c_str(), result.first->second.c_str())); + return false; + } + } + } + PackageFlattener flattener(context, package.get(), &table->included_packages_, options_.use_sparse_entries); if (!flattener.FlattenPackage(&package_buffer)) {