APP安装时抛出error code -102的由来

7,957 阅读3分钟

有时修改AM文件,AS编译代码时,可能因编译环境导致打包得到的APK安装时出现Installation error code: -102的现象,那-102错误码到底是指PM在何阶段出现的?

1、PackageManagerService

frameworks\base\services\core\java\com\android\server\pm

1.1 processPendingInstall在解析APP时,捕获-102,并将结果缓存至SparseArray mRunningInstalls中,对应key为token。

    private void processPendingInstall(final InstallArgs args, final int currentStatus) {
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.returnCode = currentStatus;
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = new PackageRemovedInfo();
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                    args.doPreInstall(res.returnCode);
                    synchronized (mInstallLock) {
                        installPackageLI(args, res);//解析,捕获-102异常,保存在res中
                    }
                    args.doPostInstall(res.returnCode, res.uid);
                }
                ...
                PostInstallData data = new PostInstallData(args, res);
                mRunningInstalls.put(token, data);//-102缓存至SparseArray<PostInstallData> mRunningInstalls中。
                if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);//注意token,在处理POST_INSTALL消息时会根据其取出-102
                ...
                if (!doRestore) {
                    // No restore possible, or the Backup Manager was mysteriously not
                    // available -- just fire the post-install work request directly.
                    if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
                    Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
                    mHandler.sendMessage(msg);
                }
    }

1.2 installPackageLI 捕获-102

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
    // Result object to be returned
        res.returnCode = PackageManager.INSTALL_SUCCEEDED;
        ...
        PackageParser pp = new PackageParser();
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setDisplayMetrics(mMetrics);

        final PackageParser.Package pkg;
        try {
            pkg = pp.parsePackage(tmpPackageFile, parseFlags);
        } catch (PackageParserException e) {
            res.setError("Failed parse during installPackageLI", e);//注意在此处捕获-102异常
            return;
        }
}

2、PackageParser抛出-102

frameworks\base\core\java\android\content\pm

2.1 parsePackage 抛出-102

    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        if (packageFile.isDirectory()) {
            return parseClusterPackage(packageFile, flags);
        } else {
            return parseMonolithicPackage(packageFile, flags);
        }
    }

2.2 parseMonolithicPackage 抛出-102

public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
 try {
            final Package pkg = parseBaseApk(apkFile, assets, flags);
            pkg.codePath = apkFile.getAbsolutePath();
            return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
}

2.3 parseBaseApk 抛出-102

在调用parseBaseApk(res, parser, flags, outError);会抛出错误码为INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102的异常,由PackageManagerService在其installPackageLI中捕获。

    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
            throws PackageParserException {
            try {
            res = new Resources(assets, mMetrics, null);
            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    Build.VERSION.RESOURCES_SDK_INT);
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

            final String[] outError = new String[1];
            final Package pkg = parseBaseApk(res, parser, flags, outError);
            if (pkg == null) {
                throw new PackageParserException(mParseError,
                        apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
            }

            pkg.volumeUuid = volumeUuid;
            pkg.baseCodePath = apkPath;
            pkg.mSignatures = null;

            return pkg;

        } catch (PackageParserException e) {
            throw e;
        } catch (Exception e) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                    "Failed to read manifest from " + apkPath, e);
        } finally {
            IoUtils.closeQuietly(parser);
        }
    }

3 PMS的processPendingInstall 发送POST_INSTALL消息

frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java

3.1 发送POST_INSTALL消息

  private void processPendingInstall(final InstallArgs args, final int currentStatus) {
  ...
  if (!doRestore) {
                    // No restore possible, or the Backup Manager was mysteriously not
                    // available -- just fire the post-install work request directly.
                    if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
                    Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
                    mHandler.sendMessage(msg);
                }
  ...
  }

3.2 通知应用层安装器

mRunningInstalls.get(msg.arg1);根据token取出含有-102信息的PostInstallData。

 class PackageHandler extends Handler {
 void doHandleMessage(Message msg) {
            switch (msg.what) {
                case POST_INSTALL: {
                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
                    PostInstallData data = mRunningInstalls.get(msg.arg1);
                    if (data != null) {
                        InstallArgs args = data.args;
                        PackageInstalledInfo res = data.res;

                        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                           if (args.observer != null) {
                            try {
                                Bundle extras = extrasForInstallResult(res);
                                args.observer.onPackageInstalled(res.name, res.returnCode,
                                        res.returnMsg, extras);//通知应用层安装器,PMS出现-102异常
                            } catch (RemoteException e) {
                                Slog.i(TAG, "Observer no longer exists.");
                            }
                        }
                        }
                    }
            }
 }

4 PackageHandler的observer从何来

4.1 应用层PackageInstaller

packages/apps/PackageInstaller

public class InstallAppProgress{
    PackageInstallObserver observer = new PackageInstallObserver();
        pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);
}

class PackageInstallObserver extends IPackageInstallObserver.Stub {
        public void packageInstalled(String packageName, int returnCode) {
            Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
            msg.arg1 = returnCode;
            mHandler.sendMessage(msg);
        }
    }

4.2 ApplicationPackageManager installPackage

frameworks\base\core\java\android\app\ApplicationPackageManager.java

    public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
                               String installerPackageName) {
        final VerificationParams verificationParams = new VerificationParams(null, null,
                null, VerificationParams.NO_UID, null);
        installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
                installerPackageName, verificationParams, null);
    }

4.3 PMS installPackage 发出INIT_COPY

frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java

    @Override
    public void installPackage(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, VerificationParams verificationParams,
            String packageAbiOverride) {
        installPackageAsUser(originPath, observer, installFlags, installerPackageName,
                verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
    }
    
    public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,int installFlags, String installerPackageName, VerificationParams verificationParams, String packageAbiOverride, int userId) {
             final Message msg = mHandler.obtainMessage(INIT_COPY);
        msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
                null, verificationParams, user, packageAbiOverride, null);
        mHandler.sendMessage(msg);
    }

5 PMS中observer的创建过程

 case MCS_BOUND: {
 else if (mPendingInstalls.size() > 0) {
                        HandlerParams params = mPendingInstalls.get(0);
                        if (params != null) {
                            if (params.startCopy()) {
        final boolean startCopy() {
            boolean res;
            try {
                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);

                if (++mRetries > MAX_RETRIES) {
                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                    mHandler.sendEmptyMessage(MCS_GIVE_UP);
                    handleServiceError();
                    return false;
                } else {
                    handleStartCopy();
                    res = true;
                }
            } catch (RemoteException e) {
                if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
                mHandler.sendEmptyMessage(MCS_RECONNECT);
                res = false;
            }
            handleReturnCode();
            return res;
        }
  public void handleStartCopy() throws RemoteException {
            int ret = PackageManager.INSTALL_SUCCEEDED;
             final InstallArgs args = createInstallArgs(this);
            mArgs = args;
            }
void handleReturnCode() {
            // If mArgs is null, then MCS couldn't be reached. When it
            // reconnects, it will try again to install. At that point, this
            // will succeed.
            if (mArgs != null) {
                processPendingInstall(mArgs, mRet);
            }
        }

至此,processPendingInstall中的observer就存储在mRunningInstalls中了。这样APP安装时,解析出现-102异常,就可以通知应用层PackageInstaller了。