与ActivityManager和AMS的关系类似,PMS也有一个对应的管理类PackageManager,用于向应用程序进程提供一些功能。PackageManager是一个抽象类,它的具体实现类为ApplicationPackageManager,ApplicationPackageManager中的方法会通过IPackageManager与PMS进行进程间通信,因此PackageManager所提供的功能最终是由PMS来实现的,这么设计的主要用意是为了避免系统服务PMS直接被访问。PackageManager提供了一些功能,主要有以下几点:
这里分析点击安装包的情况:
跳转到PackageInstaller应用
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- if (Build.VERSION.SDK_INT >= 24) { //7.0新跳转
- Uri apkUri = FileProvider.getUriForFile(paramContext, "com.xxx.xxx.xxx", file);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
- } else {
- intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
- }
application/vnd.android.package-archive对应文件类型apk
PackageInstaller的AndroidManifest.xml
- <activity android:name=".InstallStart"
- 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="file" />
- <data android:scheme="content" />
- <data android:mimeType="application/vnd.android.package-archive" />
- intent-filter>
- ...
- activity>
注意 action与mimeType与Intent参数对应,到InstallStart页面
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStart.java
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mIPackageManager = AppGlobals.getPackageManager();
- Intent intent = getIntent();
- String callingPackage = getCallingPackage();
- final boolean isSessionInstall =
- PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
- // If the activity was started via a PackageInstaller session, we retrieve the calling
- // package from that session
- final int sessionId = (isSessionInstall
- ? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
- : -1);
- .....
- //获取应用信息
- final ApplicationInfo sourceInfo = getSourceInfo(callingPackage);
- final int originatingUid = getOriginatingUid(sourceInfo);
- boolean isTrustedSource = false;
- if (sourceInfo != null
- && (sourceInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
- isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false);
- }
- ....
- Intent nextActivity = new Intent(intent);
- nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
- // The the installation source as the nextActivity thinks this activity is the source, hence
- // set the originating UID and sourceInfo explicitly
- nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_PACKAGE, callingPackage);
- nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
- nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);
-
- //这里为false
- if (isSessionInstall) {
- nextActivity.setClass(this, PackageInstallerActivity.class);
- } else {
- Uri packageUri = intent.getData();
- // 判断Uri的Scheme协议是否是content
- if (packageUri != null && packageUri.getScheme().equals(
- ContentResolver.SCHEME_CONTENT)) {
- nextActivity.setClass(this, InstallStaging.class);
- } else if (packageUri != null && packageUri.getScheme().equals(
- PackageInstallerActivity.SCHEME_PACKAGE)) {
- nextActivity.setClass(this, PackageInstallerActivity.class);
- } else {
- Intent result = new Intent();
- result.putExtra(Intent.EXTRA_INSTALL_RESULT,
- PackageManager.INSTALL_FAILED_INVALID_URI);
- setResult(RESULT_FIRST_USER, result);
- nextActivity = null;
- }
- }
-
- if (nextActivity != null) {
- startActivity(nextActivity);
- }
- finish();
- }
这里是安卓10的源码,需要用到FileProvider,所以会走到
nextActivity.setClass(this, InstallStaging.class);
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStaging.java
- @Override
- protected void onResume() {
- super.onResume();
-
- // This is the first onResume in a single life of the activity
- if (mStagingTask == null) {
- // File does not exist, or became invalid
- if (mStagedFile == null) {
- // Create file delayed to be able to show error
- try {
- mStagedFile = TemporaryFileManager.getStagedFile(this);
- } catch (IOException e) {
- showError();
- return;
- }
- }
-
- mStagingTask = new StagingAsyncTask();
- mStagingTask.execute(getIntent().getData());
- }
- }
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\TemporaryFileManager.java
- @NonNull
- public static File getStagedFile(@NonNull Context context) throws IOException {
- return File.createTempFile("package", ".apk", context.getNoBackupFilesDir());
- }
mStagedFile是一个叫package.apk的File对象
- private final class StagingAsyncTask extends AsyncTask
{ - @Override
- protected Boolean doInBackground(Uri... params) {
- if (params == null || params.length <= 0) {
- return false;
- }
- Uri packageUri = params[0];
- try (InputStream in = getContentResolver().openInputStream(packageUri)) {
- // Despite the comments in ContentResolver#openInputStream the returned stream can
- // be null.
- if (in == null) {
- return false;
- }
-
- try (OutputStream out = new FileOutputStream(mStagedFile)) {
- byte[] buffer = new byte[1024 * 1024];
- int bytesRead;
- while ((bytesRead = in.read(buffer)) >= 0) {
- // Be nice and respond to a cancellation
- if (isCancelled()) {
- return false;
- }
- out.write(buffer, 0, bytesRead);
- }
- }
- } catch (IOException | SecurityException | IllegalStateException e) {
- Log.w(LOG_TAG, "Error staging apk from content URI", e);
- return false;
- }
- return true;
- }
-
- @Override
- protected void onPostExecute(Boolean success) {
- if (success) {
- // Now start the installation again from a file
- Intent installIntent = new Intent(getIntent());
- installIntent.setClass(InstallStaging.this, DeleteStagedFileOnResult.class);
- installIntent.setData(Uri.fromFile(mStagedFile));
-
- if (installIntent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
- installIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
- }
-
- installIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
- startActivity(installIntent);
-
- InstallStaging.this.finish();
- } else {
- showError();
- }
- }
- }
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
- public class DeleteStagedFileOnResult extends Activity {
- @Override
- protected 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);
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- File sourceFile = new File(getIntent().getData().getPath());
- sourceFile.delete();
-
- setResult(resultCode, data);
- finish();
- }
- }
DeleteStagedFileOnResult是个过度,负责跳转后删除package.apk
APK的安装Activity:PackageInstallerActivity
- @Override
- protected void onCreate(Bundle icicle) {
- getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
- super.onCreate(null);
- mPm = getPackageManager();
- mIpm = AppGlobals.getPackageManager();
- mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
- mInstaller = mPm.getPackageInstaller();
- mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
- ....
- boolean wasSetUp = processPackageUri(packageUri);
- if (!wasSetUp) {
- return;
- }
-
- // load dummy layout with OK button disabled until we override this layout in
- // startInstallConfirm
- bindUi();
- checkIfAllowedAndInitiateInstall();
- }
- /**
- * **解析Uri并设置此包的安装程序。
- *
- * @param packageUri The URI to parse
- *
- * @return {@code true} 如果安装程序可以设置
- */
- private boolean processPackageUri(final Uri packageUri) {
- mPackageURI = packageUri;
- final String scheme = packageUri.getScheme();
- switch (scheme) {
- case SCHEME_PACKAGE: {
- ....
- } break;
- case ContentResolver.SCHEME_FILE: {
- File sourceFile = new File(packageUri.getPath());
- PackageParser.Package parsed = PackageUtil.getPackageInfo(this, sourceFile);
-
- // Check for parse errors
- if (parsed == null) {
- Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
- showDialogInner(DLG_PACKAGE_ERROR);
- setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
- return false;
- }
- mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
- PackageManager.GET_PERMISSIONS, 0, 0, null,
- new PackageUserState());
- mAppSnippet = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
- } break;
-
- default: {
- throw new IllegalArgumentException("Unexpected URI scheme " + packageUri);
- }
- }
-
- return true;
- }
前面apk的数据已经用
installIntent.setData(Uri.fromFile(mStagedFile));
传到PackageInstallerActivity了,所以这里走的是file。
processPackageUri解析uri获取
- 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 {
- startInstall();
- }
- }
- }, null);
- mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
- (ignored, ignored2) -> {
- // Cancel and finish
- setResult(RESULT_CANCELED);
- if (mSessionId != -1) {
- mInstaller.setPermissionsResult(mSessionId, false);
- }
- finish();
- }, null);
- setupAlert();
-
- mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
- mOk.setEnabled(false);
- }
bindUI()就是给弹出来的安装界面设置UI,然后为安装和取消两个按钮设置点击事件。安装按钮的点击事件是startInstall();
- private void checkIfAllowedAndInitiateInstall() {
- // Check for install apps user restriction first.
- final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource(
- UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle());
- if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
- showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER);
- return;
- } else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
- startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
- finish();
- return;
- }
-
- if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
- initiateInstall();
- } else {
- // Check for unknown sources restrictions.
- final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(
- UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle());
- final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource(
- UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle());
- final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM
- & (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
- if (systemRestriction != 0) {
- showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
- } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
- startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
- } else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
- startAdminSupportDetailsActivity(
- UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
- } else {
- handleUnknownSources();
- }
- }
- }
这个方法作用就如名字所示了,检查应用权限,还有就是是否是未知来源安装包。
主要看initiateInstall();
- private void initiateInstall() {
- String pkgName = mPkgInfo.packageName;
- // Check if there is already a package on the device with this name
- // but it has been renamed to something else.
- String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
- if (oldName != null && oldName.length > 0 && oldName[0] != null) {
- pkgName = oldName[0];
- mPkgInfo.packageName = pkgName;
- mPkgInfo.applicationInfo.packageName = pkgName;
- }
- // Check if package is already installed. display confirmation dialog if replacing pkg
- try {
- // This is a little convoluted because we want to get all uninstalled
- // apps, but this may include apps with just data, and if it is just
- // data we still want to count it as "installed".
- mAppInfo = mPm.getApplicationInfo(pkgName,
- PackageManager.MATCH_UNINSTALLED_PACKAGES);
- if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
- mAppInfo = null;
- }
- } catch (NameNotFoundException e) {
- mAppInfo = null;
- }
-
- startInstallConfirm();
- }
-
- private void startInstallConfirm() {
- View viewToEnable;
-
- if (mAppInfo != null) {
- viewToEnable = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
- ? requireViewById(R.id.install_confirm_question_update_system)
- : requireViewById(R.id.install_confirm_question_update);
- } else {
- // This is a new application with no permissions.
- viewToEnable = requireViewById(R.id.install_confirm_question);
- }
-
- viewToEnable.setVisibility(View.VISIBLE);
-
- mEnableOk = true;
- mOk.setEnabled(true);
- }
mOk.setEnabled(true);这里让界面的安装按钮可点击。
onCreate就分析完了,接下来看点击安装按钮的点击事件startInstall()。
- private void startInstall() {
- // Start subactivity to actually install the application
- Intent newIntent = new Intent();
- newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
- mPkgInfo.applicationInfo);
- newIntent.setData(mPackageURI);
- newIntent.setClass(this, InstallInstalling.class);
- String installerPackageName = getIntent().getStringExtra(
- Intent.EXTRA_INSTALLER_PACKAGE_NAME);
- if (mOriginatingURI != null) {
- newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
- }
- if (mReferrerURI != null) {
- newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
- }
- if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
- newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
- }
- if (installerPackageName != null) {
- newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
- installerPackageName);
- }
- if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
- newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
- }
- newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
- if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
- startActivity(newIntent);
- finish();
- }
startInstall方法用于跳转到InstallInstalling这个Activity,并关闭掉当前的PackageInstallerActivity。
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallInstalling.java
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- ApplicationInfo appInfo = getIntent()
- .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
- mPackageURI = getIntent().getData();
- //这里为false
- if ("package".equals(mPackageURI.getScheme())) {
- .....
- } else {
- final 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);
-
- if (savedInstanceState != null) {
- ....
- } 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();
- }
- }
解析pkg获取安装包参数,通过PMS获取mSessionId。
- @Override
- protected void onResume() {
- super.onResume();
-
- // This is the first onResume in a single life of the activity
- if (mInstallingTask == null) {
- PackageInstaller installer = getPackageManager().getPackageInstaller();
- PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
-
- if (sessionInfo != null && !sessionInfo.isActive()) {
- mInstallingTask = new InstallingAsyncTask();
- mInstallingTask.execute();
- } else {
- // we will receive a broadcast when the install is finished
- mCancelButton.setEnabled(false);
- setFinishOnTouchOutside(false);
- }
- }
- }
onResume执行了 InstallingAsyncTask
- /**
- * Send the package to the package installer and then register a event result observer that
- * will call {@link #launchFinishBasedOnResult(int, int, String)}
- */
- private final class InstallingAsyncTask extends AsyncTask
- PackageInstaller.Session> {
- volatile boolean isDone;
-
- @Override
- protected 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();
- }
- }
- }
-
- @Override
- protected void onPostExecute(PackageInstaller.Session session) {
- if (session != null) {
- Intent broadcastIntent = new Intent(BROADCAST_ACTION);
- broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- broadcastIntent.setPackage(getPackageName());
- broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
-
- PendingIntent pendingIntent = PendingIntent.getBroadcast(
- InstallInstalling.this,
- mInstallId,
- broadcastIntent,
- PendingIntent.FLAG_UPDATE_CURRENT);
-
- session.commit(pendingIntent.getIntentSender());
- mCancelButton.setEnabled(false);
- setFinishOnTouchOutside(false);
- } else {
- getPackageManager().getPackageInstaller().abandonSession(mSessionId);
-
- if (!isCancelled()) {
- launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
- }
- }
- }
- }
doInBackground将 APK 文件写入 session中。
onPostExecute创建了一个PendingIntent,并将该PendingIntent的IntentSender通过session的commit方法发送出去
通过 IPackageInstallerSession 来进行进程间的通信,最终会调用PackageInstallerSession 的 commit 方法
frameworks\base\services\core\java\com\android\server\pm\PackageInstallerSession.java
- @Override
- public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
- ....
- mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
- }
-
- private final Handler.Callback mHandlerCallback = new Handler.Callback() {
- @Override
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_COMMIT:
- handleCommit();
- break;
- ....
- }
-
- return true;
- }
- };
-
- private void handleCommit() {
- ....
- try {
- synchronized (mLock) {
- commitNonStagedLocked(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);
- }
- }
-
- private void commitNonStagedLocked(List
childSessions) - throws PackageManagerException {
- final PackageManagerService.ActiveInstallSession committingSession =
- makeSessionActiveLocked();
- if (committingSession == null) {
- return;
- }
- //多个包
- if (isMultiPackage()) {
- .....
- mPm.installStage(activeChildSessions);
- } else {
- mPm.installStage(committingSession);
- }
- }
这个mPm是PMS
private final PackageManagerService mPm;
frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java
- void installStage(ActiveInstallSession activeInstallSession) {
- 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);
- }
-
- class PackageHandler extends Handler {
-
- PackageHandler(Looper looper) {
- super(looper);
- }
-
- public void handleMessage(Message msg) {
- try {
- doHandleMessage(msg);
- } finally {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- }
- }
-
- void doHandleMessage(Message msg) {
- switch (msg.what) {
- case INIT_COPY: {
- HandlerParams params = (HandlerParams) msg.obj;
- if (params != null) {
- if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
- System.identityHashCode(params));
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
- params.startCopy();
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- break;
- .....
- }
- }
- }
- }
-
- private abstract class HandlerParams {
- /** User handle for the user requesting the information or installation. */
- private final UserHandle mUser;
- String traceMethod;
- int traceCookie;
- ....
-
- final void startCopy() {
- if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
- handleStartCopy();
- handleReturnCode();
- }
-
- abstract void handleStartCopy();
- abstract void handleReturnCode();
- }
PackageHandler 和 HandlerParams都是PMS的内部类,INIT_COPY的msg中,执行了 params.startCopy(),这个params是HandlerParams,而发送到handler之前是通过以下生成的。
InstallParams params = new InstallParams(activeInstallSession);
所以看InstallParams的handleStartCopy()和handleReturnCode()方法
- //调用远程方法获取包信息和安装位置值。如果需要,根据默认策略覆盖安装位置,然后根据安装位置创建安装参数。
- public void handleStartCopy() {
- int ret = PackageManager.INSTALL_SUCCEEDED;
-
- final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
- final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
- PackageInfoLite pkgLite = null;
- pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
- origin.resolvedPath, installFlags, packageAbiOverride);
- /*
- * 如果没有空间,释放缓存
- */
- if (!origin.staged && pkgLite.recommendedInstallLocation
- == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
- // TODO: focus freeing disk space on the target device
- final StorageManager storage = StorageManager.from(mContext);
- final long lowThreshold = storage.getStorageLowBytes(
- Environment.getDataDirectory());
-
- final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
- origin.resolvedPath, packageAbiOverride);
- if (sizeBytes >= 0) {
- try {
- mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
- pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
- origin.resolvedPath, installFlags, packageAbiOverride);
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to free cache", e);
- }
- }
- }
-
- //决定安装位置
- 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 flags
- if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
- // Set the flag to install on external media.
- installFlags &= ~PackageManager.INSTALL_INTERNAL;
- } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
- if (DEBUG_INSTANT) {
- Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
- }
- installFlags |= PackageManager.INSTALL_INSTANT_APP;
- installFlags &= ~PackageManager.INSTALL_INTERNAL;
- } else {
- // Make sure the flag for installing on external
- // media is unset
- installFlags |= PackageManager.INSTALL_INTERNAL;
- }
- }
- }
- }
-
- //生成安装参数
- final InstallArgs args = createInstallArgs(this);
- mVerificationCompleted = true;
- mEnableRollbackCompleted = true;
- mArgs = args;
- ....
- mRet = ret;
- }
-
- void handleReturnCode() {
- if (mVerificationCompleted && mEnableRollbackCompleted) {
- ....
- if (mRet == PackageManager.INSTALL_SUCCEEDED) {
- mRet = mArgs.copyApk();
- }
- processPendingInstall(mArgs, mRet);
- }
- }
-
- private InstallArgs createInstallArgs(InstallParams params) {
- if (params.move != null) {
- //处理现有已安装应用程序移动的逻辑。
- return new MoveInstallArgs(params);
- } else {
- //处理新应用程序安装的逻辑,包括复制和重命名逻辑。
- return new FileInstallArgs(params);
- }
- }
handleReturnCode()有两个重要的方法
- mRet = mArgs.copyApk();
- processPendingInstall(mArgs, mRet);
他们的作用看名字就能猜到了,1是复制apk,2是安装应用
1.copyApk
FileInstallArgs也是PMS内部类
- int copyApk() {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
- try {
- return doCopyApk();
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- private int doCopyApk() {
- 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;
- }
- //将包复制到指定路径
- int ret = PackageManagerServiceUtils.copyPackage(
- origin.file.getAbsolutePath(), codeFile);
- if (ret != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Failed to copy package");
- return ret;
- }
-
- final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
- NativeLibraryHelper.Handle handle = null;
- try {
- // 将 apk 中的动态库.so 文件也拷贝到目标路径中。
- handle = NativeLibraryHelper.Handle.create(codeFile);
- ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
- abiOverride);
- } catch (IOException e) {
- Slog.e(TAG, "Copying native libraries failed", e);
- ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- } finally {
- IoUtils.closeQuietly(handle);
- }
-
- return ret;
- }
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)
- 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
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));
- }
- });
- }
预安装操作主要是检查安装包的状态,确保安装环境正常,如果安装环境有问题会清理拷贝文件。
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进行安装。