odex是OptimizedDEX的缩写,是优化过的dex文件

odex两种存在方式:

1. 从apk程序中提取,和apk文件放在一起,后缀odex,此类文件多是AndroidRom系统文件

2. 在cache/dalvik-cache缓存文件,后缀dex

a)      Eg:system@app@calcuator.apk@classes.dex 安装在/system/app目录下calcuator.apk程序的odex文件

odex作用:

因为Dalvik每次加载从apk中读取classes.dex文件会消耗cpu时间,odex则已经包含了需要加载的库文件列表,Dalvik虚拟机加载时根据需要加载的库对照dex文件即可。

部分Android系统的ROM将系统odex文件与app放在同一目录,系统在启动加载这些程序会更省时间。

一、生成odex文件:

使用Android系统源码工具生成dex

build/tools/dexpreopt/dexopt-wrapper下的dexopt-wrapper拷入真机adb push命令

给予777权限,将需要生成dex文件拷入到手机cd跳转该目录执行如下命令

adb pull将文件拷出得到odex文件,文件位置默认为此时cmd的路径位置

分析odex文件:

文件结构体

Dalvik虚拟机将dex文件映射到内存后

500structDexFile {
501/* directly-mapped "opt" header */
502const DexOptHeader*pOptHeader;          // odex文件头
503
504/* pointers to directly-mapped structs and arrays in base DEX */
505const DexHeader*pHeader;
506const DexStringId*pStringIds;
507const DexTypeId*pTypeIds;
508const DexFieldId*pFieldIds;
509const DexMethodId*pMethodIds;
510const DexProtoId*pProtoIds;
511const DexClassDef*pClassDefs;
512const DexLink*pLinkData;
513
514/*
515* 辅助数据段,记录文件被优化后添加的一些信息
517*/
518const DexClassLookup*pClassLookup;
519const void*pRegisterMapPool;       // RegisterMapClassPool
520
521/* points to start of DEX file data */
522const u1*baseAddr;
523
524/* track memory overhead for auxillary structures */
525intoverhead;
526
527/* additional app-specific data structures associated with the DEX */
528//void*               auxData;
529};

DexFile结构中存入其他结构的指针,描述的是加载到内存的数据结构,还有些数据是不会加载到内存的

odex文件结构

struct ODEXFile{

DexOptHeader  header;// odex文件头

DEXFile dexfile;// dex文件

Dependence  deps;//依赖库列表

ChunkDexClassLoopup       lookup;// 类查询结构

ChunkRegisterMapPool  mappool;// 映射池

ChunkEnd     end;// 结束标志

}

