Android中APK的安装流程

  • Post author:
  • Post category:其他


这篇文章,来学习apk的安装流程,在开始之前,先看看我们在APP中是通过下面代码来安装apk的

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive");
context.startActivity(intent);

构造一个intent,并且setDataAndType,然后启动这个activity,此时系统默认的安装apk的PackageInstallerActivity界面就出现了。

##使用PackageInstallerActivity安装apk的流程##

在PackageInstallerActivity中定义了这样的字符串

private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";

这个是在PackageManagerService中匹配的。

PackageInstallerActivity也是一个activity,所以当该界面显示的时候,会首先调用其onCreate方法,我们来看看。

 @Override
protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        mPm = getPackageManager(); //是一个PackageManager实例,具体用来执行安装操作的
        mInstaller = mPm.getPackageInstaller(); // PackageInstaller实例,在该实例中包含了安装apk的基本信息
        mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);

        final Intent intent = getIntent();

        //set view
        setContentView(R.layout.install_start);
        mInstallConfirm = findViewById(R.id.install_confirm_panel);
        mInstallConfirm.setVisibility(View.INVISIBLE);

        // Block the install attempt on the Unknown Sources setting if necessary.
        if (!requestFromUnknownSource) {
            // 为安装操作,执行一些初始化的工作
            initiateInstall();
            return;
        }
}

可以看到,在onCreate中,主要通过initiateInstall();为安装操作,执行一些初始化的工作。

private void initiateInstall() {
        // 当前apk的包名
        String pkgName = mPkgInfo.packageName;
        // Check if there is already a package on the device with this name
        // but it has been renamed to something else.
        String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
        if (oldName != null && oldName.length > 0 && oldName[0] != null) {
            pkgName = oldName[0];
            mPkgInfo.packageName = pkgName;
            mPkgInfo.applicationInfo.packageName = pkgName;
        }

        try {
            // 通过PackageManager从系统中获取没有安装的apk的信息
            mAppInfo = mPm.getApplicationInfo(pkgName,
                    PackageManager.GET_UNINSTALLED_PACKAGES);
            // 如果已经安装,在后面会给出用户是否替换的提示
            if ((mAppInfo.flags& ApplicationInfo.FLAG_INSTALLED) == 0) {
                mAppInfo = null;
            }
        } catch (PackageManager.NameNotFoundException e) {
            mAppInfo = null;
        }
        // 调用startInstallConfirm进行进一步的安装操作
        startInstallConfirm();
}

上面代码最终主要该通过startInstallConfirm来进一步安装apk

private void startInstallConfirm() {
        mInstallConfirm.setVisibility(View.VISIBLE);
        mOk = (Button)findViewById(R.id.ok_button);
        mCancel = (Button)findViewById(R.id.cancel_button);
        mOk.setOnClickListener(this);
        mCancel.setOnClickListener(this);
}
PackageInstallerActivity实现了OnClicklistener
public void onClick(View v) {
        if (v == mOk) {
           startInstall();
        } else if(v == mCancel) {
            // Cancel and finish
            setResult(RESULT_CANCELED);
            finish();
        }
}



private void startInstall() {
        // 安装apk,构造intent,这里会跳转到InstallAppProgress里
        Intent newIntent = new Intent();
        // 传递数据
        newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
                mPkgInfo.applicationInfo);
        newIntent.setData(mPackageURI);
        newIntent.setClass(this, InstallAppProgress.class);
        newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest);
        newIntent.putExtra(
                InstallAppProgress.EXTRA_INSTALL_FLOW_ANALYTICS, mInstallFlowAnalytics);
        String installerPackageName = getIntent().getStringExtra(
                Intent.EXTRA_INSTALLER_PACKAGE_NAME);
        if (mOriginatingURI != null) {
            newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
        }
        if (mReferrerURI != null) {
            newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
        }
        if (mOriginatingUid != VerificationParams.NO_UID) {
            newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
        }
        if (installerPackageName != null) {
            newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
                    installerPackageName);
        }
        if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
            newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
            newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
        }
        // 进入InstallAppProgress
        startActivity(newIntent);
        finish();
}

