Loading tools/aapt2/dump/DumpManifest.cpp +37 −0 Original line number Diff line number Diff line Loading @@ -1851,6 +1851,41 @@ class SupportsGlTexture : public ManifestExtractor::Element { } }; /** Represents <property> elements. **/ class Property : public ManifestExtractor::Element { public: Property() = default; std::string name; std::string value; const int* value_int; std::string resource; const int* resource_int; void Extract(xml::Element* element) override { name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), ""); value = GetAttributeStringDefault(FindAttribute(element, VALUE_ATTR), ""); value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR)); resource = GetAttributeStringDefault(FindAttribute(element, RESOURCE_ATTR), ""); resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR)); } void Print(text::Printer* printer) override { printer->Print(StringPrintf("property: name='%s' ", name.data())); if (!value.empty()) { printer->Print(StringPrintf("value='%s' ", value.data())); } else if (value_int) { printer->Print(StringPrintf("value='%d' ", *value_int)); } else { if (!resource.empty()) { printer->Print(StringPrintf("resource='%s' ", resource.data())); } else if (resource_int) { printer->Print(StringPrintf("resource='%d' ", *resource_int)); } } printer->Print("\n"); } }; /** Recursively prints the extracted badging element. */ static void Print(ManifestExtractor::Element* el, text::Printer* printer) { el->Print(printer); Loading Loading @@ -2291,6 +2326,7 @@ T* ElementCast(ManifestExtractor::Element* element) { {"overlay", std::is_base_of<Overlay, T>::value}, {"package-verifier", std::is_base_of<PackageVerifier, T>::value}, {"permission", std::is_base_of<Permission, T>::value}, {"property", std::is_base_of<Property, T>::value}, {"provider", std::is_base_of<Provider, T>::value}, {"receiver", std::is_base_of<Receiver, T>::value}, {"required-feature", std::is_base_of<RequiredFeature, T>::value}, Loading Loading @@ -2344,6 +2380,7 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate( {"overlay", &CreateType<Overlay>}, {"package-verifier", &CreateType<PackageVerifier>}, {"permission", &CreateType<Permission>}, {"property", &CreateType<Property>}, {"provider", &CreateType<Provider>}, {"receiver", &CreateType<Receiver>}, {"required-feature", &CreateType<RequiredFeature>}, Loading tools/aapt2/link/ManifestFixer.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -112,6 +112,27 @@ static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std }; } static xml::XmlNodeAction::ActionFuncWithDiag RequiredOneAndroidAttribute( const std::string& attrName1, const std::string& attrName2) { return [=](xml::Element* el, SourcePathDiagnostics* diag) -> bool { xml::Attribute* attr1 = el->FindAttribute(xml::kSchemaAndroid, attrName1); xml::Attribute* attr2 = el->FindAttribute(xml::kSchemaAndroid, attrName2); if (attr1 == nullptr && attr2 == nullptr) { diag->Error(DiagMessage(el->line_number) << "<" << el->name << "> is missing required attribute 'android:" << attrName1 << "' or 'android:" << attrName2 << "'"); return false; } if (attr1 != nullptr && attr2 != nullptr) { diag->Error(DiagMessage(el->line_number) << "<" << el->name << "> can only specify one of attribute 'android:" << attrName1 << "' or 'android:" << attrName2 << "'"); return false; } return true; }; } static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics* diag) { constexpr const char* kFeatureSplit = "featureSplit"; constexpr const char* kIsFeatureSplit = "isFeatureSplit"; Loading Loading @@ -282,6 +303,10 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, // Common <meta-data> actions. xml::XmlNodeAction meta_data_action; // Common <property> actions. xml::XmlNodeAction property_action; property_action.Action(RequiredOneAndroidAttribute("resource", "value")); // Common <uses-feature> actions. xml::XmlNodeAction uses_feature_action; uses_feature_action.Action(VerifyUsesFeature); Loading @@ -292,6 +317,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, component_action["intent-filter"] = intent_filter_action; component_action["preferred"] = intent_filter_action; component_action["meta-data"] = meta_data_action; component_action["property"] = property_action; // Manifest actions. xml::XmlNodeAction& manifest_action = (*executor)["manifest"]; Loading Loading @@ -427,6 +453,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, application_action["uses-native-library"].Action(RequiredNameIsNotEmpty); application_action["library"].Action(RequiredNameIsNotEmpty); application_action["profileable"]; application_action["property"] = property_action; xml::XmlNodeAction& static_library_action = application_action["static-library"]; static_library_action.Action(RequiredNameIsJavaPackage); Loading tools/aapt2/link/ManifestFixer_test.cpp +74 −0 Original line number Diff line number Diff line Loading @@ -886,4 +886,78 @@ TEST_F(ManifestFixerTest, UsesLibraryMustHaveNonEmptyName) { EXPECT_THAT(Verify(input), NotNull()); } TEST_F(ManifestFixerTest, ApplicationPropertyAttributeRequired) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <property android:name="" /> </application> </manifest>)"; EXPECT_THAT(Verify(input), IsNull()); } TEST_F(ManifestFixerTest, ApplicationPropertyOnlyOneAttributeDefined) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <property android:name="" android:value="" android:resource="" /> </application> </manifest>)"; EXPECT_THAT(Verify(input), IsNull()); input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <property android:name="" android:resource="" /> </application> </manifest>)"; EXPECT_THAT(Verify(input), NotNull()); input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <property android:name="" android:value="" /> </application> </manifest>)"; EXPECT_THAT(Verify(input), NotNull()); } TEST_F(ManifestFixerTest, ComponentPropertyOnlyOneAttributeDefined) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <activity android:name=".MyActivity"> <property android:name="" android:value="" android:resource="" /> </activity> </application> </manifest>)"; EXPECT_THAT(Verify(input), IsNull()); input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <activity android:name=".MyActivity"> <property android:name="" android:value="" /> </activity> </application> </manifest>)"; EXPECT_THAT(Verify(input), NotNull()); input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <activity android:name=".MyActivity"> <property android:name="" android:resource="" /> </activity> </application> </manifest>)"; EXPECT_THAT(Verify(input), NotNull()); } } // namespace aapt Loading
tools/aapt2/dump/DumpManifest.cpp +37 −0 Original line number Diff line number Diff line Loading @@ -1851,6 +1851,41 @@ class SupportsGlTexture : public ManifestExtractor::Element { } }; /** Represents <property> elements. **/ class Property : public ManifestExtractor::Element { public: Property() = default; std::string name; std::string value; const int* value_int; std::string resource; const int* resource_int; void Extract(xml::Element* element) override { name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), ""); value = GetAttributeStringDefault(FindAttribute(element, VALUE_ATTR), ""); value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR)); resource = GetAttributeStringDefault(FindAttribute(element, RESOURCE_ATTR), ""); resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR)); } void Print(text::Printer* printer) override { printer->Print(StringPrintf("property: name='%s' ", name.data())); if (!value.empty()) { printer->Print(StringPrintf("value='%s' ", value.data())); } else if (value_int) { printer->Print(StringPrintf("value='%d' ", *value_int)); } else { if (!resource.empty()) { printer->Print(StringPrintf("resource='%s' ", resource.data())); } else if (resource_int) { printer->Print(StringPrintf("resource='%d' ", *resource_int)); } } printer->Print("\n"); } }; /** Recursively prints the extracted badging element. */ static void Print(ManifestExtractor::Element* el, text::Printer* printer) { el->Print(printer); Loading Loading @@ -2291,6 +2326,7 @@ T* ElementCast(ManifestExtractor::Element* element) { {"overlay", std::is_base_of<Overlay, T>::value}, {"package-verifier", std::is_base_of<PackageVerifier, T>::value}, {"permission", std::is_base_of<Permission, T>::value}, {"property", std::is_base_of<Property, T>::value}, {"provider", std::is_base_of<Provider, T>::value}, {"receiver", std::is_base_of<Receiver, T>::value}, {"required-feature", std::is_base_of<RequiredFeature, T>::value}, Loading Loading @@ -2344,6 +2380,7 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate( {"overlay", &CreateType<Overlay>}, {"package-verifier", &CreateType<PackageVerifier>}, {"permission", &CreateType<Permission>}, {"property", &CreateType<Property>}, {"provider", &CreateType<Provider>}, {"receiver", &CreateType<Receiver>}, {"required-feature", &CreateType<RequiredFeature>}, Loading
tools/aapt2/link/ManifestFixer.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -112,6 +112,27 @@ static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std }; } static xml::XmlNodeAction::ActionFuncWithDiag RequiredOneAndroidAttribute( const std::string& attrName1, const std::string& attrName2) { return [=](xml::Element* el, SourcePathDiagnostics* diag) -> bool { xml::Attribute* attr1 = el->FindAttribute(xml::kSchemaAndroid, attrName1); xml::Attribute* attr2 = el->FindAttribute(xml::kSchemaAndroid, attrName2); if (attr1 == nullptr && attr2 == nullptr) { diag->Error(DiagMessage(el->line_number) << "<" << el->name << "> is missing required attribute 'android:" << attrName1 << "' or 'android:" << attrName2 << "'"); return false; } if (attr1 != nullptr && attr2 != nullptr) { diag->Error(DiagMessage(el->line_number) << "<" << el->name << "> can only specify one of attribute 'android:" << attrName1 << "' or 'android:" << attrName2 << "'"); return false; } return true; }; } static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics* diag) { constexpr const char* kFeatureSplit = "featureSplit"; constexpr const char* kIsFeatureSplit = "isFeatureSplit"; Loading Loading @@ -282,6 +303,10 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, // Common <meta-data> actions. xml::XmlNodeAction meta_data_action; // Common <property> actions. xml::XmlNodeAction property_action; property_action.Action(RequiredOneAndroidAttribute("resource", "value")); // Common <uses-feature> actions. xml::XmlNodeAction uses_feature_action; uses_feature_action.Action(VerifyUsesFeature); Loading @@ -292,6 +317,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, component_action["intent-filter"] = intent_filter_action; component_action["preferred"] = intent_filter_action; component_action["meta-data"] = meta_data_action; component_action["property"] = property_action; // Manifest actions. xml::XmlNodeAction& manifest_action = (*executor)["manifest"]; Loading Loading @@ -427,6 +453,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, application_action["uses-native-library"].Action(RequiredNameIsNotEmpty); application_action["library"].Action(RequiredNameIsNotEmpty); application_action["profileable"]; application_action["property"] = property_action; xml::XmlNodeAction& static_library_action = application_action["static-library"]; static_library_action.Action(RequiredNameIsJavaPackage); Loading
tools/aapt2/link/ManifestFixer_test.cpp +74 −0 Original line number Diff line number Diff line Loading @@ -886,4 +886,78 @@ TEST_F(ManifestFixerTest, UsesLibraryMustHaveNonEmptyName) { EXPECT_THAT(Verify(input), NotNull()); } TEST_F(ManifestFixerTest, ApplicationPropertyAttributeRequired) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <property android:name="" /> </application> </manifest>)"; EXPECT_THAT(Verify(input), IsNull()); } TEST_F(ManifestFixerTest, ApplicationPropertyOnlyOneAttributeDefined) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <property android:name="" android:value="" android:resource="" /> </application> </manifest>)"; EXPECT_THAT(Verify(input), IsNull()); input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <property android:name="" android:resource="" /> </application> </manifest>)"; EXPECT_THAT(Verify(input), NotNull()); input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <property android:name="" android:value="" /> </application> </manifest>)"; EXPECT_THAT(Verify(input), NotNull()); } TEST_F(ManifestFixerTest, ComponentPropertyOnlyOneAttributeDefined) { std::string input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <activity android:name=".MyActivity"> <property android:name="" android:value="" android:resource="" /> </activity> </application> </manifest>)"; EXPECT_THAT(Verify(input), IsNull()); input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <activity android:name=".MyActivity"> <property android:name="" android:value="" /> </activity> </application> </manifest>)"; EXPECT_THAT(Verify(input), NotNull()); input = R"( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"> <application> <activity android:name=".MyActivity"> <property android:name="" android:resource="" /> </activity> </application> </manifest>)"; EXPECT_THAT(Verify(input), NotNull()); } } // namespace aapt