Apk安裝流程-基于Android API31

apk的安裝有多種方式(系統(tǒng)、adb、應(yīng)用商店、第三方)。這里我們?nèi)∮寐窂阶铋L(zhǎng)的一種安裝方式(第三方安裝)進(jìn)行分析,先上一個(gè)整個(gè)流程的時(shí)序圖。


時(shí)序圖

注意本文是關(guān)于整個(gè)安裝流程的詳細(xì)調(diào)用鏈,文章較長(zhǎng)涉及代碼較多,適合源碼探索,androidstudio導(dǎo)入系統(tǒng)源碼
,需要可自取

第三方安裝調(diào)用
            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);

這里就不用去區(qū)分7.0之前和之后,uri都代表了文件地址

安裝器AndroidManifest

路徑:frameworks/base/packages/PackageInstaller/AndroidManifest.xml
這里將安裝過(guò)程要用到的所有組件都列出來(lái)

 <application >
        //意圖接收頁(yè)面
        <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>
        //中轉(zhuǎn)頁(yè)面,目的是將不同形式的文件路徑,轉(zhuǎn)為系統(tǒng)temp目錄下等待安裝
        <activity android:name=".InstallStaging"
                android:exported="false" />
        //中轉(zhuǎn)頁(yè)面,安裝成功后刪除上面temp目錄下的安裝包
        <activity android:name=".DeleteStagedFileOnResult"
            android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
            android:exported="false" />
        //包信息展示頁(yè)面,有icon、應(yīng)用名稱、安裝/取消按鈕的那個(gè)頁(yè)面
        <activity android:name=".PackageInstallerActivity"
                android:exported="false" />
        //安裝進(jìn)程中頁(yè)面
        <activity android:name=".InstallInstalling"
                android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
                android:exported="false" />
        //安裝session結(jié)果接受廣播
        <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>
        //安裝成功狀態(tài)展示頁(yè)面
        <activity android:name=".InstallSuccess"
                android:theme="@style/Theme.AlertDialogActivity.NoAnimation"
                android:exported="false" />
        //安裝失敗狀態(tài)展示頁(yè)面
        <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
根據(jù)意圖跳轉(zhuǎn)至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);
        //根據(jù)前面獲取到的狀態(tài),跳轉(zhuǎn)不同的頁(yè)面
        if (isSessionInstall) {
            nextActivity.setClass(this, PackageInstallerActivity.class);
        } else {
            Uri packageUri = intent.getData();

            if (packageUri != null && packageUri.getScheme().equals(
                    ContentResolver.SCHEME_CONTENT)) {
                // 更注冊(cè)的意圖,可知第三方安裝滿足這個(gè)條件
                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
中轉(zhuǎn)頁(yè)面,將意圖中提供的uri文件,拷貝至目錄(/data/user/0/com.android.packageinstaller/no_backup/packagexxx.apk)下

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         //設(shè)置取消按鈕
        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));
                ...
                //拷貝完成,跳轉(zhuǎn)至刪除中轉(zhuǎn)Activity
                startActivity(installIntent);

                InstallStaging.this.finish();
        }
    }
DeleteStagedFileOnResult

路徑:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\DeleteStagedFileOnResult.java
刪除中轉(zhuǎn)頁(yè)面,安裝成功后刪除上面拷貝的安裝包

    @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);
            //跳轉(zhuǎn)至應(yīng)用安裝詳情頁(yè)面
            startActivityForResult(installIntent, 0);
        }
    }

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

     //安裝流程結(jié)束,同時(shí)也刪除中轉(zhuǎn)的包
    @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
安裝確認(rèn)界面,也是應(yīng)用寶信息展示頁(yè)面,也是廠商廣告展示頁(yè)面?

      protected void onCreate(Bundle icicle) {
         ...
        //解析url,獲取應(yīng)用信息
        boolean wasSetUp = processPackageUri(packageUri);
        ...
      }

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

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

        if (mAppSnippet != null) {
            //用獲取的應(yīng)用信息,填充頁(yè)面(icon,名稱,版本,權(quán)限等)
            bindUi();
            //檢查發(fā)起程序是否有第三方應(yīng)用安裝權(quán)限
            checkIfAllowedAndInitiateInstall();
        }

        if (mOk != null) {
            //還不允許點(diǎn)擊安裝按鈕
            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 {
                            //點(diǎn)擊安裝按鈕
                            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);
        ...
        //點(diǎn)擊安裝按鈕后,跳轉(zhuǎn)至正在安裝頁(yè)面
        startActivity(newIntent);
        finish();
    }

