Apk安装流程-基于Android API31

apk的安装有多种方式(系统、adb、应用商店、第三方)。这里我们取用路径最长的一种安装方式(第三方安装)进行分析,先上一个整个流程的时序图。


时序图

注意本文是关于整个安装流程的详细调用链,文章较长涉及代码较多,适合源码探索,androidstudio导入系统源码
,需要可自取

第三方安装调用
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_VIEW);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setDataAndType(uri, "application/vnd.android.package-archive");
            context.startActivity(intent);

这里就不用去区分7.0之前和之后,uri都代表了文件地址

安装器AndroidManifest

路径:frameworks/base/packages/PackageInstaller/AndroidManifest.xml
这里将安装过程要用到的所有组件都列出来

 <application >
        //意图接收页面
        <activity android:name=".InstallStart"
                android:theme="@android:style/Theme.Translucent.NoTitleBar"
                android:exported="true"
                android:excludeFromRecents="true">
            <intent-filter android:priority="1">
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.INSTALL_PACKAGE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="content" />
                <data android:mimeType="application/vnd.android.package-archive" />
            </intent-filter>
            <intent-filter android:priority="1">
                <action android:name="android.intent.action.INSTALL_PACKAGE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="package" />
                <data android:scheme="content" />
            </intent-filter>
            <intent-filter android:priority="1">
                <action android:name="android.content.pm.action.CONFIRM_INSTALL" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        //中转页面,目的是将不同形式的文件路径,转为系统temp目录下等待安装
        <activity android:name=".InstallStaging"
                android:exported="false" />
        //中转页面,安装成功后删除上面temp目录下的安装包
        <activity android:name=".DeleteStagedFileOnResult"
            android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
            android:exported="false" />
        //包信息展示页面,有icon、应用名称、安装/取消按钮的那个页面
        <activity android:name=".PackageInstallerActivity"
                android:exported="false" />
        //安装进程中页面
        <activity android:name=".InstallInstalling"
                android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
                android:exported="false" />
        //安装session结果接受广播
        <receiver android:name=".InstallEventReceiver"
                android:permission="android.permission.INSTALL_PACKAGES"
                android:exported="false">
            <intent-filter android:priority="1">
                <action android:name="com.android.packageinstaller.ACTION_INSTALL_COMMIT" />
            </intent-filter>
        </receiver>
        //安装成功状态展示页面
        <activity android:name=".InstallSuccess"
                android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
                android:exported="false" />
        //安装失败状态展示页面
        <activity android:name=".InstallFailed"
                android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
                android:exported="false" />
...
    </application>
InstallStart

路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStart.java
根据意图跳转至InstallStart

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        //是否是session安装
        final boolean isSessionInstall =
                PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());

        ....
        Intent nextActivity = new Intent(intent);
        nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
                | Intent.FLAG_GRANT_READ_URI_PERMISSION);

        // The the installation source as the nextActivity thinks this activity is the source, hence
        // set the originating UID and sourceInfo explicitly
        nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_PACKAGE, callingPackage);
        nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_ATTRIBUTION_TAG,
                callingAttributionTag);
        nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
        nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);
        //根据前面获取到的状态,跳转不同的页面
        if (isSessionInstall) {
            nextActivity.setClass(this, PackageInstallerActivity.class);
        } else {
            Uri packageUri = intent.getData();

            if (packageUri != null && packageUri.getScheme().equals(
                    ContentResolver.SCHEME_CONTENT)) {
                // 更注册的意图,可知第三方安装满足这个条件
                nextActivity.setClass(this, InstallStaging.class);
            } else if (packageUri != null && packageUri.getScheme().equals(
                    PackageInstallerActivity.SCHEME_PACKAGE)) {
                nextActivity.setClass(this, PackageInstallerActivity.class);
            } else {
                Intent result = new Intent();
                result.putExtra(Intent.EXTRA_INSTALL_RESULT,
                        PackageManager.INSTALL_FAILED_INVALID_URI);
                setResult(RESULT_FIRST_USER, result);

                nextActivity = null;
            }
        }

        if (nextActivity != null) {
            startActivity(nextActivity);
        }
        finish();
    }
