如何强制停止一个应用进程

369 阅读3分钟

飞书链接

一、ActivityManager.java killBackgroundProcesses

该方法须在manifest文件中申明相关权限。调用该方法杀掉后台进程后,系统会根据一系列的判断来决定是否有必要重新启动该进程。不会杀掉有persistent 属性的进程。不会杀掉system级别权限的进程。被杀掉的进程当前的ADJ级别要大于SERVICE_ADJ。电视开发中,在杀死某些直播软件后起声音也可能不会停止。

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
activityManager.killBackgroundProcesses(包名);


permission :<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>

Android 中调用位置较少,主要是 低内存情况下调用 和 提供APP使用。

ADB 调用 adb shell am kill packagename

android/frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java

case "kill":
    return runKill(pw);
case "kill-all":
    return runKillAll(pw);
                    
int runKill(PrintWriter pw) throws RemoteException {
    int userId = UserHandle.USER_ALL;

    String opt;
    while ((opt=getNextOption()) != null) {
        if (opt.equals("--user")) {
            userId = UserHandle.parseUserArg(getNextArgRequired());
        } else {
            getErrPrintWriter().println("Error: Unknown option: " + opt);
            return -1;
        }
    }
    mInterface.killBackgroundProcesses(getNextArgRequired(), userId);
    return 0;
}

int runKillAll(PrintWriter pw) throws RemoteException {
    mInterface.killAllBackgroundProcesses();
    return 0;
}

最终实现 (默认allowRestart 值为 true)

Process.killProcessQuiet(pid); ProcessList.killProcessGroup(uid, pid);

android/frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java

void kill(String reason, @Reason int reasonCode, @SubReason int subReason, boolean noisy) {
    if (!killedByAm) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");
        if (mService != null && (noisy || info.uid == mService.mCurOomAdjUid)) {
            mService.reportUidInfoMessageLocked(TAG,
                    "Killing " + toShortString() + " (adj " + setAdj + "): " + reason,
                    info.uid);
        }
        if (pid > 0) {
            mService.mProcessList.noteAppKill(this, reasonCode, subReason, reason);
            EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
            Process.killProcessQuiet(pid);
            ProcessList.killProcessGroup(uid, pid);
        } else {
            pendingStart = false;
        }
        if (!mPersistent) {
            killed = true;
            killedByAm = true;
        }
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
}

二、ActivityManager.java forceStopPackage

拥有相同uid的进程都会被杀掉。运行其中的服务都是停止掉,activity都会移除掉,应用不会重新启动。须在manifest文件中申明相关的权限。

ActivityManager mAm = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 
mAm.forceStopPackage(包名);


permission :<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>

Android 中这个的使用场景就多了。常见的有:

Lowmemkiller 调用

public void doLmkForceStop(int pid) {
    Slog.d(TAG, "doLmkForceStop pid=" + pid);
    
    ......

    mService.forceStopPackage(pkgName, UserHandle.USER_CURRENT);
    Slog.i(TAG, "force stop pkg:" + pkgName + ", pid:" + pid
            + " (adj " + pr.setAdj + ") has done.");
}

ADB 调用 adb shell am force-stop packagename

android/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;

    String opt;
    while ((opt = getNextOption()) != null) {
        if (opt.equals("--user")) {
            userId = UserHandle.parseUserArg(getNextArgRequired());
        } else {
            getErrPrintWriter().println("Error: Unknown option: " + opt);
            return -1;
        }
    }
    mInterface.forceStopPackage(getNextArgRequired(), userId);
    return 0;
}

最终实现 同为 下面, 区别在于 allowRestart 这里是 false

Process.killProcessQuiet(pid); ProcessList.killProcessGroup(uid, pid);

三、Process.java KillProcess

最终调用的是Linux API kill()方法发送SIGKILL信号。理论上该接口允许我们凭借pid号杀掉任意进程,但Kernel 仍然会对调用者进行标准的检查已判断哪些进程允许被调用者杀掉。以下几种情况可以调用此方法:

1、调用者自杀。

2、被杀进程是由调用者创建。

3、共享相同UID的进程能够互杀。

此方法在Google原生代码中多用于Framework 层AM服务,单个应用运用此方法较少。大多数的用法为进程自我销毁,基本没有看到运用此方法杀非本进程的用法。

android.os.Process.killProcess(android.os.Process.myPid());

Android 中实例:

很常见的 Thread.UncaughtExceptionHandler ,

下面是 framework 中默认实现 UncaughtExceptionHandler 的 KillApplicationHandler 的代码。

可以看出,异常退出时,是需要 kill + exit 的。

android/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

@Override
public void uncaughtException(Thread t, Throwable e) {
    try {
        ensureLogging(t, e);

        // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
        if (mCrashing) return;
        mCrashing = true;

        // Try to end profiling. If a profiler is running at this point, and we kill the
        // process (below), the in-memory buffer will be lost. So try to stop, which will
        // flush the buffer. (This makes method trace profiling useful to debug crashes.)
        if (ActivityThread.currentActivityThread() != null) {
            ActivityThread.currentActivityThread().stopProfiling();
        }

        // Bring up crash dialog, wait for it to be dismissed
        ActivityManager.getService().handleApplicationCrash(
                mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
    } catch (Throwable t2) {
        if (t2 instanceof DeadObjectException) {
            // System process is dead; ignore
        } else {
            try {
                Clog_e(TAG, "Error reporting crash", t2);
            } catch (Throwable t3) {
                // Even Clog_e() fails!  Oh well.
            }
        }
    } finally {
        // Try everything to make sure this process goes away.
        Process.killProcess(Process.myPid());
        System.exit(10);
    }
}

四、System.java exit

导致虚拟机停止运行并且该应用退出,所带参数如果非0,则说明是非正常退出。此方法在Google原生代码中多用于cts类和tool类,即(J2SE代码中对应的main方法中调用此方法退出),单个应用程序基本没有运用此方法。平台偶尔有使用此方法完成应用启动后的退出。但貌似该方法会引起findBug问题。不建议使用。

System.exit(0);

Android 中实例:

android/frameworks/base/cmds/sm/src/com/android/commands/sm/Sm.java

public static void main(String[] args) {
        boolean success = false;
        try {
            new Sm().run(args);
            success = true;
        } catch (Exception e) {
            if (e instanceof IllegalArgumentException) {
                showUsage();
                System.exit(1);
            }
            Log.e(TAG, "Error", e);
            System.err.println("Error: " + e);
        }
        System.exit(success ? 0 : 1);
    }

五、Runtime.java exit

其实system.java 的 exit方法的具体实现即为: Runtime.getRuntime().exit(code);

private static final int MSG_DELAY_EXIT_APP = 0;
private static Handler mHandler = new Handler() {
    public void handleMessage(android.os.Message msg) {
        switch (msg.what) {
        case MSG_DELAY_EXIT_APP:
            Runtime.getRuntime().exit(0);
            break;
        }
    }
};
mHandler.sendEmptyMessageDelayed(MSG_DELAY_EXIT_APP, 4000);

几乎没有在使用,不举例了