当前位置:   article > 正文

app 安装方式_action: confirm

action: confirm

APK的安装方式主要有以下几种:

  • 通过adb命令安装:adb 命令包括adb push/install
  • 用户下载的Apk,通过系统安装器PackageInstaller安装该Apk。PackageInstaller是系统内置的应用程序,用于安装和卸载应用程序。
  • 系统开机时安装系统应用。 persistent属性
  • 应用商店下载后自动安装。

PackageInstaller的位置

frameworks\base\packages\PackageInstaller\路径下

其中InstallStart为PackageInstaller入口
  1. <activity android:name=".InstallStart"
  2. android:theme="@android:style/Theme.Translucent.NoTitleBar"
  3. android:exported="true"
  4. android:excludeFromRecents="true">
  5. <intent-filter android:priority="1">
  6. <action android:name="android.intent.action.VIEW" />
  7. <action android:name="android.intent.action.INSTALL_PACKAGE" />
  8. <category android:name="android.intent.category.DEFAULT" />
  9. <data android:scheme="content" />
  10. <data android:mimeType="application/vnd.android.package-archive" />
  11. </intent-filter>
  12. <intent-filter android:priority="1">
  13. <action android:name="android.intent.action.INSTALL_PACKAGE" />
  14. <category android:name="android.intent.category.DEFAULT" />
  15. <data android:scheme="package" />
  16. <data android:scheme="content" />
  17. </intent-filter>
  18. <intent-filter android:priority="1">
  19. <action android:name="android.content.pm.action.CONFIRM_INSTALL" />
  20. <category android:name="android.intent.category.DEFAULT" />
  21. </intent-filter>
  22. </activity>

安装apk的代码主要是调用InstallStart

  1. Intent intent = new Intent(Intent.ACTION_VIEW);
  2. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  3. intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive");
  4. context.startActivity(intent);

PackageInstaller是系统内置的应用程序,用于安装和卸载应用。当我们调用PackageInstaller来安装应用时会跳转到InstallStart,并调用它的onCreate方法:

  1. String callingPackage = getCallingPackage();
  2. final boolean isSessionInstall =
  3. PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
  4. if (isSessionInstall) {
  5. nextActivity.setClass(this, PackageInstallerActivity.class);
  6. } else {
  7. Uri packageUri = intent.getData();
  8. if (packageUri != null && packageUri.getScheme().equals(
  9. ContentResolver.SCHEME_CONTENT)) {
  10. // [IMPORTANT] This path is deprecated, but should still work. Only necessary
  11. // features should be added.
  12. // Copy file to prevent it from being changed underneath this process
  13. //调用这里,启动InstallStaging
  14. nextActivity.setClass(this, InstallStaging.class);
  15. } else if (packageUri != null && packageUri.getScheme().equals(
  16. PackageInstallerActivity.SCHEME_PACKAGE)) {
  17. nextActivity.setClass(this, PackageInstallerActivity.class);
  18. } else {
  19. Intent result = new Intent();
  20. result.putExtra(Intent.EXTRA_INSTALL_RESULT,
  21. PackageManager.INSTALL_FAILED_INVALID_URI);
  22. setResult(RESULT_FIRST_USER, result);
  23. nextActivity = null;
  24. }
  25. }
  26. if (nextActivity != null) {
  27. startActivity(nextActivity);
  28. }
  29. finish();

frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStaging.java   InstallStaging的onResume方法

  1. @Override
  2. protected void onResume() {
  3. super.onResume();
  4. // This is the first onResume in a single life of the activity
  5. if (mStagingTask == null) {
  6. // File does not exist, or became invalid
  7. if (mStagedFile == null) {
  8. // Create file delayed to be able to show error
  9. try {
  10. 如果File类型的mStagedFile 为null,则创建mStagedFile ,mStagedFile用于存储临时数据
  11. mStagedFile = TemporaryFileManager.getStagedFile(this);
  12. } catch (IOException e) {
  13. showError();
  14. return;
  15. }
  16. }
  17. 启动StagingAsyncTask
  18. mStagingTask = new StagingAsyncTask();
  19. mStagingTask.execute(getIntent().getData());
  20. }
  21. }

 StagingAsyncTask是InstallStaging的内部类,

  1. private final class StagingAsyncTask extends AsyncTask<Uri, Void, Boolean> {
  2. @Override
  3. protected Boolean doInBackground(Uri... params) {
  4. if (params == null || params.length <= 0) {
  5. return false;
  6. }
  7. Uri packageUri = params[0];
  8. try (InputStream in = getContentResolver().openInputStream(packageUri)) {
  9. // Despite the comments in ContentResolver#openInputStream the returned stream can
  10. // be null.
  11. if (in == null) {
  12. return false;
  13. }
  14. try (OutputStream out = new FileOutputStream(mStagedFile)) {
  15. byte[] buffer = new byte[1024 * 1024];
  16. int bytesRead;
  17. while ((bytesRead = in.read(buffer)) >= 0) {
  18. // Be nice and respond to a cancellation
  19. if (isCancelled()) {
  20. return false;
  21. }
  22. out.write(buffer, 0, bytesRead);
  23. }
  24. }
  25. } catch (IOException | SecurityException | IllegalStateException e) {
  26. Log.w(LOG_TAG, "Error staging apk from content URI", e);
  27. return false;
  28. }
  29. return true;
  30. }
  31. @Override
  32. protected void onPostExecute(Boolean success) {
  33. if (success) {
  34. // Now start the installation again from a file
  35. Intent installIntent = new Intent(getIntent());
  36. installIntent.setClass(InstallStaging.this, DeleteStagedFileOnResult.class);
  37. installIntent.setData(Uri.fromFile(mStagedFile));
  38. if (installIntent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
  39. installIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
  40. }
  41. installIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
  42. startActivity(installIntent);
  43. InstallStaging.this.finish();
  44. } else {
  45. showError();
  46. }
  47. }
  48. }

