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