Loading tools/aapt2/cmd/Link.cpp +11 −6 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ struct LinkOptions { Maybe<std::string> generate_text_symbols_path; Maybe<std::string> generate_proguard_rules_path; Maybe<std::string> generate_main_dex_proguard_rules_path; bool generate_conditional_proguard_rules = false; bool generate_non_final_ids = false; std::vector<std::string> javadoc_annotations; Maybe<std::string> private_symbols; Loading Loading @@ -499,7 +500,7 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer return {}; } if (options_.update_proguard_spec && !proguard::CollectProguardRules(src, doc, keep_set_)) { if (options_.update_proguard_spec && !proguard::CollectProguardRules(doc, keep_set_)) { return {}; } Loading Loading @@ -538,6 +539,8 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv bool error = false; std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> config_sorted_files; proguard::CollectResourceReferences(context_, table, keep_set_); for (auto& pkg : table->packages) { CHECK(!pkg->name.empty()) << "Packages must have names when being linked"; Loading Loading @@ -1719,7 +1722,8 @@ class LinkCommand { } } proguard::KeepSet proguard_keep_set; proguard::KeepSet proguard_keep_set = proguard::KeepSet(options_.generate_conditional_proguard_rules); proguard::KeepSet proguard_main_dex_keep_set; if (context_->GetPackageType() == PackageType::kStaticLib) { Loading Loading @@ -1795,14 +1799,12 @@ class LinkCommand { XmlReferenceLinker manifest_linker; if (manifest_linker.Consume(context_, manifest_xml.get())) { if (options_.generate_proguard_rules_path && !proguard::CollectProguardRulesForManifest(Source(options_.manifest_path), manifest_xml.get(), &proguard_keep_set)) { !proguard::CollectProguardRulesForManifest(manifest_xml.get(), &proguard_keep_set)) { error = true; } if (options_.generate_main_dex_proguard_rules_path && !proguard::CollectProguardRulesForManifest(Source(options_.manifest_path), manifest_xml.get(), !proguard::CollectProguardRulesForManifest(manifest_xml.get(), &proguard_main_dex_keep_set, true)) { error = true; } Loading Loading @@ -1919,6 +1921,9 @@ int Link(const std::vector<StringPiece>& args, IDiagnostics* diagnostics) { .OptionalFlag("--proguard-main-dex", "Output file for generated Proguard rules for the main dex.", &options.generate_main_dex_proguard_rules_path) .OptionalSwitch("--proguard-conditional-keep-rules", "Generate conditional Proguard keep rules.", &options.generate_conditional_proguard_rules) .OptionalSwitch("--no-auto-version", "Disables automatic style and layout SDK versioning.", &options.no_auto_version) Loading tools/aapt2/java/JavaClassGenerator.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -61,7 +61,7 @@ static bool IsValidSymbol(const StringPiece& symbol) { // Java symbols can not contain . or -, but those are valid in a resource name. // Replace those with '_'. static std::string TransformToFieldName(const StringPiece& symbol) { std::string JavaClassGenerator::TransformToFieldName(const StringPiece& symbol) { std::string output = symbol.to_string(); for (char& c : output) { if (c == '.' || c == '-') { Loading Loading @@ -89,9 +89,9 @@ static std::string TransformNestedAttr(const ResourceNameRef& attr_name, // the package. if (!attr_name.package.empty() && package_name_to_generate != attr_name.package) { output += "_" + TransformToFieldName(attr_name.package); output += "_" + JavaClassGenerator::TransformToFieldName(attr_name.package); } output += "_" + TransformToFieldName(attr_name.entry); output += "_" + JavaClassGenerator::TransformToFieldName(attr_name.entry); return output; } Loading tools/aapt2/java/JavaClassGenerator.h +3 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include "ResourceTable.h" #include "ResourceValues.h" #include "androidfw/StringPiece.h" #include "process/IResourceTableConsumer.h" #include "process/SymbolTable.h" Loading Loading @@ -78,6 +79,8 @@ class JavaClassGenerator { const std::string& getError() const; static std::string TransformToFieldName(const android::StringPiece& symbol); private: bool SkipSymbol(SymbolState state); bool SkipSymbol(const Maybe<SymbolTable::Symbol>& symbol); Loading tools/aapt2/java/ProguardRules.cpp +147 −27 Original line number Diff line number Diff line Loading @@ -21,6 +21,10 @@ #include "android-base/macros.h" #include "JavaClassGenerator.h" #include "ResourceUtils.h" #include "ValueVisitor.h" #include "androidfw/StringPiece.h" #include "util/Util.h" #include "xml/XmlDom.h" Loading @@ -31,7 +35,7 @@ class BaseVisitor : public xml::Visitor { public: using xml::Visitor::Visit; BaseVisitor(const Source& source, KeepSet* keep_set) : source_(source), keep_set_(keep_set) { BaseVisitor(const ResourceFile& file, KeepSet* keep_set) : file_(file), keep_set_(keep_set) { } void Visit(xml::Element* node) override { Loading @@ -52,27 +56,47 @@ class BaseVisitor : public xml::Visitor { for (const auto& child : node->children) { child->Accept(this); } for (const auto& attr : node->attributes) { if (attr.compiled_value) { auto ref = ValueCast<Reference>(attr.compiled_value.get()); if (ref) { AddReference(node->line_number, ref); } } } } protected: void AddClass(size_t line_number, const std::string& class_name) { keep_set_->AddClass(Source(source_.path, line_number), class_name); ResourceFile file_; KeepSet* keep_set_; virtual void AddClass(size_t line_number, const std::string& class_name) { keep_set_->AddConditionalClass({file_.name, file_.source.WithLine(line_number)}, class_name); } void AddMethod(size_t line_number, const std::string& method_name) { keep_set_->AddMethod(Source(source_.path, line_number), method_name); keep_set_->AddMethod({file_.name, file_.source.WithLine(line_number)}, method_name); } void AddReference(size_t line_number, Reference* ref) { if (ref && ref->name) { ResourceName ref_name = ref->name.value(); if (ref_name.package.empty()) { ref_name = ResourceName(file_.name.package, ref_name.type, ref_name.entry); } keep_set_->AddReference({file_.name, file_.source.WithLine(line_number)}, ref_name); } } private: DISALLOW_COPY_AND_ASSIGN(BaseVisitor); Source source_; KeepSet* keep_set_; }; class LayoutVisitor : public BaseVisitor { public: LayoutVisitor(const Source& source, KeepSet* keep_set) : BaseVisitor(source, keep_set) { LayoutVisitor(const ResourceFile& file, KeepSet* keep_set) : BaseVisitor(file, keep_set) { } void Visit(xml::Element* node) override { Loading Loading @@ -110,7 +134,7 @@ class LayoutVisitor : public BaseVisitor { class MenuVisitor : public BaseVisitor { public: MenuVisitor(const Source& source, KeepSet* keep_set) : BaseVisitor(source, keep_set) { MenuVisitor(const ResourceFile& file, KeepSet* keep_set) : BaseVisitor(file, keep_set) { } void Visit(xml::Element* node) override { Loading @@ -136,7 +160,7 @@ class MenuVisitor : public BaseVisitor { class XmlResourceVisitor : public BaseVisitor { public: XmlResourceVisitor(const Source& source, KeepSet* keep_set) : BaseVisitor(source, keep_set) { XmlResourceVisitor(const ResourceFile& file, KeepSet* keep_set) : BaseVisitor(file, keep_set) { } void Visit(xml::Element* node) override { Loading @@ -163,7 +187,7 @@ class XmlResourceVisitor : public BaseVisitor { class TransitionVisitor : public BaseVisitor { public: TransitionVisitor(const Source& source, KeepSet* keep_set) : BaseVisitor(source, keep_set) { TransitionVisitor(const ResourceFile& file, KeepSet* keep_set) : BaseVisitor(file, keep_set) { } void Visit(xml::Element* node) override { Loading @@ -185,8 +209,9 @@ class TransitionVisitor : public BaseVisitor { class ManifestVisitor : public BaseVisitor { public: ManifestVisitor(const Source& source, KeepSet* keep_set, bool main_dex_only) : BaseVisitor(source, keep_set), main_dex_only_(main_dex_only) {} ManifestVisitor(const ResourceFile& file, KeepSet* keep_set, bool main_dex_only) : BaseVisitor(file, keep_set), main_dex_only_(main_dex_only) { } void Visit(xml::Element* node) override { if (node->namespace_uri.empty()) { Loading Loading @@ -241,6 +266,10 @@ class ManifestVisitor : public BaseVisitor { BaseVisitor::Visit(node); } virtual void AddClass(size_t line_number, const std::string& class_name) override { keep_set_->AddManifestClass({file_.name, file_.source.WithLine(line_number)}, class_name); } private: DISALLOW_COPY_AND_ASSIGN(ManifestVisitor); Loading @@ -249,9 +278,8 @@ class ManifestVisitor : public BaseVisitor { std::string default_process_; }; bool CollectProguardRulesForManifest(const Source& source, xml::XmlResource* res, KeepSet* keep_set, bool main_dex_only) { ManifestVisitor visitor(source, keep_set, main_dex_only); bool CollectProguardRulesForManifest(xml::XmlResource* res, KeepSet* keep_set, bool main_dex_only) { ManifestVisitor visitor(res->file, keep_set, main_dex_only); if (res->root) { res->root->Accept(&visitor); return true; Loading @@ -259,58 +287,150 @@ bool CollectProguardRulesForManifest(const Source& source, xml::XmlResource* res return false; } bool CollectProguardRules(const Source& source, xml::XmlResource* res, KeepSet* keep_set) { bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set) { if (!res->root) { return false; } switch (res->file.name.type) { case ResourceType::kLayout: { LayoutVisitor visitor(source, keep_set); LayoutVisitor visitor(res->file, keep_set); res->root->Accept(&visitor); break; } case ResourceType::kXml: { XmlResourceVisitor visitor(source, keep_set); XmlResourceVisitor visitor(res->file, keep_set); res->root->Accept(&visitor); break; } case ResourceType::kTransition: { TransitionVisitor visitor(source, keep_set); TransitionVisitor visitor(res->file, keep_set); res->root->Accept(&visitor); break; } case ResourceType::kMenu: { MenuVisitor visitor(source, keep_set); MenuVisitor visitor(res->file, keep_set); res->root->Accept(&visitor); break; } default: default: { BaseVisitor visitor(res->file, keep_set); res->root->Accept(&visitor); break; } } return true; } bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set) { for (const auto& entry : keep_set.keep_set_) { for (const Source& source : entry.second) { *out << "# Referenced at " << source << "\n"; for (const auto& entry : keep_set.manifest_class_set_) { for (const UsageLocation& location : entry.second) { *out << "# Referenced at " << location.source << "\n"; } *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl; } for (const auto& entry : keep_set.keep_method_set_) { for (const Source& source : entry.second) { *out << "# Referenced at " << source << "\n"; for (const auto& entry : keep_set.conditional_class_set_) { std::set<UsageLocation> locations; bool can_be_conditional = true; for (const UsageLocation& location : entry.second) { can_be_conditional &= CollectLocations(location, keep_set, &locations); } for (const UsageLocation& location : entry.second) { *out << "# Referenced at " << location.source << "\n"; } if (keep_set.conditional_keep_rules_ && can_be_conditional) { *out << "-keep class " << entry.first << " {\n ifused class **.R$layout {\n"; for (const UsageLocation& location : locations) { auto transformed_name = JavaClassGenerator::TransformToFieldName(location.name.entry); *out << " int " << transformed_name << ";\n"; } *out << " };\n <init>(...);\n}\n" << std::endl; } else { *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl; } } for (const auto& entry : keep_set.method_set_) { for (const UsageLocation& location : entry.second) { *out << "# Referenced at " << location.source << "\n"; } *out << "-keepclassmembers class * { *** " << entry.first << "(...); }\n" << std::endl; } return true; } bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set, std::set<UsageLocation>* locations) { locations->insert(location); // TODO: allow for more reference types if we can determine its safe. if (location.name.type != ResourceType::kLayout) { return false; } for (const auto& entry : keep_set.reference_set_) { if (entry.first == location.name) { for (auto& refLocation : entry.second) { // Don't get stuck in loops if (locations->find(refLocation) != locations->end()) { return false; } if (!CollectLocations(refLocation, keep_set, locations)) { return false; } } } } return true; } class ReferenceVisitor : public ValueVisitor { public: using ValueVisitor::Visit; ReferenceVisitor(aapt::IAaptContext* context, ResourceName from, KeepSet* keep_set) : context_(context), from_(from), keep_set_(keep_set) { } void Visit(Reference* reference) override { if (reference->name) { ResourceName reference_name = reference->name.value(); if (reference_name.package.empty()) { reference_name = ResourceName(context_->GetCompilationPackage(), reference_name.type, reference_name.entry); } keep_set_->AddReference({from_, reference->GetSource()}, reference_name); } } private: aapt::IAaptContext* context_; ResourceName from_; KeepSet* keep_set_; }; bool CollectResourceReferences(aapt::IAaptContext* context, ResourceTable* table, KeepSet* keep_set) { for (auto& pkg : table->packages) { for (auto& type : pkg->types) { for (auto& entry : type->entries) { for (auto& config_value : entry->values) { ResourceName from(pkg->name, type->type, entry->name); ReferenceVisitor visitor(context, from, keep_set); config_value->value->Accept(&visitor); } } } } return true; } } // namespace proguard } // namespace aapt tools/aapt2/java/ProguardRules.h +53 −10 Original line number Diff line number Diff line Loading @@ -23,37 +23,80 @@ #include <string> #include "Resource.h" #include "ResourceTable.h" #include "Source.h" #include "ValueVisitor.h" #include "androidfw/StringPiece.h" #include "process/IResourceTableConsumer.h" #include "xml/XmlDom.h" namespace aapt { namespace proguard { struct UsageLocation { ResourceName name; Source source; }; class KeepSet { public: inline void AddClass(const Source& source, const std::string& class_name) { keep_set_[class_name].insert(source); KeepSet() = default; KeepSet(bool conditional_keep_rules) : conditional_keep_rules_(conditional_keep_rules) { } inline void AddManifestClass(const UsageLocation& file, const std::string& class_name) { manifest_class_set_[class_name].insert(file); } inline void AddConditionalClass(const UsageLocation& file, const std::string& class_name) { conditional_class_set_[class_name].insert(file); } inline void AddMethod(const UsageLocation& file, const std::string& method_name) { method_set_[method_name].insert(file); } inline void AddMethod(const Source& source, const std::string& method_name) { keep_method_set_[method_name].insert(source); inline void AddReference(const UsageLocation& file, const ResourceName& resource_name) { reference_set_[resource_name].insert(file); } private: friend bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set); std::map<std::string, std::set<Source>> keep_set_; std::map<std::string, std::set<Source>> keep_method_set_; friend bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set, std::set<UsageLocation>* locations); bool conditional_keep_rules_ = false; std::map<std::string, std::set<UsageLocation>> manifest_class_set_; std::map<std::string, std::set<UsageLocation>> method_set_; std::map<std::string, std::set<UsageLocation>> conditional_class_set_; std::map<ResourceName, std::set<UsageLocation>> reference_set_; }; bool CollectProguardRulesForManifest(const Source& source, xml::XmlResource* res, KeepSet* keep_set, bool CollectProguardRulesForManifest(xml::XmlResource* res, KeepSet* keep_set, bool main_dex_only = false); bool CollectProguardRules(const Source& source, xml::XmlResource* res, bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set); bool CollectResourceReferences(aapt::IAaptContext* context, ResourceTable* table, KeepSet* keep_set); bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set); bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set, std::set<UsageLocation>* locations); // // UsageLocation implementation. // inline bool operator==(const UsageLocation& lhs, const UsageLocation& rhs) { return lhs.name == rhs.name; } inline int operator<(const UsageLocation& lhs, const UsageLocation& rhs) { return lhs.name.compare(rhs.name); } } // namespace proguard } // namespace aapt Loading Loading
tools/aapt2/cmd/Link.cpp +11 −6 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ struct LinkOptions { Maybe<std::string> generate_text_symbols_path; Maybe<std::string> generate_proguard_rules_path; Maybe<std::string> generate_main_dex_proguard_rules_path; bool generate_conditional_proguard_rules = false; bool generate_non_final_ids = false; std::vector<std::string> javadoc_annotations; Maybe<std::string> private_symbols; Loading Loading @@ -499,7 +500,7 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer return {}; } if (options_.update_proguard_spec && !proguard::CollectProguardRules(src, doc, keep_set_)) { if (options_.update_proguard_spec && !proguard::CollectProguardRules(doc, keep_set_)) { return {}; } Loading Loading @@ -538,6 +539,8 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv bool error = false; std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> config_sorted_files; proguard::CollectResourceReferences(context_, table, keep_set_); for (auto& pkg : table->packages) { CHECK(!pkg->name.empty()) << "Packages must have names when being linked"; Loading Loading @@ -1719,7 +1722,8 @@ class LinkCommand { } } proguard::KeepSet proguard_keep_set; proguard::KeepSet proguard_keep_set = proguard::KeepSet(options_.generate_conditional_proguard_rules); proguard::KeepSet proguard_main_dex_keep_set; if (context_->GetPackageType() == PackageType::kStaticLib) { Loading Loading @@ -1795,14 +1799,12 @@ class LinkCommand { XmlReferenceLinker manifest_linker; if (manifest_linker.Consume(context_, manifest_xml.get())) { if (options_.generate_proguard_rules_path && !proguard::CollectProguardRulesForManifest(Source(options_.manifest_path), manifest_xml.get(), &proguard_keep_set)) { !proguard::CollectProguardRulesForManifest(manifest_xml.get(), &proguard_keep_set)) { error = true; } if (options_.generate_main_dex_proguard_rules_path && !proguard::CollectProguardRulesForManifest(Source(options_.manifest_path), manifest_xml.get(), !proguard::CollectProguardRulesForManifest(manifest_xml.get(), &proguard_main_dex_keep_set, true)) { error = true; } Loading Loading @@ -1919,6 +1921,9 @@ int Link(const std::vector<StringPiece>& args, IDiagnostics* diagnostics) { .OptionalFlag("--proguard-main-dex", "Output file for generated Proguard rules for the main dex.", &options.generate_main_dex_proguard_rules_path) .OptionalSwitch("--proguard-conditional-keep-rules", "Generate conditional Proguard keep rules.", &options.generate_conditional_proguard_rules) .OptionalSwitch("--no-auto-version", "Disables automatic style and layout SDK versioning.", &options.no_auto_version) Loading
tools/aapt2/java/JavaClassGenerator.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -61,7 +61,7 @@ static bool IsValidSymbol(const StringPiece& symbol) { // Java symbols can not contain . or -, but those are valid in a resource name. // Replace those with '_'. static std::string TransformToFieldName(const StringPiece& symbol) { std::string JavaClassGenerator::TransformToFieldName(const StringPiece& symbol) { std::string output = symbol.to_string(); for (char& c : output) { if (c == '.' || c == '-') { Loading Loading @@ -89,9 +89,9 @@ static std::string TransformNestedAttr(const ResourceNameRef& attr_name, // the package. if (!attr_name.package.empty() && package_name_to_generate != attr_name.package) { output += "_" + TransformToFieldName(attr_name.package); output += "_" + JavaClassGenerator::TransformToFieldName(attr_name.package); } output += "_" + TransformToFieldName(attr_name.entry); output += "_" + JavaClassGenerator::TransformToFieldName(attr_name.entry); return output; } Loading
tools/aapt2/java/JavaClassGenerator.h +3 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include "ResourceTable.h" #include "ResourceValues.h" #include "androidfw/StringPiece.h" #include "process/IResourceTableConsumer.h" #include "process/SymbolTable.h" Loading Loading @@ -78,6 +79,8 @@ class JavaClassGenerator { const std::string& getError() const; static std::string TransformToFieldName(const android::StringPiece& symbol); private: bool SkipSymbol(SymbolState state); bool SkipSymbol(const Maybe<SymbolTable::Symbol>& symbol); Loading
tools/aapt2/java/ProguardRules.cpp +147 −27 Original line number Diff line number Diff line Loading @@ -21,6 +21,10 @@ #include "android-base/macros.h" #include "JavaClassGenerator.h" #include "ResourceUtils.h" #include "ValueVisitor.h" #include "androidfw/StringPiece.h" #include "util/Util.h" #include "xml/XmlDom.h" Loading @@ -31,7 +35,7 @@ class BaseVisitor : public xml::Visitor { public: using xml::Visitor::Visit; BaseVisitor(const Source& source, KeepSet* keep_set) : source_(source), keep_set_(keep_set) { BaseVisitor(const ResourceFile& file, KeepSet* keep_set) : file_(file), keep_set_(keep_set) { } void Visit(xml::Element* node) override { Loading @@ -52,27 +56,47 @@ class BaseVisitor : public xml::Visitor { for (const auto& child : node->children) { child->Accept(this); } for (const auto& attr : node->attributes) { if (attr.compiled_value) { auto ref = ValueCast<Reference>(attr.compiled_value.get()); if (ref) { AddReference(node->line_number, ref); } } } } protected: void AddClass(size_t line_number, const std::string& class_name) { keep_set_->AddClass(Source(source_.path, line_number), class_name); ResourceFile file_; KeepSet* keep_set_; virtual void AddClass(size_t line_number, const std::string& class_name) { keep_set_->AddConditionalClass({file_.name, file_.source.WithLine(line_number)}, class_name); } void AddMethod(size_t line_number, const std::string& method_name) { keep_set_->AddMethod(Source(source_.path, line_number), method_name); keep_set_->AddMethod({file_.name, file_.source.WithLine(line_number)}, method_name); } void AddReference(size_t line_number, Reference* ref) { if (ref && ref->name) { ResourceName ref_name = ref->name.value(); if (ref_name.package.empty()) { ref_name = ResourceName(file_.name.package, ref_name.type, ref_name.entry); } keep_set_->AddReference({file_.name, file_.source.WithLine(line_number)}, ref_name); } } private: DISALLOW_COPY_AND_ASSIGN(BaseVisitor); Source source_; KeepSet* keep_set_; }; class LayoutVisitor : public BaseVisitor { public: LayoutVisitor(const Source& source, KeepSet* keep_set) : BaseVisitor(source, keep_set) { LayoutVisitor(const ResourceFile& file, KeepSet* keep_set) : BaseVisitor(file, keep_set) { } void Visit(xml::Element* node) override { Loading Loading @@ -110,7 +134,7 @@ class LayoutVisitor : public BaseVisitor { class MenuVisitor : public BaseVisitor { public: MenuVisitor(const Source& source, KeepSet* keep_set) : BaseVisitor(source, keep_set) { MenuVisitor(const ResourceFile& file, KeepSet* keep_set) : BaseVisitor(file, keep_set) { } void Visit(xml::Element* node) override { Loading @@ -136,7 +160,7 @@ class MenuVisitor : public BaseVisitor { class XmlResourceVisitor : public BaseVisitor { public: XmlResourceVisitor(const Source& source, KeepSet* keep_set) : BaseVisitor(source, keep_set) { XmlResourceVisitor(const ResourceFile& file, KeepSet* keep_set) : BaseVisitor(file, keep_set) { } void Visit(xml::Element* node) override { Loading @@ -163,7 +187,7 @@ class XmlResourceVisitor : public BaseVisitor { class TransitionVisitor : public BaseVisitor { public: TransitionVisitor(const Source& source, KeepSet* keep_set) : BaseVisitor(source, keep_set) { TransitionVisitor(const ResourceFile& file, KeepSet* keep_set) : BaseVisitor(file, keep_set) { } void Visit(xml::Element* node) override { Loading @@ -185,8 +209,9 @@ class TransitionVisitor : public BaseVisitor { class ManifestVisitor : public BaseVisitor { public: ManifestVisitor(const Source& source, KeepSet* keep_set, bool main_dex_only) : BaseVisitor(source, keep_set), main_dex_only_(main_dex_only) {} ManifestVisitor(const ResourceFile& file, KeepSet* keep_set, bool main_dex_only) : BaseVisitor(file, keep_set), main_dex_only_(main_dex_only) { } void Visit(xml::Element* node) override { if (node->namespace_uri.empty()) { Loading Loading @@ -241,6 +266,10 @@ class ManifestVisitor : public BaseVisitor { BaseVisitor::Visit(node); } virtual void AddClass(size_t line_number, const std::string& class_name) override { keep_set_->AddManifestClass({file_.name, file_.source.WithLine(line_number)}, class_name); } private: DISALLOW_COPY_AND_ASSIGN(ManifestVisitor); Loading @@ -249,9 +278,8 @@ class ManifestVisitor : public BaseVisitor { std::string default_process_; }; bool CollectProguardRulesForManifest(const Source& source, xml::XmlResource* res, KeepSet* keep_set, bool main_dex_only) { ManifestVisitor visitor(source, keep_set, main_dex_only); bool CollectProguardRulesForManifest(xml::XmlResource* res, KeepSet* keep_set, bool main_dex_only) { ManifestVisitor visitor(res->file, keep_set, main_dex_only); if (res->root) { res->root->Accept(&visitor); return true; Loading @@ -259,58 +287,150 @@ bool CollectProguardRulesForManifest(const Source& source, xml::XmlResource* res return false; } bool CollectProguardRules(const Source& source, xml::XmlResource* res, KeepSet* keep_set) { bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set) { if (!res->root) { return false; } switch (res->file.name.type) { case ResourceType::kLayout: { LayoutVisitor visitor(source, keep_set); LayoutVisitor visitor(res->file, keep_set); res->root->Accept(&visitor); break; } case ResourceType::kXml: { XmlResourceVisitor visitor(source, keep_set); XmlResourceVisitor visitor(res->file, keep_set); res->root->Accept(&visitor); break; } case ResourceType::kTransition: { TransitionVisitor visitor(source, keep_set); TransitionVisitor visitor(res->file, keep_set); res->root->Accept(&visitor); break; } case ResourceType::kMenu: { MenuVisitor visitor(source, keep_set); MenuVisitor visitor(res->file, keep_set); res->root->Accept(&visitor); break; } default: default: { BaseVisitor visitor(res->file, keep_set); res->root->Accept(&visitor); break; } } return true; } bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set) { for (const auto& entry : keep_set.keep_set_) { for (const Source& source : entry.second) { *out << "# Referenced at " << source << "\n"; for (const auto& entry : keep_set.manifest_class_set_) { for (const UsageLocation& location : entry.second) { *out << "# Referenced at " << location.source << "\n"; } *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl; } for (const auto& entry : keep_set.keep_method_set_) { for (const Source& source : entry.second) { *out << "# Referenced at " << source << "\n"; for (const auto& entry : keep_set.conditional_class_set_) { std::set<UsageLocation> locations; bool can_be_conditional = true; for (const UsageLocation& location : entry.second) { can_be_conditional &= CollectLocations(location, keep_set, &locations); } for (const UsageLocation& location : entry.second) { *out << "# Referenced at " << location.source << "\n"; } if (keep_set.conditional_keep_rules_ && can_be_conditional) { *out << "-keep class " << entry.first << " {\n ifused class **.R$layout {\n"; for (const UsageLocation& location : locations) { auto transformed_name = JavaClassGenerator::TransformToFieldName(location.name.entry); *out << " int " << transformed_name << ";\n"; } *out << " };\n <init>(...);\n}\n" << std::endl; } else { *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl; } } for (const auto& entry : keep_set.method_set_) { for (const UsageLocation& location : entry.second) { *out << "# Referenced at " << location.source << "\n"; } *out << "-keepclassmembers class * { *** " << entry.first << "(...); }\n" << std::endl; } return true; } bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set, std::set<UsageLocation>* locations) { locations->insert(location); // TODO: allow for more reference types if we can determine its safe. if (location.name.type != ResourceType::kLayout) { return false; } for (const auto& entry : keep_set.reference_set_) { if (entry.first == location.name) { for (auto& refLocation : entry.second) { // Don't get stuck in loops if (locations->find(refLocation) != locations->end()) { return false; } if (!CollectLocations(refLocation, keep_set, locations)) { return false; } } } } return true; } class ReferenceVisitor : public ValueVisitor { public: using ValueVisitor::Visit; ReferenceVisitor(aapt::IAaptContext* context, ResourceName from, KeepSet* keep_set) : context_(context), from_(from), keep_set_(keep_set) { } void Visit(Reference* reference) override { if (reference->name) { ResourceName reference_name = reference->name.value(); if (reference_name.package.empty()) { reference_name = ResourceName(context_->GetCompilationPackage(), reference_name.type, reference_name.entry); } keep_set_->AddReference({from_, reference->GetSource()}, reference_name); } } private: aapt::IAaptContext* context_; ResourceName from_; KeepSet* keep_set_; }; bool CollectResourceReferences(aapt::IAaptContext* context, ResourceTable* table, KeepSet* keep_set) { for (auto& pkg : table->packages) { for (auto& type : pkg->types) { for (auto& entry : type->entries) { for (auto& config_value : entry->values) { ResourceName from(pkg->name, type->type, entry->name); ReferenceVisitor visitor(context, from, keep_set); config_value->value->Accept(&visitor); } } } } return true; } } // namespace proguard } // namespace aapt
tools/aapt2/java/ProguardRules.h +53 −10 Original line number Diff line number Diff line Loading @@ -23,37 +23,80 @@ #include <string> #include "Resource.h" #include "ResourceTable.h" #include "Source.h" #include "ValueVisitor.h" #include "androidfw/StringPiece.h" #include "process/IResourceTableConsumer.h" #include "xml/XmlDom.h" namespace aapt { namespace proguard { struct UsageLocation { ResourceName name; Source source; }; class KeepSet { public: inline void AddClass(const Source& source, const std::string& class_name) { keep_set_[class_name].insert(source); KeepSet() = default; KeepSet(bool conditional_keep_rules) : conditional_keep_rules_(conditional_keep_rules) { } inline void AddManifestClass(const UsageLocation& file, const std::string& class_name) { manifest_class_set_[class_name].insert(file); } inline void AddConditionalClass(const UsageLocation& file, const std::string& class_name) { conditional_class_set_[class_name].insert(file); } inline void AddMethod(const UsageLocation& file, const std::string& method_name) { method_set_[method_name].insert(file); } inline void AddMethod(const Source& source, const std::string& method_name) { keep_method_set_[method_name].insert(source); inline void AddReference(const UsageLocation& file, const ResourceName& resource_name) { reference_set_[resource_name].insert(file); } private: friend bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set); std::map<std::string, std::set<Source>> keep_set_; std::map<std::string, std::set<Source>> keep_method_set_; friend bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set, std::set<UsageLocation>* locations); bool conditional_keep_rules_ = false; std::map<std::string, std::set<UsageLocation>> manifest_class_set_; std::map<std::string, std::set<UsageLocation>> method_set_; std::map<std::string, std::set<UsageLocation>> conditional_class_set_; std::map<ResourceName, std::set<UsageLocation>> reference_set_; }; bool CollectProguardRulesForManifest(const Source& source, xml::XmlResource* res, KeepSet* keep_set, bool CollectProguardRulesForManifest(xml::XmlResource* res, KeepSet* keep_set, bool main_dex_only = false); bool CollectProguardRules(const Source& source, xml::XmlResource* res, bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set); bool CollectResourceReferences(aapt::IAaptContext* context, ResourceTable* table, KeepSet* keep_set); bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set); bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set, std::set<UsageLocation>* locations); // // UsageLocation implementation. // inline bool operator==(const UsageLocation& lhs, const UsageLocation& rhs) { return lhs.name == rhs.name; } inline int operator<(const UsageLocation& lhs, const UsageLocation& rhs) { return lhs.name.compare(rhs.name); } } // namespace proguard } // namespace aapt Loading