文章目录
- 前言
- 一、DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析
- 二、/bin/dexopt 源码分析
前言
上一篇博客 【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | RawDexFile.cpp 分析 | dvmRawDexFileOpen函数读取 DEX 文件 ) 中 , 在 RawDexFile.cpp 中的 dvmRawDexFileOpen() 方法中 , 调用了 DexPrepare.cpp 的 dvmOptimizeDexFile() 函数 , 对 DEX 文件进行了优化 ;
一、DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析
dvmOptimizeDexFile 函数的参数说明 : int fd
是打开的 dex 文件标识符 , long dexLength
是打开的 dex 文件大小 ;
在该函数中 , 调用 /bin/dexopt 程序 , 优化 dex 文件 , 最终产生 odex 文件 ;
/*
* 给定包含DEX数据的文件的描述符,生成
* 优化版本。
*
* “fd”指向的文件应为锁定的共享资源
* (或私人);我们不努力实施多进程正确性
* 在这里。
*
* “文件名”仅用于调试输出。存储“modWhen”和“crc”
* 在依赖项集中。
*
* “isBootstrap”标志确定优化器和验证器如何处理
* 包范围访问检查。优化时,我们只加载引导
* 类DEX文件和目标DEX,因此该标志确定
* 给目标DEX类一个(合成的)非空类加载器指针。
* 只有当目标DEX包含声明
* 与引导类位于同一个包中。
*
* 优化器需要加载目标DEX文件中的每个类。
* 这通常是不可取的,因此我们启动一个子流程来执行
* 工作并等待它完成。
*
* 成功时返回“true”。所有数据均已写入“fd”。
*/
bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,
const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
{
const char* lastPart = strrchr(fileName, '/');
if (lastPart != NULL)
lastPart++;
else
lastPart = fileName;
ALOGD("DexOpt: --- BEGIN '%s' (bootstrap=%d) ---", lastPart, isBootstrap);
pid_t pid;
/*
* 如果我们的bootclasspath中出现了我们认为
* 都优化了,被拒绝了。
*/
if (gDvm.optimizing) {
ALOGW("Rejecting recursive optimization attempt on '%s'", fileName);
return false;
}
pid = fork();
if (pid == 0) {
static const int kUseValgrind = 0;
// 调用 /bin/dexopt 程序 , 优化 dex 文件 , 最终产生 odex 文件
static const char* kDexOptBin = "/bin/dexopt";
static const char* kValgrinder = "/usr/bin/valgrind";
static const int kFixedArgCount = 10;
static const int kValgrindArgCount = 5;
static const int kMaxIntLen = 12; // '-'+10dig+'\0' -OR- 0x+8dig
int bcpSize = dvmGetBootPathSize();
int argc = kFixedArgCount + bcpSize
+ (kValgrindArgCount * kUseValgrind);
const char* argv[argc+1]; // last entry is NULL
char values[argc][kMaxIntLen];
char* execFile;
const char* androidRoot;
int flags;
/* change process groups, so we don't clash with ProcessManager */
setpgid(0, 0);
/* full path to optimizer */
androidRoot = getenv("ANDROID_ROOT");
if (androidRoot == NULL) {
ALOGW("ANDROID_ROOT not set, defaulting to /system");
androidRoot = "/system";
}
execFile = (char*)alloca(strlen(androidRoot) + strlen(kDexOptBin) + 1);
strcpy(execFile, androidRoot);
strcat(execFile, kDexOptBin);
/*
* Create arg vector.
*/
int curArg = 0;
if (kUseValgrind) {
/* probably shouldn't ship the hard-coded path */
argv[curArg++] = (char*)kValgrinder;
argv[curArg++] = "--tool=memcheck";
argv[curArg++] = "--leak-check=yes"; // check for leaks too
argv[curArg++] = "--leak-resolution=med"; // increase from 2 to 4
argv[curArg++] = "--num-callers=16"; // default is 12
assert(curArg == kValgrindArgCount);
}
argv[curArg++] = execFile;
argv[curArg++] = "--dex";
sprintf(values[2], "%d", DALVIK_VM_BUILD);
argv[curArg++] = values[2];
sprintf(values[3], "%d", fd);
argv[curArg++] = values[3];
sprintf(values[4], "%d", (int) dexOffset);
argv[curArg++] = values[4];
sprintf(values[5], "%d", (int) dexLength);
argv[curArg++] = values[5];
argv[curArg++] = (char*)fileName;
sprintf(values[7], "%d", (int) modWhen);
argv[curArg++] = values[7];
sprintf(values[8], "%d", (int) crc);
argv[curArg++] = values[8];
flags = 0;
if (gDvm.dexOptMode != OPTIMIZE_MODE_NONE) {
flags |= DEXOPT_OPT_ENABLED;
if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)
flags |= DEXOPT_OPT_ALL;
}
if (gDvm.classVerifyMode != VERIFY_MODE_NONE) {
flags |= DEXOPT_VERIFY_ENABLED;
if (gDvm.classVerifyMode == VERIFY_MODE_ALL)
flags |= DEXOPT_VERIFY_ALL;
}
if (isBootstrap)
flags |= DEXOPT_IS_BOOTSTRAP;
if (gDvm.generateRegisterMaps)
flags |= DEXOPT_GEN_REGISTER_MAPS;
sprintf(values[9], "%d", flags);
argv[curArg++] = values[9];
assert(((!kUseValgrind && curArg == kFixedArgCount) ||
((kUseValgrind && curArg == kFixedArgCount+kValgrindArgCount))));
ClassPathEntry* cpe;
for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
argv[curArg++] = cpe->fileName;
}
assert(curArg == argc);
argv[curArg] = NULL;
if (kUseValgrind)
execv(kValgrinder, const_cast<char**>(argv));
else
execv(execFile, const_cast<char**>(argv));
ALOGE("execv '%s'%s failed: %s", execFile,
kUseValgrind ? " [valgrind]" : "", strerror(errno));
exit(1);
} else {
ALOGV("DexOpt: waiting for verify+opt, pid=%d", (int) pid);
int status;
pid_t gotPid;
/*
* 等待优化过程完成。我们进入VMI等待
* 模式,这样GC暂停就不必等待我们了。
*/
ThreadStatus oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
while (true) {
gotPid = waitpid(pid, &status, 0);
if (gotPid == -1 && errno == EINTR) {
ALOGD("waitpid interrupted, retrying");
} else {
break;
}
}
dvmChangeStatus(NULL, oldStatus);
if (gotPid != pid) {
ALOGE("waitpid failed: wanted %d, got %d: %s",
(int) pid, (int) gotPid, strerror(errno));
return false;
}
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
ALOGD("DexOpt: --- END '%s' (success) ---", lastPart);
return true;
} else {
ALOGW("DexOpt: --- END '%s' --- status=0x%04x, process failed",
lastPart, status);
return false;
}
}
}
二、/bin/dexopt 源码分析
dex 文件优化 , 主要是调用 /bin/dexopt 程序 , 最终产生 odex 文件 ;
其源码路径是 /dalvik/dexopt/ 路径 ,
该 OptMain.cpp 源码是一个有 main 函数 , 可以独立执行的 C++ 程序 , 可以在 Android 命令中执行 ;
加载 dex 文件时 , 执行 fromDex 函数 ;
return fromDex(argc, argv);
在 fromfromDex 函数中 , 先准备优化环境 ,
if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {
ALOGE("VM init failed");
goto bail;
}
然后进行正式优化 ;
/* do the optimization */
if (!dvmContinueOptimization(fd, offset, length, debugFileName,
modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0))
{
ALOGE("Optimization failed");
goto bail;
}
真正的优化操作 , 在 dvmContinueOptimization
函数中执行的 ;
核心源码如下 : 源码路径 /dalvik/dexopt/OptMain.cpp
/*
* Copyright (C) 2008 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.
*/
/*
* 命令行DEX优化和验证入口点。
*
* 有三种方法可以启动此功能:
* (1)来自虚拟机。这需要十几个参数,其中一个是文件
* 同时作为输入和输出的描述符。这使我们能够
* 仍然不知道DEX数据最初来自何处。
* (2)来自installd或其他本机应用程序。传入文件
* 用于zip文件的描述符、用于输出的文件描述符,以及
* 调试消息的文件名。关于这一点,人们做了许多假设
* 发生了什么(验证+优化已启用,启动
* 类路径位于BOOTCLASSPATH中,等等)。
* (3)在构建过程中在主机上进行预优化。这种行为
* 与(2)几乎相同,只是它采用文件名而不是
* 文件描述符。
*
* bootclasspath条目存在一些脆弱的方面,原因如下
* 很大程度上是由于虚拟机在它认为需要的时候进行工作的历史
* 而不是严格按照要求去做。如果优化引导类路径
* 条目,始终按照它们在路径中出现的顺序执行。
*/
#include "Dalvik.h"
#include "libdex/OptInvocation.h"
#include "cutils/log.h"
#include "cutils/process_name.h"
#include <fcntl.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static const char* kClassesDex = "classes.dex";
/*
*将zipFd中的“classes.dex”提取到“cacheFd”中,留下一点空间
*用于DEX优化收割台的前端。
*/
static int extractAndProcessZip(int zipFd, int cacheFd,
const char* debugFileName, bool isBootstrap, const char* bootClassPath,
const char* dexoptFlagStr)
{
ZipArchive zippy;
ZipEntry zipEntry;
size_t uncompLen;
long modWhen, crc32;
off_t dexOffset;
int err;
int result = -1;
int dexoptFlags = 0; /* bit flags, from enum DexoptFlags */
DexClassVerifyMode verifyMode = VERIFY_MODE_ALL;
DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED;
memset(&zippy, 0, sizeof(zippy));
/* make sure we're still at the start of an empty file */
if (lseek(cacheFd, 0, SEEK_END) != 0) {
ALOGE("DexOptZ: new cache file '%s' is not empty", debugFileName);
goto bail;
}
/*
*编写骨架索引优化标头。我们要上课。指数
*紧跟其后。
*/
err = dexOptCreateEmptyHeader(cacheFd);
if (err != 0)
goto bail;
/* record the file position so we can get back here later */
dexOffset = lseek(cacheFd, 0, SEEK_CUR);
if (dexOffset < 0)
goto bail;
/*
*打开zip存档,找到DEX条目。
*/
if (dexZipPrepArchive(zipFd, debugFileName, &zippy) != 0) {
ALOGW("DexOptZ: unable to open zip archive '%s'", debugFileName);
goto bail;
}
zipEntry = dexZipFindEntry(&zippy, kClassesDex);
if (zipEntry == NULL) {
ALOGW("DexOptZ: zip archive '%s' does not include %s",
debugFileName, kClassesDex);
goto bail;
}
/*
*提取一些关于zip条目的信息。
*/
if (dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL,
&modWhen, &crc32) != 0)
{
ALOGW("DexOptZ: zip archive GetEntryInfo failed on %s", debugFileName);
goto bail;
}
uncompLen = uncompLen;
modWhen = modWhen;
crc32 = crc32;
/*
*以当前偏移量将DEX数据提取到缓存文件中。
*/
if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) {
ALOGW("DexOptZ: extraction of %s from %s failed",
kClassesDex, debugFileName);
goto bail;
}
/* Parse the options. */
if (dexoptFlagStr[0] != '\0') {
const char* opc;
const char* val;
opc = strstr(dexoptFlagStr, "v="); /* verification */
if (opc != NULL) {
switch (*(opc+2)) {
case 'n': verifyMode = VERIFY_MODE_NONE; break;
case 'r': verifyMode = VERIFY_MODE_REMOTE; break;
case 'a': verifyMode = VERIFY_MODE_ALL; break;
default: break;
}
}
opc = strstr(dexoptFlagStr, "o="); /* optimization */
if (opc != NULL) {
switch (*(opc+2)) {
case 'n': dexOptMode = OPTIMIZE_MODE_NONE; break;
case 'v': dexOptMode = OPTIMIZE_MODE_VERIFIED; break;
case 'a': dexOptMode = OPTIMIZE_MODE_ALL; break;
case 'f': dexOptMode = OPTIMIZE_MODE_FULL; break;
default: break;
}
}
opc = strstr(dexoptFlagStr, "m=y"); /* register map */
if (opc != NULL) {
dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;
}
opc = strstr(dexoptFlagStr, "u="); /* uniprocessor target */
if (opc != NULL) {
switch (*(opc+2)) {
case 'y': dexoptFlags |= DEXOPT_UNIPROCESSOR; break;
case 'n': dexoptFlags |= DEXOPT_SMP; break;
default: break;
}
}
}
/*
*准备VM并执行优化。
*/
if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,
dexoptFlags) != 0)
{
ALOGE("DexOptZ: VM init failed");
goto bail;
}
//vmStarted = 1;
/* do the optimization */
if (!dvmContinueOptimization(cacheFd, dexOffset, uncompLen, debugFileName,
modWhen, crc32, isBootstrap))
{
ALOGE("Optimization failed");
goto bail;
}
/* we don't shut the VM down -- process is about to exit */
result = 0;
bail:
dexZipCloseArchive(&zippy);
return result;
}
/*
*普通设备端处理的通用功能以及
*预优化。
*/
static int processZipFile(int zipFd, int cacheFd, const char* zipName,
const char *dexoptFlags)
{
char* bcpCopy = NULL;
/*
* Check to see if this is a bootstrap class entry. If so, truncate
* the path.
*/
const char* bcp = getenv("BOOTCLASSPATH");
if (bcp == NULL) {
ALOGE("DexOptZ: BOOTCLASSPATH not set");
return -1;
}
bool isBootstrap = false;
const char* match = strstr(bcp, zipName);
if (match != NULL) {
/*
*TODO:我们有一个部分字符串匹配,但这并不意味着
*我们已经匹配了整个路径组件。我们应该确保
*我们正在匹配完整的zipName,如果不是
*应从(匹配+1)开始重新执行strstr。
*
*该场景将是一个bootclasspath,具有以下内容
*“/system/framework/core.jar”,而我们正在尝试优化
*“/framework/core.jar”。不太可能,因为所有路径都是
*绝对,以“.jar”结尾,但并非不可能。
*/
int matchOffset = match - bcp;
if (matchOffset > 0 && bcp[matchOffset-1] == ':')
matchOffset--;
ALOGV("DexOptZ: found '%s' in bootclasspath, cutting off at %d",
zipName, matchOffset);
bcpCopy = strdup(bcp);
bcpCopy[matchOffset] = '\0';
bcp = bcpCopy;
ALOGD("DexOptZ: truncated BOOTCLASSPATH to '%s'", bcp);
isBootstrap = true;
}
int result = extractAndProcessZip(zipFd, cacheFd, zipName, isBootstrap,
bcp, dexoptFlags);
free(bcpCopy);
return result;
}
/* advance to the next arg and extract it */
#define GET_ARG(_var, _func, _msg) \
{ \
char* endp; \
(_var) = _func(*++argv, &endp, 0); \
if (*endp != '\0') { \
ALOGE("%s '%s'", _msg, *argv); \
goto bail; \
} \
--argc; \
}
/*
*解析参数。我们希望:
* 0. (dexopt命令的名称--已忽略)
* 1. “--zip”
* 2. zip fd(输入,只读)
* 3. 缓存fd(输出、读写、用群集锁定)
* 4. 正在优化的zipfile的文件名(用于调试消息和
*用于与BOOTCLASSPATH进行比较;不需要
*可访问或甚至存在)
* 5. dexopt标志
*
*假定BOOTCLASSPATH环境变量包含正确的
*引导类路径。如果提供的文件名出现在引导类中
*路径,路径将在该条目之前被截断(因此,如果
*如果您选择dexopt“core.jar”,您的引导类路径将为空)。
*
*这不会尝试规范化引导类路径名,因此
*如果你有创意,文件名测试不会抓住你。
*/
static int fromZip(int argc, char* const argv[])
{
int result = -1;
int zipFd, cacheFd;
const char* zipName;
char* bcpCopy = NULL;
const char* dexoptFlags;
if (argc != 6) {
ALOGE("Wrong number of args for --zip (found %d)", argc);
goto bail;
}
/* skip "--zip" */
argc--;
argv++;
GET_ARG(zipFd, strtol, "bad zip fd");
GET_ARG(cacheFd, strtol, "bad cache fd");
zipName = *++argv;
--argc;
dexoptFlags = *++argv;
--argc;
result = processZipFile(zipFd, cacheFd, zipName, dexoptFlags);
bail:
return result;
}
/*
*分析预优化运行的参数。这是dalvikvm运行的时间
*在主机上优化dex文件,以便最终在主机上运行(不同)
*装置。我们希望:
* 0. (dexopt命令的名称--已忽略)
* 1. “--preopt”
* 2. zipfile名称
* 3. 输出文件名
* 4. dexopt标志
*
*假定BOOTCLASSPATH环境变量包含正确的
*引导类路径。如果提供的文件名出现在引导类中
*路径,路径将在该条目之前被截断(因此,如果
*如果您选择dexopt“core.jar”,您的引导类路径将为空)。
*
*这不会尝试规范化引导类路径名,因此
*如果你有创意,文件名测试不会抓住你。
*/
static int preopt(int argc, char* const argv[])
{
int zipFd = -1;
int outFd = -1;
int result = -1;
if (argc != 5) {
/*
* Use stderr here, since this variant is meant to be called on
* the host side.
*/
fprintf(stderr, "Wrong number of args for --preopt (found %d)\n",
argc);
return -1;
}
const char* zipName = argv[2];
const char* outName = argv[3];
const char* dexoptFlags = argv[4];
if (strstr(dexoptFlags, "u=y") == NULL &&
strstr(dexoptFlags, "u=n") == NULL)
{
fprintf(stderr, "Either 'u=y' or 'u=n' must be specified\n");
return -1;
}
zipFd = open(zipName, O_RDONLY);
if (zipFd < 0) {
perror(argv[0]);
return -1;
}
outFd = open(outName, O_RDWR | O_EXCL | O_CREAT, 0666);
if (outFd < 0) {
perror(argv[0]);
goto bail;
}
result = processZipFile(zipFd, outFd, zipName, dexoptFlags);
bail:
if (zipFd >= 0) {
close(zipFd);
}
if (outFd >= 0) {
close(outFd);
}
return result;
}
/*
*直接从VM解析“旧式”调用的参数。
*
*以下是我们想要的:
* 0. (dexopt命令的名称--已忽略)
* 1. “--dex”
* 2. DALVIK_VM_构建值,作为一种健全性检查
* 3. 文件描述符,用flock锁定,用于正在优化的DEX文件
* 4. 文件内的索引偏移量
* 5. 指数长度
* 6. 正在优化的文件的文件名(仅适用于调试消息)
* 7. 源的修改日期(进入依赖项部分)
* 8. 源的CRC(进入依赖项部分)
* 9. 标志(优化级别,isBootstrap)
* 10. bootclasspath条目#1
* 11. bootclasspath条目#2
* ...
*
*dalvik/vm/analysis/DexOptimize中的dvmOptimizeDexFile()。c构建
*参数列表并调用此可执行文件。
*
*bootclasspath条目将成为此DEX文件的依赖项。
*
*打开的文件描述符不能用于任何bootclasspath文件。
*父项已锁定描述符,我们将尝试再次将其锁定
*处理引导类路径的一部分。(我们可以抓住这个然后回来
*比较文件名或打开bootclasspath文件时出错
*并统计它们的索引节点编号)。
*/
static int fromDex(int argc, char* const argv[])
{
int result = -1;
bool vmStarted = false;
char* bootClassPath = NULL;
int fd, flags, vmBuildVersion;
long offset, length;
const char* debugFileName;
u4 crc, modWhen;
char* endp;
bool onlyOptVerifiedDex = false;
DexClassVerifyMode verifyMode;
DexOptimizerMode dexOptMode;
if (argc < 10) {
/* don't have all mandatory args */
ALOGE("Not enough arguments for --dex (found %d)", argc);
goto bail;
}
/* skip "--dex" */
argc--;
argv++;
/*
* Extract the args.
*/
GET_ARG(vmBuildVersion, strtol, "bad vm build");
if (vmBuildVersion != DALVIK_VM_BUILD) {
ALOGE("DexOpt: build rev does not match VM: %d vs %d",
vmBuildVersion, DALVIK_VM_BUILD);
goto bail;
}
GET_ARG(fd, strtol, "bad fd");
GET_ARG(offset, strtol, "bad offset");
GET_ARG(length, strtol, "bad length");
debugFileName = *++argv;
--argc;
GET_ARG(modWhen, strtoul, "bad modWhen");
GET_ARG(crc, strtoul, "bad crc");
GET_ARG(flags, strtol, "bad flags");
ALOGV("Args: fd=%d off=%ld len=%ld name='%s' mod=%#x crc=%#x flg=%d (argc=%d)",
fd, offset, length, debugFileName, modWhen, crc, flags, argc);
assert(argc > 0);
if (--argc == 0) {
bootClassPath = strdup("");
} else {
int i, bcpLen;
char* const* argp;
char* cp;
bcpLen = 0;
for (i = 0, argp = argv; i < argc; i++) {
++argp;
ALOGV("DEP: '%s'", *argp);
bcpLen += strlen(*argp) + 1;
}
cp = bootClassPath = (char*) malloc(bcpLen +1);
for (i = 0, argp = argv; i < argc; i++) {
int strLen;
++argp;
strLen = strlen(*argp);
if (i != 0)
*cp++ = ':';
memcpy(cp, *argp, strLen);
cp += strLen;
}
*cp = '\0';
assert((int) strlen(bootClassPath) == bcpLen-1);
}
ALOGV(" bootclasspath is '%s'", bootClassPath);
/* start the VM partway */
/* ugh -- upgrade these to a bit field if they get any more complex */
if ((flags & DEXOPT_VERIFY_ENABLED) != 0) {
if ((flags & DEXOPT_VERIFY_ALL) != 0)
verifyMode = VERIFY_MODE_ALL;
else
verifyMode = VERIFY_MODE_REMOTE;
} else {
verifyMode = VERIFY_MODE_NONE;
}
if ((flags & DEXOPT_OPT_ENABLED) != 0) {
if ((flags & DEXOPT_OPT_ALL) != 0)
dexOptMode = OPTIMIZE_MODE_ALL;
else
dexOptMode = OPTIMIZE_MODE_VERIFIED;
} else {
dexOptMode = OPTIMIZE_MODE_NONE;
}
// 准备优化环境
if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {
ALOGE("VM init failed");
goto bail;
}
vmStarted = true;
/* 正式进行优化 */
if (!dvmContinueOptimization(fd, offset, length, debugFileName,
modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0))
{
ALOGE("Optimization failed");
goto bail;
}
result = 0;
bail:
/*
*理论上,此时我们应该优雅地关闭VM。在里面
*只有当我们使用检查内存泄漏时,这才有意义
*valgrind——简单地退出要快得多。
*
*事实证明,DEX优化器有点快,有点松
*使用类加载。我们从一个部分-
*形成的DEX文件,完成后将取消映射。如果我们想
*在这里进行清洁关机,可能是为了使用valgrind进行测试,我们需要
*要跳过那里的munmap调用。
*/
#if 0
if (vmStarted) {
ALOGI("DexOpt shutting down, result=%d", result);
dvmShutdown();
}
#endif
free(bootClassPath);
ALOGV("DexOpt command complete (result=%d)", result);
return result;
}
/*
*主要入口点。决定去哪里。
*/
int main(int argc, char* const argv[])
{
set_process_name("dexopt");
setvbuf(stdout, NULL, _IONBF, 0);
if (argc > 1) {
if (strcmp(argv[1], "--zip") == 0)
return fromZip(argc, argv);
else if (strcmp(argv[1], "--dex") == 0)
// 加载 dex 文件时 , 执行 fromDex 函数
return fromDex(argc, argv);
else if (strcmp(argv[1], "--preopt") == 0)
return preopt(argc, argv);
}
fprintf(stderr,
"Usage:\n\n"
"Short version: Don't use this.\n\n"
"Slightly longer version: This system-internal tool is used to\n"
"produce optimized dex files. See the source code for details.\n");
return 1;
}
源码路径 : /dalvik/dexopt/OptMain.cpp