public class Watchdog extends Thread {
static final String TAG = "Watchdog";
// Set this to true to use debug default values.
static final boolean DB = false;
// Set this to true to have the watchdog record kernel thread stacks when it fires
static final boolean RECORD_KERNEL_THREADS = true;
static final long DEFAULT_TIMEOUT = DB ? 10*1000 : 60*1000;
static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
// These are temporally ordered: larger values as lateness increases
static final int COMPLETED = 0;
static final int WAITING = 1;
static final int WAITED_HALF = 2;
static final int OVERDUE = 3;
static final int TIME_SF_WAIT = 20000;
// Which native processes to dump into dropbox's stack traces
public static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
"/system/bin/mediaserver",
"/system/bin/sdcard",
"/system/bin/surfaceflinger"
};
static Watchdog sWatchdog;
ExceptionLog exceptionHWT;
private ServerSocket mServerSocket = null;
private static final int PROT = 23233;
private Socket mSocket = null;
/* This handler will be used to post message back onto the main thread */
final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<>();
final HandlerChecker mMonitorChecker;
ContentResolver mResolver;
ActivityManagerService mActivity;
int mPhonePid;
IActivityController mController;
boolean mAllowRestart = true;
public long GetSFStatus() {
if (exceptionHWT != null) {
return exceptionHWT.SFMatterJava(0, 0);
} else {
return 0;
}
}
public static int GetSFReboot() {
return SystemProperties.getInt("service.sf.reboot", 0);
}
public static void SetSFReboot() {
int OldTime = SystemProperties.getInt("service.sf.reboot", 0);
OldTime = OldTime + 1;
if (OldTime > 9) OldTime = 9;
SystemProperties.set("service.sf.reboot", String.valueOf(OldTime));
}
/**
* Used for checking status of handle threads and scheduling monitor callbacks.
*/
public final class HandlerChecker implements Runnable {
private final Handler mHandler;
public final String mName;
private final long mWaitMax;
public final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
private boolean mCompleted;
private Monitor mCurrentMonitor;
private long mStartTime;
HandlerChecker(Handler handler, String name, long waitMaxMillis) {
mHandler = handler;
mName = name;
mWaitMax = waitMaxMillis;
mCompleted = true;
}
public void addMonitor(Monitor monitor) {
Log.d("hecheng_watchdog", "addMonitor");
mMonitors.add(monitor);
}
//检测本 handlerChecker 线程是否ok
public void scheduleCheckLocked() {
if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {
// If the target looper has recently been polling, then
// there is no reason to enqueue our checker on it since that
// is as good as it not being deadlocked. This avoid having
// to do a context switch to check the thread. Note that we
// only do this if mCheckReboot is false and we have no
// monitors, since those would need to be executed at this point.
mCompleted = true;
return;
}
//如果其一次检测没有完成返回。
if (!mCompleted) {
// we already have a check in flight, so no need
return;
}
mCompleted = false;
mCurrentMonitor = null;
//给被监控的进程发送消息
//监控线程受到消息后会调用 HandlerChecker的run 方法。
//mStartTime 记录本handlerChecker 开始检测的时间
mStartTime = SystemClock.uptimeMillis();
mHandler.postAtFrontOfQueue(this);
}
//判断当前handlerChcker是否超时
public boolean isOverdueLocked() {
return (!mCompleted) && (SystemClock.uptimeMillis() > mStartTime + mWaitMax);
}
//如果没有COMPLETED,获取其超时时间,并返回对应的值
//超时时间小于指定时间的一般(一般为30s),返回WAITING, 系统会继续等待不做处理
//超时时间大于 30s 小于指定时间,返回WAITED_HALF, 系统会dump出运行所有进程堆栈,然后继续等待
//超过超时时间返回OVEROUE,系统会dump堆栈,并重启
public int getCompletionStateLocked() {
if (mCompleted) {
return COMPLETED;
} else {
long latency = SystemClock.uptimeMillis() - mStartTime;
if (latency < mWaitMax/2) {
return WAITING;
} else if (latency < mWaitMax) {
return WAITED_HALF;
}
}
return OVERDUE;
}
public Thread getThread() {
return mHandler.getLooper().getThread();
}
public String getName() {
return mName;
}
public String describeBlockedStateLocked() {
if (mCurrentMonitor == null) {
return "Blocked in handler on " + mName + " (" + getThread().getName() + ")";
} else {
return "Blocked in monitor " + mCurrentMonitor.getClass().getName()
+ " on " + mName + " (" + getThread().getName() + ")";
}
}
//调用到此处说明,此线程的handler 是通畅的可以正常接受消息
@Override
public void run() {
//监控 此线程内添加的monitor 对象,是否存在死锁情况,
final int size = mMonitors.size();
for (int i = 0 ; i < size ; i++) {
synchronized (Watchdog.this) {
mCurrentMonitor = mMonitors.get(i);
}
mCurrentMonitor.monitor();
}
//此线程内的monitor 不存在死锁情况,handlerChecker基本上就通过了。
Log.d("hecheng_watchdog", "Thread is " + mName + ", size is " + size);
synchronized (Watchdog.this) {
mCompleted = true;
mCurrentMonitor = null;
}
}
}
final class RebootRequestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
if (intent.getIntExtra("nowait", 0) != 0) {
rebootSystem("Received ACTION_REBOOT broadcast");
return;
}
if (intent.getIntExtra("hangdump", 0) != 0) {
Slog.i(TAG, "Receiver hangdump start!\n");
runHangdump();
return;
}
Slog.w(TAG, "Unsupported ACTION_REBOOT broadcast: " + intent);
}
}
/** Monitor for checking the availability of binder threads. The monitor will block until
* there is a binder thread available to process in coming IPCs to make sure other processes
* can still communicate with the service.
*/
private static final class BinderThreadMonitor implements Watchdog.Monitor {
@Override
public void monitor() {
Binder.blockUntilThreadAvailable();
}
}
public interface Monitor {
void monitor();
}
public static Watchdog getInstance() {
if (sWatchdog == null) {
sWatchdog = new Watchdog();
}
return sWatchdog;
}
private Watchdog() {
super("watchdog");
// Initialize handler checkers for each common thread we want to check. Note
// that we are not currently checking the background thread, since it can
// potentially hold longer running operations with no guarantees about the timeliness
// of operations there.
// The shared foreground thread is the main checker. It is where we
// will also dispatch monitor checks and do other work.
//watchdog 检测多个线程,超时时间是 60秒,
//HandlerChecker 是通过检测handler 来检测线程是否堵塞
//TODO
mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
"foreground thread", DEFAULT_TIMEOUT);
mHandlerCheckers.add(mMonitorChecker);
// Add checker for main thread. We only do a quick check since there
// can be UI running on the thread.
mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
"main thread", DEFAULT_TIMEOUT));
// Add checker for shared UI thread.
mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
"ui thread", DEFAULT_TIMEOUT));
// And also check IO thread.
mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
"i/o thread", DEFAULT_TIMEOUT));
mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
"display thread", DEFAULT_TIMEOUT));
if (SystemProperties.get("ro.have_aee_feature").equals("1")) {
exceptionHWT = new ExceptionLog();
runHangdumpServer();
}
}
public void setLight() {
Slog.i(TAG, "runHangdump-server-start setLight!\n");
Light tNotificationLight = null;
LightsManager tLights = LocalServices.getService(LightsManager.class);
tNotificationLight = tLights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
tNotificationLight.setFlashing(0xFF0000FF, Light.LIGHT_FLASH_NONE,
1000, 1000);
Slog.i(TAG, "runHangdump-server-start setLight end!\n");
}
public void runHangdump() {
Slog.i(TAG, "runHangdump-server-start thread!\n");
new Thread(new Runnable() {
@Override
public void run() {
Slog.i(TAG, "runHangdump-server hangdump thread start!\n");
final ArrayList<HandlerChecker> blockedCheckers;
String subject;
exceptionHWT.WDTMatterJava(52325);
setLight();
// trace and wait another half.
if (exceptionHWT != null) exceptionHWT.WDTMatterJava(60);
dumpAllBackTraces(true);
Slog.i(TAG, "runHangdump-server thread dumpAllBackTraces first end!\n");
SystemClock.sleep(30000);
Slog.i(TAG, "runHangdump-server thread get subject start!\n");
blockedCheckers = getBlockedCheckersLocked();
subject = describeCheckersLocked(blockedCheckers);
EventLog.writeEvent(EventLogTags.WATCHDOG, subject);
Slog.i(TAG, "runHangdump-server thread get subject end!\n");
if (exceptionHWT != null) exceptionHWT.WDTMatterJava(60);
dumpAllBackTraces(true);
Slog.i(TAG, "runHangdump-server thread dumpAllBackTraces second end!\n");
SystemClock.sleep(2000);
Slog.i(TAG, "runHangdump-server thread get dumpKernelStackTraces start!\n");
dumpKernelStackTraces();
// Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
doSysRq('w');
doSysRq('l');
Slog.i(TAG, "runHangdump-server thread get dumpKernelStackTraces end!\n");
Slog.i(TAG, "runHangdump-server thread start addErrorToDropbox!\n");
mActivity.addErrorToDropBox("watchdog", null, "system_server", null, null, subject, null, null, null);
Slog.i(TAG, "runHangdump-server thread addErrorToDropBox end!subject:" + "subject!" + "\n");
SystemClock.sleep(2000);
if (exceptionHWT != null) {
Slog.i(TAG, "runHangdump-server exceptionHWT start!\n");
exceptionHWT.WDTMatterJava(52323);
}
}
}).start();
}
public void runHangdumpServer() {
Slog.i(TAG, "runHangdumpServer start!\n");
new Thread(new Runnable() {
@Override
public void run() {
Slog.i(TAG, "runHangdumpServer thread!\n");
try{
if (mServerSocket == null) {
Slog.i(TAG, "runHangdumpServer ServerSocket(prot):" + PROT + "!\n");
mServerSocket= new ServerSocket(PROT);
while(true){
Slog.i(TAG, "runHangdumpServer accept!\n");
mSocket = mServerSocket.accept();
InputStream inputStream = mSocket.getInputStream();
OutputStream outputStream = mSocket.getOutputStream();
DataInputStream mDataInputStream = new DataInputStream(new BufferedInputStream(inputStream));
byte[] data = new byte[16];
int len = mDataInputStream.read(data);
String msg = new String(data, "UTF-8");
Slog.i(TAG, "runHangdumpServer thread msg: " + msg + "\n");
while(msg!=null){
Slog.i(TAG, "runHangdumpServer write!\n");
outputStream.write("hello runHangdumpServer ok!\n".getBytes());
outputStream.flush();
if (msg.equals("start_hangdump_j")) {
Slog.i(TAG, "runHangdumpServer thread_j start!\n");
runHangdump();
} else if (msg.equals("start_hangdump_c")) {
Slog.i(TAG, "runHangdumpServer thread_c start!\n");
runHangdump();
}
break;
}
}
}
} catch(Exception e){
Slog.w(TAG, "mServerSocket exception", e);
} finally {
Slog.i(TAG, "mServerSocket finally!\n");
try {
mSocket.close();
mSocket = null;
mServerSocket.close();
mServerSocket = null;
} catch (IOException e) {
Slog.w(TAG, "mServerSocket IOException", e);
}
}
}
}).start();
}
public void init(Context context, ActivityManagerService activity) {
mResolver = context.getContentResolver();
mActivity = activity;
context.registerReceiver(new RebootRequestReceiver(),
new IntentFilter(Intent.ACTION_REBOOT),
android.Manifest.permission.REBOOT, null);
if(exceptionHWT!= null){
exceptionHWT.WDTMatterJava(0);
}
}
public void processStarted(String name, int pid) {
synchronized (this) {
if ("com.android.phone".equals(name)) {
mPhonePid = pid;
}
}
}
public void setActivityController(IActivityController controller) {
synchronized (this) {
mController = controller;
}
}
public void setAllowRestart(boolean allowRestart) {
synchronized (this) {
mAllowRestart = allowRestart;
}
}
//addMonitor 添加 fg线程内的对象monitor,在检测fg线程时,并检测其添加的对象,是否存在死锁。
//检测顺序为,先检测fg线程的handler是否可以正常接受信息,然后检测其添加的monitor 是否存在死锁
public void addMonitor(Monitor monitor) {
synchronized (this) {
if (isAlive()) {
throw new RuntimeException("Monitors can't be added once the Watchdog is running");
}
mMonitorChecker.addMonitor(monitor);
}
}
//addThread 添加要检测的 线程,默认时间为60s,可以指定时间时间
public void addThread(Handler thread) {
addThread(thread, DEFAULT_TIMEOUT);
}
public void addThread(Handler thread, long timeoutMillis) {
synchronized (this) {
if (isAlive()) {
throw new RuntimeException("Threads can't be added once the Watchdog is running");
}
final String name = thread.getLooper().getThread().getName();
mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis));
}
}
/**
* Perform a full reboot of the system.
*/
void rebootSystem(String reason) {
Slog.i(TAG, "Rebooting system because: " + reason);
IPowerManager pms = (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE);
try {
pms.reboot(false, reason, false);
} catch (RemoteException ex) {
}
}
//检测所有的handlerChecker,看其中是否存在超时的现象。
private int evaluateCheckerCompletionLocked() {
int state = COMPLETED;
//遍历检测handlerChecker 看是否存在超时现象。
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
state = Math.max(state, hc.getCompletionStateLocked());//getCompletionStateLocked 检测对应的线程的handlerChecker是否超时
}
return state;
}
private ArrayList<HandlerChecker> getBlockedCheckersLocked() {
ArrayList<HandlerChecker> checkers = new ArrayList<HandlerChecker>();
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
if (hc.isOverdueLocked()) {
checkers.add(hc);
}
}
return checkers;
}
private String describeCheckersLocked(ArrayList<HandlerChecker> checkers) {
StringBuilder builder = new StringBuilder(128);
for (int i=0; i<checkers.size(); i++) {
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(checkers.get(i).describeBlockedStateLocked());
}
return builder.toString();
}
/*
private void CputimeEnable(String bootevent){
try {
FileOutputStream fcputime = new FileOutputStream("/proc/mtprof/cputime");
fcputime.write(bootevent.getBytes());
fcputime.close();
} catch (FileNotFoundException e) {
Slog.e(TAG, "cputime entry can not found!", e);
} catch (java.io.IOException e) {
Slog.e(TAG, "cputime entry open fail", e);
}
}
*/
//watchdog 监控开始
@Override
public void run() {
boolean waitedHalf = false;
boolean mNeedDump = false;
boolean mSFHang = false;
while (true) {
final ArrayList<HandlerChecker> blockedCheckers;
String subject;
mSFHang = false;
if (exceptionHWT != null) {
exceptionHWT.WDTMatterJava(60);
}
if (mNeedDump) {
// We've waited half the deadlock-detection interval. Pull a stack
// trace and wait another half.
if (exceptionHWT != null) exceptionHWT.WDTMatterJava(60);
dumpAllBackTraces(true);
mNeedDump = false;
}
final boolean allowRestart;
int debuggerWasConnected = 0;
Slog.w(TAG, "SWT Watchdog before synchronized:" + SystemClock.uptimeMillis());
synchronized (this) {
Slog.w(TAG, "SWT Watchdog after synchronized:" + SystemClock.uptimeMillis());
long timeout = CHECK_INTERVAL;
long SFHangTime;
// Make sure we (re)spin the checkers that have become idle within
// this wait-and-check interval
//TODO 遍历所有的handlerChecker, 向他们发送消息看线程是否ok。
//如果handlerChecker的前一次检测没有完成,那么此handlerchecker 线程跳过本次检测。
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
Log.d("hecheng_watchdog", "hc is " + hc.mName + ", mMonitors size is " + hc.mMonitors.size());
hc.scheduleCheckLocked();
}
if (debuggerWasConnected > 0) {
debuggerWasConnected--;
}
// 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.
//CputimeEnable(new String("1"));
long start = SystemClock.uptimeMillis();
//设置此循环是为了防止,被异常唤醒,确保wait 时间为 30s
while (timeout > 0) {
if (Debug.isDebuggerConnected()) {
debuggerWasConnected = 2;
}
try {
Slog.w(TAG, "SWT Watchdog before wait timeout:" + timeout);
Slog.w(TAG, "SWT Watchdog before wait current time:" + SystemClock.uptimeMillis());
Slog.w(TAG, "SWT Watchdog before wait start:" + start);
Slog.w(TAG, "SWT Watchdog before wait CHECK_INTERVAL:" + CHECK_INTERVAL);
wait(timeout);
Slog.w(TAG, "SWT Watchdog after wait current time:" + SystemClock.uptimeMillis());
} catch (InterruptedException e) {
Log.wtf(TAG, e);
}
if (Debug.isDebuggerConnected()) {
debuggerWasConnected = 2;
}
//CHECK_INTERVAL 30s, 那么相当于watchdog 30 秒检测一次
timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
}
//MTK enhance
SFHangTime = GetSFStatus();
Slog.w(TAG, "**Get SF Time **" + SFHangTime);
if (SFHangTime > TIME_SF_WAIT * 2) {
Slog.v(TAG, "**SF hang Time **" + SFHangTime);
mSFHang = true;
} //@@
else {
//检测是否存在超时的线程
final int waitState = evaluateCheckerCompletionLocked();
//COMPLETED 无超时进程
//WAITING 有等待进程,0< 等待时间< 超时时间/2
//WAITED_HALF 有等待进程,超时时间/2 < 等待时间 < 超时时间
if (waitState == COMPLETED) {
Slog.v(TAG, "**COMPLETED **");
// The monitors have returned; reset
waitedHalf = false;
//CputimeEnable(new String("0"));
continue;
} else if (waitState == WAITING) {
Slog.v(TAG, "**WAITING **");
// still waiting but within their configured intervals; back off and recheck
// CputimeEnable(new String("0"));
continue;
} else if (waitState == WAITED_HALF) {
Slog.v(TAG, "**WAITED_HALF **");
if (!waitedHalf) {
Slog.v(TAG, "**waitedHalf **");
// We've waited half the deadlock-detection interval. Pull a stack
// trace and wait another half.
mNeedDump = true;
waitedHalf = true;
}
continue;
}
}
//handlerChecker 超时
//something is overdue!
blockedCheckers = getBlockedCheckersLocked();//获取所有超时的handlerChecker
subject = describeCheckersLocked(blockedCheckers);// 获取String ,看是 handler time out, 还是 monitor time out.
allowRestart = mAllowRestart;
}
//CputimeEnable(new String("0"));
// 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.
Slog.e(TAG, "**SWT happen **" + subject);
if (mSFHang && subject.isEmpty()) {
subject = "surfaceflinger hang.";
}
EventLog.writeEvent(EventLogTags.WATCHDOG, subject);
if (exceptionHWT != null) exceptionHWT.WDTMatterJava(60);
dumpAllBackTraces(false);
// 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, and backtraces on all CPUs to the kernel log
doSysRq('w');
doSysRq('l');
/// 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, subject, null, null, null);
IActivityController controller;
synchronized (this) {
controller = mController;
}
if ((mSFHang == false) && (controller != null)) {
Slog.i(TAG, "Reporting stuck state to activity controller");
try {
Binder.setDumpDisabled("Service dumps disabled due to hung system process.");
Slog.i(TAG, "Binder.setDumpDisabled");
// 1 = keep waiting, -1 = kill system
int res = controller.systemNotResponding(subject);
if (res >= 0) {
Slog.i(TAG, "Activity controller requested to coninue to wait");
waitedHalf = false;
continue;
}
Slog.i(TAG, "Activity controller requested to reboot");
} catch (RemoteException e) {
}
}
// Only kill the process if the debugger is not attached.
if (Debug.isDebuggerConnected()) {
debuggerWasConnected = 2;
}
if (debuggerWasConnected >= 2) {
Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
} else if (debuggerWasConnected > 0) {
Slog.w(TAG, "Debugger was connected: Watchdog is *not* killing the system process");
} else if (!allowRestart) {
Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process");
} else {
Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject);
for (int i=0; i<blockedCheckers.size(); i++) {
Slog.w(TAG, blockedCheckers.get(i).getName() + " stack trace:");
StackTraceElement[] stackTrace
= blockedCheckers.get(i).getThread().getStackTrace();
for (StackTraceElement element: stackTrace) {
Slog.w(TAG, " at " + element);
}
}
SystemClock.sleep(25000);
/// @}
Slog.w(TAG, "*** GOODBYE!");
// MTK enhance
if (mSFHang)
{
Slog.w(TAG, "SF hang!");
if (GetSFReboot() > 3)
{
Slog.w(TAG, "SF hang reboot time larger than 3 time, reboot device!");
rebootSystem("Maybe SF driver hang,reboot device.");
}
else
{
SetSFReboot();
}
}
//@
Process.killProcess(Process.myPid());
System.exit(10);
}
waitedHalf = false;
}
}
private void doSysRq(char c) {
try {
FileWriter sysrq_trigger = new FileWriter("/proc/sysrq-trigger");
sysrq_trigger.write(c);
sysrq_trigger.close();
} catch (IOException e) {
Slog.w(TAG, "Failed to write to /proc/sysrq-trigger", e);
}
}
private File dumpKernelStackTraces() {
String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
if (tracesPath == null || tracesPath.length() == 0) {
return null;
}
native_dumpKernelStacks(tracesPath);
return new File(tracesPath);
}
private native void native_dumpKernelStacks(String tracesPath);
/**
* M: WDT debug enhancement
*/
private File dumpAllBackTraces(boolean clearTraces) {
/*debug flag for dump all thread backtrace for ANR*/
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
mActivity.getRunningProcessPids(pids);
File stack = ActivityManagerService.dumpStackTraces(true, pids, null, null, NATIVE_STACKS_OF_INTEREST);
return stack;
}
}
Watchdog 源码分析
最新推荐文章于 2024-09-13 14:41:53 发布