二、odex文件解析DexOptHeader在DexFile.h文件中466/*

467* Header added by DEX optimization pass.  Values are always written in
468* local byte and structure padding.  The first field (magic + version)
469* is guaranteed to be present and directly readable for all expected
470* compiler configurations; the rest is version-dependent.
471*
472* Try to keep this simple and fixed-size.
473*/
474structDexOptHeader {

475u1magic[8];           /* odex版本标示 目前固定“64 65 79 0A 30 33 36 00” dey 036 */

476
477u4dexOffset;          /* dex文件头偏移 目前固定为“28 00 00 00”*/
478u4dexLength;          /* dex文件总长度*/
479u4depsOffset;         /* odex依赖库列表偏移*/
480u4depsLength;         /* 依赖库列表总长度*/
481u4optOffset;          /* 辅助数据偏移 */
482u4optLength;         /* 辅助数据总长度 */
483
484u4flags;              /* 标志,标识了Dalvik虚拟机加载odex时的优化与验证选项*/
485u4checksum;           /* 依赖库与辅助数据的校验和*/
486
487/* pad for 64-bit alignment if necessary */
488};
DexOptheader结构以下为DEXFile。
DEXFile下为Dependences结构,Dependences结构不会加载到内存,并且Android源码没有明确定义。
整理出来的结构
struct DexOptHeader{
u4 modWhen;            // 时间戳
u4 crc;        // 校验
u4 DALVIK_VM_BUILD;            // Dalvik虚拟机版本号
u4 numDeps;            // 依赖库的个数
struct{
u4 len;        // name字符串长度
u1 name[len];  // 依赖库的名称,依赖库的完整路径
kSHA1DigestLen signature;      // SHA-1 哈希值
}table[numDeps];       // numDeps决定了table连续的个数
};
Dependences结构的具体操作函数位置dalvik\vm\analysis\DexPrepare.cpp 中的writeDependencies()1358/*
1359* Write the dependency info to "fd" at the current file position.
1360*/
1361staticintwriteDependencies(intfd, u4modWhen, u4crc)
1362{
1363u1*buf = NULL;
1364intresult = -1;
1365ssize_tbufLen;
1366ClassPathEntry*cpe;
1367intnumDeps;
1368
1369/*
1370* Count up the number of completed entries in the bootclasspath.
1371*/
1372numDeps = 0;
1373bufLen = 0;
1374for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
1375const char*cacheFileName =
1376dvmPathToAbsolutePortion(getCacheFileName(cpe));
1377assert(cacheFileName!= NULL); /* guaranteed by Class.c*/
1378
1379ALOGV("+++ DexOpt: found dep '%s'", cacheFileName);
1380
1381numDeps++;
1382bufLen+= strlen(cacheFileName) +1;
1383}
1384
1385bufLen+= 4*4+ numDeps* (4+kSHA1DigestLen);
1386
1387buf= (u1*)malloc(bufLen);
1388
1389set4LE(buf+0, modWhen);              // 写入时间戳注意:modWhenhe和crc通过
1390set4LE(buf+4, crc);                  // 写入crc校验dexZipGetEntryInfo()获取的
1391set4LE(buf+8, DALVIK_VM_BUILD);      // 写入Dalvik虚拟机版本号
1392set4LE(buf+12, numDeps);             // 写入依赖库的个数
1393
1394// TODO: do we want to add dvmGetInlineOpsTableLength() here?  Won't
1395// help us if somebody replaces an existing entry, but it'd catch
1396// additions/removals.
1397
1398u1*ptr= buf+ 4*4;                 // 跳过前四个字段
1399for (cpe= gDvm.bootClassPath; cpe->ptr!= NULL; cpe++) {           // 循环写入依赖库
1400const char* cacheFileName =
1401dvmPathToAbsolutePortion(getCacheFileName(cpe));
1402assert(cacheFileName != NULL); /* guaranteed by Class.c */
1403
1404const u1*signature = getSignature(cpe);      // 计算SHA-1 哈希值
1405intlen = strlen(cacheFileName) +1;
1406
1407if (ptr + 4+ len + kSHA1DigestLen > buf + bufLen) {
1408ALOGE("DexOpt: overran buffer");
1409dvmAbort();
1410}
1411
1412set4LE(ptr, len);
1413ptr += 4;
1414memcpy(ptr, cacheFileName, len);         // 写入依赖库的名字
1415ptr += len;
1416memcpy(ptr, signature, kSHA1DigestLen);          // 写入SHA-1哈希值
1417ptr += kSHA1DigestLen;
1418}
1419
1420assert(ptr == buf + bufLen);
1421
1422result = sysWriteFully(fd, buf, bufLen, "DexOpt dep info");
1423
1424free(buf);
1425return result;
1426}
dexZipGetEntryInfo()函数位于 /dalvik/libdex/ZipArchive.cpp       根据结构体分析二进制即可

Dalvik版本号:Android2.2.3            19

Android2.3~2.3.7 23

Android4.0~4.1          27

