高通项目 首次开机后apk随机报错

     在开发msm8909项目过程中,碰到一个现象,就是烧完版本后开机,会随机出现apk报错的情况,过一段时间,再关机开机,就没有报错。

     在Log中,主要报如下错误:


E AndroidRuntime: java.lang.RuntimeException: Unable to get provider com.android.providers.contacts.debug.DumpFileProvider: java.lang.ClassNotFoundException: Didn't find class "com.android.providers.contacts.debug.DumpFileProvider" on path: DexPathList[[zip file "/system/priv-app/ContactsProvider/ContactsProvider.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
E AndroidRuntime: at android.app.ActivityThread.installProvider(ActivityThread.java:5002)
E AndroidRuntime: at android.app.ActivityThread.installContentProviders(ActivityThread.java:4594)
E AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4534)
E AndroidRuntime: at android.app.ActivityThread.access$1500(ActivityThread.java:151)
E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1364)
E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
E AndroidRuntime: at android.os.Looper.loop(Looper.java:135)
E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5254)
E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
E AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:372)
E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902)
E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697)
E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "com.android.providers.contacts.debug.DumpFileProvider" on path: DexPathList[[zip file "/system/priv-app/ContactsProvider/ContactsProvider.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
E AndroidRuntime: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
E AndroidRuntime: at android.app.ActivityThread.installProvider(ActivityThread.java:4987)
E AndroidRuntime: ... 11 more
E AndroidRuntime: Suppressed: java.io.IOException: Failed to open oat file from dex location '/system/priv-app/ContactsProvider/ContactsProvider.apk'
E AndroidRuntime: at dalvik.system.DexFile.openDexFileNative(Native Method)
E AndroidRuntime: at dalvik.system.DexFile.openDexFile(DexFile.java:295)
E AndroidRuntime: at dalvik.system.DexFile.(DexFile.java:80)
E AndroidRuntime: at dalvik.system.DexFile.(DexFile.java:59)
E AndroidRuntime: at dalvik.system.DexPathList.loadDexFile(DexPathList.java:262)
E AndroidRuntime: at dalvik.system.DexPathList.makeDexElements(DexPathList.java:231)
E AndroidRuntime: at dalvik.system.DexPathList.(DexPathList.java:109)
E AndroidRuntime: at dalvik.system.BaseDexClassLoader.(BaseDexClassLoader.java:48)
E AndroidRuntime: at dalvik.system.PathClassLoader.(PathClassLoader.java:65)
E AndroidRuntime: at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:57)
E AndroidRuntime: at android.app.LoadedApk.getClassLoader(LoadedApk.java:361)
E AndroidRuntime: at android.app.LoadedApk.makeApplication(LoadedApk.java:553)
E AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4526)
E AndroidRuntime: ... 9 more

从Log中看到,这是报类找不到。开始时怀疑apk是不是有问题,尝试着把报错机器的apk提取,放入到正常机器后,开机运行,是没有问题的,而且报错的机器,在一段时间后,关机再开机就不会报这样的错误。

通过代码跟踪,怀疑是不是dex文件没有生成。

 查看/data/dalvik-cache/目录下,有生成apk对应的dex文件。而且文件大小不为0。把这文件提取出来,并和第二次开机后的dex文件做对比,发现是一样的。排除是这个文件的问题。


再次跟踪代码。发现一个可疑的地方。

在/frameworks/native/cmds/installd 目录下,有个installd.c文件。在开机时,PackageManagerService会调用scanPackageDirtyLI接口,再调用mInstaller.dexopt接口。这个接口和service通信,再调用installd.c文件。感兴趣的同学,可以跟踪下代码,查看流程。


在installd.c文件中,找到do_dexopt接口,可以看出,在高通的代码中,对需要做do_dexopt的apk文件,做了缓存,保存在一个链表中。这样缓存后,是在什么时候做dexopt呢。

高通项目 首次开机后apk随机报错_第1张图片

在下面的代码,我们找到了答案。do_mark_boot_complete接口,这个接口实在开启启动完成后调用。也就是说开机后在调用这个接口,开启一个线程,对apk做dexopt优化。

高通项目 首次开机后apk随机报错_第2张图片

在看do_dexopt_func接口实现:

高通项目 首次开机后apk随机报错_第3张图片

很明显了。开机后,马上启动这个线程做apk的dexopt优化。但是还有个sleep,等待了一段时间。这样就导致,在开机时,有些apk是依赖开机广播启动的。这样在启动apk时,因为dexopt并没有优化apk,导致未生成dex文件,也就无法找到相应的class了。


还了问题找到了。通过试验,去除do_dexopt接口中的apk缓存链表代码,只保留dexopt的代码,如下:


编译版本验证通过。问题的原因找到了。但是为什么会有这段代码呢?

我去找了android的原生代码,发现原生代码就是去除缓存后的修改代码。也就确认了,缓存apk到链表中的代码是高通自己添加的。

但是高通为什么要添加这段代码?


其实高通添加这段代码,是为了提高首次开机的速度。在apk没有在编译时做odex优化时,首次开机过程中,需要对每个apk都做一次dex优化,提取apk中的classes.dex文件,并生成oat文件。这样开机速度会慢很多。如果做了缓存,在开机时,就减少了这段时间。开始速度大大提高。但是 因为部分apk需要开机完成马上启动,导致了出现apk报停止运行的错误。


你可能感兴趣的:(android)