blob: 8cab1a501a6c5e5feffcce314e48ae29c5a15193 [file] [log] [blame]
Mathieu Chartier79c87da2017-10-10 11:54:29 -07001/*
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#include "dex_file_loader.h"
18
19#include <sys/mman.h> // For the PROT_* and MAP_* constants.
20#include <sys/stat.h>
21
22#include "android-base/stringprintf.h"
23
24#include "base/file_magic.h"
25#include "base/stl_util.h"
26#include "base/systrace.h"
27#include "base/unix_file/fd_file.h"
28#include "dex_file.h"
29#include "dex_file_verifier.h"
Mathieu Chartier292567e2017-10-12 13:24:38 -070030#include "standard_dex_file.h"
Mathieu Chartier79c87da2017-10-10 11:54:29 -070031#include "zip_archive.h"
32
33namespace art {
34
35using android::base::StringPrintf;
36
37static constexpr OatDexFile* kNoOatDexFile = nullptr;
38
39
40bool DexFileLoader::IsValidMagic(uint32_t magic) {
41 return IsValidMagic(reinterpret_cast<uint8_t*>(&magic));
42}
43
44bool DexFileLoader::IsValidMagic(const uint8_t* magic) {
Mathieu Chartier292567e2017-10-12 13:24:38 -070045 return StandardDexFile::IsMagicValid(magic);
Mathieu Chartier79c87da2017-10-10 11:54:29 -070046}
47
48bool DexFileLoader::GetMultiDexChecksums(const char* filename,
49 std::vector<uint32_t>* checksums,
50 std::string* error_msg) {
51 CHECK(checksums != nullptr);
52 uint32_t magic;
53
54 File fd = OpenAndReadMagic(filename, &magic, error_msg);
55 if (fd.Fd() == -1) {
56 DCHECK(!error_msg->empty());
57 return false;
58 }
59 if (IsZipMagic(magic)) {
60 std::unique_ptr<ZipArchive> zip_archive(
61 ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
62 if (zip_archive.get() == nullptr) {
63 *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
64 error_msg->c_str());
65 return false;
66 }
67
68 uint32_t i = 0;
69 std::string zip_entry_name = GetMultiDexClassesDexName(i++);
70 std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
71 if (zip_entry.get() == nullptr) {
72 *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
73 zip_entry_name.c_str(), error_msg->c_str());
74 return false;
75 }
76
77 do {
78 checksums->push_back(zip_entry->GetCrc32());
79 zip_entry_name = GetMultiDexClassesDexName(i++);
80 zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
81 } while (zip_entry.get() != nullptr);
82 return true;
83 }
84 if (IsValidMagic(magic)) {
85 std::unique_ptr<const DexFile> dex_file(
86 OpenFile(fd.Release(), filename, false, false, error_msg));
87 if (dex_file == nullptr) {
88 return false;
89 }
90 checksums->push_back(dex_file->GetHeader().checksum_);
91 return true;
92 }
93 *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
94 return false;
95}
96
97bool DexFileLoader::IsMultiDexLocation(const char* location) {
98 return strrchr(location, kMultiDexSeparator) != nullptr;
99}
100
101std::string DexFileLoader::GetMultiDexClassesDexName(size_t index) {
102 return (index == 0) ? "classes.dex" : StringPrintf("classes%zu.dex", index + 1);
103}
104
105std::string DexFileLoader::GetMultiDexLocation(size_t index, const char* dex_location) {
106 return (index == 0)
107 ? dex_location
108 : StringPrintf("%s%cclasses%zu.dex", dex_location, kMultiDexSeparator, index + 1);
109}
110
111std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) {
112 CHECK_NE(dex_location, static_cast<const char*>(nullptr));
113 std::string base_location = GetBaseLocation(dex_location);
114 const char* suffix = dex_location + base_location.size();
115 DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
116 UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
117 if (path != nullptr && path.get() != base_location) {
118 return std::string(path.get()) + suffix;
119 } else if (suffix[0] == 0) {
120 return base_location;
121 } else {
122 return dex_location;
123 }
124}
125
126std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base,
127 size_t size,
128 const std::string& location,
129 uint32_t location_checksum,
130 const OatDexFile* oat_dex_file,
131 bool verify,
132 bool verify_checksum,
133 std::string* error_msg) {
134 ScopedTrace trace(std::string("Open dex file from RAM ") + location);
135 return OpenCommon(base,
136 size,
137 location,
138 location_checksum,
139 oat_dex_file,
140 verify,
141 verify_checksum,
142 error_msg);
143}
144
145std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location,
146 uint32_t location_checksum,
147 std::unique_ptr<MemMap> map,
148 bool verify,
149 bool verify_checksum,
150 std::string* error_msg) {
151 ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location);
152 CHECK(map.get() != nullptr);
153
154 if (map->Size() < sizeof(DexFile::Header)) {
155 *error_msg = StringPrintf(
156 "DexFile: failed to open dex file '%s' that is too short to have a header",
157 location.c_str());
158 return nullptr;
159 }
160
161 std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
162 map->Size(),
163 location,
164 location_checksum,
165 kNoOatDexFile,
166 verify,
167 verify_checksum,
168 error_msg);
169 if (dex_file != nullptr) {
170 dex_file->mem_map_ = std::move(map);
171 }
172 return dex_file;
173}
174
175bool DexFileLoader::Open(const char* filename,
176 const std::string& location,
177 bool verify_checksum,
178 std::string* error_msg,
179 std::vector<std::unique_ptr<const DexFile>>* dex_files) {
180 ScopedTrace trace(std::string("Open dex file ") + std::string(location));
181 DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
182 uint32_t magic;
183 File fd = OpenAndReadMagic(filename, &magic, error_msg);
184 if (fd.Fd() == -1) {
185 DCHECK(!error_msg->empty());
186 return false;
187 }
188 if (IsZipMagic(magic)) {
189 return OpenZip(fd.Release(), location, verify_checksum, error_msg, dex_files);
190 }
191 if (IsValidMagic(magic)) {
192 std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(),
193 location,
194 /* verify */ true,
195 verify_checksum,
196 error_msg));
197 if (dex_file.get() != nullptr) {
198 dex_files->push_back(std::move(dex_file));
199 return true;
200 } else {
201 return false;
202 }
203 }
204 *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
205 return false;
206}
207
208std::unique_ptr<const DexFile> DexFileLoader::OpenDex(int fd,
209 const std::string& location,
210 bool verify_checksum,
211 std::string* error_msg) {
212 ScopedTrace trace("Open dex file " + std::string(location));
213 return OpenFile(fd, location, true /* verify */, verify_checksum, error_msg);
214}
215
216bool DexFileLoader::OpenZip(int fd,
217 const std::string& location,
218 bool verify_checksum,
219 std::string* error_msg,
220 std::vector<std::unique_ptr<const DexFile>>* dex_files) {
221 ScopedTrace trace("Dex file open Zip " + std::string(location));
222 DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr";
223 std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
224 if (zip_archive.get() == nullptr) {
225 DCHECK(!error_msg->empty());
226 return false;
227 }
228 return OpenAllDexFilesFromZip(*zip_archive, location, verify_checksum, error_msg, dex_files);
229}
230
231std::unique_ptr<const DexFile> DexFileLoader::OpenFile(int fd,
232 const std::string& location,
233 bool verify,
234 bool verify_checksum,
235 std::string* error_msg) {
236 ScopedTrace trace(std::string("Open dex file ") + std::string(location));
237 CHECK(!location.empty());
238 std::unique_ptr<MemMap> map;
239 {
240 File delayed_close(fd, /* check_usage */ false);
241 struct stat sbuf;
242 memset(&sbuf, 0, sizeof(sbuf));
243 if (fstat(fd, &sbuf) == -1) {
244 *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
245 strerror(errno));
246 return nullptr;
247 }
248 if (S_ISDIR(sbuf.st_mode)) {
249 *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
250 return nullptr;
251 }
252 size_t length = sbuf.st_size;
253 map.reset(MemMap::MapFile(length,
254 PROT_READ,
255 MAP_PRIVATE,
256 fd,
257 0,
258 /*low_4gb*/false,
259 location.c_str(),
260 error_msg));
261 if (map == nullptr) {
262 DCHECK(!error_msg->empty());
263 return nullptr;
264 }
265 }
266
267 if (map->Size() < sizeof(DexFile::Header)) {
268 *error_msg = StringPrintf(
269 "DexFile: failed to open dex file '%s' that is too short to have a header",
270 location.c_str());
271 return nullptr;
272 }
273
274 const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin());
275
276 std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
277 map->Size(),
278 location,
279 dex_header->checksum_,
280 kNoOatDexFile,
281 verify,
282 verify_checksum,
283 error_msg);
284 if (dex_file != nullptr) {
285 dex_file->mem_map_ = std::move(map);
286 }
287
288 return dex_file;
289}
290
291std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip(
292 const ZipArchive& zip_archive,
293 const char* entry_name,
294 const std::string& location,
295 bool verify_checksum,
296 std::string* error_msg,
297 ZipOpenErrorCode* error_code) {
298 ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
299 CHECK(!location.empty());
300 std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
301 if (zip_entry == nullptr) {
302 *error_code = ZipOpenErrorCode::kEntryNotFound;
303 return nullptr;
304 }
305 if (zip_entry->GetUncompressedLength() == 0) {
306 *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
307 *error_code = ZipOpenErrorCode::kDexFileError;
308 return nullptr;
309 }
310
311 std::unique_ptr<MemMap> map;
312 if (zip_entry->IsUncompressed()) {
313 if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) {
314 // Do not mmap unaligned ZIP entries because
315 // doing so would fail dex verification which requires 4 byte alignment.
316 LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
317 << "please zipalign to " << alignof(DexFile::Header) << " bytes. "
318 << "Falling back to extracting file.";
319 } else {
320 // Map uncompressed files within zip as file-backed to avoid a dirty copy.
321 map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));
322 if (map == nullptr) {
323 LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
324 << "is your ZIP file corrupted? Falling back to extraction.";
325 // Try again with Extraction which still has a chance of recovery.
326 }
327 }
328 }
329
330 if (map == nullptr) {
331 // Default path for compressed ZIP entries,
332 // and fallback for stored ZIP entries.
333 map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
334 }
335
336 if (map == nullptr) {
337 *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
338 error_msg->c_str());
339 *error_code = ZipOpenErrorCode::kExtractToMemoryError;
340 return nullptr;
341 }
342 VerifyResult verify_result;
343 std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
344 map->Size(),
345 location,
346 zip_entry->GetCrc32(),
347 kNoOatDexFile,
348 /* verify */ true,
349 verify_checksum,
350 error_msg,
351 &verify_result);
352 if (dex_file == nullptr) {
353 if (verify_result == VerifyResult::kVerifyNotAttempted) {
354 *error_code = ZipOpenErrorCode::kDexFileError;
355 } else {
356 *error_code = ZipOpenErrorCode::kVerifyError;
357 }
358 return nullptr;
359 }
360 dex_file->mem_map_ = std::move(map);
361 if (!dex_file->DisableWrite()) {
362 *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
363 *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
364 return nullptr;
365 }
366 CHECK(dex_file->IsReadOnly()) << location;
367 if (verify_result != VerifyResult::kVerifySucceeded) {
368 *error_code = ZipOpenErrorCode::kVerifyError;
369 return nullptr;
370 }
371 *error_code = ZipOpenErrorCode::kNoError;
372 return dex_file;
373}
374
375// Technically we do not have a limitation with respect to the number of dex files that can be in a
376// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
377// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
378// seems an excessive number.
379static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
380
381bool DexFileLoader::OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
382 const std::string& location,
383 bool verify_checksum,
384 std::string* error_msg,
385 std::vector<std::unique_ptr<const DexFile>>* dex_files) {
386 ScopedTrace trace("Dex file open from Zip " + std::string(location));
387 DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
388 ZipOpenErrorCode error_code;
389 std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
390 kClassesDex,
391 location,
392 verify_checksum,
393 error_msg,
394 &error_code));
395 if (dex_file.get() == nullptr) {
396 return false;
397 } else {
398 // Had at least classes.dex.
399 dex_files->push_back(std::move(dex_file));
400
401 // Now try some more.
402
403 // We could try to avoid std::string allocations by working on a char array directly. As we
404 // do not expect a lot of iterations, this seems too involved and brittle.
405
406 for (size_t i = 1; ; ++i) {
407 std::string name = GetMultiDexClassesDexName(i);
408 std::string fake_location = GetMultiDexLocation(i, location.c_str());
409 std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
410 name.c_str(),
411 fake_location,
412 verify_checksum,
413 error_msg,
414 &error_code));
415 if (next_dex_file.get() == nullptr) {
416 if (error_code != ZipOpenErrorCode::kEntryNotFound) {
417 LOG(WARNING) << "Zip open failed: " << *error_msg;
418 }
419 break;
420 } else {
421 dex_files->push_back(std::move(next_dex_file));
422 }
423
424 if (i == kWarnOnManyDexFilesThreshold) {
425 LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
426 << " dex files. Please consider coalescing and shrinking the number to "
427 " avoid runtime overhead.";
428 }
429
430 if (i == std::numeric_limits<size_t>::max()) {
431 LOG(ERROR) << "Overflow in number of dex files!";
432 break;
433 }
434 }
435
436 return true;
437 }
438}
439
440std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
441 size_t size,
442 const std::string& location,
443 uint32_t location_checksum,
444 const OatDexFile* oat_dex_file,
445 bool verify,
446 bool verify_checksum,
447 std::string* error_msg,
448 VerifyResult* verify_result) {
449 if (verify_result != nullptr) {
450 *verify_result = VerifyResult::kVerifyNotAttempted;
451 }
452 std::unique_ptr<DexFile> dex_file;
Mathieu Chartier292567e2017-10-12 13:24:38 -0700453 if (StandardDexFile::IsMagicValid(base)) {
454 dex_file.reset(new StandardDexFile(base, size, location, location_checksum, oat_dex_file));
Mathieu Chartier79c87da2017-10-10 11:54:29 -0700455 } else {
456 return nullptr;
457 }
458 if (dex_file == nullptr) {
459 *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
460 error_msg->c_str());
461 return nullptr;
462 }
463 if (!dex_file->Init(error_msg)) {
464 dex_file.reset();
465 return nullptr;
466 }
467 if (verify && !DexFileVerifier::Verify(dex_file.get(),
468 dex_file->Begin(),
469 dex_file->Size(),
470 location.c_str(),
471 verify_checksum,
472 error_msg)) {
473 if (verify_result != nullptr) {
474 *verify_result = VerifyResult::kVerifyFailed;
475 }
476 return nullptr;
477 }
478 if (verify_result != nullptr) {
479 *verify_result = VerifyResult::kVerifySucceeded;
480 }
481 return dex_file;
482}
483
484} // namespace art