美文网首页Android Framework
Android 包管理机制---PackageInstaller

Android 包管理机制---PackageInstaller

作者: 我看Android | 来源:发表于2021-08-02 17:57 被阅读0次

    本文基于API 30即Android11源码解读

    前些日子做了一个电视机的应用市场APP,搞了一下Android的应用管理机制。撸篇文章记录一下。

    一、安装应用 PackageInstaller初始化

        /**
         * 安装Apk
         * 非静默安装
         */
        private fun installApk(context: Context, path: String){
            val intent =Intent(Intent.ACTION_VIEW)
            val file=File(path)
            if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
                //7.0版本及以上
                val apkUri=FileProvider.getUriForFile(context,"包名.provider",file)
                intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
                intent.setDataAndType(apkUri,"application/vnd.android.package-archive")
            }else{
                //7.0版本以下
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                val uri=Uri.fromFile(file)
                intent.setDataAndType(uri, "application/vnd.android.package-archive");
            }
            context.startActivity(intent)
        }
    

    由于StrictMode API 政策,我们在7.0及以上不能再使用file:// Uri形式进行应用安装。但无论7.0以上还是一下,我们都调用了

          val intent =Intent(Intent.ACTION_VIEW)
          context.startActivity(intent)
    

    Intent.ACTION_VIEW在7.0隐式匹配的是Activity为PackageInstallerActivity,
    8.0及以上隐式匹配的是Activity为InstallStart,从调用startActivity()方法我们可以认为应用安装的入口是拉起一个Activity界面。我们这里查看的是Android11.0的源码,那么便进入InstallStart的onCreate()方法看一看

        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mIPackageManager = AppGlobals.getPackageManager();
            mIPermissionManager = AppGlobals.getPermissionManager();
            mUserManager = getSystemService(UserManager.class);
            
            ......
    
            final boolean isSessionInstall =
                    PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
    
            ......
            ......
    
            if (isSessionInstall) {
                nextActivity.setClass(this, PackageInstallerActivity.class);
            } else {
                Uri packageUri = intent.getData();
    
                if (packageUri != null && packageUri.getScheme().equals(
                        ContentResolver.SCHEME_CONTENT)) {
                    // [IMPORTANT] This path is deprecated, but should still work. Only necessary
                    // features should be added.
    
                    // Copy file to prevent it from being changed underneath this process
                    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();
        }
    

    这里首先会判断intent传进来的action是否为CONFIRM_INSTALL,根据我们方法参数传入情况显然不是。然后对packageUri 的Scheme进行判断。如果是content就跳转到InstallStaging,如果是package就跳转到PackageInstallerActivity,否则就置空。在Android7.0及以上安装应用,我们都会使用FileProvider来处理URI ,FileProvider会隐藏文件真实路径,将路径转换成content://Uri路径,这样就满足packageUri Scheme协议匹配content的条件,后续跳转进入InstallStaging界面。
    在InstallStagingon的核心逻辑它的onResume()方法执行

        @Override
        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;
                }
                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) {
                if (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));
    
                    if (installIntent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
                        installIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
                    }
    
                    installIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                    startActivity(installIntent);
    
                    InstallStaging.this.finish();
                } else {
                    showError();
                }
            }
        }
    

    onResume()方法其实就是执行了一个StagingAsyncTask任务,在StagingAsyncTask的doInBackground(Uri... params)方法中会将packageUri协议写到mStagedFile中,然后再onPostExecute(Boolean success)方法中执行对DeleteStagedFileOnResult的跳转,并将mStagedFile传入,在DeleteStagedFileOnResult中执行了对PackageInstallerActivity的跳转,执行一圈,最终还是回到了PackageInstallerActivity类

        @Override
        protected void onCreate(Bundle icicle) {
            getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    
            super.onCreate(null);
    
            ......
            ......
    
          
            boolean wasSetUp = processPackageUri(packageUri);
            if (!wasSetUp) {
                return;
            }
    
            // load dummy layout with OK button disabled until we override this layout in
            // startInstallConfirm
            bindUi();
            checkIfAllowedAndInitiateInstall();
        }
    

    在PackageInstallerActivity的onCreate(Bundle icicle)方法中会调用processPackageUri()方法对packageUri进行预处理, bindUi()方法进行应用安装界面初始化 ,checkIfAllowedAndInitiateInstall()方法用来判断是否是未知来源的应用,如果开启允许安装未知来源选项则直接初始化安装

        private void checkIfAllowedAndInitiateInstall() {
            // Check for install apps user restriction first.
            final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource(
                    UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle());
            if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
                showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER);
                return;
            } else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
                startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
                finish();
                return;
            }
            //如果允许安装,就进入安装流程
            if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
                //调用安装方法
                initiateInstall();
            } else {
                // Check for unknown sources restrictions.
                final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(
                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle());
                final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource(
                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle());
                final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM
                        & (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
                if (systemRestriction != 0) {
                    showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
                } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
                    startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
                } else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
                    startAdminSupportDetailsActivity(
                            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
                } else {
                    handleUnknownSources();
                }
            }
        }
        
        
        private void initiateInstall() {
            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;
            }
            // Check if package is already installed. display confirmation dialog if replacing pkg
            try {
                // This is a little convoluted because we want to get all uninstalled
                // apps, but this may include apps with just data, and if it is just
                // data we still want to count it as "installed".
                mAppInfo = mPm.getApplicationInfo(pkgName,
                        PackageManager.MATCH_UNINSTALLED_PACKAGES);
                if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
                    mAppInfo = null;
                }
            } catch (NameNotFoundException e) {
                mAppInfo = null;
            }
             //设置安装确认界面可见
            startInstallConfirm();
        }
        
         
            private void startInstallConfirm() {
            View viewToEnable;
    
            if (mAppInfo != null) {
                viewToEnable = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
                        ? requireViewById(R.id.install_confirm_question_update_system)
                        : requireViewById(R.id.install_confirm_question_update);
            } else {
                // This is a new application with no permissions.
                viewToEnable = requireViewById(R.id.install_confirm_question);
            }
    
            viewToEnable.setVisibility(View.VISIBLE);
    
            mEnableOk = true;
            mOk.setEnabled(true);
            mOk.setFilterTouchesWhenObscured(true);
        }
    

    在initiateInstall()方法中,mPm.getApplicationInfo(pkgName,
    PackageManager.MATCH_UNINSTALLED_PACKAGES)会通过包名拿到应用信息。在startInstallConfirm()方法中会通过 viewToEnable.setVisibility(View.VISIBLE)使确认界面对用户可见,执行到这个阶段PackageInstaller的初始化工作便完成了

    二、APK的验证拷贝

    在第一阶段对PackageInstaller 完成了初始化工作并拉起安装确认界面,那么第二阶段便从安装确认界面的确认按钮点击事件开始

        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);
        ......
        ......  
    
        }
    

    mSessionId 是在PackageInstallerActivity的onCreate()方法中进行赋值的,我们直接去看 startInstall()方法

        private void startInstall() {
            // Start subactivity to actually install the application
            Intent newIntent = new Intent();
            newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
                    mPkgInfo.applicationInfo);
            newIntent.setData(mPackageURI);
            newIntent.setClass(this, InstallInstalling.class);
            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 != PackageInstaller.SessionParams.UID_UNKNOWN) {
                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);
            if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
            startActivity(newIntent);
            finish();
        }
    

    startInstall() 主要作用就是跳转到InstallInstalling类并关闭当前安装确认界面。
    在InstallInstalling的onCreate()方法会通过PackageParser.parsePackageLite(file, 0)对apk文件进行轻量解析,并调用getPackageManager().getPackageInstaller().createSession(params)。实际是调用PackageInstaller的createSession()方法

        public int createSession(@NonNull SessionParams params) throws IOException {
            try {
                return mInstaller.createSession(params, mInstallerPackageName, mUserId);
            } catch (RuntimeException e) {
                ExceptionUtils.maybeUnwrapIOException(e);
                throw e;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    mInstaller是一个IPackageInstaller对象,IPackageInstaller是一个aidl接口类,它的实现类PackageInstallerService,所以mInstaller.createSession()最终调用到的是PackageInstallerService的createSession()方法并返回了mSessionId。 由此二者实现了进程间的通信
    在看一下InstallInstalling的onResume()方法

        protected void onResume() {
            super.onResume();
    
            // This is the first onResume in a single life of the activity
            if (mInstallingTask == null) {
                PackageInstaller installer = getPackageManager().getPackageInstaller();
               //用mSessionId通过PackageInstaller 的getSessionInfo()拿到sessionInfo 信息
                PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
    
                if (sessionInfo != null && !sessionInfo.isActive()) {
                    mInstallingTask = new InstallingAsyncTask();
                    mInstallingTask.execute();
                } else {
                    // we will receive a broadcast when the install is finished
                    mCancelButton.setEnabled(false);
                    setFinishOnTouchOutside(false);
                }
            }
        }
    

    在onResume()方法中,通过mSessionId拿到了SessionInfo信息然后执行力InstallingAsyncTask任务,InstallingAsyncTask的doInBackground方法中会根据安装包包(APK)的Uri,将APK的信息通过IO流的形式写入到PackageInstaller.Session中。InstallingAsyncTask的onPostExecute方法如下所示

            @Override
            protected void onPostExecute(PackageInstaller.Session session) {
                if (session != null) {
                    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);
                    //通过 PackageInstaller.Session 的commit方法将IntentSender提交
                    session.commit(pendingIntent.getIntentSender());
                    mCancelButton.setEnabled(false);
                    setFinishOnTouchOutside(false);
                } else {
                    getPackageManager().getPackageInstaller().abandonSession(mSessionId);
    
                    if (!isCancelled()) {
                        launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
                    }
                }
            }
    

    onPostExecute() 中创建了一个PendingIntent,并将该PendingIntent的IntentSender通过PackageInstaller.Session的commit方法发送出去。

            public void commit(@NonNull IntentSender statusReceiver) {
                try {
                    mSession.commit(statusReceiver, false);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
    

    mSession为IPackageInstallerSession实例化对象,是一个aidl对象,它的实现类为PackageInstallerSession,这表明要通过IPackageInstallerSession来实现进程间的通信,然后调用到PackageInstallerSession的commit()方法

    /frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
    
        @Override
        public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
            if (hasParentSessionId()) {
                throw new IllegalStateException(
                        "Session " + sessionId + " is a child of multi-package session "
                                + mParentSessionId +  " and may not be committed directly.");
            }
    
            if (!markAsSealed(statusReceiver, forTransfer)) {
                return;
            }
            if (isMultiPackage()) {
                final SparseIntArray remainingSessions = mChildSessionIds.clone();
                final IntentSender childIntentSender =
                        new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
                                .getIntentSender();
                boolean sealFailed = false;
                for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
                    final int childSessionId = mChildSessionIds.keyAt(i);
                    // seal all children, regardless if any of them fail; we'll throw/return
                    // as appropriate once all children have been processed
                    if (!mSessionProvider.getSession(childSessionId)
                            .markAsSealed(childIntentSender, forTransfer)) {
                        sealFailed = true;
                    }
                }
                if (sealFailed) {
                    return;
                }
            }
    
            dispatchStreamValidateAndCommit();
        }
    
        private void dispatchStreamValidateAndCommit() {
            //向Handler发送消息
            mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
        }
         //处理对应消息
        private final Handler.Callback mHandlerCallback = new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_STREAM_VALIDATE_AND_COMMIT:
                        handleStreamValidateAndCommit();
                        break;
                    case MSG_INSTALL:
                        handleInstall();
                        break;
                    ......
                    ......
                }
    
                return true;
            }
        };
    
        private void handleStreamValidateAndCommit() {
            PackageManagerException unrecoverableFailure = null;
            // This will track whether the session and any children were validated and are ready to
            // progress to the next phase of install
            boolean allSessionsReady = false;
            ......
            ......
    
            mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
        }
    
        private void handleInstall() {
            ......
            ......
            try {
               //保证线程同步
                synchronized (mLock) {
                    installNonStagedLocked(childSessions);
                }
            } catch (PackageManagerException e) {
                final String completeMsg = ExceptionUtils.getCompleteMessage(e);
                Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
                destroyInternal();
                dispatchSessionFinished(e.error, completeMsg, null);
            }
        }
    
    
        @GuardedBy("mLock")
        private void installNonStagedLocked(List<PackageInstallerSession> childSessions)
                throws PackageManagerException {
            final PackageManagerService.ActiveInstallSession installingSession =
                    makeSessionActiveLocked();
            if (installingSession == null) {
                return;
            }
            if (isMultiPackage()) {
                ......
                ......
               //mPm是PackageManagerService的实例对象
                mPm.installStage(installingChildSessions);
            } else {
                mPm.installStage(installingSession);
            }
        }
    

    在PackageInstallerSession##commit()方法中会调用到dispatchStreamValidateAndCommit(),该方法作用就是向mHandler以Callback形式发送一条msg.what为MSG_STREAM_VALIDATE_AND_COMMIT的消息,在mHandler的handleMessage()中会调用handleStreamValidateAndCommit()对该消息进行处理在handleStreamValidateAndCommit()中又会向向mHandler以Callback形式发送一条msg.what为MSG_INSTALL的消息,以 handleInstall()对该消息进行处理,在handleInstall()中通过synchronized 保证了对installNonStagedLocked()方法调用的线程同步,installNonStagedLocked()方法中会调用 mPm.installStage(),mPm是PackageManagerService实例化对象。这样代码逻辑便进入PackageManagerService##installStage()

        void installStage(ActiveInstallSession activeInstallSession) {
            if (DEBUG_INSTANT) {
                if ((activeInstallSession.getSessionParams().installFlags
                        & PackageManager.INSTALL_INSTANT_APP) != 0) {
                    Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
                }
            }
            final Message msg = mHandler.obtainMessage(INIT_COPY);
            final InstallParams params = new InstallParams(activeInstallSession);
            params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
            msg.obj = params;
    
            Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
                    System.identityHashCode(msg.obj));
            Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                    System.identityHashCode(msg.obj));
    
            mHandler.sendMessage(msg);
        }
    
        void installStage(List<ActiveInstallSession> children)
                throws PackageManagerException {
            final Message msg = mHandler.obtainMessage(INIT_COPY);
            final MultiPackageInstallParams params =
                    new MultiPackageInstallParams(UserHandle.ALL, children);
            params.setTraceMethod("installStageMultiPackage")
                    .setTraceCookie(System.identityHashCode(params));
            msg.obj = params;
    
            Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
                    System.identityHashCode(msg.obj));
            Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                    System.identityHashCode(msg.obj));
            mHandler.sendMessage(msg);
        }
    

    PackageManagerService##installStage()有两个不同参数的重载方法,这个方法没什么重点,只是创建并向Handler发送一条msg.what为INIT_COPY的消息

        class PackageHandler extends Handler {
    
            PackageHandler(Looper looper) {
                super(looper);
            }
    
            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");
                            params.startCopy();
                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                        }
                        break;
                    }
                }
            }
        }
    

    在PackageHandler 对该消息的处理逻辑是调用HandlerParams ##startCopy()

            final void startCopy() {
                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
                handleStartCopy();
                handleReturnCode();
            }
    
           abstract void handleStartCopy();
           abstract void handleReturnCode();
    

    HandlerParams是一个抽象类它的实现类有PackageManagerService##MultiPackageInstallParams及
    PackageManagerService##InstallParams。在PackageHandler ##doHandleMessage()方法对msg的处理逻辑中可以发现,INIT_COPY消息体中包含HandlerParams 对象,往前查看发现传入对象为根据调用方法不一样而分为MultiPackageInstallParams与InstallParams两种。先看一下MultiPackageInstallParams##handleStartCopy()实现

            @Override
            void handleStartCopy() {
                for (InstallParams params : mChildParams) {
                   //还是调用到了InstallParams 的handleStartCopy()
                    params.handleStartCopy();
                    if (params.mRet != INSTALL_SUCCEEDED) {
                        mRet = params.mRet;
                    }
                }
            }
    

    发现其实就是对InstallParams集合进行了遍历然后调用handleStartCopy()方法。所以,殊途同归handleStartCopy()的实现最终还是要看InstallParams##handleStartCopy()

            public void handleStartCopy() {
                int ret = PackageManager.INSTALL_SUCCEEDED;
    
                // If we're already staged, we've firmly committed to an install location
                //检查文件是否已生成 是则对installFlags进行赋值
                if (origin.staged) {
                    if (origin.file != null) {
                        installFlags |= PackageManager.INSTALL_INTERNAL;
                    } else {
                        throw new IllegalStateException("Invalid stage location");
                    }
                }
    
                final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
                final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
                PackageInfoLite pkgLite = null;
    
    
                pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                        origin.resolvedPath, installFlags, packageAbiOverride);
    
                if (DEBUG_INSTANT && ephemeral) {
                    Slog.v(TAG, "pkgLite for install: " + pkgLite);
                }
    
                /*
                 * If we have too little free space, try to free cache
                 * before giving up.
                 */
                 //判断安装空间是否充足,若不充足则尝试释放部分空间
                if (!origin.staged && pkgLite.recommendedInstallLocation
                        == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                    // TODO: focus freeing disk space on the target device
                    final StorageManager storage = StorageManager.from(mContext);
                    final long lowThreshold = storage.getStorageLowBytes(
                            Environment.getDataDirectory());
    
                    final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
                            origin.resolvedPath, packageAbiOverride);
                    if (sizeBytes >= 0) {
                        try {
                            mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
                            pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                                    origin.resolvedPath, installFlags, packageAbiOverride);
                        } catch (InstallerException e) {
                            Slog.w(TAG, "Failed to free cache", e);
                        }
                    }
    
                    /*
                     * The cache free must have deleted the file we downloaded to install.
                     *
                     * TODO: fix the "freeCache" call to not delete the file we care about.
                     */
                    if (pkgLite.recommendedInstallLocation
                            == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                        pkgLite.recommendedInstallLocation
                                = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
                    }
                }
    
    
                if (ret == PackageManager.INSTALL_SUCCEEDED) {//1
                    int loc = pkgLite.recommendedInstallLocation;
                    if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
                        ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
                    } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
                        ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
                    } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                        ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                    } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
                        ret = PackageManager.INSTALL_FAILED_INVALID_APK;
                    } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                        ret = PackageManager.INSTALL_FAILED_INVALID_URI;
                    } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                        ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
                    } else {
                        // Override with defaults if needed.
                        //对包信息进行覆盖
                        loc = installLocationPolicy(pkgLite);
                        if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
                            ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
                        } else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
                            ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
                        } else if (!onInt) {
                            // Override install location with flags
                            if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
                                // Set the flag to install on external media.
                                installFlags &= ~PackageManager.INSTALL_INTERNAL;
                            } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
                                if (DEBUG_INSTANT) {
                                    Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
                                }
                                installFlags |= PackageManager.INSTALL_INSTANT_APP;
                                installFlags &= ~PackageManager.INSTALL_INTERNAL;
                            } else {
                                // Make sure the flag for installing on external
                                // media is unset
                                installFlags |= PackageManager.INSTALL_INTERNAL;
                            }
                        }
                    }
                }
    
                final InstallArgs args = createInstallArgs(this);
                mVerificationCompleted = true;
                mIntegrityVerificationCompleted = true;
                mEnableRollbackCompleted = true;
                mArgs = args;
    
                if (ret == PackageManager.INSTALL_SUCCEEDED) {
                    final int verificationId = mPendingVerificationToken++;
    
                    // Perform package verification (unless we are simply moving the package).
                    //验证包信息
                    if (!origin.existing) {
                        PackageVerificationState verificationState =
                                new PackageVerificationState(this);
                        mPendingVerification.append(verificationId, verificationState);
    
                        sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
                        ret = sendPackageVerificationRequest(
                                verificationId, pkgLite, verificationState);
    
                        // If both verifications are skipped, we should remove the state.
                        if (verificationState.areAllVerificationsComplete()) {
                            mPendingVerification.remove(verificationId);
                        }
                    }
                ......
                ......
                }
    
                mRet = ret;
            }
    

    在InstallParams##handleStartCopy()主要功能就是四点:
    1.验证文件是否已生成,若生成则对installFlags进行赋值处理
    2.验证空间是否充足 不充足则尝试释放无用空间
    3.对包信息进行覆盖处理 同时返回一个int值 loc
    4.验证包信息
    同样handleReturnCode()最终实现也是在InstallParams类中

            @Override
            void handleReturnCode() {
                if (mVerificationCompleted
                        && mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
                    if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
                        String packageName = "";
                        ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
                                new ParseTypeImpl(
                                        (changeId, packageName1, targetSdkVersion) -> {
                                            ApplicationInfo appInfo = new ApplicationInfo();
                                            appInfo.packageName = packageName1;
                                            appInfo.targetSdkVersion = targetSdkVersion;
                                            return mPackageParserCallback.isChangeEnabled(changeId,
                                                    appInfo);
                                        }).reset(),
                                origin.file, 0);
                        if (result.isError()) {
                            Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(),
                                    result.getException());
                        } else {
                            packageName = result.getResult().packageName;
                        }
                        try {
                            observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
                        } catch (RemoteException e) {
                            Slog.i(TAG, "Observer no longer exists.");
                        }
                        return;
                    }
                    if (mRet == PackageManager.INSTALL_SUCCEEDED) {
                        mRet = mArgs.copyApk();
                    }
                    processPendingInstall(mArgs, mRet);
                }
            }
    

    InstallParams##handleReturnCode()中调用InstallArgs的copyApk()进行APK的拷贝工作。InstallArgs是一个抽象类,FileInstallArgs及MoveInstallArgs继承并实现了它。InstallArgs的实例对象会在InstallParams##handleStartCopy()中调用createInstallArgs()进行创建,最终创建出来的是一个FileInstallArgs类型对象。所以代码逻辑又执行到了FileInstallArgs##copyApk()

    
            int copyApk() {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
                try {
                    return doCopyApk();
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
            }
    
            private int doCopyApk() {
                .....
                ......
                
                int ret = PackageManagerServiceUtils.copyPackage(
                        origin.file.getAbsolutePath(), codeFile);
                if (ret != PackageManager.INSTALL_SUCCEEDED) {
                    Slog.e(TAG, "Failed to copy package");
                    return ret;
                }
    
                final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath());
                final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
                NativeLibraryHelper.Handle handle = null;
                try {
                    handle = NativeLibraryHelper.Handle.create(codeFile);
                    ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
                            abiOverride, isIncremental);
                } catch (IOException e) {
                    Slog.e(TAG, "Copying native libraries failed", e);
                    ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                } finally {
                    IoUtils.closeQuietly(handle);
                }
    
                return ret;
            }
        public static int copyPackage(String packagePath, File targetDir) {
            if (packagePath == null) {
                return PackageManager.INSTALL_FAILED_INVALID_URI;
            }
    
            try {
                final File packageFile = new File(packagePath);
                final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0);
                copyFile(pkg.baseCodePath, targetDir, "base.apk");
                if (!ArrayUtils.isEmpty(pkg.splitNames)) {
                    for (int i = 0; i < pkg.splitNames.length; i++) {
                        copyFile(pkg.splitCodePaths[i], targetDir,
                                "split_" + pkg.splitNames[i] + ".apk");
                    }
                }
                return PackageManager.INSTALL_SUCCEEDED;
            } catch (PackageParserException | IOException | ErrnoException e) {
                Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
            }
        }
        private static void copyFile(String sourcePath, File targetDir, String targetName)
                throws ErrnoException, IOException {
            if (!FileUtils.isValidExtFilename(targetName)) {
                throw new IllegalArgumentException("Invalid filename: " + targetName);
            }
            Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
    
            final File targetFile = new File(targetDir, targetName);
            final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
                    O_RDWR | O_CREAT, 0644);
            Os.chmod(targetFile.getAbsolutePath(), 0644);
            FileInputStream source = null;
            try {
                source = new FileInputStream(sourcePath);
                FileUtils.copy(source.getFD(), targetFd);
            } finally {
                IoUtils.closeQuietly(source);
            }
        }
    

    在copyApk()调用 doCopyApk(),在 doCopyApk()再调用到PackageManagerServiceUtils##copyPackage(),逻辑进入到PackageManagerServiceUtils##copyPackage()会调用PackageManagerServiceUtils##copyFile()方法,而copyFile()方法就是将文件通过IO流将apk拷贝到相关目录下
    至此,APK验证拷贝流程完结

    三、安装APK

    在APK拷贝完成后即InstallParams##handleReturnCode()中mArgs.copyApk()流程执行完毕后,会在调用processPendingInstall()开始安装

        private void processPendingInstall(final InstallArgs args, final int currentStatus) {
            if (args.mMultiPackageInstallParams != null) {
                args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
            } else {
                PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
                processInstallRequestsAsync(
                        res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                        Collections.singletonList(new InstallRequest(args, res)));
            }
        }
    
        // Queue up an async operation since the package installation may take a little while.
        private void processInstallRequestsAsync(boolean success,
                List<InstallRequest> installRequests) {
            mHandler.post(() -> {
                if (success) {
                    for (InstallRequest request : installRequests) {
                       //安装前处理
                        request.args.doPreInstall(request.installResult.returnCode);
                    }
                    synchronized (mInstallLock) {
                        installPackagesTracedLI(installRequests);
                    }
                    for (InstallRequest request : installRequests) {
                       //安装后收尾
                        request.args.doPostInstall(
                                request.installResult.returnCode, request.installResult.uid);
                    }
                }
                for (InstallRequest request : installRequests) {
                    restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                            new PostInstallData(request.args, request.installResult, null));
                }
            });
        }
        @GuardedBy({"mInstallLock", "mLock"})
        private void installPackagesTracedLI(List<InstallRequest> requests) {
            try {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
                installPackagesLI(requests);
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        }
        @GuardedBy("mInstallLock")
        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) {
                    // TODO(b/109941548): remove this once we've pulled everything from it and into
                    //                    scan, reconcile or commit.
                    final PrepareResult prepareResult;
                    try {
                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
                    
                        // Prepare 准备:分析当前安装状态,分析包并对其进行初始验证
                        prepareResult =
                                preparePackageLI(request.args, request.installResult);
                    } catch (PrepareFailure prepareFailure) {
                        request.installResult.setError(prepareFailure.error,
                                prepareFailure.getMessage());
                        request.installResult.origPackage = prepareFailure.conflictingPackage;
                        request.installResult.origPermission = prepareFailure.conflictingPermission;
                        return;
                    } finally {
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                    ......
                    try {
                        //扫描分析准备阶段拿到的包信息
                        final ScanResult result = scanPackageTracedLI(
                                prepareResult.packageToScan, prepareResult.parseFlags,
                                prepareResult.scanFlags, System.currentTimeMillis(),
                                request.args.user, request.args.abiOverride);
                    ......
                    } catch (PackageManagerException e) {
                        request.installResult.setError("Scanning Failed.", e);
                        return;
                    }
                }
                //创建一个ReconcileRequest对象保存包扫描结果和相关请求详细信息,用于协调可能向系统添加的一个或多个包。
                ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
                        installResults,
                        prepareResults,
                        mSharedLibraries,
                        Collections.unmodifiableMap(mPackages), versionInfos,
                        lastStaticSharedLibSettings);
                CommitRequest commitRequest = null;
                synchronized (mLock) {
                    Map<String, ReconciledPackage> reconciledPackages;
                    ......
                    try {
                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
                        commitRequest = new CommitRequest(reconciledPackages,
                                mUserManager.getUserIds());
                        //提交扫描到的包信息并且在其中删除旧状态,写入新状态
                        commitPackagesLocked(commitRequest);
                        success = true;
                    } finally {
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                }
                //完成APK的安装
                executePostCommitSteps(commitRequest);
            } finally {
             ......
            }
        }
    

    processPendingInstall()会调用processInstallRequestsAsync()方法,在processInstallRequestsAsync()方法中再调用installPackagesTracedLI()方法执行安装流程,同时会对该方法以synchronized修饰保证线程同步。
    在installPackagesTracedLI()中会对应用信息进行处理然后调用executePostCommitSteps ()执行安装。
    executePostCommitSteps ()方法中会为新的代码路径准备应用程序配置文件,并在此检查是否需要dex优化。
    如果是安装新包,会为新的代码路径准备应用程序配置文件;如果是替换已安装应用,其主要过程为更新设置,清除原有应用数据数据,重新生成相关的app数据目录等步骤,同时要区分系统应用替换和非系统应用替换。而安装新包,则直接更新设置,生成APP数据即可。这部分代码以及总结会后续补全发出

    如果你有什么疑问或者认为哪个地方解析有错误,欢迎您在评论区指正。技术都是交流出来的

    相关文章

      网友评论

        本文标题:Android 包管理机制---PackageInstaller

        本文链接:https://www.haomeiwen.com/subject/bevqvltx.html