doInBackground方法中将packageUri(content协议的Uri)的内容写入到mStagedFile中,如果写入成功,onPostExecute方法中会跳转到DeleteStagedFileOnResult中,

frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\DeleteStagedFileOnResult.java

DeleteStagedFileOnResult启动PackageInstallerActivity实现apk的安装

  1. public class DeleteStagedFileOnResult extends Activity {
  2. @Override
  3. protected void onCreate(@Nullable Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. if (savedInstanceState == null) {
  6. Intent installIntent = new Intent(getIntent());
  7. installIntent.setClass(this, PackageInstallerActivity.class);
  8. installIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
  9. startActivityForResult(installIntent, 0);
  10. }
  11. }
  12. @Override
  13. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  14. File sourceFile = new File(getIntent().getData().getPath());
  15. sourceFile.delete();
  16. setResult(resultCode, data);
  17. finish();
  18. }
  19. }

DeleteStagedFileOnResult将mStagedFile传入PackageInstallerActivity,InstallStaging主要将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity,这样就可以像此前版本(Android7.0之前)一样启动安装流程了。

frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\PackageInstallerActivity.java

  1. @Override
  2. protected void onCreate(Bundle icicle) {
  3. getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
  4. super.onCreate(null);
  5. if (icicle != null) {
  6. mAllowUnknownSources = icicle.getBoolean(ALLOW_UNKNOWN_SOURCES_KEY);
  7. }
  8. //初始话安装所需要的各种对象
  9. mPm = getPackageManager();
  10. mIpm = AppGlobals.getPackageManager();
  11. mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
  12. mInstaller = mPm.getPackageInstaller();
  13. mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
  14. final Intent intent = getIntent();
  15. mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);
  16. mSourceInfo = intent.getParcelableExtra(EXTRA_ORIGINAL_SOURCE_INFO);
  17. mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
  18. PackageInstaller.SessionParams.UID_UNKNOWN);
  19. mOriginatingPackage = (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN)
  20. ? getPackageNameForUid(mOriginatingUid) : null;
  21. final Uri packageUri;
  22. if (PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction())) {
  23. final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
  24. final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
  25. if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
  26. Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
  27. finish();
  28. return;
  29. }
  30. mSessionId = sessionId;
  31. packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));
  32. mOriginatingURI = null;
  33. mReferrerURI = null;
  34. } else {
  35. mSessionId = -1;
  36. packageUri = intent.getData();
  37. mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
  38. mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
  39. }
  40. // if there's nothing to do, quietly slip into the ether
  41. if (packageUri == null) {
  42. Log.w(TAG, "Unspecified source");
  43. setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
  44. finish();
  45. return;
  46. }
  47. if (DeviceUtils.isWear(this)) {
  48. showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR);
  49. return;
  50. }
  51. boolean wasSetUp = processPackageUri(packageUri);
  52. if (!wasSetUp) {
  53. return;
  54. }
  55. // load dummy layout with OK button disabled until we override this layout in
  56. // startInstallConfirm
  57. bindUi();
  58. //判断是否是未知来源的应用,如果开启允许安装未知来源选项则直接初始化安装
  59. checkIfAllowedAndInitiateInstall();
  60. }
类名描述
PackageManager用于向应用程序进程提供一些功能,最终的功能是由PMS来实现的
IPackageManager一个AIDL的接口,用于和PMS进行进程间通信
AppOpsManager用于权限动态检测,在Android4.3中被引入
PackageInstaller提供安装、升级和删除应用程序功能
UserManager用于多用户管理


        bindUi();

  1. /**
  2. * Check if it is allowed to install the package and initiate install if allowed. If not allowed
  3. * show the appropriate dialog.
  4. */
  5. private void checkIfAllowedAndInitiateInstall() {
  6. // Check for install apps user restriction first.
  7. final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource(
  8. UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle());
  9. if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
  10. showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER);
  11. return;
  12. } else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
  13. startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
  14. finish();
  15. return;
  16. }
  17. //判断如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源
  18. if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
  19. initiateInstall();
  20. } else {
  21. // 如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面
  22. // Check for unknown sources restrictions.
  23. final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(
  24. UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle());
  25. final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource(
  26. UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle());
  27. final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM
  28. & (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
  29. if (systemRestriction != 0) {
  30. showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
  31. } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
  32. startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
  33. } else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
  34. startAdminSupportDetailsActivity(
  35. UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
  36. } else {
  37. handleUnknownSources();
  38. }
  39. }
  40. }

bindUi()方法主要完成对安装界面的加载

  1. private void bindUi() {
  2. mAlert.setIcon(mAppSnippet.icon);
  3. mAlert.setTitle(mAppSnippet.label);
  4. mAlert.setView(R.layout.install_content_view);
  5. mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
  6. (ignored, ignored2) -> {
  7. if (mOk.isEnabled()) {
  8. if (mSessionId != -1) {
  9. mInstaller.setPermissionsResult(mSessionId, true);
  10. finish();
  11. } else {
  12. 完成app的安装
  13. startInstall();
  14. }
  15. }
  16. }, null);
  17. mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
  18. (ignored, ignored2) -> {
  19. // Cancel and finish
  20. setResult(RESULT_CANCELED);
  21. if (mSessionId != -1) {
  22. mInstaller.setPermissionsResult(mSessionId, false);
  23. }
  24. finish();
  25. }, null);
  26. setupAlert();
  27. mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
  28. mOk.setEnabled(false);
  29. if (!mOk.isInTouchMode()) {
  30. mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
  31. }
  32. }

 

  1. private void initiateInstall() {
  2. String pkgName = mPkgInfo.packageName;
  3. // Check if there is already a package on the device with this name
  4. // but it has been renamed to something else.
  5. String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
  6. if (oldName != null && oldName.length > 0 && oldName[0] != null) {
  7. pkgName = oldName[0];
  8. mPkgInfo.packageName = pkgName;
  9. mPkgInfo.applicationInfo.packageName = pkgName;
  10. }
  11. // Check if package is already installed. display confirmation dialog if replacing pkg
  12. try {
  13. // This is a little convoluted because we want to get all uninstalled
  14. // apps, but this may include apps with just data, and if it is just
  15. // data we still want to count it as "installed".
  16. mAppInfo = mPm.getApplicationInfo(pkgName,
  17. PackageManager.MATCH_UNINSTALLED_PACKAGES);
  18. if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
  19. mAppInfo = null;
  20. }
  21. } catch (NameNotFoundException e) {
  22. mAppInfo = null;
  23. }
  24. startInstallConfirm();
  25. }
  1. private void startInstallConfirm() {
  2. View viewToEnable;
  3. if (mAppInfo != null) {
  4. viewToEnable = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
  5. ? requireViewById(R.id.install_confirm_question_update_system)
  6. : requireViewById(R.id.install_confirm_question_update);
  7. } else {
  8. // This is a new application with no permissions.
  9. viewToEnable = requireViewById(R.id.install_confirm_question);
  10. }
  11. viewToEnable.setVisibility(View.VISIBLE);
  12. mEnableOk = true;
  13. mOk.setEnabled(true);
  14. mOk.setFilterTouchesWhenObscured(true);
  15. }

 具体加载的布局文件再frameworks\base\packages\PackageInstaller\res\layout\下

