Loading services/java/com/android/server/Watchdog.java +13 −221 Original line number Diff line number Diff line Loading @@ -58,20 +58,7 @@ public class Watchdog extends Thread { // Set this to true to have the watchdog record kernel thread stacks when it fires static final boolean RECORD_KERNEL_THREADS = true; static final int MONITOR = 2718; 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_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 static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0; // never force reboot 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 REBOOT_ACTION = "com.android.service.Watchdog.REBOOT"; static final int TIME_TO_WAIT = DB ? 5*1000 : 30*1000; static final String[] NATIVE_STACKS_OF_INTEREST = new String[] { "/system/bin/mediaserver", Loading @@ -94,24 +81,6 @@ public class Watchdog extends Thread { IActivityController mController; boolean mAllowRestart = true; final Calendar mCalendar = Calendar.getInstance(); int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF; int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM; boolean mNeedScheduledCheck; PendingIntent mCheckupIntent; PendingIntent mRebootIntent; long mBootTime; int mRebootInterval; boolean mReqRebootNoWait; // should wait for one interval before reboot? int mReqRebootInterval = -1; // >= 0 if a reboot has been requested int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested int mReqRebootWindow = -1; // >= 0 if a specific window has been requested int mReqMinScreenOff = -1; // >= 0 if a specific screen off time has been requested int mReqMinNextAlarm = -1; // >= 0 if specific time to next alarm has been requested int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested /** * Used for checking status of handle threads and scheduling monitor callbacks. */ Loading @@ -119,14 +88,12 @@ public class Watchdog extends Thread { private final Handler mHandler; private final String mName; private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>(); private final boolean mCheckReboot; private boolean mCompleted; private Monitor mCurrentMonitor; HandlerChecker(Handler handler, String name, boolean checkReboot) { HandlerChecker(Handler handler, String name) { mHandler = handler; mName = name; mCheckReboot = checkReboot; } public void addMonitor(Monitor monitor) { Loading @@ -134,7 +101,7 @@ public class Watchdog extends Thread { } public void scheduleCheckLocked() { if (!mCheckReboot && mMonitors.size() == 0 && mHandler.getLooper().isIdling()) { if (mMonitors.size() == 0 && mHandler.getLooper().isIdling()) { // If the target looper is or just recently was idling, then // there is no reason to enqueue our checker on it since that // is as good as it not being deadlocked. This avoid having Loading @@ -159,18 +126,6 @@ public class Watchdog extends Thread { @Override public void run() { // See if we should force a reboot. if (mCheckReboot) { int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval : REBOOT_DEFAULT_INTERVAL; if (mRebootInterval != rebootInterval) { mRebootInterval = rebootInterval; // We have been running long enough that a reboot can // be considered... checkReboot(false); } } final int size = mMonitors.size(); for (int i = 0 ; i < size ; i++) { synchronized (Watchdog.this) { Loading @@ -186,29 +141,14 @@ public class Watchdog extends Thread { } } final class RebootReceiver extends BroadcastReceiver { @Override public void onReceive(Context c, Intent intent) { if (localLOGV) Slog.v(TAG, "Alarm went off, checking reboot."); checkReboot(true); } } final class RebootRequestReceiver extends BroadcastReceiver { @Override public void onReceive(Context c, Intent intent) { mReqRebootNoWait = intent.getIntExtra("nowait", 0) != 0; mReqRebootInterval = intent.getIntExtra("interval", -1); mReqRebootStartTime = intent.getIntExtra("startTime", -1); mReqRebootWindow = intent.getIntExtra("window", -1); mReqMinScreenOff = intent.getIntExtra("minScreenOff", -1); mReqMinNextAlarm = intent.getIntExtra("minNextAlarm", -1); mReqRecheckInterval = intent.getIntExtra("recheckInterval", -1); EventLog.writeEvent(EventLogTags.WATCHDOG_REQUESTED_REBOOT, mReqRebootNoWait ? 1 : 0, mReqRebootInterval, mReqRecheckInterval, mReqRebootStartTime, mReqRebootWindow, mReqMinScreenOff, mReqMinNextAlarm); checkReboot(true); if (intent.getIntExtra("nowait", 0) != 0) { rebootSystem("Received ACTION_REBOOT broadcast"); return; } Slog.w(TAG, "Unsupported ACTION_REBOOT broadcast: " + intent); } } Loading @@ -233,16 +173,16 @@ public class Watchdog extends Thread { // The shared foreground thread is the main checker. It is where we // will also dispatch monitor checks and do other work. mMonitorChecker = new HandlerChecker(FgThread.getHandler(), "foreground thread", true); mMonitorChecker = new HandlerChecker(FgThread.getHandler(), "foreground thread"); 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", false)); "main thread")); // Add checker for shared UI thread. mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread", false)); mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread")); // And also check IO thread. mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread", false)); mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread")); } public void init(Context context, BatteryService battery, Loading @@ -254,16 +194,9 @@ public class Watchdog extends Thread { mAlarm = alarm; mActivity = activity; context.registerReceiver(new RebootReceiver(), new IntentFilter(REBOOT_ACTION)); mRebootIntent = PendingIntent.getBroadcast(context, 0, new Intent(REBOOT_ACTION), 0); context.registerReceiver(new RebootRequestReceiver(), new IntentFilter(Intent.ACTION_REBOOT), android.Manifest.permission.REBOOT, null); mBootTime = System.currentTimeMillis(); } public void processStarted(String name, int pid) { Loading Loading @@ -300,85 +233,8 @@ public class Watchdog extends Thread { if (isAlive()) { throw new RuntimeException("Threads can't be added once the Watchdog is running"); } mHandlerCheckers.add(new HandlerChecker(thread, name, false)); } } void checkReboot(boolean fromAlarm) { int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval : REBOOT_DEFAULT_INTERVAL; mRebootInterval = rebootInterval; if (rebootInterval <= 0) { // No reboot interval requested. if (localLOGV) Slog.v(TAG, "No need to schedule a reboot alarm!"); mAlarm.remove(mRebootIntent); return; } long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime : REBOOT_DEFAULT_START_TIME; long rebootWindowMillis = (mReqRebootWindow >= 0 ? mReqRebootWindow : REBOOT_DEFAULT_WINDOW) * 1000; long recheckInterval = (mReqRecheckInterval >= 0 ? mReqRecheckInterval : MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000; retrieveBrutalityAmount(); long realStartTime; long now; synchronized (this) { now = System.currentTimeMillis(); realStartTime = computeCalendarTime(mCalendar, now, rebootStartTime); long rebootIntervalMillis = rebootInterval*24*60*60*1000; if (DB || mReqRebootNoWait || (now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) { if (fromAlarm && rebootWindowMillis <= 0) { // No reboot window -- just immediately reboot. EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now, (int)rebootIntervalMillis, (int)rebootStartTime*1000, (int)rebootWindowMillis, ""); rebootSystem("Checkin scheduled forced"); return; } // Are we within the reboot window? if (now < realStartTime) { // Schedule alarm for next check interval. realStartTime = computeCalendarTime(mCalendar, now, rebootStartTime); } else if (now < (realStartTime+rebootWindowMillis)) { String doit = shouldWeBeBrutalLocked(now); EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now, (int)rebootInterval, (int)rebootStartTime*1000, (int)rebootWindowMillis, doit != null ? doit : ""); if (doit == null) { rebootSystem("Checked scheduled range"); return; } // Schedule next alarm either within the window or in the // next interval. if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) { realStartTime = computeCalendarTime(mCalendar, now + rebootIntervalMillis, rebootStartTime); } else { realStartTime = now + recheckInterval; } } else { // Schedule alarm for next check interval. realStartTime = computeCalendarTime(mCalendar, now + rebootIntervalMillis, rebootStartTime); } } mHandlerCheckers.add(new HandlerChecker(thread, name)); } if (localLOGV) Slog.v(TAG, "Scheduling next reboot alarm for " + ((realStartTime-now)/1000/60) + "m from now"); mAlarm.remove(mRebootIntent); mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent); } /** Loading @@ -390,70 +246,6 @@ public class Watchdog extends Thread { pms.reboot(false, reason, false); } /** * Load the current Gservices settings for when * {@link #shouldWeBeBrutalLocked} will allow the brutality to happen. * Must not be called with the lock held. */ void retrieveBrutalityAmount() { mMinScreenOff = (mReqMinScreenOff >= 0 ? mReqMinScreenOff : MEMCHECK_DEFAULT_MIN_SCREEN_OFF) * 1000; mMinAlarm = (mReqMinNextAlarm >= 0 ? mReqMinNextAlarm : MEMCHECK_DEFAULT_MIN_ALARM) * 1000; } /** * Determine whether it is a good time to kill, crash, or otherwise * plunder the current situation for the overall long-term benefit of * the world. * * @param curTime The current system time. * @return Returns null if this is a good time, else a String with the * text of why it is not a good time. */ String shouldWeBeBrutalLocked(long curTime) { if (mBattery == null || !mBattery.isPowered(BatteryManager.BATTERY_PLUGGED_ANY)) { return "battery"; } if (mMinScreenOff >= 0 && (mPower == null || mPower.timeSinceScreenWasLastOn() < mMinScreenOff)) { return "screen"; } if (mMinAlarm >= 0 && (mAlarm == null || mAlarm.timeToNextAlarm() < mMinAlarm)) { return "alarm"; } return null; } static long computeCalendarTime(Calendar c, long curTime, long secondsSinceMidnight) { // start with now c.setTimeInMillis(curTime); int val = (int)secondsSinceMidnight / (60*60); c.set(Calendar.HOUR_OF_DAY, val); secondsSinceMidnight -= val * (60*60); val = (int)secondsSinceMidnight / 60; c.set(Calendar.MINUTE, val); c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60)); c.set(Calendar.MILLISECOND, 0); long newTime = c.getTimeInMillis(); if (newTime < curTime) { // The given time (in seconds since midnight) has already passed for today, so advance // by one day (due to daylight savings, etc., the delta may differ from 24 hours). c.add(Calendar.DAY_OF_MONTH, 1); newTime = c.getTimeInMillis(); } return newTime; } private boolean haveAllCheckersCompletedLocked() { for (int i=0; i<mHandlerCheckers.size(); i++) { HandlerChecker hc = mHandlerCheckers.get(i); Loading Loading
services/java/com/android/server/Watchdog.java +13 −221 Original line number Diff line number Diff line Loading @@ -58,20 +58,7 @@ public class Watchdog extends Thread { // Set this to true to have the watchdog record kernel thread stacks when it fires static final boolean RECORD_KERNEL_THREADS = true; static final int MONITOR = 2718; 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_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 static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0; // never force reboot 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 REBOOT_ACTION = "com.android.service.Watchdog.REBOOT"; static final int TIME_TO_WAIT = DB ? 5*1000 : 30*1000; static final String[] NATIVE_STACKS_OF_INTEREST = new String[] { "/system/bin/mediaserver", Loading @@ -94,24 +81,6 @@ public class Watchdog extends Thread { IActivityController mController; boolean mAllowRestart = true; final Calendar mCalendar = Calendar.getInstance(); int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF; int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM; boolean mNeedScheduledCheck; PendingIntent mCheckupIntent; PendingIntent mRebootIntent; long mBootTime; int mRebootInterval; boolean mReqRebootNoWait; // should wait for one interval before reboot? int mReqRebootInterval = -1; // >= 0 if a reboot has been requested int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested int mReqRebootWindow = -1; // >= 0 if a specific window has been requested int mReqMinScreenOff = -1; // >= 0 if a specific screen off time has been requested int mReqMinNextAlarm = -1; // >= 0 if specific time to next alarm has been requested int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested /** * Used for checking status of handle threads and scheduling monitor callbacks. */ Loading @@ -119,14 +88,12 @@ public class Watchdog extends Thread { private final Handler mHandler; private final String mName; private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>(); private final boolean mCheckReboot; private boolean mCompleted; private Monitor mCurrentMonitor; HandlerChecker(Handler handler, String name, boolean checkReboot) { HandlerChecker(Handler handler, String name) { mHandler = handler; mName = name; mCheckReboot = checkReboot; } public void addMonitor(Monitor monitor) { Loading @@ -134,7 +101,7 @@ public class Watchdog extends Thread { } public void scheduleCheckLocked() { if (!mCheckReboot && mMonitors.size() == 0 && mHandler.getLooper().isIdling()) { if (mMonitors.size() == 0 && mHandler.getLooper().isIdling()) { // If the target looper is or just recently was idling, then // there is no reason to enqueue our checker on it since that // is as good as it not being deadlocked. This avoid having Loading @@ -159,18 +126,6 @@ public class Watchdog extends Thread { @Override public void run() { // See if we should force a reboot. if (mCheckReboot) { int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval : REBOOT_DEFAULT_INTERVAL; if (mRebootInterval != rebootInterval) { mRebootInterval = rebootInterval; // We have been running long enough that a reboot can // be considered... checkReboot(false); } } final int size = mMonitors.size(); for (int i = 0 ; i < size ; i++) { synchronized (Watchdog.this) { Loading @@ -186,29 +141,14 @@ public class Watchdog extends Thread { } } final class RebootReceiver extends BroadcastReceiver { @Override public void onReceive(Context c, Intent intent) { if (localLOGV) Slog.v(TAG, "Alarm went off, checking reboot."); checkReboot(true); } } final class RebootRequestReceiver extends BroadcastReceiver { @Override public void onReceive(Context c, Intent intent) { mReqRebootNoWait = intent.getIntExtra("nowait", 0) != 0; mReqRebootInterval = intent.getIntExtra("interval", -1); mReqRebootStartTime = intent.getIntExtra("startTime", -1); mReqRebootWindow = intent.getIntExtra("window", -1); mReqMinScreenOff = intent.getIntExtra("minScreenOff", -1); mReqMinNextAlarm = intent.getIntExtra("minNextAlarm", -1); mReqRecheckInterval = intent.getIntExtra("recheckInterval", -1); EventLog.writeEvent(EventLogTags.WATCHDOG_REQUESTED_REBOOT, mReqRebootNoWait ? 1 : 0, mReqRebootInterval, mReqRecheckInterval, mReqRebootStartTime, mReqRebootWindow, mReqMinScreenOff, mReqMinNextAlarm); checkReboot(true); if (intent.getIntExtra("nowait", 0) != 0) { rebootSystem("Received ACTION_REBOOT broadcast"); return; } Slog.w(TAG, "Unsupported ACTION_REBOOT broadcast: " + intent); } } Loading @@ -233,16 +173,16 @@ public class Watchdog extends Thread { // The shared foreground thread is the main checker. It is where we // will also dispatch monitor checks and do other work. mMonitorChecker = new HandlerChecker(FgThread.getHandler(), "foreground thread", true); mMonitorChecker = new HandlerChecker(FgThread.getHandler(), "foreground thread"); 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", false)); "main thread")); // Add checker for shared UI thread. mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread", false)); mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread")); // And also check IO thread. mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread", false)); mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread")); } public void init(Context context, BatteryService battery, Loading @@ -254,16 +194,9 @@ public class Watchdog extends Thread { mAlarm = alarm; mActivity = activity; context.registerReceiver(new RebootReceiver(), new IntentFilter(REBOOT_ACTION)); mRebootIntent = PendingIntent.getBroadcast(context, 0, new Intent(REBOOT_ACTION), 0); context.registerReceiver(new RebootRequestReceiver(), new IntentFilter(Intent.ACTION_REBOOT), android.Manifest.permission.REBOOT, null); mBootTime = System.currentTimeMillis(); } public void processStarted(String name, int pid) { Loading Loading @@ -300,85 +233,8 @@ public class Watchdog extends Thread { if (isAlive()) { throw new RuntimeException("Threads can't be added once the Watchdog is running"); } mHandlerCheckers.add(new HandlerChecker(thread, name, false)); } } void checkReboot(boolean fromAlarm) { int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval : REBOOT_DEFAULT_INTERVAL; mRebootInterval = rebootInterval; if (rebootInterval <= 0) { // No reboot interval requested. if (localLOGV) Slog.v(TAG, "No need to schedule a reboot alarm!"); mAlarm.remove(mRebootIntent); return; } long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime : REBOOT_DEFAULT_START_TIME; long rebootWindowMillis = (mReqRebootWindow >= 0 ? mReqRebootWindow : REBOOT_DEFAULT_WINDOW) * 1000; long recheckInterval = (mReqRecheckInterval >= 0 ? mReqRecheckInterval : MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000; retrieveBrutalityAmount(); long realStartTime; long now; synchronized (this) { now = System.currentTimeMillis(); realStartTime = computeCalendarTime(mCalendar, now, rebootStartTime); long rebootIntervalMillis = rebootInterval*24*60*60*1000; if (DB || mReqRebootNoWait || (now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) { if (fromAlarm && rebootWindowMillis <= 0) { // No reboot window -- just immediately reboot. EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now, (int)rebootIntervalMillis, (int)rebootStartTime*1000, (int)rebootWindowMillis, ""); rebootSystem("Checkin scheduled forced"); return; } // Are we within the reboot window? if (now < realStartTime) { // Schedule alarm for next check interval. realStartTime = computeCalendarTime(mCalendar, now, rebootStartTime); } else if (now < (realStartTime+rebootWindowMillis)) { String doit = shouldWeBeBrutalLocked(now); EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now, (int)rebootInterval, (int)rebootStartTime*1000, (int)rebootWindowMillis, doit != null ? doit : ""); if (doit == null) { rebootSystem("Checked scheduled range"); return; } // Schedule next alarm either within the window or in the // next interval. if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) { realStartTime = computeCalendarTime(mCalendar, now + rebootIntervalMillis, rebootStartTime); } else { realStartTime = now + recheckInterval; } } else { // Schedule alarm for next check interval. realStartTime = computeCalendarTime(mCalendar, now + rebootIntervalMillis, rebootStartTime); } } mHandlerCheckers.add(new HandlerChecker(thread, name)); } if (localLOGV) Slog.v(TAG, "Scheduling next reboot alarm for " + ((realStartTime-now)/1000/60) + "m from now"); mAlarm.remove(mRebootIntent); mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent); } /** Loading @@ -390,70 +246,6 @@ public class Watchdog extends Thread { pms.reboot(false, reason, false); } /** * Load the current Gservices settings for when * {@link #shouldWeBeBrutalLocked} will allow the brutality to happen. * Must not be called with the lock held. */ void retrieveBrutalityAmount() { mMinScreenOff = (mReqMinScreenOff >= 0 ? mReqMinScreenOff : MEMCHECK_DEFAULT_MIN_SCREEN_OFF) * 1000; mMinAlarm = (mReqMinNextAlarm >= 0 ? mReqMinNextAlarm : MEMCHECK_DEFAULT_MIN_ALARM) * 1000; } /** * Determine whether it is a good time to kill, crash, or otherwise * plunder the current situation for the overall long-term benefit of * the world. * * @param curTime The current system time. * @return Returns null if this is a good time, else a String with the * text of why it is not a good time. */ String shouldWeBeBrutalLocked(long curTime) { if (mBattery == null || !mBattery.isPowered(BatteryManager.BATTERY_PLUGGED_ANY)) { return "battery"; } if (mMinScreenOff >= 0 && (mPower == null || mPower.timeSinceScreenWasLastOn() < mMinScreenOff)) { return "screen"; } if (mMinAlarm >= 0 && (mAlarm == null || mAlarm.timeToNextAlarm() < mMinAlarm)) { return "alarm"; } return null; } static long computeCalendarTime(Calendar c, long curTime, long secondsSinceMidnight) { // start with now c.setTimeInMillis(curTime); int val = (int)secondsSinceMidnight / (60*60); c.set(Calendar.HOUR_OF_DAY, val); secondsSinceMidnight -= val * (60*60); val = (int)secondsSinceMidnight / 60; c.set(Calendar.MINUTE, val); c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60)); c.set(Calendar.MILLISECOND, 0); long newTime = c.getTimeInMillis(); if (newTime < curTime) { // The given time (in seconds since midnight) has already passed for today, so advance // by one day (due to daylight savings, etc., the delta may differ from 24 hours). c.add(Calendar.DAY_OF_MONTH, 1); newTime = c.getTimeInMillis(); } return newTime; } private boolean haveAllCheckersCompletedLocked() { for (int i=0; i<mHandlerCheckers.size(); i++) { HandlerChecker hc = mHandlerCheckers.get(i); Loading