InstallStaging

路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStaging.java
中转页面,将意图中提供的uri文件,拷贝至目录(/data/user/0/com.android.packageinstaller/no_backup/packagexxx.apk)下

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         //设置取消按钮
        mAlert.setIcon(R.drawable.ic_file_download);
        mAlert.setTitle(getString(R.string.app_name_unknown));
        mAlert.setView(R.layout.install_content_view);
        mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
                (ignored, ignored2) -> {
                    if (mStagingTask != null) {
                        mStagingTask.cancel(true);
                    }
                    setResult(RESULT_CANCELED);
                    finish();
                }, null);
        setupAlert();
        requireViewById(R.id.staging).setVisibility(View.VISIBLE);

        if (savedInstanceState != null) {
            mStagedFile = new File(savedInstanceState.getString(STAGED_FILE));

            if (!mStagedFile.exists()) {
                mStagedFile = null;
            }
        }
    }
    
    //文件存在,异步拷贝
    protected void onResume() {
        super.onResume();

        // This is the first onResume in a single life of the activity
        if (mStagingTask == null) {
            // File does not exist, or became invalid
            if (mStagedFile == null) {
                // Create file delayed to be able to show error
                try {
                    mStagedFile = TemporaryFileManager.getStagedFile(this);
                } catch (IOException e) {
                    showError();
                    return;
                }
            }

            mStagingTask = new StagingAsyncTask();
            mStagingTask.execute(getIntent().getData());
        }
    }

private final class StagingAsyncTask extends AsyncTask<Uri, Void, Boolean> {
        @Override
        protected Boolean doInBackground(Uri... params) {
            if (params == null || params.length <= 0) {
                return false;
            }
            //apk包拷贝至/data/user/0/com.android.packageinstaller/no_backup/packagexxx.apk
            Uri packageUri = params[0];
            try (InputStream in = getContentResolver().openInputStream(packageUri)) {
                // Despite the comments in ContentResolver#openInputStream the returned stream can
                // be null.
                if (in == null) {
                    return false;
                }

                try (OutputStream out = new FileOutputStream(mStagedFile)) {
                    byte[] buffer = new byte[1024 * 1024];
                    int bytesRead;
                    while ((bytesRead = in.read(buffer)) >= 0) {
                        // Be nice and respond to a cancellation
                        if (isCancelled()) {
                            return false;
                        }
                        out.write(buffer, 0, bytesRead);
                    }
                }
            } catch (IOException | SecurityException | IllegalStateException e) {
                Log.w(LOG_TAG, "Error staging apk from content URI", e);
                return false;
            }
            return true;
        }

        @Override
        protected void onPostExecute(Boolean success) {
                // Now start the installation again from a file
                Intent installIntent = new Intent(getIntent());
                installIntent.setClass(InstallStaging.this, DeleteStagedFileOnResult.class);
                installIntent.setData(Uri.fromFile(mStagedFile));
                ...
                //拷贝完成,跳转至删除中转Activity
                startActivity(installIntent);

                InstallStaging.this.finish();
        }
    }
DeleteStagedFileOnResult

路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\DeleteStagedFileOnResult.java
删除中转页面,安装成功后删除上面拷贝的安装包

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

        if (savedInstanceState == null) {
            Intent installIntent = new Intent(getIntent());
            installIntent.setClass(this, PackageInstallerActivity.class);
    
            installIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
            //跳转至应用安装详情页面
            startActivityForResult(installIntent, 0);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        setResult(resultCode, data);
        finish();
    }

     //安装流程结束,同时也删除中转的包
    @Override
    protected void onDestroy() {
        super.onDestroy();
         //删除安装包
        if (isFinishing()) {
            File sourceFile = new File(getIntent().getData().getPath());
            new Thread(sourceFile::delete).start();
        }
    }
PackageInstallerActivity