可以看到在startInstall方法中,主要构造一个intent,并且传递必要的数据,跳转到InstallAppProgress类,在该类中有一个initView方法

public void initView() {
        setContentView(R.layout.op_progress);
        int installFlags = 0;
        PackageManager pm = getPackageManager();
        // 判断当前apk是否已经安装过
        try {
            PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,
                    PackageManager.GET_UNINSTALLED_PACKAGES);
            if(pi != null) {
                installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
            }
        } catch (PackageManager.NameNotFoundException e) {
        }
        // 省略代码
        // 构造一个PackageInstallObserver,当安装完成以后,回调对应的方法
        PackageInstallObserver observer = new PackageInstallObserver();

        if ("package".equals(mPackageURI.getScheme())) {
            try {
                // 调用PackageManagerService服务的installExistingPackage进行安装
                pm.installExistingPackage(mAppInfo.packageName);
                observer.packageInstalled(mAppInfo.packageName,
                        PackageManager.INSTALL_SUCCEEDED);
            } catch (PackageManager.NameNotFoundException e) {
                observer.packageInstalled(mAppInfo.packageName,
                        PackageManager.INSTALL_FAILED_INVALID_APK);
            }
        } else {
            pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
                    installerPackageName, verificationParams, null);
        }
}

这里具体的PackageManagerService服务安装的过程我们稍后会进行学习,先看下当安装完成以后通过PackageInstallObserver执行的回调方法

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

发送”INSTALL_COMPLETE”这样的消息到自身,在handleMessage中主要做了下面的操作:

mLaunchIntent = getPackageManager().getLaunchIntentForPackage(
                                mAppInfo.packageName);
mLaunchButton.setOnClickListener(InstallAppProgress.this);
mDoneButton.setOnClickListener(InstallAppProgress.this);

获取启动当前apk的intent,并且为done和lunch按钮设置点击事件

 public void onClick(View v) {
        if(v == mDoneButton) {
            if (mAppInfo.packageName != null) {
                Log.i(TAG, "Finished installing "+mAppInfo.packageName);
            }
            finish();
        } else if(v == mLaunchButton) {
            startActivity(mLaunchIntent);
            finish();
        }
}

好了,到现在为止,使用PackageInstallerActivity安装apk的整个流程已经梳理完毕,实际上真正执行安装操作的都是交给了PackageManagerService服务的installExistingPackage进行安装的

##PackageManagerService安装apk流程##

平时我们可以使用下面两个命令来安装apk

pm get-install-location 查找安装apk的位置 一般默认 为0[auto]
pm set-install-location 设置位置

这里最终都是通过PackageManagerService来实现安装具体包的操作


调用PackageManagerService#installPackage方法开始apk的安装过程

public void installPackage(String originPath, IPackageInstallObserver2 observer,
            int installFlags, String installerPackageName, VerificationParams verificationParams,
            String packageAbiOverride) {
        installPackageAsUser(originPath, observer, installFlags, installerPackageName,
                verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
}



@Override
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
                                     int installFlags, String installerPackageName, VerificationParams verificationParams,
                                     String packageAbiOverride, int userId) {
        // 检查是否有install权限
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);

        final int callingUid = Binder.getCallingUid();
        enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");
        // 判断当前用户是否被Restricted,回调onPackageInstalled方法,安装失败
        if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
            try {
                if (observer != null) {
                    observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
                }
            } catch (RemoteException re) {
            }
            return;
        }

       // 代码省略,主要是判断当前安装的方式设置对应的installFlags


        final File originFile = new File(originPath);
        final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
        // 发送"INIT_COPY" 消息,构造InstallParams参数
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
                null, verificationParams, user, packageAbiOverride, null);
        mHandler.sendMessage(msg);
}


整个PackageHandler是PackageManagerService的一个内部类

