Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e9e66e5 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by The Android Automerger
Browse files

Include important native processes in watchdog stacks.

Helps us track down deadlocks involving native service processes.

Bug: 6615693
Change-Id: I580047550772e29586195a8cf440141574e3f40c
parent 5f952be8
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -1325,6 +1325,13 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
        }
    }

    /**
     * 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 
+3 −0
Original line number Diff line number Diff line
@@ -933,6 +933,9 @@ public class Process {
    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.
     * 
+34 −0
Original line number Diff line number Diff line
@@ -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_dumpNativeHeap(JNIEnv* env, jobject clazz,
}


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 @@ static JNINativeMethod gMethods[] = {
            (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)
+88 −0
Original line number Diff line number Diff line
@@ -892,6 +892,93 @@ static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid)
    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 @@ static const JNINativeMethod methods[] = {
    {"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},
};

+9 −2
Original line number Diff line number Diff line
@@ -67,6 +67,12 @@ public class Watchdog extends Thread {

    static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";

    static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
        "/system/bin/mediaserver",
        "/system/bin/sdcard",
        "/system/bin/surfaceflinger"
    };

    static Watchdog sWatchdog;

    /* This handler will be used to post message back onto the main thread */
@@ -414,7 +420,8 @@ public class Watchdog extends Thread {
                    // trace and wait another half.
                    ArrayList<Integer> pids = new ArrayList<Integer>();
                    pids.add(Process.myPid());
                    ActivityManagerService.dumpStackTraces(true, pids, null, null);
                    ActivityManagerService.dumpStackTraces(true, pids, null, null,
                            NATIVE_STACKS_OF_INTEREST);
                    waitedHalf = true;
                    continue;
                }
@@ -434,7 +441,7 @@ public class Watchdog extends Thread {
            // Pass !waitedHalf so that just in case we somehow wind up here without having
            // dumped the halfway stacks, we properly re-initialize the trace file.
            final File stack = ActivityManagerService.dumpStackTraces(
                    !waitedHalf, pids, null, null);
                    !waitedHalf, pids, null, null, NATIVE_STACKS_OF_INTEREST);

            // Give some extra time to make sure the stack traces get written.
            // The system's been hanging for a minute, another second or two won't hurt much.
Loading