1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef AAPT_PROGUARD_RULES_H
18 #define AAPT_PROGUARD_RULES_H
19 
20 #include <map>
21 #include <ostream>
22 #include <set>
23 #include <string>
24 
25 #include "Resource.h"
26 #include "ResourceTable.h"
27 #include "ValueVisitor.h"
28 #include "androidfw/Source.h"
29 #include "androidfw/Streams.h"
30 #include "androidfw/StringPiece.h"
31 #include "process/IResourceTableConsumer.h"
32 #include "xml/XmlDom.h"
33 
34 namespace aapt {
35 namespace proguard {
36 
37 struct UsageLocation {
38   ResourceName name;
39   android::Source source;
40 };
41 
42 struct NameAndSignature {
43   std::string name;
44   std::string signature;
45 };
46 
47 class KeepSet {
48  public:
49   KeepSet() = default;
50 
KeepSet(bool conditional_keep_rules)51   explicit KeepSet(bool conditional_keep_rules) : conditional_keep_rules_(conditional_keep_rules) {
52   }
53 
AddManifestClass(const UsageLocation & file,const std::string & class_name)54   inline void AddManifestClass(const UsageLocation& file, const std::string& class_name) {
55     manifest_class_set_[class_name].insert(file);
56   }
57 
AddConditionalClass(const UsageLocation & file,const NameAndSignature & class_and_signature)58   inline void AddConditionalClass(const UsageLocation& file,
59                                   const NameAndSignature& class_and_signature) {
60     conditional_class_set_[class_and_signature].insert(file);
61   }
62 
AddMethod(const UsageLocation & file,const NameAndSignature & name_and_signature)63   inline void AddMethod(const UsageLocation& file, const NameAndSignature& name_and_signature) {
64     method_set_[name_and_signature].insert(file);
65   }
66 
AddReference(const UsageLocation & file,const ResourceName & resource_name)67   inline void AddReference(const UsageLocation& file, const ResourceName& resource_name) {
68     reference_set_[resource_name].insert(file);
69   }
70 
71  private:
72   friend void WriteKeepSet(const KeepSet& keep_set, android::OutputStream* out, bool minimal_keep,
73                            bool no_location_reference);
74 
75   friend bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
76                                std::set<UsageLocation>* locations);
77 
78   bool conditional_keep_rules_ = false;
79   std::map<std::string, std::set<UsageLocation>> manifest_class_set_;
80   std::map<NameAndSignature, std::set<UsageLocation>> method_set_;
81   std::map<NameAndSignature, std::set<UsageLocation>> conditional_class_set_;
82   std::map<ResourceName, std::set<UsageLocation>> reference_set_;
83 };
84 
85 bool CollectProguardRulesForManifest(xml::XmlResource* res, KeepSet* keep_set,
86                                      bool main_dex_only = false);
87 
88 bool CollectProguardRules(IAaptContext* context, xml::XmlResource* res, KeepSet* keep_set);
89 
90 bool CollectResourceReferences(IAaptContext* context, ResourceTable* table, KeepSet* keep_set);
91 
92 void WriteKeepSet(const KeepSet& keep_set, android::OutputStream* out, bool minimal_keep,
93                   bool no_location_reference);
94 
95 bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
96                       std::set<UsageLocation>* locations);
97 
98 //
99 // UsageLocation implementation.
100 //
101 
102 inline bool operator==(const UsageLocation& lhs, const UsageLocation& rhs) {
103   // The "source" member is ignored because we only need "name" for outputting
104   // keep rules; "source" is used for comments.
105   return lhs.name == rhs.name;
106 }
107 
108 inline bool operator<(const UsageLocation& lhs, const UsageLocation& rhs) {
109   return lhs.name.compare(rhs.name) < 0;
110 }
111 
112 //
113 // NameAndSignature implementation.
114 //
115 
116 inline bool operator<(const NameAndSignature& lhs, const NameAndSignature& rhs) {
117   if (lhs.name < rhs.name) {
118     return true;
119   }
120   if (lhs.name == rhs.name) {
121     return lhs.signature < rhs.signature;
122   }
123   return false;
124 }
125 
126 }  // namespace proguard
127 }  // namespace aapt
128 
129 #endif  // AAPT_PROGUARD_RULES_H
130