路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\PackageInstallerActivity.java
安装确认界面,也是应用宝信息展示页面,也是厂商广告展示页面☺

      protected void onCreate(Bundle icicle) {
         ...
        //解析url,获取应用信息
        boolean wasSetUp = processPackageUri(packageUri);
        ...
      }

      protected void onResume() {
        super.onResume();

        if (mLocalLOGV) Log.i(TAG, "onResume(): mAppSnippet=" + mAppSnippet);

        if (mAppSnippet != null) {
            //用获取的应用信息,填充页面(icon,名称,版本,权限等)
            bindUi();
            //检查发起程序是否有第三方应用安装权限
            checkIfAllowedAndInitiateInstall();
        }

        if (mOk != null) {
            //还不允许点击安装按钮
            mOk.setEnabled(mEnableOk);
        }
    }

    private void bindUi() {
         ...
        mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
                (ignored, ignored2) -> {
                    if (mOk.isEnabled()) {
                        if (mSessionId != -1) {
                            mInstaller.setPermissionsResult(mSessionId, true);
                            finish();
                        } else {
                            //点击安装按钮
                            startInstall();
                        }
                    }
                }, null);
        ...
        mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
        mOk.setEnabled(false);
        ...
    }

    private void startInstall() {
        Intent newIntent = new Intent();
        newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
                mPkgInfo.applicationInfo);
        newIntent.setData(mPackageURI);
        newIntent.setClass(this, InstallInstalling.class);
        ...
        //点击安装按钮后,跳转至正在安装页面
        startActivity(newIntent);
        finish();
    }

checkIfAllowedAndInitiateInstall:方法会去检查发起安装的应用,是否有第三方安装权限,没有就弹出请求弹窗,然后跳转至设置界面。根据授权结果,在onActivityResult更改安装按钮状态

InstallInstalling

路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallInstalling.java
安装中页面,在onCreate中初始化loading动画和取消按钮

    protected void onCreate(@Nullable Bundle savedInstanceState) {
           ...
           //在安装结束的广播中添加监听,launchFinishBasedOnResult中根据状态码跳转成功/失败页面
           mInstallId = InstallEventReceiver.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
                                    this::launchFinishBasedOnResult);
           ...
          //创建Session
          mSessionId = getPackageManager().getPackageInstaller().createSession(params);
           ...
    }

    protected void onResume() {
        super.onResume();
        if (mInstallingTask == null) {
            PackageInstaller installer = getPackageManager().getPackageInstaller();
            //取出Seesion
            PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
            //判断Session活跃状态
            if (sessionInfo != null && !sessionInfo.isActive()) {
                //未开始安装,进行下一步安装
                mInstallingTask = new InstallingAsyncTask();
                mInstallingTask.execute();
            } else {
                //正在安装,等待安装完成
                mCancelButton.setEnabled(false);
                setFinishOnTouchOutside(false);
            }
        }
    }

    private final class InstallingAsyncTask extends AsyncTask<Void, Void,
            PackageInstaller.Session> {
        volatile boolean isDone;

        @Override
        protected PackageInstaller.Session doInBackground(Void... params) {
            PackageInstaller.Session session;
            try {
                //打开Session
                session = getPackageManager().getPackageInstaller().openSession(mSessionId);
            } catch (IOException e) {
                synchronized (this) {
                    isDone = true;
                    notifyAll();
                }
                return null;
            }
           //设置写入进度
            session.setStagingProgress(0);

            try {
                File file = new File(mPackageURI.getPath());

                try (InputStream in = new FileInputStream(file)) {
                    long sizeBytes = file.length();
                    //设置文件大小,优化写入磁盘操作
                    try (OutputStream out = session
                            .openWrite("PackageInstaller", 0, sizeBytes)) {
                        byte[] buffer = new byte[1024 * 1024];
                        while (true) {
                            int numRead = in.read(buffer);

                            if (numRead == -1) {
                                //更新到磁盘
                                session.fsync(out);
                                break;
                            }

                            if (isCancelled()) {
                                session.close();
                                break;
                            }
                            //写入数据
                            out.write(buffer, 0, numRead);
                            if (sizeBytes > 0) {
                                float fraction = ((float) numRead / (float) sizeBytes);
                                //设置进度
                                session.addProgress(fraction);
                            }
                        }
                    }
                }

                return session;
            } catch (IOException | SecurityException e) {
                Log.e(LOG_TAG, "Could not write package", e);

                session.close();

                return null;
            } finally {
                synchronized (this) {
                    isDone = true;
                    notifyAll();
                }
            }
        }

        @Override
        protected void onPostExecute(PackageInstaller.Session session) {
            if (session != null) {
                //BROADCAST_ACTION的值为:com.android.packageinstaller.ACTION_INSTALL_COMMIT
                Intent broadcastIntent = new Intent(BROADCAST_ACTION);
                broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                broadcastIntent.setPackage(getPackageName());
                broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);

                PendingIntent pendingIntent = PendingIntent.getBroadcast(
                        InstallInstalling.this,
                        mInstallId,
                        broadcastIntent,
                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
                //Session提交IntentSender,用于完成后发送完成的广播
                session.commit(pendingIntent.getIntentSender());
                //取消按钮设置为不可点击
                mCancelButton.setEnabled(false);
                setFinishOnTouchOutside(false);
            } else {
                getPackageManager().getPackageInstaller().abandonSession(mSessionId);

                if (!isCancelled()) {
                    launchFailure(PackageInstaller.STATUS_FAILURE,
                            PackageManager.INSTALL_FAILED_INVALID_APK, null);
                }
            }
        }
    }
  • 给安装结束的广播中添加监听
  • 创建Session
  • 通过Session将安装包写入磁盘
  • Session提交具有发送安装结束功能的IntentSender
