diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index a93ee2e2b71dd..deb9cc083eb00 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -68,6 +68,7 @@ public: mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL), mBuildSharedLibrary(false), mBuildAppAsSharedLibrary(false), + mCompileSdkVersion(0), mArgc(0), mArgv(NULL) {} ~Bundle(void) {} @@ -123,6 +124,10 @@ public: void setErrorOnFailedInsert(bool val) { mErrorOnFailedInsert = val; } bool getErrorOnMissingConfigEntry() { return mErrorOnMissingConfigEntry; } void setErrorOnMissingConfigEntry(bool val) { mErrorOnMissingConfigEntry = val; } + const android::String8& getCompileSdkVersionCodename() { return mCompileSdkVersionCodename; } + void setCompileSdkVersionCodename(const android::String8& codename) { mCompileSdkVersionCodename = codename; } + int getCompileSdkVersion() { return mCompileSdkVersion; } + void setCompileSdkVersion(int version) { mCompileSdkVersion = version; } const android::String8& getPlatformBuildVersionCode() { return mPlatformVersionCode; } void setPlatformBuildVersionCode(const android::String8& code) { mPlatformVersionCode = code; } const android::String8& getPlatformBuildVersionName() { return mPlatformVersionName; } @@ -344,6 +349,8 @@ private: const char* mSingleCrunchOutputFile; bool mBuildSharedLibrary; bool mBuildAppAsSharedLibrary; + int mCompileSdkVersion; + android::String8 mCompileSdkVersionCodename; android::String8 mPlatformVersionCode; android::String8 mPlatformVersionName; android::String8 mPrivateSymbolsPackage; diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index cb87737c68684..05375b0cb8717 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -293,6 +293,8 @@ enum { ISGAME_ATTR = 0x10103f4, REQUIRED_FEATURE_ATTR = 0x1010557, REQUIRED_NOT_FEATURE_ATTR = 0x1010558, + COMPILE_SDK_VERSION_ATTR = 0x01010572, // NOT FINALIZED + COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573, // NOT FINALIZED }; String8 getComponentName(String8 &pkgName, String8 &componentName) { @@ -1247,9 +1249,37 @@ int doDump(Bundle* bundle) splitName.string()).string()); } - String8 platformVersionName = AaptXml::getAttribute(tree, NULL, + String8 platformBuildVersionName = AaptXml::getAttribute(tree, NULL, "platformBuildVersionName"); - printf(" platformBuildVersionName='%s'", platformVersionName.string()); + if (platformBuildVersionName != "") { + printf(" platformBuildVersionName='%s'", platformBuildVersionName.string()); + } + + String8 platformBuildVersionCode = AaptXml::getAttribute(tree, NULL, + "platformBuildVersionCode"); + if (platformBuildVersionCode != "") { + printf(" platformBuildVersionCode='%s'", platformBuildVersionCode.string()); + } + + int32_t compileSdkVersion = AaptXml::getIntegerAttribute(tree, + COMPILE_SDK_VERSION_ATTR, &error); + if (error != "") { + SourcePos(manifestFile, tree.getLineNumber()).error( + "ERROR getting 'android:compileSdkVersion' attribute: %s", + error.string()); + goto bail; + } + if (compileSdkVersion > 0) { + printf(" compileSdkVersion='%d'", compileSdkVersion); + } + + String8 compileSdkVersionCodename = AaptXml::getResolvedAttribute(res, tree, + COMPILE_SDK_VERSION_CODENAME_ATTR, &error); + if (compileSdkVersionCodename != "") { + printf(" compileSdkVersionCodename='%s'", ResTable::normalizeForOutput( + compileSdkVersionCodename.string()).string()); + } + printf("\n"); int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree, diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index bd2b2a36788fa..ab6dced5b67d6 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -918,6 +918,22 @@ status_t massageManifest(Bundle* bundle, ResourceTable* table, sp root) } } + + if (bundle->getCompileSdkVersion() != 0) { + if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "compileSdkVersion", + String8::format("%d", bundle->getCompileSdkVersion()), + errorOnFailedInsert, true)) { + return UNKNOWN_ERROR; + } + } + + if (bundle->getCompileSdkVersionCodename() != "") { + if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "compileSdkVersionCodename", + bundle->getCompileSdkVersionCodename(), errorOnFailedInsert, true)) { + return UNKNOWN_ERROR; + } + } + if (bundle->getPlatformBuildVersionCode() != "") { if (!addTagAttribute(root, "", "platformBuildVersionCode", bundle->getPlatformBuildVersionCode(), errorOnFailedInsert, true)) { @@ -1052,7 +1068,12 @@ enum { VERSION_NAME_ATTR = 0x0101021c, }; -static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) { +static ssize_t extractPlatformBuildVersion(const ResTable& table, ResXMLTree& tree, Bundle* bundle) { + // First check if we should be recording the compileSdkVersion* attributes. + static const String16 compileSdkVersionName("android:attr/compileSdkVersion"); + const bool useCompileSdkVersion = table.identifierForName(compileSdkVersionName.string(), + compileSdkVersionName.size()) != 0u; + size_t len; ResXMLTree::event_code_t code; while ((code = tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { @@ -1082,6 +1103,10 @@ static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) { bundle->setPlatformBuildVersionCode(String8::format("%d", versionCode)); } + if (useCompileSdkVersion && versionCode >= 0 && bundle->getCompileSdkVersion() == 0) { + bundle->setCompileSdkVersion(versionCode); + } + String8 versionName = AaptXml::getAttribute(tree, VERSION_NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR: failed to get platform version name\n"); @@ -1091,6 +1116,11 @@ static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) { if (versionName != "" && bundle->getPlatformBuildVersionName() == "") { bundle->setPlatformBuildVersionName(versionName); } + + if (useCompileSdkVersion && versionName != "" + && bundle->getCompileSdkVersionCodename() == "") { + bundle->setCompileSdkVersionCodename(versionName); + } return NO_ERROR; } @@ -1121,7 +1151,7 @@ static ssize_t extractPlatformBuildVersion(AssetManager& assets, Bundle* bundle) fprintf(stderr, "ERROR: Platform AndroidManifest.xml is corrupt\n"); result = UNKNOWN_ERROR; } else { - result = extractPlatformBuildVersion(tree, bundle); + result = extractPlatformBuildVersion(assets.getResources(true), tree, bundle); } } @@ -1707,7 +1737,9 @@ status_t buildResources(Bundle* bundle, const sp& assets, spgetPlatformBuildVersionCode() == "" || - bundle->getPlatformBuildVersionName() == "")) { + bundle->getPlatformBuildVersionName() == "" || + bundle->getCompileSdkVersion() == 0 || + bundle->getCompileSdkVersionCodename() == "")) { err = extractPlatformBuildVersion(assets->getAssetManager(), bundle); if (err != NO_ERROR) { return UNKNOWN_ERROR; diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index d2aebfd31bbf8..13dd93e83b646 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 eaaefd5e099aa..a68df1dbc998d 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 470f65eb01c48..f5715f605b041 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 40085eab97071..1320dcd2a170e 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 4a2181e0b344f..b676efb8d0251 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 b0cf44accafaa..fddb6b8c5d878 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 cf06ba5cc50ed..8f3829611f30e 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;