checkIfAllowedAndInitiateInstall:方法會(huì)去檢查發(fā)起安裝的應(yīng)用,是否有第三方安裝權(quán)限,沒(méi)有就彈出請(qǐng)求彈窗,然后跳轉(zhuǎn)至設(shè)置界面。根據(jù)授權(quán)結(jié)果,在onActivityResult更改安裝按鈕狀態(tài)

InstallInstalling

路徑:frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallInstalling.java
安裝中頁(yè)面,在onCreate中初始化loading動(dòng)畫(huà)和取消按鈕

    protected void onCreate(@Nullable Bundle savedInstanceState) {
           ...
           //在安裝結(jié)束的廣播中添加監(jiān)聽(tīng),launchFinishBasedOnResult中根據(jù)狀態(tài)碼跳轉(zhuǎn)成功/失敗頁(yè)面
           mInstallId = InstallEventReceiver.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
                                    this::launchFinishBasedOnResult);
           ...
          //創(chuàng)建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活躍狀態(tài)
            if (sessionInfo != null && !sessionInfo.isActive()) {
                //未開(kāi)始安裝,進(jìn)行下一步安裝
                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 {
                //打開(kāi)Session
                session = getPackageManager().getPackageInstaller().openSession(mSessionId);
            } catch (IOException e) {
                synchronized (this) {
                    isDone = true;
                    notifyAll();
                }
                return null;
            }
           //設(shè)置寫(xiě)入進(jìn)度
            session.setStagingProgress(0);

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

                try (InputStream in = new FileInputStream(file)) {
                    long sizeBytes = file.length();
                    //設(shè)置文件大小,優(yōu)化寫(xiě)入磁盤(pán)操作
                    try (OutputStream out = session
                            .openWrite("PackageInstaller", 0, sizeBytes)) {
                        byte[] buffer = new byte[1024 * 1024];
                        while (true) {
                            int numRead = in.read(buffer);

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

                            if (isCancelled()) {
                                session.close();
                                break;
                            }
                            //寫(xiě)入數(shù)據(jù)
                            out.write(buffer, 0, numRead);
                            if (sizeBytes > 0) {
                                float fraction = ((float) numRead / (float) sizeBytes);
                                //設(shè)置進(jìn)度
                                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,用于完成后發(fā)送完成的廣播
                session.commit(pendingIntent.getIntentSender());
                //取消按鈕設(shè)置為不可點(diǎn)擊
                mCancelButton.setEnabled(false);
                setFinishOnTouchOutside(false);
            } else {
                getPackageManager().getPackageInstaller().abandonSession(mSessionId);

                if (!isCancelled()) {
                    launchFailure(PackageInstaller.STATUS_FAILURE,
                            PackageManager.INSTALL_FAILED_INVALID_APK, null);
                }
            }
        }
    }
  • 給安裝結(jié)束的廣播中添加監(jiān)聽(tīng)
  • 創(chuàng)建Session
  • 通過(guò)Session將安裝包寫(xiě)入磁盤(pán)
  • Session提交具有發(fā)送安裝結(jié)束功能的IntentSender
PackageInstallerSession

路徑:frameworks\base\services\core\java\com\android\server\pm\PackageInstallerSession.java
PackageInstaller.Session.commit方法最終遠(yuǎn)程調(diào)用到了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.");
        }
        //標(biāo)識(shí)請(qǐng)求,同時(shí)記錄statusReceiver,用于發(fā)送安裝結(jié)果
        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安裝這種大多數(shù)用于系統(tǒng)安裝
        if (isApexSession()) {
         ...
        }
        //分階段安裝,一般需要重啟后會(huì)進(jìn)行后面的安裝步驟
        if (params.isStaged) {
      
        }

        verify();
    }


    private void verify() {
        verifyNonStaged();
    }

