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