现在来总结下PackageInstaller初始化的过程:

  1. 根据Uri的Scheme协议不同,跳转到不同的界面,content协议跳转到InstallStart,其他的跳转到PackageInstallerActivity。
  2. InstallStart将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity。
  3. PackageInstallerActivity会分别对package协议和file协议的Uri进行处理,如果是file协议会解析APK文件得到包信息PackageInfo。
  4. PackageInstallerActivity中会对未知来源进行处理,如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源,就会初始化安装确认界面,如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面。

 startInstall();方法调用 InstallInstalling 来安装apk

startInstall方法用于跳转到InstallInstalling这个Activity,并关闭掉当前的PackageInstallerActivity。InstallInstalling主要用于向包管理器发送包的信息并处理包管理的回调。

  1. private void startInstall() {
  2. // Start subactivity to actually install the application
  3. Intent newIntent = new Intent();
  4. newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
  5. mPkgInfo.applicationInfo);
  6. newIntent.setData(mPackageURI);
  7. newIntent.setClass(this, InstallInstalling.class);
  8. String installerPackageName = getIntent().getStringExtra(
  9. Intent.EXTRA_INSTALLER_PACKAGE_NAME);
  10. if (mOriginatingURI != null) {
  11. newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
  12. }
  13. if (mReferrerURI != null) {
  14. newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
  15. }
  16. if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
  17. newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
  18. }
  19. if (installerPackageName != null) {
  20. newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
  21. installerPackageName);
  22. }
  23. if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
  24. newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
  25. }
  26. newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
  27. if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
  28. startActivity(newIntent);
  29. finish();
  30. }

frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallInstalling.java

  1. @Override
  2. protected void onCreate(@Nullable Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. ApplicationInfo appInfo = getIntent()
  5. .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
  6. mPackageURI = getIntent().getData();
  7. if ("package".equals(mPackageURI.getScheme())) {
  8. try {
  9. getPackageManager().installExistingPackage(appInfo.packageName);
  10. launchSuccess();
  11. } catch (PackageManager.NameNotFoundException e) {
  12. launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
  13. }
  14. } else {
  15. //根据mPackageURI创建一个对应的File
  16. final File sourceFile = new File(mPackageURI.getPath());
  17. PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
  18. mAlert.setIcon(as.icon);
  19. mAlert.setTitle(as.label);
  20. mAlert.setView(R.layout.install_content_view);
  21. mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
  22. (ignored, ignored2) -> {
  23. if (mInstallingTask != null) {
  24. mInstallingTask.cancel(true);
  25. }
  26. if (mSessionId > 0) {
  27. getPackageManager().getPackageInstaller().abandonSession(mSessionId);
  28. mSessionId = 0;
  29. }
  30. setResult(RESULT_CANCELED);
  31. finish();
  32. }, null);
  33. setupAlert();
  34. requireViewById(R.id.installing).setVisibility(View.VISIBLE);
  35. //如果savedInstanceState不为null,获取此前保存的mSessionId和mInstallId
  36. if (savedInstanceState != null) {
  37. mSessionId = savedInstanceState.getInt(SESSION_ID);
  38. mInstallId = savedInstanceState.getInt(INSTALL_ID);
  39. // Reregister for result; might instantly call back if result was delivered while
  40. // activity was destroyed
  41. try {
  42. //向InstallEventReceiver注册一个观察者
  43. InstallEventReceiver.addObserver(this, mInstallId,
  44. this::launchFinishBasedOnResult);
  45. } catch (EventResultPersister.OutOfIdsException e) {
  46. // Does not happen
  47. }
  48. } else {
  49. PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
  50. PackageInstaller.SessionParams.MODE_FULL_INSTALL);
  51. params.setInstallAsInstantApp(false);
  52. params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
  53. params.setOriginatingUri(getIntent()
  54. .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
  55. params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
  56. UID_UNKNOWN));
  57. params.setInstallerPackageName(getIntent().getStringExtra(
  58. Intent.EXTRA_INSTALLER_PACKAGE_NAME));
  59. params.setInstallReason(PackageManager.INSTALL_REASON_USER);
  60. File file = new File(mPackageURI.getPath());
  61. try {
  62. PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
  63. params.setAppPackageName(pkg.packageName);
  64. params.setInstallLocation(pkg.installLocation);
  65. params.setSize(
  66. PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
  67. } catch (PackageParser.PackageParserException e) {
  68. Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.");
  69. Log.e(LOG_TAG,
  70. "Cannot calculate installed size " + file + ". Try only apk size.");
  71. params.setSize(file.length());
  72. } catch (IOException e) {
  73. Log.e(LOG_TAG,
  74. "Cannot calculate installed size " + file + ". Try only apk size.");
  75. params.setSize(file.length());
  76. }
  77. try {
  78. mInstallId = InstallEventReceiver
  79. .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
  80. this::launchFinishBasedOnResult);
  81. } catch (EventResultPersister.OutOfIdsException e) {
  82. launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
  83. }
  84. try {
  85. mSessionId = getPackageManager().getPackageInstaller().createSession(params);
  86. } catch (IOException e) {
  87. launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
  88. }
  89. }
  90. mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);
  91. mSessionCallback = new InstallSessionCallback();
  92. }
  93. }

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。

  1. @Override
  2. protected void onResume() {
  3. super.onResume();
  4. // This is the first onResume in a single life of the activity
  5. if (mInstallingTask == null) {
  6. PackageInstaller installer = getPackageManager().getPackageInstaller();
  7. PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
  8. if (sessionInfo != null && !sessionInfo.isActive()) {
  9. mInstallingTask = new InstallingAsyncTask();
  10. mInstallingTask.execute();
  11. } else {
  12. // we will receive a broadcast when the install is finished
  13. mCancelButton.setEnabled(false);
  14. setFinishOnTouchOutside(false);
  15. }
  16. }
  17. }

