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