witch (msg.what) {
                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
                    //这里获取当前需要安装的apk个数,mPendingInstalls保存着所有需要安装的apk解析出来的HandlerParams参数
                    int idx = mPendingInstalls.size();
                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
                    // 如果没有绑定DefaultContainerService,则进行那个绑定,DefaultContainerService主要负责计算当前存储和拷贝工作
                    if (!mBound) {
                        if (!connectToService()) {
                            params.serviceError();
                            return;
                        } else {
                            mPendingInstalls.add(idx, params);
                        }
                    } else {
                        mPendingInstalls.add(idx, params);
                        if (idx == 0) {
                            mHandler.sendEmptyMessage(MCS_BOUND);
                        }
                    }
                    break;
}


继续发送”MCS_BOUND”参数到自己处理,表示绑定DefaultContainerService服务完成

case MCS_BOUND: {
        if (msg.obj != null) {
            mContainerService = (IMediaContainerService) msg.obj;
        }
        if (mContainerService == null) {
            // 绑定DefaultContainerService服务失败,回调serviceError方法
            if (!mBound) {
                Slog.e(TAG, "Cannot bind to media container service");
                for (HandlerParams params : mPendingInstalls) {
                    params.serviceError();
                }
                mPendingInstalls.clear();
            } else {
                Slog.w(TAG, "Waiting to connect to media container service");
            }
        } else if (mPendingInstalls.size() > 0) {
            // 总是安装队列中的第一个
            HandlerParams params = mPendingInstalls.get(0);
            if (params != null) {
                if (params.startCopy()) { //首先拷贝当前apk到对应的目录下
                    // We are done...  look for more work or to
                    // go idle.
                    if (mPendingInstalls.size() > 0) { // 将第一个移除当前队列
                        mPendingInstalls.remove(0);
                    }
                    if (mPendingInstalls.size() == 0) { //size等于0,表示所有的apk都已经安装完成,unbind当前DefaultContainerService服务
                        if (mBound) {
                            if (DEBUG_SD_INSTALL) Log.i(TAG,
                                    "Posting delayed MCS_UNBIND");
                            removeMessages(MCS_UNBIND);
                            Message ubmsg = obtainMessage(MCS_UNBIND);
                            // Unbind after a little delay, to avoid
                            // continual thrashing.
                            sendMessageDelayed(ubmsg, 10000);
                        }
                    } else {
                        //继续安装下一个需要安装的包
                        mHandler.sendEmptyMessage(MCS_BOUND);
                    }
                }
            }
        } else {
            Slog.w(TAG, "Empty queue");
        }
        break;
    }


可以看到,其实所有的安装apk的代码都放到了HandlerParams#startCopy方法中,看下HandlerParams

private abstract class HandlerParams {
	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 {
                    // 这里的具体copy处理是由其子类来完成的
                    handleStartCopy();
                    res = true;
                }
            } catch (RemoteException e) {
                if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
                mHandler.sendEmptyMessage(MCS_RECONNECT);
                res = false;
            }
            // handleReturnCode,该方法会在handleStartCopy执行玩拷贝相关动作之后,根据在handleStartCopy中的做进一步处理
            handleReturnCode();
            return res;
        }

        final void serviceError() {
            if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");
            handleServiceError();
            handleReturnCode();
        }

        abstract void handleStartCopy() throws RemoteException;
        abstract void handleServiceError();
        abstract void handleReturnCode();
    }

}


这里是由InstallParams来处理copy操作的。

