Loading core/java/android/os/Process.java +101 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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; } core/jni/android_util_Process.cpp +74 −32 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -1271,6 +1274,39 @@ 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}, Loading @@ -1293,17 +1329,23 @@ static const JNINativeMethod methods[] = { {"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}, {"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}, {"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}, {"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) Loading services/core/java/com/android/server/am/ProcessList.java +4 −44 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -2168,28 +2161,6 @@ public final class ProcessList { return success ? app : null; } /** * 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 Loading @@ -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) { 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, Loading Loading
core/java/android/os/Process.java +101 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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; }
core/jni/android_util_Process.cpp +74 −32 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -1271,6 +1274,39 @@ 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}, Loading @@ -1293,17 +1329,23 @@ static const JNINativeMethod methods[] = { {"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}, {"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}, {"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}, {"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) Loading
services/core/java/com/android/server/am/ProcessList.java +4 −44 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -2168,28 +2161,6 @@ public final class ProcessList { return success ? app : null; } /** * 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 Loading @@ -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) { 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, Loading