最近了解一键清理功能,需要实现强制关闭进程的功能。下面介绍下killBackgroundProcesses()方法和forceStopPackage()方法。
killBackgroundProcesses()
ActivityManager的killBackgroundProcesses方法,可以立即杀死与指定包相关联的所有后台进程,这与内核杀死那些进程回收内存是一样的,但这些进程如果在将来某一时刻需要使用,会重新启动。该方法需要权限android.permission.KILL_BACKGROUND_PROCESSES。源码解释如下:
/**
* Have the system immediately kill all background processes associated
* with the given package. This is the same as the kernel killing those
* processes to reclaim memory; the system will take care of restarting
* these processes in the future as needed.
*
* <p>You must hold the permission
* {@link android.Manifest.permission#KILL_BACKGROUND_PROCESSES} to be able to
* call this method.
*
* @param packageName The name of the package whose processes are to
* be killed.
*/
public void killBackgroundProcesses(String packageName) {
try {
ActivityManagerNative.getDefault().killBackgroundProcesses(packageName,
UserHandle.myUserId());
} catch (RemoteException e) {
}
}
最终调用到ActivityManagerService的killBackgroundProcesses()方法。
@Override
public void killBackgroundProcesses(final String packageName, int userId) {
if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
!= PackageManager.PERMISSION_GRANTED &&
checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: killBackgroundProcesses() from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null);
long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
synchronized(this) {
int appId = -1;
try {
appId = UserHandle.getAppId(
pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId));
} catch (RemoteException e) {
}
if (appId == -1) {
Slog.w(TAG, "Invalid packageName: " + packageName);
return;
}
// 杀死package相关的进程
killPackageProcessesLocked(packageName, appId, userId,
ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
调用AMS的killPackageProcessesLocked()方法,杀死package相关的进程。
forceStopPackage()
调用此方法,系统会强制停止与指定包关联的所有事情,将会杀死使用同一个uid的所有进程,停止所有服务,移除所有activity。所有注册的定时器和通知也会移除。这个方法时不允许第三方应用调用的,否则,APP间可以相互停止对方(因为这个方法可以停止其他应用的服务,移除alarm等);forceStopPackage方法源码解释如下():
/**
* Have the system perform a force stop of everything associated with
* the given application package. All processes that share its uid
* will be killed, all services it has running stopped, all activities
* removed, etc. In addition, a {@link Intent#ACTION_PACKAGE_RESTARTED}
* broadcast will be sent, so that any of its registered alarms can
* be stopped, notifications removed, etc.
*
* <p>You must hold the permission
* {@link android.Manifest.permission#FORCE_STOP_PACKAGES} to be able to
* call this method.
*
* @param packageName The name of the package to be stopped.
* @param userId The user for which the running package is to be stopped.
*
* @hide This is not available to third party applications due to
* it allowing them to break other applications by stopping their
* services, removing their alarms, etc.
*/
public void forceStopPackageAsUser(String packageName, int userId) {
try {
ActivityManagerNative.getDefault().forceStopPackage(packageName, userId);
} catch (RemoteException e) {
}
}
/**
* @see #forceStopPackageAsUser(String, int)
* @hide
*/
public void forceStopPackage(String packageName) {
forceStopPackageAsUser(packageName, UserHandle.myUserId());
}
注意使用forceStopPackage方法时,需要添加权限android.permission.FORCE_STOP_PACKAGES。同时注意该方法是隐藏的方法,需要使用反射机制调用。如下:
ActivityManager mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
Method method = Class.forName("android.app.ActivityManager").getMethod("forceStopPackage", String.class);
method.invoke(mActivityManager, packageName); //packageName是需要强制停止的应用程序包名
该方法最终在AMS中处理:
@Override
public void forceStopPackage(final String packageName, int userId) {
if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: forceStopPackage() from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}// 检查是否有android.permission.FORCE_STOP_PACKAGES权限
final int callingPid = Binder.getCallingPid();
userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(),
userId, true, ALLOW_FULL_ONLY, "forceStopPackage", null);
long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();//在系统中可以这样获取PackageManager对象
synchronized(this) {
int[] users = userId == UserHandle.USER_ALL
? mUserController.getUsers() : new int[] { userId };
for (int user : users) {//遍历所有user
int pkgUid = -1;
try {
pkgUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING,
user);
} catch (RemoteException e) {
}
if (pkgUid == -1) {
Slog.w(TAG, "Invalid packageName: " + packageName);
continue;
}
try {
pm.setPackageStoppedState(packageName, true, user);//(1)设置应用的stop状态
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ packageName + ": " + e);
}
if (mUserController.isUserRunningLocked(user, 0)) {
forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);//(2)清理进程,以及package所涉及的四大组件
finishForceStopPackageLocked(packageName, pkgUid);//(3)清理alarm,notification。
}
}
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
(1)setPackageStoppedState()
这里有一个过程非常重要,就是setPackageStoppedState()方法将包的状态设置为stopped,那么所有广播都无法接收,除非带有标记FLAG_INCLUDE_STOPPED_PACKAGES的广播,系统默认的广播几乎都不带有该标记,也就意味着被force-stop的应用是无法通过建立手机网络状态或者亮灭屏广播来拉起进程的。
当使用force stop方式来结束进程时,reason一般都是“from pid ” + callingPid。当然也有另外,那就是AMS.clearApplicationUserData方法调用forceStopPackageLocked的reason为“clear data”。
(2)forceStopPackageLocked()
private void forceStopPackageLocked(final String packageName, int uid, String reason) {
forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
false, true, false, false, UserHandle.getUserId(uid), reason);
}
final boolean forceStopPackageLocked(String packageName, int appId,
boolean callerWillRestart, boolean purgeCache, boolean doit,
boolean evenPersistent, boolean uninstalling, int userId, String reason) {
int i;
if (userId == UserHandle.USER_ALL && packageName == null) {
Slog.w(TAG, "Can't force stop all processes of all users, that is insane!");
}
if (appId < 0 && packageName != null) {
try {
appId = UserHandle.getAppId(AppGlobals.getPackageManager()
.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, 0));//重新获取正确的appid
} catch (RemoteException e) {
}
}
if (doit) {// doit为true,进入这个分支,
if (packageName != null) {
Slog.i(TAG, "Force stopping " + packageName + " appid=" + appId
+ " user=" + userId + ": " + reason);
} else {
Slog.i(TAG, "Force stopping u" + userId + ": " + reason);
}
mAppErrors.resetProcessCrashTimeLocked(packageName == null, appId, userId);//移除应用的crash计数
}
boolean didSomething = killPackageProcessesLocked(packageName, appId, userId,
ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
packageName == null ? ("stop user " + userId) : ("stop " + packageName));//清理进程
// 清理进程包含的Activity
if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
packageName, null, doit, evenPersistent, userId)) {
if (!doit) {
return true;
}
didSomething = true;
}
// 结束该包中的service
if (mServices.bringDownDisabledPackageServicesLocked(
packageName, null, userId, evenPersistent, true, doit)) {
if (!doit) {
return true;
}
didSomething = true;
}
if (packageName == null) {
// Remove all sticky broadcasts from this user.
mStickyBroadcasts.remove(userId);//包名为空时,则移除当前用户的所有stickyBroadcasts
}
ArrayList<ContentProviderRecord> providers = new ArrayList<>();//收集进程包含的providers
if (mProviderMap.collectPackageProvidersLocked(packageName, null, doit, evenPersistent,
userId, providers)) {
if (!doit) {
return true;
}
didSomething = true;
}
for (i = providers.size() - 1; i >= 0; i--) {
removeDyingProviderLocked(null, providers.get(i), true);//清理providers
}
// Remove transient permissions granted from/to this package/user
removeUriPermissionsForPackageLocked(packageName, userId, false);//移除以获取的跟该package/user相关的临时权限
if (doit) {
// 清理广播
for (i = mBroadcastQueues.length - 1; i >= 0; i--) {
didSomething |= mBroadcastQueues[i].cleanupDisabledPackageReceiversLocked(
packageName, null, userId, doit);
}
}
if (packageName == null || uninstalling) {// 包名为null的情况
// Remove pending intents. For now we only do this when force移除Pending Intent
// stopping users, because we have some problems when doing this
// for packages -- app widgets are not currently cleaned up for
// such packages, so they can be left with bad pending intents.
// 现在我们仅在强制停止用户时才这样做,因为我们在为包做这件事时遇到了一些问题——应用程序小部件目前没有被清理出来,
// 所以它们可以留下坏的挂起意图。
if (mIntentSenderRecords.size() > 0) {
Iterator<WeakReference<PendingIntentRecord>> it
= mIntentSenderRecords.values().iterator();
while (it.hasNext()) {
WeakReference<PendingIntentRecord> wpir = it.next();
if (wpir == null) {
it.remove();
continue;
}
PendingIntentRecord pir = wpir.get();
if (pir == null) {
it.remove();
continue;
}
if (packageName == null) {
// Stopping user, remove all objects for the user.
if (pir.key.userId != userId) {
// Not the same user, skip it.
continue;
}
} else {
if (UserHandle.getAppId(pir.uid) != appId) {
// Different app id, skip it.
continue;
}
if (userId != UserHandle.USER_ALL && pir.key.userId != userId) {
// Different user, skip it.
continue;
}
if (!pir.key.packageName.equals(packageName)) {
// Different package, skip it.
continue;
}
}
if (!doit) {
return true;
}
didSomething = true;
it.remove();
pir.canceled = true;
if (pir.key.activity != null && pir.key.activity.pendingResults != null) {
pir.key.activity.pendingResults.remove(pir.ref);
}
}
}
}
if (doit) {
if (purgeCache && packageName != null) {// purgeCache为false
AttributeCache ac = AttributeCache.instance();
if (ac != null) {
ac.removePackage(packageName);
}
}
if (mBooted){//恢复栈顶的Activity
mStackSupervisor.resumeFocusedStackTopActivityLocked();
mStackSupervisor.scheduleIdleLocked();
}
}
return didSomething;
}
对于didSomething只指当方法中所有行为都发生时,则返回true。比如killPackageProcessesLocked(),只要杀死一个进程则代表didSomething为true。
该方法主要功能:
1、Process:调用AMS.killPackageProcessesLocked()清理该package所涉及的进程;
2、Activity:调用ActivityStackSupervisor.finishDisablePackageActivitiesLocked()清理该package所涉及的Activity;
3、Service:调用ActiveService.bringDownDisabledPackageServiceLocked()清理该package所涉及的Service;
4、Provider:调用AMS.removeDyingProviderLocked()清理该package所涉及的Provider;
5、BroadcastReceiver:调用BroadcastQueue.cleanupDisabledPackageReceiversLocked()清理该package所涉及的广播。
6、还要清除进程临时获取的Uri访问权限。
各个方法的具体分析可参考:http://blog.csdn.net/wuyabing12345/article/details/53067470
(3)finishForceStopPackageLocked()
private void finishForceStopPackageLocked(final String packageName, int uid) {
Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
Uri.fromParts("package", packageName, null));
if (!mProcessesReady) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
}
intent.putExtra(Intent.EXTRA_UID, uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
//发送广播用于停止alarm以及通知
broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid));
清理跟该包名相关的进程和四大组件之外,还会发送广播ACTION_PACKAGE_RESTARTED,用于清理已注册的alarm,notification信息。
发送这个广播后,最后调用到注册该广播的接收者。
(A)、Alarm清理:在AlarmManagerService.java中注册了该广播。
class UninstallReceiver extends BroadcastReceiver {
public UninstallReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
filter.addDataScheme("package");
getContext().registerReceiver(this, filter);
......
}
@Override
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {
String action = intent.getAction();
String pkgList[] = null;
if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
......
} else {
......
Uri data = intent.getData();
if (data != null) {
String pkg = data.getSchemeSpecificPart();
if (pkg != null) {
pkgList = new String[]{pkg};
}
}
}
if (pkgList != null && (pkgList.length > 0)) {
for (String pkg : pkgList) {
// 移除alarm
removeLocked(pkg);
mPriorities.remove(pkg);
for (int i=mBroadcastStats.size()-1; i>=0; i--) {
ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
if (uidStats.remove(pkg) != null) {
if (uidStats.size() <= 0) {
mBroadcastStats.removeAt(i);
}
}
}
}
}
}
}
调用AlarmManagerService中的removeLocked()方法,从mAlarmBatches和mPendingWhileIdleAlarms队列中移除包所相关的alarm。
(B)、notification清理:NotificationManagerService.java注册该广播。
private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
return;
}
boolean queryRestart = false;
boolean queryRemove = false;
boolean packageChanged = false;
boolean cancelNotifications = true;
int reason = REASON_PACKAGE_CHANGED;
if (action.equals(Intent.ACTION_PACKAGE_ADDED)
|| (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)
|| (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
|| (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
|| action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
|| action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_ALL);
String pkgList[] = null;
boolean removingPackage = queryRemove &&
!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
......
} else {
Uri uri = intent.getData();
if (uri == null) {
return;
}
String pkgName = uri.getSchemeSpecificPart();
if (pkgName == null) {
return;
}
if (packageChanged) {
// We cancel notifications for packages which have just been disabled
......
}
if (pkgList != null && (pkgList.length > 0)) {
for (String pkgName : pkgList) {
// 移除notification
if (cancelNotifications) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
changeUserId, reason, null);
}
}
}
mListeners.onPackagesChanged(removingPackage, pkgList);
mRankerServices.onPackagesChanged(removingPackage, pkgList);
mConditionProviders.onPackagesChanged(removingPackage, pkgList);
mRankingHelper.onPackagesChanged(removingPackage, pkgList);
}
}
};
调用NotificationManagerService.java中的cancelAllNotificationsInt()方法,从mNotificationList队列中移除package所相关的Notification。
功能点归纳:
1、force stop并不会杀死persistent进程;
2、当app被force stop后, 无法接收到正常广播,那么也就无法通过监听手机网络状态的变化或亮灭屏来拉起进程;
3、当app被force stop后,alarm闹钟一并被清理,无法实现定时响起的功能;
4、当app被force stop后,四大组件以及相关进程被一一清理,即便多进程架构的app也无法拉起自己;
5、级联诛杀:当app通过ClassLoader加载另一个app,则会在force stop的过程中会被级联诛杀;
6、生死与共: 当app与另一个app使用了share uid,则会在force stop的过程,任意一方被杀则另一方也被杀,建立起生死与共的强关系。