public void handleStartCopy() throws RemoteException {
        int ret = PackageManager.INSTALL_SUCCEEDED;

        if (origin.staged) {
            if (origin.file != null) {
                installFlags |= PackageManager.INSTALL_INTERNAL;
                installFlags &= ~PackageManager.INSTALL_EXTERNAL;
            } else if (origin.cid != null) {
                installFlags |= PackageManager.INSTALL_EXTERNAL;
                installFlags &= ~PackageManager.INSTALL_INTERNAL;
            } else {
                throw new IllegalStateException("Invalid stage location");
            }
        }
        // 是否安装到sdcard或者内部存储中
        final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
        final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;

        PackageInfoLite pkgLite = null;

        if (onInt && onSd) {
            // 用户同时设置安装到sdcard和内部存储
            Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
            ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
        } else {
            pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
                    packageAbiOverride);

            .......
            //代码省略,主要根据存储情况,释放当前存储空间
        }
        // 根据当前InstallParams构造具体的InstallArgs实现类,在该实现类中做具体的拷贝操作
        final InstallArgs args = createInstallArgs(this);
        mArgs = args;

        if (ret == PackageManager.INSTALL_SUCCEEDED) {
                 /*
                 * ADB installs appear as UserHandle.USER_ALL, and can only be performed by
                 * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
                 */
            int userIdentifier = getUser().getIdentifier();
            if (userIdentifier == UserHandle.USER_ALL
                    && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) {
                userIdentifier = UserHandle.USER_OWNER;
            }

            final int requiredUid = mRequiredVerifierPackage == null ? -1
                    : getPackageUid(mRequiredVerifierPackage, userIdentifier);
            if (!origin.existing && requiredUid != -1
                    && isVerificationEnabled(userIdentifier, installFlags) &&
                    isVerificationRequired()) { // 对当前的包做验证操作
                final Intent verification = new Intent(
                        Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
                verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                        PACKAGE_MIME_TYPE);
                verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

                final List<ResolveInfo> receivers = queryIntentReceivers(verification,
                        PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS,
                        0 /* TODO: Which userId? */);

                final int verificationId = mPendingVerificationToken++;

                verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);

                verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
                        installerPackageName);

                verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS,
                        installFlags);

                verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME,
                        pkgLite.packageName);

                verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
                        pkgLite.versionCode);

                if (verificationParams != null) {
                    if (verificationParams.getVerificationURI() != null) {
                        verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI,
                                verificationParams.getVerificationURI());
                    }
                    if (verificationParams.getOriginatingURI() != null) {
                        verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
                                verificationParams.getOriginatingURI());
                    }
                    if (verificationParams.getReferrer() != null) {
                        verification.putExtra(Intent.EXTRA_REFERRER,
                                verificationParams.getReferrer());
                    }
                    if (verificationParams.getOriginatingUid() >= 0) {
                        verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
                                verificationParams.getOriginatingUid());
                    }
                    if (verificationParams.getInstallerUid() >= 0) {
                        verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
                                verificationParams.getInstallerUid());
                    }
                }

                final PackageVerificationState verificationState = new PackageVerificationState(
                        requiredUid, args);

                mPendingVerification.append(verificationId, verificationState);

                final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                        receivers, verificationState);

                // Apps installed for "all" users use the device owner to verify the app
                UserHandle verifierUser = getUser();
                if (verifierUser == UserHandle.ALL) {
                    verifierUser = UserHandle.OWNER;
                }

                    /*
                     * If any sufficient verifiers were listed in the package
                     * manifest, attempt to ask them.
                     */
                if (sufficientVerifiers != null) {
                    final int N = sufficientVerifiers.size();
                    if (N == 0) {
                        Slog.i(TAG, "Additional verifiers required, but none installed.");
                        ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
                    } else {
                        for (int i = 0; i < N; i++) {
                            final ComponentName verifierComponent = sufficientVerifiers.get(i);

                            final Intent sufficientIntent = new Intent(verification);
                            sufficientIntent.setComponent(verifierComponent);
                            mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
                        }
                    }
                }

                final ComponentName requiredVerifierComponent = matchComponentForVerifier(
                        mRequiredVerifierPackage, receivers);
                if (ret == PackageManager.INSTALL_SUCCEEDED
                        && mRequiredVerifierPackage != null) {
                        /*
                         * Send the intent to the required verification agent,
                         * but only start the verification timeout after the
                         * target BroadcastReceivers have run.
                         */
                    verification.setComponent(requiredVerifierComponent);
                    mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
                            android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
                            new BroadcastReceiver() {
                                @Override
                                public void onReceive(Context context, Intent intent) {
                                    final Message msg = mHandler
                                            .obtainMessage(CHECK_PENDING_VERIFICATION);
                                    msg.arg1 = verificationId;
                                    mHandler.sendMessageDelayed(msg, getVerificationTimeout());
                                }
                            }, null, 0, null, null);

                        /*
                         * We don't want the copy to proceed until verification
                         * succeeds, so null out this field.
                         */
                    mArgs = null;
                }
            } else {
                // 执行拷贝操作
                ret = args.copyApk(mContainerService, true);
            }
        }

        mRet = ret;
    }


