diff options
-rw-r--r-- | tools/aapt/Bundle.h | 7 | ||||
-rw-r--r-- | tools/aapt/Command.cpp | 34 | ||||
-rw-r--r-- | tools/aapt/Resource.cpp | 38 | ||||
-rw-r--r-- | tools/aapt2/cmd/Link.cpp | 104 | ||||
-rw-r--r-- | tools/aapt2/link/ManifestFixer.cpp | 19 | ||||
-rw-r--r-- | tools/aapt2/link/ManifestFixer.h | 32 | ||||
-rw-r--r-- | tools/aapt2/link/ManifestFixer_test.cpp | 211 | ||||
-rw-r--r-- | tools/aapt2/process/SymbolTable.h | 4 | ||||
-rw-r--r-- | tools/aapt2/xml/XmlDom.cpp | 9 | ||||
-rw-r--r-- | tools/aapt2/xml/XmlDom.h | 2 |
10 files changed, 350 insertions, 110 deletions
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index a93ee2e2b71d..deb9cc083eb0 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 cb87737c6868..05375b0cb871 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 bd2b2a36788f..ab6dced5b67d 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -918,6 +918,22 @@ status_t massageManifest(Bundle* bundle, ResourceTable* table, sp<XMLNode> 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<AaptAssets>& assets, sp<ApkBuil // extract them from the platform APK. if (packageType != ResourceTable::System && (bundle->getPlatformBuildVersionCode() == "" || - 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 d2aebfd31bbf..13dd93e83b64 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -15,6 +15,7 @@ */ #include <sys/stat.h> +#include <cinttypes> #include <queue> #include <unordered_map> @@ -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<io::FileCollection>()) { } + 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<Asset> manifest( + assets->openNonAsset(cookie, kAndroidManifestPath, Asset::AccessMode::ACCESS_BUFFER)); + if (manifest == nullptr) { + // No errors. + return; + } + + std::string error; + std::unique_ptr<xml::XmlResource> 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<std::string>& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version; + if (BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get())) { + switch (prim->value.dataType) { + case Res_value::TYPE_INT_DEC: + compile_sdk_version = StringPrintf("%" PRId32, static_cast<int32_t>(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<String>(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<std::string>& compile_sdk_version_codename = + options_.manifest_fixer_options.compile_sdk_version_codename; + if (String* str = ValueCast<String>(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<AssetManagerSymbolSource>(); 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<SymbolTable::Symbol> 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<TableMerger>(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 <uses-sdk> tag. Maybe<std::string> min_sdk_version_default; + + // The target SDK version to set if no 'android:targetSdkVersion' is defined in a <uses-sdk> tag. Maybe<std::string> target_sdk_version_default; + + // The Android package to use instead of the one defined in 'package' in <manifest>. + // This also renames all relative package/class names in the manifest to fully qualified + // Java names. Maybe<std::string> rename_manifest_package; + + // The Android package to use instead of the one defined in 'android:targetPackage' in + // <instrumentation>. Maybe<std::string> rename_instrumentation_target_package; + + // The version name to set if 'android:versionName' is not defined in <manifest>. Maybe<std::string> version_name_default; + + // The version code to set if 'android:versionCode' is not defined in <manifest>. Maybe<std::string> version_code_default; + + // The version of the framework being compiled against to set for 'android:compileSdkVersion' in + // the <manifest> tag. + Maybe<std::string> compile_sdk_version; + + // The version codename of the framework being compiled against to set for + // 'android:compileSdkVersionCodename' in the <manifest> tag. + Maybe<std::string> 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("<other-tag />")); - EXPECT_EQ(nullptr, Verify("<ns:manifest xmlns:ns=\"com\" />")); - EXPECT_NE(nullptr, Verify("<manifest package=\"android\"></manifest>")); + EXPECT_THAT(Verify("<other-tag />"), IsNull()); + EXPECT_THAT(Verify("<ns:manifest xmlns:ns=\"com\" />"), IsNull()); + EXPECT_THAT(Verify("<manifest package=\"android\"></manifest>"), NotNull()); } TEST_F(ManifestFixerTest, EnsureManifestHasPackage) { - EXPECT_NE(nullptr, Verify("<manifest package=\"android\" />")); - EXPECT_NE(nullptr, Verify("<manifest package=\"com.android\" />")); - EXPECT_NE(nullptr, Verify("<manifest package=\"com.android.google\" />")); - EXPECT_EQ(nullptr, - Verify("<manifest package=\"com.android.google.Class$1\" />")); - EXPECT_EQ(nullptr, Verify("<manifest " - "xmlns:android=\"http://schemas.android.com/apk/" - "res/android\" " - "android:package=\"com.android\" />")); - EXPECT_EQ(nullptr, Verify("<manifest package=\"@string/str\" />")); + EXPECT_THAT(Verify("<manifest package=\"android\" />"), NotNull()); + EXPECT_THAT(Verify("<manifest package=\"com.android\" />"), NotNull()); + EXPECT_THAT(Verify("<manifest package=\"com.android.google\" />"), NotNull()); + EXPECT_THAT(Verify("<manifest package=\"com.android.google.Class$1\" />"), IsNull()); + EXPECT_THAT(Verify("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" " + "android:package=\"com.android\" />"), + IsNull()); + EXPECT_THAT(Verify("<manifest package=\"@string/str\" />"), IsNull()); } TEST_F(ManifestFixerTest, AllowMetaData) { @@ -105,7 +108,7 @@ TEST_F(ManifestFixerTest, AllowMetaData) { </application> <instrumentation android:name=".Go"><meta-data /></instrumentation> </manifest>)EOF"); - ASSERT_NE(nullptr, doc); + ASSERT_THAT(doc, NotNull()); } TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) { @@ -117,21 +120,21 @@ TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) { <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" /> </manifest>)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( <manifest xmlns:android="http://schemas.android.com/apk/res/android" @@ -139,18 +142,18 @@ TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) { <uses-sdk android:targetSdkVersion="21" /> </manifest>)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( <manifest xmlns:android="http://schemas.android.com/apk/res/android" @@ -158,35 +161,35 @@ TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) { <uses-sdk /> </manifest>)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( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" />)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) { <application android:name=".MainApplication" /> </manifest>)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) { </application> </manifest>)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, <instrumentation android:name=".TestRunner" android:targetPackage="android" /> </manifest>)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) { <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" />)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("<manifest package=\"android\" coreApp=\"hello\" />")); - EXPECT_EQ(nullptr, - Verify("<manifest package=\"android\" coreApp=\"1dp\" />")); + EXPECT_THAT(Verify("<manifest package=\"android\" coreApp=\"hello\" />"), IsNull()); + EXPECT_THAT(Verify("<manifest package=\"android\" coreApp=\"1dp\" />"), IsNull()); std::unique_ptr<xml::XmlResource> doc = Verify("<manifest package=\"android\" coreApp=\"true\" />"); - 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<BinaryPrimitive>(attr->compiled_value.get())); + EXPECT_THAT(attr->compiled_value, NotNull()); + EXPECT_THAT(ValueCast<BinaryPrimitive>(attr->compiled_value.get()), NotNull()); } TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) { @@ -375,21 +377,21 @@ TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) { <uses-feature android:glEsVersion="2" /> </feature-group> </manifest>)EOF"; - EXPECT_NE(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), NotNull()); input = R"EOF( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <uses-feature android:name="feature" android:glEsVersion="1" /> </manifest>)EOF"; - EXPECT_EQ(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), IsNull()); input = R"EOF( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <uses-feature /> </manifest>)EOF"; - EXPECT_EQ(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), IsNull()); input = R"EOF( <manifest xmlns:android="http://schemas.android.com/apk/res/android" @@ -398,7 +400,7 @@ TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) { <uses-feature android:name="feature" android:glEsVersion="1" /> </feature-group> </manifest>)EOF"; - EXPECT_EQ(nullptr, Verify(input)); + EXPECT_THAT(Verify(input), IsNull()); input = R"EOF( <manifest xmlns:android="http://schemas.android.com/apk/res/android" @@ -407,7 +409,7 @@ TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) { <uses-feature /> </feature-group> </manifest>)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"> <special:tag whoo="true" xmlns:special="http://google.com" /> </manifest>)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"> <tag whoo="true" /> </manifest>)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"( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" />)"; + ManifestFixerOptions options; + options.compile_sdk_version = {"28"}; + options.compile_sdk_version_codename = {"P"}; + + std::unique_ptr<xml::XmlResource> 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<SymbolTable::Symbol> 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; |