/* * native public static long nativePreFork() */ static void Dalvik_dalvik_system_ZygoteHooks_preFork(const u4* args, JValue* pResult) { dvmDumpLoaderStats("zygote"); if (!gDvm.zygote) { dvmThrowIllegalStateException( "VM instance not started with -Xzygote"); RETURN_LONG(-1L); } if (!dvmGcPreZygoteFork()) { ALOGE("pre-fork heap failed"); dvmAbort(); } RETURN_LONG(0L); }
/* * Sleep in sigwait() until a signal arrives. */ static void* signalCatcherThreadStart(void* arg) { Thread* self = dvmThreadSelf(); sigset_t mask; int cc; UNUSED_PARAMETER(arg); LOGV("Signal catcher thread started (threadid=%d)\n", self->threadId); /* set up mask with signals we want to handle */ sigemptyset(&mask); sigaddset(&mask, SIGQUIT); sigaddset(&mask, SIGUSR1); while (true) { int rcvd; dvmChangeStatus(self, THREAD_VMWAIT); /* * Signals for sigwait() must be blocked but not ignored. We * block signals like SIGQUIT for all threads, so the condition * is met. When the signal hits, we wake up, without any signal * handlers being invoked. * * We want to suspend all other threads, so that it's safe to * traverse their stacks. * * When running under GDB we occasionally return with EINTR (e.g. * when other threads exit). */ loop: cc = sigwait(&mask, &rcvd); if (cc != 0) { if (cc == EINTR) { //LOGV("sigwait: EINTR\n"); goto loop; } assert(!"bad result from sigwait"); } if (!gDvm.haltSignalCatcher) { LOGI("threadid=%d: reacting to signal %d\n", dvmThreadSelf()->threadId, rcvd); } /* set our status to RUNNING, self-suspending if GC in progress */ dvmChangeStatus(self, THREAD_RUNNING); if (gDvm.haltSignalCatcher) break; if (rcvd == SIGQUIT) { dvmSuspendAllThreads(SUSPEND_FOR_STACK_DUMP); dvmDumpLoaderStats("sig"); logThreadStacks(); if (false) { dvmLockMutex(&gDvm.jniGlobalRefLock); dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global"); dvmUnlockMutex(&gDvm.jniGlobalRefLock); } //dvmDumpTrackedAllocations(true); dvmResumeAllThreads(SUSPEND_FOR_STACK_DUMP); } else if (rcvd == SIGUSR1) { #if WITH_HPROF LOGI("SIGUSR1 forcing GC and HPROF dump\n"); hprofDumpHeap(NULL); #else LOGI("SIGUSR1 forcing GC (no HPROF)\n"); dvmCollectGarbage(false); #endif } else { LOGE("unexpected signal %d\n", rcvd); } } return NULL; }
/* * Respond to a SIGQUIT by dumping the thread stacks. Optionally dump * a few other things while we're at it. * * Thread stacks can either go to the log or to a file designated for holding * ANR traces. If we're writing to a file, we want to do it in one shot, * so we can use a single O_APPEND write instead of contending for exclusive * access with flock(). There may be an advantage in resuming the VM * before doing the file write, so we don't stall the VM if disk I/O is * bottlenecked. * * If JIT tuning is compiled in, dump compiler stats as well. */ static void handleSigQuit() { char* traceBuf = NULL; size_t traceLen; dvmSuspendAllThreads(SUSPEND_FOR_STACK_DUMP); dvmDumpLoaderStats("sig"); if (gDvm.stackTraceFile == NULL) { /* just dump to log */ DebugOutputTarget target; dvmCreateLogOutputTarget(&target, ANDROID_LOG_INFO, LOG_TAG); dvmDumpJniStats(&target); dvmDumpAllThreadsEx(&target, true); } else { /* write to memory buffer */ FILE* memfp = open_memstream(&traceBuf, &traceLen); if (memfp == NULL) { ALOGE("Unable to create memstream for stack traces"); traceBuf = NULL; /* make sure it didn't touch this */ /* continue on */ } else { logThreadStacks(memfp); fclose(memfp); } } #if defined(WITH_JIT) && defined(WITH_JIT_TUNING) dvmCompilerDumpStats(); #endif if (false) dvmDumpTrackedAllocations(true); dvmResumeAllThreads(SUSPEND_FOR_STACK_DUMP); if (traceBuf != NULL) { /* * We don't know how long it will take to do the disk I/O, so put us * into VMWAIT for the duration. */ ThreadStatus oldStatus = dvmChangeStatus(dvmThreadSelf(), THREAD_VMWAIT); /* * Open the stack trace output file, creating it if necessary. It * needs to be world-writable so other processes can write to it. */ int fd = open(gDvm.stackTraceFile, O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd < 0) { ALOGE("Unable to open stack trace file '%s': %s", gDvm.stackTraceFile, strerror(errno)); } else { ssize_t actual = write(fd, traceBuf, traceLen); if (actual != (ssize_t) traceLen) { ALOGE("Failed to write stack traces to %s (%d of %zd): %s", gDvm.stackTraceFile, (int) actual, traceLen, strerror(errno)); } else { ALOGI("Wrote stack traces to '%s'", gDvm.stackTraceFile); } close(fd); } free(traceBuf); dvmChangeStatus(dvmThreadSelf(), oldStatus); } }