PackageInstallerSession

路径:frameworks\base\services\core\java\com\android\server\pm\PackageInstallerSession.java
PackageInstaller.Session.commit方法最终远程调用到了PackageInstallerSession.commit方法

 @Override
    public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
        if (hasParentSessionId()) {
            throw new IllegalStateException(
                    "Session " + sessionId + " is a child of multi-package session "
                            + getParentSessionId() +  " and may not be committed directly.");
        }
        //标识请求,同时记录statusReceiver,用于发送安装结果
        if (!markAsSealed(statusReceiver, forTransfer)) {
            return;
        }
        if (isMultiPackage()) {
           //多包安装
        }

        dispatchSessionSealed();
    }

    private void dispatchSessionSealed() {
        mHandler.obtainMessage(MSG_ON_SESSION_SEALED).sendToTarget();
    }

 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_ON_SESSION_SEALED:
                    handleSessionSealed();
                    break;
                case MSG_STREAM_VALIDATE_AND_COMMIT:
                    handleStreamValidateAndCommit();
                    break;
                case MSG_INSTALL:
                    handleInstall();
                    break;
        }
    }

    private void handleSessionSealed() {
        ...
        dispatchStreamValidateAndCommit();
    }

    private void dispatchStreamValidateAndCommit() {
        mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
    }

     private void handleStreamValidateAndCommit() {
        ...
        mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
    }

    private void handleInstall() {
         //apex安装这种大多数用于系统安装
        if (isApexSession()) {
         ...
        }
        //分阶段安装,一般需要重启后会进行后面的安装步骤
        if (params.isStaged) {
      
        }

        verify();
    }


    private void verify() {
        verifyNonStaged();
    }

private void verifyNonStaged()
            throws PackageManagerException {
        //创建验证参数
        final PackageManagerService.VerificationParams verifyingSession =
                prepareForVerification();
         ...
        mPm.verifyStage(verifyingSession);
    }

    private PackageManagerService.VerificationParams prepareForVerification()
            throws PackageManagerException {
        ....
        synchronized (mLock) {
            return makeVerificationParamsLocked();
        }
    }

    private PackageManagerService.VerificationParams makeVerificationParamsLocked() {
        final IPackageInstallObserver2 localObserver;
        if (!hasParentSessionId()) {
            //添加验证回调
            localObserver = new IPackageInstallObserver2.Stub() {
                @Override
                public void onUserActionRequired(Intent intent) {
                    throw new IllegalStateException();
                }

                @Override
                public void onPackageInstalled(String basePackageName, int returnCode, String msg,
                        Bundle extras) {
                    if (returnCode == INSTALL_SUCCEEDED) {
                        onVerificationComplete();
                    } else {
                        onSessionVerificationFailure(returnCode, msg);
                    }
                }
            };
        ...
        return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams,
                mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite);
    }
  1. 记录提交过来的IntentSender用于后面发送广播
  2. 创建验证回调,并在创建验证参数是传入
