diff options
Diffstat (limited to 'services/java/com/android/server/Watchdog.java')
-rw-r--r-- | services/java/com/android/server/Watchdog.java | 413 |
1 files changed, 1 insertions, 412 deletions
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java index d4133f3..a742093 100644 --- a/services/java/com/android/server/Watchdog.java +++ b/services/java/com/android/server/Watchdog.java @@ -57,20 +57,10 @@ public class Watchdog extends Thread { static final boolean RECORD_KERNEL_THREADS = true; static final int MONITOR = 2718; - static final int GLOBAL_PSS = 2719; static final int TIME_TO_RESTART = DB ? 15*1000 : 60*1000; static final int TIME_TO_WAIT = TIME_TO_RESTART / 2; - static final int MEMCHECK_DEFAULT_INTERVAL = DB ? 30 : 30*60; // 30 minutes - static final int MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL = DB ? 60 : 2*60*60; // 2 hours - static final int MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD = (DB ? 10:16)*1024*1024; // 16MB - static final int MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD = (DB ? 14:20)*1024*1024; // 20MB - static final int MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD = (DB ? 4:8)*1024*1024; // 8MB - static final int MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD = (DB ? 8:12)*1024*1024; // 12MB - - static final int MEMCHECK_DEFAULT_EXEC_START_TIME = 1*60*60; // 1:00am - static final int MEMCHECK_DEFAULT_EXEC_END_TIME = 5*60*60; // 5:00am static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60; // 5 minutes static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60; // 3 minutes static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes @@ -79,14 +69,12 @@ public class Watchdog extends Thread { static final int REBOOT_DEFAULT_START_TIME = 3*60*60; // 3:00am static final int REBOOT_DEFAULT_WINDOW = 60*60; // within 1 hour - static final String CHECKUP_ACTION = "com.android.service.Watchdog.CHECKUP"; static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT"; static Watchdog sWatchdog; /* This handler will be used to post message back onto the main thread */ final Handler mHandler; - final Runnable mGlobalPssCollected; final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>(); ContentResolver mResolver; BatteryService mBattery; @@ -97,31 +85,9 @@ public class Watchdog extends Thread { boolean mForceKillSystem; Monitor mCurrentMonitor; - PssRequestor mPhoneReq; int mPhonePid; - int mPhonePss; - - long mLastMemCheckTime = -(MEMCHECK_DEFAULT_INTERVAL*1000); - boolean mHavePss; - long mLastMemCheckRealtime = -(MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL*1000); - boolean mHaveGlobalPss; - final MemMonitor mSystemMemMonitor = new MemMonitor("system", - Settings.Secure.MEMCHECK_SYSTEM_ENABLED, - Settings.Secure.MEMCHECK_SYSTEM_SOFT_THRESHOLD, - MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD, - Settings.Secure.MEMCHECK_SYSTEM_HARD_THRESHOLD, - MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD); - final MemMonitor mPhoneMemMonitor = new MemMonitor("com.android.phone", - Settings.Secure.MEMCHECK_PHONE_ENABLED, - Settings.Secure.MEMCHECK_PHONE_SOFT_THRESHOLD, - MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD, - Settings.Secure.MEMCHECK_PHONE_HARD_THRESHOLD, - MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD); final Calendar mCalendar = Calendar.getInstance(); - long mMemcheckLastTime; - long mMemcheckExecStartTime; - long mMemcheckExecEndTime; int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF; int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM; boolean mNeedScheduledCheck; @@ -140,126 +106,13 @@ public class Watchdog extends Thread { int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested /** - * This class monitors the memory in a particular process. - */ - final class MemMonitor { - final String mProcessName; - final String mEnabledSetting; - final String mSoftSetting; - final String mHardSetting; - - int mSoftThreshold; - int mHardThreshold; - boolean mEnabled; - long mLastPss; - - static final int STATE_OK = 0; - static final int STATE_SOFT = 1; - static final int STATE_HARD = 2; - int mState; - - MemMonitor(String processName, String enabledSetting, - String softSetting, int defSoftThreshold, - String hardSetting, int defHardThreshold) { - mProcessName = processName; - mEnabledSetting = enabledSetting; - mSoftSetting = softSetting; - mHardSetting = hardSetting; - mSoftThreshold = defSoftThreshold; - mHardThreshold = defHardThreshold; - } - - void retrieveSettings(ContentResolver resolver) { - mSoftThreshold = Settings.Secure.getInt( - resolver, mSoftSetting, mSoftThreshold); - mHardThreshold = Settings.Secure.getInt( - resolver, mHardSetting, mHardThreshold); - mEnabled = Settings.Secure.getInt( - resolver, mEnabledSetting, 0) != 0; - } - - boolean checkLocked(long curTime, int pid, int pss) { - mLastPss = pss; - if (mLastPss < mSoftThreshold) { - mState = STATE_OK; - } else if (mLastPss < mHardThreshold) { - mState = STATE_SOFT; - } else { - mState = STATE_HARD; - } - EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_PSS, mProcessName, pid, mLastPss); - - if (mState == STATE_OK) { - // Memory is good, don't recover. - return false; - } - - if (mState == STATE_HARD) { - // Memory is really bad, kill right now. - EventLog.writeEvent(EventLogTags.WATCHDOG_HARD_RESET, mProcessName, pid, - mHardThreshold, mLastPss); - return mEnabled; - } - - // It is time to schedule a reset... - // Check if we are currently within the time to kill processes due - // to memory use. - computeMemcheckTimesLocked(curTime); - String skipReason = null; - if (curTime < mMemcheckExecStartTime || curTime > mMemcheckExecEndTime) { - skipReason = "time"; - } else { - skipReason = shouldWeBeBrutalLocked(curTime); - } - EventLog.writeEvent(EventLogTags.WATCHDOG_SOFT_RESET, mProcessName, pid, - mSoftThreshold, mLastPss, skipReason != null ? skipReason : ""); - if (skipReason != null) { - mNeedScheduledCheck = true; - return false; - } - return mEnabled; - } - - void clear() { - mLastPss = 0; - mState = STATE_OK; - } - } - - /** * Used for scheduling monitor callbacks and checking memory usage. */ final class HeartbeatHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { - case GLOBAL_PSS: { - if (mHaveGlobalPss) { - // During the last pass we collected pss information, so - // now it is time to report it. - mHaveGlobalPss = false; - if (localLOGV) Slog.v(TAG, "Received global pss, logging."); - logGlobalMemory(); - } - } break; - case MONITOR: { - if (mHavePss) { - // During the last pass we collected pss information, so - // now it is time to report it. - mHavePss = false; - if (localLOGV) Slog.v(TAG, "Have pss, checking memory."); - checkMemory(); - } - - if (mHaveGlobalPss) { - // During the last pass we collected pss information, so - // now it is time to report it. - mHaveGlobalPss = false; - if (localLOGV) Slog.v(TAG, "Have global pss, logging."); - logGlobalMemory(); - } - long now = SystemClock.uptimeMillis(); // See if we should force a reboot. @@ -274,32 +127,6 @@ public class Watchdog extends Thread { checkReboot(false); } - // See if we should check memory conditions. - long memCheckInterval = Settings.Secure.getLong( - mResolver, Settings.Secure.MEMCHECK_INTERVAL, - MEMCHECK_DEFAULT_INTERVAL) * 1000; - if ((mLastMemCheckTime+memCheckInterval) < now) { - // It is now time to collect pss information. This - // is async so we won't report it now. And to keep - // things simple, we will assume that everyone has - // reported back by the next MONITOR message. - mLastMemCheckTime = now; - if (localLOGV) Slog.v(TAG, "Collecting memory usage."); - collectMemory(); - mHavePss = true; - - long memCheckRealtimeInterval = Settings.Secure.getLong( - mResolver, Settings.Secure.MEMCHECK_LOG_REALTIME_INTERVAL, - MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL) * 1000; - long realtimeNow = SystemClock.elapsedRealtime(); - if ((mLastMemCheckRealtime+memCheckRealtimeInterval) < realtimeNow) { - mLastMemCheckRealtime = realtimeNow; - if (localLOGV) Slog.v(TAG, "Collecting global memory usage."); - collectGlobalMemory(); - mHaveGlobalPss = true; - } - } - final int size = mMonitors.size(); for (int i = 0 ; i < size ; i++) { mCurrentMonitor = mMonitors.get(i); @@ -315,20 +142,6 @@ public class Watchdog extends Thread { } } - final class GlobalPssCollected implements Runnable { - public void run() { - mHandler.sendEmptyMessage(GLOBAL_PSS); - } - } - - final class CheckupReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context c, Intent intent) { - if (localLOGV) Slog.v(TAG, "Alarm went off, checking memory."); - checkMemory(); - } - } - final class RebootReceiver extends BroadcastReceiver { @Override public void onReceive(Context c, Intent intent) { @@ -359,27 +172,6 @@ public class Watchdog extends Thread { void monitor(); } - public interface PssRequestor { - void requestPss(); - } - - public class PssStats { - public int mEmptyPss; - public int mEmptyCount; - public int mBackgroundPss; - public int mBackgroundCount; - public int mServicePss; - public int mServiceCount; - public int mVisiblePss; - public int mVisibleCount; - public int mForegroundPss; - public int mForegroundCount; - - public int mNoPssCount; - - public int mProcDeaths[] = new int[10]; - } - public static Watchdog getInstance() { if (sWatchdog == null) { sWatchdog = new Watchdog(); @@ -391,7 +183,6 @@ public class Watchdog extends Thread { private Watchdog() { super("watchdog"); mHandler = new HeartbeatHandler(); - mGlobalPssCollected = new GlobalPssCollected(); } public void init(Context context, BatteryService battery, @@ -403,11 +194,6 @@ public class Watchdog extends Thread { mAlarm = alarm; mActivity = activity; - context.registerReceiver(new CheckupReceiver(), - new IntentFilter(CHECKUP_ACTION)); - mCheckupIntent = PendingIntent.getBroadcast(context, - 0, new Intent(CHECKUP_ACTION), 0); - context.registerReceiver(new RebootReceiver(), new IntentFilter(REBOOT_ACTION)); mRebootIntent = PendingIntent.getBroadcast(context, @@ -420,20 +206,10 @@ public class Watchdog extends Thread { mBootTime = System.currentTimeMillis(); } - public void processStarted(PssRequestor req, String name, int pid) { + public void processStarted(String name, int pid) { synchronized (this) { if ("com.android.phone".equals(name)) { - mPhoneReq = req; mPhonePid = pid; - mPhonePss = 0; - } - } - } - - public void reportPss(PssRequestor req, String name, int pss) { - synchronized (this) { - if (mPhoneReq == req) { - mPhonePss = pss; } } } @@ -447,152 +223,6 @@ public class Watchdog extends Thread { } } - /** - * Retrieve memory usage information from specific processes being - * monitored. This is an async operation, so must be done before doing - * memory checks. - */ - void collectMemory() { - synchronized (this) { - if (mPhoneReq != null) { - mPhoneReq.requestPss(); - } - } - } - - /** - * Retrieve memory usage over all application processes. This is an - * async operation, so must be done before doing memory checks. - */ - void collectGlobalMemory() { - mActivity.requestPss(mGlobalPssCollected); - } - - /** - * Check memory usage in the system, scheduling kills/reboots as needed. - * This always runs on the mHandler thread. - */ - void checkMemory() { - boolean needScheduledCheck; - long curTime; - long nextTime = 0; - - long recheckInterval = Settings.Secure.getLong( - mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL, - MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000; - - mSystemMemMonitor.retrieveSettings(mResolver); - mPhoneMemMonitor.retrieveSettings(mResolver); - retrieveBrutalityAmount(); - - synchronized (this) { - curTime = System.currentTimeMillis(); - mNeedScheduledCheck = false; - - // How is the system doing? - if (mSystemMemMonitor.checkLocked(curTime, Process.myPid(), - (int)Process.getPss(Process.myPid()))) { - // Not good! Time to suicide. - mForceKillSystem = true; - notifyAll(); - return; - } - - // How is the phone process doing? - if (mPhoneReq != null) { - if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid, - mPhonePss)) { - // Just kill the phone process and let it restart. - Slog.i(TAG, "Watchdog is killing the phone process"); - Process.killProcess(mPhonePid); - } - } else { - mPhoneMemMonitor.clear(); - } - - needScheduledCheck = mNeedScheduledCheck; - if (needScheduledCheck) { - // Something is going bad, but now is not a good time to - // tear things down... schedule an alarm to check again soon. - nextTime = curTime + recheckInterval; - if (nextTime < mMemcheckExecStartTime) { - nextTime = mMemcheckExecStartTime; - } else if (nextTime >= mMemcheckExecEndTime){ - // Need to check during next exec time... so that needs - // to be computed. - if (localLOGV) Slog.v(TAG, "Computing next time range"); - computeMemcheckTimesLocked(nextTime); - nextTime = mMemcheckExecStartTime; - } - - if (localLOGV) { - mCalendar.setTimeInMillis(nextTime); - Slog.v(TAG, "Next Alarm Time: " + mCalendar); - } - } - } - - if (needScheduledCheck) { - if (localLOGV) Slog.v(TAG, "Scheduling next memcheck alarm for " - + ((nextTime-curTime)/1000/60) + "m from now"); - mAlarm.remove(mCheckupIntent); - mAlarm.set(AlarmManager.RTC_WAKEUP, nextTime, mCheckupIntent); - } else { - if (localLOGV) Slog.v(TAG, "No need to schedule a memcheck alarm!"); - mAlarm.remove(mCheckupIntent); - } - } - - final PssStats mPssStats = new PssStats(); - final String[] mMemInfoFields = new String[] { - "MemFree:", "Buffers:", "Cached:", - "Active:", "Inactive:", - "AnonPages:", "Mapped:", "Slab:", - "SReclaimable:", "SUnreclaim:", "PageTables:" }; - final long[] mMemInfoSizes = new long[mMemInfoFields.length]; - final String[] mVMStatFields = new String[] { - "pgfree ", "pgactivate ", "pgdeactivate ", - "pgfault ", "pgmajfault " }; - final long[] mVMStatSizes = new long[mVMStatFields.length]; - final long[] mPrevVMStatSizes = new long[mVMStatFields.length]; - long mLastLogGlobalMemoryTime; - - void logGlobalMemory() { - PssStats stats = mPssStats; - mActivity.collectPss(stats); - EventLog.writeEvent(EventLogTags.WATCHDOG_PSS_STATS, - stats.mEmptyPss, stats.mEmptyCount, - stats.mBackgroundPss, stats.mBackgroundCount, - stats.mServicePss, stats.mServiceCount, - stats.mVisiblePss, stats.mVisibleCount, - stats.mForegroundPss, stats.mForegroundCount, - stats.mNoPssCount); - EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_STATS, - stats.mProcDeaths[0], stats.mProcDeaths[1], stats.mProcDeaths[2], - stats.mProcDeaths[3], stats.mProcDeaths[4]); - Process.readProcLines("/proc/meminfo", mMemInfoFields, mMemInfoSizes); - for (int i=0; i<mMemInfoSizes.length; i++) { - mMemInfoSizes[i] *= 1024; - } - EventLog.writeEvent(EventLogTags.WATCHDOG_MEMINFO, - (int)mMemInfoSizes[0], (int)mMemInfoSizes[1], (int)mMemInfoSizes[2], - (int)mMemInfoSizes[3], (int)mMemInfoSizes[4], - (int)mMemInfoSizes[5], (int)mMemInfoSizes[6], (int)mMemInfoSizes[7], - (int)mMemInfoSizes[8], (int)mMemInfoSizes[9], (int)mMemInfoSizes[10]); - long now = SystemClock.uptimeMillis(); - long dur = now - mLastLogGlobalMemoryTime; - mLastLogGlobalMemoryTime = now; - Process.readProcLines("/proc/vmstat", mVMStatFields, mVMStatSizes); - for (int i=0; i<mVMStatSizes.length; i++) { - long v = mVMStatSizes[i]; - mVMStatSizes[i] -= mPrevVMStatSizes[i]; - mPrevVMStatSizes[i] = v; - } - EventLog.writeEvent(EventLogTags.WATCHDOG_VMSTAT, dur, - (int)mVMStatSizes[0], (int)mVMStatSizes[1], (int)mVMStatSizes[2], - (int)mVMStatSizes[3], (int)mVMStatSizes[4]); - } - void checkReboot(boolean fromAlarm) { int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval : Settings.Secure.getInt( @@ -730,47 +360,6 @@ public class Watchdog extends Thread { return null; } - /** - * Compute the times during which we next would like to perform process - * restarts. - * - * @param curTime The current system time. - */ - void computeMemcheckTimesLocked(long curTime) { - if (mMemcheckLastTime == curTime) { - return; - } - - mMemcheckLastTime = curTime; - - long memcheckExecStartTime = Settings.Secure.getLong( - mResolver, Settings.Secure.MEMCHECK_EXEC_START_TIME, - MEMCHECK_DEFAULT_EXEC_START_TIME); - long memcheckExecEndTime = Settings.Secure.getLong( - mResolver, Settings.Secure.MEMCHECK_EXEC_END_TIME, - MEMCHECK_DEFAULT_EXEC_END_TIME); - - mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime, - memcheckExecEndTime); - if (mMemcheckExecEndTime < curTime) { - memcheckExecStartTime += 24*60*60; - memcheckExecEndTime += 24*60*60; - mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime, - memcheckExecEndTime); - } - mMemcheckExecStartTime = computeCalendarTime(mCalendar, curTime, - memcheckExecStartTime); - - if (localLOGV) { - mCalendar.setTimeInMillis(curTime); - Slog.v(TAG, "Current Time: " + mCalendar); - mCalendar.setTimeInMillis(mMemcheckExecStartTime); - Slog.v(TAG, "Start Check Time: " + mCalendar); - mCalendar.setTimeInMillis(mMemcheckExecEndTime); - Slog.v(TAG, "End Check Time: " + mCalendar); - } - } - static long computeCalendarTime(Calendar c, long curTime, long secondsSinceMidnight) { |