Dependences结构下有3个Chunk块。由/dalvik/vm/analysis/DexPrepare.cpp中的writeOptData()写入1474
1475* Write opt data.
1476*
1477* We have different pieces, some of which may be optional.  To make the
1478* most effective use of space, we use a "chunk" format, with a 4-byte
1479* type and a 4-byte length.  We guarantee 64-bit alignment for the data,
1480* so it can be used directly when the file is mapped for reading.
1481*/
1482staticboolwriteOptData(int fd, const DexClassLookup* pClassLookup,
1483const RegisterMapBuilder* pRegMapBuilder)
1484{
1485/* pre-computed class lookup hash table */
1486if (!writeChunk(fd, (u4) kDexChunkClassLookup,
1487pClassLookup, pClassLookup->size))
1488{
1489return false;
1490}
1491
1492/* register maps (optional) */
1493if (pRegMapBuilder != NULL) {
1494if (!writeChunk(fd, (u4) kDexChunkRegisterMaps,
1495pRegMapBuilder->data, pRegMapBuilder->size))
1496{
1497return false;
1498}
1499}
1500
1501/* write the end marker */
1502if (!writeChunk(fd, (u4) kDexChunkEnd, NULL, 0)) {
1503return false;
1504}
1505
1506return true;
1507}
数据是通过writeChunk()写入的,writeChunk()源码1429/*
1430* Write a block of data in "chunk" format.
1431*
1432* header结构体占8字节,type字段为1一个kDexChunk开头的常量
1433*
1434*/
1435staticboolwriteChunk(int fd, u4type, const void*data, size_tsize)
1436{
1437union {             /* save a syscall by grouping these together */
1438charraw[8];
1439struct {
1440u4type;
1441u4size;
1442}ts;
1443}header;
1444
1445assert(sizeof(header) == 8);
1446
1447ALOGV("Writing chunk, type=%.4s size=%d", (char*) &type, size);
1448
1449header.ts.type = type;
1450header.ts.size = (u4) size;
1451if (sysWriteFully(fd, &header, sizeof(header),
1452"DexOpt opt chunk header write") != 0)
1453{
1454return false;
1455}
1456
1457if (size > 0) {
1458if (sysWriteFully(fd, data, size, "DexOpt opt chunk write") != 0)
1459return false;
1460}
1461
1462/* if necessary, pad to 64-bit alignment */
1463if ((size & 7) != 0) {
1464intpadSize = 8- (size & 7);
1465ALOGV("size was %d, inserting %d pad bytes", size, padSize);
1466lseek(fd, padSize, SEEK_CUR);
1467}
1468
1469assert( ((int)lseek(fd, 0, SEEK_CUR) & 7) == 0);
1470
1471return true;
1472}

writeChunk()方法中传入的type字段
188/* auxillary data section chunk codes */
189enum{
190kDexChunkClassLookup            = 0x434c4b50,   /* CLKP */
191kDexChunkRegisterMaps           = 0x524d4150,   /* RMAP */
192
193kDexChunkEnd                    = 0x41454e44,   /* AEND */
194};

writeOptData ()方法中传入DexClassLookup结构指针,Dalvik虚拟机通过DexClassLookup结构检索dex文件中的类
447/*
448* Lookup table for classes.  It provides a mapping from class name to
449* class definition.  Used by dexFindClass().
450*
451* We calculate this at DEX optimization time and embed it in the file so we
452* don't need the same hash table in every VM.  This is slightly slower than
453* a hash table with direct pointers to the items, but because it's shared
454* there's less of a penalty for using a fairly sparse table.
455*/
456structDexClassLookup {
457int     size;                       //本结构的字节数
458int     numEntries;                 // 接下来table结构的项数,通常值为2
459struct {
460u4classDescriptorHash;    // 类的哈希值
461intclassDescriptorOffset;  //类的描述
462int     classDefOffset;         // 指向DexClassDef结构的指针
463}table[1];// 用来描述类的信息
464};
465

根据上述源码总结出的ChunkDexClassLookup结构声明:

struct ChunkDexClassLookup{

Header header;

DexClassLookup lookup;

}

ChunkRegisterMapPool的结构体是writeOptData()函数向writeChunk()函数传递1个RegisterMapBuilder结构体指针。

RegisterMapBuilder结构体通过dvmGenerateRegisterMaps()函数填充。

dvmGenerateRegisterMaps()调用writeMapsAllClasses()填充所有类的映射信息,

writeMapsAllClasses()调用writeMapsAllMethods()填充所有方法映射信息

writeMapsAllMethods()调用writeMapForMethod()依次填充每个方法的映射信息

并调用computeRegisterMapSize()函数计算填充的每个方法映射信息的长度,用来循环遍历所有的方法

struct ChunkRegisterMapPool{

Header header;

struct{

struct RegisterMapClassPool{

u4 numClasses;

u4 classDataOffset[1];

}classpool;

struct RegisterMapMethodPool{

u2 methodCount;

u4 methodData[1];

};

}lookup;

};

ChunkEnd结构时,writeOptData()向writeChunk()传递了一个null指针,根据传递的kDexChunkEnd类型来判断。

odex文件最后的8个字节固定为“44 4E 45 41 00 00 00 00”

struct ChunkEnd{

Header header;

}

转载于:https://www.cnblogs.com/heixiang/p/10967142.html

