@Override public void run() { boolean waitedHalf = false; while (true) { mCompleted = false; mHandler.sendEmptyMessage(MONITOR); synchronized (this) { long timeout = TIME_TO_WAIT; // NOTE: We use uptimeMillis() here because we do not want to increment the time we // wait while asleep. If the device is asleep then the thing that we are waiting // to timeout on is asleep as well and won't have a chance to run, causing a false // positive on when to kill things. long start = SystemClock.uptimeMillis(); while (timeout > 0 && !mForceKillSystem) { try { wait(timeout); // notifyAll() is called when mForceKillSystem is set } catch (InterruptedException e) { Log.wtf(TAG, e); } timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start); } if (mCompleted && !mForceKillSystem) { // The monitors have returned. waitedHalf = false; continue; } if (!waitedHalf) { // We've waited half the deadlock-detection interval. Pull a stack // trace and wait another half. ArrayList<Integer> pids = new ArrayList<Integer>(); pids.add(Process.myPid()); ActivityManagerService.dumpStackTraces(true, pids, null, null); waitedHalf = true; continue; } } // If we got here, that means that the system is most likely hung. // First collect stack traces from all threads of the system process. // Then kill this process so that the system will restart. final String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null"; EventLog.writeEvent(EventLogTags.WATCHDOG, name); ArrayList<Integer> pids = new ArrayList<Integer>(); pids.add(Process.myPid()); if (mPhonePid > 0) pids.add(mPhonePid); // 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); // 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. SystemClock.sleep(2000); // Pull our own kernel thread stacks as well if we're configured for that if (RECORD_KERNEL_THREADS) { dumpKernelStackTraces(); } String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null); if (tracesPath != null && tracesPath.length() != 0) { File traceRenameFile = new File(tracesPath); String newTracesPath; int lpos = tracesPath.lastIndexOf("."); if (-1 != lpos) newTracesPath = tracesPath.substring(0, lpos) + "_SystemServer_WDT" + tracesPath.substring(lpos); else newTracesPath = tracesPath + "_SystemServer_WDT"; traceRenameFile.renameTo(new File(newTracesPath)); tracesPath = newTracesPath; } final File newFd = new File(tracesPath); // Try to add the error to the dropbox, but assuming that the ActivityManager // itself may be deadlocked. (which has happened, causing this statement to // deadlock and the watchdog as a whole to be ineffective) Thread dropboxThread = new Thread("watchdogWriteToDropbox") { public void run() { mActivity.addErrorToDropBox( "watchdog", null, "system_server", null, null, name, null, newFd, null); } }; dropboxThread.start(); try { dropboxThread.join(2000); // wait up to 2 seconds for it to return. } catch (InterruptedException ignored) { } // Only kill the process if the debugger is not attached. if (!Debug.isDebuggerConnected()) { if (SystemProperties.getInt("sys.watchdog.disabled", 0) == 0) { Process.sendSignal(Process.myPid(), 6); SystemClock.sleep(2000); Process.sendSignal(Process.myPid(), 6); SystemClock.sleep(2000); String procs = SystemProperties.get("sys.watchdog.extraprocnames"); if (procs != null && procs.length() > 0) { Slog.w(TAG, "Processes to create tombstones: [" + procs + "]"); createTombstone(procs); } else { Slog.w(TAG, "No process is given for creating tombstones on framework reboot."); } Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name); Process.killProcess(Process.myPid()); System.exit(10); } else { Slog.w(TAG, "*** WATCHDOG NOT KILLING SYSTEM PROCESS: " + name); // Send the SIGSTOP to the System Process for DEBUG purposes Process.sendSignal(Process.myPid(), 19); break; } } else { Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process"); } waitedHalf = false; } }
@Override public void run() { boolean waitedHalf = false; while (true) { mCompleted = false; mHandler.sendEmptyMessage(MONITOR); synchronized (this) { long timeout = TIME_TO_WAIT; // NOTE: We use uptimeMillis() here because we do not want to increment the time we // wait while asleep. If the device is asleep then the thing that we are waiting // to timeout on is asleep as well and won't have a chance to run, causing a false // positive on when to kill things. long start = SystemClock.uptimeMillis(); while (timeout > 0 && !mForceKillSystem) { try { wait(timeout); // notifyAll() is called when mForceKillSystem is set } catch (InterruptedException e) { Log.wtf(TAG, e); } timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start); } if (mCompleted && !mForceKillSystem) { // The monitors have returned. waitedHalf = false; continue; } if (!waitedHalf) { // We've waited half the deadlock-detection interval. Pull a stack // trace and wait another half. ArrayList<Integer> pids = new ArrayList<Integer>(); /// M: WDT debug enhancement: /// it's better to dump all running processes backtraces @{ // pids.add(Process.myPid()); mActivity.getRunningProcessPids(pids); /// @} pids.add(Process.myPid()); ActivityManagerService.dumpStackTraces(true, pids, null, null, NATIVE_STACKS_OF_INTEREST); waitedHalf = true; continue; } } // If we got here, that means that the system is most likely hung. // First collect stack traces from all threads of the system process. // Then kill this process so that the system will restart. final String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null"; EventLog.writeEvent(EventLogTags.WATCHDOG, name); ArrayList<Integer> pids = new ArrayList<Integer>(); /// M: WDT debug enhancement /// it's better to dump all running processes backtraces /// and integrate with AEE @{ /* pids.add(Process.myPid()); if (mPhonePid > 0) pids.add(mPhonePid); // 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, NATIVE_STACKS_OF_INTEREST); */ mActivity.getRunningProcessPids(pids); final File stack = dumpAllBackTraces(pids); /// @} // 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. SystemClock.sleep(2000); // Pull our own kernel thread stacks as well if we're configured for that if (RECORD_KERNEL_THREADS) { dumpKernelStackTraces(); } // Trigger the kernel to dump all blocked threads to the kernel log try { FileWriter sysrq_trigger = new FileWriter("/proc/sysrq-trigger"); sysrq_trigger.write("w"); sysrq_trigger.close(); } catch (IOException e) { Slog.e(TAG, "Failed to write to /proc/sysrq-trigger"); Slog.e(TAG, e.getMessage()); } /// M: WDT debug enhancement /// need to wait the AEE dumps all info, then kill system server @{ /* // Try to add the error to the dropbox, but assuming that the ActivityManager // itself may be deadlocked. (which has happened, causing this statement to // deadlock and the watchdog as a whole to be ineffective) Thread dropboxThread = new Thread("watchdogWriteToDropbox") { public void run() { mActivity.addErrorToDropBox( "watchdog", null, "system_server", null, null, name, null, stack, null); } }; dropboxThread.start(); try { dropboxThread.join(2000); // wait up to 2 seconds for it to return. } catch (InterruptedException ignored) {} */ Slog.v(TAG, "** save all info before killnig system server **"); mActivity.addErrorToDropBox( "watchdog", null, "system_server", null, null, name, null, null, null); SystemClock.sleep(25000); /// @} // Only kill the process if the debugger is not attached. if (!Debug.isDebuggerConnected()) { Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name); Process.killProcess(Process.myPid()); System.exit(10); } else { Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process"); } waitedHalf = false; } }