From c6284379a5dde6bc5927409eff292db2f0add578 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 4 Dec 2017 13:46:23 -0800 Subject: [PATCH] AAPT2: Embed version of framework an app was compiled against. This change injects the 'android:compileSdkVersion' and 'android:compileSdkVersionCodename' into an app's AndroidManifest.xml, whose values are dervied from the version name and version code of the framework AndroidManifest.xml that is being linked against. Bug: 63388434 Test: make aapt2_tests Change-Id: I7b607192ecb337307c4bcb5770e7f716c6d4c9d2 --- tools/aapt2/cmd/Link.cpp | 104 +++++++++++++++- tools/aapt2/link/ManifestFixer.cpp | 19 +++ tools/aapt2/link/ManifestFixer.h | 32 ++++- tools/aapt2/link/ManifestFixer_test.cpp | 211 ++++++++++++++++++-------------- tools/aapt2/process/SymbolTable.h | 4 + tools/aapt2/xml/XmlDom.cpp | 9 ++ tools/aapt2/xml/XmlDom.h | 2 + 7 files changed, 276 insertions(+), 105 deletions(-) diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index d2aebfd31bbf..13dd93e83b64 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -725,6 +726,30 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path, return true; } +static int32_t FindFrameworkAssetManagerCookie(const android::AssetManager& assets) { + using namespace android; + + // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so + // we're looking for the first attribute resource in the system package. + const ResTable& table = assets.getResources(true); + Res_value val; + ssize_t idx = table.getResource(0x01010000, &val, true); + if (idx != NO_ERROR) { + // Try as a bag. + const ResTable::bag_entry* entry; + ssize_t cnt = table.lockBag(0x01010000, &entry); + if (cnt >= 0) { + idx = entry->stringBlock; + } + table.unlockBag(entry); + } + + if (idx < 0) { + return 0; + } + return table.getTableCookie(idx); +} + class LinkCommand { public: LinkCommand(LinkContext* context, const LinkOptions& options) @@ -734,7 +759,65 @@ class LinkCommand { file_collection_(util::make_unique()) { } + void ExtractCompileSdkVersions(android::AssetManager* assets) { + using namespace android; + + int32_t cookie = FindFrameworkAssetManagerCookie(*assets); + if (cookie == 0) { + // No Framework assets loaded. Not a failure. + return; + } + + std::unique_ptr manifest( + assets->openNonAsset(cookie, kAndroidManifestPath, Asset::AccessMode::ACCESS_BUFFER)); + if (manifest == nullptr) { + // No errors. + return; + } + + std::string error; + std::unique_ptr manifest_xml = + xml::Inflate(manifest->getBuffer(true /*wordAligned*/), manifest->getLength(), &error); + if (manifest_xml == nullptr) { + // No errors. + return; + } + + xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionCode"); + if (attr != nullptr) { + Maybe& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version; + if (BinaryPrimitive* prim = ValueCast(attr->compiled_value.get())) { + switch (prim->value.dataType) { + case Res_value::TYPE_INT_DEC: + compile_sdk_version = StringPrintf("%" PRId32, static_cast(prim->value.data)); + break; + case Res_value::TYPE_INT_HEX: + compile_sdk_version = StringPrintf("%" PRIx32, prim->value.data); + break; + default: + break; + } + } else if (String* str = ValueCast(attr->compiled_value.get())) { + compile_sdk_version = *str->value; + } else { + compile_sdk_version = attr->value; + } + } + + attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionName"); + if (attr != nullptr) { + Maybe& compile_sdk_version_codename = + options_.manifest_fixer_options.compile_sdk_version_codename; + if (String* str = ValueCast(attr->compiled_value.get())) { + compile_sdk_version_codename = *str->value; + } else { + compile_sdk_version_codename = attr->value; + } + } + } + // Creates a SymbolTable that loads symbols from the various APKs. + // Pre-condition: context_->GetCompilationPackage() needs to be set. bool LoadSymbolsFromIncludePaths() { auto asset_source = util::make_unique(); for (const std::string& path : options_.include_paths) { @@ -802,6 +885,17 @@ class LinkCommand { } else if (entry.first == kAppPackageId) { // Capture the included base feature package. included_feature_base_ = entry.second; + } else if (entry.first == kFrameworkPackageId) { + // Try to embed which version of the framework we're compiling against. + // First check if we should use compileSdkVersion at all. Otherwise compilation may fail + // when linking our synthesized 'android:compileSdkVersion' attribute. + std::unique_ptr symbol = asset_source->FindByName( + ResourceName("android", ResourceType::kAttr, "compileSdkVersion")); + if (symbol != nullptr && symbol->is_public) { + // The symbol is present and public, extract the android:versionName and + // android:versionCode from the framework AndroidManifest.xml. + ExtractCompileSdkVersions(asset_source->GetAssetManager()); + } } } @@ -1535,6 +1629,12 @@ class LinkCommand { context_->SetCompilationPackage(app_info.package); } + // Now that the compilation package is set, load the dependencies. This will also extract + // the Android framework's versionCode and versionName, if they exist. + if (!LoadSymbolsFromIncludePaths()) { + return 1; + } + ManifestFixer manifest_fixer(options_.manifest_fixer_options); if (!manifest_fixer.Consume(context_, manifest_xml.get())) { return 1; @@ -1563,10 +1663,6 @@ class LinkCommand { } } - if (!LoadSymbolsFromIncludePaths()) { - return 1; - } - TableMergerOptions table_merger_options; table_merger_options.auto_add_overlay = options_.auto_add_overlay; table_merger_ = util::make_unique(context_, &final_table_, table_merger_options); diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index eaaefd5e099a..a68df1dbc998 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -406,6 +406,25 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) { root->InsertChild(0, std::move(uses_sdk)); } + if (options_.compile_sdk_version) { + xml::Attribute* attr = root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersion"); + + // Make sure we un-compile the value if it was set to something else. + attr->compiled_value = {}; + + attr->value = options_.compile_sdk_version.value(); + } + + if (options_.compile_sdk_version_codename) { + xml::Attribute* attr = + root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename"); + + // Make sure we un-compile the value if it was set to something else. + attr->compiled_value = {}; + + attr->value = options_.compile_sdk_version_codename.value(); + } + xml::XmlActionExecutor executor; if (!BuildRules(&executor, context->GetDiagnostics())) { return false; diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h index 470f65eb01c4..f5715f605b04 100644 --- a/tools/aapt2/link/ManifestFixer.h +++ b/tools/aapt2/link/ManifestFixer.h @@ -29,22 +29,42 @@ namespace aapt { struct ManifestFixerOptions { + // The minimum SDK version to set if no 'android:minSdkVersion' is defined in a tag. Maybe min_sdk_version_default; + + // The target SDK version to set if no 'android:targetSdkVersion' is defined in a tag. Maybe target_sdk_version_default; + + // The Android package to use instead of the one defined in 'package' in . + // This also renames all relative package/class names in the manifest to fully qualified + // Java names. Maybe rename_manifest_package; + + // The Android package to use instead of the one defined in 'android:targetPackage' in + // . Maybe rename_instrumentation_target_package; + + // The version name to set if 'android:versionName' is not defined in . Maybe version_name_default; + + // The version code to set if 'android:versionCode' is not defined in . Maybe version_code_default; + + // The version of the framework being compiled against to set for 'android:compileSdkVersion' in + // the tag. + Maybe compile_sdk_version; + + // The version codename of the framework being compiled against to set for + // 'android:compileSdkVersionCodename' in the tag. + Maybe compile_sdk_version_codename; }; -/** - * Verifies that the manifest is correctly formed and inserts defaults - * where specified with ManifestFixerOptions. - */ +// Verifies that the manifest is correctly formed and inserts defaults where specified with +// ManifestFixerOptions. class ManifestFixer : public IXmlResourceConsumer { public: - explicit ManifestFixer(const ManifestFixerOptions& options) - : options_(options) {} + explicit ManifestFixer(const ManifestFixerOptions& options) : options_(options) { + } bool Consume(IAaptContext* context, xml::XmlResource* doc) override; diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp index 40085eab9707..1320dcd2a170 100644 --- a/tools/aapt2/link/ManifestFixer_test.cpp +++ b/tools/aapt2/link/ManifestFixer_test.cpp @@ -19,7 +19,12 @@ #include "test/Test.h" using ::android::StringPiece; +using ::testing::Eq; +using ::testing::Gt; +using ::testing::IsNull; +using ::testing::Ne; using ::testing::NotNull; +using ::testing::StrEq; namespace aapt { @@ -72,22 +77,20 @@ struct ManifestFixerTest : public ::testing::Test { }; TEST_F(ManifestFixerTest, EnsureManifestIsRootTag) { - EXPECT_EQ(nullptr, Verify("")); - EXPECT_EQ(nullptr, Verify("")); - EXPECT_NE(nullptr, Verify("")); + EXPECT_THAT(Verify(""), IsNull()); + EXPECT_THAT(Verify(""), IsNull()); + EXPECT_THAT(Verify(""), NotNull()); } TEST_F(ManifestFixerTest, EnsureManifestHasPackage) { - EXPECT_NE(nullptr, Verify("")); - EXPECT_NE(nullptr, Verify("")); - EXPECT_NE(nullptr, Verify("")); - EXPECT_EQ(nullptr, - Verify("")); - EXPECT_EQ(nullptr, Verify("")); - EXPECT_EQ(nullptr, Verify("")); + EXPECT_THAT(Verify(""), NotNull()); + EXPECT_THAT(Verify(""), NotNull()); + EXPECT_THAT(Verify(""), NotNull()); + EXPECT_THAT(Verify(""), IsNull()); + EXPECT_THAT(Verify(""), + IsNull()); + EXPECT_THAT(Verify(""), IsNull()); } TEST_F(ManifestFixerTest, AllowMetaData) { @@ -105,7 +108,7 @@ TEST_F(ManifestFixerTest, AllowMetaData) { )EOF"); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); } TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) { @@ -117,21 +120,21 @@ TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) { )EOF", options); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); xml::Element* el; xml::Attribute* attr; el = doc->root.get(); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); el = el->FindChild({}, "uses-sdk"); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ("7", attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("7")); attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ("21", attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("21")); doc = VerifyWithOptions(R"EOF( )EOF", options); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); el = doc->root.get(); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); el = el->FindChild({}, "uses-sdk"); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ("8", attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("8")); attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ("21", attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("21")); doc = VerifyWithOptions(R"EOF( )EOF", options); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); el = doc->root.get(); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); el = el->FindChild({}, "uses-sdk"); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ("8", attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("8")); attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ("22", attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("22")); doc = VerifyWithOptions(R"EOF( )EOF", options); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); el = doc->root.get(); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); el = el->FindChild({}, "uses-sdk"); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ("8", attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("8")); attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ("22", attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("22")); } TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) { @@ -197,17 +200,17 @@ TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) { )EOF", options); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); - ASSERT_NE(nullptr, manifest_el); + ASSERT_THAT(manifest_el, NotNull()); ASSERT_EQ("manifest", manifest_el->name); xml::Element* application_el = manifest_el->FindChild("", "application"); - ASSERT_NE(nullptr, application_el); + ASSERT_THAT(application_el, NotNull()); xml::Element* uses_sdk_el = manifest_el->FindChild("", "uses-sdk"); - ASSERT_NE(nullptr, uses_sdk_el); + ASSERT_THAT(uses_sdk_el, NotNull()); // Check that the uses_sdk_el comes before application_el in the children // vector. @@ -225,12 +228,12 @@ TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) { return child.get() == application_el; }); - ASSERT_NE(manifest_el->children.end(), uses_sdk_iter); - ASSERT_NE(manifest_el->children.end(), application_iter); + ASSERT_THAT(uses_sdk_iter, Ne(manifest_el->children.end())); + ASSERT_THAT(application_iter, Ne(manifest_el->children.end())); // The distance should be positive, meaning uses_sdk_iter comes before // application_iter. - EXPECT_GT(std::distance(uses_sdk_iter, application_iter), 0); + EXPECT_THAT(std::distance(uses_sdk_iter, application_iter), Gt(0)); } TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) { @@ -247,48 +250,49 @@ TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) { )EOF", options); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); - ASSERT_NE(nullptr, manifest_el); + ASSERT_THAT(manifest_el, NotNull()); xml::Attribute* attr = nullptr; attr = manifest_el->FindAttribute({}, "package"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ(std::string("com.android"), attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("com.android")); xml::Element* uses_split_el = manifest_el->FindChild({}, "uses-split"); - ASSERT_NE(nullptr, uses_split_el); + ASSERT_THAT(uses_split_el, NotNull()); attr = uses_split_el->FindAttribute(xml::kSchemaAndroid, "name"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ(std::string("feature_a"), attr->value); + ASSERT_THAT(attr, NotNull()); + // This should NOT have been affected. + EXPECT_THAT(attr->value, StrEq("feature_a")); xml::Element* application_el = manifest_el->FindChild({}, "application"); - ASSERT_NE(nullptr, application_el); + ASSERT_THAT(application_el, NotNull()); attr = application_el->FindAttribute(xml::kSchemaAndroid, "name"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ(std::string("android.MainApplication"), attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("android.MainApplication")); attr = application_el->FindAttribute({}, "text"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ(std::string("hello"), attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("hello")); xml::Element* el; el = application_el->FindChild({}, "activity"); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "name"); - ASSERT_NE(nullptr, el); - EXPECT_EQ(std::string("android.activity.Start"), attr->value); + ASSERT_THAT(el, NotNull()); + EXPECT_THAT(attr->value, StrEq("android.activity.Start")); el = application_el->FindChild({}, "receiver"); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "name"); - ASSERT_NE(nullptr, el); - EXPECT_EQ(std::string("com.google.android.Receiver"), attr->value); + ASSERT_THAT(el, NotNull()); + EXPECT_THAT(attr->value, StrEq("com.google.android.Receiver")); } TEST_F(ManifestFixerTest, @@ -302,19 +306,19 @@ TEST_F(ManifestFixerTest, )EOF", options); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); - ASSERT_NE(nullptr, manifest_el); + ASSERT_THAT(manifest_el, NotNull()); xml::Element* instrumentation_el = manifest_el->FindChild({}, "instrumentation"); - ASSERT_NE(nullptr, instrumentation_el); + ASSERT_THAT(instrumentation_el, NotNull()); xml::Attribute* attr = instrumentation_el->FindAttribute(xml::kSchemaAndroid, "targetPackage"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ(std::string("com.android"), attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("com.android")); } TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) { @@ -326,41 +330,39 @@ TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) { )EOF", options); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); - ASSERT_NE(nullptr, manifest_el); + ASSERT_THAT(manifest_el, NotNull()); xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ(std::string("Beta"), attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("Beta")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); - ASSERT_NE(nullptr, attr); - EXPECT_EQ(std::string("0x10000000"), attr->value); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("0x10000000")); } TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) { - EXPECT_EQ(nullptr, - Verify("")); - EXPECT_EQ(nullptr, - Verify("")); + EXPECT_THAT(Verify(""), IsNull()); + EXPECT_THAT(Verify(""), IsNull()); std::unique_ptr doc = Verify(""); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); xml::Element* el = doc->root.get(); - ASSERT_NE(nullptr, el); + ASSERT_THAT(el, NotNull()); - EXPECT_EQ("manifest", el->name); + EXPECT_THAT(el->name, StrEq("manifest")); xml::Attribute* attr = el->FindAttribute("", "coreApp"); - ASSERT_NE(nullptr, attr); + ASSERT_THAT(attr, NotNull()); - EXPECT_NE(nullptr, attr->compiled_value); - EXPECT_NE(nullptr, ValueCast(attr->compiled_value.get())); + EXPECT_THAT(attr->compiled_value, NotNull()); + EXPECT_THAT(ValueCast(attr->compiled_value.get()), NotNull()); } TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) { @@ -375,21 +377,21 @@ TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) { )EOF"; - EXPECT_NE(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), NotNull()); input = R"EOF( )EOF"; - EXPECT_EQ(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), IsNull()); input = R"EOF( )EOF"; - EXPECT_EQ(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), IsNull()); input = R"EOF( )EOF"; - EXPECT_EQ(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), IsNull()); input = R"EOF( )EOF"; - EXPECT_EQ(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), IsNull()); } TEST_F(ManifestFixerTest, IgnoreNamespacedElements) { @@ -416,7 +418,7 @@ TEST_F(ManifestFixerTest, IgnoreNamespacedElements) { package="android"> )EOF"; - EXPECT_NE(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), NotNull()); } TEST_F(ManifestFixerTest, DoNotIgnoreNonNamespacedElements) { @@ -425,7 +427,7 @@ TEST_F(ManifestFixerTest, DoNotIgnoreNonNamespacedElements) { package="android"> )EOF"; - EXPECT_EQ(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), IsNull()); } TEST_F(ManifestFixerTest, SupportKeySets) { @@ -446,4 +448,23 @@ TEST_F(ManifestFixerTest, SupportKeySets) { EXPECT_THAT(Verify(input), NotNull()); } +TEST_F(ManifestFixerTest, InsertCompileSdkVersions) { + std::string input = R"( + )"; + ManifestFixerOptions options; + options.compile_sdk_version = {"28"}; + options.compile_sdk_version_codename = {"P"}; + + std::unique_ptr manifest = VerifyWithOptions(input, options); + ASSERT_THAT(manifest, NotNull()); + + xml::Attribute* attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersion"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("28")); + + attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("P")); +} + } // namespace aapt diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h index 4a2181e0b344..b676efb8d025 100644 --- a/tools/aapt2/process/SymbolTable.h +++ b/tools/aapt2/process/SymbolTable.h @@ -199,6 +199,10 @@ class AssetManagerSymbolSource : public ISymbolSource { std::unique_ptr FindByReference( const Reference& ref) override; + android::AssetManager* GetAssetManager() { + return &assets_; + } + private: android::AssetManager assets_; diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp index b0cf44accafa..fddb6b8c5d87 100644 --- a/tools/aapt2/xml/XmlDom.cpp +++ b/tools/aapt2/xml/XmlDom.cpp @@ -418,6 +418,15 @@ const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece return nullptr; } +Attribute* Element::FindOrCreateAttribute(const StringPiece& ns, const StringPiece& name) { + Attribute* attr = FindAttribute(ns, name); + if (attr == nullptr) { + attributes.push_back(Attribute{ns.to_string(), name.to_string()}); + attr = &attributes.back(); + } + return attr; +} + Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) { return FindChildWithAttribute(ns, name, {}, {}, {}); } diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h index cf06ba5cc50e..8f3829611f30 100644 --- a/tools/aapt2/xml/XmlDom.h +++ b/tools/aapt2/xml/XmlDom.h @@ -100,6 +100,8 @@ class Element : public Node { Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name); const Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name) const; + Attribute* FindOrCreateAttribute(const android::StringPiece& ns, + const android::StringPiece& name); Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name); const Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name) const; -- 2.11.0