描述:
Android系统ODEX文件格式解析
Android动态加载DEX文件流程分析
LOCAL_DEX_PREOPT
WITH_DEXPREOPT
WITH_DEXPREOPT_PIC
1、 系统预置的odex,arch选择不对,比如 PposTv 只能在32 bit 下运行
a) 预置的odex:/system/app/PposTv/oat/arm64/PposTv.odex
b) 实际使用的odex:/data/dalvik-cache/arm/system@app@PposTv@PposTv@class.dex
c) 第三方APK(prebuilt)也不对
2、 如果系统已经预置,可以删除APK里面的class.dex,节约存储
a) 需要重签名,只能是自家的应用
b) 顺便so库如果预置的话,也可以从apk删除
c) 另外Zipalign功能好像没有用上(减少so库占用)
备注1:
一个系统预置 odex 的应用
# dumpsys package com.android.defcontainer
Key Set Manager:
[com.android.defcontainer]
Signing KeySets: 1
Packages:
Package [com.android.defcontainer] (42090770):
userId=10002 gids=[1028, 1015, 1023, 2001, 1035]
pkg=Package{420f2250 com.android.defcontainer}
codePath=/system/priv-app/DefaultContainerService.apk
resourcePath=/system/priv-app/DefaultContainerService.apk
nativeLibraryPath=/data/app-lib/DefaultContainerService
versionCode=19 targetSdk=19
versionName=4.4.4-1.0.0
applicationInfo=ApplicationInfo{420f2300 com.android.defcontainer}
flags=[ SYSTEM HAS_CODE ALLOW_CLEAR_USER_DATA PRIVILEGED ]
dataDir=/data/data/com.android.defcontainer
supportsScreens=[small, medium, large, xlarge, resizeable, anyDensity]
timeStamp=2008-08-01 20:00:00
firstInstallTime=2017-10-24 17:13:35
lastUpdateTime=2008-08-01 20:00:00
signatures=PackageSignatures{4204e238 [420faab8]}
permissionsFixed=false haveGids=true installStatus=1
pkgFlags=[ SYSTEM HAS_CODE ALLOW_CLEAR_USER_DATA PRIVILEGED ]
User 0: installed=true blocked=false stopped=false notLaunched=false enabled=0
备注2:
虽然 codePath 还是 apk 文件,但是确实用了预置 odex 作为代码文件
cat /proc/7646/maps | grep odex
58726000-5872c000 r--p 00000000 b3:09 1477 /system/priv-app/DefaultContainerService.odex
备注3:
修改 dex文件权限,打印 DexFile 的调用 track
06-05 13:32:23.716 15619 15619 E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "com.pptv.wallpaperplayer.WallpaperPlayerService" on path: DexPathList[[zip file "/system/framework/framework-pptv.jar", zip file "/data/app/com.pptv.wallpaperplayer-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.pptv.wallpaperplayer-1, /system/lib, /vendor/lib, /system/lib/egl]]
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at android.app.ActivityThread.handleCreateService(ActivityThread.java:2540)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: ... 10 more
06-05 13:32:23.716 15619 15619 E AndroidRuntime: Suppressed: java.io.IOException: unable to open DEX file
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at dalvik.system.DexFile.openDexFileNative(Native Method)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at dalvik.system.DexFile.openDexFile(DexFile.java:296)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at dalvik.system.DexFile.<init>(DexFile.java:80)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at dalvik.system.DexFile.<init>(DexFile.java:59)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at dalvik.system.DexPathList.loadDexFile(DexPathList.java:263)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at dalvik.system.DexPathList.makeDexElements(DexPathList.java:230)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at dalvik.system.DexPathList.<init>(DexPathList.java:112)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:48)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at dalvik.system.PathClassLoader.<init>(PathClassLoader.java:65)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:57)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at android.app.LoadedApk.getClassLoader(LoadedApk.java:318)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at android.app.LoadedApk.makeApplication(LoadedApk.java:500)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4301)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at android.app.ActivityThread.access$1500(ActivityThread.java:135)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
06-05 13:32:23.716 15619 15619 E AndroidRuntime: ... 8 more
备注4:
好像是native层在计算 dex 路径,上层没有传优化文件路径。但是没有找到直接代码。
备注5:
出现一个问题:
06-28 13:20:40:277 29343 29375 D PluginManager: loadPlugins: start delayed com.pptv.hooray.watcher
06-28 13:20:40:349 29343 29375 W Plugin: start
06-28 13:20:40:349 29343 29375 W Plugin: java.lang.IllegalArgumentException: optimizedDirectory not readable/writable: /system/wplayerplugins
06-28 13:20:40:349 29343 29375 W Plugin: at dalvik.system.DexPathList.<init>(DexPathList.java:104)
06-28 13:20:40:349 29343 29375 W Plugin: at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:48)
06-28 13:20:40:349 29343 29375 W Plugin: at dalvik.system.DexClassLoader.<init>(DexClassLoader.java:57)
06-28 13:20:40:349 29343 29375 W Plugin: at com.pptv.base.plugin.PluginClassLoader.<init>(PluginClassLoader.java:55)
06-28 13:20:40:349 29343 29375 W Plugin: at com.pptv.base.plugin.PluginClassLoader.<init>(PluginClassLoader.java:50)
06-28 13:20:40:349 29343 29375 W Plugin: at com.pptv.base.plugin.Plugin.start(Plugin.java:273)
06-28 13:20:40:349 29343 29375 W Plugin: at com.pptv.base.plugin.PluginManager$1.run(PluginManager.java:153)
06-28 13:20:40:349 29343 29375 W Plugin: at com.pptv.player.WallpaperContext$1.run(WallpaperContext.java:440)
06-28 13:20:40:349 29343 29375 W Plugin: at android.os.Handler.handleCallback(Handler.java:733)
06-28 13:20:40:349 29343 29375 W Plugin: at android.os.Handler.dispatchMessage(Handler.java:95)
06-28 13:20:40:349 29343 29375 W Plugin: at android.os.Looper.loop(Looper.java:136)
06-28 13:20:40:349 29343 29375 W Plugin: at android.os.HandlerThread.run(HandlerThread.java:61)
备注6:
if (outputName != null) {
try {
String parent = new File(outputName).getParent();
if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) {
throw new IllegalArgumentException("Optimized data directory " + parent
+ " is not owned by the current user. Shared storage cannot protect"
+ " your application from code injection attacks.");
}
} catch (ErrnoException ignored) {
// assume we'll fail with a more contextual error later
}
}
备注7:
Android 5.0 以上,ART 虚拟机
std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat(
const char* dex_location, const char* oat_location,
std::vector<std::string>* error_msgs) {
dex_location 是 apk 路径
oat_location 是外面传的优化文件路径
bool OatFileAssistant::DexFilenameToOdexFilename(const std::string& location,
InstructionSet isa, std::string* odex_filename, std::string* error_msg) {
// The odex file name is formed by replacing the dex_location extension with
// .odex and inserting an oat/<isa> directory. For example:
// location = /foo/bar/baz.jar
// odex_location = /foo/bar/oat/<isa>/baz.odex
备注8:
Android 4.4 情形:
Case 1:
系统预置了 hooray odex
ll /system/wplayerplugins/
-rw-r--r-- root root 44444 2008-08-01 20:00 com.pptv.ads.apk
-rw-r--r-- root root 13402482 2008-08-01 20:00 com.pptv.gstplayer.apk
-rw-r--r-- root root 26079 2008-08-01 20:00 com.pptv.hooray.watcher.apk
-rw-r--r-- root log 21472 2008-08-01 20:00 com.pptv.hooray.watcher.odex
缓存目录生产了新的 dex 文件
ll /data/wplayerplugins/com.pptv.hooray.watcher/dex/
-rw-r--r-- system system 21792 2018-06-29 10:08 com.pptv.hooray.watcher.dex
使用的缓存目录的 dex
5a89d000-5a89e000 r--p 00000000 b3:0a 748 /data/wplayerplugins/com.pptv.hooray.watcher/dex/com.pptv.hooray.watcher.dex
说明:这里系统预置的 odex 不匹配(因为 framework.jar 更新过),所以没有使用。
备注9:
Case 2:
拷贝,更新预置的 odex
cp /data/wplayerplugins/com.pptv.hooray.watcher/dex/com.pptv.hooray.watcher.dex /system/wplayerplugins/com.pptv.hooray.watcher.odex
使用的是预置的 odex
5a9d8000-5a9d9000 r--p 00000000 b3:09 14 /system/wplayerplugins/com.pptv.hooray.watcher.odex
备注10:
Case 3:
将 odex 移动到 app 目录
mv /system/wplayerplugins/com.pptv.hooray.watcher.odex /system/app/
使用的缓存目录的 dex
cat /proc/13465/maps | grep hoo
5a89d000-5a89e000 r--p 00000000 b3:0a 748 /data/wplayerplugins/com.pptv.hooray.watcher/dex/com.pptv.hooray.watcher.dex
缓存目录的 dex 文件没有更新
ll /data/wplayerplugins/com.pptv.hooray.watcher/dex/
-rw-r--r-- system system 21792 2018-06-29 10:08 com.pptv.hooray.watcher.dex
备注11:
Case 4:
将 odex 移动回来到 wplayerplugins 目录
mv /system/app/com.pptv.hooray.watcher.odex /system/wplayerplugins/
删除缓存目录
rm -rf /data/wplayerplugins/com.pptv.hooray.watcher/
缓存目录没有生成新的 dex 文件
ll /data/wplayerplugins/com.pptv.hooray.watcher/dex/
使用的是预置的 odex
cat /proc/14271/maps | grep hoo
5a8d6000-5a8d7000 r--p 00000000 b3:09 14 /system/wplayerplugins/com.pptv.hooray.watcher.odex