1 /* 2 * Copyright (C) 2018 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 /* 18 * # idmap file format (current version) 19 * 20 * idmap := header data* 21 * header := magic version target_crc overlay_crc target_path overlay_path debug_info 22 * data := data_header data_block* 23 * data_header := target_package_id types_count 24 * data_block := target_type overlay_type entry_count entry_offset entry* 25 * overlay_path := string256 26 * target_path := string256 27 * debug_info := string 28 * string := <uint32_t> <uint8_t>+ '\0'+ 29 * entry := <uint32_t> 30 * entry_count := <uint16_t> 31 * entry_offset := <uint16_t> 32 * magic := <uint32_t> 33 * overlay_crc := <uint32_t> 34 * overlay_type := <uint16_t> 35 * string256 := <uint8_t>[256] 36 * target_crc := <uint32_t> 37 * target_package_id := <uint16_t> 38 * target_type := <uint16_t> 39 * types_count := <uint16_t> 40 * version := <uint32_t> 41 * 42 * 43 * # idmap file format changelog 44 * ## v1 45 * - Identical to idmap v1. 46 * 47 * ## v2 48 * - Entries are no longer separated by type into type specific data blocks. 49 * - Added overlay-indexed target resource id lookup capabilities. 50 * - Target and overlay entries are stored as a sparse array in the data block. The target entries 51 * array maps from target resource id to overlay data type and value and the array is sorted by 52 * target resource id. The overlay entries array maps from overlay resource id to target resource 53 * id and the array is sorted by overlay resource id. It is important for both arrays to be sorted 54 * to allow for O(log(number_of_overlaid_resources)) performance when looking up resource 55 * mappings at runtime. 56 * - Idmap can now encode a type and value to override a resource without needing a table entry. 57 * - A string pool block is included to retrieve the value of strings that do not have a resource 58 * table entry. 59 * 60 * ## v3 61 * - Add 'debug' block to IdmapHeader. 62 */ 63 64 #ifndef IDMAP2_INCLUDE_IDMAP2_IDMAP_H_ 65 #define IDMAP2_INCLUDE_IDMAP2_IDMAP_H_ 66 67 #include <iostream> 68 #include <memory> 69 #include <string> 70 #include <vector> 71 72 #include "android-base/macros.h" 73 #include "androidfw/ApkAssets.h" 74 #include "androidfw/ResourceTypes.h" 75 #include "androidfw/StringPiece.h" 76 #include "idmap2/ResourceMapping.h" 77 #include "idmap2/ZipFile.h" 78 79 namespace android::idmap2 { 80 81 class Idmap; 82 class Visitor; 83 84 static constexpr const ResourceId kPadding = 0xffffffffu; 85 static constexpr const EntryId kNoEntry = 0xffffu; 86 87 // magic number: all idmap files start with this 88 static constexpr const uint32_t kIdmapMagic = android::kIdmapMagic; 89 90 // current version of the idmap binary format; must be incremented when the format is changed 91 static constexpr const uint32_t kIdmapCurrentVersion = android::kIdmapCurrentVersion; 92 93 // strings in the idmap are encoded char arrays of length 'kIdmapStringLength' (including mandatory 94 // terminating null) 95 static constexpr const size_t kIdmapStringLength = 256; 96 97 // Retrieves a crc generated using all of the files within the zip that can affect idmap generation. 98 Result<uint32_t> GetPackageCrc(const ZipFile& zip_info); 99 100 class IdmapHeader { 101 public: 102 static std::unique_ptr<const IdmapHeader> FromBinaryStream(std::istream& stream); 103 GetMagic()104 inline uint32_t GetMagic() const { 105 return magic_; 106 } 107 GetVersion()108 inline uint32_t GetVersion() const { 109 return version_; 110 } 111 GetTargetCrc()112 inline uint32_t GetTargetCrc() const { 113 return target_crc_; 114 } 115 GetOverlayCrc()116 inline uint32_t GetOverlayCrc() const { 117 return overlay_crc_; 118 } 119 GetFulfilledPolicies()120 inline uint32_t GetFulfilledPolicies() const { 121 return fulfilled_policies_; 122 } 123 GetEnforceOverlayable()124 bool GetEnforceOverlayable() const { 125 return enforce_overlayable_; 126 } 127 GetTargetPath()128 inline StringPiece GetTargetPath() const { 129 return StringPiece(target_path_); 130 } 131 GetOverlayPath()132 inline StringPiece GetOverlayPath() const { 133 return StringPiece(overlay_path_); 134 } 135 GetDebugInfo()136 inline const std::string& GetDebugInfo() const { 137 return debug_info_; 138 } 139 140 // Invariant: anytime the idmap data encoding is changed, the idmap version 141 // field *must* be incremented. Because of this, we know that if the idmap 142 // header is up-to-date the entire file is up-to-date. 143 Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path, 144 PolicyBitmask fulfilled_policies, bool enforce_overlayable) const; 145 Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path, uint32_t target_crc, 146 uint32_t overlay_crc, PolicyBitmask fulfilled_policies, 147 bool enforce_overlayable) const; 148 149 void accept(Visitor* v) const; 150 151 private: IdmapHeader()152 IdmapHeader() { 153 } 154 155 uint32_t magic_; 156 uint32_t version_; 157 uint32_t target_crc_; 158 uint32_t overlay_crc_; 159 uint32_t fulfilled_policies_; 160 bool enforce_overlayable_; 161 char target_path_[kIdmapStringLength]; 162 char overlay_path_[kIdmapStringLength]; 163 std::string debug_info_; 164 165 friend Idmap; 166 DISALLOW_COPY_AND_ASSIGN(IdmapHeader); 167 }; 168 class IdmapData { 169 public: 170 class Header { 171 public: 172 static std::unique_ptr<const Header> FromBinaryStream(std::istream& stream); 173 GetTargetPackageId()174 inline PackageId GetTargetPackageId() const { 175 return target_package_id_; 176 } 177 GetOverlayPackageId()178 inline PackageId GetOverlayPackageId() const { 179 return overlay_package_id_; 180 } 181 GetTargetEntryCount()182 inline uint32_t GetTargetEntryCount() const { 183 return target_entry_count; 184 } 185 GetOverlayEntryCount()186 inline uint32_t GetOverlayEntryCount() const { 187 return overlay_entry_count; 188 } 189 GetStringPoolIndexOffset()190 inline uint32_t GetStringPoolIndexOffset() const { 191 return string_pool_index_offset; 192 } 193 GetStringPoolLength()194 inline uint32_t GetStringPoolLength() const { 195 return string_pool_len; 196 } 197 198 void accept(Visitor* v) const; 199 200 private: 201 PackageId target_package_id_; 202 PackageId overlay_package_id_; 203 uint32_t target_entry_count; 204 uint32_t overlay_entry_count; 205 uint32_t string_pool_index_offset; 206 uint32_t string_pool_len; 207 Header() = default; 208 209 friend Idmap; 210 friend IdmapData; 211 DISALLOW_COPY_AND_ASSIGN(Header); 212 }; 213 214 struct TargetEntry { 215 ResourceId target_id; 216 TargetValue::DataType data_type; 217 TargetValue::DataValue data_value; 218 }; 219 220 struct OverlayEntry { 221 ResourceId overlay_id; 222 ResourceId target_id; 223 }; 224 225 static std::unique_ptr<const IdmapData> FromBinaryStream(std::istream& stream); 226 227 static Result<std::unique_ptr<const IdmapData>> FromResourceMapping( 228 const ResourceMapping& resource_mapping); 229 GetHeader()230 inline const std::unique_ptr<const Header>& GetHeader() const { 231 return header_; 232 } 233 GetTargetEntries()234 inline const std::vector<TargetEntry>& GetTargetEntries() const { 235 return target_entries_; 236 } 237 GetOverlayEntries()238 inline const std::vector<OverlayEntry>& GetOverlayEntries() const { 239 return overlay_entries_; 240 } 241 GetStringPoolData()242 inline const void* GetStringPoolData() const { 243 return string_pool_.get(); 244 } 245 246 void accept(Visitor* v) const; 247 248 private: IdmapData()249 IdmapData() { 250 } 251 252 std::unique_ptr<const Header> header_; 253 std::vector<TargetEntry> target_entries_; 254 std::vector<OverlayEntry> overlay_entries_; 255 std::unique_ptr<uint8_t[]> string_pool_; 256 257 friend Idmap; 258 DISALLOW_COPY_AND_ASSIGN(IdmapData); 259 }; 260 261 class Idmap { 262 public: 263 static std::string CanonicalIdmapPathFor(const std::string& absolute_dir, 264 const std::string& absolute_apk_path); 265 266 static Result<std::unique_ptr<const Idmap>> FromBinaryStream(std::istream& stream); 267 268 // In the current version of idmap, the first package in each resources.arsc 269 // file is used; change this in the next version of idmap to use a named 270 // package instead; also update FromApkAssets to take additional parameters: 271 // the target and overlay package names 272 static Result<std::unique_ptr<const Idmap>> FromApkAssets(const ApkAssets& target_apk_assets, 273 const ApkAssets& overlay_apk_assets, 274 const PolicyBitmask& fulfilled_policies, 275 bool enforce_overlayable); 276 GetHeader()277 inline const std::unique_ptr<const IdmapHeader>& GetHeader() const { 278 return header_; 279 } 280 GetData()281 inline const std::vector<std::unique_ptr<const IdmapData>>& GetData() const { 282 return data_; 283 } 284 285 void accept(Visitor* v) const; 286 287 private: Idmap()288 Idmap() { 289 } 290 291 std::unique_ptr<const IdmapHeader> header_; 292 std::vector<std::unique_ptr<const IdmapData>> data_; 293 294 DISALLOW_COPY_AND_ASSIGN(Idmap); 295 }; 296 297 class Visitor { 298 public: ~Visitor()299 virtual ~Visitor() { 300 } 301 virtual void visit(const Idmap& idmap) = 0; 302 virtual void visit(const IdmapHeader& header) = 0; 303 virtual void visit(const IdmapData& data) = 0; 304 virtual void visit(const IdmapData::Header& header) = 0; 305 }; 306 307 } // namespace android::idmap2 308 309 #endif // IDMAP2_INCLUDE_IDMAP2_IDMAP_H_ 310