• Android—PMS: PackageInstaller到PMS


    PackageManager

    与ActivityManager和AMS的关系类似,PMS也有一个对应的管理类PackageManager,用于向应用程序进程提供一些功能。PackageManager是一个抽象类,它的具体实现类为ApplicationPackageManager,ApplicationPackageManager中的方法会通过IPackageManager与PMS进行进程间通信,因此PackageManager所提供的功能最终是由PMS来实现的,这么设计的主要用意是为了避免系统服务PMS直接被访问。PackageManager提供了一些功能,主要有以下几点:

    1. 获取一个应用程序的所有信息(ApplicationInfo)。
    2. 解析manifest.xml文件,查询permission相关信息。
    3. 获取包的信息。
    4. 安装、卸载APK.

    这里分析点击安装包的情况:

    跳转到PackageInstaller应用

    1. Intent intent = new Intent(Intent.ACTION_VIEW);
    2. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    3. if (Build.VERSION.SDK_INT >= 24) { //7.0新跳转
    4. Uri apkUri = FileProvider.getUriForFile(paramContext, "com.xxx.xxx.xxx", file);
    5. intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    6. intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
    7. } else {
    8. intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
    9. }

    application/vnd.android.package-archive对应文件类型apk

     PackageInstaller的AndroidManifest.xml

    1. <activity android:name=".InstallStart"
    2. android:exported="true"
    3. android:excludeFromRecents="true">
    4. <intent-filter android:priority="1">
    5. <action android:name="android.intent.action.VIEW" />
    6. <action android:name="android.intent.action.INSTALL_PACKAGE" />
    7. <category android:name="android.intent.category.DEFAULT" />
    8. <data android:scheme="file" />
    9. <data android:scheme="content" />
    10. <data android:mimeType="application/vnd.android.package-archive" />
    11. intent-filter>
    12. ...
    13. activity>

    注意 action与mimeType与Intent参数对应,到InstallStart页面

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

    1. @Override
    2. protected void onCreate(@Nullable Bundle savedInstanceState) {
    3. super.onCreate(savedInstanceState);
    4. mIPackageManager = AppGlobals.getPackageManager();
    5. Intent intent = getIntent();
    6. String callingPackage = getCallingPackage();
    7. final boolean isSessionInstall =
    8. PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
    9. // If the activity was started via a PackageInstaller session, we retrieve the calling
    10. // package from that session
    11. final int sessionId = (isSessionInstall
    12. ? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
    13. : -1);
    14. .....
    15. //获取应用信息
    16. final ApplicationInfo sourceInfo = getSourceInfo(callingPackage);
    17. final int originatingUid = getOriginatingUid(sourceInfo);
    18. boolean isTrustedSource = false;
    19. if (sourceInfo != null
    20. && (sourceInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
    21. isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false);
    22. }
    23. ....
    24. Intent nextActivity = new Intent(intent);
    25. nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
    26. // The the installation source as the nextActivity thinks this activity is the source, hence
    27. // set the originating UID and sourceInfo explicitly
    28. nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_PACKAGE, callingPackage);
    29. nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
    30. nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);
    31. //这里为false
    32. if (isSessionInstall) {
    33. nextActivity.setClass(this, PackageInstallerActivity.class);
    34. } else {
    35. Uri packageUri = intent.getData();
    36. // 判断Uri的Scheme协议是否是content
    37. if (packageUri != null && packageUri.getScheme().equals(
    38. ContentResolver.SCHEME_CONTENT)) {
    39. nextActivity.setClass(this, InstallStaging.class);
    40. } else if (packageUri != null && packageUri.getScheme().equals(
    41. PackageInstallerActivity.SCHEME_PACKAGE)) {
    42. nextActivity.setClass(this, PackageInstallerActivity.class);
    43. } else {
    44. Intent result = new Intent();
    45. result.putExtra(Intent.EXTRA_INSTALL_RESULT,
    46. PackageManager.INSTALL_FAILED_INVALID_URI);
    47. setResult(RESULT_FIRST_USER, result);
    48. nextActivity = null;
    49. }
    50. }
    51. if (nextActivity != null) {
    52. startActivity(nextActivity);
    53. }
    54. finish();
    55. }

    这里是安卓10的源码,需要用到FileProvider,所以会走到 

    nextActivity.setClass(this, InstallStaging.class);

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

    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. mStagedFile = TemporaryFileManager.getStagedFile(this);
    11. } catch (IOException e) {
    12. showError();
    13. return;
    14. }
    15. }
    16. mStagingTask = new StagingAsyncTask();
    17. mStagingTask.execute(getIntent().getData());
    18. }
    19. }

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

    1.     @NonNull
    2.     public static File getStagedFile(@NonNull Context context) throws IOException {
    3.         return File.createTempFile("package", ".apk", context.getNoBackupFilesDir());
    4.     }

     mStagedFile是一个叫package.apk的File对象

    1. private final class StagingAsyncTask extends AsyncTask {
    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. }

    StagingAsyncTask工作:
    1.doInBackground 把uri中需要安装的apk拷贝到临时文件中/data/no_backup/package.apk
    2.onPostExecute 当拷贝任务处理完之后,就会把当前的临时文件Uri作为Intent的参数(这个时候会把Uri的类型设置为file),跳转到DeleteStagedFileOnResult中。

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

    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是个过度,负责跳转后删除package.apk

    APK的安装Activity:PackageInstallerActivity

    1. @Override
    2. protected void onCreate(Bundle icicle) {
    3. getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    4. super.onCreate(null);
    5. mPm = getPackageManager();
    6. mIpm = AppGlobals.getPackageManager();
    7. mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
    8. mInstaller = mPm.getPackageInstaller();
    9. mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
    10. ....
    11. boolean wasSetUp = processPackageUri(packageUri);
    12. if (!wasSetUp) {
    13. return;
    14. }
    15. // load dummy layout with OK button disabled until we override this layout in
    16. // startInstallConfirm
    17. bindUi();
    18. checkIfAllowedAndInitiateInstall();
    19. }
    • PackageManager 用于向应用程序进程提供一些功能,最终的功能是由PMS来实现的 
    • AppOpsManager 用于权限动态检测,在Android4.3中被引入
    • PackageInstaller 提供安装、升级和删除应用程序功能
    • UserManager 用于多用户管理

    1.processPackageUri(packageUri);

    1. /**
    2. * **解析Uri并设置此包的安装程序。
    3. *
    4. * @param packageUri The URI to parse
    5. *
    6. * @return {@code true} 如果安装程序可以设置
    7. */
    8. private boolean processPackageUri(final Uri packageUri) {
    9. mPackageURI = packageUri;
    10. final String scheme = packageUri.getScheme();
    11. switch (scheme) {
    12. case SCHEME_PACKAGE: {
    13. ....
    14. } break;
    15. case ContentResolver.SCHEME_FILE: {
    16. File sourceFile = new File(packageUri.getPath());
    17. PackageParser.Package parsed = PackageUtil.getPackageInfo(this, sourceFile);
    18. // Check for parse errors
    19. if (parsed == null) {
    20. Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
    21. showDialogInner(DLG_PACKAGE_ERROR);
    22. setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
    23. return false;
    24. }
    25. mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
    26. PackageManager.GET_PERMISSIONS, 0, 0, null,
    27. new PackageUserState());
    28. mAppSnippet = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
    29. } break;
    30. default: {
    31. throw new IllegalArgumentException("Unexpected URI scheme " + packageUri);
    32. }
    33. }
    34. return true;
    35. }

    前面apk的数据已经用

    installIntent.setData(Uri.fromFile(mStagedFile));

    传到PackageInstallerActivity了,所以这里走的是file。

    processPackageUri解析uri获取

    1. mPkgInfo,主要获取Permission相关信息。
    2. mAppSnippet,应用label名,没有定义则用应用包名

    2.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. startInstall();
    13. }
    14. }
    15. }, null);
    16. mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
    17. (ignored, ignored2) -> {
    18. // Cancel and finish
    19. setResult(RESULT_CANCELED);
    20. if (mSessionId != -1) {
    21. mInstaller.setPermissionsResult(mSessionId, false);
    22. }
    23. finish();
    24. }, null);
    25. setupAlert();
    26. mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
    27. mOk.setEnabled(false);
    28. }

     bindUI()就是给弹出来的安装界面设置UI,然后为安装和取消两个按钮设置点击事件。安装按钮的点击事件是startInstall();

    3.checkIfAllowedAndInitiateInstall()

    1. private void checkIfAllowedAndInitiateInstall() {
    2. // Check for install apps user restriction first.
    3. final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource(
    4. UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle());
    5. if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
    6. showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER);
    7. return;
    8. } else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
    9. startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
    10. finish();
    11. return;
    12. }
    13. if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
    14. initiateInstall();
    15. } else {
    16. // Check for unknown sources restrictions.
    17. final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(
    18. UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle());
    19. final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource(
    20. UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle());
    21. final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM
    22. & (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
    23. if (systemRestriction != 0) {
    24. showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
    25. } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
    26. startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
    27. } else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
    28. startAdminSupportDetailsActivity(
    29. UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
    30. } else {
    31. handleUnknownSources();
    32. }
    33. }
    34. }

    这个方法作用就如名字所示了,检查应用权限,还有就是是否是未知来源安装包。

    主要看initiateInstall();

    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. }
    26. private void startInstallConfirm() {
    27. View viewToEnable;
    28. if (mAppInfo != null) {
    29. viewToEnable = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
    30. ? requireViewById(R.id.install_confirm_question_update_system)
    31. : requireViewById(R.id.install_confirm_question_update);
    32. } else {
    33. // This is a new application with no permissions.
    34. viewToEnable = requireViewById(R.id.install_confirm_question);
    35. }
    36. viewToEnable.setVisibility(View.VISIBLE);
    37. mEnableOk = true;
    38. mOk.setEnabled(true);
    39. }

    mOk.setEnabled(true);这里让界面的安装按钮可点击。

    onCreate就分析完了,接下来看点击安装按钮的点击事件startInstall()。

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

    startInstall方法用于跳转到InstallInstalling这个Activity,并关闭掉当前的PackageInstallerActivity。

    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. //这里为false
    8. if ("package".equals(mPackageURI.getScheme())) {
    9. .....
    10. } else {
    11. final File sourceFile = new File(mPackageURI.getPath());
    12. PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
    13. mAlert.setIcon(as.icon);
    14. mAlert.setTitle(as.label);
    15. mAlert.setView(R.layout.install_content_view);
    16. mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
    17. (ignored, ignored2) -> {
    18. if (mInstallingTask != null) {
    19. mInstallingTask.cancel(true);
    20. }
    21. if (mSessionId > 0) {
    22. getPackageManager().getPackageInstaller().abandonSession(mSessionId);
    23. mSessionId = 0;
    24. }
    25. setResult(RESULT_CANCELED);
    26. finish();
    27. }, null);
    28. setupAlert();
    29. requireViewById(R.id.installing).setVisibility(View.VISIBLE);
    30. if (savedInstanceState != null) {
    31. ....
    32. } else {
    33. PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
    34. PackageInstaller.SessionParams.MODE_FULL_INSTALL);
    35. params.setInstallAsInstantApp(false);
    36. params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
    37. params.setOriginatingUri(getIntent()
    38. .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
    39. params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
    40. UID_UNKNOWN));
    41. params.setInstallerPackageName(getIntent().getStringExtra(
    42. Intent.EXTRA_INSTALLER_PACKAGE_NAME));
    43. params.setInstallReason(PackageManager.INSTALL_REASON_USER);
    44. File file = new File(mPackageURI.getPath());
    45. try {
    46. PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
    47. params.setAppPackageName(pkg.packageName);
    48. params.setInstallLocation(pkg.installLocation);
    49. params.setSize(
    50. PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
    51. } catch (PackageParser.PackageParserException e) {
    52. Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.");
    53. Log.e(LOG_TAG,
    54. "Cannot calculate installed size " + file + ". Try only apk size.");
    55. params.setSize(file.length());
    56. } catch (IOException e) {
    57. Log.e(LOG_TAG,
    58. "Cannot calculate installed size " + file + ". Try only apk size.");
    59. params.setSize(file.length());
    60. }
    61. try {
    62. mInstallId = InstallEventReceiver
    63. .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
    64. this::launchFinishBasedOnResult);
    65. } catch (EventResultPersister.OutOfIdsException e) {
    66. launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
    67. }
    68. try {
    69. mSessionId = getPackageManager().getPackageInstaller().createSession(params);
    70. } catch (IOException e) {
    71. launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
    72. }
    73. }
    74. mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);
    75. mSessionCallback = new InstallSessionCallback();
    76. }
    77. }

    解析pkg获取安装包参数,通过PMS获取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. }

    onResume执行了 InstallingAsyncTask

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

    doInBackground将 APK 文件写入 session中。

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

    通过 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. ....
    4. mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
    5. }
    6. private final Handler.Callback mHandlerCallback = new Handler.Callback() {
    7. @Override
    8. public boolean handleMessage(Message msg) {
    9. switch (msg.what) {
    10. case MSG_COMMIT:
    11. handleCommit();
    12. break;
    13. ....
    14. }
    15. return true;
    16. }
    17. };
    18. private void handleCommit() {
    19. ....
    20. try {
    21. synchronized (mLock) {
    22. commitNonStagedLocked(childSessions);
    23. }
    24. } catch (PackageManagerException e) {
    25. final String completeMsg = ExceptionUtils.getCompleteMessage(e);
    26. Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
    27. destroyInternal();
    28. dispatchSessionFinished(e.error, completeMsg, null);
    29. }
    30. }
    31. private void commitNonStagedLocked(List childSessions)
    32. throws PackageManagerException {
    33. final PackageManagerService.ActiveInstallSession committingSession =
    34. makeSessionActiveLocked();
    35. if (committingSession == null) {
    36. return;
    37. }
    38. //多个包
    39. if (isMultiPackage()) {
    40. .....
    41. mPm.installStage(activeChildSessions);
    42. } else {
    43. mPm.installStage(committingSession);
    44. }
    45. }

    这个mPm是PMS

        private final PackageManagerService mPm;

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

    1. void installStage(ActiveInstallSession activeInstallSession) {
    2. final Message msg = mHandler.obtainMessage(INIT_COPY);
    3. final InstallParams params = new InstallParams(activeInstallSession);
    4. params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
    5. msg.obj = params;
    6. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
    7. System.identityHashCode(msg.obj));
    8. Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
    9. System.identityHashCode(msg.obj));
    10. mHandler.sendMessage(msg);
    11. }
    12. class PackageHandler extends Handler {
    13. PackageHandler(Looper looper) {
    14. super(looper);
    15. }
    16. public void handleMessage(Message msg) {
    17. try {
    18. doHandleMessage(msg);
    19. } finally {
    20. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    21. }
    22. }
    23. void doHandleMessage(Message msg) {
    24. switch (msg.what) {
    25. case INIT_COPY: {
    26. HandlerParams params = (HandlerParams) msg.obj;
    27. if (params != null) {
    28. if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
    29. Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
    30. System.identityHashCode(params));
    31. Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
    32. params.startCopy();
    33. Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    34. }
    35. break;
    36. .....
    37. }
    38. }
    39. }
    40. }
    41. private abstract class HandlerParams {
    42. /** User handle for the user requesting the information or installation. */
    43. private final UserHandle mUser;
    44. String traceMethod;
    45. int traceCookie;
    46. ....
    47. final void startCopy() {
    48. if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
    49. handleStartCopy();
    50. handleReturnCode();
    51. }
    52. abstract void handleStartCopy();
    53. abstract void handleReturnCode();
    54. }

     PackageHandler 和 HandlerParams都是PMS的内部类,INIT_COPY的msg中,执行了 params.startCopy(),这个params是HandlerParams,而发送到handler之前是通过以下生成的。

    InstallParams params = new InstallParams(activeInstallSession);

     所以看InstallParams的handleStartCopy()和handleReturnCode()方法

    1. //调用远程方法获取包信息和安装位置值。如果需要,根据默认策略覆盖安装位置,然后根据安装位置创建安装参数。
    2. public void handleStartCopy() {
    3. int ret = PackageManager.INSTALL_SUCCEEDED;
    4. final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
    5. final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
    6. PackageInfoLite pkgLite = null;
    7. pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
    8. origin.resolvedPath, installFlags, packageAbiOverride);
    9. /*
    10. * 如果没有空间,释放缓存
    11. */
    12. if (!origin.staged && pkgLite.recommendedInstallLocation
    13. == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
    14. // TODO: focus freeing disk space on the target device
    15. final StorageManager storage = StorageManager.from(mContext);
    16. final long lowThreshold = storage.getStorageLowBytes(
    17. Environment.getDataDirectory());
    18. final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
    19. origin.resolvedPath, packageAbiOverride);
    20. if (sizeBytes >= 0) {
    21. try {
    22. mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
    23. pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
    24. origin.resolvedPath, installFlags, packageAbiOverride);
    25. } catch (InstallerException e) {
    26. Slog.w(TAG, "Failed to free cache", e);
    27. }
    28. }
    29. }
    30. //决定安装位置
    31. if (ret == PackageManager.INSTALL_SUCCEEDED) {
    32. int loc = pkgLite.recommendedInstallLocation;
    33. if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
    34. ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
    35. } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
    36. ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
    37. } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
    38. ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    39. } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
    40. ret = PackageManager.INSTALL_FAILED_INVALID_APK;
    41. } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
    42. ret = PackageManager.INSTALL_FAILED_INVALID_URI;
    43. } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
    44. ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
    45. } else {
    46. // Override with defaults if needed.
    47. loc = installLocationPolicy(pkgLite);
    48. if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
    49. ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
    50. } else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
    51. ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
    52. } else if (!onInt) {
    53. // Override install location with flags
    54. if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
    55. // Set the flag to install on external media.
    56. installFlags &= ~PackageManager.INSTALL_INTERNAL;
    57. } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
    58. if (DEBUG_INSTANT) {
    59. Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
    60. }
    61. installFlags |= PackageManager.INSTALL_INSTANT_APP;
    62. installFlags &= ~PackageManager.INSTALL_INTERNAL;
    63. } else {
    64. // Make sure the flag for installing on external
    65. // media is unset
    66. installFlags |= PackageManager.INSTALL_INTERNAL;
    67. }
    68. }
    69. }
    70. }
    71. //生成安装参数
    72. final InstallArgs args = createInstallArgs(this);
    73. mVerificationCompleted = true;
    74. mEnableRollbackCompleted = true;
    75. mArgs = args;
    76. ....
    77. mRet = ret;
    78. }
    79. void handleReturnCode() {
    80. if (mVerificationCompleted && mEnableRollbackCompleted) {
    81. ....
    82. if (mRet == PackageManager.INSTALL_SUCCEEDED) {
    83. mRet = mArgs.copyApk();
    84. }
    85. processPendingInstall(mArgs, mRet);
    86. }
    87. }
    88. private InstallArgs createInstallArgs(InstallParams params) {
    89. if (params.move != null) {
    90. //处理现有已安装应用程序移动的逻辑。
    91. return new MoveInstallArgs(params);
    92. } else {
    93. //处理新应用程序安装的逻辑,包括复制和重命名逻辑。
    94. return new FileInstallArgs(params);
    95. }
    96. }

    handleReturnCode()有两个重要的方法

    1. mRet = mArgs.copyApk();
    2. processPendingInstall(mArgs, mRet);

    他们的作用看名字就能猜到了,1是复制apk,2是安装应用

    1.copyApk

    FileInstallArgs也是PMS内部类

    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. try {
    11. final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
    12. //创建路径
    13. final File tempDir =
    14. mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
    15. codeFile = tempDir;
    16. resourceFile = tempDir;
    17. } catch (IOException e) {
    18. Slog.w(TAG, "Failed to create copy file: " + e);
    19. return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    20. }
    21. //将包复制到指定路径
    22. int ret = PackageManagerServiceUtils.copyPackage(
    23. origin.file.getAbsolutePath(), codeFile);
    24. if (ret != PackageManager.INSTALL_SUCCEEDED) {
    25. Slog.e(TAG, "Failed to copy package");
    26. return ret;
    27. }
    28. final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
    29. NativeLibraryHelper.Handle handle = null;
    30. try {
    31. // 将 apk 中的动态库.so 文件也拷贝到目标路径中。
    32. handle = NativeLibraryHelper.Handle.create(codeFile);
    33. ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
    34. abiOverride);
    35. } catch (IOException e) {
    36. Slog.e(TAG, "Copying native libraries failed", e);
    37. ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
    38. } finally {
    39. IoUtils.closeQuietly(handle);
    40. }
    41. return ret;
    42. }

    PackageManagerServiceUtils.copyPackage(
                        origin.file.getAbsolutePath(), codeFile);

     copyPackage就是把origin.file.getAbsolutePath()的安装包复制到codeFile,里面的实现就是输入输出流。

    至此我们的apk就在 data/app 目录下以 base.apk 的方式保存,至于为啥是在data/app,可以去看下

    final File tempDir =
                            mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);

    2.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. }
    11. // Queue up an async operation since the package installation may take a little while.
    12. private void processInstallRequestsAsync(boolean success,
    13. List installRequests) {
    14. mHandler.post(() -> {
    15. if (success) {
    16. for (InstallRequest request : installRequests) {
    17. //预安装
    18. request.args.doPreInstall(request.installResult.returnCode);
    19. }
    20. synchronized (mInstallLock) {
    21. //安装
    22. installPackagesTracedLI(installRequests);
    23. }
    24. for (InstallRequest request : installRequests) {
    25. request.args.doPostInstall(
    26. request.installResult.returnCode, request.installResult.uid);
    27. }
    28. }
    29. for (InstallRequest request : installRequests) {
    30. restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
    31. new PostInstallData(request.args, request.installResult, null));
    32. }
    33. });
    34. }

    预安装操作主要是检查安装包的状态,确保安装环境正常,如果安装环境有问题会清理拷贝文件。

    installPackagesLI是安装的核心。

    Android—PMS: installPackagesLI

    简单总结:

    InstallStaging会先把apk存储在临时文件夹,然后跳转并把URI传给PackageInstallerActivity,点击PackageInstallerActivity的OK按钮进入InstallInstalling页面,InstallInstalling页面建立异步任务将APK通过IO流的形式写入到PackageInstaller.Session,通过PackageInstaller.Session进行进程间通信,发送一个MSG_COMMIT的Message最终调用到了PackageManagerService.installStage方法。installStage方法发送了一个INIT_COPY的Message,调用copyAPK方法将apk拷贝到data/app/,然后再调用processPendingInstall进行安装。

  • 相关阅读:
    图像增强算法的安卓移植
    构建动态交互式H5导航栏:滑动高亮、吸顶和锚点导航技巧详解
    WebSocket快速入门及基本使用
    Spring原理之web.xml加载过程
    创建性-构造者设计模式
    【云原生之K8s】 Pod控制器
    NLC: Search Correlated Window Pairs on Long Time Series(VLDB2022)
    word图题表题公式按照章节编号(不用题注)
    会话技术之Coookie && Session详解
    学校网页设计成品 基于HTML+CSS+JavaScript仿山东财经大学官网 学校班级网页制作模板 校园网页设计成品
  • 原文地址:https://blog.csdn.net/weixin_41939525/article/details/126929917