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 ART_LIBDEXFILE_DEX_DEX_FILE_LOADER_H_ 18 #define ART_LIBDEXFILE_DEX_DEX_FILE_LOADER_H_ 19 20 #include <cstdint> 21 #include <functional> 22 #include <memory> 23 #include <optional> 24 #include <string> 25 #include <string_view> 26 #include <utility> 27 #include <vector> 28 29 #include "base/os.h" 30 #include "base/unix_file/fd_file.h" 31 #include "dex_file.h" 32 33 namespace art { 34 35 class MemMap; 36 class OatDexFile; 37 class ZipArchive; 38 39 enum class DexFileLoaderErrorCode { 40 kNoError, 41 kEntryNotFound, 42 kExtractToMemoryError, 43 kDexFileError, 44 kMakeReadOnlyError, 45 kVerifyError 46 }; 47 48 // Class that is used to open dex files and deal with corresponding multidex and location logic. 49 class DexFileLoader { 50 public: 51 // name of the DexFile entry within a zip archive 52 static constexpr const char* kClassesDex = "classes.dex"; 53 54 // The separator character in MultiDex locations. 55 static constexpr char kMultiDexSeparator = '!'; 56 57 // Return true if the magic is valid for dex or cdex. 58 static bool IsMagicValid(uint32_t magic); 59 static bool IsMagicValid(const uint8_t* magic); 60 61 // Return true if the corresponding version and magic is valid. 62 static bool IsVersionAndMagicValid(const uint8_t* magic); 63 64 // Check whether a location denotes a multidex dex file. This is a very simple check: returns 65 // whether the string contains the separator character. 66 static bool IsMultiDexLocation(std::string_view location); 67 68 // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for 69 // index == 0, and classes{index + 1}.dex else. 70 static std::string GetMultiDexClassesDexName(size_t index); 71 72 // Return the (possibly synthetic) dex location for a multidex entry. This is dex_location for 73 // index == 0, and dex_location + multi-dex-separator + GetMultiDexClassesDexName(index) else. 74 static std::string GetMultiDexLocation(size_t index, const char* dex_location); 75 76 // Returns the multidex location and the checksum for each dex file in a zip or a dex container. 77 // 78 // This uses the source path provided to DexFileLoader constructor. 79 // 80 // Returns false on error. 81 bool GetMultiDexChecksums(/*out*/ std::vector<std::pair<std::string, uint32_t>>* checksums, 82 /*out*/ std::string* error_msg, 83 /*out*/ bool* only_contains_uncompressed_dex = nullptr); 84 85 // Returns combined checksum of one or more dex files (one checksum for the whole multidex set). 86 // 87 // This uses the source path provided to DexFileLoader constructor. 88 // 89 // Returns false on error. Sets *checksum to nullopt for an empty set. 90 bool GetMultiDexChecksum(/*out*/ std::optional<uint32_t>* checksum, 91 /*out*/ std::string* error_msg, 92 /*out*/ bool* only_contains_uncompressed_dex = nullptr); 93 94 // Returns combined checksum of one or more dex files (one checksum for the whole multidex set). 95 // 96 // This uses already open dex files. 97 // 98 // It starts iteration at index 'i', which must be a primary dex file, 99 // and it sets 'i' to the next primary dex file or to end of the array. 100 template <typename DexFilePtrVector> // array|vector<unique_ptr|DexFile|OatDexFile*>. GetMultiDexChecksum(const DexFilePtrVector & dex_files,size_t * i)101 static uint32_t GetMultiDexChecksum(const DexFilePtrVector& dex_files, 102 /*inout*/ size_t* i) { 103 CHECK_LT(*i, dex_files.size()) << "No dex files"; 104 std::optional<uint32_t> checksum; 105 for (; *i < dex_files.size(); ++(*i)) { 106 const auto* dex_file = &*dex_files[*i]; 107 bool is_primary_dex = !IsMultiDexLocation(dex_file->GetLocation()); 108 if (!checksum.has_value()) { // First dex file. 109 CHECK(is_primary_dex) << dex_file->GetLocation(); // Expect primary dex. 110 } else if (is_primary_dex) { // Later dex file. 111 break; // Found another primary dex file, terminate iteration. 112 } 113 if (!is_primary_dex && dex_file->GetDexVersion() >= DexFile::kDexContainerVersion) { 114 if (dex_file->GetLocationChecksum() == dex_files[*i - 1]->GetLocationChecksum() + 1) { 115 continue; 116 } 117 } 118 checksum = checksum.value_or(kEmptyMultiDexChecksum) ^ dex_file->GetLocationChecksum(); 119 } 120 CHECK(checksum.has_value()); 121 return checksum.value(); 122 } 123 124 // Calculate checksum of dex files in a vector, starting at index 0. 125 // It will CHECK that the whole vector is consumed (i.e. there is just one primary dex file). 126 template <typename DexFilePtrVector> GetMultiDexChecksum(const DexFilePtrVector & dex_files)127 static uint32_t GetMultiDexChecksum(const DexFilePtrVector& dex_files) { 128 size_t i = 0; 129 uint32_t checksum = GetMultiDexChecksum(dex_files, &i); 130 CHECK_EQ(i, dex_files.size()); 131 return checksum; 132 } 133 134 // Non-zero initial value for multi-dex to catch bugs if multi-dex checksum is compared 135 // directly to DexFile::GetLocationChecksum without going through GetMultiDexChecksum. 136 static constexpr uint32_t kEmptyMultiDexChecksum = 1; 137 138 // Returns the canonical form of the given dex location. 139 // 140 // There are different flavors of "dex locations" as follows: 141 // the file name of a dex file: 142 // The actual file path that the dex file has on disk. 143 // dex_location: 144 // This acts as a key for the class linker to know which dex file to load. 145 // It may correspond to either an old odex file or a particular dex file 146 // inside an oat file. In the first case it will also match the file name 147 // of the dex file. In the second case (oat) it will include the file name 148 // and possibly some multidex annotation to uniquely identify it. 149 // canonical_dex_location: 150 // the dex_location where its file name part has been made canonical. 151 static std::string GetDexCanonicalLocation(const char* dex_location); 152 153 // For normal dex files, location and base location coincide. If a dex file is part of a multidex 154 // archive, the base location is the name of the originating jar/apk, stripped of any internal 155 // classes*.dex path. GetBaseLocation(const char * location)156 static std::string GetBaseLocation(const char* location) { 157 const char* pos = strrchr(location, kMultiDexSeparator); 158 return (pos == nullptr) ? location : std::string(location, pos - location); 159 } 160 GetBaseLocation(const std::string & location)161 static std::string GetBaseLocation(const std::string& location) { 162 return GetBaseLocation(location.c_str()); 163 } 164 165 // Returns the '!classes*.dex' part of the dex location. Returns an empty 166 // string if there is no multidex suffix for the given location. 167 // The kMultiDexSeparator is included in the returned suffix. GetMultiDexSuffix(const std::string & location)168 static std::string GetMultiDexSuffix(const std::string& location) { 169 size_t pos = location.rfind(kMultiDexSeparator); 170 return (pos == std::string::npos) ? std::string() : location.substr(pos); 171 } 172 DexFileLoader(const char * filename,const File * file,const std::string & location)173 DexFileLoader(const char* filename, const File* file, const std::string& location) 174 : filename_(filename), file_(file), location_(location) { 175 CHECK(file != nullptr); // Must be non-null, but may be invalid. 176 } 177 DexFileLoader(std::shared_ptr<DexFileContainer> container,const std::string & location)178 DexFileLoader(std::shared_ptr<DexFileContainer> container, const std::string& location) 179 : root_container_(std::move(container)), location_(location) { 180 CHECK(root_container_ != nullptr); 181 } 182 183 DexFileLoader(const uint8_t* base, size_t size, const std::string& location); 184 185 DexFileLoader(std::vector<uint8_t>&& memory, const std::string& location); 186 187 DexFileLoader(MemMap&& mem_map, const std::string& location); 188 DexFileLoader(File * file,const std::string & location)189 DexFileLoader(File* file, const std::string& location) 190 : DexFileLoader(/*filename=*/location.c_str(), file, location) {} 191 DexFileLoader(const char * filename,const std::string & location)192 DexFileLoader(const char* filename, const std::string& location) 193 : DexFileLoader(filename, /*file=*/&kInvalidFile, location) {} 194 DexFileLoader(const std::string & location)195 explicit DexFileLoader(const std::string& location) 196 : DexFileLoader(location.c_str(), /*file=*/&kInvalidFile, location) {} 197 ~DexFileLoader()198 virtual ~DexFileLoader() {} 199 200 // Open singe dex file at the given offset within the container (usually 0). 201 // This intentionally ignores all other dex files in the container 202 std::unique_ptr<const DexFile> OpenOne(size_t header_offset, 203 uint32_t location_checksum, 204 const OatDexFile* oat_dex_file, 205 bool verify, 206 bool verify_checksum, 207 std::string* error_msg); 208 209 // Open single dex file (starting at offset 0 of the container). 210 // It expects only single dex file to be present and will fail otherwise. Open(uint32_t location_checksum,const OatDexFile * oat_dex_file,bool verify,bool verify_checksum,std::string * error_msg)211 std::unique_ptr<const DexFile> Open(uint32_t location_checksum, 212 const OatDexFile* oat_dex_file, 213 bool verify, 214 bool verify_checksum, 215 std::string* error_msg) { 216 std::unique_ptr<const DexFile> dex_file = OpenOne( 217 /*header_offset=*/0, location_checksum, oat_dex_file, verify, verify_checksum, error_msg); 218 // This API returns only singe DEX file, so check there is just single dex in the container. 219 CHECK(dex_file == nullptr || dex_file->IsDexContainerLastEntry()) << location_; 220 return dex_file; 221 } 222 Open(uint32_t location_checksum,bool verify,bool verify_checksum,std::string * error_msg)223 std::unique_ptr<const DexFile> Open(uint32_t location_checksum, 224 bool verify, 225 bool verify_checksum, 226 std::string* error_msg) { 227 return Open(location_checksum, 228 /*oat_dex_file=*/nullptr, 229 verify, 230 verify_checksum, 231 error_msg); 232 } 233 234 // Opens all dex files, guessing the container format based on file magic. 235 bool Open(bool verify, 236 bool verify_checksum, 237 bool allow_no_dex_files, 238 DexFileLoaderErrorCode* error_code, 239 std::string* error_msg, 240 std::vector<std::unique_ptr<const DexFile>>* dex_files); 241 Open(bool verify,bool verify_checksum,DexFileLoaderErrorCode * error_code,std::string * error_msg,std::vector<std::unique_ptr<const DexFile>> * dex_files)242 bool Open(bool verify, 243 bool verify_checksum, 244 DexFileLoaderErrorCode* error_code, 245 std::string* error_msg, 246 std::vector<std::unique_ptr<const DexFile>>* dex_files) { 247 return Open(verify, 248 verify_checksum, 249 /*allow_no_dex_files=*/false, 250 error_code, 251 error_msg, 252 dex_files); 253 } 254 Open(bool verify,bool verify_checksum,bool allow_no_dex_files,std::string * error_msg,std::vector<std::unique_ptr<const DexFile>> * dex_files)255 bool Open(bool verify, 256 bool verify_checksum, 257 bool allow_no_dex_files, 258 std::string* error_msg, 259 std::vector<std::unique_ptr<const DexFile>>* dex_files) { 260 DexFileLoaderErrorCode error_code; 261 return Open(verify, verify_checksum, allow_no_dex_files, &error_code, error_msg, dex_files); 262 } 263 Open(bool verify,bool verify_checksum,std::string * error_msg,std::vector<std::unique_ptr<const DexFile>> * dex_files)264 bool Open(bool verify, 265 bool verify_checksum, 266 std::string* error_msg, 267 std::vector<std::unique_ptr<const DexFile>>* dex_files) { 268 DexFileLoaderErrorCode error_code; 269 return Open(verify, 270 verify_checksum, 271 /*allow_no_dex_files=*/false, 272 &error_code, 273 error_msg, 274 dex_files); 275 } 276 277 protected: 278 static const File kInvalidFile; // Used for "no file descriptor" (-1). 279 280 bool InitAndReadMagic(size_t header_offset, uint32_t* magic, std::string* error_msg); 281 282 // Ensure we have root container. If we are backed by a file, memory-map it. 283 // We can only do this for dex files since zip files might be too big to map. 284 bool MapRootContainer(std::string* error_msg); 285 286 static std::unique_ptr<DexFile> OpenCommon(std::shared_ptr<DexFileContainer> container, 287 const uint8_t* base, 288 size_t size, 289 const std::string& location, 290 std::optional<uint32_t> location_checksum, 291 const OatDexFile* oat_dex_file, 292 bool verify, 293 bool verify_checksum, 294 std::string* error_msg, 295 DexFileLoaderErrorCode* error_code); 296 297 // Old signature preserved for app-compat. 298 std::unique_ptr<const DexFile> Open(const uint8_t* base, 299 size_t size, 300 const std::string& location, 301 uint32_t location_checksum, 302 const OatDexFile* oat_dex_file, 303 bool verify, 304 bool verify_checksum, 305 std::string* error_msg, 306 std::unique_ptr<DexFileContainer> container) const; 307 308 // Old signature preserved for app-compat. 309 enum VerifyResult {}; 310 static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base, 311 size_t size, 312 const uint8_t* data_base, 313 size_t data_size, 314 const std::string& location, 315 uint32_t location_checksum, 316 const OatDexFile* oat_dex_file, 317 bool verify, 318 bool verify_checksum, 319 std::string* error_msg, 320 std::unique_ptr<DexFileContainer> container, 321 VerifyResult* verify_result); 322 323 // Open .dex files from the entry_name in a zip archive. 324 bool OpenFromZipEntry(const ZipArchive& zip_archive, 325 const char* entry_name, 326 const std::string& location, 327 bool verify, 328 bool verify_checksum, 329 /*inout*/ size_t* multidex_count, 330 /*out*/ DexFileLoaderErrorCode* error_code, 331 /*out*/ std::string* error_msg, 332 /*out*/ std::vector<std::unique_ptr<const DexFile>>* dex_files) const; 333 334 // The DexFileLoader can be backed either by file or by memory (i.e. DexFileContainer). 335 // We can not just mmap the file since APKs might be unreasonably large for 32-bit system. 336 std::string filename_; 337 const File* file_ = &kInvalidFile; 338 std::optional<File> owned_file_; // May be used as backing storage for 'file_'. 339 std::shared_ptr<DexFileContainer> root_container_; 340 341 // The full absolute path to the dex file, if it was loaded from disk. 342 // 343 // Can also be a path to a multidex container (typically apk), followed by 344 // kMultiDexSeparator and the file inside the container. 345 // 346 // On host this may not be an absolute path. 347 // 348 // On device libnativeloader uses this to determine the location of the java 349 // package or shared library, which decides where to load native libraries 350 // from. 351 const std::string location_; 352 }; 353 354 } // namespace art 355 356 #endif // ART_LIBDEXFILE_DEX_DEX_FILE_LOADER_H_ 357