/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
/** * A {@link ClassLoader} implementation that loads classes from a * buffer containing a DEX file. This can be used to execute code that * has not been written to the local file system. */ publicfinalclassInMemoryDexClassLoaderextendsBaseDexClassLoader { /** * Create an in-memory DEX class loader with the given dex buffers. * * @param dexBuffers array of buffers containing DEX files between * <tt>buffer.position()</tt> and <tt>buffer.limit()</tt>. * @param librarySearchPath the list of directories containing native * libraries, delimited by {@code File.pathSeparator}; may be {@code null} * @param parent the parent class loader for delegation. */ publicInMemoryDexClassLoader(@NonNull ByteBuffer @NonNull [] dexBuffers, @Nullable String librarySearchPath, @Nullable ClassLoader parent) { // 都是调用的这个构造函数 // dexBuffers:一个 ByteBuffer 数组,每个元素都是一个 DEX 文件的数据。 // librarySearchPath:可选的 .so 库搜索路径,通常传 null // parent是父类加载器 super(dexBuffers, librarySearchPath, parent); }
/** * Create an in-memory DEX class loader with the given dex buffers. * * @param dexBuffers array of buffers containing DEX files between * <tt>buffer.position()</tt> and <tt>buffer.limit()</tt>. * @param parent the parent class loader for delegation. */ publicInMemoryDexClassLoader(@NonNull ByteBuffer @NonNull [] dexBuffers, @Nullable ClassLoader parent) { // 再次调用自身的构造函数,最终调用父类加载器 this(dexBuffers, null, parent); }
/** * Creates a new in-memory DEX class loader. * * @param dexBuffer buffer containing DEX file contents between * <tt>buffer.position()</tt> and <tt>buffer.limit()</tt>. * @param parent the parent class loader for delegation. */ publicInMemoryDexClassLoader(@NonNull ByteBuffer dexBuffer, @Nullable ClassLoader parent) { // dexBuffer其实就是dex文件,这里转成了字节 // 调用自身的构造函数,就是上面的那个 this(newByteBuffer[] { dexBuffer }, parent); } }
/** * For InMemoryDexClassLoader. Initializes {@code dexElements} with dex files * loaded from {@code dexFiles} buffers. * * @param dexFiles ByteBuffers containing raw dex data. Apks are not supported. */ /* package */voidinitByteBufferDexPath(ByteBuffer[] dexFiles) { // 这三个逻辑不用管,一般进不到这里面去 if (dexFiles == null) { thrownewNullPointerException("dexFiles == null"); } if (Arrays.stream(dexFiles).anyMatch(v -> v == null)) { thrownewNullPointerException("dexFiles contains a null Buffer!"); } if (dexElements != null || dexElementsSuppressedExceptions != null) { thrownewIllegalStateException("Should only be called once"); }
final List<IOException> suppressedExceptions = newArrayList<IOException>();
try { Element[] null_elements = null; // 得到DexFile对象 DexFiledex=newDexFile(dexFiles, definingContext, null_elements); // Capture class loader context from *before* `dexElements` is set (see comment below). StringclassLoaderContext= dex.isBackedByOatFile() ? null : DexFile.getClassLoaderContext(definingContext, null_elements); // 把得到的DexFile对象转成dexElements dexElements = newElement[] { newElement(dex) }; // Spawn background thread to verify all classes and cache verification results. // Must be called *after* `dexElements` has been initialized for ART to find // its classes (the field is hardcoded in ART and dex files iterated over in // the order of the array), but with class loader context from *before* // `dexElements` was set because that is what it will be compared against next // time the same bytecode is loaded. // We only spawn the background thread if the bytecode is not backed by an oat // file, i.e. this is the first time this bytecode is being loaded and/or // verification results have not been cached yet. Skip spawning the thread on // all subsequent loads of the same bytecode in the same class loader context. if (classLoaderContext != null) { dex.verifyInBackground(definingContext, classLoaderContext); } } catch (IOException suppressed) { System.logE("Unable to load dex files", suppressed); suppressedExceptions.add(suppressed); dexElements = newElement[0]; }
static jobject CreateCookieFromOatFileManagerResult( JNIEnv* env, std::vector<std::unique_ptr<const DexFile>>& dex_files, const OatFile* oat_file, conststd::vector<std::string>& error_msgs) { ClassLinker* linker = Runtime::Current()->GetClassLinker(); if (dex_files.empty()) { ScopedObjectAccess soa(env); CHECK(!error_msgs.empty()); // The most important message is at the end. So set up nesting by going forward, which will // wrap the existing exception as a cause for the following one. auto it = error_msgs.begin(); auto itEnd = error_msgs.end(); for ( ; it != itEnd; ++it) { ThrowWrappedIOException("%s", it->c_str()); } return nullptr; } // 其实关键就在这一句 // 最终调用ConvertDexFilesToJavaArray方法把dex_files处理成了jlongArray // 返回jlongArray类型 jlongArray array = ConvertDexFilesToJavaArray(env, oat_file, dex_files); if (array == nullptr) { ScopedObjectAccess soa(env); for (auto& dex_file : dex_files) { if (linker->IsDexFileRegistered(soa.Self(), *dex_file)) { dex_file.release(); // NOLINT } } } returnarray; }
// TODO: Optimize. On 32bit we can use an int array. jboolean is_long_data_copied; jlong* long_data = env->GetLongArrayElements(reinterpret_cast<jlongArray>(array), &is_long_data_copied); if (env->ExceptionCheck() == JNI_TRUE) { returnfalse; }
oat_file = reinterpret_cast64<const OatFile*>(long_data[kOatFileIndex]); dex_files.reserve(array_size - 1); for (jsize i = kDexFileIndexStart; i < array_size; ++i) { // 把每个array数组中的成员都给转成DexFile类型的指针 dex_files.push_back(reinterpret_cast64<const DexFile*>(long_data[i])); }
if (error_msgs->empty()) { // Remove write permission from DexFile pages. We do this at the end because // OatFile assigns OatDexFile pointer in the DexFile objects. for (std::unique_ptr<const DexFile>& dex_file : dex_files) { if (!dex_file->DisableWrite()) { error_msgs->push_back("Failed to make dex file " + dex_file->GetLocation() + " read-only"); } } }
if (!error_msgs->empty()) { returnstd::vector<std::unique_ptr<const DexFile>>(); }
// Attempt to open an existing vdex and check dex file checksums match. std::unique_ptr<VdexFile> vdex_file = nullptr; if (has_vdex && OS::FileExists(vdex_path.c_str())) { vdex_file = VdexFile::Open(vdex_path, /* writable= */false, /* low_4gb= */false, /* unquicken= */false, &error_msg); if (vdex_file == nullptr) { LOG(WARNING) << "Failed to open vdex " << vdex_path << ": " << error_msg; } elseif (!vdex_file->MatchesDexFileChecksums(dex_headers)) { LOG(WARNING) << "Failed to open vdex " << vdex_path << ": dex file checksum mismatch"; vdex_file.reset(nullptr); } } // Load dex files. Skip structural dex file verification if vdex was found // and dex checksums matched. std::vector<std::unique_ptr<const DexFile>> dex_files; // 调用dex_file函数加载dex文件 for (size_t i = 0; i < dex_mem_maps.size(); ++i) { staticconstexprbool kVerifyChecksum = true; const ArtDexFileLoader dex_file_loader; std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open( DexFileLoader::GetMultiDexLocation(i, dex_location.c_str()), location_checksum, std::move(dex_mem_maps[i]), /* verify= */ (vdex_file == nullptr) && Runtime::Current()->IsVerificationEnabled(), kVerifyChecksum, &error_msg)); if (dex_file != nullptr) { dex::tracking::RegisterDexFile(dex_file.get()); // Register for tracking. dex_files.push_back(std::move(dex_file)); } else { error_msgs->push_back("Failed to open dex files from memory: " + error_msg); } }
// Check if we should proceed to creating an OatFile instance backed by the vdex. // We need: (a) an existing vdex, (b) class loader (can be null if invoked via reflection), // and (c) no errors during dex file loading. if (vdex_file == nullptr || class_loader == nullptr || !error_msgs->empty()) { return dex_files; }
// Attempt to create a class loader context, check OpenDexFiles succeeds (prerequisite // for using the context later). std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::CreateContextForClassLoader( class_loader, dex_elements); if (context == nullptr) { LOG(ERROR) << "Could not create class loader context for " << vdex_path; return dex_files; } DCHECK(context->OpenDexFiles(kRuntimeISA, "")) << "Context created from already opened dex files should not attempt to open again";
// Check that we can use the vdex against this boot class path and in this class loader context. // Note 1: We do not need a class loader collision check because there is no compiled code. // Note 2: If these checks fail, we cannot fast-verify because the vdex does not contain // full VerifierDeps. if (!vdex_file->MatchesBootClassPathChecksums() || !vdex_file->MatchesClassLoaderContext(*context.get())) { return dex_files; }
// Initialize an OatFile instance backed by the loaded vdex. std::unique_ptr<OatFile> oat_file(OatFile::OpenFromVdex(MakeNonOwningPointerVector(dex_files), std::move(vdex_file), dex_location)); DCHECK(oat_file != nullptr); VLOG(class_linker) << "Registering " << oat_file->GetLocation(); *out_oat_file = RegisterOatFile(std::move(oat_file)); return dex_files; }
重点看加载dex文件的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
for (size_t i = 0; i < dex_mem_maps.size(); ++i) { staticconstexprbool kVerifyChecksum = true; const ArtDexFileLoader dex_file_loader; std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open( DexFileLoader::GetMultiDexLocation(i, dex_location.c_str()), location_checksum, std::move(dex_mem_maps[i]), /* verify= */ (vdex_file == nullptr) && Runtime::Current()->IsVerificationEnabled(), kVerifyChecksum, &error_msg)); if (dex_file != nullptr) { dex::tracking::RegisterDexFile(dex_file.get()); // Register for tracking. // 最终函数返回的就是dex_files dex_files.push_back(std::move(dex_file)); } else { error_msgs->push_back("Failed to open dex files from memory: " + error_msg); } }
size_t size = map.Size(); if (size < sizeof(DexFile::Header)) { *error_msg = StringPrintf( "DexFile: failed to open dex file '%s' that is too short to have a header", location.c_str()); return nullptr; }
uint8_t* begin = map.Begin(); std::unique_ptr<DexFile> dex_file = OpenCommon(begin, size, /*data_base=*/ nullptr, /*data_size=*/0u, location, location_checksum, kNoOatDexFile, verify, verify_checksum, error_msg, std::make_unique<MemMapContainer>(std::move(map)), /*verify_result=*/ nullptr); // Opening CompactDex is only supported from vdex files. if (dex_file != nullptr && dex_file->IsCompactDexFile()) { *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files", location.c_str()); return nullptr; } return dex_file; }