根据mSessionId得到SessionInfo,SessionInfo代表安装会话的详细信息。如果sessionInfo不为Null并且不是活动的,就创建并执行InstallingAsyncTask。InstallingAsyncTask的doInBackground方法中会根据包(APK)的Uri,将APK的信息通过IO流的形式写入到PackageInstaller.Session中 

onResune 启动InstallingAsyncTask 

  1. private final class InstallingAsyncTask extends AsyncTask<Void, Void,
  2. PackageInstaller.Session> {
  3. volatile boolean isDone;
  4. @Override
  5. protected PackageInstaller.Session doInBackground(Void... params) {
  6. PackageInstaller.Session session;
  7. try {
  8. session = getPackageManager().getPackageInstaller().openSession(mSessionId);
  9. } catch (IOException e) {
  10. return null;
  11. }
  12. session.setStagingProgress(0);
  13. try {
  14. File file = new File(mPackageURI.getPath());
  15. try (InputStream in = new FileInputStream(file)) {
  16. long sizeBytes = file.length();
  17. try (OutputStream out = session
  18. .openWrite("PackageInstaller", 0, sizeBytes)) {
  19. byte[] buffer = new byte[1024 * 1024];
  20. while (true) {
  21. int numRead = in.read(buffer);
  22. if (numRead == -1) {
  23. session.fsync(out);
  24. break;
  25. }
  26. if (isCancelled()) {
  27. session.close();
  28. break;
  29. }
  30. out.write(buffer, 0, numRead);
  31. if (sizeBytes > 0) {
  32. float fraction = ((float) numRead / (float) sizeBytes);
  33. session.addProgress(fraction);
  34. }
  35. }
  36. }
  37. }
  38. return session;
  39. } catch (IOException | SecurityException e) {
  40. Log.e(LOG_TAG, "Could not write package", e);
  41. session.close();
  42. return null;
  43. } finally {
  44. synchronized (this) {
  45. isDone = true;
  46. notifyAll();
  47. }
  48. }
  49. }
  50. @Override
  51. protected void onPostExecute(PackageInstaller.Session session) {
  52. if (session != null) {
  53. Intent broadcastIntent = new Intent(BROADCAST_ACTION);
  54. broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
  55. broadcastIntent.setPackage(getPackageName());
  56. broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
  57. PendingIntent pendingIntent = PendingIntent.getBroadcast(
  58. InstallInstalling.this,
  59. mInstallId,
  60. broadcastIntent,
  61. PendingIntent.FLAG_UPDATE_CURRENT);
  62. session.commit(pendingIntent.getIntentSender());
  63. mCancelButton.setEnabled(false);
  64. setFinishOnTouchOutside(false);
  65. } else {
  66. getPackageManager().getPackageInstaller().abandonSession(mSessionId);
  67. if (!isCancelled()) {
  68. launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
  69. }
  70. }
  71. }
  72. }

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

frameworks\base\core\java\android\content\pm\PackageInstaller.java

  1. protected final IPackageInstallerSession mSession;
  2. public void commit(@NonNull IntentSender statusReceiver) {
  3. try {
  4. mSession.commit(statusReceiver, false);
  5. } catch (RemoteException e) {
  6. throw e.rethrowFromSystemServer();
  7. }
  8. }

mSession的类型为IPackageInstallerSession,这说明要通过IPackageInstallerSession来进行进程间的通信,最终会调用PackageInstallerSession的commit方法

