[toc]
基于 Android7.1.1 分析 PackageManagerService 的架构设计!
0 综述 前面总结了通过 pm uninstall 的方式来卸载一个 apk,下面我们来分析下通过 PackageInstaller 来卸载应用!
对于用户来说,他们最常用的卸载方式,就是进入应用管理,然后进入指定的应用界面,选择卸载应用:
我们通过 dumpsys window 指令,可以看到这个焦点弹窗:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 sailfish:/ $ dumpsys window | grep mF mLastSystemUiFlags=0x8008 mResettingSystemUiFlags=0x0 mForceClearedSystemUiFlags=0x0 mFocusedWindow=Window{b272ea0 u0 com.google.android.packageinstaller/com.android.packageinstaller.UninstallerActivity} mFocusedApp=Token{b7d3821 ActivityRecord{53e1688 u0 com.google.android.packageinstaller/com.android.packageinstaller.UninstallerActivity t55}} mForceStatusBar=false mForceStatusBarFromKeyguard=false mFillsParent=false mOrientation=-1 mFillsParent=true mOrientation=-1 mFillsParent=true mOrientation=-1 mFillsParent=true mOrientation=-1 mFillsParent=true mOrientation=-1 mFillsParent=true mOrientation=5 mFillsParent=true mOrientation=1 mPolicyVisibility=false mPolicyVisibilityAfterAnim=false mAppOpVisibility=true parentHidden=false mPermanentlyHidden=false mHiddenWhileSuspended=false mForceHideNonSystemOverlayWindow=false mFocusedApp=AppWindowToken{5f12446 token=Token{b7d3821 ActivityRecord{53e1688 u0 com.google.android.packageinstaller/com.android.packageinstaller.UninstallerActivity t55}}}
可以看到,这个看起来像弹窗的界面,实际上是一个 Activity:
1 com.google.android.packageinstaller/com.android.packageinstaller.UninstallerActivity
也就是说,拉起了 packageInstaller 去进行卸载操作,当我们点击卸载后,会触发如下的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @VisibleForTesting void uninstallPkg (String packageName, boolean allUsers, boolean andDisable) { stopListeningToPackageRemove(); Uri packageUri = Uri.parse("package:" + packageName); Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri); uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers); mMetricsFeatureProvider.action( mActivity, MetricsProto.MetricsEvent.ACTION_SETTINGS_UNINSTALL_APP); mFragment.startActivityForResult(uninstallIntent, mRequestUninstall); mDisableAfterUninstall = andDisable; }
下面我们继续分析:
1 UninstallerActivity 1.1 onCreate 当我们点击了卸载时,会拉起 PackageInstaller 的 UninstallerActivity 界面:
卸载时,传入的 Uri 的格式如下:
package://<packageName>#<className>
,className 是额外的参数,如果被指定,表示用户要卸载的具体的 activity;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 @Override public void onCreate (Bundle icicle) { super .onCreate(icicle); final Intent intent = getIntent(); final Uri packageUri = intent.getData(); if (packageUri == null ) { Log.e(TAG, "No package URI in intent" ); showAppNotFound(); return ; } mPackageName = packageUri.getEncodedSchemeSpecificPart(); if (mPackageName == null ) { Log.e(TAG, "Invalid package name in URI: " + packageUri); showAppNotFound(); return ; } final IPackageManager pm = IPackageManager.Stub.asInterface( ServiceManager.getService("package" )); mDialogInfo = new DialogInfo(); mDialogInfo.user = intent.getParcelableExtra(Intent.EXTRA_USER); if (mDialogInfo.user == null ) { mDialogInfo.user = android.os.Process.myUserHandle(); } mDialogInfo.allUsers = intent.getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, false ); mDialogInfo.callback = intent.getIBinderExtra(PackageInstaller.EXTRA_CALLBACK); try { mDialogInfo.appInfo = pm.getApplicationInfo(mPackageName, PackageManager.GET_UNINSTALLED_PACKAGES, mDialogInfo.user.getIdentifier()); } catch (RemoteException e) { Log.e(TAG, "Unable to get packageName. Package manager is dead?" ); } if (mDialogInfo.appInfo == null ) { Log.e(TAG, "Invalid packageName: " + mPackageName); showAppNotFound(); return ; } final String className = packageUri.getFragment(); if (className != null ) { try { mDialogInfo.activityInfo = pm.getActivityInfo( new ComponentName(mPackageName, className), 0 , mDialogInfo.user.getIdentifier()); } catch (RemoteException e) { Log.e(TAG, "Unable to get className. Package manager is dead?" ); } } showConfirmationDialog(); }
1.1.1 new DialogInfo 这里创建了一个 DialogInfo 对象,1 2 3 4 5 6 7 static class DialogInfo { ApplicationInfo appInfo; ActivityInfo activityInfo; boolean allUsers; UserHandle user; IBinder callback; }
1.2 showConfirmationDialog 继续下一步的处理:
1 2 3 4 5 private void showConfirmationDialog () { showDialogFragment(new UninstallAlertDialogFragment()); }
1.2.1 showDialogFragment 切换显示 Fragment:
1 2 3 4 5 6 7 8 private void showDialogFragment (DialogFragment fragment) { FragmentTransaction ft = getFragmentManager().beginTransaction(); Fragment prev = getFragmentManager().findFragmentByTag("dialog" ); if (prev != null ) { ft.remove(prev); } fragment.show(ft, "dialog" ); }
1.3 startUninstallProgress 开始卸载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void startUninstallProgress () { Intent newIntent = new Intent(Intent.ACTION_VIEW); newIntent.putExtra(Intent.EXTRA_USER, mDialogInfo.user); newIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, mDialogInfo.allUsers); newIntent.putExtra(PackageInstaller.EXTRA_CALLBACK, mDialogInfo.callback); newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mDialogInfo.appInfo); if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false )) { newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true ); newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); } newIntent.setClass(this , UninstallAppProgress.class); startActivity(newIntent); }
启动 UninstallAppProgress activity,进入卸载状态!
2 UninstallAlertDialogFragment UninstallAlertDialogFragment 是 DialogFragment 的子类,实现了 DialogInterface.OnClickListener 接口。
我们去他的 onCreateDialog 方法中看看:
2.1 onCreateDialog 该方法会创建一个 Dialog:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 @Override public Dialog onCreateDialog (Bundle savedInstanceState) { final PackageManager pm = getActivity().getPackageManager(); final DialogInfo dialogInfo = ((UninstallerActivity) getActivity()).mDialogInfo; final CharSequence appLabel = dialogInfo.appInfo.loadLabel(pm); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity()); StringBuilder messageBuilder = new StringBuilder(); if (dialogInfo.activityInfo != null ) { final CharSequence activityLabel = dialogInfo.activityInfo.loadLabel(pm); if (!activityLabel.equals(appLabel)) { messageBuilder.append( getString(R.string.uninstall_activity_text, activityLabel)); messageBuilder.append(" " ).append(appLabel).append(".\n\n" ); } } final boolean isUpdate = ((dialogInfo.appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ); UserManager userManager = UserManager.get(getActivity()); if (isUpdate) { if (isSingleUser(userManager)) { messageBuilder.append(getString(R.string.uninstall_update_text)); } else { messageBuilder.append(getString(R.string.uninstall_update_text_multiuser)); } } else { if (dialogInfo.allUsers && !isSingleUser(userManager)) { messageBuilder.append(getString(R.string.uninstall_application_text_all_users)); } else if (!dialogInfo.user.equals(android.os.Process.myUserHandle())) { UserInfo userInfo = userManager.getUserInfo(dialogInfo.user.getIdentifier()); messageBuilder.append( getString(R.string.uninstall_application_text_user, userInfo.name)); } else { messageBuilder.append(getString(R.string.uninstall_application_text)); } } dialogBuilder.setTitle(appLabel); dialogBuilder.setIcon(dialogInfo.appInfo.loadIcon(pm)); dialogBuilder.setPositiveButton(android.R.string.ok, this ); dialogBuilder.setNegativeButton(android.R.string.cancel, this ); dialogBuilder.setMessage(messageBuilder.toString()); return dialogBuilder.create(); }
整个过程很简单,不多说了!
2.1.1 isSingleUser 判断系统是否是单用户:
1 2 3 4 5 private boolean isSingleUser (UserManager userManager) { final int userCount = userManager.getUserCount(); return userCount == 1 || (UserManager.isSplitSystemUser() && userCount == 2 ); }
2.2 onClick 卸载的关键触发是在 UninstallAlertDialogFragment 的点击事件中:
1 2 3 4 5 6 7 8 9 @Override public void onClick (DialogInterface dialog, int which) { if (which == Dialog.BUTTON_POSITIVE) { ((UninstallerActivity) getActivity()).startUninstallProgress(); } else { ((UninstallerActivity) getActivity()).dispatchAborted(); } }
不多说了!!
3 UninstallAppProgress 3.1 onCreate 下面是卸载界面的 onCreate 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 @Override public void onCreate (Bundle icicle) { super .onCreate(icicle); Intent intent = getIntent(); mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); mCallback = intent.getIBinderExtra(PackageInstaller.EXTRA_CALLBACK); if (icicle != null ) { mResultCode = PackageManager.DELETE_FAILED_INTERNAL_ERROR; if (mCallback != null ) { final IPackageDeleteObserver2 observer = IPackageDeleteObserver2.Stub .asInterface(mCallback); try { observer.onPackageDeleted(mAppInfo.packageName, mResultCode, null ); } catch (RemoteException ignored) { } finish(); } else { setResultAndFinish(mResultCode); } return ; } mAllUsers = intent.getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, false ); if (mAllUsers && !UserManager.get(this ).isAdminUser()) { throw new SecurityException("Only admin user can request uninstall for all users" ); } mUser = intent.getParcelableExtra(Intent.EXTRA_USER); if (mUser == null ) { mUser = android.os.Process.myUserHandle(); } else { UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); List<UserHandle> profiles = userManager.getUserProfiles(); if (!profiles.contains(mUser)) { throw new SecurityException("User " + android.os.Process.myUserHandle() + " can't " + "request uninstall for user " + mUser); } } PackageDeleteObserver observer = new PackageDeleteObserver(); getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); getWindow().setStatusBarColor(Color.TRANSPARENT); getWindow().setNavigationBarColor(Color.TRANSPARENT); getPackageManager().deletePackageAsUser(mAppInfo.packageName, observer, mAllUsers ? PackageManager.DELETE_ALL_USERS : 0 , mUser.getIdentifier()); mHandler.sendMessageDelayed(mHandler.obtainMessage(UNINSTALL_IS_SLOW), QUICK_INSTALL_DELAY_MILLIS); }
3.1.1 new PackageDeleteObserver PackageDeleteObserver 接收安装结果!
1 2 3 4 5 6 7 8 9 class PackageDeleteObserver extends IPackageDeleteObserver .Stub { public void packageDeleted (String packageName, int returnCode) { Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE); msg.arg1 = returnCode; msg.obj = packageName; mHandler.sendMessage(msg); } }
这里就不多说了!
3.2 initView 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public void initView () { if (mIsViewInitialized) { return ; } mIsViewInitialized = true ; TypedValue attribute = new TypedValue(); getTheme().resolveAttribute(android.R.attr.windowBackground, attribute, true ); if (attribute.type >= TypedValue.TYPE_FIRST_COLOR_INT && attribute.type <= TypedValue.TYPE_LAST_COLOR_INT) { getWindow().setBackgroundDrawable(new ColorDrawable(attribute.data)); } else { getWindow().setBackgroundDrawable(getResources().getDrawable(attribute.resourceId, getTheme())); } getTheme().resolveAttribute(android.R.attr.navigationBarColor, attribute, true ); getWindow().setNavigationBarColor(attribute.data); getTheme().resolveAttribute(android.R.attr.statusBarColor, attribute, true ); getWindow().setStatusBarColor(attribute.data); boolean isUpdate = ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ); setTitle(isUpdate ? R.string.uninstall_update_title : R.string.uninstall_application_title); setContentView(R.layout.uninstall_progress); View snippetView = findViewById(R.id.app_snippet); PackageUtil.initSnippetForInstalledApp(this , mAppInfo, snippetView); mDeviceManagerButton = (Button) findViewById(R.id.device_manager_button); mUsersButton = (Button) findViewById(R.id.users_button); mDeviceManagerButton.setVisibility(View.GONE); mDeviceManagerButton.setOnClickListener(new OnClickListener() { @Override public void onClick (View v) { Intent intent = new Intent(); intent.setClassName("com.android.settings" , "com.android.settings.Settings$DeviceAdminSettingsActivity" ); intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); finish(); } }); mUsersButton.setVisibility(View.GONE); mUsersButton.setOnClickListener(new OnClickListener() { @Override public void onClick (View v) { Intent intent = new Intent(Settings.ACTION_USER_SETTINGS); intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); finish(); } }); mOkButton = (Button) findViewById(R.id.ok_button); mOkButton.setOnClickListener(this ); }
4 mHandler - mainLooper 1 2 3 private Handler mHandler = new Handler() { ... ... ... }
mHandler 持有 main thead 的 looper 对象,消息都会发送到主线程操作!
4.1 handleMessage[UNINSTALL_IS_SLOW] 发送 UNINSTALL_IS_SLOW 消息,触发 initView 操作:
1 2 3 4 case UNINSTALL_IS_SLOW: initView(); break ;
不多说了!
4.2 handleMessage[UNINSTALL_COMPLETE] 发送 UNINSTALL_COMPLETE 消息,处理卸载结果和最终的显示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 case UNINSTALL_COMPLETE: mHandler.removeMessages(UNINSTALL_IS_SLOW); if (msg.arg1 != PackageManager.DELETE_SUCCEEDED) { initView(); } mResultCode = msg.arg1; final String packageName = (String) msg.obj; if (mCallback != null ) { final IPackageDeleteObserver2 observer = IPackageDeleteObserver2.Stub .asInterface(mCallback); try { observer.onPackageDeleted(mAppInfo.packageName, mResultCode, packageName); } catch (RemoteException ignored) { } finish(); return ; } if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false )) { Intent result = new Intent(); result.putExtra(Intent.EXTRA_INSTALL_RESULT, mResultCode); setResult(mResultCode == PackageManager.DELETE_SUCCEEDED ? Activity.RESULT_OK : Activity.RESULT_FIRST_USER, result); finish(); return ; } final String statusText; switch (msg.arg1) { case PackageManager.DELETE_SUCCEEDED: statusText = getString(R.string.uninstall_done); Context ctx = getBaseContext(); Toast.makeText(ctx, statusText, Toast.LENGTH_LONG).show(); setResultAndFinish(mResultCode); return ; case PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER: { UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface( ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)); int myUserId = UserHandle.myUserId(); UserInfo otherBlockingUser = null ; for (UserInfo user : userManager.getUsers()) { if (isProfileOfOrSame(userManager, myUserId, user.id)) continue ; try { if (dpm.packageHasActiveAdmins(packageName, user.id)) { otherBlockingUser = user; break ; } } catch (RemoteException e) { Log.e(TAG, "Failed to talk to package manager" , e); } } if (otherBlockingUser == null ) { Log.d(TAG, "Uninstall failed because " + packageName + " is a device admin" ); mDeviceManagerButton.setVisibility(View.VISIBLE); statusText = getString( R.string.uninstall_failed_device_policy_manager); } else { Log.d(TAG, "Uninstall failed because " + packageName + " is a device admin of user " + otherBlockingUser); mDeviceManagerButton.setVisibility(View.GONE); statusText = String.format( getString(R.string.uninstall_failed_device_policy_manager_of_user), otherBlockingUser.name); } break ; } case PackageManager.DELETE_FAILED_OWNER_BLOCKED: { UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); IPackageManager packageManager = IPackageManager.Stub.asInterface( ServiceManager.getService("package" )); List<UserInfo> users = userManager.getUsers(); int blockingUserId = UserHandle.USER_NULL; for (int i = 0 ; i < users.size(); ++i) { final UserInfo user = users.get(i); try { if (packageManager.getBlockUninstallForUser(packageName, user.id)) { blockingUserId = user.id; break ; } } catch (RemoteException e) { Log.e(TAG, "Failed to talk to package manager" , e); } } int myUserId = UserHandle.myUserId(); if (isProfileOfOrSame(userManager, myUserId, blockingUserId)) { mDeviceManagerButton.setVisibility(View.VISIBLE); } else { mDeviceManagerButton.setVisibility(View.GONE); mUsersButton.setVisibility(View.VISIBLE); } if (blockingUserId == UserHandle.USER_SYSTEM) { statusText = getString(R.string.uninstall_blocked_device_owner); } else if (blockingUserId == UserHandle.USER_NULL) { Log.d(TAG, "Uninstall failed for " + packageName + " with code " + msg.arg1 + " no blocking user" ); statusText = getString(R.string.uninstall_failed); } else { statusText = mAllUsers ? getString(R.string.uninstall_all_blocked_profile_owner) : getString(R.string.uninstall_blocked_profile_owner); } break ; } default : Log.d(TAG, "Uninstall failed for " + packageName + " with code " + msg.arg1); statusText = getString(R.string.uninstall_failed); break ; } findViewById(R.id.progress_view).setVisibility(View.GONE); findViewById(R.id.status_view).setVisibility(View.VISIBLE); ((TextView)findViewById(R.id.status_text)).setText(statusText); findViewById(R.id.ok_panel).setVisibility(View.VISIBLE); break ;
5 PackageManagerService 最终的卸载,进入了 pms:1 2 3 4 5 6 7 8 @Override public void deletePackageAsUser (String packageName, IPackageDeleteObserver observer, int userId, int flags) { deletePackage(packageName, new LegacyPackageDeleteObserver(observer).getBinder(), userId, flags); }
5.1 new LegacyPackageDeleteObserver LegacyPackageDeleteObserver 的定义是在 PackageManager.java 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static class LegacyPackageDeleteObserver extends PackageDeleteObserver { private final IPackageDeleteObserver mLegacy; public LegacyPackageDeleteObserver (IPackageDeleteObserver legacy) { mLegacy = legacy; } @Override public void onPackageDeleted (String basePackageName, int returnCode, String msg) { if (mLegacy == null ) return ; try { mLegacy.packageDeleted(basePackageName, returnCode); } catch (RemoteException ignored) { } } }
LegacyPackageDeleteObserver 实际上是对前面的回调的一次封装!