Android 应用冻结流程分析

xiaoxiao2021-02-28  40

Android 的这些组件有两种状态,禁止的和正常激活 ,默认为激活状态。Android应用冻结主要是调用PMS来实现应用冻结。用户可以通过命令 PackageManager接口的方法实现或者通过pm命令来实现。

1.客户端调用PackageManager如下接口: int getComponentEnabledSetting(in ComponentName componentName); //获取当前组件状态 int getApplicationEnabledSetting(in String packageName);//获取当前包状态 void setComponentEnabledSetting(in ComponentName componentName,in int newState, in int flags);//设置指定组件的状态 void setApplicationEnabledSetting(in String packageName, in int newState, int flags);//设置指定包的状态

2.通过pm命令: pm enable [–user USER_ID] PACKAGE_OR_COMPONENT 恢复为激活状态 pm disable [–user USER_ID] PACKAGE_OR_COMPONENT 修改为禁用状态 pm list packages -d 查看禁用的列表 (返回的package name 的列表)

最终通过binder进程间通信调用PMS服务的如下方法:

@Override public void setApplicationEnabledSetting(String appPackageName, int newState, int flags, int userId, String callingPackage) { if (!sUserManager.exists(userId)) return; if (callingPackage == null) { callingPackage = Integer.toString(Binder.getCallingUid()); } setEnabledSetting(appPackageName, null, newState, flags, userId, callingPackage); } @Override public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, int userId) { if (!sUserManager.exists(userId)) return; setEnabledSetting(componentName.getPackageName(), componentName.getClassName(), newState, flags, userId, null); }

可以发现他们最终调用到 setEnabledSetting(appPackageName, null, newState, flags, userId, callingPackage)方法,下面看看这个方法

private void setEnabledSetting(final String packageName, String className, int newState, final int flags, int userId, String callingPackage) { if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT || newState == COMPONENT_ENABLED_STATE_ENABLED || newState == COMPONENT_ENABLED_STATE_DISABLED || newState == COMPONENT_ENABLED_STATE_DISABLED_USER || newState == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { throw new IllegalArgumentException("Invalid new component state: " + newState); //如果netState不是这几个状态,抛出IllegalArgumentException异常 } PackageSetting pkgSetting; final int uid = Binder.getCallingUid(); final int permission; if (uid == Process.SYSTEM_UID) { //系统签名 permission = PackageManager.PERMISSION_GRANTED; } else { permission = mContext.checkCallingOrSelfPermission( android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); } enforceCrossUserPermission(uid, userId, false /* requireFullPermission */, true /* checkShell */, "set enabled"); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);//是否有权限修改 boolean sendNow = false; boolean isApp = (className == null);//是包名还是组件 String componentName = isApp ? packageName : className; int packageUid = -1; ArrayList<String> components; // writer synchronized (mPackages) { pkgSetting = mSettings.mPackages.get(packageName);//获取PackageSetting对象 if (pkgSetting == null) { if (className == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } throw new IllegalArgumentException( "Unknown component: " + packageName + "/" + className); } } // Limit who can change which apps if (!UserHandle.isSameApp(uid, pkgSetting.appId)) { // Don't allow apps that don't have permission to modify other apps if (!allowedByPermission) { throw new SecurityException( "Permission Denial: attempt to change component state from pid=" + Binder.getCallingPid() + ", uid=" + uid + ", package uid=" + pkgSetting.appId); } // Don't allow changing protected packages. if (mProtectedPackages.isPackageStateProtected(userId, packageName)) { throw new SecurityException("Cannot disable a protected package: " + packageName); } } synchronized (mPackages) { if (uid == Process.SHELL_UID) { // Shell can only change whole packages between ENABLED and DISABLED_USER states int oldState = pkgSetting.getEnabled(userId); if (className == null && (oldState == COMPONENT_ENABLED_STATE_DISABLED_USER || oldState == COMPONENT_ENABLED_STATE_DEFAULT || oldState == COMPONENT_ENABLED_STATE_ENABLED) && (newState == COMPONENT_ENABLED_STATE_DISABLED_USER || newState == COMPONENT_ENABLED_STATE_DEFAULT || newState == COMPONENT_ENABLED_STATE_ENABLED)) { // ok } else { throw new SecurityException( "Shell cannot change component state for " + packageName + "/" + className + " to " + newState); } } if (className == null) { //setApplicationEnabledSetting()方法的className值为null // We're dealing with an application/package level state change if (pkgSetting.getEnabled(userId) == newState) { // Nothing to do return; } if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { // Don't care about who enables an app. callingPackage = null; } pkgSetting.setEnabled(newState, userId, callingPackage); // pkgSetting.pkg.mSetEnabled = newState; } else { //setComponentEnableSetting()方法执行这里 // We're dealing with a component level state change // First, verify that this is a valid class name. PackageParser.Package pkg = pkgSetting.pkg; if (pkg == null || !pkg.hasComponentClassName(className)) { if (pkg != null && pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN) { throw new IllegalArgumentException("Component class " + className + " does not exist in " + packageName); } else { Slog.w(TAG, "Failed setComponentEnabledSetting: component class " + className + " does not exist in " + packageName); } } switch (newState) { case COMPONENT_ENABLED_STATE_ENABLED: if (!pkgSetting.enableComponentLPw(className, userId)) { return; } break; case COMPONENT_ENABLED_STATE_DISABLED: if (!pkgSetting.disableComponentLPw(className, userId)) { return; } break; case COMPONENT_ENABLED_STATE_DEFAULT: if (!pkgSetting.restoreComponentLPw(className, userId)) { return; } break; default: Slog.e(TAG, "Invalid new component state: " + newState); return; } } Log.e(TAG," liang changed2 ", new RuntimeException().fillInStackTrace()); scheduleWritePackageRestrictionsLocked(userId); //将/data/system/users/0/package-restrictions.xml文件写入package-restrictions components = mPendingBroadcasts.get(userId, packageName);//获取该包名下的所有组件(包括enabled、disabled状态的组件) final boolean newPackage = components == null; if (newPackage) { components = new ArrayList<String>(); } if (!components.contains(componentName)) { components.add(componentName); } if ((flags&PackageManager.DONT_KILL_APP) == 0) { sendNow = true; // Purge entry from pending broadcast list if another one exists already // since we are sending one right away. mPendingBroadcasts.remove(userId, packageName);//从预发送广播的组件列表中移除 } else { if (newPackage) { mPendingBroadcasts.put(userId, packageName, components); } if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) { // Schedule a message mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY); } } } long callingId = Binder.clearCallingIdentity(); try { if (sendNow) { packageUid = UserHandle.getUid(userId, pkgSetting.appId); sendPackageChangedBroadcast(packageName, (flags&PackageManager.DONT_KILL_APP) != 0, components, packageUid); } } finally { Binder.restoreCallingIdentity(callingId); } }

最后调用sendPackageChangedBroadcast()方法,发送广播。此时,killFlag为false。

private void sendPackageChangedBroadcast(String packageName, boolean killFlag, ArrayList<String> componentNames, int packageUid) { if (DEBUG_INSTALL) Log.v(TAG, "Sending package changed: package=" + packageName + " components=" + componentNames); Bundle extras = new Bundle(4); extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0)); String nameList[] = new String[componentNames.size()]; componentNames.toArray(nameList); extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);//false extras.putInt(Intent.EXTRA_UID, packageUid); sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null, new int[] {UserHandle.getUserId(packageUid)}); }

