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