frameworks\base\services\core\java\com\android\server\pm\PackageInstallerSession.java

  1. @Override
  2. public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
  3. if (hasParentSessionId()) {
  4. throw new IllegalStateException(
  5. "Session " + sessionId + " is a child of multi-package session "
  6. + mParentSessionId + " and may not be committed directly.");
  7. }
  8. if (!markAsSealed(statusReceiver, forTransfer)) {
  9. return;
  10. }
  11. if (isMultiPackage()) {
  12. final SparseIntArray remainingSessions = mChildSessionIds.clone();
  13. final IntentSender childIntentSender =
  14. new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
  15. .getIntentSender();
  16. boolean sealFailed = false;
  17. for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
  18. final int childSessionId = mChildSessionIds.keyAt(i);
  19. // seal all children, regardless if any of them fail; we'll throw/return
  20. // as appropriate once all children have been processed
  21. if (!mSessionProvider.getSession(childSessionId)
  22. .markAsSealed(childIntentSender, forTransfer)) {
  23. sealFailed = true;
  24. }
  25. }
  26. if (sealFailed) {
  27. return;
  28. }
  29. }
  30. dispatchStreamValidateAndCommit();
  31. }
  1. private void dispatchStreamValidateAndCommit() {
  2. mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
  3. }
  4. private void handleStreamValidateAndCommit() {
  5. PackageManagerException unrecoverableFailure = null;
  6. // This will track whether the session and any children were validated and are ready to
  7. // progress to the next phase of install
  8. boolean allSessionsReady = false;
  9. try {
  10. allSessionsReady = streamValidateAndCommit();
  11. } catch (PackageManagerException e) {
  12. unrecoverableFailure = e;
  13. }
  14. if (isMultiPackage()) {
  15. int childCount = mChildSessionIds.size();
  16. // This will contain all child sessions that do not encounter an unrecoverable failure
  17. ArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount);
  18. for (int i = childCount - 1; i >= 0; --i) {
  19. final int childSessionId = mChildSessionIds.keyAt(i);
  20. // commit all children, regardless if any of them fail; we'll throw/return
  21. // as appropriate once all children have been processed
  22. try {
  23. PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
  24. allSessionsReady &= session.streamValidateAndCommit();
  25. nonFailingSessions.add(session);
  26. } catch (PackageManagerException e) {
  27. allSessionsReady = false;
  28. if (unrecoverableFailure == null) {
  29. unrecoverableFailure = e;
  30. }
  31. }
  32. }
  33. // If we encountered any unrecoverable failures, destroy all other sessions including
  34. // the parent
  35. if (unrecoverableFailure != null) {
  36. // {@link #streamValidateAndCommit()} calls
  37. // {@link #onSessionVerificationFailure(PackageManagerException)}, but we don't
  38. // expect it to ever do so for parent sessions. Call that on this parent to clean
  39. // it up and notify listeners of the error.
  40. onSessionVerificationFailure(unrecoverableFailure);
  41. // fail other child sessions that did not already fail
  42. for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
  43. PackageInstallerSession session = nonFailingSessions.get(i);
  44. session.onSessionVerificationFailure(unrecoverableFailure);
  45. }
  46. }
  47. }
  48. if (!allSessionsReady) {
  49. return;
  50. }
  51. mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
  52. }
  1. private void handleInstall() {
  2. if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
  3. DevicePolicyEventLogger
  4. .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
  5. .setAdmin(mInstallSource.installerPackageName)
  6. .write();
  7. }
  8. if (params.isStaged) {
  9. mStagingManager.commitSession(this);
  10. destroyInternal();
  11. dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
  12. return;
  13. }
  14. if (isApexInstallation()) {
  15. destroyInternal();
  16. dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
  17. "APEX packages can only be installed using staged sessions.", null);
  18. return;
  19. }
  20. // For a multiPackage session, read the child sessions
  21. // outside of the lock, because reading the child
  22. // sessions with the lock held could lead to deadlock
  23. // (b/123391593).
  24. List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
  25. try {
  26. synchronized (mLock) {
  27. installNonStagedLocked(childSessions);
  28. }
  29. } catch (PackageManagerException e) {
  30. final String completeMsg = ExceptionUtils.getCompleteMessage(e);
  31. Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
  32. destroyInternal();
  33. dispatchSessionFinished(e.error, completeMsg, null);
  34. }
  35. }
  1. @GuardedBy("mLock")
  2. private void installNonStagedLocked(List<PackageInstallerSession> childSessions)
  3. throws PackageManagerException {
  4. final PackageManagerService.ActiveInstallSession installingSession =
  5. makeSessionActiveLocked();
  6. if (installingSession == null) {
  7. return;
  8. }
  9. if (isMultiPackage()) {
  10. List<PackageManagerService.ActiveInstallSession> installingChildSessions =
  11. new ArrayList<>(childSessions.size());
  12. boolean success = true;
  13. PackageManagerException failure = null;
  14. for (int i = 0; i < childSessions.size(); ++i) {
  15. final PackageInstallerSession session = childSessions.get(i);
  16. try {
  17. final PackageManagerService.ActiveInstallSession installingChildSession =
  18. session.makeSessionActiveLocked();
  19. if (installingChildSession != null) {
  20. installingChildSessions.add(installingChildSession);
  21. }
  22. } catch (PackageManagerException e) {
  23. failure = e;
  24. success = false;
  25. }
  26. }
  27. if (!success) {
  28. sendOnPackageInstalled(mContext, mRemoteStatusReceiver, sessionId,
  29. isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
  30. failure.error, failure.getLocalizedMessage(), null);
  31. return;
  32. }
  33. mPm.installStage(installingChildSessions);
  34. } else {
  35. mPm.installStage(installingSession);
  36. }
  37. }

调用 mPm的installStage方法

private final PackageManagerService mPm;

frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java

  1. void installStage(ActiveInstallSession activeInstallSession) {
  2. if (DEBUG_INSTANT) {
  3. if ((activeInstallSession.getSessionParams().installFlags
  4. & PackageManager.INSTALL_INSTANT_APP) != 0) {
  5. Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
  6. }
  7. }
  8. final Message msg = mHandler.obtainMessage(INIT_COPY);
  9. final InstallParams params = new InstallParams(activeInstallSession);
  10. params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
  11. msg.obj = params;
  12. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
  13. System.identityHashCode(msg.obj));
  14. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
  15. System.identityHashCode(msg.obj));
  16. mHandler.sendMessage(msg);
  17. }

