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