[toc]
基于 Android7.1.1 分析 PackageManagerService 的架构设计!
0 综述 本文来分析下 pms hide 相关的操作:
adb shell pm hide
adb shell pm unhide
这个指令可以让一个 package 被 hide,无法被找到,同样的,我们从 Pm 中看起!
1 Pm 1.1 run 和其他方法的调用逻辑一样,进入 run 方法:
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 public int run (String[] args) throws RemoteException { boolean validCommand = false ; if (args.length < 1 ) { return showUsage(); } mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE)); mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE)); mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package" )); if (mPm == null ) { System.err.println(PM_NOT_RUNNING_ERR); return 1 ; } mInstaller = mPm.getPackageInstaller(); mArgs = args; String op = args[0 ]; mNextArg = 1 ; ... ... ... if ("hide" .equals(op)) { return runSetHiddenSetting(true ); } if ("unhide" .equals(op)) { return runSetHiddenSetting(false ); } ... ... ... }
1.2 runSetHiddenSetting 我们来看下 runSetHiddenSetting 的调用逻辑:
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 private int runSetHiddenSetting (boolean state) { int userId = UserHandle.USER_SYSTEM; String option = nextOption(); if (option != null && option.equals("--user" )) { String optionData = nextOptionData(); if (optionData == null || !isNumber(optionData)) { System.err.println("Error: no USER_ID specified" ); return showUsage(); } else { userId = Integer.parseInt(optionData); } } String pkg = nextArg(); if (pkg == null ) { System.err.println("Error: no package or component specified" ); return showUsage(); } try { mPm.setApplicationHiddenSettingAsUser(pkg, state, userId); System.out.println("Package " + pkg + " new hidden state: " + mPm.getApplicationHiddenSettingAsUser(pkg, userId)); return 0 ; } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); return 1 ; } }
不多说了!
2 PackageManagerService 进入 pms 中去:
2.1 setApplicationHiddenSettingAsUser 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 @Override public boolean setApplicationHiddenSettingAsUser (String packageName, boolean hidden, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null ); PackageSetting pkgSetting; final int uid = Binder.getCallingUid(); enforceCrossUserPermission(uid, userId, true , true , "setApplicationHiddenSetting for user " + userId); if (hidden && isPackageDeviceAdmin(packageName, userId)) { Slog.w(TAG, "Not hiding package " + packageName + ": has active device admin" ); return false ; } long callingId = Binder.clearCallingIdentity(); try { boolean sendAdded = false ; boolean sendRemoved = false ; synchronized (mPackages) { pkgSetting = mSettings.mPackages.get(packageName); if (pkgSetting == null ) { return false ; } if ("android" .equals(packageName)) { Slog.w(TAG, "Cannot hide package: android" ); return false ; } if (hidden && !UserHandle.isSameApp(uid, pkgSetting.appId) && mProtectedPackages.isPackageStateProtected(userId, packageName)) { Slog.w(TAG, "Not hiding protected package: " + packageName); return false ; } if (pkgSetting.getHidden(userId) != hidden) { pkgSetting.setHidden(hidden, userId); mSettings.writePackageRestrictionsLPr(userId); if (hidden) { sendRemoved = true ; } else { sendAdded = true ; } } } if (sendAdded) { sendPackageAddedForUser(packageName, pkgSetting, userId); return true ; } if (sendRemoved) { killApplication(packageName, UserHandle.getUid(userId, pkgSetting.appId), "hiding pkg" ); sendApplicationHiddenForUser(packageName, pkgSetting, userId); return true ; } } finally { Binder.restoreCallingIdentity(callingId); } return false ; }
2.1.1 PackageSetting.getHidden 1 2 3 4 boolean getHidden (int userId) { return readUserState(userId).hidden; }
继续来看:
2.1.1.1 readUserState 1 2 3 4 5 6 7 8 public PackageUserState readUserState (int userId) { PackageUserState state = userState.get(userId); if (state != null ) { return state; } return DEFAULT_USER_STATE; }
2.1.2 PackageSetting.setHidden 1 2 3 4 void setHidden (boolean hidden, int userId) { modifyUserState(userId).hidden = hidden; }
2.1.2.1 modifyUserState 该方法其实很简单,不多说了!
1 2 3 4 5 6 7 8 private PackageUserState modifyUserState (int userId) { PackageUserState state = userState.get(userId); if (state == null ) { state = new PackageUserState(); userState.put(userId, state); } return state; }
2.2 sendPackageAddedForUser[3] 给指定的 user 发送 Intent.ACTION_PACKAGE_ADDED 广播:
1 2 3 4 5 6 7 private void sendPackageAddedForUser (String packageName, PackageSetting pkgSetting, int userId) { final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting); sendPackageAddedForUser(packageName, isSystem, pkgSetting.appId, userId); }
继续来看:
2.2.1 sendPackageAddedForUser[4] 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 private void sendPackageAddedForUser (String packageName, boolean isSystem, int appId, int userId) { Bundle extras = new Bundle(1 ); extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, appId)); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, 0 , null , null , new int [] {userId}); try { IActivityManager am = ActivityManagerNative.getDefault(); if (isSystem && am.isUserRunning(userId, 0 )) { Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED) .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) .setPackage(packageName); am.broadcastIntent(null , bcIntent, null , null , 0 , null , null , null , android.app.AppOpsManager.OP_NONE, null , false , false , userId); } } catch (RemoteException e) { Slog.w(TAG, "Unable to bootstrap installed package" , e); } }
不多说了!
2.2.1.1 sendPackageBroadcast 发送广播的代码如下:
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 final void sendPackageBroadcast (final String action, final String pkg, final Bundle extras, final int flags, final String targetPkg, final IIntentReceiver finishedReceiver, final int [] userIds) { mHandler.post(new Runnable() { @Override public void run () { try { final IActivityManager am = ActivityManagerNative.getDefault(); if (am == null ) return ; final int [] resolvedUserIds; if (userIds == null ) { resolvedUserIds = am.getRunningUserIds(); } else { resolvedUserIds = userIds; } for (int id : resolvedUserIds) { final Intent intent = new Intent(action, pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null ) : null ); if (extras != null ) { intent.putExtras(extras); } if (targetPkg != null ) { intent.setPackage(targetPkg); } int uid = intent.getIntExtra(Intent.EXTRA_UID, -1 ); if (uid > 0 && UserHandle.getUserId(uid) != id) { uid = UserHandle.getUid(id, UserHandle.getAppId(uid)); intent.putExtra(Intent.EXTRA_UID, uid); } intent.putExtra(Intent.EXTRA_USER_HANDLE, id); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | flags); if (DEBUG_BROADCASTS) { RuntimeException here = new RuntimeException("here" ); here.fillInStackTrace(); Slog.d(TAG, "Sending to user " + id + ": " + intent.toShortString(false , true , false , false ) + " " + intent.getExtras(), here); } am.broadcastIntent(null , intent, null , finishedReceiver, 0 , null , null , null , android.app.AppOpsManager.OP_NONE, null , finishedReceiver != null , false , id); } } catch (RemoteException ex) { } } }); }
这就不多说了!
2.3 killApplication[3] 杀掉应用的进程:1 2 3 4 private void killApplication (String pkgName, int appId, String reason) { killApplication(pkgName, appId, UserHandle.USER_ALL, reason); }
2.3.1 killApplication[4] 另一个 4 参数的 kill:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private void killApplication (String pkgName, int appId, int userId, String reason) { final long token = Binder.clearCallingIdentity(); try { IActivityManager am = ActivityManagerNative.getDefault(); if (am != null ) { try { am.killApplication(pkgName, appId, userId, reason); } catch (RemoteException e) { } } } finally { Binder.restoreCallingIdentity(token); } }
对于 killApplication 杀进程的流程,这里就不再分析了!
2.4 sendApplicationHiddenForUser 给指定的 user 发送 Intent.ACTION_PACKAGE_REMOVED 广播:
1 2 3 4 5 6 7 8 9 10 11 private void sendApplicationHiddenForUser (String packageName, PackageSetting pkgSetting, int userId) { final PackageRemovedInfo info = new PackageRemovedInfo(); info.removedPackage = packageName; info.removedUsers = new int [] {userId}; info.uid = UserHandle.getUid(userId, pkgSetting.appId); info.sendPackageRemovedBroadcasts(true ); }
这里不多数说了!
2.4.1 new PackageRemovedInfo 对于 PackageRemovedInfo 这里简单看下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class PackageRemovedInfo { String removedPackage; int uid = -1 ; int removedAppId = -1 ; int [] origUsers; int [] removedUsers = null ; boolean isRemovedPackageSystemUpdate = false ; boolean isUpdate; boolean dataRemoved; boolean removedForAllUsers; InstallArgs args = null ; ArrayMap<String, PackageRemovedInfo> removedChildPackages; ArrayMap<String, PackageInstalledInfo> appearedChildPackages; ... ... ... }
2.4.2 PackageRemovedInfo.sendPackageRemovedBroadcasts 1 2 3 4 5 6 7 8 9 10 11 void sendPackageRemovedBroadcasts (boolean killApp) { sendPackageRemovedBroadcastInternal(killApp); final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0 ; for (int i = 0 ; i < childCount; i++) { PackageRemovedInfo childInfo = removedChildPackages.valueAt(i); childInfo.sendPackageRemovedBroadcastInternal(killApp); } }
2.4.1.1 PackageRemovedInfo.sendPackageRemovedBroadcastInternal 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 private void sendPackageRemovedBroadcastInternal (boolean killApp) { Bundle extras = new Bundle(2 ); extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp); if (isUpdate || isRemovedPackageSystemUpdate) { extras.putBoolean(Intent.EXTRA_REPLACING, true ); } extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers); if (removedPackage != null ) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras, 0 , null , null , removedUsers); if (dataRemoved && !isRemovedPackageSystemUpdate) { sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage, extras, 0 , null , null , removedUsers); } } if (removedAppId >= 0 ) { sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null , extras, 0 , null , null , removedUsers); } }
这里就不多说了!!