private void verifyNonStaged()
            throws PackageManagerException {
        //創(chuàng)建驗(yàn)證參數(shù)
        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()) {
            //添加驗(yàn)證回調(diào)
            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. 記錄提交過(guò)來(lái)的IntentSender用于后面發(fā)送廣播
  2. 創(chuàng)建驗(yàn)證回調(diào),并在創(chuàng)建驗(yàn)證參數(shù)是傳入
PackageManagerService

路徑:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java
調(diào)用了pms的verifyStage方法

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

路徑:frameworks\base\services\core\java\com\android\server\pm\PackageManagerService$VerificationParams.java
調(diào)用的是VerificationParams對(duì)象的startCopy()方法,VerificationParams對(duì)象繼承了HandlerParams,并未重寫(xiě)startCopy()方法

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

       public void handleStartCopy() {
            //獲取包信息
            PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                    mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
            //驗(yàn)證versioncode是否合法(降級(jí)等)
            mRet = verifyReplacingVersionCode(pkgLite, requiredInstalledVersionCode, installFlags);
            if (mRet != INSTALL_SUCCEEDED) {
                return;
            }
            ...
        }

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

        private void sendVerificationCompleteNotification() {
            //調(diào)用前面設(shè)置的回調(diào)
            observer.onPackageInstalled(null, mRet, "Package Verification Result",
                            new Bundle());
        }
PackageInstallerSession

驗(yàn)證回調(diào)中調(diào)用onVerificationComplete()方法

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

    private void install() {
            installNonStaged();
    }

    private void installNonStaged()
            throws PackageManagerException {
        //創(chuàng)建安裝參數(shù)
        final PackageManagerService.InstallParams installingSession = makeInstallParams();
        ...
        //開(kāi)始安裝
        mPm.installStage(installingSession);
    }

private PackageManagerService.InstallParams makeInstallParams()
            throws PackageManagerException {
        //創(chuàng)建安裝監(jiān)聽(tīng)
        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 {
                    //不是分段安裝,安裝成功后會(huì)回調(diào)這里
                    destroyInternal();
                    dispatchSessionFinished(returnCode, msg, extras);
                }
            }
        };
        .....
        synchronized (mLock) {
            return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
                    mSigningDetails, mInstallerUid, mPackageLite);
        }
    }