创建InstallParams,它对应于包的安装数据

  1. void doHandleMessage(Message msg) {
  2. switch (msg.what) {
  3. case INIT_COPY: {
  4. HandlerParams params = (HandlerParams) msg.obj;
  5. if (params != null) {
  6. if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
  7. Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
  8. System.identityHashCode(params));
  9. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
  10. params.startCopy();
  11. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  12. }
  13. break;
  14. }

params.startCopy();

params是HandlerParams类 

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

具体实现在 InstallParams里 是PackageManagerService的内部类

    class InstallParams extends HandlerParams {

  1. public void handleStartCopy() {
  2. int ret = PackageManager.INSTALL_SUCCEEDED;
  3. // If we're already staged, we've firmly committed to an install location
  4. if (origin.staged) {
  5. if (origin.file != null) {
  6. installFlags |= PackageManager.INSTALL_INTERNAL;
  7. } else {
  8. throw new IllegalStateException("Invalid stage location");
  9. }
  10. }
  11. //确定APK的安装位置。 onInt:内部存储即Data分区,ephemeral:安装到临时存储(Instant Apps安装)
  12. final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
  13. final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
  14. PackageInfoLite pkgLite = null;
  15. //获取APK的少量的信息
  16. pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
  17. origin.resolvedPath, installFlags, packageAbiOverride);
  18. if (DEBUG_INSTANT && ephemeral) {
  19. Slog.v(TAG, "pkgLite for install: " + pkgLite);
  20. }
  21. /*
  22. * If we have too little free space, try to free cache
  23. * before giving up.
  24. */
  25. if (!origin.staged && pkgLite.recommendedInstallLocation
  26. == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
  27. // TODO: focus freeing disk space on the target device
  28. final StorageManager storage = StorageManager.from(mContext);
  29. final long lowThreshold = storage.getStorageLowBytes(
  30. Environment.getDataDirectory());
  31. final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
  32. origin.resolvedPath, packageAbiOverride);
  33. if (sizeBytes >= 0) {
  34. try {
  35. mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
  36. pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
  37. origin.resolvedPath, installFlags, packageAbiOverride);
  38. } catch (InstallerException e) {
  39. Slog.w(TAG, "Failed to free cache", e);
  40. }
  41. }
  42. /*
  43. * The cache free must have deleted the file we downloaded to install.
  44. *
  45. * TODO: fix the "freeCache" call to not delete the file we care about.
  46. */
  47. if (pkgLite.recommendedInstallLocation
  48. == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
  49. pkgLite.recommendedInstallLocation
  50. = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
  51. }
  52. }
  53. if (ret == PackageManager.INSTALL_SUCCEEDED) {
  54. //判断安装的位置
  55. int loc = pkgLite.recommendedInstallLocation;
  56. if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
  57. ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
  58. } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
  59. ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
  60. } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
  61. ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
  62. } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
  63. ret = PackageManager.INSTALL_FAILED_INVALID_APK;
  64. } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
  65. ret = PackageManager.INSTALL_FAILED_INVALID_URI;
  66. } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
  67. ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
  68. } else {
  69. // Override with defaults if needed.
  70. loc = installLocationPolicy(pkgLite);
  71. if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
  72. ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
  73. } else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
  74. ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
  75. } else if (!onInt) {
  76. // Override install location with flags
  77. if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
  78. // Set the flag to install on external media.
  79. installFlags &= ~PackageManager.INSTALL_INTERNAL;
  80. } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
  81. if (DEBUG_INSTANT) {
  82. Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
  83. }
  84. installFlags |= PackageManager.INSTALL_INSTANT_APP;
  85. installFlags &= ~PackageManager.INSTALL_INTERNAL;
  86. } else {
  87. // Make sure the flag for installing on external
  88. // media is unset
  89. installFlags |= PackageManager.INSTALL_INTERNAL;
  90. }
  91. }
  92. }
  93. }
  94. //根据InstallParams创建InstallArgs对象
  95. final InstallArgs args = createInstallArgs(this);
  96. mVerificationCompleted = true;
  97. mIntegrityVerificationCompleted = true;
  98. mEnableRollbackCompleted = true;
  99. mArgs = args;
  100. if (ret == PackageManager.INSTALL_SUCCEEDED) {
  101. final int verificationId = mPendingVerificationToken++;
  102. // Perform package verification (unless we are simply moving the package).
  103. if (!origin.existing) {
  104. PackageVerificationState verificationState =
  105. new PackageVerificationState(this);
  106. mPendingVerification.append(verificationId, verificationState);
  107. sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
  108. ret = sendPackageVerificationRequest(
  109. verificationId, pkgLite, verificationState);
  110. // If both verifications are skipped, we should remove the state.
  111. if (verificationState.areAllVerificationsComplete()) {
  112. mPendingVerification.remove(verificationId);
  113. }
  114. }
  115. if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
  116. // TODO(ruhler) b/112431924: Don't do this in case of 'move'?
  117. final int enableRollbackToken = mPendingEnableRollbackToken++;
  118. Trace.asyncTraceBegin(
  119. TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
  120. mPendingEnableRollback.append(enableRollbackToken, this);
  121. Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
  122. enableRollbackIntent.putExtra(
  123. PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
  124. enableRollbackToken);
  125. enableRollbackIntent.putExtra(
  126. PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
  127. mSessionId);
  128. enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
  129. enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  130. // Allow the broadcast to be sent before boot complete.
  131. // This is needed when committing the apk part of a staged
  132. // session in early boot. The rollback manager registers
  133. // its receiver early enough during the boot process that
  134. // it will not miss the broadcast.
  135. enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
  136. mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
  137. android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
  138. new BroadcastReceiver() {
  139. @Override
  140. public void onReceive(Context context, Intent intent) {
  141. // the duration to wait for rollback to be enabled, in millis
  142. long rollbackTimeout = DeviceConfig.getLong(
  143. DeviceConfig.NAMESPACE_ROLLBACK,
  144. PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
  145. DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
  146. if (rollbackTimeout < 0) {
  147. rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
  148. }
  149. final Message msg = mHandler.obtainMessage(
  150. ENABLE_ROLLBACK_TIMEOUT);
  151. msg.arg1 = enableRollbackToken;
  152. msg.arg2 = mSessionId;
  153. mHandler.sendMessageDelayed(msg, rollbackTimeout);
  154. }
  155. }, null, 0, null, null);
  156. mEnableRollbackCompleted = false;
  157. }
  158. }
  159. mRet = ret;
  160. }

 InstallArgs 是一个抽象类,定义了APK的安装逻辑,比如复制和重命名APK等,

其中FileInstallArgs用于处理安装到非ASEC的存储空间的APK,也就是内部存储空间(Data分区)

