APK的安装方式主要有以下几种:
- 通过adb命令安装:adb 命令包括adb push/install
- 用户下载的Apk,通过系统安装器PackageInstaller安装该Apk。PackageInstaller是系统内置的应用程序,用于安装和卸载应用程序。
- 系统开机时安装系统应用。 persistent属性
- 应用商店下载后自动安装。
PackageInstaller的位置
frameworks\base\packages\PackageInstaller\路径下
其中InstallStart为PackageInstaller入口
<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>
安装apk的代码主要是调用InstallStart
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive");
context.startActivity(intent);
PackageInstaller是系统内置的应用程序,用于安装和卸载应用。当我们调用PackageInstaller来安装应用时会跳转到InstallStart,并调用它的onCreate方法:
String callingPackage = getCallingPackage();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//调用这里,启动InstallStagingnextActivity.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();
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStaging.java InstallStaging的onResume方法
@Overrideprotected void onResume() {super.onResume();// This is the first onResume in a single life of the activityif (mStagingTask == null) {// File does not exist, or became invalidif (mStagedFile == null) {// Create file delayed to be able to show errortry {
如果File类型的mStagedFile 为null,则创建mStagedFile ,mStagedFile用于存储临时数据mStagedFile = TemporaryFileManager.getStagedFile(this);} catch (IOException e) {showError();return;}}
启动StagingAsyncTaskmStagingTask = new StagingAsyncTask();mStagingTask.execute(getIntent().getData());}}
StagingAsyncTask是InstallStaging的内部类,
private final class StagingAsyncTask extends AsyncTask<Uri, Void, Boolean> {@Overrideprotected 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 cancellationif (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;}@Overrideprotected void onPostExecute(Boolean success) {if (success) {// Now start the installation again from a fileIntent 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();}}}
doInBackground方法中将packageUri(content协议的Uri)的内容写入到mStagedFile中,如果写入成功,onPostExecute方法中会跳转到DeleteStagedFileOnResult中,
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\DeleteStagedFileOnResult.java
DeleteStagedFileOnResult启动PackageInstallerActivity实现apk的安装
public class DeleteStagedFileOnResult extends Activity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (savedInstanceState == null) {Intent installIntent = new Intent(getIntent());installIntent.setClass(this, PackageInstallerActivity.class);installIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);startActivityForResult(installIntent, 0);}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {File sourceFile = new File(getIntent().getData().getPath());sourceFile.delete();setResult(resultCode, data);finish();}
}
DeleteStagedFileOnResult将mStagedFile传入PackageInstallerActivity,InstallStaging主要将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity,这样就可以像此前版本(Android7.0之前)一样启动安装流程了。
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\PackageInstallerActivity.java
@Overrideprotected void onCreate(Bundle icicle) {getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);super.onCreate(null);if (icicle != null) {mAllowUnknownSources = icicle.getBoolean(ALLOW_UNKNOWN_SOURCES_KEY);}//初始话安装所需要的各种对象mPm = getPackageManager();mIpm = AppGlobals.getPackageManager();mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);mInstaller = mPm.getPackageInstaller();mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);final Intent intent = getIntent();mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);mSourceInfo = intent.getParcelableExtra(EXTRA_ORIGINAL_SOURCE_INFO);mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,PackageInstaller.SessionParams.UID_UNKNOWN);mOriginatingPackage = (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN)? getPackageNameForUid(mOriginatingUid) : null;final Uri packageUri;if (PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction())) {final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");finish();return;}mSessionId = sessionId;packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));mOriginatingURI = null;mReferrerURI = null;} else {mSessionId = -1;packageUri = intent.getData();mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);}// if there's nothing to do, quietly slip into the etherif (packageUri == null) {Log.w(TAG, "Unspecified source");setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);finish();return;}if (DeviceUtils.isWear(this)) {showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR);return;}boolean wasSetUp = processPackageUri(packageUri);if (!wasSetUp) {return;}// load dummy layout with OK button disabled until we override this layout in// startInstallConfirmbindUi();//判断是否是未知来源的应用,如果开启允许安装未知来源选项则直接初始化安装checkIfAllowedAndInitiateInstall();}
类名 | 描述 |
---|---|
PackageManager | 用于向应用程序进程提供一些功能,最终的功能是由PMS来实现的 |
IPackageManager | 一个AIDL的接口,用于和PMS进行进程间通信 |
AppOpsManager | 用于权限动态检测,在Android4.3中被引入 |
PackageInstaller | 提供安装、升级和删除应用程序功能 |
UserManager | 用于多用户管理 |
bindUi();
/*** Check if it is allowed to install the package and initiate install if allowed. If not allowed* show the appropriate dialog.*/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;}
//判断如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {initiateInstall();} else {
// 如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面// 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();}}}
bindUi()方法主要完成对安装界面的加载
private void bindUi() {mAlert.setIcon(mAppSnippet.icon);mAlert.setTitle(mAppSnippet.label);mAlert.setView(R.layout.install_content_view);mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),(ignored, ignored2) -> {if (mOk.isEnabled()) {if (mSessionId != -1) {mInstaller.setPermissionsResult(mSessionId, true);finish();} else {
完成app的安装startInstall();}}}, null);mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),(ignored, ignored2) -> {// Cancel and finishsetResult(RESULT_CANCELED);if (mSessionId != -1) {mInstaller.setPermissionsResult(mSessionId, false);}finish();}, null);setupAlert();mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);mOk.setEnabled(false);if (!mOk.isInTouchMode()) {mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();}}
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 pkgtry {// 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);}
具体加载的布局文件再frameworks\base\packages\PackageInstaller\res\layout\下
现在来总结下PackageInstaller初始化的过程:
- 根据Uri的Scheme协议不同,跳转到不同的界面,content协议跳转到InstallStart,其他的跳转到PackageInstallerActivity。
- InstallStart将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity。
- PackageInstallerActivity会分别对package协议和file协议的Uri进行处理,如果是file协议会解析APK文件得到包信息PackageInfo。
- PackageInstallerActivity中会对未知来源进行处理,如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源,就会初始化安装确认界面,如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面。
startInstall();方法调用 InstallInstalling 来安装apk
startInstall方法用于跳转到InstallInstalling这个Activity,并关闭掉当前的PackageInstallerActivity。InstallInstalling主要用于向包管理器发送包的信息并处理包管理的回调。
private void startInstall() {// Start subactivity to actually install the applicationIntent 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();}
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallInstalling.java
@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);ApplicationInfo appInfo = getIntent().getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);mPackageURI = getIntent().getData();if ("package".equals(mPackageURI.getScheme())) {try {getPackageManager().installExistingPackage(appInfo.packageName);launchSuccess();} catch (PackageManager.NameNotFoundException e) {launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);}} else {
//根据mPackageURI创建一个对应的Filefinal File sourceFile = new File(mPackageURI.getPath());PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);mAlert.setIcon(as.icon);mAlert.setTitle(as.label);mAlert.setView(R.layout.install_content_view);mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),(ignored, ignored2) -> {if (mInstallingTask != null) {mInstallingTask.cancel(true);}if (mSessionId > 0) {getPackageManager().getPackageInstaller().abandonSession(mSessionId);mSessionId = 0;}setResult(RESULT_CANCELED);finish();}, null);setupAlert();requireViewById(R.id.installing).setVisibility(View.VISIBLE);//如果savedInstanceState不为null,获取此前保存的mSessionId和mInstallId if (savedInstanceState != null) {mSessionId = savedInstanceState.getInt(SESSION_ID);mInstallId = savedInstanceState.getInt(INSTALL_ID);// Reregister for result; might instantly call back if result was delivered while// activity was destroyedtry {
//向InstallEventReceiver注册一个观察者InstallEventReceiver.addObserver(this, mInstallId,this::launchFinishBasedOnResult);} catch (EventResultPersister.OutOfIdsException e) {// Does not happen}} else {PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);params.setInstallAsInstantApp(false);params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));params.setOriginatingUri(getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,UID_UNKNOWN));params.setInstallerPackageName(getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME));params.setInstallReason(PackageManager.INSTALL_REASON_USER);File file = new File(mPackageURI.getPath());try {PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);params.setAppPackageName(pkg.packageName);params.setInstallLocation(pkg.installLocation);params.setSize(PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));} catch (PackageParser.PackageParserException e) {Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.");Log.e(LOG_TAG,"Cannot calculate installed size " + file + ". Try only apk size.");params.setSize(file.length());} catch (IOException e) {Log.e(LOG_TAG,"Cannot calculate installed size " + file + ". Try only apk size.");params.setSize(file.length());}try {mInstallId = InstallEventReceiver.addObserver(this, EventResultPersister.GENERATE_NEW_ID,this::launchFinishBasedOnResult);} catch (EventResultPersister.OutOfIdsException e) {launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);}try {mSessionId = getPackageManager().getPackageInstaller().createSession(params);} catch (IOException e) {launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);}}mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);mSessionCallback = new InstallSessionCallback();}}
onCreate方法中会分别对package和content协议的Uri进行处理,我们来看content协议的Uri处理部分。注释1处如果savedInstanceState不为null,获取此前保存的mSessionId和mInstallId,其中mSessionId是安装包的会话id,mInstallId是等待的安装事件id。注释2处根据mInstallId向InstallEventReceiver注册一个观察者,launchFinishBasedOnResult会接收到安装事件的回调,无论安装成功或者失败都会关闭当前的Activity(InstallInstalling)。如果savedInstanceState为null,代码的逻辑也是类似的,注释3处创建SessionParams,它用来代表安装会话的参数,注释4、5处根据mPackageUri对包(APK)进行轻量级的解析,并将解析的参数赋值给SessionParams。注释6处和注释2处类似向InstallEventReceiver注册一个观察者返回一个新的mInstallId,其中InstallEventReceiver继承自BroadcastReceiver,用于接收安装事件并回调给EventResultPersister。 注释7处PackageInstaller的createSession方法内部会通过IPackageInstaller与PackageInstallerService进行进程间通信,最终调用的是PackageInstallerService的createSession方法来创建并返回mSessionId。
@Overrideprotected void onResume() {super.onResume();// This is the first onResume in a single life of the activityif (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 finishedmCancelButton.setEnabled(false);setFinishOnTouchOutside(false);}}}
根据mSessionId得到SessionInfo,SessionInfo代表安装会话的详细信息。如果sessionInfo不为Null并且不是活动的,就创建并执行InstallingAsyncTask。InstallingAsyncTask的doInBackground方法中会根据包(APK)的Uri,将APK的信息通过IO流的形式写入到PackageInstaller.Session中
onResune 启动InstallingAsyncTask
private final class InstallingAsyncTask extends AsyncTask<Void, Void,PackageInstaller.Session> {volatile boolean isDone;@Overrideprotected PackageInstaller.Session doInBackground(Void... params) {PackageInstaller.Session session;try {session = getPackageManager().getPackageInstaller().openSession(mSessionId);} catch (IOException e) {return null;}session.setStagingProgress(0);try {File file = new File(mPackageURI.getPath());try (InputStream in = new FileInputStream(file)) {long sizeBytes = file.length();try (OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes)) {byte[] buffer = new byte[1024 * 1024];while (true) {int numRead = in.read(buffer);if (numRead == -1) {session.fsync(out);break;}if (isCancelled()) {session.close();break;}out.write(buffer, 0, numRead);if (sizeBytes > 0) {float fraction = ((float) numRead / (float) sizeBytes);session.addProgress(fraction);}}}}return session;} catch (IOException | SecurityException e) {Log.e(LOG_TAG, "Could not write package", e);session.close();return null;} finally {synchronized (this) {isDone = true;notifyAll();}}}@Overrideprotected 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);session.commit(pendingIntent.getIntentSender());mCancelButton.setEnabled(false);setFinishOnTouchOutside(false);} else {getPackageManager().getPackageInstaller().abandonSession(mSessionId);if (!isCancelled()) {launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);}}}}
创建了一个PendingIntent,并将该PendingIntent的IntentSender通过PackageInstaller.Session的commit方法发送出去
frameworks\base\core\java\android\content\pm\PackageInstaller.java
protected final IPackageInstallerSession mSession;public void commit(@NonNull IntentSender statusReceiver) {try {mSession.commit(statusReceiver, false);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
mSession的类型为IPackageInstallerSession,这说明要通过IPackageInstallerSession来进行进程间的通信,最终会调用PackageInstallerSession的commit方法
frameworks\base\services\core\java\com\android\server\pm\PackageInstallerSession.java
@Overridepublic 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 processedif (!mSessionProvider.getSession(childSessionId).markAsSealed(childIntentSender, forTransfer)) {sealFailed = true;}}if (sealFailed) {return;}}dispatchStreamValidateAndCommit();}
private void dispatchStreamValidateAndCommit() {mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();}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 installboolean allSessionsReady = false;try {allSessionsReady = streamValidateAndCommit();} catch (PackageManagerException e) {unrecoverableFailure = e;}if (isMultiPackage()) {int childCount = mChildSessionIds.size();// This will contain all child sessions that do not encounter an unrecoverable failureArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount);for (int i = childCount - 1; i >= 0; --i) {final int childSessionId = mChildSessionIds.keyAt(i);// commit all children, regardless if any of them fail; we'll throw/return// as appropriate once all children have been processedtry {PackageInstallerSession session = mSessionProvider.getSession(childSessionId);allSessionsReady &= session.streamValidateAndCommit();nonFailingSessions.add(session);} catch (PackageManagerException e) {allSessionsReady = false;if (unrecoverableFailure == null) {unrecoverableFailure = e;}}}// If we encountered any unrecoverable failures, destroy all other sessions including// the parentif (unrecoverableFailure != null) {// {@link #streamValidateAndCommit()} calls// {@link #onSessionVerificationFailure(PackageManagerException)}, but we don't// expect it to ever do so for parent sessions. Call that on this parent to clean// it up and notify listeners of the error.onSessionVerificationFailure(unrecoverableFailure);// fail other child sessions that did not already failfor (int i = nonFailingSessions.size() - 1; i >= 0; --i) {PackageInstallerSession session = nonFailingSessions.get(i);session.onSessionVerificationFailure(unrecoverableFailure);}}}if (!allSessionsReady) {return;}mHandler.obtainMessage(MSG_INSTALL).sendToTarget();}
private void handleInstall() {if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {DevicePolicyEventLogger.createEvent(DevicePolicyEnums.INSTALL_PACKAGE).setAdmin(mInstallSource.installerPackageName).write();}if (params.isStaged) {mStagingManager.commitSession(this);destroyInternal();dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);return;}if (isApexInstallation()) {destroyInternal();dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,"APEX packages can only be installed using staged sessions.", null);return;}// For a multiPackage session, read the child sessions// outside of the lock, because reading the child// sessions with the lock held could lead to deadlock// (b/123391593).List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();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()) {List<PackageManagerService.ActiveInstallSession> installingChildSessions =new ArrayList<>(childSessions.size());boolean success = true;PackageManagerException failure = null;for (int i = 0; i < childSessions.size(); ++i) {final PackageInstallerSession session = childSessions.get(i);try {final PackageManagerService.ActiveInstallSession installingChildSession =session.makeSessionActiveLocked();if (installingChildSession != null) {installingChildSessions.add(installingChildSession);}} catch (PackageManagerException e) {failure = e;success = false;}}if (!success) {sendOnPackageInstalled(mContext, mRemoteStatusReceiver, sessionId,isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,failure.error, failure.getLocalizedMessage(), null);return;}mPm.installStage(installingChildSessions);} else {mPm.installStage(installingSession);}}
调用 mPm的installStage方法
private final PackageManagerService mPm;
frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java
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);}
创建InstallParams,它对应于包的安装数据
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;}
params.startCopy();
params是HandlerParams类
final void startCopy() {if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);handleStartCopy();handleReturnCode();}
abstract void handleStartCopy();abstract void handleReturnCode();
具体实现在 InstallParams里 是PackageManagerService的内部类
class InstallParams extends HandlerParams {
public void handleStartCopy() {int ret = PackageManager.INSTALL_SUCCEEDED;// If we're already staged, we've firmly committed to an install locationif (origin.staged) {if (origin.file != null) {installFlags |= PackageManager.INSTALL_INTERNAL;} else {throw new IllegalStateException("Invalid stage location");}}
//确定APK的安装位置。 onInt:内部存储即Data分区,ephemeral:安装到临时存储(Instant Apps安装)final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;PackageInfoLite pkgLite = null;//获取APK的少量的信息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 devicefinal 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) {
//判断安装的位置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 flagsif (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 unsetinstallFlags |= PackageManager.INSTALL_INTERNAL;}}}}
//根据InstallParams创建InstallArgs对象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);}}if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {// TODO(ruhler) b/112431924: Don't do this in case of 'move'?final int enableRollbackToken = mPendingEnableRollbackToken++;Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);mPendingEnableRollback.append(enableRollbackToken, this);Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);enableRollbackIntent.putExtra(PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,enableRollbackToken);enableRollbackIntent.putExtra(PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,mSessionId);enableRollbackIntent.setType(PACKAGE_MIME_TYPE);enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);// Allow the broadcast to be sent before boot complete.// This is needed when committing the apk part of a staged// session in early boot. The rollback manager registers// its receiver early enough during the boot process that// it will not miss the broadcast.enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {// the duration to wait for rollback to be enabled, in millislong rollbackTimeout = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ROLLBACK,PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);if (rollbackTimeout < 0) {rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;}final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT);msg.arg1 = enableRollbackToken;msg.arg2 = mSessionId;mHandler.sendMessageDelayed(msg, rollbackTimeout);}}, null, 0, null, null);mEnableRollbackCompleted = false;}}mRet = ret;}
InstallArgs 是一个抽象类,定义了APK的安装逻辑,比如复制和重命名APK等,
其中FileInstallArgs用于处理安装到非ASEC的存储空间的APK,也就是内部存储空间(Data分区)
MoveInstallArgs用于处理已安装APK的移动的逻辑。
static abstract class InstallArgs {class FileInstallArgs extends InstallArgs {
class MoveInstallArgs extends InstallArgs {
@Overridevoid 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);}}
mArgs.copyApk();
private InstallArgs mArgs;
int copyApk() {Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");try {return doCopyApk();} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}}private int doCopyApk() {if (origin.staged) {if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");codeFile = origin.file;resourceFile = origin.file;return PackageManager.INSTALL_SUCCEEDED;}try {final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;//创建临时文件存储目录final File tempDir =mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);codeFile = tempDir;resourceFile = tempDir;} catch (IOException e) {Slog.w(TAG, "Failed to create copy file: " + e);return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;}
将APK复制到临时存储目录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;}
processPendingInstall(mArgs, mRet);
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));}});}
private PackageInstalledInfo createPackageInstalledInfo(int currentStatus) {PackageInstalledInfo res = new PackageInstalledInfo();res.setReturnCode(currentStatus);res.uid = -1;res.pkg = null;res.removedInfo = null;return res;}
@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);}}
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");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);}request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);request.installResult.installerPackageName =request.args.installSource.installerPackageName;final String packageName = prepareResult.packageToScan.getPackageName();prepareResults.put(packageName, prepareResult);installResults.put(packageName, request.installResult);installArgs.put(packageName, request.args);try {final ScanResult result = scanPackageTracedLI(prepareResult.packageToScan, prepareResult.parseFlags,prepareResult.scanFlags, System.currentTimeMillis(),request.args.user, request.args.abiOverride);if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {request.installResult.setError(PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,"Duplicate package " + result.pkgSetting.pkg.getPackageName()+ " in multi-package install request.");return;}createdAppId.put(packageName, optimisticallyRegisterAppId(result));versionInfos.put(result.pkgSetting.pkg.getPackageName(),getSettingsVersionForPackage(result.pkgSetting.pkg));if (result.staticSharedLibraryInfo != null) {final PackageSetting sharedLibLatestVersionSetting =getSharedLibLatestVersionSetting(result);if (sharedLibLatestVersionSetting != null) {lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),sharedLibLatestVersionSetting);}}} catch (PackageManagerException e) {request.installResult.setError("Scanning Failed.", e);return;}}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, "reconcilePackages");reconciledPackages = reconcilePackagesLocked(reconcileRequest, mSettings.mKeySetManagerService);} catch (ReconcileFailure e) {for (InstallRequest request : requests) {request.installResult.setError("Reconciliation failed...", e);}return;} finally {Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}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);}}executePostCommitSteps(commitRequest);} finally {if (success) {for (InstallRequest request : requests) {final InstallArgs args = request.args;if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {continue;}if (args.signingDetails.signatureSchemeVersion != SIGNING_BLOCK_V4) {continue;}// For incremental installs, we bypass the verifier prior to install. Now// that we know the package is valid, send a notice to the verifier with// the root hash of the base.apk.final String baseCodePath = request.installResult.pkg.getBaseCodePath();final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths();final Uri originUri = Uri.fromFile(args.origin.resolvedFile);final int verificationId = mPendingVerificationToken++;final String rootHashString = PackageManagerServiceUtils.buildVerificationRootHashString(baseCodePath, splitCodePaths);broadcastPackageVerified(verificationId, originUri,PackageManager.VERIFICATION_ALLOW, rootHashString,args.mDataLoaderType, args.getUser());}} else {for (ScanResult result : preparedScans.values()) {if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),false)) {cleanUpAppIdCreation(result);}}// TODO(patb): create a more descriptive reason than unknown in future release// mark all non-failure installs as UNKNOWN so we do not treat them as successfor (InstallRequest request : requests) {if (request.installResult.freezer != null) {request.installResult.freezer.close();}if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;}}}Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);}}
executePostCommitSteps执行安装
installPackageLI方法的代码有将近500行,这里截取主要的部分,主要做了几件事:
- 创建PackageParser解析APK。
- 检查APK是否存在,如果存在就获取此前没被改名前的包名并在注释1处赋值给PackageParser.Package类型的pkg,在注释3处将标志位replace置为true表示是替换安装。
- 注释3处,如果Settings中保存有要安装的APK的信息,说明此前安装过该APK,则需要校验APK的签名信息,确保安全的进行替换。
- 在注释4处将临时文件重新命名,比如前面提到的/data/app/vmdl18300388.tmp/base.apk,重命名为/data/app/包名-1/base.apk。这个新命名的包名会带上一个数字后缀1,每次升级一个已有的App,这个数字会不断的累加。
- 系统APP的更新安装会有两个限制,一个是系统APP不能在SD卡上替换安装,另一个是系统APP不能被Instant App替换。
- 注释5处根据replace来做区分,如果是替换安装就会调用replacePackageLIF方法,其方法内部还会对系统APP和非系统APP进行区分处理,如果是新安装APK会调用installNewPackageLIF方法。
installNewPackageLIF主要做了以下3件事:
- 扫描APK,将APK的信息存储在PackageParser.Package类型的newPackage中,一个Package的信息包含了1个base APK以及0个或者多个split APK。
- 更新该APK对应的Settings信息,Settings用于保存所有包的动态设置。
- 如果安装成功就为新安装的应用程序准备数据,安装失败就删除APK。
安装APK的过程就讲到这里,就不再往下分析下去,有兴趣的同学可以接着深挖。
**4.总结 **
本文主要讲解了PMS是如何处理APK安装的,主要有几个步骤:
- PackageInstaller安装APK时会将APK的信息交由PMS处理,PMS通过向PackageHandler发送消息来驱动APK的复制和安装工作。
- PMS发送INIT_COPY和MCS_BOUND类型的消息,控制PackageHandler来绑定DefaultContainerService,完成复制APK等工作。
- 复制APK完成后,会开始进行安装APK的流程,包括安装前的检查、安装APK和安装后的收尾工作。