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