MoveInstallArgs用于处理已安装APK的移动的逻辑。

  1. static abstract class InstallArgs {
  2. class FileInstallArgs extends InstallArgs {
  3. class MoveInstallArgs extends InstallArgs {
  1. @Override
  2. void handleReturnCode() {
  3. if (mVerificationCompleted
  4. && mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
  5. if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
  6. String packageName = "";
  7. ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
  8. new ParseTypeImpl(
  9. (changeId, packageName1, targetSdkVersion) -> {
  10. ApplicationInfo appInfo = new ApplicationInfo();
  11. appInfo.packageName = packageName1;
  12. appInfo.targetSdkVersion = targetSdkVersion;
  13. return mPackageParserCallback.isChangeEnabled(changeId,
  14. appInfo);
  15. }).reset(),
  16. origin.file, 0);
  17. if (result.isError()) {
  18. Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(),
  19. result.getException());
  20. } else {
  21. packageName = result.getResult().packageName;
  22. }
  23. try {
  24. observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
  25. } catch (RemoteException e) {
  26. Slog.i(TAG, "Observer no longer exists.");
  27. }
  28. return;
  29. }
  30. if (mRet == PackageManager.INSTALL_SUCCEEDED) {
  31. mRet = mArgs.copyApk();
  32. }
  33. processPendingInstall(mArgs, mRet);
  34. }
  35. }

mArgs.copyApk();

private InstallArgs mArgs;

  1. int copyApk() {
  2. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
  3. try {
  4. return doCopyApk();
  5. } finally {
  6. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  7. }
  8. }
  9. private int doCopyApk() {
  10. if (origin.staged) {
  11. if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
  12. codeFile = origin.file;
  13. resourceFile = origin.file;
  14. return PackageManager.INSTALL_SUCCEEDED;
  15. }
  16. try {
  17. final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
  18. //创建临时文件存储目录
  19. final File tempDir =
  20. mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
  21. codeFile = tempDir;
  22. resourceFile = tempDir;
  23. } catch (IOException e) {
  24. Slog.w(TAG, "Failed to create copy file: " + e);
  25. return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
  26. }
  27. 将APK复制到临时存储目录
  28. int ret = PackageManagerServiceUtils.copyPackage(
  29. origin.file.getAbsolutePath(), codeFile);
  30. if (ret != PackageManager.INSTALL_SUCCEEDED) {
  31. Slog.e(TAG, "Failed to copy package");
  32. return ret;
  33. }
  34. final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath());
  35. final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
  36. NativeLibraryHelper.Handle handle = null;
  37. try {
  38. handle = NativeLibraryHelper.Handle.create(codeFile);
  39. ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
  40. abiOverride, isIncremental);
  41. } catch (IOException e) {
  42. Slog.e(TAG, "Copying native libraries failed", e);
  43. ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
  44. } finally {
  45. IoUtils.closeQuietly(handle);
  46. }
  47. return ret;
  48. }

 processPendingInstall(mArgs, mRet);

  1. private void processPendingInstall(final InstallArgs args, final int currentStatus) {
  2. if (args.mMultiPackageInstallParams != null) {
  3. args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
  4. } else {
  5. PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
  6. processInstallRequestsAsync(
  7. res.returnCode == PackageManager.INSTALL_SUCCEEDED,
  8. Collections.singletonList(new InstallRequest(args, res)));
  9. }
  10. }
  1. // Queue up an async operation since the package installation may take a little while.
  2. private void processInstallRequestsAsync(boolean success,
  3. List<InstallRequest> installRequests) {
  4. mHandler.post(() -> {
  5. if (success) {
  6. for (InstallRequest request : installRequests) {
  7. 安装前
  8. request.args.doPreInstall(request.installResult.returnCode);
  9. }
  10. synchronized (mInstallLock) {
  11. 安装中
  12. installPackagesTracedLI(installRequests);
  13. }
  14. for (InstallRequest request : installRequests) {
  15. 安装后
  16. request.args.doPostInstall(
  17. request.installResult.returnCode, request.installResult.uid);
  18. }
  19. }
  20. for (InstallRequest request : installRequests) {
  21. restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
  22. new PostInstallData(request.args, request.installResult, null));
  23. }
  24. });
  25. }
  1. private PackageInstalledInfo createPackageInstalledInfo(
  2. int currentStatus) {
  3. PackageInstalledInfo res = new PackageInstalledInfo();
  4. res.setReturnCode(currentStatus);
  5. res.uid = -1;
  6. res.pkg = null;
  7. res.removedInfo = null;
  8. return res;
  9. }
  1.     @GuardedBy({"mInstallLock", "mLock"})
  2.     private void installPackagesTracedLI(List<InstallRequest> requests) {
  3.         try {
  4.             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
  5.             installPackagesLI(requests);
  6.         } finally {
  7.             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  8.         }
  9.     }

 

  1. private void installPackagesLI(List<InstallRequest> requests) {
  2. final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
  3. final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
  4. final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
  5. final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
  6. final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
  7. final Map<String, PackageSetting> lastStaticSharedLibSettings =
  8. new ArrayMap<>(requests.size());
  9. final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
  10. boolean success = false;
  11. try {
  12. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
  13. for (InstallRequest request : requests) {
  14. // TODO(b/109941548): remove this once we've pulled everything from it and into
  15. // scan, reconcile or commit.
  16. final PrepareResult prepareResult;
  17. try {
  18. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
  19. prepareResult =
  20. preparePackageLI(request.args, request.installResult);
  21. } catch (PrepareFailure prepareFailure) {
  22. request.installResult.setError(prepareFailure.error,
  23. prepareFailure.getMessage());
  24. request.installResult.origPackage = prepareFailure.conflictingPackage;
  25. request.installResult.origPermission = prepareFailure.conflictingPermission;
  26. return;
  27. } finally {
  28. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  29. }
  30. request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
  31. request.installResult.installerPackageName =
  32. request.args.installSource.installerPackageName;
  33. final String packageName = prepareResult.packageToScan.getPackageName();
  34. prepareResults.put(packageName, prepareResult);
  35. installResults.put(packageName, request.installResult);
  36. installArgs.put(packageName, request.args);
  37. try {
  38. final ScanResult result = scanPackageTracedLI(
  39. prepareResult.packageToScan, prepareResult.parseFlags,
  40. prepareResult.scanFlags, System.currentTimeMillis(),
  41. request.args.user, request.args.abiOverride);
  42. if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {
  43. request.installResult.setError(
  44. PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
  45. "Duplicate package " + result.pkgSetting.pkg.getPackageName()
  46. + " in multi-package install request.");
  47. return;
  48. }
  49. createdAppId.put(packageName, optimisticallyRegisterAppId(result));
  50. versionInfos.put(result.pkgSetting.pkg.getPackageName(),
  51. getSettingsVersionForPackage(result.pkgSetting.pkg));
  52. if (result.staticSharedLibraryInfo != null) {
  53. final PackageSetting sharedLibLatestVersionSetting =
  54. getSharedLibLatestVersionSetting(result);
  55. if (sharedLibLatestVersionSetting != null) {
  56. lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),
  57. sharedLibLatestVersionSetting);
  58. }
  59. }
  60. } catch (PackageManagerException e) {
  61. request.installResult.setError("Scanning Failed.", e);
  62. return;
  63. }
  64. }
  65. ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
  66. installResults,
  67. prepareResults,
  68. mSharedLibraries,
  69. Collections.unmodifiableMap(mPackages), versionInfos,
  70. lastStaticSharedLibSettings);
  71. CommitRequest commitRequest = null;
  72. synchronized (mLock) {
  73. Map<String, ReconciledPackage> reconciledPackages;
  74. try {
  75. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
  76. reconciledPackages = reconcilePackagesLocked(
  77. reconcileRequest, mSettings.mKeySetManagerService);
  78. } catch (ReconcileFailure e) {
  79. for (InstallRequest request : requests) {
  80. request.installResult.setError("Reconciliation failed...", e);
  81. }
  82. return;
  83. } finally {
  84. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  85. }
  86. try {
  87. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
  88. commitRequest = new CommitRequest(reconciledPackages,
  89. mUserManager.getUserIds());
  90. commitPackagesLocked(commitRequest);
  91. success = true;
  92. } finally {
  93. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  94. }
  95. }
  96. executePostCommitSteps(commitRequest);
  97. } finally {
  98. if (success) {
  99. for (InstallRequest request : requests) {
  100. final InstallArgs args = request.args;
  101. if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
  102. continue;
  103. }
  104. if (args.signingDetails.signatureSchemeVersion != SIGNING_BLOCK_V4) {
  105. continue;
  106. }
  107. // For incremental installs, we bypass the verifier prior to install. Now
  108. // that we know the package is valid, send a notice to the verifier with
  109. // the root hash of the base.apk.
  110. final String baseCodePath = request.installResult.pkg.getBaseCodePath();
  111. final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths();
  112. final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
  113. final int verificationId = mPendingVerificationToken++;
  114. final String rootHashString = PackageManagerServiceUtils
  115. .buildVerificationRootHashString(baseCodePath, splitCodePaths);
  116. broadcastPackageVerified(verificationId, originUri,
  117. PackageManager.VERIFICATION_ALLOW, rootHashString,
  118. args.mDataLoaderType, args.getUser());
  119. }
  120. } else {
  121. for (ScanResult result : preparedScans.values()) {
  122. if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),
  123. false)) {
  124. cleanUpAppIdCreation(result);
  125. }
  126. }
  127. // TODO(patb): create a more descriptive reason than unknown in future release
  128. // mark all non-failure installs as UNKNOWN so we do not treat them as success
  129. for (InstallRequest request : requests) {
  130. if (request.installResult.freezer != null) {
  131. request.installResult.freezer.close();
  132. }
  133. if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
  134. request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
  135. }
  136. }
  137. }
  138. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
  139. }
  140. }