接下来看下sendPackageBroadcast()方法是如何调用的。此时,action=Intent.ACTION_PACKAGE_CHANGED,targetPkg和finishedReceiver都为null。

static final void sendPackageBroadcast(String action, String pkg, Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, int[] userIds) { IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { try { if (userIds == null) { userIds = am.getRunningUserIds(); } for (int id : userIds) { final Intent intent = new Intent(action, pkg != null ? Uri.fromParts("package", pkg, null) : null); if (extras != null) { intent.putExtras(extras); } if (targetPkg != null) { intent.setPackage(targetPkg); } // Modify the UID when posting to other users 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); 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, finishedReceiver != null, false, id); } } catch (RemoteException ex) { } } }

调用ActivityManager发送广播。

case Intent.ACTION_PACKAGE_CHANGED: Uri data = intent.getData(); String ssp; if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);//false boolean fullUninstall = removed && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);//false if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {//true forceStopPackageLocked(ssp, UserHandle.getAppId( intent.getIntExtra(Intent.EXTRA_UID, -1)), false, true, true, false, fullUninstall, userId, removed ? "pkg removed" : "pkg changed");调用forceStopPackaageLocked()方法 } if (removed) { sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED, new String[] {ssp}, userId); if (fullUninstall) { mAppOpsService.packageRemoved( intent.getIntExtra(Intent.EXTRA_UID, -1), ssp); // Remove all permissions granted from/to this package removeUriPermissionsForPackageLocked(ssp, userId, true); removeTasksByPackageNameLocked(ssp, userId); if (userId == UserHandle.USER_OWNER) { mTaskPersister.removeFromPackageCache(ssp); } } } else { removeTasksByRemovedPackageComponentsLocked(ssp, userId); if (userId == UserHandle.USER_OWNER) { mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp); } } } break; } break;

此时调用forceStopPackageLocked()方法用来停止组件运行。

最后开机的时候是怎么获取组件的状态了? 这里我初步分析了一下,系统在启动的时候会启动系统进程的PMS服务,PMS服务在初始化阶段会调用setting.java(pm里面)里面的readPackageRestrictionsLPr(int userId)方法读取刚才那个xml文件并且存储

ArraySet<String> enabledComponents = null; ArraySet<String> disabledComponents = null;

这样开机的时候通过获取pm接口可以获取组件的状态了。

转载请注明原文地址: https://www.6miu.com/read-800311.html

最新回复(0)