1 /* 2 * Copyright (C) 2017 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 IDMAP_H_ 18 #define IDMAP_H_ 19 20 #include <memory> 21 #include <string> 22 #include <unordered_map> 23 #include <variant> 24 25 #include "android-base/macros.h" 26 #include "androidfw/ConfigDescription.h" 27 #include "androidfw/StringPiece.h" 28 #include "androidfw/ResourceTypes.h" 29 #include "utils/ByteOrder.h" 30 31 namespace android { 32 33 class LoadedIdmap; 34 class IdmapResMap; 35 struct Idmap_header; 36 struct Idmap_data_header; 37 struct Idmap_target_entry; 38 struct Idmap_target_entry_inline; 39 struct Idmap_target_entry_inline_value; 40 struct Idmap_overlay_entry; 41 42 // A string pool for overlay apk assets. The string pool holds the strings of the overlay resources 43 // table and additionally allows for loading strings from the idmap string pool. The idmap string 44 // pool strings are offset after the end of the overlay resource table string pool entries so 45 // queries for strings defined inline in the idmap do not conflict with queries for overlay 46 // resource table strings. 47 class OverlayStringPool : public ResStringPool { 48 public: 49 virtual ~OverlayStringPool(); 50 base::expected<StringPiece16, NullOrIOError> stringAt(size_t idx) const override; 51 base::expected<StringPiece, NullOrIOError> string8At(size_t idx) const override; 52 size_t size() const override; 53 54 explicit OverlayStringPool(const LoadedIdmap* loaded_idmap); 55 private: 56 const Idmap_data_header* data_header_; 57 const ResStringPool* idmap_string_pool_; 58 }; 59 60 // A dynamic reference table for loaded overlay packages that rewrites the resource id of overlay 61 // resources to the resource id of corresponding target resources. 62 class OverlayDynamicRefTable : public DynamicRefTable { 63 public: 64 ~OverlayDynamicRefTable() override = default; 65 status_t lookupResourceId(uint32_t* resId) const override; 66 67 private: 68 explicit OverlayDynamicRefTable(const Idmap_data_header* data_header, 69 const Idmap_overlay_entry* entries, 70 uint8_t target_assigned_package_id); 71 72 // Rewrites a compile-time overlay resource id to the runtime resource id of corresponding target 73 // resource. 74 virtual status_t lookupResourceIdNoRewrite(uint32_t* resId) const; 75 76 const Idmap_data_header* data_header_; 77 const Idmap_overlay_entry* entries_; 78 const int8_t target_assigned_package_id_; 79 80 friend LoadedIdmap; 81 friend IdmapResMap; 82 }; 83 84 // A mapping of target resource ids to a values or resource ids that should overlay the target. 85 class IdmapResMap { 86 public: 87 // Represents the result of a idmap lookup. The result can be one of three possibilities: 88 // 1) The result is a resource id which represents the overlay resource that should act as an 89 // alias of the target resource. 90 // 2) The result is a table entry which overlays the type and value of the target resource. 91 // 3) The result is neither and the target resource is not overlaid. 92 class Result { 93 public: 94 Result() = default; Result(uint32_t value)95 explicit Result(uint32_t value) : data_(value) {}; Result(std::map<ConfigDescription,Res_value> value)96 explicit Result(std::map<ConfigDescription, Res_value> value) : data_(std::move(value)) { 97 } 98 99 // Returns `true` if the resource is overlaid. 100 explicit operator bool() const { 101 return std::get_if<std::monostate>(&data_) == nullptr; 102 } 103 IsResourceId()104 bool IsResourceId() const { 105 return std::get_if<uint32_t>(&data_) != nullptr; 106 } 107 GetResourceId()108 uint32_t GetResourceId() const { 109 return std::get<uint32_t>(data_); 110 } 111 IsInlineValue()112 bool IsInlineValue() const { 113 return std::get_if<2>(&data_) != nullptr; 114 } 115 GetInlineValue()116 const std::map<ConfigDescription, Res_value>& GetInlineValue() const { 117 return std::get<2>(data_); 118 } 119 120 private: 121 std::variant<std::monostate, uint32_t, 122 std::map<ConfigDescription, Res_value> > data_; 123 }; 124 125 // Looks up the value that overlays the target resource id. 126 Result Lookup(uint32_t target_res_id) const; 127 GetOverlayDynamicRefTable()128 inline const OverlayDynamicRefTable* GetOverlayDynamicRefTable() const { 129 return overlay_ref_table_; 130 } 131 132 private: 133 explicit IdmapResMap(const Idmap_data_header* data_header, 134 const Idmap_target_entry* entries, 135 const Idmap_target_entry_inline* inline_entries, 136 const Idmap_target_entry_inline_value* inline_entry_values, 137 const ConfigDescription* configs, 138 uint8_t target_assigned_package_id, 139 const OverlayDynamicRefTable* overlay_ref_table); 140 141 const Idmap_data_header* data_header_; 142 const Idmap_target_entry* entries_; 143 const Idmap_target_entry_inline* inline_entries_; 144 const Idmap_target_entry_inline_value* inline_entry_values_; 145 const ConfigDescription* configurations_; 146 const uint8_t target_assigned_package_id_; 147 const OverlayDynamicRefTable* overlay_ref_table_; 148 149 friend LoadedIdmap; 150 }; 151 152 // Represents a loaded/parsed IDMAP for a Runtime Resource Overlay (RRO). 153 // An RRO and its target APK have different resource IDs assigned to their resources. 154 // An IDMAP is a generated mapping between the resource IDs of the RRO and the target APK. 155 // A LoadedIdmap can be set alongside the overlay's LoadedArsc to allow the overlay ApkAssets to 156 // masquerade as the target ApkAssets resources. 157 class LoadedIdmap { 158 public: 159 // Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed. 160 static std::unique_ptr<LoadedIdmap> Load(StringPiece idmap_path, StringPiece idmap_data); 161 162 // Returns the path to the IDMAP. IdmapPath()163 std::string_view IdmapPath() const { 164 return idmap_path_; 165 } 166 167 // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated. OverlayApkPath()168 std::string_view OverlayApkPath() const { 169 return overlay_apk_path_; 170 } 171 172 // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated. TargetApkPath()173 std::string_view TargetApkPath() const { 174 return target_apk_path_; 175 } 176 177 // Returns a mapping from target resource ids to overlay values. GetTargetResourcesMap(uint8_t target_assigned_package_id,const OverlayDynamicRefTable * overlay_ref_table)178 const IdmapResMap GetTargetResourcesMap(uint8_t target_assigned_package_id, 179 const OverlayDynamicRefTable* overlay_ref_table) const { 180 return IdmapResMap(data_header_, target_entries_, target_inline_entries_, inline_entry_values_, 181 configurations_, target_assigned_package_id, overlay_ref_table); 182 } 183 184 // Returns a dynamic reference table for a loaded overlay package. GetOverlayDynamicRefTable(uint8_t target_assigned_package_id)185 const OverlayDynamicRefTable GetOverlayDynamicRefTable(uint8_t target_assigned_package_id) const { 186 return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id); 187 } 188 189 // Returns whether the idmap file on disk has not been modified since the construction of this 190 // LoadedIdmap. 191 bool IsUpToDate() const; 192 193 protected: 194 // Exposed as protected so that tests can subclass and mock this class out. 195 LoadedIdmap() = default; 196 197 const Idmap_header* header_; 198 const Idmap_data_header* data_header_; 199 const Idmap_target_entry* target_entries_; 200 const Idmap_target_entry_inline* target_inline_entries_; 201 const Idmap_target_entry_inline_value* inline_entry_values_; 202 const ConfigDescription* configurations_; 203 const Idmap_overlay_entry* overlay_entries_; 204 const std::unique_ptr<ResStringPool> string_pool_; 205 206 std::string idmap_path_; 207 std::string_view overlay_apk_path_; 208 std::string_view target_apk_path_; 209 time_t idmap_last_mod_time_; 210 211 private: 212 DISALLOW_COPY_AND_ASSIGN(LoadedIdmap); 213 214 explicit LoadedIdmap(std::string&& idmap_path, 215 const Idmap_header* header, 216 const Idmap_data_header* data_header, 217 const Idmap_target_entry* target_entries, 218 const Idmap_target_entry_inline* target_inline_entries, 219 const Idmap_target_entry_inline_value* inline_entry_values_, 220 const ConfigDescription* configs, 221 const Idmap_overlay_entry* overlay_entries, 222 std::unique_ptr<ResStringPool>&& string_pool, 223 std::string_view overlay_apk_path, 224 std::string_view target_apk_path); 225 226 friend OverlayStringPool; 227 }; 228 229 } // namespace android 230 231 #endif // IDMAP_H_ 232