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 "ConfigDescription.h"
21 #include "Diagnostics.h"
22 #include "Resource.h"
23 #include "ResourceValues.h"
24 #include "Source.h"
25 #include "StringPool.h"
26 #include "io/File.h"
27 
28 #include "android-base/macros.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 // The policy dictating whether an entry is overlayable at runtime by RROs.
61 struct Overlayable {
62   Source source;
63   std::string comment;
64 };
65 
66 class ResourceConfigValue {
67  public:
68   // The configuration for which this value is defined.
69   const ConfigDescription config;
70 
71   // The product for which this value is defined.
72   const std::string product;
73 
74   // The actual Value.
75   std::unique_ptr<Value> value;
76 
ResourceConfigValue(const ConfigDescription & config,const android::StringPiece & product)77   ResourceConfigValue(const ConfigDescription& config, const android::StringPiece& product)
78       : config(config), product(product.to_string()) {}
79 
80  private:
81   DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
82 };
83 
84 // Represents a resource entry, which may have varying values for each defined configuration.
85 class ResourceEntry {
86  public:
87   // The name of the resource. Immutable, as this determines the order of this resource
88   // when doing lookups.
89   const std::string name;
90 
91   // The entry ID for this resource (the EEEE in 0xPPTTEEEE).
92   Maybe<uint16_t> id;
93 
94   // Whether this resource is public (and must maintain the same entry ID across builds).
95   Visibility visibility;
96 
97   Maybe<AllowNew> allow_new;
98 
99   Maybe<Overlayable> overlayable;
100 
101   // The resource's values for each configuration.
102   std::vector<std::unique_ptr<ResourceConfigValue>> values;
103 
ResourceEntry(const android::StringPiece & name)104   explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {}
105 
106   ResourceConfigValue* FindValue(const ConfigDescription& config);
107 
108   ResourceConfigValue* FindValue(const ConfigDescription& config,
109                                  const android::StringPiece& product);
110 
111   ResourceConfigValue* FindOrCreateValue(const ConfigDescription& config,
112                                          const android::StringPiece& product);
113   std::vector<ResourceConfigValue*> FindAllValues(const ConfigDescription& config);
114 
115   template <typename Func>
FindValuesIf(Func f)116   std::vector<ResourceConfigValue*> FindValuesIf(Func f) {
117     std::vector<ResourceConfigValue*> results;
118     for (auto& config_value : values) {
119       if (f(config_value.get())) {
120         results.push_back(config_value.get());
121       }
122     }
123     return results;
124   }
125 
126   bool HasDefaultValue() const;
127 
128  private:
129   DISALLOW_COPY_AND_ASSIGN(ResourceEntry);
130 };
131 
132 // Represents a resource type (eg. string, drawable, layout, etc.) containing resource entries.
133 class ResourceTableType {
134  public:
135   // The logical type of resource (string, drawable, layout, etc.).
136   const ResourceType type;
137 
138   // The type ID for this resource (the TT in 0xPPTTEEEE).
139   Maybe<uint8_t> id;
140 
141   // Whether this type is public (and must maintain the same type ID across builds).
142   Visibility::Level visibility_level = Visibility::Level::kUndefined;
143 
144   // List of resources for this type.
145   std::vector<std::unique_ptr<ResourceEntry>> entries;
146 
ResourceTableType(const ResourceType type)147   explicit ResourceTableType(const ResourceType type) : type(type) {}
148 
149   ResourceEntry* FindEntry(const android::StringPiece& name);
150   ResourceEntry* FindOrCreateEntry(const android::StringPiece& name);
151 
152  private:
153   DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
154 };
155 
156 class ResourceTablePackage {
157  public:
158   std::string name;
159 
160   // The package ID (the PP in 0xPPTTEEEE).
161   Maybe<uint8_t> id;
162 
163   std::vector<std::unique_ptr<ResourceTableType>> types;
164 
165   ResourceTablePackage() = default;
166   ResourceTableType* FindType(ResourceType type);
167   ResourceTableType* FindOrCreateType(const ResourceType type);
168 
169  private:
170   DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
171 };
172 
173 // The container and index for all resources defined for an app.
174 class ResourceTable {
175  public:
176   ResourceTable() = default;
177 
178   enum class CollisionResult { kKeepOriginal, kConflict, kTakeNew };
179 
180   using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*)>;
181 
182   // When a collision of resources occurs, this method decides which value to keep.
183   static CollisionResult ResolveValueCollision(Value* existing, Value* incoming);
184 
185   bool AddResource(const ResourceNameRef& name, const ConfigDescription& config,
186                    const android::StringPiece& product, std::unique_ptr<Value> value,
187                    IDiagnostics* diag);
188 
189   bool AddResourceWithId(const ResourceNameRef& name, const ResourceId& res_id,
190                          const ConfigDescription& config, const android::StringPiece& product,
191                          std::unique_ptr<Value> value, IDiagnostics* diag);
192 
193   bool AddFileReference(const ResourceNameRef& name, const ConfigDescription& config,
194                         const Source& source, const android::StringPiece& path, IDiagnostics* diag);
195 
196   bool AddFileReferenceMangled(const ResourceNameRef& name, const ConfigDescription& config,
197                                const Source& source, const android::StringPiece& path,
198                                io::IFile* file, IDiagnostics* diag);
199 
200   // Same as AddResource, but doesn't verify the validity of the name. This is used
201   // when loading resources from an existing binary resource table that may have mangled names.
202   bool AddResourceMangled(const ResourceNameRef& name, const ConfigDescription& config,
203                           const android::StringPiece& product, std::unique_ptr<Value> value,
204                           IDiagnostics* diag);
205 
206   bool AddResourceWithIdMangled(const ResourceNameRef& name, const ResourceId& id,
207                                 const ConfigDescription& config,
208                                 const android::StringPiece& product, std::unique_ptr<Value> value,
209                                 IDiagnostics* diag);
210 
211   bool SetVisibility(const ResourceNameRef& name, const Visibility& visibility, IDiagnostics* diag);
212   bool SetVisibilityMangled(const ResourceNameRef& name, const Visibility& visibility,
213                             IDiagnostics* diag);
214   bool SetVisibilityWithId(const ResourceNameRef& name, const Visibility& visibility,
215                            const ResourceId& res_id, IDiagnostics* diag);
216   bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility,
217                                   const ResourceId& res_id, IDiagnostics* diag);
218 
219   bool SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
220                       IDiagnostics* diag);
221   bool SetOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable,
222                              IDiagnostics* diag);
223 
224   bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag);
225   bool SetAllowNewMangled(const ResourceNameRef& name, const AllowNew& allow_new,
226                           IDiagnostics* diag);
227 
228   struct SearchResult {
229     ResourceTablePackage* package;
230     ResourceTableType* type;
231     ResourceEntry* entry;
232   };
233 
234   Maybe<SearchResult> FindResource(const ResourceNameRef& name) const;
235 
236   // Returns the package struct with the given name, or nullptr if such a package does not
237   // exist. The empty string is a valid package and typically is used to represent the
238   // 'current' package before it is known to the ResourceTable.
239   ResourceTablePackage* FindPackage(const android::StringPiece& name) const;
240 
241   ResourceTablePackage* FindPackageById(uint8_t id) const;
242 
243   ResourceTablePackage* CreatePackage(const android::StringPiece& name, Maybe<uint8_t> id = {});
244 
245   // Attempts to find a package having the specified name and ID. If not found, a new package
246   // of the specified parameters is created and returned.
247   ResourceTablePackage* CreatePackageAllowingDuplicateNames(const android::StringPiece& name,
248                                                             const Maybe<uint8_t> id);
249 
250   std::unique_ptr<ResourceTable> Clone() const;
251 
252   // The string pool used by this resource table. Values that reference strings must use
253   // this pool to create their strings.
254   // NOTE: `string_pool` must come before `packages` so that it is destroyed after.
255   // When `string_pool` references are destroyed (as they will be when `packages` is destroyed),
256   // they decrement a refCount, which would cause invalid memory access if the pool was already
257   // destroyed.
258   StringPool string_pool;
259 
260   // The list of packages in this table, sorted alphabetically by package name and increasing
261   // package ID (missing ID being the lowest).
262   std::vector<std::unique_ptr<ResourceTablePackage>> packages;
263 
264   // Set of dynamic packages that this table may reference. Their package names get encoded
265   // into the resources.arsc along with their compile-time assigned IDs.
266   std::map<size_t, std::string> included_packages_;
267 
268  private:
269   // The function type that validates a symbol name. Returns a non-empty StringPiece representing
270   // the offending character (which may be more than one byte in UTF-8). Returns an empty string
271   // if the name was valid.
272   using NameValidator = android::StringPiece(const android::StringPiece&);
273 
274   ResourceTablePackage* FindOrCreatePackage(const android::StringPiece& name);
275 
276   bool ValidateName(NameValidator validator, const ResourceNameRef& name, const Source& source,
277                     IDiagnostics* diag);
278 
279   bool AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id,
280                        const ConfigDescription& config, const android::StringPiece& product,
281                        std::unique_ptr<Value> value, NameValidator name_validator,
282                        const CollisionResolverFunc& conflict_resolver, IDiagnostics* diag);
283 
284   bool AddFileReferenceImpl(const ResourceNameRef& name, const ConfigDescription& config,
285                             const Source& source, const android::StringPiece& path, io::IFile* file,
286                             NameValidator name_validator, IDiagnostics* diag);
287 
288   bool SetVisibilityImpl(const ResourceNameRef& name, const Visibility& visibility,
289                          const ResourceId& res_id, NameValidator name_validator,
290                          IDiagnostics* diag);
291 
292   bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new,
293                        NameValidator name_validator, IDiagnostics* diag);
294 
295   bool SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
296                           NameValidator name_validator, IDiagnostics* diag);
297 
298   bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id,
299                           const Visibility& symbol, NameValidator name_validator,
300                           IDiagnostics* diag);
301 
302   DISALLOW_COPY_AND_ASSIGN(ResourceTable);
303 };
304 
305 }  // namespace aapt
306 
307 #endif  // AAPT_RESOURCE_TABLE_H
308