executePostCommitSteps执行安装

installPackageLI方法的代码有将近500行,这里截取主要的部分,主要做了几件事:

  1. 创建PackageParser解析APK。
  2. 检查APK是否存在,如果存在就获取此前没被改名前的包名并在注释1处赋值给PackageParser.Package类型的pkg,在注释3处将标志位replace置为true表示是替换安装。
  3. 注释3处,如果Settings中保存有要安装的APK的信息,说明此前安装过该APK,则需要校验APK的签名信息,确保安全的进行替换。
  4. 在注释4处将临时文件重新命名,比如前面提到的/data/app/vmdl18300388.tmp/base.apk,重命名为/data/app/包名-1/base.apk。这个新命名的包名会带上一个数字后缀1,每次升级一个已有的App,这个数字会不断的累加。
  5. 系统APP的更新安装会有两个限制,一个是系统APP不能在SD卡上替换安装,另一个是系统APP不能被Instant App替换。
  6. 注释5处根据replace来做区分,如果是替换安装就会调用replacePackageLIF方法,其方法内部还会对系统APP和非系统APP进行区分处理,如果是新安装APK会调用installNewPackageLIF方法。

installNewPackageLIF主要做了以下3件事:

  1. 扫描APK,将APK的信息存储在PackageParser.Package类型的newPackage中,一个Package的信息包含了1个base APK以及0个或者多个split APK。
  2. 更新该APK对应的Settings信息,Settings用于保存所有包的动态设置。
  3. 如果安装成功就为新安装的应用程序准备数据,安装失败就删除APK。

安装APK的过程就讲到这里,就不再往下分析下去,有兴趣的同学可以接着深挖。

**4.总结 **

本文主要讲解了PMS是如何处理APK安装的,主要有几个步骤:

  1. PackageInstaller安装APK时会将APK的信息交由PMS处理,PMS通过向PackageHandler发送消息来驱动APK的复制和安装工作。
  2. PMS发送INIT_COPY和MCS_BOUND类型的消息,控制PackageHandler来绑定DefaultContainerService,完成复制APK等工作。
  3. 复制APK完成后,会开始进行安装APK的流程,包括安装前的检查、安装APK和安装后的收尾工作。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/283739
推荐阅读