PackageManagerService

路径:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java
调用了pms的verifyStage方法

    void verifyStage(VerificationParams params) {
        mHandler.post(()-> {
            params.startCopy();
        });
    }
VerificationParams

路径:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService$VerificationParams.java
调用的是VerificationParams对象的startCopy()方法,VerificationParams对象继承了HandlerParams,并未重写startCopy()方法

        final void startCopy() {
            handleStartCopy();
            handleReturnCode();
        }

       public void handleStartCopy() {
            //获取包信息
            PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                    mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
            //验证versioncode是否合法(降级等)
            mRet = verifyReplacingVersionCode(pkgLite, requiredInstalledVersionCode, installFlags);
            if (mRet != INSTALL_SUCCEEDED) {
                return;
            }
            ...
        }

        void handleReturnCode() {
            if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete
                    || mWaitForEnableRollbackToComplete) {
                return;
            }
            sendVerificationCompleteNotification();
        }

        private void sendVerificationCompleteNotification() {
            //调用前面设置的回调
            observer.onPackageInstalled(null, mRet, "Package Verification Result",
                            new Bundle());
        }
PackageInstallerSession

验证回调中调用onVerificationComplete()方法

    private void onVerificationComplete() {
        ...
        install();
    }

    private void install() {
            installNonStaged();
    }

    private void installNonStaged()
            throws PackageManagerException {
        //创建安装参数
        final PackageManagerService.InstallParams installingSession = makeInstallParams();
        ...
        //开始安装
        mPm.installStage(installingSession);
    }

private PackageManagerService.InstallParams makeInstallParams()
            throws PackageManagerException {
        //创建安装监听
        final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
            @Override
            public void onUserActionRequired(Intent intent) {
                throw new IllegalStateException();
            }

            @Override
            public void onPackageInstalled(String basePackageName, int returnCode, String msg,
                    Bundle extras) {
                if (isStaged()) {
                    sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);
                } else {
                    //不是分段安装,安装成功后会回调这里
                    destroyInternal();
                    dispatchSessionFinished(returnCode, msg, extras);
                }
            }
        };
        .....
        synchronized (mLock) {
            return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
                    mSigningDetails, mInstallerUid, mPackageLite);
        }
    }

调用makeInstallParams方法创建安装参数,并添加IPackageInstallObserver2监听
当安装成功后会调用onPackageInstalled方法,returnCode为安装状态码。后面会分析dispatchSessionFinished方法。

PackageManagerService
    void installStage(InstallParams params) {
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        ...
        mHandler.sendMessage(msg);
    }

    class PackageHandler extends Handler {
        ...
        public void handleMessage(Message msg) {
            try {
                doHandleMessage(msg);
            } finally {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            }
        }

        void doHandleMessage(Message msg) {
            switch (msg.what) {
                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
                    if (params != null) {
                        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                System.identityHashCode(params));
                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                        执行InstallParams.startCopy()方法
                        params.startCopy();
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                    break;
                 }
                case POST_INSTALL: {
                    ...
                        //安装成功后发送消息
                        handlePackagePostInstall(parentRes, killApp, virtualPreload,
                                didRestore, args.installSource.installerPackageName, args.observer,
                                args.mDataLoaderType);
                    ...
                } break;

            }
      }
InstallParams

路径:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService$InstallParams.java
InstallParams类真正执行了将apk安装到系统的操作

        final void startCopy() {
            handleStartCopy();
            handleReturnCode();
        }

        public void handleStartCopy() {
            if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
                mRet = INSTALL_SUCCEEDED;
                return;
            }
            PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                    mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
            ...
            boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
            //这里是分段安装的再次验证,第三方安装流程不会走这里
            if (isStaged) {
                mRet = verifyReplacingVersionCode(
                        pkgLite, requiredInstalledVersionCode, installFlags);
                if (mRet != INSTALL_SUCCEEDED) {
                    return;
                }
            }
            //获取覆盖安装的位置
            mRet = overrideInstallLocation(pkgLite);
        }

        void handleReturnCode() {
            processPendingInstall();
        }

