基于Android 12的force-stop流程分析

基于Android 12的force-stop流程分析

Force-stop可以强制结束一个package进程及其相关的信息。可以通过adb命令和设置中的入口来使用。如果想结束进程,主要的adb命令有以下几种:

(1)adb shell kill -9 <进程号>

这种方式只会结束一个进程

(2)adb shell am force-stop <包名>

这种方式会结束package进程及其相关的进程,也就是说可能不止结束一个进程。

(3)adb shell pm clear <包名>

这种方法不仅会停止APP进程,而且会清除这个APP进程产生的所有数据。

这里,只分析force-stop的流程

从adb shell am命令来开始分析,force-stop是一个am的命令,所以可以从ActivityManagerShellCommand.java来开始分析,这个文件里定义了各种am命令会执行的原生方法,我们可以通过这个类来很快的判断am命令最终调用的方法。

frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
case "force-stop":
    return runForceStop(pw);
 
int runForceStop(PrintWriter pw) throws RemoteException {
   
        int userId = UserHandle.USER_ALL;//当不指定userId时,则默认为UserHandle.USER_ALL
 
        String opt;
        while ((opt = getNextOption()) != null) {
   
            if (opt.equals("--user")) {
   //是否需要指定userId
                userId = UserHandle.parseUserArg(getNextArgRequired());
            } else {
   
                getErrPrintWriter().println("Error: Unknown option: " + opt);
                return -1;
            }
        }
        mInterface.forceStopPackage(getNextArgRequired(), userId);//binder访问AMS中的方法
        return 0;
    }

adb shell force-stop命令有两种使用方法:

(1)adb shell force-stop <包名>

(2)adb shell force-stop --user <包名> :停止某个userId下某个包名的进程信息,指定userId

无论哪种方法,都是通过binder调用了AMS的forceStopPackage()方法

AMS
@Override
public void forceStopPackage(final String packageName, int userId) {
   
    if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
            != PackageManager.PERMISSION_GRANTED) {
   //force-stop需要FORCE_STOP_PACKAGES权限
        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);//缺少权限的情况下需要抛出异常
    }
    final int callingPid = Binder.getCallingPid();
    userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(),
            userId, true, ALLOW_FULL_ONLY, "forceStopPackage", null);
    final long callingId = Binder.clearCallingIdentity();
    try {
   
        IPackageManager pm = AppGlobals.getPackageManager();
        synchronized(this) {
   
            int[] users = userId == UserHandle.USER_ALL
                    ? mUserController.getUsers() : new int[] {
    userId };
            for (int user : users) {
   //遍历所有用户,可能涉及到多用户
                if (getPackageManagerInternal().isPackageStateProtected(
                        packageName, user)) {
   //如果package的状态是受保护的,那么不能被force-stop
                    Slog.w(TAG, "Ignoring request to force stop protected package "
                            + packageName + " u" + user);
                    return;
                }
 
                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);//将包的状态设置为stopped
                } catch (RemoteException e) {
   
                } catch (IllegalArgumentException e) {
   
                    Slog.w(TAG, "Failed trying to unstop package "
                            + packageName + ": " + e);
                }
                if (mUserController.isUserRunning(user, 0)) {
   
                    forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);//主要实现方法
                    finishForceStopPackageLocked(packageName, pkgUid);//结束force-stop之后的广播发送
                }
            }
        }
    } finally {
   
        Binder.restoreCallingIdentity(callingId);
    }
}

setPackageStoppedState()方法会将包的状态设置为stopped(被force-stop或者没有被启动过的三方应用都是stopped状态),这个状态下所有广播都无法被接收,除非带有标记FLAG_INCLUDE_STOPPED_PACKAGES的广播。系统默认的广播几乎都是不带有该标志,也就意味着一般情况下被force-stop的应用是无法通过广播来拉起进程的,但是我们可以通过给广播添加FLAG_INCLUDE_STOPPED_PACKAGES标识来让stopped状态下的应用接收到此广播。

finishForceStopPackageLocked()方法,主要是发送ACTION_PACKAGE_RESTARTED广播,这个广播的作用是用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播)

主要来看下forceStopPackageLocked()方法

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@GuardedBy("this")
private void forceStopPackageLocked(final String packageName, int uid, String reason) {
   
    forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
            false, true, false, false, UserHandle.getUserId(uid), reason);
}
 
 
@GuardedBy("this")
f
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值