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