• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
107   // Whether the value uses read/write feature flags
108   bool uses_readwrite_feature_flags = false;
109 
ResourceConfigValue(const android::ConfigDescription & config,android::StringPiece product)110   ResourceConfigValue(const android::ConfigDescription& config, android::StringPiece product)
111       : config(config), product(product) {
112   }
113 
114  private:
115   DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
116 };
117 
118 // Represents a resource entry, which may have varying values for each defined configuration.
119 class ResourceEntry {
120  public:
121   // The name of the resource. Immutable, as this determines the order of this resource
122   // when doing lookups.
123   const std::string name;
124 
125   // The entry ID for this resource (the EEEE in 0xPPTTEEEE).
126   std::optional<ResourceId> id;
127 
128   // Whether this resource is public (and must maintain the same entry ID across builds).
129   Visibility visibility;
130 
131   std::optional<AllowNew> allow_new;
132 
133   // The declarations of this resource as overlayable for RROs
134   std::optional<OverlayableItem> overlayable_item;
135 
136   // The staged resource id for a finalized resource.
137   std::optional<StagedId> staged_id;
138 
139   // The resource's values for each configuration.
140   std::vector<std::unique_ptr<ResourceConfigValue>> values;
141 
142   // The resource's values that are behind disabled flags.
143   std::vector<std::unique_ptr<ResourceConfigValue>> flag_disabled_values;
144 
ResourceEntry(android::StringPiece name)145   explicit ResourceEntry(android::StringPiece name) : name(name) {
146   }
147 
148   ResourceConfigValue* FindValue(const android::ConfigDescription& config,
149                                  android::StringPiece product = {});
150   const ResourceConfigValue* FindValue(const android::ConfigDescription& config,
151                                        android::StringPiece product = {}) const;
152 
153   ResourceConfigValue* FindOrCreateValue(const android::ConfigDescription& config,
154                                          android::StringPiece product);
155   std::vector<ResourceConfigValue*> FindAllValues(const android::ConfigDescription& config);
156 
157   // Either returns the existing ResourceConfigValue in the disabled list with the given flag,
158   // config, and product or creates a new one and returns that. In either case the returned value
159   // does not have the flag set on the value so it must be set by the caller.
160   ResourceConfigValue* FindOrCreateFlagDisabledValue(const FeatureFlagAttribute& flag,
161                                                      const android::ConfigDescription& config,
162                                                      android::StringPiece product = {});
163 
164   template <typename Func>
FindValuesIf(Func f)165   std::vector<ResourceConfigValue*> FindValuesIf(Func f) {
166     std::vector<ResourceConfigValue*> results;
167     for (auto& config_value : values) {
168       if (f(config_value.get())) {
169         results.push_back(config_value.get());
170       }
171     }
172     return results;
173   }
174 
175   bool HasDefaultValue() const;
176 
177  private:
178   DISALLOW_COPY_AND_ASSIGN(ResourceEntry);
179 };
180 
181 // Represents a resource type (eg. string, drawable, layout, etc.) containing resource entries.
182 class ResourceTableType {
183  public:
184   // The logical type of resource (string, drawable, layout, etc.).
185   const ResourceNamedType named_type;
186 
187   // Whether this type is public (and must maintain the same type ID across builds).
188   Visibility::Level visibility_level = Visibility::Level::kUndefined;
189 
190   // List of resources for this type.
191   std::vector<std::unique_ptr<ResourceEntry>> entries;
192 
ResourceTableType(const ResourceNamedTypeRef & type)193   explicit ResourceTableType(const ResourceNamedTypeRef& type)
194       : named_type(type.ToResourceNamedType()) {
195   }
196 
197   ResourceEntry* CreateEntry(android::StringPiece name);
198   ResourceEntry* FindEntry(android::StringPiece name) const;
199   ResourceEntry* FindOrCreateEntry(android::StringPiece name);
200 
201  private:
202   DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
203 };
204 
205 class ResourceTablePackage {
206  public:
207   std::string name;
208 
209   std::vector<std::unique_ptr<ResourceTableType>> types;
210 
ResourceTablePackage(android::StringPiece name)211   explicit ResourceTablePackage(android::StringPiece name) : name(name) {
212   }
213 
214   ResourceTablePackage() = default;
215   ResourceTableType* FindTypeWithDefaultName(const ResourceType type) const;
216   ResourceTableType* FindType(const ResourceNamedTypeRef& type) const;
217   ResourceTableType* FindOrCreateType(const ResourceNamedTypeRef& type);
218 
219  private:
220   DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
221 };
222 
223 struct ResourceTableEntryView {
224   std::string name;
225   std::optional<uint16_t> id;
226   Visibility visibility;
227   std::optional<AllowNew> allow_new;
228   std::optional<OverlayableItem> overlayable_item;
229   std::optional<StagedId> staged_id;
230   std::vector<const ResourceConfigValue*> values;
231   std::vector<const ResourceConfigValue*> flag_disabled_values;
232 
233   const ResourceConfigValue* FindValue(const android::ConfigDescription& config,
234                                        android::StringPiece product = {}) const;
235 
236   const ResourceConfigValue* FindFlagDisabledValue(const FeatureFlagAttribute& flag,
237                                                    const android::ConfigDescription& config,
238                                                    android::StringPiece product = {}) const;
239 };
240 
241 struct ResourceTableTypeView {
242   ResourceNamedType named_type;
243   std::optional<uint8_t> id;
244   Visibility::Level visibility_level = Visibility::Level::kUndefined;
245 
246   // Entries sorted in ascending entry id order. If ids have not been assigned, the entries are
247   // sorted lexicographically.
248   std::vector<ResourceTableEntryView> entries;
249 };
250 
251 struct ResourceTablePackageView {
252   std::string name;
253   std::optional<uint8_t> id;
254   // Types sorted in ascending type id order. If ids have not been assigned, the types are sorted by
255   // their declaration order in the ResourceType enum.
256   std::vector<ResourceTableTypeView> types;
257 };
258 
259 struct ResourceTableViewOptions {
260   bool create_alias_entries = false;
261 };
262 
263 struct ResourceTableView {
264   // Packages sorted in ascending package id order. If ids have not been assigned, the packages are
265   // sorted lexicographically.
266   std::vector<ResourceTablePackageView> packages;
267 };
268 
269 enum class OnIdConflict {
270   // If the resource entry already exists but has a different resource id, the resource value will
271   // not be added to the table.
272   ERROR,
273 
274   // If the resource entry already exists but has a different resource id, create a new resource
275   // with this resource name and id combination.
276   CREATE_ENTRY,
277 };
278 
279 struct NewResource {
280   ResourceName name;
281   std::unique_ptr<Value> value;
282   android::ConfigDescription config;
283   std::string product;
284   std::optional<std::pair<ResourceId, OnIdConflict>> id;
285   std::optional<Visibility> visibility;
286   std::optional<OverlayableItem> overlayable;
287   std::optional<AllowNew> allow_new;
288   std::optional<StagedId> staged_id;
289   bool allow_mangled = false;
290   bool uses_readwrite_feature_flags = false;
291 };
292 
293 struct NewResourceBuilder {
294   explicit NewResourceBuilder(const ResourceNameRef& name);
295   explicit NewResourceBuilder(const std::string& name);
296   NewResourceBuilder& SetValue(std::unique_ptr<Value> value, android::ConfigDescription config = {},
297                                std::string product = {});
298   NewResourceBuilder& SetId(ResourceId id, OnIdConflict on_conflict = OnIdConflict::ERROR);
299   NewResourceBuilder& SetVisibility(Visibility id);
300   NewResourceBuilder& SetOverlayable(OverlayableItem overlayable);
301   NewResourceBuilder& SetAllowNew(AllowNew allow_new);
302   NewResourceBuilder& SetStagedId(StagedId id);
303   NewResourceBuilder& SetAllowMangled(bool allow_mangled);
304   NewResourceBuilder& SetUsesReadWriteFeatureFlags(bool uses_feature_flags);
305   NewResource Build();
306 
307  private:
308   NewResource res_;
309 };
310 
311 // The container and index for all resources defined for an app.
312 class ResourceTable {
313  public:
314   enum class Validation {
315     kEnabled,
316     kDisabled,
317   };
318 
319   enum class CollisionResult { kKeepBoth, kKeepOriginal, kConflict, kTakeNew };
320 
321   ResourceTable() = default;
322   explicit ResourceTable(Validation validation);
323 
324   bool AddResource(NewResource&& res, android::IDiagnostics* diag);
325 
326   // Retrieves a sorted a view of the packages, types, and entries sorted in ascending resource id
327   // order.
328   ResourceTableView GetPartitionedView(const ResourceTableViewOptions& options = {}) const;
329 
330   using ReferencedPackages = std::map<uint8_t, std::string>;
GetReferencedPackages()331   const ReferencedPackages& GetReferencedPackages() const {
332     return included_packages_;
333   }
334 
335   struct SearchResult {
336     ResourceTablePackage* package;
337     ResourceTableType* type;
338     ResourceEntry* entry;
339   };
340 
341   std::optional<SearchResult> FindResource(const ResourceNameRef& name) const;
342   std::optional<SearchResult> FindResource(const ResourceNameRef& name, ResourceId id) const;
343   bool RemoveResource(const ResourceNameRef& name, ResourceId id) const;
344 
345   // Returns the package struct with the given name, or nullptr if such a package does not
346   // exist. The empty string is a valid package and typically is used to represent the
347   // 'current' package before it is known to the ResourceTable.
348   ResourceTablePackage* FindPackage(android::StringPiece name) const;
349   ResourceTablePackage* FindOrCreatePackage(android::StringPiece name);
350 
351   std::unique_ptr<ResourceTable> Clone() const;
352 
353   // When a collision of resources occurs, these methods decide which value to keep.
354   static CollisionResult ResolveFlagCollision(FlagStatus existing, FlagStatus incoming);
355   static CollisionResult ResolveValueCollision(Value* existing, Value* incoming);
356 
357   // The string pool used by this resource table. Values that reference strings must use
358   // this pool to create their strings.
359   // NOTE: `string_pool` must come before `packages` so that it is destroyed after.
360   // When `string_pool` references are destroyed (as they will be when `packages` is destroyed),
361   // they decrement a refCount, which would cause invalid memory access if the pool was already
362   // destroyed.
363   android::StringPool string_pool;
364 
365   // The list of packages in this table, sorted alphabetically by package name and increasing
366   // package ID (missing ID being the lowest).
367   std::vector<std::unique_ptr<ResourceTablePackage>> packages;
368 
369   // Set of dynamic packages that this table may reference. Their package names get encoded
370   // into the resources.arsc along with their compile-time assigned IDs.
371   ReferencedPackages included_packages_;
372 
373  private:
374   DISALLOW_COPY_AND_ASSIGN(ResourceTable);
375 
376   Validation validation_ = Validation::kEnabled;
377 };
378 
379 }  // namespace aapt
380 
381 #endif  // AAPT_RESOURCE_TABLE_H
382