調(diào)用makeInstallParams方法創(chuàng)建安裝參數(shù),并添加IPackageInstallObserver2監(jiān)聽(tīng)
當(dāng)安裝成功后會(huì)調(diào)用onPackageInstalled方法,returnCode為安裝狀態(tài)碼。后面會(huì)分析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");
                        執(zhí)行InstallParams.startCopy()方法
                        params.startCopy();
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                    break;
                 }
                case POST_INSTALL: {
                    ...
                        //安裝成功后發(fā)送消息
                        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類真正執(zhí)行了將apk安裝到系統(tǒng)的操作

        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;
            //這里是分段安裝的再次驗(yàn)證,第三方安裝流程不會(huì)走這里
            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) {
                //拷貝安裝包和動(dòng)態(tài)鏈接庫(kù)
                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);
                //異步執(zhí)行解析、系統(tǒng)配置寫(xiě)入等操作
                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) {
                    //清理安裝目錄,因?yàn)榘惭b失敗等原因,造成的無(wú)用文件,在這一步清理
                    request.args.doPreInstall(request.installResult.returnCode);
                }
                synchronized (mInstallLock) {
                    //解析包、驗(yàn)證包、提交到系統(tǒng)
                    installPackagesTracedLI(apkInstallRequests);
                }
                for (InstallRequest request : apkInstallRequests) {
                    //清理安裝過(guò)程造成的無(wú)用文件,和doPreInstall作用是一樣的
                    request.args.doPostInstall(
                            request.installResult.returnCode, request.installResult.uid);
                }
            }
            for (InstallRequest request : apkInstallRequests) {
                //發(fā)送廣播,通知系統(tǒng)更換或者添加icon、通知安裝應(yīng)用、通知監(jiān)聽(tīng)安裝事件的其他廣播等
               //如果安裝失敗進(jìn)行回滾
                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.準(zhǔn)備:分析當(dāng)前安裝狀態(tài),解析包并初始驗(yàn)證
                    prepareResult =
                            preparePackageLI(request.args, request.installResult);
                   ...
                   //2.掃描:根據(jù)準(zhǔn)備階段解析的包信息上下文 進(jìn)一步解析
                    final ScanResult result = scanPackageTracedLI(
                            prepareResult.packageToScan, prepareResult.parseFlags,
                            prepareResult.scanFlags, System.currentTimeMillis(),
                            request.args.user, request.args.abiOverride);
                    //注冊(cè)appId
                    createdAppId.put(packageName, optimisticallyRegisterAppId(result));
                    //保存version信息
                    versionInfos.put(result.pkgSetting.pkg.getPackageName(),
                            getSettingsVersionForPackage(result.pkgSetting.pkg));
                    ..
                    //3.核對(duì):驗(yàn)證掃描后的包信息和系統(tǒng)狀態(tài),確保安裝成功
                    reconciledPackages = reconcilePackagesLocked(
                            reconcileRequest, mSettings.getKeySetManagerService(), mInjector);

                  ...
                  //4.提交:提交掃描的包、更新系統(tǒng)狀態(tài)。這是唯一可以修改系統(tǒng)狀態(tài)的地方,并且要對(duì)所有可預(yù)測(cè)的錯(cuò)誤進(jìn)行檢測(cè)。
                    commitRequest = new CommitRequest(reconciledPackages,
                            mUserManager.getUserIds());
                    commitPackagesLocked(commitRequest);
                    //安裝后續(xù),準(zhǔn)備App數(shù)據(jù)、編譯布局資源、執(zhí)行dexopt
                    executePostCommitSteps(commitRequest);
         }
    }

    private void executePostCommitSteps(CommitRequest commitRequest) {
        final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
        for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
             ... 
            //準(zhǔn)備app目錄(/data/user/用戶ID/包名/code_cache)
            prepareAppDataAfterInstallLIF(pkg);
             ... 
            //準(zhǔn)備應(yīng)用配置文件
            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目錄下后執(zhí)行了4個(gè)關(guān)鍵的操作:

  1. 準(zhǔn)備:分析當(dāng)前安裝狀態(tài),解析包并初始驗(yàn)證
    • 對(duì)apk的AndroidManifest.xml文件做了全面的解析,比如apk中的所有
    • activityservice、permission等信息,并將解析結(jié)果保存在了PackageParser.Package類里
    • 通過(guò)Dm-verity校驗(yàn)dex文件的有效性
    • 解析apk簽名信息
    • 解析android資源索引表resources.arsc文件。
  2. 掃描:根據(jù)準(zhǔn)備階段解析的包信息上下文 進(jìn)一步解析
  3. 核對(duì):驗(yàn)證掃描后的包信息和系統(tǒng)狀態(tài),確保安裝成功
  4. 提交:提交掃描的包、更新系統(tǒng)狀態(tài)。這是唯一可以修改系統(tǒng)狀態(tài)的地方,并且要對(duì)所有可預(yù)測(cè)的錯(cuò)誤進(jìn)行檢測(cè)。

安裝完成后,會(huì)進(jìn)行后續(xù)的步驟:

  1. 準(zhǔn)備App data目錄,如果已經(jīng)存在則對(duì)目錄進(jìn)行校驗(yàn)
  2. 準(zhǔn)備應(yīng)用配置文件
  3. 對(duì)dex進(jìn)行dexopt操作

下圖附一張不同版本dexopt區(qū)別


dexopt版本區(qū)別

返回到上面的processInstallRequestsAsync()方法中,進(jìn)行安裝完成后的后續(xù)處理restoreAndPostInstall方法

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

        //是否更新標(biāo)識(shí)
        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);
        }

        //更新應(yīng)用,做數(shù)據(jù)回滾
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
            doRestore = performRollbackManagerRestore(userId, token, res, data);
        }
        //不回滾發(fā)送消息進(jìn)行后面的操作
        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);
            //這個(gè)消息最終會(huì)調(diào)用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) {
          ...
          //發(fā)送消息更新桌面icon
          sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, 0 /*flags*/,
                        null /*targetPackage*/, null /*finishedReceiver*/,
                        updateUserIds, instantUserIds, newBroadcastAllowList, null);
        //通知上面InstallParams對(duì)象中注冊(cè)的監(jiān)聽(tīng)對(duì)象
        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) {
       ...
       //最終調(diào)用了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對(duì)象為commit提交的IntentSender對(duì)象。
       target.sendIntent(context, 0, fillIn, null, null);
    }

使用IntentSender對(duì)象發(fā)送action(com.android.packageinstaller.ACTION_INSTALL_COMMIT)廣播,根據(jù)上面AndroidManifest.xml中注冊(cè)的BroadcastReceiver,最終InstallEventReceiver會(huì)收到廣播

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中執(zhí)行了EventResultPersister.onEventReceivedf方法,最終回調(diào)InstallInstalling.launchFinishBasedOnResult方法,launchFinishBasedOnResult方法又根據(jù)安裝狀態(tài)碼展示成功或者失敗頁(yè)面。

?。。?!OVER?。。?!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容