/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "link/ManifestFixer.h" #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 { struct ManifestFixerTest : public ::testing::Test { std::unique_ptr mContext; void SetUp() override { mContext = test::ContextBuilder() .SetCompilationPackage("android") .SetPackageId(0x01) .SetNameManglerPolicy(NameManglerPolicy{"android"}) .AddSymbolSource( test::StaticSymbolSourceBuilder() .AddSymbol( "android:attr/package", ResourceId(0x01010000), test::AttributeBuilder() .SetTypeMask(android::ResTable_map::TYPE_STRING) .Build()) .AddSymbol( "android:attr/minSdkVersion", ResourceId(0x01010001), test::AttributeBuilder() .SetTypeMask(android::ResTable_map::TYPE_STRING | android::ResTable_map::TYPE_INTEGER) .Build()) .AddSymbol( "android:attr/targetSdkVersion", ResourceId(0x01010002), test::AttributeBuilder() .SetTypeMask(android::ResTable_map::TYPE_STRING | android::ResTable_map::TYPE_INTEGER) .Build()) .AddSymbol("android:string/str", ResourceId(0x01060000)) .Build()) .Build(); } std::unique_ptr Verify(const StringPiece& str) { return VerifyWithOptions(str, {}); } std::unique_ptr VerifyWithOptions( const StringPiece& str, const ManifestFixerOptions& options) { std::unique_ptr doc = test::BuildXmlDom(str); ManifestFixer fixer(options); if (fixer.Consume(mContext.get(), doc.get())) { return doc; } return {}; } }; TEST_F(ManifestFixerTest, EnsureManifestIsRootTag) { EXPECT_THAT(Verify(""), IsNull()); EXPECT_THAT(Verify(""), IsNull()); EXPECT_THAT(Verify(""), NotNull()); } TEST_F(ManifestFixerTest, EnsureManifestHasPackage) { 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) { auto doc = Verify(R"EOF( )EOF"); ASSERT_THAT(doc, NotNull()); } TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) { ManifestFixerOptions options; options.min_sdk_version_default = std::string("8"); options.target_sdk_version_default = std::string("22"); std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* el; xml::Attribute* attr; el = doc->root.get(); ASSERT_THAT(el, NotNull()); el = el->FindChild({}, "uses-sdk"); ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("7")); attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("21")); doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); el = doc->root.get(); ASSERT_THAT(el, NotNull()); el = el->FindChild({}, "uses-sdk"); ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("8")); attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("21")); doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); el = doc->root.get(); ASSERT_THAT(el, NotNull()); el = el->FindChild({}, "uses-sdk"); ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("8")); attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("22")); doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); el = doc->root.get(); ASSERT_THAT(el, NotNull()); el = el->FindChild({}, "uses-sdk"); ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("8")); attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("22")); } TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) { ManifestFixerOptions options; options.min_sdk_version_default = std::string("8"); options.target_sdk_version_default = std::string("22"); std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); ASSERT_THAT(manifest_el, NotNull()); ASSERT_EQ("manifest", manifest_el->name); xml::Element* application_el = manifest_el->FindChild("", "application"); ASSERT_THAT(application_el, NotNull()); xml::Element* uses_sdk_el = manifest_el->FindChild("", "uses-sdk"); ASSERT_THAT(uses_sdk_el, NotNull()); // Check that the uses_sdk_el comes before application_el in the children // vector. // Since there are no namespaces here, these children are direct descendants // of manifest. auto uses_sdk_iter = std::find_if(manifest_el->children.begin(), manifest_el->children.end(), [&](const std::unique_ptr& child) { return child.get() == uses_sdk_el; }); auto application_iter = std::find_if(manifest_el->children.begin(), manifest_el->children.end(), [&](const std::unique_ptr& child) { return child.get() == application_el; }); 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_THAT(std::distance(uses_sdk_iter, application_iter), Gt(0)); } TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) { ManifestFixerOptions options; options.rename_manifest_package = std::string("com.android"); std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); ASSERT_THAT(manifest_el, NotNull()); xml::Attribute* attr = nullptr; attr = manifest_el->FindAttribute({}, "package"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("com.android")); xml::Element* uses_split_el = manifest_el->FindChild({}, "uses-split"); ASSERT_THAT(uses_split_el, NotNull()); attr = uses_split_el->FindAttribute(xml::kSchemaAndroid, "name"); 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_THAT(application_el, NotNull()); attr = application_el->FindAttribute(xml::kSchemaAndroid, "name"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("android.MainApplication")); attr = application_el->FindAttribute({}, "text"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("hello")); xml::Element* el; el = application_el->FindChild({}, "activity"); ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "name"); ASSERT_THAT(el, NotNull()); EXPECT_THAT(attr->value, StrEq("android.activity.Start")); el = application_el->FindChild({}, "receiver"); ASSERT_THAT(el, NotNull()); attr = el->FindAttribute(xml::kSchemaAndroid, "name"); ASSERT_THAT(el, NotNull()); EXPECT_THAT(attr->value, StrEq("com.google.android.Receiver")); } TEST_F(ManifestFixerTest, RenameManifestInstrumentationPackageAndFullyQualifyTarget) { ManifestFixerOptions options; options.rename_instrumentation_target_package = std::string("com.android"); std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); ASSERT_THAT(manifest_el, NotNull()); xml::Element* instrumentation_el = manifest_el->FindChild({}, "instrumentation"); ASSERT_THAT(instrumentation_el, NotNull()); xml::Attribute* attr = instrumentation_el->FindAttribute(xml::kSchemaAndroid, "targetPackage"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("com.android")); } TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) { ManifestFixerOptions options; options.version_name_default = std::string("Beta"); options.version_code_default = std::string("0x10000000"); options.version_code_major_default = std::string("0x20000000"); std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); ASSERT_THAT(manifest_el, NotNull()); xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("Beta")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x10000000")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x20000000")); } TEST_F(ManifestFixerTest, DontUseDefaultVersionNameAndCode) { ManifestFixerOptions options; options.version_name_default = std::string("Beta"); options.version_code_default = std::string("0x10000000"); options.version_code_major_default = std::string("0x20000000"); std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); ASSERT_THAT(manifest_el, NotNull()); xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("Alpha")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x00000001")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x00000002")); } TEST_F(ManifestFixerTest, ReplaceVersionNameAndCode) { ManifestFixerOptions options; options.replace_version = true; options.version_name_default = std::string("Beta"); options.version_code_default = std::string("0x10000000"); options.version_code_major_default = std::string("0x20000000"); std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); ASSERT_THAT(manifest_el, NotNull()); xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("Beta")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x10000000")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x20000000")); } TEST_F(ManifestFixerTest, ReplaceVersionName) { ManifestFixerOptions options; options.replace_version = true; options.version_name_default = std::string("Beta"); std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); ASSERT_THAT(manifest_el, NotNull()); xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("Beta")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x00000001")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x00000002")); } TEST_F(ManifestFixerTest, ReplaceVersionCode) { ManifestFixerOptions options; options.replace_version = true; options.version_code_default = std::string("0x10000000"); std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); ASSERT_THAT(manifest_el, NotNull()); xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("Alpha")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x10000000")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x00000002")); } TEST_F(ManifestFixerTest, ReplaceVersionCodeMajor) { ManifestFixerOptions options; options.replace_version = true; options.version_code_major_default = std::string("0x20000000"); std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); ASSERT_THAT(manifest_el, NotNull()); xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("Alpha")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x00000001")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x20000000")); } TEST_F(ManifestFixerTest, DontReplaceVersionNameOrCode) { ManifestFixerOptions options; options.replace_version = true; std::unique_ptr doc = VerifyWithOptions(R"EOF( )EOF", options); ASSERT_THAT(doc, NotNull()); xml::Element* manifest_el = doc->root.get(); ASSERT_THAT(manifest_el, NotNull()); xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("Alpha")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x00000001")); attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("0x00000002")); } TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) { EXPECT_THAT(Verify(""), IsNull()); EXPECT_THAT(Verify(""), IsNull()); std::unique_ptr doc = Verify(""); ASSERT_THAT(doc, NotNull()); xml::Element* el = doc->root.get(); ASSERT_THAT(el, NotNull()); EXPECT_THAT(el->name, StrEq("manifest")); xml::Attribute* attr = el->FindAttribute("", "coreApp"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->compiled_value, NotNull()); EXPECT_THAT(ValueCast(attr->compiled_value.get()), NotNull()); } TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) { std::string input = R"EOF( )EOF"; EXPECT_THAT(Verify(input), NotNull()); input = R"EOF( )EOF"; EXPECT_THAT(Verify(input), IsNull()); input = R"EOF( )EOF"; EXPECT_THAT(Verify(input), IsNull()); input = R"EOF( )EOF"; EXPECT_THAT(Verify(input), IsNull()); input = R"EOF( )EOF"; EXPECT_THAT(Verify(input), IsNull()); } TEST_F(ManifestFixerTest, ApplicationInjectDebuggable) { ManifestFixerOptions options; options.debug_mode = true; std::string no_d = R"( )"; std::string false_d = R"( )"; std::string true_d = R"( )"; // Inject the debuggable attribute when the attribute is not present and the // flag is present std::unique_ptr manifest = VerifyWithOptions(no_d, options); EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( {}, "application", xml::kSchemaAndroid, "debuggable", "true"), NotNull()); // Set the debuggable flag to true if the attribute is false and the flag is // present manifest = VerifyWithOptions(false_d, options); EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( {}, "application", xml::kSchemaAndroid, "debuggable", "true"), NotNull()); // Keep debuggable flag true if the attribute is true and the flag is present manifest = VerifyWithOptions(true_d, options); EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( {}, "application", xml::kSchemaAndroid, "debuggable", "true"), NotNull()); // Do not inject the debuggable attribute when the attribute is not present // and the flag is not present manifest = Verify(no_d); EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( {}, "application", xml::kSchemaAndroid, "debuggable", "true"), IsNull()); // Do not set the debuggable flag to true if the attribute is false and the // flag is not present manifest = Verify(false_d); EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( {}, "application", xml::kSchemaAndroid, "debuggable", "true"), IsNull()); // Keep debuggable flag true if the attribute is true and the flag is not // present manifest = Verify(true_d); EXPECT_THAT(manifest->root.get()->FindChildWithAttribute( {}, "application", xml::kSchemaAndroid, "debuggable", "true"), NotNull()); } TEST_F(ManifestFixerTest, ApplicationProfileable) { std::string shell = R"( )"; EXPECT_THAT(Verify(shell), NotNull()); std::string noshell = R"( )"; EXPECT_THAT(Verify(noshell), NotNull()); } TEST_F(ManifestFixerTest, IgnoreNamespacedElements) { std::string input = R"EOF( )EOF"; EXPECT_THAT(Verify(input), NotNull()); } TEST_F(ManifestFixerTest, DoNotIgnoreNonNamespacedElements) { std::string input = R"EOF( )EOF"; EXPECT_THAT(Verify(input), IsNull()); } TEST_F(ManifestFixerTest, SupportKeySets) { std::string input = R"( )"; 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")); attr = manifest->root->FindAttribute("", "platformBuildVersionCode"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("28")); attr = manifest->root->FindAttribute("", "platformBuildVersionName"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("P")); } TEST_F(ManifestFixerTest, OverrideCompileSdkVersions) { 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")); attr = manifest->root->FindAttribute("", "platformBuildVersionCode"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("28")); attr = manifest->root->FindAttribute("", "platformBuildVersionName"); ASSERT_THAT(attr, NotNull()); EXPECT_THAT(attr->value, StrEq("P")); } TEST_F(ManifestFixerTest, UnexpectedElementsInManifest) { std::string input = R"( )"; ManifestFixerOptions options; options.warn_validation = true; // Unexpected element should result in a warning if the flag is set to 'true'. std::unique_ptr manifest = VerifyWithOptions(input, options); ASSERT_THAT(manifest, NotNull()); // Unexpected element should result in an error if the flag is set to 'false'. options.warn_validation = false; manifest = VerifyWithOptions(input, options); ASSERT_THAT(manifest, IsNull()); // By default the flag should be set to 'false'. manifest = Verify(input); ASSERT_THAT(manifest, IsNull()); } TEST_F(ManifestFixerTest, UsesLibraryMustHaveNonEmptyName) { std::string input = R"( )"; EXPECT_THAT(Verify(input), IsNull()); input = R"( )"; EXPECT_THAT(Verify(input), IsNull()); input = R"( )"; EXPECT_THAT(Verify(input), NotNull()); } } // namespace aapt