ClassNotFoundException debug

问题描述:

java.lang.RuntimeException:Unable to instantiate applicationcom.goodreads.kindle.application.MyApplication:java.lang.ClassNotFoundException: Didn't find class"com.goodreads.kindle.application.MyApplication" on path:DexPathList[[zip file "/system/framework/com.amazon.kindle.cms.jar",zip file "/system/framework/com.amazon.sics.jar", zip file"/system/framework/com.amazon.sync.api.jar", zip file "/system/framework/retaildemoapi.jar",zip file "/system/framework/com.amazon.identity.auth.device.jar", zipfile"/system/priv-app/DeviceClientPlatformContractsFramework/DeviceClientPlatformContractsFramework.apk",zip file "/system/priv-app/DeviceSoftwareOTAContracts/DeviceSoftwareOTAContracts.apk",zip file "/system/priv-app/MetricsApi/MetricsApi.apk", zip file"/system/priv-app/RemoteSettingsInternalSDK/RemoteSettingsInternalSDK.apk",zip file "/system/priv-app/com.amazon.dp.logger/com.amazon.dp.logger.apk"],nativeLibraryDirectories=[/vendor/lib,/system/lib]]


问题调查:

log整理:

java.lang.RuntimeException:Unable to instantiate applicationcom.goodreads.kindle.application.MyApplication:java.lang.ClassNotFoundException

Didn't find class"com.goodreads.kindle.application.MyApplication" on path:DexPathList[[

zip file "/system/framework/com.amazon.kindle.cms.jar",

zip file "/system/framework/com.amazon.sics.jar", 

zip file"/system/framework/com.amazon.sync.api.jar", 

zip file "/system/framework/retaildemoapi.jar",

zip file "/system/framework/com.amazon.identity.auth.device.jar", 

zip file"/system/priv-app/DeviceClientPlatformContractsFramework/DeviceClientPlatformContractsFramework.apk",

zip file "/system/priv-app/DeviceSoftwareOTAContracts/DeviceSoftwareOTAContracts.apk",

zip file "/system/priv-app/MetricsApi/MetricsApi.apk", 

zip file"/system/priv-app/RemoteSettingsInternalSDK/RemoteSettingsInternalSDK.apk",

zip file "/system/priv-app/com.amazon.dp.logger/com.amazon.dp.logger.apk"],

nativeLibraryDirectories=[/vendor/lib,/system/lib]]


背景知识:

正常情况下,要启动一个package,需要先启动其中的Application。在启动过程中,会创建一个LoadedApk对象负责apk的管理,它可以读取apk文件的资源,也可以加载apk中的类。

要加载一个类,需要用到ClassLoader对象,在LoadedApk对象中,会生成一个PathClassLoader类,他是ClassLoader的子类。其中最重要的参数就是类文件的路径列表,就像上面message中显示的一样。

在这个列表,必要要包含本apk文件的路径,已经它所依赖的jar文件路径。


问题分析:

从log看,第一感觉是因为dexpathlist中缺少要启动的apk,导致其中的Application类没有找到。但是从代码的角度分析,这是不可能的。

    public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
            CompatibilityInfo compatInfo, ClassLoader baseLoader,
            boolean securityViolation, boolean includeCode, boolean registerPackage) {
        final int myUid = Process.myUid();
        aInfo = adjustNativeLibraryPaths(aInfo);


        mActivityThread = activityThread;
        mApplicationInfo = aInfo;
        mPackageName = aInfo.packageName;
        mAppDir = aInfo.sourceDir; ---------------------------------------------------------------------- important
        mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
        mSplitAppDirs = aInfo.splitSourceDirs;
        mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
        mOverlayDirs = aInfo.resourceDirs;
        if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
            aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
                    mPackageName);
        }
        mSharedLibraries = aInfo.sharedLibraryFiles;
        mDataDir = aInfo.dataDir;
        mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
        mLibDir = aInfo.nativeLibraryDir;
        mBaseClassLoader = baseLoader;
        mSecurityViolation = securityViolation;
        mIncludeCode = includeCode;
        mRegisterPackage = registerPackage;
        mDisplayAdjustments.setCompatibilityInfo(compatInfo);
    }

在loadedapk的构造函数中,会记录当前apk的路径,而这个路径一定是apk的实际路径。这个路径是是PMS提供的,AMS会向PMS查询,如果PMS查询不到,则AMS不会启动,也就不会走到LoadedApk这个步骤。

但是从最终的crash message看,DexPathList中确实不包含当前apk的路径。

从代码的角度分析,有一个地方可能把传入的路径删除掉。

DexPathList的构造函数中,splitDexPath函数先处理传入的path,它会调用splitAndAdd函数逐一验证path的有效性. 把有效的路径加入到最终的列表中。所以,如果用户通过adb删除了某些apk文件,那么在验证路径的时候,就不会把路径加入到最终的列表中,导致启动class时找不到。

    public DexPathList(ClassLoader definingContext, String dexPath,
            String libraryPath, File optimizedDirectory) {

        this.definingContext = definingContext;
        ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
        this.dexElements = makeDexElements(splitDexPath(
dexPath), optimizedDirectory,
                                           suppressedExceptions);
    }


    private static void splitAndAdd(String searchPath, boolean directoriesOnly,
            ArrayList<File> resultList) {
        for (String path : searchPath.split(":")) {
            try {
                StructStat sb = Libcore.os.stat(path); // 文件不存在的时候会抛出异常
                if (!directoriesOnly || S_ISDIR(sb.st_mode)) {
                    resultList.add(new File(path));
                }
            } catch (ErrnoException ignored) {
            }
        }
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值