Android 8.0 原生PackageInstaller安装逻辑梳理

PackageInstaller是system app ,是一个安装应用的应用。因为它本身具有system相关权限,可以直接与pms交互进行apk安装。三方应用因为权限受限,因此需要通过它来间接安装apk。

核心权限:



intent隐式启动呼起PackageInstaller入口
匹配: 原生对应的入口是:InstallStart.java

安装的核心逻辑在:PackageInstallerActivity.java

一、初始化逻辑

   @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
 
        //intent信息校验
 
        bindUi(R.layout.install_confirm, false);//构建安装页UI
        checkIfAllowedAndInitiateInstall();//安装校验
    }
 
 
  private void checkIfAllowedAndInitiateInstall() {
        if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
            initiateInstall();
            return;
        }
        // If the admin prohibits it, just show error and exit.
        // 安装应用未知来源
        if (isUnknownSourcesDisallowed()) {
         ...
        } else {
            handleUnknownSources();
        }
    }
 
 
   private void handleUnknownSources() {
        if (mOriginatingPackage == null) {
            Log.i(TAG, "No source found for package " + mPkgInfo.packageName);
            showDialogInner(DLG_ANONYMOUS_SOURCE);
            return;
        }
        //android O 新权限 
        int appOpMode = mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
                mOriginatingUid, mOriginatingPackage);
        switch (appOpMode) {
      ...
            case AppOpsManager.MODE_ALLOWED:
                initiateInstall();//初始化安装
                break;
     ...
        }
    }
 
 
  private void initiateInstall() {
       ...
        // 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() {
        // We might need to show permissions, load layout with permissions
        if (mAppInfo != null) {
            bindUi(R.layout.install_confirm_perm_update, true);
        } else {
            bindUi(R.layout.install_confirm_perm, true);
        }
...
        //从apk中提取权限,然后把提取出的权限存放在AppSecurityPermissions类的mPermsList变量中
        AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
...
        //根据提取出来的权限设置UI内容
    }

这部分简单看主要就是页面UI绑定展示和安装相关权限检查。

二、安装逻辑

 public void onClick(View v) {
        if (v == mOk) { //确定安装
            if (mOk.isEnabled()) {
                if (mOkCanInstall || mScrollView == null) {
                    if (mSessionId != -1) {
                        mInstaller.setPermissionsResult(mSessionId, true);
                        finish();
                    } else {
                        startInstall();//走安装流程
                    }
                } else {
                    mScrollView.pageScroll(View.FOCUS_DOWN);
                }
            }
        } else if (v == mCancel) {
            // Cancel and finish
            setResult(RESULT_CANCELED);
            if (mSessionId != -1) {
                mInstaller.setPermissionsResult(mSessionId, false);
            }
            finish();
        }
    }
 
安装跳转到InstallInstalling
   protected void onResume() {
        super.onResume();
 
        // This is the first onResume in a single life of the activity
        if (mInstallingTask == null) {
            PackageInstaller installer = getPackageManager().getPackageInstaller();
            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);
            }
        }
    }
 
     protected void onPostExecute(PackageInstaller.Session session) {
            if (session != null) {
              ...
                session.commit(pendingIntent.getIntentSender());
            }
...
        }
 
 
public void commit(@NonNull IntentSender statusReceiver) {
            try {
                //mSession 对应 PackageInstallerSession
                mSession.commit(statusReceiver);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
 
 
PackageInstallerSession:
    public void commit(IntentSender statusReceiver) {
       ...
        final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
                statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
        mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
    }
 
commit方法中会将包的信息封装为PackageInstallObserverAdapter ,它在PMS中被定义。在注释1处会向Handler发送一个类型为MSG_COMMIT的消息,其中adapter.getBinder()会得到IPackageInstallObserver2.Stub类型的观察者,从类型就知道这个观察者是可以跨进程进行回调的。
 
 
  private final Handler.Callback mHandlerCallback = new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            // Cache package manager data without the lock held
            final PackageInfo pkgInfo = mPm.getPackageInfo(
                    params.appPackageName, PackageManager.GET_SIGNATURES
                            | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
            final ApplicationInfo appInfo = mPm.getApplicationInfo(
                    params.appPackageName, 0, userId);
 
            synchronized (mLock) {
                if (msg.obj != null) {
                    mRemoteObserver = (IPackageInstallObserver2) msg.obj;
                }
 
                try {
                    commitLocked(pkgInfo, appInfo);
                } catch (PackageManagerException e) {
                    final String completeMsg = ExceptionUtils.getCompleteMessage(e);
                    Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
                    destroyInternal();
                    dispatchSessionFinished(e.error, completeMsg, null);
                }
 
                return true;
            }
        }
    };
 
    private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
            throws PackageManagerException {
    ...
        mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
                installerPackageName, installerUid, user, mCertificates);
    }
PackageInstaller安装流程

你可能感兴趣的:(Android 8.0 原生PackageInstaller安装逻辑梳理)