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