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_RESOURCE_TABLE_H
18 #define AAPT_RESOURCE_TABLE_H
19 
20 #include "Diagnostics.h"
21 #include "Resource.h"
22 #include "ResourceValues.h"
23 #include "Source.h"
24 #include "StringPool.h"
25 #include "io/File.h"
26 
27 #include "android-base/macros.h"
28 #include "androidfw/ConfigDescription.h"
29 #include "androidfw/StringPiece.h"
30 
31 #include <functional>
32 #include <map>
33 #include <memory>
34 #include <string>
35 #include <tuple>
36 #include <unordered_map>
37 #include <vector>
38 
39 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
40 
41 namespace aapt {
42 
43 // The Public status of a resource.
44 struct Visibility {
45   enum class Level {
46     kUndefined,
47     kPrivate,
48     kPublic,
49   };
50 
51   Level level = Level::kUndefined;
52   Source source;
53   std::string comment;
54 };
55 
56 // Represents <add-resource> in an overlay.
57 struct AllowNew {
58   Source source;
59   std::string comment;
60 };
61 
62 struct Overlayable {
63   Overlayable() = default;
OverlayableOverlayable64    Overlayable(const android::StringPiece& name, const android::StringPiece& actor)
65        : name(name.to_string()), actor(actor.to_string()) {}
OverlayableOverlayable66    Overlayable(const android::StringPiece& name, const android::StringPiece& actor,
67                     const Source& source)
68        : name(name.to_string()), actor(actor.to_string()), source(source ){}
69 
70   static const char* kActorScheme;
71   std::string name;
72   std::string actor;
73   Source source;
74 };
75 
76 // Represents a declaration that a resource is overlayable at runtime.
77 struct OverlayableItem {
OverlayableItemOverlayableItem78   explicit OverlayableItem(const std::shared_ptr<Overlayable>& overlayable)
79       : overlayable(overlayable) {}
80   std::shared_ptr<Overlayable> overlayable;
81   PolicyFlags policies = PolicyFlags::NONE;
82   std::string comment;
83   Source source;
84 };
85 
86 class ResourceConfigValue {
87  public:
88   // The configuration for which this value is defined.
89   const android::ConfigDescription config;
90 
91   // The product for which this value is defined.
92   const std::string product;
93 
94   // The actual Value.
95   std::unique_ptr<Value> value;
96 
ResourceConfigValue(const android::ConfigDescription & config,const android::StringPiece & product)97   ResourceConfigValue(const android::ConfigDescription& config, const android::StringPiece& product)
98       : config(config), product(product.to_string()) {}
99 
100  private:
101   DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
102 };
103 
104 // Represents a resource entry, which may have varying values for each defined configuration.
105 class ResourceEntry {
106  public:
107   // The name of the resource. Immutable, as this determines the order of this resource
108   // when doing lookups.
109   const std::string name;
110 
111   // The entry ID for this resource (the EEEE in 0xPPTTEEEE).
112   Maybe<uint16_t> id;
113 
114   // Whether this resource is public (and must maintain the same entry ID across builds).
115   Visibility visibility;
116 
117   Maybe<AllowNew> allow_new;
118 
119   // The declarations of this resource as overlayable for RROs
120   Maybe<OverlayableItem> overlayable_item;
121 
122   // The resource's values for each configuration.
123   std::vector<std::unique_ptr<ResourceConfigValue>> values;
124 
ResourceEntry(const android::StringPiece & name)125   explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {}
126 
127   ResourceConfigValue* FindValue(const android::ConfigDescription& config);
128 
129   ResourceConfigValue* FindValue(const android::ConfigDescription& config,
130                                  const android::StringPiece& product);
131 
132   ResourceConfigValue* FindOrCreateValue(const android::ConfigDescription& config,
133                                          const android::StringPiece& product);
134   std::vector<ResourceConfigValue*> FindAllValues(const android::ConfigDescription& config);
135 
136   template <typename Func>
FindValuesIf(Func f)137   std::vector<ResourceConfigValue*> FindValuesIf(Func f) {
138     std::vector<ResourceConfigValue*> results;
139     for (auto& config_value : values) {
140       if (f(config_value.get())) {
141         results.push_back(config_value.get());
142       }
143     }
144     return results;
145   }
146 
147   bool HasDefaultValue() const;
148 
149  private:
150   DISALLOW_COPY_AND_ASSIGN(ResourceEntry);
151 };
152 
153 // Represents a resource type (eg. string, drawable, layout, etc.) containing resource entries.
154 class ResourceTableType {
155  public:
156   // The logical type of resource (string, drawable, layout, etc.).
157   const ResourceType type;
158 
159   // The type ID for this resource (the TT in 0xPPTTEEEE).
160   Maybe<uint8_t> id;
161 
162   // Whether this type is public (and must maintain the same type ID across builds).
163   Visibility::Level visibility_level = Visibility::Level::kUndefined;
164 
165   // List of resources for this type.
166   std::vector<std::unique_ptr<ResourceEntry>> entries;
167 
ResourceTableType(const ResourceType type)168   explicit ResourceTableType(const ResourceType type) : type(type) {}
169 
170   ResourceEntry* FindEntry(const android::StringPiece& name,
171                            Maybe<uint16_t> id = Maybe<uint16_t>());
172   ResourceEntry* FindOrCreateEntry(const android::StringPiece& name,
173                                    Maybe<uint16_t> id = Maybe<uint16_t>());
174 
175  private:
176   DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
177 };
178 
179 class ResourceTablePackage {
180  public:
181   std::string name;
182 
183   // The package ID (the PP in 0xPPTTEEEE).
184   Maybe<uint8_t> id;
185 
186   std::vector<std::unique_ptr<ResourceTableType>> types;
187 
188   ResourceTablePackage() = default;
189   ResourceTableType* FindType(ResourceType type, Maybe<uint8_t> id = Maybe<uint8_t>());
190   ResourceTableType* FindOrCreateType(const ResourceType type,
191                                       Maybe<uint8_t> id = Maybe<uint8_t>());
192 
193  private:
194   DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
195 };
196 
197 // The container and index for all resources defined for an app.
198 class ResourceTable {
199  public:
200   ResourceTable() = default;
ResourceTable(bool validate_resources)201   explicit ResourceTable(bool validate_resources) : validate_resources_(validate_resources) {}
202 
203   enum class CollisionResult { kKeepBoth, kKeepOriginal, kConflict, kTakeNew };
204 
205   using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*)>;
206 
207   // When a collision of resources occurs, this method decides which value to keep.
208   static CollisionResult ResolveValueCollision(Value* existing, Value* incoming);
209 
210   // When a collision of resources occurs, this method keeps both values
211   static CollisionResult IgnoreCollision(Value* existing, Value* incoming);
212 
213   bool AddResource(const ResourceNameRef& name, const android::ConfigDescription& config,
214                    const android::StringPiece& product, std::unique_ptr<Value> value,
215                    IDiagnostics* diag);
216 
217   bool AddResourceWithId(const ResourceNameRef& name, const ResourceId& res_id,
218                          const android::ConfigDescription& config,
219                          const android::StringPiece& product, std::unique_ptr<Value> value,
220                          IDiagnostics* diag);
221 
222   // Same as AddResource, but doesn't verify the validity of the name. This is used
223   // when loading resources from an existing binary resource table that may have mangled names.
224   bool AddResourceMangled(const ResourceNameRef& name, const android::ConfigDescription& config,
225                           const android::StringPiece& product, std::unique_ptr<Value> value,
226                           IDiagnostics* diag);
227 
228   bool AddResourceWithIdMangled(const ResourceNameRef& name, const ResourceId& id,
229                                 const android::ConfigDescription& config,
230                                 const android::StringPiece& product, std::unique_ptr<Value> value,
231                                 IDiagnostics* diag);
232 
233   bool GetValidateResources();
234 
235   bool SetVisibility(const ResourceNameRef& name, const Visibility& visibility, IDiagnostics* diag);
236   bool SetVisibilityWithId(const ResourceNameRef& name, const Visibility& visibility,
237                            const ResourceId& res_id, IDiagnostics* diag);
238   bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility,
239                                   const ResourceId& res_id, IDiagnostics* diag);
240 
241   bool SetOverlayable(const ResourceNameRef& name, const OverlayableItem& overlayable,
242                       IDiagnostics *diag);
243 
244   bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag);
245   bool SetAllowNewMangled(const ResourceNameRef& name, const AllowNew& allow_new,
246                           IDiagnostics* diag);
247 
248   struct SearchResult {
249     ResourceTablePackage* package;
250     ResourceTableType* type;
251     ResourceEntry* entry;
252   };
253 
254   Maybe<SearchResult> FindResource(const ResourceNameRef& name) const;
255 
256   // Returns the package struct with the given name, or nullptr if such a package does not
257   // exist. The empty string is a valid package and typically is used to represent the
258   // 'current' package before it is known to the ResourceTable.
259   ResourceTablePackage* FindPackage(const android::StringPiece& name) const;
260 
261   ResourceTablePackage* FindPackageById(uint8_t id) const;
262 
263   ResourceTablePackage* CreatePackage(const android::StringPiece& name, Maybe<uint8_t> id = {});
264 
265   // Attempts to find a package having the specified name and ID. If not found, a new package
266   // of the specified parameters is created and returned.
267   ResourceTablePackage* CreatePackageAllowingDuplicateNames(const android::StringPiece& name,
268                                                             const Maybe<uint8_t> id);
269 
270   std::unique_ptr<ResourceTable> Clone() const;
271 
272   // The string pool used by this resource table. Values that reference strings must use
273   // this pool to create their strings.
274   // NOTE: `string_pool` must come before `packages` so that it is destroyed after.
275   // When `string_pool` references are destroyed (as they will be when `packages` is destroyed),
276   // they decrement a refCount, which would cause invalid memory access if the pool was already
277   // destroyed.
278   StringPool string_pool;
279 
280   // The list of packages in this table, sorted alphabetically by package name and increasing
281   // package ID (missing ID being the lowest).
282   std::vector<std::unique_ptr<ResourceTablePackage>> packages;
283 
284   // Set of dynamic packages that this table may reference. Their package names get encoded
285   // into the resources.arsc along with their compile-time assigned IDs.
286   std::map<size_t, std::string> included_packages_;
287 
288  private:
289   // The function type that validates a symbol name. Returns a non-empty StringPiece representing
290   // the offending character (which may be more than one byte in UTF-8). Returns an empty string
291   // if the name was valid.
292   using NameValidator = android::StringPiece(const android::StringPiece&);
293 
294   ResourceTablePackage* FindOrCreatePackage(const android::StringPiece& name);
295 
296   bool ValidateName(NameValidator validator, const ResourceNameRef& name, const Source& source,
297                     IDiagnostics* diag);
298 
299   bool AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id,
300                        const android::ConfigDescription& config,
301                        const android::StringPiece& product, std::unique_ptr<Value> value,
302                        NameValidator name_validator, const CollisionResolverFunc& conflict_resolver,
303                        IDiagnostics* diag);
304 
305   bool SetVisibilityImpl(const ResourceNameRef& name, const Visibility& visibility,
306                          const ResourceId& res_id, NameValidator name_validator,
307                          IDiagnostics* diag);
308 
309   bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new,
310                        NameValidator name_validator, IDiagnostics* diag);
311 
312   bool SetOverlayableImpl(const ResourceNameRef &name, const OverlayableItem& overlayable,
313                           NameValidator name_validator, IDiagnostics *diag);
314 
315   // Controls whether the table validates resource names and prevents duplicate resource names
316   bool validate_resources_ = true;
317 
318   DISALLOW_COPY_AND_ASSIGN(ResourceTable);
319 };
320 
321 }  // namespace aapt
322 
323 #endif  // AAPT_RESOURCE_TABLE_H
324