private void processPendingInstall() {
            InstallArgs args = createInstallArgs(this);
            if (mRet == PackageManager.INSTALL_SUCCEEDED) {
                //拷贝安装包和动态链接库
                mRet = args.copyApk();
            }
            if (mRet == PackageManager.INSTALL_SUCCEEDED) {
                //释放资源占用的空间
                F2fsUtils.releaseCompressedBlocks(
                        mContext.getContentResolver(), new File(args.getCodePath()));
            }
            if (mParentInstallParams != null) {
                mParentInstallParams.tryProcessInstallRequest(args, mRet);
            } else {
                PackageInstalledInfo res = createPackageInstalledInfo(mRet);
                //异步执行解析、系统配置写入等操作
                processInstallRequestsAsync(
                        res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                        Collections.singletonList(new InstallRequest(args, res)));
            }
        }

 private void processInstallRequestsAsync(boolean success,
            List<InstallRequest> installRequests) {
            ...
            if (success) {
                for (InstallRequest request : apkInstallRequests) {
                    //清理安装目录,因为安装失败等原因,造成的无用文件,在这一步清理
                    request.args.doPreInstall(request.installResult.returnCode);
                }
                synchronized (mInstallLock) {
                    //解析包、验证包、提交到系统
                    installPackagesTracedLI(apkInstallRequests);
                }
                for (InstallRequest request : apkInstallRequests) {
                    //清理安装过程造成的无用文件,和doPreInstall作用是一样的
                    request.args.doPostInstall(
                            request.installResult.returnCode, request.installResult.uid);
                }
            }
            for (InstallRequest request : apkInstallRequests) {
                //发送广播,通知系统更换或者添加icon、通知安装应用、通知监听安装事件的其他广播等
               //如果安装失败进行回滚
                restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                        new PostInstallData(request.args, request.installResult, null));
            }
        });

    private void installPackagesTracedLI(List<InstallRequest> requests) {
       installPackagesLI(requests);
    }

  private void installPackagesLI(List<InstallRequest> requests) {
        final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
        final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
        final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
        final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
        final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
        final Map<String, PackageSetting> lastStaticSharedLibSettings =
                new ArrayMap<>(requests.size());
        final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
        boolean success = false;
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
            for (InstallRequest request : requests) {
                    ...
                    //1.准备:分析当前安装状态,解析包并初始验证
                    prepareResult =
                            preparePackageLI(request.args, request.installResult);
                   ...
                   //2.扫描:根据准备阶段解析的包信息上下文 进一步解析
                    final ScanResult result = scanPackageTracedLI(
                            prepareResult.packageToScan, prepareResult.parseFlags,
                            prepareResult.scanFlags, System.currentTimeMillis(),
                            request.args.user, request.args.abiOverride);
                    //注册appId
                    createdAppId.put(packageName, optimisticallyRegisterAppId(result));
                    //保存version信息
                    versionInfos.put(result.pkgSetting.pkg.getPackageName(),
                            getSettingsVersionForPackage(result.pkgSetting.pkg));
                    ..
                    //3.核对:验证扫描后的包信息和系统状态,确保安装成功
                    reconciledPackages = reconcilePackagesLocked(
                            reconcileRequest, mSettings.getKeySetManagerService(), mInjector);

                  ...
                  //4.提交:提交扫描的包、更新系统状态。这是唯一可以修改系统状态的地方,并且要对所有可预测的错误进行检测。
                    commitRequest = new CommitRequest(reconciledPackages,
                            mUserManager.getUserIds());
                    commitPackagesLocked(commitRequest);
                    //安装后续,准备App数据、编译布局资源、执行dexopt
                    executePostCommitSteps(commitRequest);
         }
    }

    private void executePostCommitSteps(CommitRequest commitRequest) {
        final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
        for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
             ... 
            //准备app目录(/data/user/用户ID/包名/code_cache)
            prepareAppDataAfterInstallLIF(pkg);
             ... 
            //准备应用配置文件
            mArtManagerService.prepareAppProfiles(
                    pkg,
                    resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
                    /* updateReferenceProfileContent= */ true);
            ...
           //dexopt操作
            mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
                        null /* instructionSets */,
                        getOrCreateCompilerPackageStats(pkg),
                        mDexManager.getPackageUseInfoOrDefault(packageName),
                        dexoptOptions);
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        ...
        }
    }