上面主要做了这样的事情:

  1. 判断安装默认存储
  2. 若当前存储不够,则释放储存空间
  3. 如果需要,对当前包做验证操作
  4. 执行拷贝操作

    就安装而言,最重要的还是最后的执行拷贝操作,这里是InstallArgs#copyApk
static abstract class InstallArgs


包含三个子类

  1. FileInstallArgs apk安装到内部存储器时使用。
  2. AsecInstallArgs 安装到sdcard或者ForwardLocked时使用
  3. MoveInstallArgs 移动包的位置,比如从内部存储移动到sdcard上

    在构造方法中根据InstallParams会构造出具体类型
private InstallArgs createInstallArgs(InstallParams params) {
        if (params.move != null) {
            return new MoveInstallArgs(params);
        } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
            return new AsecInstallArgs(params);
        } else {
            return new FileInstallArgs(params);
        }
}


这里我们以AsecInstallArgs为例,进行说明

int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
            
            if (origin.staged) {
                if (DEBUG_INSTALL) Slog.d(TAG, origin.cid + " already staged; skipping copy");
                cid = origin.cid;
                setMountPath(PackageHelper.getSdDir(cid));
                return PackageManager.INSTALL_SUCCEEDED;
            }

            if (temp) {
                createCopyFile();
            } else {
                /*
                 * Pre-emptively destroy the container since it's destroyed if
                 * copying fails due to it existing anyway.
                 */
                PackageHelper.destroySdDir(cid);
            }
            //copyPackageToContainer执行真正的拷贝操作
            final String newMountPath = imcs.copyPackageToContainer(
                    origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternalAsec(),
                    isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */));

            if (newMountPath != null) {
                setMountPath(newMountPath);
                return PackageManager.INSTALL_SUCCEEDED; //这里安装成功之后,会将mRet赋值为PackageManager.INSTALL_SUCCEEDED
            } else {
                return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
            }
}


到现在为止,copyApk的操作已经完成,接下来交给handleReturnCode处理

@Override
void handleReturnCode() {
            // mArgs是在handleStartCopy中创建的
            if (mArgs != null) {
                processPendingInstall(mArgs, mRet);
            }
}




private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        // 由于安装可能耗时操作,所以这里开启了一个线程
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
                // Result object to be returned
                PackageInstalledInfo res = new PackageInstalledInfo();
                res.returnCode = currentStatus;
                res.uid = -1;
                res.pkg = null;
                res.removedInfo = new PackageRemovedInfo();
                // 如果之前copyApk正常执行完成,这里res.returnCode == PackageManager.INSTALL_SUCCEEDED成立
                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                    args.doPreInstall(res.returnCode); //安装前的准备工作
                    synchronized (mInstallLock) {
                        installPackageLI(args, res); //执行安装操作
                    }
                    args.doPostInstall(res.returnCode, res.uid); //安装完成以后的曹操作
                }

                .........
                Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); // 安装完成后发送"POST_INSTALL"广播
                mHandler.sendMessage(msg);
            }
        });
}