5.2 odex文件相关推荐

  1. 更改后缀为.dex文件为.odex文件 让你的程序瘦身 运行更稳定

    今天无聊就把自己安装的软件在dalvik_cache对应的后缀为.dex文件重命名为.odex文件 然后把修改好的.odex文件移动到DATA中的APP里面[如果是复制过去的话 这里面.dex文件可以 ...

  2. android 中的 odex 文件

    有很多时候,我们在修改bug的时候,发现代码明明修改了, 编译也ok了,但是将编译的结果 push 到手机上去之后,发现经常没效,纳闷了-- 经常是odex 在作怪: ODEX是安卓上的应用程序apk ...

  3. Android odex文件反编译

    odex 是经过优化的dex文件,且独立存在于apk文件.odex 多用于系统预制应用或服务.通过将apk中的dex文件进行 odex,可以加载 apk 的启动速度,同时减小空间的占用.请参考ODEX ...

  4. .odex文件的反编译

    0x00 问题呈现 在分析某手机自带应用时,为了在JEB中反编译,将其adb pull到了电脑上.解压后发现如下文件: APK解压目录列表 惊奇的发现该APK包中没有dex文件,一开始特别疑惑没有de ...

  5. 【Android安全】vdex、odex文件

    Android中的vdex.odex文件 参考:https://blog.csdn.net/linxinfa/article/details/107669242 以下内容未验证 vdex文件 为何要搞 ...

  6. android odex文件权限定制

    在做Felica FN认证的时候,遇到一个奇怪的需求:要求生成的odex文件权限是640 刚开始拿到这个问题的时候,还以为是在编译CI里有哪个地方可以配置,查了一下编译相当的mk文件,没有找到,然后查 ...

  7. android odex文件作用,安卓odex详细介绍

    首先解释一下什么是Odex?Odex全称optimize dalvik package,Odex是安卓上的应用程序apk中提取出x来的可运行文件,是通过apk安装包的中的dex优化过的,再把apk包里 ...

  8. android odex 作用,Android ROM中Odex文件的作用及介绍

    细心的网友可能发现Android的ROM中有很多odex文件,相对于 APK中的dex文件而言这个odex有什么作用呢? Android123提示大家,如果你仔细观察会发现文件名时一一对应的,同时那些 ...

  9. Android中odex 文件

    聊完DexClassLoader问知不知道odex,这个以前也注意过. odex是安卓上的应用程序apk中提取出来的可运行文件,是通过apk安装包的中的dex优化过的,再把apk包里的dex文件删除. ...

最新文章

  1. 遍历二叉树的各种操作(非递归遍历)
  2. 基于若依框架的二次开发_浅谈若依框架
  3. 社交营销产品设计思考
  4. 切片slice(python)
  5. Redis简介及配置文件介绍
  6. java singleton inner class_Java面向对象设计模式-单例模式
  7. UITableViewCell点击不能push解决方法
  8. Hive中Join的 MR 底层原理
  9. zabbix通过jmx监控tomcat
  10. OpenCASCADE Expression Interpreter by Flex Bison
  11. 1bit等于多少字节,换算方法?
  12. als算法参数_推荐算法之ALS
  13. 2021-02-26
  14. java中laber字体颜色设置,重写jxl中可用的颜色实现自定义颜色
  15. 【日常】从批量合并 PDF 到 PyPDF2 的使用
  16. 宠物智能家居风口下,为何智能猫砂盆才是探路灯?
  17. python-----列表(list)下
  18. 使用C#语言编写记事本程序
  19. 易语言时间转化linux格式,易语言取时间年月日格式化
  20. 关于BP相关的若干赋值参数

热门文章

  1. 几个好用的Visual Studio插件推荐。
  2. 人工智能在游戏领域的应用有哪些?
  3. LM07丨细聊期货横截面策略
  4. boundschecher
  5. ObjectARX编程(六) ------块和属性
  6. 图形化编程语言的设计
  7. 广州Java工程师平均薪资_【广州恒生电子工资】java开发工程师待遇-看准网
  8. EXCEL插入、数据灰色不能使用的解决办法之一
  9. python手机壁纸高清_python爬取手机壁纸
  10. sklearn实现决策树,随机森林,逻辑回归,KNN,贝叶斯,SVM,以葡萄干数据集为例