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