看下进一步安装的相关步骤

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
        ......
        PackageParser pp = new PackageParser();
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setDisplayMetrics(mMetrics);
        pp.setRuntimeSkinBlacklist(mRuntimeSkinManager.getBlacklistedPackages());

        final PackageParser.Package pkg;
        try {
            // PackageParser解析manifest文件
            pkg = pp.parsePackage(tmpPackageFile, parseFlags);
        } catch (PackageParser.PackageParserException e) {
            res.setError("Failed parse during installPackageLI", e);
            return;
        }

        // Mark that we have an install time CPU ABI override.
        pkg.cpuAbiOverride = args.abiOverride;

        String pkgName = res.name = pkg.packageName;

        // Mark that we have an install time CPU ABI override.
        pkg.cpuAbiOverride = args.abiOverride;

        String pkgName = res.name = pkg.packageName;
        // 根据用户策略,判断当前用户是否允许安装apk,否则直接返回
        boolean installForAllUsers = ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0);
        int user = args.user == null ? -1 : args.user.getIdentifier();
        if (isInstallationBlockedByDevicePolicy(pkgName, installForAllUsers, user)) {
            res.returnCode = PackageManager.INSTALL_FAILED_USER_RESTRICTED;
            return;
        }
        // 签名相关信息
        try {
            pp.collectCertificates(pkg, parseFlags);
            pp.collectManifestDigest(pkg);
        } catch (PackageParser.PackageParserException e) {
            res.setError("Failed collect during installPackageLI", e);
            return;
        }
        ........
        // 如果已经安装当前应用,则替换,否则安装
        if (replace) {
            replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                    installerPackageName, volumeUuid, res);
        } else {
            installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
                    args.user, installerPackageName, volumeUuid, res);
        }

}


可以看到上面的代码主要做了下面操作:

  1. 解析manifest文件,并且将解析结果封装成PackageParser对象
  2. 判断当前安装条件四是否满足,否则直接返回,比如:根据用户策略,判断当前用户是否允许安装apk,否则直接返回
  3. 获取签名相关信息,并且做校验
  4. 安装或者替换当前应用installNewPackageLI或者replacePackageLI


PackageParser解析manifest文件,PackageParser#parsePackage —-> PackageParser#parseClusterPackage —> PackageParser#parseBaseApk

private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
            throws PackageParserException {
        final String apkPath = apkFile.getAbsolutePath();

        String volumeUuid = null;
        if (apkPath.startsWith(MNT_EXPAND)) {
            final int end = apkPath.indexOf('/', MNT_EXPAND.length());
            volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
        }

        mParseError = PackageManager.INSTALL_SUCCEEDED;
        mArchiveSourcePath = apkFile.getAbsolutePath();

        if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);

        Resources res = null;
        XmlResourceParser parser = null;
        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);
            // 解析manifest文件
            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.applicationInfo.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);
        }
}


通过installNewPackageLI执行安装操作

     /*
      * Install a non-existing package.
      */
private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
                                     UserHandle user, String installerPackageName, String volumeUuid,
                                     PackageInstalledInfo res) {
        // Remember this for later, in case we need to rollback this install
        String pkgName = pkg.packageName;

        .......

        try {
            // 核心的调用
            PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
                    System.currentTimeMillis(), user);

            updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
            //如果安装失败,则执行回退操作,删除创建的文件夹等缓存文件
            if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
                deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
                        dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
                        res.removedInfo, true);
            }

        } catch (PackageManagerException e) {
            res.setError("Package couldn't be installed in " + pkg.codePath, e);
        }
    }




private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
        boolean success = false;
        try {
            final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,
                    currentTime, user);
            success = true;
            // 程序走到这里说明安装成功了,这里会返回根据解析构建的Package对象,该对象中包含了该apk对应的manifest中的信息
            return res;
        } finally {
            if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
                removeDataDirsLI(pkg.volumeUuid, pkg.packageName);
            }
        }
    }




终于走到了scanPackageDirtyLI方法,安装apk的核心方法:

在该方法中,会根据之前解析出来的内容,添加到对应的list中,方便以后query查询

    // Currently known shared libraries.
    final ArrayMap<String, SharedLibraryEntry> mSharedLibraries =
            new ArrayMap<String, SharedLibraryEntry>();

    // All available activities, for your resolving pleasure.
    final ActivityIntentResolver mActivities =
            new ActivityIntentResolver();

    // All available receivers, for your resolving pleasure.
    final ActivityIntentResolver mReceivers =
            new ActivityIntentResolver();

    // All available services, for your resolving pleasure.
    final ServiceIntentResolver mServices = new ServiceIntentResolver();

    // All available providers, for your resolving pleasure.
    final ProviderIntentResolver mProviders = new ProviderIntentResolver();



private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
                                                     int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
            .......

            int N = pkg.providers.size();
            StringBuilder r = null;
            int i;
            for (i=0; i<N; i++) {
                PackageParser.Provider p = pkg.providers.get(i);
                p.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        p.info.processName, pkg.applicationInfo.uid);
                // 添加provider
                mProviders.addProvider(p);
                p.syncable = p.info.isSyncable;
                if (p.info.authority != null) {
                    String names[] = p.info.authority.split(";");
                    p.info.authority = null;
                    for (int j = 0; j < names.length; j++) {
                        if (j == 1 && p.syncable) {
                            // We only want the first authority for a provider to possibly be
                            // syncable, so if we already added this provider using a different
                            // authority clear the syncable flag. We copy the provider before
                            // changing it because the mProviders object contains a reference
                            // to a provider that we don't want to change.
                            // Only do this for the second authority since the resulting provider
                            // object can be the same for all future authorities for this provider.
                            p = new PackageParser.Provider(p);
                            p.syncable = false;
                        }
                        if (!mProvidersByAuthority.containsKey(names[j])) {
                            mProvidersByAuthority.put(names[j], p);
                            if (p.info.authority == null) {
                                p.info.authority = names[j];
                            } else {
                                p.info.authority = p.info.authority + ";" + names[j];
                            }
                            if (DEBUG_PACKAGE_SCANNING) {
                                if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
                                    Log.d(TAG, "Registered content provider: " + names[j]
                                            + ", className = " + p.info.name + ", isSyncable = "
                                            + p.info.isSyncable);
                            }
                        } else {
                            PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
                            Slog.w(TAG, "Skipping provider name " + names[j] +
                                    " (in package " + pkg.applicationInfo.packageName +
                                    "): name already used by "
                                    + ((other != null && other.getComponentName() != null)
                                    ? other.getComponentName().getPackageName() : "?"));
                        }
                    }
                }
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(p.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Providers: " + r);
            }

            N = pkg.services.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Service s = pkg.services.get(i);
                s.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        s.info.processName, pkg.applicationInfo.uid);
                // 添加service
                mServices.addService(s);
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(s.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Services: " + r);
            }

            N = pkg.receivers.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Activity a = pkg.receivers.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName, pkg.applicationInfo.uid);
                // 添加receivers
                mReceivers.addActivity(a, "receiver");
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(a.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Receivers: " + r);
            }

            N = pkg.activities.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Activity a = pkg.activities.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName, pkg.applicationInfo.uid);
                // 添加activity
                mActivities.addActivity(a, "activity");
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(a.info.name);
                }
            }
            if (r != null) {
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Activities: " + r);
            }

            N = pkg.permissionGroups.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
                PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
                if (cur == null) {
                    // 添加权限
                    mPermissionGroups.put(pg.info.name, pg);
                    if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                        if (r == null) {
                            r = new StringBuilder(256);
                        } else {
                            r.append(' ');
                        }
                        r.append(pg.info.name);
                    }
                } else {
                    Slog.w(TAG, "Permission group " + pg.info.name + " from package "
                            + pg.info.packageName + " ignored: original from "
                            + cur.info.packageName);
                    if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                        if (r == null) {
                            r = new StringBuilder(256);
                        } else {
                            r.append(' ');
                        }
                        r.append("DUP:");
                        r.append(pg.info.name);
                    }
                }
            }
         ......

        return pkg;
    }


