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