blob: f97f50a45a12553e001c6a3f34df1a28f23a8be5 [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;
Dan Egnor9bdc94b2010-03-04 14:20:31 -080037import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080038import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
Dan Egnor9bdc94b2010-03-04 14:20:31 -080040import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import java.io.IOException;
42import java.util.ArrayList;
43import java.util.Calendar;
44
45/** This class calls its monitor every minute. Killing this process if they don't return **/
46public class Watchdog extends Thread {
47 static final String TAG = "Watchdog";
48 static final boolean localLOGV = false || Config.LOGV;
49
50 // Set this to true to use debug default values.
51 static final boolean DB = false;
52
53 static final int MONITOR = 2718;
54 static final int GLOBAL_PSS = 2719;
55
56 static final int TIME_TO_WAIT = DB ? 15*1000 : 60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057
58 static final int MEMCHECK_DEFAULT_INTERVAL = DB ? 30 : 30*60; // 30 minutes
59 static final int MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL = DB ? 60 : 2*60*60; // 2 hours
60 static final int MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD = (DB ? 10:16)*1024*1024; // 16MB
61 static final int MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD = (DB ? 14:20)*1024*1024; // 20MB
62 static final int MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD = (DB ? 4:8)*1024*1024; // 8MB
63 static final int MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD = (DB ? 8:12)*1024*1024; // 12MB
64
65 static final int MEMCHECK_DEFAULT_EXEC_START_TIME = 1*60*60; // 1:00am
66 static final int MEMCHECK_DEFAULT_EXEC_END_TIME = 5*60*60; // 5:00am
67 static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60; // 5 minutes
68 static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60; // 3 minutes
69 static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes
70
71 static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0; // never force reboot
72 static final int REBOOT_DEFAULT_START_TIME = 3*60*60; // 3:00am
73 static final int REBOOT_DEFAULT_WINDOW = 60*60; // within 1 hour
74
75 static final String CHECKUP_ACTION = "com.android.service.Watchdog.CHECKUP";
76 static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";
77
78 static Watchdog sWatchdog;
79
80 /* This handler will be used to post message back onto the main thread */
81 final Handler mHandler;
82 final Runnable mGlobalPssCollected;
83 final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
84 ContentResolver mResolver;
85 BatteryService mBattery;
86 PowerManagerService mPower;
87 AlarmManagerService mAlarm;
88 ActivityManagerService mActivity;
89 boolean mCompleted;
90 boolean mForceKillSystem;
91 Monitor mCurrentMonitor;
92
93 PssRequestor mPhoneReq;
94 int mPhonePid;
95 int mPhonePss;
96
97 long mLastMemCheckTime = -(MEMCHECK_DEFAULT_INTERVAL*1000);
98 boolean mHavePss;
99 long mLastMemCheckRealtime = -(MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL*1000);
100 boolean mHaveGlobalPss;
101 final MemMonitor mSystemMemMonitor = new MemMonitor("system",
Doug Zongkerf6888892010-01-06 16:38:14 -0800102 Settings.Secure.MEMCHECK_SYSTEM_ENABLED,
103 Settings.Secure.MEMCHECK_SYSTEM_SOFT_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD,
Doug Zongkerf6888892010-01-06 16:38:14 -0800105 Settings.Secure.MEMCHECK_SYSTEM_HARD_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD);
107 final MemMonitor mPhoneMemMonitor = new MemMonitor("com.android.phone",
Doug Zongkerf6888892010-01-06 16:38:14 -0800108 Settings.Secure.MEMCHECK_PHONE_ENABLED,
109 Settings.Secure.MEMCHECK_PHONE_SOFT_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD,
Doug Zongkerf6888892010-01-06 16:38:14 -0800111 Settings.Secure.MEMCHECK_PHONE_HARD_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD);
113
114 final Calendar mCalendar = Calendar.getInstance();
115 long mMemcheckLastTime;
116 long mMemcheckExecStartTime;
117 long mMemcheckExecEndTime;
118 int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF;
119 int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM;
120 boolean mNeedScheduledCheck;
121 PendingIntent mCheckupIntent;
122 PendingIntent mRebootIntent;
123
124 long mBootTime;
125 int mRebootInterval;
126
127 boolean mReqRebootNoWait; // should wait for one interval before reboot?
128 int mReqRebootInterval = -1; // >= 0 if a reboot has been requested
129 int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested
130 int mReqRebootWindow = -1; // >= 0 if a specific window has been requested
131 int mReqMinScreenOff = -1; // >= 0 if a specific screen off time has been requested
132 int mReqMinNextAlarm = -1; // >= 0 if specific time to next alarm has been requested
133 int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested
134
135 /**
136 * This class monitors the memory in a particular process.
137 */
138 final class MemMonitor {
139 final String mProcessName;
140 final String mEnabledSetting;
141 final String mSoftSetting;
142 final String mHardSetting;
143
144 int mSoftThreshold;
145 int mHardThreshold;
146 boolean mEnabled;
147 long mLastPss;
148
149 static final int STATE_OK = 0;
150 static final int STATE_SOFT = 1;
151 static final int STATE_HARD = 2;
152 int mState;
153
154 MemMonitor(String processName, String enabledSetting,
155 String softSetting, int defSoftThreshold,
156 String hardSetting, int defHardThreshold) {
157 mProcessName = processName;
158 mEnabledSetting = enabledSetting;
159 mSoftSetting = softSetting;
160 mHardSetting = hardSetting;
161 mSoftThreshold = defSoftThreshold;
162 mHardThreshold = defHardThreshold;
163 }
164
165 void retrieveSettings(ContentResolver resolver) {
Doug Zongkerf6888892010-01-06 16:38:14 -0800166 mSoftThreshold = Settings.Secure.getInt(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 resolver, mSoftSetting, mSoftThreshold);
Doug Zongkerf6888892010-01-06 16:38:14 -0800168 mHardThreshold = Settings.Secure.getInt(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 resolver, mHardSetting, mHardThreshold);
Doug Zongkerf6888892010-01-06 16:38:14 -0800170 mEnabled = Settings.Secure.getInt(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 resolver, mEnabledSetting, 0) != 0;
172 }
173
174 boolean checkLocked(long curTime, int pid, int pss) {
175 mLastPss = pss;
176 if (mLastPss < mSoftThreshold) {
177 mState = STATE_OK;
178 } else if (mLastPss < mHardThreshold) {
179 mState = STATE_SOFT;
180 } else {
181 mState = STATE_HARD;
182 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800183 EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_PSS, mProcessName, pid, mLastPss);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184
185 if (mState == STATE_OK) {
186 // Memory is good, don't recover.
187 return false;
188 }
189
190 if (mState == STATE_HARD) {
191 // Memory is really bad, kill right now.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800192 EventLog.writeEvent(EventLogTags.WATCHDOG_HARD_RESET, mProcessName, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 mHardThreshold, mLastPss);
194 return mEnabled;
195 }
196
197 // It is time to schedule a reset...
198 // Check if we are currently within the time to kill processes due
199 // to memory use.
200 computeMemcheckTimesLocked(curTime);
201 String skipReason = null;
202 if (curTime < mMemcheckExecStartTime || curTime > mMemcheckExecEndTime) {
203 skipReason = "time";
204 } else {
205 skipReason = shouldWeBeBrutalLocked(curTime);
206 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800207 EventLog.writeEvent(EventLogTags.WATCHDOG_SOFT_RESET, mProcessName, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 mSoftThreshold, mLastPss, skipReason != null ? skipReason : "");
209 if (skipReason != null) {
210 mNeedScheduledCheck = true;
211 return false;
212 }
213 return mEnabled;
214 }
215
216 void clear() {
217 mLastPss = 0;
218 mState = STATE_OK;
219 }
220 }
221
222 /**
223 * Used for scheduling monitor callbacks and checking memory usage.
224 */
225 final class HeartbeatHandler extends Handler {
226 @Override
227 public void handleMessage(Message msg) {
228 switch (msg.what) {
229 case GLOBAL_PSS: {
230 if (mHaveGlobalPss) {
231 // During the last pass we collected pss information, so
232 // now it is time to report it.
233 mHaveGlobalPss = false;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800234 if (localLOGV) Slog.v(TAG, "Received global pss, logging.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 logGlobalMemory();
236 }
237 } break;
238
239 case MONITOR: {
240 if (mHavePss) {
241 // During the last pass we collected pss information, so
242 // now it is time to report it.
243 mHavePss = false;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800244 if (localLOGV) Slog.v(TAG, "Have pss, checking memory.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 checkMemory();
246 }
247
248 if (mHaveGlobalPss) {
249 // During the last pass we collected pss information, so
250 // now it is time to report it.
251 mHaveGlobalPss = false;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800252 if (localLOGV) Slog.v(TAG, "Have global pss, logging.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 logGlobalMemory();
254 }
255
256 long now = SystemClock.uptimeMillis();
257
258 // See if we should force a reboot.
259 int rebootInterval = mReqRebootInterval >= 0
Doug Zongkerf6888892010-01-06 16:38:14 -0800260 ? mReqRebootInterval : Settings.Secure.getInt(
261 mResolver, Settings.Secure.REBOOT_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 REBOOT_DEFAULT_INTERVAL);
263 if (mRebootInterval != rebootInterval) {
264 mRebootInterval = rebootInterval;
265 // We have been running long enough that a reboot can
266 // be considered...
267 checkReboot(false);
268 }
269
270 // See if we should check memory conditions.
Doug Zongkerf6888892010-01-06 16:38:14 -0800271 long memCheckInterval = Settings.Secure.getLong(
272 mResolver, Settings.Secure.MEMCHECK_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 MEMCHECK_DEFAULT_INTERVAL) * 1000;
274 if ((mLastMemCheckTime+memCheckInterval) < now) {
275 // It is now time to collect pss information. This
276 // is async so we won't report it now. And to keep
277 // things simple, we will assume that everyone has
278 // reported back by the next MONITOR message.
279 mLastMemCheckTime = now;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800280 if (localLOGV) Slog.v(TAG, "Collecting memory usage.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 collectMemory();
282 mHavePss = true;
283
Doug Zongkerf6888892010-01-06 16:38:14 -0800284 long memCheckRealtimeInterval = Settings.Secure.getLong(
285 mResolver, Settings.Secure.MEMCHECK_LOG_REALTIME_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL) * 1000;
287 long realtimeNow = SystemClock.elapsedRealtime();
288 if ((mLastMemCheckRealtime+memCheckRealtimeInterval) < realtimeNow) {
289 mLastMemCheckRealtime = realtimeNow;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800290 if (localLOGV) Slog.v(TAG, "Collecting global memory usage.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 collectGlobalMemory();
292 mHaveGlobalPss = true;
293 }
294 }
295
296 final int size = mMonitors.size();
297 for (int i = 0 ; i < size ; i++) {
298 mCurrentMonitor = mMonitors.get(i);
299 mCurrentMonitor.monitor();
300 }
301
302 synchronized (Watchdog.this) {
303 mCompleted = true;
304 mCurrentMonitor = null;
305 }
306 } break;
307 }
308 }
309 }
310
311 final class GlobalPssCollected implements Runnable {
312 public void run() {
313 mHandler.sendEmptyMessage(GLOBAL_PSS);
314 }
315 }
316
317 final class CheckupReceiver extends BroadcastReceiver {
318 @Override
319 public void onReceive(Context c, Intent intent) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800320 if (localLOGV) Slog.v(TAG, "Alarm went off, checking memory.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 checkMemory();
322 }
323 }
324
325 final class RebootReceiver extends BroadcastReceiver {
326 @Override
327 public void onReceive(Context c, Intent intent) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800328 if (localLOGV) Slog.v(TAG, "Alarm went off, checking reboot.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 checkReboot(true);
330 }
331 }
332
333 final class RebootRequestReceiver extends BroadcastReceiver {
334 @Override
335 public void onReceive(Context c, Intent intent) {
336 mReqRebootNoWait = intent.getIntExtra("nowait", 0) != 0;
337 mReqRebootInterval = intent.getIntExtra("interval", -1);
338 mReqRebootStartTime = intent.getIntExtra("startTime", -1);
339 mReqRebootWindow = intent.getIntExtra("window", -1);
340 mReqMinScreenOff = intent.getIntExtra("minScreenOff", -1);
341 mReqMinNextAlarm = intent.getIntExtra("minNextAlarm", -1);
342 mReqRecheckInterval = intent.getIntExtra("recheckInterval", -1);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800343 EventLog.writeEvent(EventLogTags.WATCHDOG_REQUESTED_REBOOT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 mReqRebootNoWait ? 1 : 0, mReqRebootInterval,
345 mReqRecheckInterval, mReqRebootStartTime,
346 mReqRebootWindow, mReqMinScreenOff, mReqMinNextAlarm);
347 checkReboot(true);
348 }
349 }
350
351 public interface Monitor {
352 void monitor();
353 }
354
355 public interface PssRequestor {
356 void requestPss();
357 }
358
359 public class PssStats {
360 public int mEmptyPss;
361 public int mEmptyCount;
362 public int mBackgroundPss;
363 public int mBackgroundCount;
364 public int mServicePss;
365 public int mServiceCount;
366 public int mVisiblePss;
367 public int mVisibleCount;
368 public int mForegroundPss;
369 public int mForegroundCount;
370
371 public int mNoPssCount;
372
373 public int mProcDeaths[] = new int[10];
374 }
375
376 public static Watchdog getInstance() {
377 if (sWatchdog == null) {
378 sWatchdog = new Watchdog();
379 }
380
381 return sWatchdog;
382 }
383
384 private Watchdog() {
385 super("watchdog");
386 mHandler = new HeartbeatHandler();
387 mGlobalPssCollected = new GlobalPssCollected();
388 }
389
390 public void init(Context context, BatteryService battery,
391 PowerManagerService power, AlarmManagerService alarm,
392 ActivityManagerService activity) {
393 mResolver = context.getContentResolver();
394 mBattery = battery;
395 mPower = power;
396 mAlarm = alarm;
397 mActivity = activity;
398
399 context.registerReceiver(new CheckupReceiver(),
400 new IntentFilter(CHECKUP_ACTION));
401 mCheckupIntent = PendingIntent.getBroadcast(context,
402 0, new Intent(CHECKUP_ACTION), 0);
403
404 context.registerReceiver(new RebootReceiver(),
405 new IntentFilter(REBOOT_ACTION));
406 mRebootIntent = PendingIntent.getBroadcast(context,
407 0, new Intent(REBOOT_ACTION), 0);
408
409 context.registerReceiver(new RebootRequestReceiver(),
410 new IntentFilter(Intent.ACTION_REBOOT),
411 android.Manifest.permission.REBOOT, null);
412
413 mBootTime = System.currentTimeMillis();
414 }
415
416 public void processStarted(PssRequestor req, String name, int pid) {
417 synchronized (this) {
418 if ("com.android.phone".equals(name)) {
419 mPhoneReq = req;
420 mPhonePid = pid;
421 mPhonePss = 0;
422 }
423 }
424 }
425
426 public void reportPss(PssRequestor req, String name, int pss) {
427 synchronized (this) {
428 if (mPhoneReq == req) {
429 mPhonePss = pss;
430 }
431 }
432 }
433
434 public void addMonitor(Monitor monitor) {
435 synchronized (this) {
436 if (isAlive()) {
437 throw new RuntimeException("Monitors can't be added while the Watchdog is running");
438 }
439 mMonitors.add(monitor);
440 }
441 }
442
443 /**
444 * Retrieve memory usage information from specific processes being
445 * monitored. This is an async operation, so must be done before doing
446 * memory checks.
447 */
448 void collectMemory() {
449 synchronized (this) {
450 if (mPhoneReq != null) {
451 mPhoneReq.requestPss();
452 }
453 }
454 }
455
456 /**
457 * Retrieve memory usage over all application processes. This is an
458 * async operation, so must be done before doing memory checks.
459 */
460 void collectGlobalMemory() {
461 mActivity.requestPss(mGlobalPssCollected);
462 }
463
464 /**
465 * Check memory usage in the system, scheduling kills/reboots as needed.
466 * This always runs on the mHandler thread.
467 */
468 void checkMemory() {
469 boolean needScheduledCheck;
470 long curTime;
471 long nextTime = 0;
472
Doug Zongkerf6888892010-01-06 16:38:14 -0800473 long recheckInterval = Settings.Secure.getLong(
474 mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000;
476
477 mSystemMemMonitor.retrieveSettings(mResolver);
478 mPhoneMemMonitor.retrieveSettings(mResolver);
479 retrieveBrutalityAmount();
480
481 synchronized (this) {
482 curTime = System.currentTimeMillis();
483 mNeedScheduledCheck = false;
484
485 // How is the system doing?
486 if (mSystemMemMonitor.checkLocked(curTime, Process.myPid(),
487 (int)Process.getPss(Process.myPid()))) {
488 // Not good! Time to suicide.
489 mForceKillSystem = true;
490 notifyAll();
491 return;
492 }
493
494 // How is the phone process doing?
495 if (mPhoneReq != null) {
496 if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid,
497 mPhonePss)) {
498 // Just kill the phone process and let it restart.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800499 Slog.i(TAG, "Watchdog is killing the phone process");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 Process.killProcess(mPhonePid);
501 }
502 } else {
503 mPhoneMemMonitor.clear();
504 }
505
506 needScheduledCheck = mNeedScheduledCheck;
507 if (needScheduledCheck) {
508 // Something is going bad, but now is not a good time to
509 // tear things down... schedule an alarm to check again soon.
510 nextTime = curTime + recheckInterval;
511 if (nextTime < mMemcheckExecStartTime) {
512 nextTime = mMemcheckExecStartTime;
513 } else if (nextTime >= mMemcheckExecEndTime){
514 // Need to check during next exec time... so that needs
515 // to be computed.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800516 if (localLOGV) Slog.v(TAG, "Computing next time range");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 computeMemcheckTimesLocked(nextTime);
518 nextTime = mMemcheckExecStartTime;
519 }
520
521 if (localLOGV) {
522 mCalendar.setTimeInMillis(nextTime);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800523 Slog.v(TAG, "Next Alarm Time: " + mCalendar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 }
525 }
526 }
527
528 if (needScheduledCheck) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800529 if (localLOGV) Slog.v(TAG, "Scheduling next memcheck alarm for "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 + ((nextTime-curTime)/1000/60) + "m from now");
531 mAlarm.remove(mCheckupIntent);
532 mAlarm.set(AlarmManager.RTC_WAKEUP, nextTime, mCheckupIntent);
533 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800534 if (localLOGV) Slog.v(TAG, "No need to schedule a memcheck alarm!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 mAlarm.remove(mCheckupIntent);
536 }
537 }
538
539 final PssStats mPssStats = new PssStats();
540 final String[] mMemInfoFields = new String[] {
541 "MemFree:", "Buffers:", "Cached:",
542 "Active:", "Inactive:",
543 "AnonPages:", "Mapped:", "Slab:",
544 "SReclaimable:", "SUnreclaim:", "PageTables:" };
545 final long[] mMemInfoSizes = new long[mMemInfoFields.length];
546 final String[] mVMStatFields = new String[] {
547 "pgfree ", "pgactivate ", "pgdeactivate ",
548 "pgfault ", "pgmajfault " };
549 final long[] mVMStatSizes = new long[mVMStatFields.length];
550 final long[] mPrevVMStatSizes = new long[mVMStatFields.length];
551 long mLastLogGlobalMemoryTime;
552
553 void logGlobalMemory() {
554 PssStats stats = mPssStats;
555 mActivity.collectPss(stats);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800556 EventLog.writeEvent(EventLogTags.WATCHDOG_PSS_STATS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 stats.mEmptyPss, stats.mEmptyCount,
558 stats.mBackgroundPss, stats.mBackgroundCount,
559 stats.mServicePss, stats.mServiceCount,
560 stats.mVisiblePss, stats.mVisibleCount,
561 stats.mForegroundPss, stats.mForegroundCount,
562 stats.mNoPssCount);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800563 EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_STATS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 stats.mProcDeaths[0], stats.mProcDeaths[1], stats.mProcDeaths[2],
565 stats.mProcDeaths[3], stats.mProcDeaths[4]);
566 Process.readProcLines("/proc/meminfo", mMemInfoFields, mMemInfoSizes);
567 for (int i=0; i<mMemInfoSizes.length; i++) {
568 mMemInfoSizes[i] *= 1024;
569 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800570 EventLog.writeEvent(EventLogTags.WATCHDOG_MEMINFO,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 (int)mMemInfoSizes[0], (int)mMemInfoSizes[1], (int)mMemInfoSizes[2],
572 (int)mMemInfoSizes[3], (int)mMemInfoSizes[4],
573 (int)mMemInfoSizes[5], (int)mMemInfoSizes[6], (int)mMemInfoSizes[7],
574 (int)mMemInfoSizes[8], (int)mMemInfoSizes[9], (int)mMemInfoSizes[10]);
575 long now = SystemClock.uptimeMillis();
576 long dur = now - mLastLogGlobalMemoryTime;
577 mLastLogGlobalMemoryTime = now;
578 Process.readProcLines("/proc/vmstat", mVMStatFields, mVMStatSizes);
579 for (int i=0; i<mVMStatSizes.length; i++) {
580 long v = mVMStatSizes[i];
581 mVMStatSizes[i] -= mPrevVMStatSizes[i];
582 mPrevVMStatSizes[i] = v;
583 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800584 EventLog.writeEvent(EventLogTags.WATCHDOG_VMSTAT, dur,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 (int)mVMStatSizes[0], (int)mVMStatSizes[1], (int)mVMStatSizes[2],
586 (int)mVMStatSizes[3], (int)mVMStatSizes[4]);
587 }
588
589 void checkReboot(boolean fromAlarm) {
590 int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval
Doug Zongkerf6888892010-01-06 16:38:14 -0800591 : Settings.Secure.getInt(
592 mResolver, Settings.Secure.REBOOT_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 REBOOT_DEFAULT_INTERVAL);
594 mRebootInterval = rebootInterval;
595 if (rebootInterval <= 0) {
596 // No reboot interval requested.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800597 if (localLOGV) Slog.v(TAG, "No need to schedule a reboot alarm!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 mAlarm.remove(mRebootIntent);
599 return;
600 }
601
602 long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime
Doug Zongkerf6888892010-01-06 16:38:14 -0800603 : Settings.Secure.getLong(
604 mResolver, Settings.Secure.REBOOT_START_TIME,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 REBOOT_DEFAULT_START_TIME);
606 long rebootWindowMillis = (mReqRebootWindow >= 0 ? mReqRebootWindow
Doug Zongkerf6888892010-01-06 16:38:14 -0800607 : Settings.Secure.getLong(
608 mResolver, Settings.Secure.REBOOT_WINDOW,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 REBOOT_DEFAULT_WINDOW)) * 1000;
610 long recheckInterval = (mReqRecheckInterval >= 0 ? mReqRecheckInterval
Doug Zongkerf6888892010-01-06 16:38:14 -0800611 : Settings.Secure.getLong(
612 mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 MEMCHECK_DEFAULT_RECHECK_INTERVAL)) * 1000;
614
615 retrieveBrutalityAmount();
616
617 long realStartTime;
618 long now;
619
620 synchronized (this) {
621 now = System.currentTimeMillis();
622 realStartTime = computeCalendarTime(mCalendar, now,
623 rebootStartTime);
624
625 long rebootIntervalMillis = rebootInterval*24*60*60*1000;
626 if (DB || mReqRebootNoWait ||
627 (now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) {
628 if (fromAlarm && rebootWindowMillis <= 0) {
629 // No reboot window -- just immediately reboot.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800630 EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 (int)rebootIntervalMillis, (int)rebootStartTime*1000,
632 (int)rebootWindowMillis, "");
633 rebootSystem("Checkin scheduled forced");
634 return;
635 }
636
637 // Are we within the reboot window?
638 if (now < realStartTime) {
639 // Schedule alarm for next check interval.
640 realStartTime = computeCalendarTime(mCalendar,
641 now, rebootStartTime);
642 } else if (now < (realStartTime+rebootWindowMillis)) {
643 String doit = shouldWeBeBrutalLocked(now);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800644 EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 (int)rebootInterval, (int)rebootStartTime*1000,
646 (int)rebootWindowMillis, doit != null ? doit : "");
647 if (doit == null) {
648 rebootSystem("Checked scheduled range");
649 return;
650 }
651
652 // Schedule next alarm either within the window or in the
653 // next interval.
654 if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) {
655 realStartTime = computeCalendarTime(mCalendar,
656 now + rebootIntervalMillis, rebootStartTime);
657 } else {
658 realStartTime = now + recheckInterval;
659 }
660 } else {
661 // Schedule alarm for next check interval.
662 realStartTime = computeCalendarTime(mCalendar,
663 now + rebootIntervalMillis, rebootStartTime);
664 }
665 }
666 }
667
Joe Onorato8a9b2202010-02-26 18:56:32 -0800668 if (localLOGV) Slog.v(TAG, "Scheduling next reboot alarm for "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 + ((realStartTime-now)/1000/60) + "m from now");
670 mAlarm.remove(mRebootIntent);
671 mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent);
672 }
673
674 /**
675 * Perform a full reboot of the system.
676 */
677 void rebootSystem(String reason) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800678 Slog.i(TAG, "Rebooting system because: " + reason);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 try {
680 android.os.Power.reboot(reason);
681 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800682 Slog.e(TAG, "Reboot failed!", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 }
684 }
685
686 /**
687 * Load the current Gservices settings for when
688 * {@link #shouldWeBeBrutalLocked} will allow the brutality to happen.
689 * Must not be called with the lock held.
690 */
691 void retrieveBrutalityAmount() {
692 mMinScreenOff = (mReqMinScreenOff >= 0 ? mReqMinScreenOff
Doug Zongkerf6888892010-01-06 16:38:14 -0800693 : Settings.Secure.getInt(
694 mResolver, Settings.Secure.MEMCHECK_MIN_SCREEN_OFF,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 MEMCHECK_DEFAULT_MIN_SCREEN_OFF)) * 1000;
696 mMinAlarm = (mReqMinNextAlarm >= 0 ? mReqMinNextAlarm
Doug Zongkerf6888892010-01-06 16:38:14 -0800697 : Settings.Secure.getInt(
698 mResolver, Settings.Secure.MEMCHECK_MIN_ALARM,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 MEMCHECK_DEFAULT_MIN_ALARM)) * 1000;
700 }
701
702 /**
703 * Determine whether it is a good time to kill, crash, or otherwise
704 * plunder the current situation for the overall long-term benefit of
705 * the world.
706 *
707 * @param curTime The current system time.
708 * @return Returns null if this is a good time, else a String with the
709 * text of why it is not a good time.
710 */
711 String shouldWeBeBrutalLocked(long curTime) {
712 if (mBattery == null || !mBattery.isPowered()) {
713 return "battery";
714 }
715
716 if (mMinScreenOff >= 0 && (mPower == null ||
717 mPower.timeSinceScreenOn() < mMinScreenOff)) {
718 return "screen";
719 }
720
721 if (mMinAlarm >= 0 && (mAlarm == null ||
722 mAlarm.timeToNextAlarm() < mMinAlarm)) {
723 return "alarm";
724 }
725
726 return null;
727 }
728
729 /**
730 * Compute the times during which we next would like to perform process
731 * restarts.
732 *
733 * @param curTime The current system time.
734 */
735 void computeMemcheckTimesLocked(long curTime) {
736 if (mMemcheckLastTime == curTime) {
737 return;
738 }
739
740 mMemcheckLastTime = curTime;
741
Doug Zongkerf6888892010-01-06 16:38:14 -0800742 long memcheckExecStartTime = Settings.Secure.getLong(
743 mResolver, Settings.Secure.MEMCHECK_EXEC_START_TIME,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 MEMCHECK_DEFAULT_EXEC_START_TIME);
Doug Zongkerf6888892010-01-06 16:38:14 -0800745 long memcheckExecEndTime = Settings.Secure.getLong(
746 mResolver, Settings.Secure.MEMCHECK_EXEC_END_TIME,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 MEMCHECK_DEFAULT_EXEC_END_TIME);
748
749 mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
750 memcheckExecEndTime);
751 if (mMemcheckExecEndTime < curTime) {
752 memcheckExecStartTime += 24*60*60;
753 memcheckExecEndTime += 24*60*60;
754 mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
755 memcheckExecEndTime);
756 }
757 mMemcheckExecStartTime = computeCalendarTime(mCalendar, curTime,
758 memcheckExecStartTime);
759
760 if (localLOGV) {
761 mCalendar.setTimeInMillis(curTime);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800762 Slog.v(TAG, "Current Time: " + mCalendar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 mCalendar.setTimeInMillis(mMemcheckExecStartTime);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800764 Slog.v(TAG, "Start Check Time: " + mCalendar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 mCalendar.setTimeInMillis(mMemcheckExecEndTime);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800766 Slog.v(TAG, "End Check Time: " + mCalendar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 }
768 }
769
770 static long computeCalendarTime(Calendar c, long curTime,
771 long secondsSinceMidnight) {
772
773 // start with now
774 c.setTimeInMillis(curTime);
775
776 int val = (int)secondsSinceMidnight / (60*60);
777 c.set(Calendar.HOUR_OF_DAY, val);
778 secondsSinceMidnight -= val * (60*60);
779 val = (int)secondsSinceMidnight / 60;
780 c.set(Calendar.MINUTE, val);
781 c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60));
782 c.set(Calendar.MILLISECOND, 0);
783
784 long newTime = c.getTimeInMillis();
785 if (newTime < curTime) {
786 // The given time (in seconds since midnight) has already passed for today, so advance
787 // by one day (due to daylight savings, etc., the delta may differ from 24 hours).
788 c.add(Calendar.DAY_OF_MONTH, 1);
789 newTime = c.getTimeInMillis();
790 }
791
792 return newTime;
793 }
794
795 @Override
796 public void run() {
797 while (true) {
798 mCompleted = false;
799 mHandler.sendEmptyMessage(MONITOR);
800
801 synchronized (this) {
802 long timeout = TIME_TO_WAIT;
803
804 // NOTE: We use uptimeMillis() here because we do not want to increment the time we
805 // wait while asleep. If the device is asleep then the thing that we are waiting
806 // to timeout on is asleep as well and won't have a chance to run. Causing a false
807 // positive on when to kill things.
808 long start = SystemClock.uptimeMillis();
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800809 while (timeout > 0 && !mForceKillSystem) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 try {
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800811 wait(timeout); // notifyAll() is called when mForceKillSystem is set
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 } catch (InterruptedException e) {
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800813 Log.wtf(TAG, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 }
815 timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800816 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817
818 if (mCompleted && !mForceKillSystem) {
819 // The monitors have returned.
820 continue;
821 }
822 }
823
824 // If we got here, that means that the system is most likely hung.
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800825 // First collect stack traces from all threads of the system process.
826 // Then kill this process so that the system will restart.
827
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null";
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800829 EventLog.writeEvent(EventLogTags.WATCHDOG, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800831 ArrayList pids = new ArrayList();
832 pids.add(Process.myPid());
833 File stack = ActivityManagerService.dumpStackTraces(pids);
834 mActivity.addErrorToDropBox("watchdog", null, null, null, name, null, stack, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835
836 // Only kill the process if the debugger is not attached.
837 if (!Debug.isDebuggerConnected()) {
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800838 Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 Process.killProcess(Process.myPid());
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800840 System.exit(10);
841 } else {
842 Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 }
844 }
845 }
846}