diff options
-rw-r--r-- | tools/lock_agent/Android.bp | 4 | ||||
-rw-r--r-- | tools/lock_agent/agent.cpp | 59 | ||||
-rw-r--r-- | tools/lock_agent/java/com/android/lock_checker/LockHook.java | 11 |
3 files changed, 73 insertions, 1 deletions
diff --git a/tools/lock_agent/Android.bp b/tools/lock_agent/Android.bp index 2125ad682bb6..408946b28836 100644 --- a/tools/lock_agent/Android.bp +++ b/tools/lock_agent/Android.bp @@ -15,6 +15,8 @@ cc_library { include_dirs: [ // NDK headers aren't available in platform NDK builds. "libnativehelper/include_jni", + // Use ScopedUtfChars. + "libnativehelper/header_only_include", ], header_libs: [ "libopenjdkjvmti_headers", @@ -33,6 +35,8 @@ cc_binary_host { include_dirs: [ // NDK headers aren't available in platform NDK builds. "libnativehelper/include_jni", + // Use ScopedUtfChars. + "libnativehelper/header_only_include", ], header_libs: [ "libopenjdkjvmti_headers", diff --git a/tools/lock_agent/agent.cpp b/tools/lock_agent/agent.cpp index 59bfa2bf849b..5b1d52e809aa 100644 --- a/tools/lock_agent/agent.cpp +++ b/tools/lock_agent/agent.cpp @@ -19,6 +19,8 @@ #include <memory> #include <sstream> +#include <unistd.h> + #include <jni.h> #include <jvmti.h> @@ -26,10 +28,14 @@ #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/macros.h> +#include <android-base/strings.h> #include <android-base/unique_fd.h> #include <fcntl.h> #include <sys/stat.h> +#include <sys/wait.h> + +#include <nativehelper/scoped_utf_chars.h> // We need dladdr. #if !defined(__APPLE__) && !defined(_WIN32) @@ -61,6 +67,7 @@ namespace { JavaVM* gJavaVM = nullptr; +bool gForkCrash = false; // Converts a class name to a type descriptor // (ex. "java.lang.String" to "Ljava/lang/String;") @@ -372,7 +379,7 @@ void prepareHook(jvmtiEnv* env) { } } -jint attach(JavaVM* vm, char* options ATTRIBUTE_UNUSED, void* reserved ATTRIBUTE_UNUSED) { +jint attach(JavaVM* vm, char* options, void* reserved ATTRIBUTE_UNUSED) { gJavaVM = vm; jvmtiEnv* env; @@ -383,9 +390,59 @@ jint attach(JavaVM* vm, char* options ATTRIBUTE_UNUSED, void* reserved ATTRIBUTE prepareHook(env); + std::vector<std::string> config = android::base::Split(options, ","); + for (const std::string& c : config) { + if (c == "native_crash") { + gForkCrash = true; + } + } + return JVMTI_ERROR_NONE; } +extern "C" JNIEXPORT +jboolean JNICALL Java_com_android_lock_1checker_LockHook_getNativeHandlingConfig(JNIEnv*, jclass) { + return gForkCrash ? JNI_TRUE : JNI_FALSE; +} + +extern "C" JNIEXPORT void JNICALL Java_com_android_lock_1checker_LockHook_nWtf(JNIEnv* env, jclass, + jstring msg) { + if (!gForkCrash || msg == nullptr) { + return; + } + + // Create a native crash with the given message. Decouple from the current crash to create a + // tombstone but continue on. + // + // TODO: Once there are not so many reports, consider making this fatal for the calling process. + ScopedUtfChars utf(env, msg); + if (utf.c_str() == nullptr) { + return; + } + const char* args[] = { + "/system/bin/lockagent_crasher", + utf.c_str(), + nullptr + }; + pid_t pid = fork(); + if (pid < 0) { + return; + } + if (pid == 0) { + // Double fork so we return quickly. Leave init to deal with the zombie. + pid_t pid2 = fork(); + if (pid2 == 0) { + execv(args[0], const_cast<char* const*>(args)); + _exit(1); + __builtin_unreachable(); + } + _exit(0); + __builtin_unreachable(); + } + int status; + waitpid(pid, &status, 0); // Ignore any results. +} + extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) { return attach(vm, options, reserved); } diff --git a/tools/lock_agent/java/com/android/lock_checker/LockHook.java b/tools/lock_agent/java/com/android/lock_checker/LockHook.java index efab1d217225..86c97d340c5b 100644 --- a/tools/lock_agent/java/com/android/lock_checker/LockHook.java +++ b/tools/lock_agent/java/com/android/lock_checker/LockHook.java @@ -72,14 +72,20 @@ public class LockHook { private static final LockChecker[] sCheckers; + private static boolean sNativeHandling = false; + static { sHandlerThread = new HandlerThread("LockHook:wtf", Process.THREAD_PRIORITY_BACKGROUND); sHandlerThread.start(); sHandler = new WtfHandler(sHandlerThread.getLooper()); sCheckers = new LockChecker[] { new OnThreadLockChecker() }; + + sNativeHandling = getNativeHandlingConfig(); } + private static native boolean getNativeHandlingConfig(); + static <T> boolean shouldDumpStacktrace(StacktraceHasher hasher, Map<String, T> dumpedSet, T val, AnnotatedStackTraceElement[] st, int from, int to) { final String stacktraceHash = hasher.stacktraceHash(st, from, to); @@ -175,8 +181,13 @@ public class LockHook { private static void handleViolation(Violation v) { String msg = v.toString(); Log.wtf(TAG, msg); + if (sNativeHandling) { + nWtf(msg); // Also send to native. + } } + private static native void nWtf(String msg); + /** * Generates a hash for a given stacktrace of a {@link Throwable}. */ |