Include important native processes in watchdog stacks.
Helps us track down deadlocks involving native service processes.
Bug: 6615693
Change-Id: I580047550772e29586195a8cf440141574e3f40c
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 98fe06a..591cd0e 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1326,6 +1326,13 @@
}
/**
+ * Have the stack traces of the given native process dumped to the
+ * specified file. Will be appended to the file.
+ * @hide
+ */
+ public static native void dumpNativeBacktraceToFile(int pid, String file);
+
+ /**
* Return a String describing the calling method and location at a particular stack depth.
* @param callStack the Thread stack
* @param depth the depth of stack to return information for.
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 18fd3cb..8eaeb1d 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -933,6 +933,9 @@
public static final native boolean parseProcLine(byte[] buffer, int startIndex,
int endIndex, int[] format, String[] outStrings, long[] outLongs, float[] outFloats);
+ /** @hide */
+ public static final native int[] getPidsForCommands(String[] cmds);
+
/**
* Gets the total Pss value for a given process, in bytes.
*
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 9586717..6724f36 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -17,8 +17,11 @@
#define LOG_TAG "android.os.Debug"
#include "JNIHelp.h"
#include "jni.h"
+#include <utils/String8.h>
#include "utils/misc.h"
+#include "cutils/debugger.h"
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -538,6 +541,35 @@
}
+static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject clazz,
+ jint pid, jstring fileName)
+{
+ if (fileName == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return;
+ }
+ const jchar* str = env->GetStringCritical(fileName, 0);
+ String8 fileName8;
+ if (str) {
+ fileName8 = String8(str, env->GetStringLength(fileName));
+ env->ReleaseStringCritical(fileName, str);
+ }
+
+ int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */
+ if (fd < 0) {
+ fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno));
+ return;
+ }
+
+ if (lseek(fd, 0, SEEK_END) < 0) {
+ fprintf(stderr, "lseek: %s\n", strerror(errno));
+ } else {
+ dump_backtrace_to_file(pid, fd);
+ }
+
+ close(fd);
+}
+
/*
* JNI registration.
*/
@@ -569,6 +601,8 @@
(void*)android_os_Debug_getProxyObjectCount },
{ "getBinderDeathObjectCount", "()I",
(void*)android_os_Debug_getDeathObjectCount },
+ { "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V",
+ (void*)android_os_Debug_dumpNativeBacktraceToFile },
};
int register_android_os_Debug(JNIEnv *env)
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 027ed16..0290857 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -892,6 +892,93 @@
return pss * 1024;
}
+jintArray android_os_Process_getPidsForCommands(JNIEnv* env, jobject clazz,
+ jobjectArray commandNames)
+{
+ if (commandNames == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return NULL;
+ }
+
+ Vector<String8> commands;
+
+ jsize count = env->GetArrayLength(commandNames);
+
+ for (int i=0; i<count; i++) {
+ jobject obj = env->GetObjectArrayElement(commandNames, i);
+ if (obj != NULL) {
+ const char* str8 = env->GetStringUTFChars((jstring)obj, NULL);
+ if (str8 == NULL) {
+ jniThrowNullPointerException(env, "Element in commandNames");
+ return NULL;
+ }
+ commands.add(String8(str8));
+ env->ReleaseStringUTFChars((jstring)obj, str8);
+ } else {
+ jniThrowNullPointerException(env, "Element in commandNames");
+ return NULL;
+ }
+ }
+
+ Vector<jint> pids;
+
+ DIR *proc = opendir("/proc");
+ if (proc == NULL) {
+ fprintf(stderr, "/proc: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ struct dirent *d;
+ while ((d = readdir(proc))) {
+ int pid = atoi(d->d_name);
+ if (pid <= 0) continue;
+
+ char path[PATH_MAX];
+ char data[PATH_MAX];
+ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
+
+ int fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ continue;
+ }
+ const int len = read(fd, data, sizeof(data)-1);
+ close(fd);
+
+ if (len < 0) {
+ continue;
+ }
+ data[len] = 0;
+
+ for (int i=0; i<len; i++) {
+ if (data[i] == ' ') {
+ data[i] = 0;
+ break;
+ }
+ }
+
+ for (size_t i=0; i<commands.size(); i++) {
+ if (commands[i] == data) {
+ pids.add(pid);
+ break;
+ }
+ }
+ }
+
+ closedir(proc);
+
+ jintArray pidArray = env->NewIntArray(pids.size());
+ if (pidArray == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return NULL;
+ }
+
+ if (pids.size() > 0) {
+ env->SetIntArrayRegion(pidArray, 0, pids.size(), pids.array());
+ }
+
+ return pidArray;
+}
+
static const JNINativeMethod methods[] = {
{"myPid", "()I", (void*)android_os_Process_myPid},
{"myTid", "()I", (void*)android_os_Process_myTid},
@@ -919,6 +1006,7 @@
{"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},
+ {"getPidsForCommands", "([Ljava/lang/String;)[I", (void*)android_os_Process_getPidsForCommands},
//{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
};