blob: 70f54cafe3a979a25e8c9e3319afd5f722bfa28e [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import com.android.server.am.ActivityManagerService;
20
21import android.app.AlarmManager;
22import android.app.PendingIntent;
23import android.content.BroadcastReceiver;
24import android.content.ContentResolver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.os.Debug;
29import android.os.Handler;
30import android.os.Message;
31import android.os.Process;
32import android.os.SystemClock;
33import android.os.SystemProperties;
34import android.provider.Settings;
35import android.util.Config;
36import android.util.EventLog;
37import android.util.Log;
38
39import java.util.ArrayList;
40import java.util.Calendar;
41
42/** This class calls its monitor every minute. Killing this process if they don't return **/
43public class Watchdog extends Thread {
44 static final String TAG = "Watchdog";
45 static final boolean localLOGV = false || Config.LOGV;
46
47 // Set this to true to use debug default values.
48 static final boolean DB = false;
49
50 static final int MONITOR = 2718;
51 static final int GLOBAL_PSS = 2719;
52
53 static final int TIME_TO_WAIT = DB ? 15*1000 : 60*1000;
54 static final int EVENT_LOG_TAG = 2802;
55 static final int EVENT_LOG_PROC_PSS_TAG = 2803;
56 static final int EVENT_LOG_SOFT_RESET_TAG = 2804;
57 static final int EVENT_LOG_HARD_RESET_TAG = 2805;
58 static final int EVENT_LOG_PSS_STATS_TAG = 2806;
59 static final int EVENT_LOG_PROC_STATS_TAG = 2807;
60 static final int EVENT_LOG_SCHEDULED_REBOOT_TAG = 2808;
61 static final int EVENT_LOG_MEMINFO_TAG = 2809;
62 static final int EVENT_LOG_VMSTAT_TAG = 2810;
63 static final int EVENT_LOG_REQUESTED_REBOOT_TAG = 2811;
64
65 static final int MEMCHECK_DEFAULT_INTERVAL = DB ? 30 : 30*60; // 30 minutes
66 static final int MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL = DB ? 60 : 2*60*60; // 2 hours
67 static final int MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD = (DB ? 10:16)*1024*1024; // 16MB
68 static final int MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD = (DB ? 14:20)*1024*1024; // 20MB
69 static final int MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD = (DB ? 4:8)*1024*1024; // 8MB
70 static final int MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD = (DB ? 8:12)*1024*1024; // 12MB
71
72 static final int MEMCHECK_DEFAULT_EXEC_START_TIME = 1*60*60; // 1:00am
73 static final int MEMCHECK_DEFAULT_EXEC_END_TIME = 5*60*60; // 5:00am
74 static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60; // 5 minutes
75 static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60; // 3 minutes
76 static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes
77
78 static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0; // never force reboot
79 static final int REBOOT_DEFAULT_START_TIME = 3*60*60; // 3:00am
80 static final int REBOOT_DEFAULT_WINDOW = 60*60; // within 1 hour
81
82 static final String CHECKUP_ACTION = "com.android.service.Watchdog.CHECKUP";
83 static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";
84
85 static Watchdog sWatchdog;
86
87 /* This handler will be used to post message back onto the main thread */
88 final Handler mHandler;
89 final Runnable mGlobalPssCollected;
90 final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
91 ContentResolver mResolver;
92 BatteryService mBattery;
93 PowerManagerService mPower;
94 AlarmManagerService mAlarm;
95 ActivityManagerService mActivity;
96 boolean mCompleted;
97 boolean mForceKillSystem;
98 Monitor mCurrentMonitor;
99
100 PssRequestor mPhoneReq;
101 int mPhonePid;
102 int mPhonePss;
103
104 long mLastMemCheckTime = -(MEMCHECK_DEFAULT_INTERVAL*1000);
105 boolean mHavePss;
106 long mLastMemCheckRealtime = -(MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL*1000);
107 boolean mHaveGlobalPss;
108 final MemMonitor mSystemMemMonitor = new MemMonitor("system",
109 Settings.Gservices.MEMCHECK_SYSTEM_ENABLED,
110 Settings.Gservices.MEMCHECK_SYSTEM_SOFT_THRESHOLD,
111 MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD,
112 Settings.Gservices.MEMCHECK_SYSTEM_HARD_THRESHOLD,
113 MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD);
114 final MemMonitor mPhoneMemMonitor = new MemMonitor("com.android.phone",
115 Settings.Gservices.MEMCHECK_PHONE_ENABLED,
116 Settings.Gservices.MEMCHECK_PHONE_SOFT_THRESHOLD,
117 MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD,
118 Settings.Gservices.MEMCHECK_PHONE_HARD_THRESHOLD,
119 MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD);
120
121 final Calendar mCalendar = Calendar.getInstance();
122 long mMemcheckLastTime;
123 long mMemcheckExecStartTime;
124 long mMemcheckExecEndTime;
125 int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF;
126 int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM;
127 boolean mNeedScheduledCheck;
128 PendingIntent mCheckupIntent;
129 PendingIntent mRebootIntent;
130
131 long mBootTime;
132 int mRebootInterval;
133
134 boolean mReqRebootNoWait; // should wait for one interval before reboot?
135 int mReqRebootInterval = -1; // >= 0 if a reboot has been requested
136 int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested
137 int mReqRebootWindow = -1; // >= 0 if a specific window has been requested
138 int mReqMinScreenOff = -1; // >= 0 if a specific screen off time has been requested
139 int mReqMinNextAlarm = -1; // >= 0 if specific time to next alarm has been requested
140 int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested
141
142 /**
143 * This class monitors the memory in a particular process.
144 */
145 final class MemMonitor {
146 final String mProcessName;
147 final String mEnabledSetting;
148 final String mSoftSetting;
149 final String mHardSetting;
150
151 int mSoftThreshold;
152 int mHardThreshold;
153 boolean mEnabled;
154 long mLastPss;
155
156 static final int STATE_OK = 0;
157 static final int STATE_SOFT = 1;
158 static final int STATE_HARD = 2;
159 int mState;
160
161 MemMonitor(String processName, String enabledSetting,
162 String softSetting, int defSoftThreshold,
163 String hardSetting, int defHardThreshold) {
164 mProcessName = processName;
165 mEnabledSetting = enabledSetting;
166 mSoftSetting = softSetting;
167 mHardSetting = hardSetting;
168 mSoftThreshold = defSoftThreshold;
169 mHardThreshold = defHardThreshold;
170 }
171
172 void retrieveSettings(ContentResolver resolver) {
173 mSoftThreshold = Settings.Gservices.getInt(
174 resolver, mSoftSetting, mSoftThreshold);
175 mHardThreshold = Settings.Gservices.getInt(
176 resolver, mHardSetting, mHardThreshold);
177 mEnabled = Settings.Gservices.getInt(
178 resolver, mEnabledSetting, 0) != 0;
179 }
180
181 boolean checkLocked(long curTime, int pid, int pss) {
182 mLastPss = pss;
183 if (mLastPss < mSoftThreshold) {
184 mState = STATE_OK;
185 } else if (mLastPss < mHardThreshold) {
186 mState = STATE_SOFT;
187 } else {
188 mState = STATE_HARD;
189 }
190 EventLog.writeEvent(EVENT_LOG_PROC_PSS_TAG, mProcessName, pid, mLastPss);
191
192 if (mState == STATE_OK) {
193 // Memory is good, don't recover.
194 return false;
195 }
196
197 if (mState == STATE_HARD) {
198 // Memory is really bad, kill right now.
199 EventLog.writeEvent(EVENT_LOG_HARD_RESET_TAG, mProcessName, pid,
200 mHardThreshold, mLastPss);
201 return mEnabled;
202 }
203
204 // It is time to schedule a reset...
205 // Check if we are currently within the time to kill processes due
206 // to memory use.
207 computeMemcheckTimesLocked(curTime);
208 String skipReason = null;
209 if (curTime < mMemcheckExecStartTime || curTime > mMemcheckExecEndTime) {
210 skipReason = "time";
211 } else {
212 skipReason = shouldWeBeBrutalLocked(curTime);
213 }
214 EventLog.writeEvent(EVENT_LOG_SOFT_RESET_TAG, mProcessName, pid,
215 mSoftThreshold, mLastPss, skipReason != null ? skipReason : "");
216 if (skipReason != null) {
217 mNeedScheduledCheck = true;
218 return false;
219 }
220 return mEnabled;
221 }
222
223 void clear() {
224 mLastPss = 0;
225 mState = STATE_OK;
226 }
227 }
228
229 /**
230 * Used for scheduling monitor callbacks and checking memory usage.
231 */
232 final class HeartbeatHandler extends Handler {
233 @Override
234 public void handleMessage(Message msg) {
235 switch (msg.what) {
236 case GLOBAL_PSS: {
237 if (mHaveGlobalPss) {
238 // During the last pass we collected pss information, so
239 // now it is time to report it.
240 mHaveGlobalPss = false;
241 if (localLOGV) Log.v(TAG, "Received global pss, logging.");
242 logGlobalMemory();
243 }
244 } break;
245
246 case MONITOR: {
247 if (mHavePss) {
248 // During the last pass we collected pss information, so
249 // now it is time to report it.
250 mHavePss = false;
251 if (localLOGV) Log.v(TAG, "Have pss, checking memory.");
252 checkMemory();
253 }
254
255 if (mHaveGlobalPss) {
256 // During the last pass we collected pss information, so
257 // now it is time to report it.
258 mHaveGlobalPss = false;
259 if (localLOGV) Log.v(TAG, "Have global pss, logging.");
260 logGlobalMemory();
261 }
262
263 long now = SystemClock.uptimeMillis();
264
265 // See if we should force a reboot.
266 int rebootInterval = mReqRebootInterval >= 0
267 ? mReqRebootInterval : Settings.Gservices.getInt(
268 mResolver, Settings.Gservices.REBOOT_INTERVAL,
269 REBOOT_DEFAULT_INTERVAL);
270 if (mRebootInterval != rebootInterval) {
271 mRebootInterval = rebootInterval;
272 // We have been running long enough that a reboot can
273 // be considered...
274 checkReboot(false);
275 }
276
277 // See if we should check memory conditions.
278 long memCheckInterval = Settings.Gservices.getLong(
279 mResolver, Settings.Gservices.MEMCHECK_INTERVAL,
280 MEMCHECK_DEFAULT_INTERVAL) * 1000;
281 if ((mLastMemCheckTime+memCheckInterval) < now) {
282 // It is now time to collect pss information. This
283 // is async so we won't report it now. And to keep
284 // things simple, we will assume that everyone has
285 // reported back by the next MONITOR message.
286 mLastMemCheckTime = now;
287 if (localLOGV) Log.v(TAG, "Collecting memory usage.");
288 collectMemory();
289 mHavePss = true;
290
291 long memCheckRealtimeInterval = Settings.Gservices.getLong(
292 mResolver, Settings.Gservices.MEMCHECK_LOG_REALTIME_INTERVAL,
293 MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL) * 1000;
294 long realtimeNow = SystemClock.elapsedRealtime();
295 if ((mLastMemCheckRealtime+memCheckRealtimeInterval) < realtimeNow) {
296 mLastMemCheckRealtime = realtimeNow;
297 if (localLOGV) Log.v(TAG, "Collecting global memory usage.");
298 collectGlobalMemory();
299 mHaveGlobalPss = true;
300 }
301 }
302
303 final int size = mMonitors.size();
304 for (int i = 0 ; i < size ; i++) {
305 mCurrentMonitor = mMonitors.get(i);
306 mCurrentMonitor.monitor();
307 }
308
309 synchronized (Watchdog.this) {
310 mCompleted = true;
311 mCurrentMonitor = null;
312 }
313 } break;
314 }
315 }
316 }
317
318 final class GlobalPssCollected implements Runnable {
319 public void run() {
320 mHandler.sendEmptyMessage(GLOBAL_PSS);
321 }
322 }
323
324 final class CheckupReceiver extends BroadcastReceiver {
325 @Override
326 public void onReceive(Context c, Intent intent) {
327 if (localLOGV) Log.v(TAG, "Alarm went off, checking memory.");
328 checkMemory();
329 }
330 }
331
332 final class RebootReceiver extends BroadcastReceiver {
333 @Override
334 public void onReceive(Context c, Intent intent) {
335 if (localLOGV) Log.v(TAG, "Alarm went off, checking reboot.");
336 checkReboot(true);
337 }
338 }
339
340 final class RebootRequestReceiver extends BroadcastReceiver {
341 @Override
342 public void onReceive(Context c, Intent intent) {
343 mReqRebootNoWait = intent.getIntExtra("nowait", 0) != 0;
344 mReqRebootInterval = intent.getIntExtra("interval", -1);
345 mReqRebootStartTime = intent.getIntExtra("startTime", -1);
346 mReqRebootWindow = intent.getIntExtra("window", -1);
347 mReqMinScreenOff = intent.getIntExtra("minScreenOff", -1);
348 mReqMinNextAlarm = intent.getIntExtra("minNextAlarm", -1);
349 mReqRecheckInterval = intent.getIntExtra("recheckInterval", -1);
350 EventLog.writeEvent(EVENT_LOG_REQUESTED_REBOOT_TAG,
351 mReqRebootNoWait ? 1 : 0, mReqRebootInterval,
352 mReqRecheckInterval, mReqRebootStartTime,
353 mReqRebootWindow, mReqMinScreenOff, mReqMinNextAlarm);
354 checkReboot(true);
355 }
356 }
357
358 public interface Monitor {
359 void monitor();
360 }
361
362 public interface PssRequestor {
363 void requestPss();
364 }
365
366 public class PssStats {
367 public int mEmptyPss;
368 public int mEmptyCount;
369 public int mBackgroundPss;
370 public int mBackgroundCount;
371 public int mServicePss;
372 public int mServiceCount;
373 public int mVisiblePss;
374 public int mVisibleCount;
375 public int mForegroundPss;
376 public int mForegroundCount;
377
378 public int mNoPssCount;
379
380 public int mProcDeaths[] = new int[10];
381 }
382
383 public static Watchdog getInstance() {
384 if (sWatchdog == null) {
385 sWatchdog = new Watchdog();
386 }
387
388 return sWatchdog;
389 }
390
391 private Watchdog() {
392 super("watchdog");
393 mHandler = new HeartbeatHandler();
394 mGlobalPssCollected = new GlobalPssCollected();
395 }
396
397 public void init(Context context, BatteryService battery,
398 PowerManagerService power, AlarmManagerService alarm,
399 ActivityManagerService activity) {
400 mResolver = context.getContentResolver();
401 mBattery = battery;
402 mPower = power;
403 mAlarm = alarm;
404 mActivity = activity;
405
406 context.registerReceiver(new CheckupReceiver(),
407 new IntentFilter(CHECKUP_ACTION));
408 mCheckupIntent = PendingIntent.getBroadcast(context,
409 0, new Intent(CHECKUP_ACTION), 0);
410
411 context.registerReceiver(new RebootReceiver(),
412 new IntentFilter(REBOOT_ACTION));
413 mRebootIntent = PendingIntent.getBroadcast(context,
414 0, new Intent(REBOOT_ACTION), 0);
415
416 context.registerReceiver(new RebootRequestReceiver(),
417 new IntentFilter(Intent.ACTION_REBOOT),
418 android.Manifest.permission.REBOOT, null);
419
420 mBootTime = System.currentTimeMillis();
421 }
422
423 public void processStarted(PssRequestor req, String name, int pid) {
424 synchronized (this) {
425 if ("com.android.phone".equals(name)) {
426 mPhoneReq = req;
427 mPhonePid = pid;
428 mPhonePss = 0;
429 }
430 }
431 }
432
433 public void reportPss(PssRequestor req, String name, int pss) {
434 synchronized (this) {
435 if (mPhoneReq == req) {
436 mPhonePss = pss;
437 }
438 }
439 }
440
441 public void addMonitor(Monitor monitor) {
442 synchronized (this) {
443 if (isAlive()) {
444 throw new RuntimeException("Monitors can't be added while the Watchdog is running");
445 }
446 mMonitors.add(monitor);
447 }
448 }
449
450 /**
451 * Retrieve memory usage information from specific processes being
452 * monitored. This is an async operation, so must be done before doing
453 * memory checks.
454 */
455 void collectMemory() {
456 synchronized (this) {
457 if (mPhoneReq != null) {
458 mPhoneReq.requestPss();
459 }
460 }
461 }
462
463 /**
464 * Retrieve memory usage over all application processes. This is an
465 * async operation, so must be done before doing memory checks.
466 */
467 void collectGlobalMemory() {
468 mActivity.requestPss(mGlobalPssCollected);
469 }
470
471 /**
472 * Check memory usage in the system, scheduling kills/reboots as needed.
473 * This always runs on the mHandler thread.
474 */
475 void checkMemory() {
476 boolean needScheduledCheck;
477 long curTime;
478 long nextTime = 0;
479
480 long recheckInterval = Settings.Gservices.getLong(
481 mResolver, Settings.Gservices.MEMCHECK_RECHECK_INTERVAL,
482 MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000;
483
484 mSystemMemMonitor.retrieveSettings(mResolver);
485 mPhoneMemMonitor.retrieveSettings(mResolver);
486 retrieveBrutalityAmount();
487
488 synchronized (this) {
489 curTime = System.currentTimeMillis();
490 mNeedScheduledCheck = false;
491
492 // How is the system doing?
493 if (mSystemMemMonitor.checkLocked(curTime, Process.myPid(),
494 (int)Process.getPss(Process.myPid()))) {
495 // Not good! Time to suicide.
496 mForceKillSystem = true;
497 notifyAll();
498 return;
499 }
500
501 // How is the phone process doing?
502 if (mPhoneReq != null) {
503 if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid,
504 mPhonePss)) {
505 // Just kill the phone process and let it restart.
506 Process.killProcess(mPhonePid);
507 }
508 } else {
509 mPhoneMemMonitor.clear();
510 }
511
512 needScheduledCheck = mNeedScheduledCheck;
513 if (needScheduledCheck) {
514 // Something is going bad, but now is not a good time to
515 // tear things down... schedule an alarm to check again soon.
516 nextTime = curTime + recheckInterval;
517 if (nextTime < mMemcheckExecStartTime) {
518 nextTime = mMemcheckExecStartTime;
519 } else if (nextTime >= mMemcheckExecEndTime){
520 // Need to check during next exec time... so that needs
521 // to be computed.
522 if (localLOGV) Log.v(TAG, "Computing next time range");
523 computeMemcheckTimesLocked(nextTime);
524 nextTime = mMemcheckExecStartTime;
525 }
526
527 if (localLOGV) {
528 mCalendar.setTimeInMillis(nextTime);
529 Log.v(TAG, "Next Alarm Time: " + mCalendar);
530 }
531 }
532 }
533
534 if (needScheduledCheck) {
535 if (localLOGV) Log.v(TAG, "Scheduling next memcheck alarm for "
536 + ((nextTime-curTime)/1000/60) + "m from now");
537 mAlarm.remove(mCheckupIntent);
538 mAlarm.set(AlarmManager.RTC_WAKEUP, nextTime, mCheckupIntent);
539 } else {
540 if (localLOGV) Log.v(TAG, "No need to schedule a memcheck alarm!");
541 mAlarm.remove(mCheckupIntent);
542 }
543 }
544
545 final PssStats mPssStats = new PssStats();
546 final String[] mMemInfoFields = new String[] {
547 "MemFree:", "Buffers:", "Cached:",
548 "Active:", "Inactive:",
549 "AnonPages:", "Mapped:", "Slab:",
550 "SReclaimable:", "SUnreclaim:", "PageTables:" };
551 final long[] mMemInfoSizes = new long[mMemInfoFields.length];
552 final String[] mVMStatFields = new String[] {
553 "pgfree ", "pgactivate ", "pgdeactivate ",
554 "pgfault ", "pgmajfault " };
555 final long[] mVMStatSizes = new long[mVMStatFields.length];
556 final long[] mPrevVMStatSizes = new long[mVMStatFields.length];
557 long mLastLogGlobalMemoryTime;
558
559 void logGlobalMemory() {
560 PssStats stats = mPssStats;
561 mActivity.collectPss(stats);
562 EventLog.writeEvent(EVENT_LOG_PSS_STATS_TAG,
563 stats.mEmptyPss, stats.mEmptyCount,
564 stats.mBackgroundPss, stats.mBackgroundCount,
565 stats.mServicePss, stats.mServiceCount,
566 stats.mVisiblePss, stats.mVisibleCount,
567 stats.mForegroundPss, stats.mForegroundCount,
568 stats.mNoPssCount);
569 EventLog.writeEvent(EVENT_LOG_PROC_STATS_TAG,
570 stats.mProcDeaths[0], stats.mProcDeaths[1], stats.mProcDeaths[2],
571 stats.mProcDeaths[3], stats.mProcDeaths[4]);
572 Process.readProcLines("/proc/meminfo", mMemInfoFields, mMemInfoSizes);
573 for (int i=0; i<mMemInfoSizes.length; i++) {
574 mMemInfoSizes[i] *= 1024;
575 }
576 EventLog.writeEvent(EVENT_LOG_MEMINFO_TAG,
577 (int)mMemInfoSizes[0], (int)mMemInfoSizes[1], (int)mMemInfoSizes[2],
578 (int)mMemInfoSizes[3], (int)mMemInfoSizes[4],
579 (int)mMemInfoSizes[5], (int)mMemInfoSizes[6], (int)mMemInfoSizes[7],
580 (int)mMemInfoSizes[8], (int)mMemInfoSizes[9], (int)mMemInfoSizes[10]);
581 long now = SystemClock.uptimeMillis();
582 long dur = now - mLastLogGlobalMemoryTime;
583 mLastLogGlobalMemoryTime = now;
584 Process.readProcLines("/proc/vmstat", mVMStatFields, mVMStatSizes);
585 for (int i=0; i<mVMStatSizes.length; i++) {
586 long v = mVMStatSizes[i];
587 mVMStatSizes[i] -= mPrevVMStatSizes[i];
588 mPrevVMStatSizes[i] = v;
589 }
590 EventLog.writeEvent(EVENT_LOG_VMSTAT_TAG, dur,
591 (int)mVMStatSizes[0], (int)mVMStatSizes[1], (int)mVMStatSizes[2],
592 (int)mVMStatSizes[3], (int)mVMStatSizes[4]);
593 }
594
595 void checkReboot(boolean fromAlarm) {
596 int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval
597 : Settings.Gservices.getInt(
598 mResolver, Settings.Gservices.REBOOT_INTERVAL,
599 REBOOT_DEFAULT_INTERVAL);
600 mRebootInterval = rebootInterval;
601 if (rebootInterval <= 0) {
602 // No reboot interval requested.
603 if (localLOGV) Log.v(TAG, "No need to schedule a reboot alarm!");
604 mAlarm.remove(mRebootIntent);
605 return;
606 }
607
608 long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime
609 : Settings.Gservices.getLong(
610 mResolver, Settings.Gservices.REBOOT_START_TIME,
611 REBOOT_DEFAULT_START_TIME);
612 long rebootWindowMillis = (mReqRebootWindow >= 0 ? mReqRebootWindow
613 : Settings.Gservices.getLong(
614 mResolver, Settings.Gservices.REBOOT_WINDOW,
615 REBOOT_DEFAULT_WINDOW)) * 1000;
616 long recheckInterval = (mReqRecheckInterval >= 0 ? mReqRecheckInterval
617 : Settings.Gservices.getLong(
618 mResolver, Settings.Gservices.MEMCHECK_RECHECK_INTERVAL,
619 MEMCHECK_DEFAULT_RECHECK_INTERVAL)) * 1000;
620
621 retrieveBrutalityAmount();
622
623 long realStartTime;
624 long now;
625
626 synchronized (this) {
627 now = System.currentTimeMillis();
628 realStartTime = computeCalendarTime(mCalendar, now,
629 rebootStartTime);
630
631 long rebootIntervalMillis = rebootInterval*24*60*60*1000;
632 if (DB || mReqRebootNoWait ||
633 (now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) {
634 if (fromAlarm && rebootWindowMillis <= 0) {
635 // No reboot window -- just immediately reboot.
636 EventLog.writeEvent(EVENT_LOG_SCHEDULED_REBOOT_TAG, now,
637 (int)rebootIntervalMillis, (int)rebootStartTime*1000,
638 (int)rebootWindowMillis, "");
639 rebootSystem("Checkin scheduled forced");
640 return;
641 }
642
643 // Are we within the reboot window?
644 if (now < realStartTime) {
645 // Schedule alarm for next check interval.
646 realStartTime = computeCalendarTime(mCalendar,
647 now, rebootStartTime);
648 } else if (now < (realStartTime+rebootWindowMillis)) {
649 String doit = shouldWeBeBrutalLocked(now);
650 EventLog.writeEvent(EVENT_LOG_SCHEDULED_REBOOT_TAG, now,
651 (int)rebootInterval, (int)rebootStartTime*1000,
652 (int)rebootWindowMillis, doit != null ? doit : "");
653 if (doit == null) {
654 rebootSystem("Checked scheduled range");
655 return;
656 }
657
658 // Schedule next alarm either within the window or in the
659 // next interval.
660 if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) {
661 realStartTime = computeCalendarTime(mCalendar,
662 now + rebootIntervalMillis, rebootStartTime);
663 } else {
664 realStartTime = now + recheckInterval;
665 }
666 } else {
667 // Schedule alarm for next check interval.
668 realStartTime = computeCalendarTime(mCalendar,
669 now + rebootIntervalMillis, rebootStartTime);
670 }
671 }
672 }
673
674 if (localLOGV) Log.v(TAG, "Scheduling next reboot alarm for "
675 + ((realStartTime-now)/1000/60) + "m from now");
676 mAlarm.remove(mRebootIntent);
677 mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent);
678 }
679
680 /**
681 * Perform a full reboot of the system.
682 */
683 void rebootSystem(String reason) {
684 Log.i(TAG, "Rebooting system because: " + reason);
685 android.os.Power.reboot(reason);
686 }
687
688 /**
689 * Load the current Gservices settings for when
690 * {@link #shouldWeBeBrutalLocked} will allow the brutality to happen.
691 * Must not be called with the lock held.
692 */
693 void retrieveBrutalityAmount() {
694 mMinScreenOff = (mReqMinScreenOff >= 0 ? mReqMinScreenOff
695 : Settings.Gservices.getInt(
696 mResolver, Settings.Gservices.MEMCHECK_MIN_SCREEN_OFF,
697 MEMCHECK_DEFAULT_MIN_SCREEN_OFF)) * 1000;
698 mMinAlarm = (mReqMinNextAlarm >= 0 ? mReqMinNextAlarm
699 : Settings.Gservices.getInt(
700 mResolver, Settings.Gservices.MEMCHECK_MIN_ALARM,
701 MEMCHECK_DEFAULT_MIN_ALARM)) * 1000;
702 }
703
704 /**
705 * Determine whether it is a good time to kill, crash, or otherwise
706 * plunder the current situation for the overall long-term benefit of
707 * the world.
708 *
709 * @param curTime The current system time.
710 * @return Returns null if this is a good time, else a String with the
711 * text of why it is not a good time.
712 */
713 String shouldWeBeBrutalLocked(long curTime) {
714 if (mBattery == null || !mBattery.isPowered()) {
715 return "battery";
716 }
717
718 if (mMinScreenOff >= 0 && (mPower == null ||
719 mPower.timeSinceScreenOn() < mMinScreenOff)) {
720 return "screen";
721 }
722
723 if (mMinAlarm >= 0 && (mAlarm == null ||
724 mAlarm.timeToNextAlarm() < mMinAlarm)) {
725 return "alarm";
726 }
727
728 return null;
729 }
730
731 /**
732 * Compute the times during which we next would like to perform process
733 * restarts.
734 *
735 * @param curTime The current system time.
736 */
737 void computeMemcheckTimesLocked(long curTime) {
738 if (mMemcheckLastTime == curTime) {
739 return;
740 }
741
742 mMemcheckLastTime = curTime;
743
744 long memcheckExecStartTime = Settings.Gservices.getLong(
745 mResolver, Settings.Gservices.MEMCHECK_EXEC_START_TIME,
746 MEMCHECK_DEFAULT_EXEC_START_TIME);
747 long memcheckExecEndTime = Settings.Gservices.getLong(
748 mResolver, Settings.Gservices.MEMCHECK_EXEC_END_TIME,
749 MEMCHECK_DEFAULT_EXEC_END_TIME);
750
751 mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
752 memcheckExecEndTime);
753 if (mMemcheckExecEndTime < curTime) {
754 memcheckExecStartTime += 24*60*60;
755 memcheckExecEndTime += 24*60*60;
756 mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
757 memcheckExecEndTime);
758 }
759 mMemcheckExecStartTime = computeCalendarTime(mCalendar, curTime,
760 memcheckExecStartTime);
761
762 if (localLOGV) {
763 mCalendar.setTimeInMillis(curTime);
764 Log.v(TAG, "Current Time: " + mCalendar);
765 mCalendar.setTimeInMillis(mMemcheckExecStartTime);
766 Log.v(TAG, "Start Check Time: " + mCalendar);
767 mCalendar.setTimeInMillis(mMemcheckExecEndTime);
768 Log.v(TAG, "End Check Time: " + mCalendar);
769 }
770 }
771
772 static long computeCalendarTime(Calendar c, long curTime,
773 long secondsSinceMidnight) {
774
775 // start with now
776 c.setTimeInMillis(curTime);
777
778 int val = (int)secondsSinceMidnight / (60*60);
779 c.set(Calendar.HOUR_OF_DAY, val);
780 secondsSinceMidnight -= val * (60*60);
781 val = (int)secondsSinceMidnight / 60;
782 c.set(Calendar.MINUTE, val);
783 c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60));
784 c.set(Calendar.MILLISECOND, 0);
785
786 return c.getTimeInMillis();
787 }
788
789 @Override
790 public void run() {
791 while (true) {
792 mCompleted = false;
793 mHandler.sendEmptyMessage(MONITOR);
794
795 synchronized (this) {
796 long timeout = TIME_TO_WAIT;
797
798 // NOTE: We use uptimeMillis() here because we do not want to increment the time we
799 // wait while asleep. If the device is asleep then the thing that we are waiting
800 // to timeout on is asleep as well and won't have a chance to run. Causing a false
801 // positive on when to kill things.
802 long start = SystemClock.uptimeMillis();
803 do {
804 try {
805 wait(timeout);
806 } catch (InterruptedException e) {
807 if (SystemProperties.getBoolean("ro.secure", false)) {
808 // If this is a secure build, just log the error.
809 Log.e("WatchDog", "Woof! Woof! Interrupter!");
810 } else {
811 throw new AssertionError("Someone interrupted the watchdog");
812 }
813 }
814 timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
815 } while (timeout > 0 && !mForceKillSystem);
816
817 if (mCompleted && !mForceKillSystem) {
818 // The monitors have returned.
819 continue;
820 }
821 }
822
823 // If we got here, that means that the system is most likely hung.
824 // First send a SIGQUIT so that we can see where it was hung. Then
825 // kill this process so that the system will restart.
826 String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null";
827 EventLog.writeEvent(EVENT_LOG_TAG, name);
828 Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT);
829
830 // Wait a bit longer before killing so we can make sure that the stacks are captured.
831 try {
832 Thread.sleep(10*1000);
833 } catch (InterruptedException e) {
834 }
835
836 // Only kill the process if the debugger is not attached.
837 if (!Debug.isDebuggerConnected()) {
838 Process.killProcess(Process.myPid());
839 }
840 }
841 }
842}