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