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 <functional>
21 #include <map>
22 #include <memory>
23 #include <string>
24 #include <tuple>
25 #include <unordered_map>
26 #include <vector>
27 
28 #include "Resource.h"
29 #include "ResourceValues.h"
30 #include "android-base/macros.h"
31 #include "androidfw/ConfigDescription.h"
32 #include "androidfw/IDiagnostics.h"
33 #include "androidfw/Source.h"
34 #include "androidfw/StringPiece.h"
35 #include "androidfw/StringPool.h"
36 #include "io/File.h"
37 
38 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
39 
40 namespace aapt {
41 
42 // The Public status of a resource.
43 struct Visibility {
44   enum class Level {
45     kUndefined,
46     kPrivate,
47     kPublic,
48   };
49 
50   Level level = Level::kUndefined;
51   android::Source source;
52   std::string comment;
53 
54   // Indicates that the resource id may change across builds and that the public R.java identifier
55   // for this resource should not be final. This is set to `true` for resources in `staging-group`
56   // tags.
57   bool staged_api = false;
58 };
59 
60 // Represents <add-resource> in an overlay.
61 struct AllowNew {
62   android::Source source;
63   std::string comment;
64 };
65 
66 // Represents the staged resource id of a finalized resource.
67 struct StagedId {
68   ResourceId id;
69   android::Source source;
70 };
71 
72 struct Overlayable {
73   Overlayable() = default;
OverlayableOverlayable74   Overlayable(android::StringPiece name, android::StringPiece actor) : name(name), actor(actor) {
75   }
OverlayableOverlayable76   Overlayable(android::StringPiece name, android::StringPiece actor, const android::Source& source)
77       : name(name), actor(actor), source(source) {
78   }
79 
80   static const char* kActorScheme;
81   std::string name;
82   std::string actor;
83   android::Source source;
84 };
85 
86 // Represents a declaration that a resource is overlayable at runtime.
87 struct OverlayableItem {
OverlayableItemOverlayableItem88   explicit OverlayableItem(const std::shared_ptr<Overlayable>& overlayable)
89       : overlayable(overlayable) {}
90   std::shared_ptr<Overlayable> overlayable;
91   PolicyFlags policies = PolicyFlags::NONE;
92   std::string comment;
93   android::Source source;
94 };
95 
96 class ResourceConfigValue {
97  public:
98   // The configuration for which this value is defined.
99   const android::ConfigDescription config;
100 
101   // The product for which this value is defined.
102   const std::string product;
103 
104   // The actual Value.
105   std::unique_ptr<Value> value;
106 
ResourceConfigValue(const android::ConfigDescription & config,android::StringPiece product)107   ResourceConfigValue(const android::ConfigDescription& config, android::StringPiece product)
108       : config(config), product(product) {
109   }
110 
111  private:
112   DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
113 };
114 
115 // Represents a resource entry, which may have varying values for each defined configuration.
116 class ResourceEntry {
117  public:
118   // The name of the resource. Immutable, as this determines the order of this resource
119   // when doing lookups.
120   const std::string name;
121 
122   // The entry ID for this resource (the EEEE in 0xPPTTEEEE).
123   std::optional<ResourceId> id;
124 
125   // Whether this resource is public (and must maintain the same entry ID across builds).
126   Visibility visibility;
127 
128   std::optional<AllowNew> allow_new;
129 
130   // The declarations of this resource as overlayable for RROs
131   std::optional<OverlayableItem> overlayable_item;
132 
133   // The staged resource id for a finalized resource.
134   std::optional<StagedId> staged_id;
135 
136   // The resource's values for each configuration.
137   std::vector<std::unique_ptr<ResourceConfigValue>> values;
138 
ResourceEntry(android::StringPiece name)139   explicit ResourceEntry(android::StringPiece name) : name(name) {
140   }
141 
142   ResourceConfigValue* FindValue(const android::ConfigDescription& config,
143                                  android::StringPiece product = {});
144   const ResourceConfigValue* FindValue(const android::ConfigDescription& config,
145                                        android::StringPiece product = {}) const;
146 
147   ResourceConfigValue* FindOrCreateValue(const android::ConfigDescription& config,
148                                          android::StringPiece product);
149   std::vector<ResourceConfigValue*> FindAllValues(const android::ConfigDescription& config);
150 
151   template <typename Func>
FindValuesIf(Func f)152   std::vector<ResourceConfigValue*> FindValuesIf(Func f) {
153     std::vector<ResourceConfigValue*> results;
154     for (auto& config_value : values) {
155       if (f(config_value.get())) {
156         results.push_back(config_value.get());
157       }
158     }
159     return results;
160   }
161 
162   bool HasDefaultValue() const;
163 
164  private:
165   DISALLOW_COPY_AND_ASSIGN(ResourceEntry);
166 };
167 
168 // Represents a resource type (eg. string, drawable, layout, etc.) containing resource entries.
169 class ResourceTableType {
170  public:
171   // The logical type of resource (string, drawable, layout, etc.).
172   const ResourceNamedType named_type;
173 
174   // Whether this type is public (and must maintain the same type ID across builds).
175   Visibility::Level visibility_level = Visibility::Level::kUndefined;
176 
177   // List of resources for this type.
178   std::vector<std::unique_ptr<ResourceEntry>> entries;
179 
ResourceTableType(const ResourceNamedTypeRef & type)180   explicit ResourceTableType(const ResourceNamedTypeRef& type)
181       : named_type(type.ToResourceNamedType()) {
182   }
183 
184   ResourceEntry* CreateEntry(android::StringPiece name);
185   ResourceEntry* FindEntry(android::StringPiece name) const;
186   ResourceEntry* FindOrCreateEntry(android::StringPiece name);
187 
188  private:
189   DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
190 };
191 
192 class ResourceTablePackage {
193  public:
194   std::string name;
195 
196   std::vector<std::unique_ptr<ResourceTableType>> types;
197 
ResourceTablePackage(android::StringPiece name)198   explicit ResourceTablePackage(android::StringPiece name) : name(name) {
199   }
200 
201   ResourceTablePackage() = default;
202   ResourceTableType* FindTypeWithDefaultName(const ResourceType type) const;
203   ResourceTableType* FindType(const ResourceNamedTypeRef& type) const;
204   ResourceTableType* FindOrCreateType(const ResourceNamedTypeRef& type);
205 
206  private:
207   DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
208 };
209 
210 struct ResourceTableEntryView {
211   std::string name;
212   std::optional<uint16_t> id;
213   Visibility visibility;
214   std::optional<AllowNew> allow_new;
215   std::optional<OverlayableItem> overlayable_item;
216   std::optional<StagedId> staged_id;
217   std::vector<const ResourceConfigValue*> values;
218 
219   const ResourceConfigValue* FindValue(const android::ConfigDescription& config,
220                                        android::StringPiece product = {}) const;
221 };
222 
223 struct ResourceTableTypeView {
224   ResourceNamedType named_type;
225   std::optional<uint8_t> id;
226   Visibility::Level visibility_level = Visibility::Level::kUndefined;
227 
228   // Entries sorted in ascending entry id order. If ids have not been assigned, the entries are
229   // sorted lexicographically.
230   std::vector<ResourceTableEntryView> entries;
231 };
232 
233 struct ResourceTablePackageView {
234   std::string name;
235   std::optional<uint8_t> id;
236   // Types sorted in ascending type id order. If ids have not been assigned, the types are sorted by
237   // their declaration order in the ResourceType enum.
238   std::vector<ResourceTableTypeView> types;
239 };
240 
241 struct ResourceTableViewOptions {
242   bool create_alias_entries = false;
243 };
244 
245 struct ResourceTableView {
246   // Packages sorted in ascending package id order. If ids have not been assigned, the packages are
247   // sorted lexicographically.
248   std::vector<ResourceTablePackageView> packages;
249 };
250 
251 enum class OnIdConflict {
252   // If the resource entry already exists but has a different resource id, the resource value will
253   // not be added to the table.
254   ERROR,
255 
256   // If the resource entry already exists but has a different resource id, create a new resource
257   // with this resource name and id combination.
258   CREATE_ENTRY,
259 };
260 
261 struct NewResource {
262   ResourceName name;
263   std::unique_ptr<Value> value;
264   android::ConfigDescription config;
265   std::string product;
266   std::optional<std::pair<ResourceId, OnIdConflict>> id;
267   std::optional<Visibility> visibility;
268   std::optional<OverlayableItem> overlayable;
269   std::optional<AllowNew> allow_new;
270   std::optional<StagedId> staged_id;
271   bool allow_mangled = false;
272 };
273 
274 struct NewResourceBuilder {
275   explicit NewResourceBuilder(const ResourceNameRef& name);
276   explicit NewResourceBuilder(const std::string& name);
277   NewResourceBuilder& SetValue(std::unique_ptr<Value> value, android::ConfigDescription config = {},
278                                std::string product = {});
279   NewResourceBuilder& SetId(ResourceId id, OnIdConflict on_conflict = OnIdConflict::ERROR);
280   NewResourceBuilder& SetVisibility(Visibility id);
281   NewResourceBuilder& SetOverlayable(OverlayableItem overlayable);
282   NewResourceBuilder& SetAllowNew(AllowNew allow_new);
283   NewResourceBuilder& SetStagedId(StagedId id);
284   NewResourceBuilder& SetAllowMangled(bool allow_mangled);
285   NewResource Build();
286 
287  private:
288   NewResource res_;
289 };
290 
291 // The container and index for all resources defined for an app.
292 class ResourceTable {
293  public:
294   enum class Validation {
295     kEnabled,
296     kDisabled,
297   };
298 
299   enum class CollisionResult { kKeepBoth, kKeepOriginal, kConflict, kTakeNew };
300 
301   ResourceTable() = default;
302   explicit ResourceTable(Validation validation);
303 
304   bool AddResource(NewResource&& res, android::IDiagnostics* diag);
305 
306   // Retrieves a sorted a view of the packages, types, and entries sorted in ascending resource id
307   // order.
308   ResourceTableView GetPartitionedView(const ResourceTableViewOptions& options = {}) const;
309 
310   using ReferencedPackages = std::map<uint8_t, std::string>;
GetReferencedPackages()311   const ReferencedPackages& GetReferencedPackages() const {
312     return included_packages_;
313   }
314 
315   struct SearchResult {
316     ResourceTablePackage* package;
317     ResourceTableType* type;
318     ResourceEntry* entry;
319   };
320 
321   std::optional<SearchResult> FindResource(const ResourceNameRef& name) const;
322   std::optional<SearchResult> FindResource(const ResourceNameRef& name, ResourceId id) const;
323   bool RemoveResource(const ResourceNameRef& name, ResourceId id) const;
324 
325   // Returns the package struct with the given name, or nullptr if such a package does not
326   // exist. The empty string is a valid package and typically is used to represent the
327   // 'current' package before it is known to the ResourceTable.
328   ResourceTablePackage* FindPackage(android::StringPiece name) const;
329   ResourceTablePackage* FindOrCreatePackage(android::StringPiece name);
330 
331   std::unique_ptr<ResourceTable> Clone() const;
332 
333   // When a collision of resources occurs, this method decides which value to keep.
334   static CollisionResult ResolveValueCollision(Value* existing, Value* incoming);
335 
336   // The string pool used by this resource table. Values that reference strings must use
337   // this pool to create their strings.
338   // NOTE: `string_pool` must come before `packages` so that it is destroyed after.
339   // When `string_pool` references are destroyed (as they will be when `packages` is destroyed),
340   // they decrement a refCount, which would cause invalid memory access if the pool was already
341   // destroyed.
342   android::StringPool string_pool;
343 
344   // The list of packages in this table, sorted alphabetically by package name and increasing
345   // package ID (missing ID being the lowest).
346   std::vector<std::unique_ptr<ResourceTablePackage>> packages;
347 
348   // Set of dynamic packages that this table may reference. Their package names get encoded
349   // into the resources.arsc along with their compile-time assigned IDs.
350   ReferencedPackages included_packages_;
351 
352  private:
353   DISALLOW_COPY_AND_ASSIGN(ResourceTable);
354 
355   Validation validation_ = Validation::kEnabled;
356 };
357 
358 }  // namespace aapt
359 
360 #endif  // AAPT_RESOURCE_TABLE_H
361