summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/Process.java101
-rw-r--r--core/jni/android_util_Process.cpp106
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java48
3 files changed, 179 insertions, 76 deletions
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 5d80ab6453cc..c7a8474c8038 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -20,14 +20,20 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
+import android.system.StructPollfd;
import android.util.Pair;
import android.webkit.WebViewZygote;
import dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+
+import java.io.FileDescriptor;
import java.util.Map;
+import java.util.concurrent.TimeoutException;
/**
* Tools for managing OS processes.
@@ -487,6 +493,15 @@ public class Process {
private static long sStartElapsedRealtime;
private static long sStartUptimeMillis;
+ private static final int PIDFD_UNKNOWN = 0;
+ private static final int PIDFD_SUPPORTED = 1;
+ private static final int PIDFD_UNSUPPORTED = 2;
+
+ /**
+ * Whether or not the underlying OS supports pidfd
+ */
+ private static int sPidFdSupported = PIDFD_UNKNOWN;
+
/**
* State associated with the zygote process.
* @hide
@@ -1189,4 +1204,90 @@ public class Process {
}
}
+
+ /**
+ * Wait for the death of the given process.
+ *
+ * @param pid The process ID to be waited on
+ * @param timeout The maximum time to wait in milliseconds, or -1 to wait forever
+ * @hide
+ */
+ public static void waitForProcessDeath(int pid, int timeout)
+ throws InterruptedException, TimeoutException {
+ FileDescriptor pidfd = null;
+ if (sPidFdSupported == PIDFD_UNKNOWN) {
+ int fd = -1;
+ try {
+ fd = nativePidFdOpen(pid, 0);
+ sPidFdSupported = PIDFD_SUPPORTED;
+ } catch (ErrnoException e) {
+ sPidFdSupported = e.errno != OsConstants.ENOSYS
+ ? PIDFD_SUPPORTED : PIDFD_UNSUPPORTED;
+ } finally {
+ if (fd >= 0) {
+ pidfd = new FileDescriptor();
+ pidfd.setInt$(fd);
+ }
+ }
+ }
+ boolean fallback = sPidFdSupported == PIDFD_UNSUPPORTED;
+ if (!fallback) {
+ try {
+ if (pidfd == null) {
+ int fd = nativePidFdOpen(pid, 0);
+ if (fd >= 0) {
+ pidfd = new FileDescriptor();
+ pidfd.setInt$(fd);
+ } else {
+ fallback = true;
+ }
+ }
+ if (pidfd != null) {
+ StructPollfd[] fds = new StructPollfd[] {
+ new StructPollfd()
+ };
+ fds[0].fd = pidfd;
+ fds[0].events = (short) OsConstants.POLLIN;
+ fds[0].revents = 0;
+ fds[0].userData = null;
+ int res = Os.poll(fds, timeout);
+ if (res > 0) {
+ return;
+ } else if (res == 0) {
+ throw new TimeoutException();
+ } else {
+ // We should get an ErrnoException now
+ }
+ }
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.EINTR) {
+ throw new InterruptedException();
+ }
+ fallback = true;
+ } finally {
+ if (pidfd != null) {
+ IoUtils.closeQuietly(pidfd);
+ }
+ }
+ }
+ if (fallback) {
+ boolean infinity = timeout < 0;
+ long now = System.currentTimeMillis();
+ final long end = now + timeout;
+ while (infinity || now < end) {
+ try {
+ Os.kill(pid, 0);
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.ESRCH) {
+ return;
+ }
+ }
+ Thread.sleep(1);
+ now = System.currentTimeMillis();
+ }
+ }
+ throw new TimeoutException();
+ }
+
+ private static native int nativePidFdOpen(int pid, int flags) throws ErrnoException;
}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index ee6e8c487bad..89dbca816d61 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -50,11 +50,14 @@
#include <pwd.h>
#include <signal.h>
#include <string.h>
+#include <sys/epoll.h>
#include <sys/errno.h>
#include <sys/resource.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
+#include <time.h>
#include <unistd.h>
#define GUARD_THREAD_PRIORITY 0
@@ -1271,39 +1274,78 @@ void android_os_Process_removeAllProcessGroups(JNIEnv* env, jobject clazz)
return removeAllProcessGroups();
}
+static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
+ ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
+ if (detailMessage.get() == NULL) {
+ // Not really much we can do here. We're probably dead in the water,
+ // but let's try to stumble on...
+ env->ExceptionClear();
+ }
+ static jclass errnoExceptionClass =
+ MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/system/ErrnoException"));
+
+ static jmethodID errnoExceptionCtor =
+ GetMethodIDOrDie(env, errnoExceptionClass, "<init>", "(Ljava/lang/String;I)V");
+
+ jobject exception =
+ env->NewObject(errnoExceptionClass, errnoExceptionCtor, detailMessage.get(), error);
+ env->Throw(reinterpret_cast<jthrowable>(exception));
+}
+
+// Wrapper function to the syscall pidfd_open, which creates a file
+// descriptor that refers to the process whose PID is specified in pid.
+static inline int sys_pidfd_open(pid_t pid, unsigned int flags) {
+ return syscall(__NR_pidfd_open, pid, flags);
+}
+
+static jboolean android_os_Process_nativePidFdOpen(JNIEnv* env, jobject, jint pid, jint flags) {
+ int fd = sys_pidfd_open(pid, flags);
+ if (fd < 0) {
+ throwErrnoException(env, "nativePidFdOpen", errno);
+ return -1;
+ }
+ return fd;
+}
+
static const JNINativeMethod methods[] = {
- {"getUidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
- {"getGidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
- {"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority},
- {"setThreadScheduler", "(III)V", (void*)android_os_Process_setThreadScheduler},
- {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground},
- {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority},
- {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority},
- {"getThreadScheduler", "(I)I", (void*)android_os_Process_getThreadScheduler},
- {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup},
- {"setThreadGroupAndCpuset", "(II)V", (void*)android_os_Process_setThreadGroupAndCpuset},
- {"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup},
- {"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup},
- {"getExclusiveCores", "()[I", (void*)android_os_Process_getExclusiveCores},
- {"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness},
- {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
- {"setUid", "(I)I", (void*)android_os_Process_setUid},
- {"setGid", "(I)I", (void*)android_os_Process_setGid},
- {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
- {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
- {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
- {"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
- {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
- {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
- {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
- {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine},
- {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
- {"getPss", "(I)J", (void*)android_os_Process_getPss},
- {"getRss", "(I)[J", (void*)android_os_Process_getRss},
- {"getPidsForCommands", "([Ljava/lang/String;)[I", (void*)android_os_Process_getPidsForCommands},
- //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
- {"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup},
- {"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups},
+ {"getUidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
+ {"getGidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
+ {"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority},
+ {"setThreadScheduler", "(III)V", (void*)android_os_Process_setThreadScheduler},
+ {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground},
+ {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority},
+ {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority},
+ {"getThreadScheduler", "(I)I", (void*)android_os_Process_getThreadScheduler},
+ {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup},
+ {"setThreadGroupAndCpuset", "(II)V", (void*)android_os_Process_setThreadGroupAndCpuset},
+ {"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup},
+ {"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup},
+ {"getExclusiveCores", "()[I", (void*)android_os_Process_getExclusiveCores},
+ {"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness},
+ {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
+ {"setUid", "(I)I", (void*)android_os_Process_setUid},
+ {"setGid", "(I)I", (void*)android_os_Process_setGid},
+ {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
+ {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
+ {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
+ {"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
+ {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V",
+ (void*)android_os_Process_readProcLines},
+ {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
+ {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z",
+ (void*)android_os_Process_readProcFile},
+ {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z",
+ (void*)android_os_Process_parseProcLine},
+ {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
+ {"getPss", "(I)J", (void*)android_os_Process_getPss},
+ {"getRss", "(I)[J", (void*)android_os_Process_getRss},
+ {"getPidsForCommands", "([Ljava/lang/String;)[I",
+ (void*)android_os_Process_getPidsForCommands},
+ //{"setApplicationObject", "(Landroid/os/IBinder;)V",
+ //(void*)android_os_Process_setApplicationObject},
+ {"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup},
+ {"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups},
+ {"nativePidFdOpen", "(II)I", (void*)android_os_Process_nativePidFdOpen},
};
int register_android_os_Process(JNIEnv* env)
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 7f9477ed5c9b..4a8984524bb7 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -91,9 +91,7 @@ import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.provider.DeviceConfig;
-import android.system.ErrnoException;
import android.system.Os;
-import android.system.OsConstants;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.EventLog;
@@ -327,12 +325,7 @@ public final class ProcessList {
/**
* How long between a process kill and we actually receive its death recipient
*/
- private static final long PROC_KILL_TIMEOUT = 2000; // 2 seconds;
-
- /**
- * How long between polls to check if the given process is dead or not.
- */
- private static final long PROC_DEATH_POLL_INTERVAL = 100;
+ private static final int PROC_KILL_TIMEOUT = 2000; // 2 seconds;
ActivityManagerService mService = null;
@@ -2169,28 +2162,6 @@ public final class ProcessList {
}
/**
- * A lite version of checking if a process is alive or not, by using kill(2) with signal 0.
- *
- * <p>
- * Note that, zombie processes are stil "alive" in this case, use the {@link
- * ActivityManagerService#isProcessAliveLocked} if zombie processes need to be excluded.
- * </p>
- */
- @GuardedBy("mService")
- private boolean isProcessAliveLiteLocked(ProcessRecord app) {
- // If somehow the pid is invalid, let's think it's dead.
- if (app.pid <= 0) {
- return false;
- }
- try {
- Os.kill(app.pid, 0);
- } catch (ErrnoException e) {
- return e.errno != OsConstants.ESRCH;
- }
- return true;
- }
-
- /**
* Kill (if asked to) and wait for the given process died if necessary
* @param app - The process record to kill
* @param doKill - Kill the given process record
@@ -2214,20 +2185,9 @@ public final class ProcessList {
// wait for the death
if (wait) {
- boolean isAlive = true;
- // ideally we should use pidfd_open(2) but it's available on kernel 5.3 or later
-
- final long timeout = SystemClock.uptimeMillis() + PROC_KILL_TIMEOUT;
- isAlive = isProcessAliveLiteLocked(app);
- while (timeout > SystemClock.uptimeMillis() && isAlive) {
- try {
- Thread.sleep(PROC_DEATH_POLL_INTERVAL);
- } catch (InterruptedException e) {
- }
- isAlive = isProcessAliveLiteLocked(app);
- }
-
- if (isAlive) {
+ try {
+ Process.waitForProcessDeath(app.pid, PROC_KILL_TIMEOUT);
+ } catch (Exception e) {
// Maybe the process goes into zombie, use an expensive API to check again.
if (mService.isProcessAliveLocked(app)) {
Slog.w(TAG, String.format(formatString,