将包拷贝到data/app目录下后执行了4个关键的操作:

  1. 准备:分析当前安装状态,解析包并初始验证
    • 对apk的AndroidManifest.xml文件做了全面的解析,比如apk中的所有
    • activityservicepermission等信息,并将解析结果保存在了PackageParser.Package类里
    • 通过Dm-verity校验dex文件的有效性
    • 解析apk签名信息
    • 解析android资源索引表resources.arsc文件。
  2. 扫描:根据准备阶段解析的包信息上下文 进一步解析
  3. 核对:验证扫描后的包信息和系统状态,确保安装成功
  4. 提交:提交扫描的包、更新系统状态。这是唯一可以修改系统状态的地方,并且要对所有可预测的错误进行检测。

安装完成后,会进行后续的步骤:

  1. 准备App data目录,如果已经存在则对目录进行校验
  2. 准备应用配置文件
  3. 对dex进行dexopt操作

下图附一张不同版本dexopt区别


dexopt版本区别

返回到上面的processInstallRequestsAsync()方法中,进行安装完成后的后续处理restoreAndPostInstall方法

PackageManagerService
    private void restoreAndPostInstall(
            int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
        if (DEBUG_INSTALL) {
            Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.pkg);
        }

        //是否更新标识
        final boolean update = res.removedInfo != null
                && res.removedInfo.removedPackage != null;
        //是否回滚
        boolean doRestore = !update && res.pkg != null;
        ...
        //安装成功,并且需要回滚
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
            if (res.freezer != null) {
                res.freezer.close();
            }
            doRestore = performBackupManagerRestore(userId, token, res);
        }

        //更新应用,做数据回滚
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
            doRestore = performRollbackManagerRestore(userId, token, res, data);
        }
        //不回滚发送消息进行后面的操作
        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);

            Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
            //这个消息最终会调用handlePackagePostInstall方法
            Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
            mHandler.sendMessage(msg);
        }
    }

    private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
            boolean virtualPreload, boolean launchedForRestore, String installerPackage,
            IPackageInstallObserver2 installObserver, int dataLoaderType) {
          ...
          //发送消息更新桌面icon
          sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, 0 /*flags*/,
                        null /*targetPackage*/, null /*finishedReceiver*/,
                        updateUserIds, instantUserIds, newBroadcastAllowList, null);
        //通知上面InstallParams对象中注册的监听对象
        notifyInstallObserver(res, installObserver);
}
PackageInstallerSession
    private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
        sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);
        ...
    }

    private void sendUpdateToRemoteStatusReceiver(int returnCode, String msg, Bundle extras) {
       ...
       //最终调用了sendOnPackageInstalled方法
       mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
    }

    private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId,
            boolean showNotification, int userId, String basePackageName, int returnCode,
            String msg, Bundle extras) {
       ...
       //target对象为commit提交的IntentSender对象。
       target.sendIntent(context, 0, fillIn, null, null);
    }

使用IntentSender对象发送action(com.android.packageinstaller.ACTION_INSTALL_COMMIT)广播,根据上面AndroidManifest.xml中注册的BroadcastReceiver,最终InstallEventReceiver会收到广播

PackageInstallerSession

路径:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallEventReceiver.java

public class InstallEventReceiver extends BroadcastReceiver {
    ...
    @Override
    public void onReceive(Context context, Intent intent) {
        getReceiver(context).onEventReceived(context, intent);
    }
    ...
}

InstallEventReceiveronReceive中执行了EventResultPersister.onEventReceivedf方法,最终回调InstallInstalling.launchFinishBasedOnResult方法,launchFinishBasedOnResult方法又根据安装状态码展示成功或者失败页面。

!!!!OVER!!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容