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