好了现在已经安装完成了,上面的代码,我们已经知道,安装分为三个阶段:

  1. 安装前的准备工作
  2. 安装工作
  3. doPostInstall 安装完成后的工作
int doPostInstall(int status, int uid) {
            if (status != PackageManager.INSTALL_SUCCEEDED) {
                // 主要清除之前创建的临时文件夹
                cleanUp();
            } else {
                final int groupOwner;
                final String protectedFile;
                if (isFwdLocked()) {
                    groupOwner = UserHandle.getSharedAppGid(uid);
                    protectedFile = RES_FILE_NAME;
                } else {
                    groupOwner = -1;
                    protectedFile = null;
                }

                if (uid < Process.FIRST_APPLICATION_UID
                        || !PackageHelper.fixSdPermissions(cid, groupOwner, protectedFile)) {
                    Slog.e(TAG, "Failed to finalize " + cid);
                    PackageHelper.destroySdDir(cid);
                    return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
                }

                boolean mounted = PackageHelper.isContainerMounted(cid);
                if (!mounted) {
                    PackageHelper.mountSdDir(cid, getEncryptKey(), Process.myUid());
                }
            }
            return status;
}


可以看到在doPostInstall方法中,主要清除之前创建的临时文件夹


到现在,安装完成并且删除临时目录,发送”POST_INSTALL”消息,交给PackageHandler处理

case POST_INSTALL: {
        .......

        if (data != null) {
            InstallArgs args = data.args;
            PackageInstalledInfo res = data.res;

            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                .....
                // 安装完成之后发送"ACTION_PACKAGE_ADDED"广播
                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                        packageName, extras, null, null, firstUsers);
                final boolean update = res.removedInfo.removedPackage != null;
                if (update) {
                    extras.putBoolean(Intent.EXTRA_REPLACING, true);
                }
                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                        packageName, extras, null, null, updateUsers);
                // 如果当前应用已经安装,发送"ACTION_PACKAGE_REPLACED"广播
                if (update) {
                    sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                            packageName, extras, null, null, updateUsers);
                    sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                            null, null, packageName, null, updateUsers);

                    // treat asec-hosted packages like removable media on upgrade
                    if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
                        if (DEBUG_INSTALL) {
                            Slog.i(TAG, "upgrading pkg " + res.pkg
                                    + " is ASEC-hosted -> AVAILABLE");
                        }
                        int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
                        ArrayList<String> pkgList = new ArrayList<String>(1);
                        pkgList.add(packageName);
                        sendResourcesChangedBroadcast(true, true,
                                pkgList,uidArray, null);
                    }
                }
                if (res.removedInfo.args != null) {
                    // Remove the replaced package's older resources safely now
                    deleteOld = true;
                }

            }
            // Force a gc to clear up things
            Runtime.getRuntime().gc();
            // We delete after a gc for applications  on sdcard.
            if (deleteOld) {
                synchronized (mInstallLock) {
                    res.removedInfo.args.doPostDeleteLI(true);
                }
            }
            if (args.observer != null) {
                try {
                    Bundle extras = extrasForInstallResult(res);
                    // 回调onPackageInstalled方法
                    args.observer.onPackageInstalled(res.name, res.returnCode,
                            res.returnMsg, extras);
                } catch (RemoteException e) {
                    Slog.i(TAG, "Observer no longer exists.");
                }
            }
        } else {
            Slog.e(TAG, "Bogus post-install token " + msg.arg1);
        }
    }

好了,关于apk的安装的大致流程就到这里了。下面画一张图来总结一下,如有遗漏或者不对的地方,欢迎指教。

这里写图片描述


欢 迎 关 注 我 的 公 众 号 “编 程 大 全”


专注技术分享,包括Java,python,AI人工智能,Android分享,不定期更新学习视频


在这里插入图片描述



版权声明:本文为mockingbirds原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。