blob: 5eaadbc3934309b060703fd0d344b6ea4ea113e6 [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;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080032import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.os.SystemClock;
34import android.os.SystemProperties;
35import android.provider.Settings;
36import android.util.Config;
37import android.util.EventLog;
Dan Egnor9bdc94b2010-03-04 14:20:31 -080038import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080039import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
Dan Egnor9bdc94b2010-03-04 14:20:31 -080041import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import java.io.IOException;
43import java.util.ArrayList;
44import java.util.Calendar;
45
46/** This class calls its monitor every minute. Killing this process if they don't return **/
47public class Watchdog extends Thread {
48 static final String TAG = "Watchdog";
49 static final boolean localLOGV = false || Config.LOGV;
50
51 // Set this to true to use debug default values.
52 static final boolean DB = false;
53
54 static final int MONITOR = 2718;
55 static final int GLOBAL_PSS = 2719;
56
Christopher Tate6ee412d2010-05-28 12:01:56 -070057 static final int TIME_TO_RESTART = DB ? 15*1000 : 60*1000;
58 static final int TIME_TO_WAIT = TIME_TO_RESTART / 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059
60 static final int MEMCHECK_DEFAULT_INTERVAL = DB ? 30 : 30*60; // 30 minutes
61 static final int MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL = DB ? 60 : 2*60*60; // 2 hours
62 static final int MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD = (DB ? 10:16)*1024*1024; // 16MB
63 static final int MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD = (DB ? 14:20)*1024*1024; // 20MB
64 static final int MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD = (DB ? 4:8)*1024*1024; // 8MB
65 static final int MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD = (DB ? 8:12)*1024*1024; // 12MB
66
67 static final int MEMCHECK_DEFAULT_EXEC_START_TIME = 1*60*60; // 1:00am
68 static final int MEMCHECK_DEFAULT_EXEC_END_TIME = 5*60*60; // 5:00am
69 static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60; // 5 minutes
70 static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60; // 3 minutes
71 static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes
72
73 static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0; // never force reboot
74 static final int REBOOT_DEFAULT_START_TIME = 3*60*60; // 3:00am
75 static final int REBOOT_DEFAULT_WINDOW = 60*60; // within 1 hour
76
77 static final String CHECKUP_ACTION = "com.android.service.Watchdog.CHECKUP";
78 static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";
79
80 static Watchdog sWatchdog;
81
82 /* This handler will be used to post message back onto the main thread */
83 final Handler mHandler;
84 final Runnable mGlobalPssCollected;
85 final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
86 ContentResolver mResolver;
87 BatteryService mBattery;
88 PowerManagerService mPower;
89 AlarmManagerService mAlarm;
90 ActivityManagerService mActivity;
91 boolean mCompleted;
92 boolean mForceKillSystem;
93 Monitor mCurrentMonitor;
94
95 PssRequestor mPhoneReq;
96 int mPhonePid;
97 int mPhonePss;
98
99 long mLastMemCheckTime = -(MEMCHECK_DEFAULT_INTERVAL*1000);
100 boolean mHavePss;
101 long mLastMemCheckRealtime = -(MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL*1000);
102 boolean mHaveGlobalPss;
103 final MemMonitor mSystemMemMonitor = new MemMonitor("system",
Doug Zongkerf6888892010-01-06 16:38:14 -0800104 Settings.Secure.MEMCHECK_SYSTEM_ENABLED,
105 Settings.Secure.MEMCHECK_SYSTEM_SOFT_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD,
Doug Zongkerf6888892010-01-06 16:38:14 -0800107 Settings.Secure.MEMCHECK_SYSTEM_HARD_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD);
109 final MemMonitor mPhoneMemMonitor = new MemMonitor("com.android.phone",
Doug Zongkerf6888892010-01-06 16:38:14 -0800110 Settings.Secure.MEMCHECK_PHONE_ENABLED,
111 Settings.Secure.MEMCHECK_PHONE_SOFT_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD,
Doug Zongkerf6888892010-01-06 16:38:14 -0800113 Settings.Secure.MEMCHECK_PHONE_HARD_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD);
115
116 final Calendar mCalendar = Calendar.getInstance();
117 long mMemcheckLastTime;
118 long mMemcheckExecStartTime;
119 long mMemcheckExecEndTime;
120 int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF;
121 int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM;
122 boolean mNeedScheduledCheck;
123 PendingIntent mCheckupIntent;
124 PendingIntent mRebootIntent;
125
126 long mBootTime;
127 int mRebootInterval;
128
129 boolean mReqRebootNoWait; // should wait for one interval before reboot?
130 int mReqRebootInterval = -1; // >= 0 if a reboot has been requested
131 int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested
132 int mReqRebootWindow = -1; // >= 0 if a specific window has been requested
133 int mReqMinScreenOff = -1; // >= 0 if a specific screen off time has been requested
134 int mReqMinNextAlarm = -1; // >= 0 if specific time to next alarm has been requested
135 int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested
136
137 /**
138 * This class monitors the memory in a particular process.
139 */
140 final class MemMonitor {
141 final String mProcessName;
142 final String mEnabledSetting;
143 final String mSoftSetting;
144 final String mHardSetting;
145
146 int mSoftThreshold;
147 int mHardThreshold;
148 boolean mEnabled;
149 long mLastPss;
150
151 static final int STATE_OK = 0;
152 static final int STATE_SOFT = 1;
153 static final int STATE_HARD = 2;
154 int mState;
155
156 MemMonitor(String processName, String enabledSetting,
157 String softSetting, int defSoftThreshold,
158 String hardSetting, int defHardThreshold) {
159 mProcessName = processName;
160 mEnabledSetting = enabledSetting;
161 mSoftSetting = softSetting;
162 mHardSetting = hardSetting;
163 mSoftThreshold = defSoftThreshold;
164 mHardThreshold = defHardThreshold;
165 }
166
167 void retrieveSettings(ContentResolver resolver) {
Doug Zongkerf6888892010-01-06 16:38:14 -0800168 mSoftThreshold = Settings.Secure.getInt(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 resolver, mSoftSetting, mSoftThreshold);
Doug Zongkerf6888892010-01-06 16:38:14 -0800170 mHardThreshold = Settings.Secure.getInt(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 resolver, mHardSetting, mHardThreshold);
Doug Zongkerf6888892010-01-06 16:38:14 -0800172 mEnabled = Settings.Secure.getInt(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 resolver, mEnabledSetting, 0) != 0;
174 }
175
176 boolean checkLocked(long curTime, int pid, int pss) {
177 mLastPss = pss;
178 if (mLastPss < mSoftThreshold) {
179 mState = STATE_OK;
180 } else if (mLastPss < mHardThreshold) {
181 mState = STATE_SOFT;
182 } else {
183 mState = STATE_HARD;
184 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800185 EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_PSS, mProcessName, pid, mLastPss);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186
187 if (mState == STATE_OK) {
188 // Memory is good, don't recover.
189 return false;
190 }
191
192 if (mState == STATE_HARD) {
193 // Memory is really bad, kill right now.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800194 EventLog.writeEvent(EventLogTags.WATCHDOG_HARD_RESET, mProcessName, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 mHardThreshold, mLastPss);
196 return mEnabled;
197 }
198
199 // It is time to schedule a reset...
200 // Check if we are currently within the time to kill processes due
201 // to memory use.
202 computeMemcheckTimesLocked(curTime);
203 String skipReason = null;
204 if (curTime < mMemcheckExecStartTime || curTime > mMemcheckExecEndTime) {
205 skipReason = "time";
206 } else {
207 skipReason = shouldWeBeBrutalLocked(curTime);
208 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800209 EventLog.writeEvent(EventLogTags.WATCHDOG_SOFT_RESET, mProcessName, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 mSoftThreshold, mLastPss, skipReason != null ? skipReason : "");
211 if (skipReason != null) {
212 mNeedScheduledCheck = true;
213 return false;
214 }
215 return mEnabled;
216 }
217
218 void clear() {
219 mLastPss = 0;
220 mState = STATE_OK;
221 }
222 }
223
224 /**
225 * Used for scheduling monitor callbacks and checking memory usage.
226 */
227 final class HeartbeatHandler extends Handler {
228 @Override
229 public void handleMessage(Message msg) {
230 switch (msg.what) {
231 case GLOBAL_PSS: {
232 if (mHaveGlobalPss) {
233 // During the last pass we collected pss information, so
234 // now it is time to report it.
235 mHaveGlobalPss = false;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800236 if (localLOGV) Slog.v(TAG, "Received global pss, logging.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 logGlobalMemory();
238 }
239 } break;
240
241 case MONITOR: {
242 if (mHavePss) {
243 // During the last pass we collected pss information, so
244 // now it is time to report it.
245 mHavePss = false;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800246 if (localLOGV) Slog.v(TAG, "Have pss, checking memory.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 checkMemory();
248 }
249
250 if (mHaveGlobalPss) {
251 // During the last pass we collected pss information, so
252 // now it is time to report it.
253 mHaveGlobalPss = false;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800254 if (localLOGV) Slog.v(TAG, "Have global pss, logging.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 logGlobalMemory();
256 }
257
258 long now = SystemClock.uptimeMillis();
259
260 // See if we should force a reboot.
261 int rebootInterval = mReqRebootInterval >= 0
Doug Zongkerf6888892010-01-06 16:38:14 -0800262 ? mReqRebootInterval : Settings.Secure.getInt(
263 mResolver, Settings.Secure.REBOOT_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 REBOOT_DEFAULT_INTERVAL);
265 if (mRebootInterval != rebootInterval) {
266 mRebootInterval = rebootInterval;
267 // We have been running long enough that a reboot can
268 // be considered...
269 checkReboot(false);
270 }
271
272 // See if we should check memory conditions.
Doug Zongkerf6888892010-01-06 16:38:14 -0800273 long memCheckInterval = Settings.Secure.getLong(
274 mResolver, Settings.Secure.MEMCHECK_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 MEMCHECK_DEFAULT_INTERVAL) * 1000;
276 if ((mLastMemCheckTime+memCheckInterval) < now) {
277 // It is now time to collect pss information. This
278 // is async so we won't report it now. And to keep
279 // things simple, we will assume that everyone has
280 // reported back by the next MONITOR message.
281 mLastMemCheckTime = now;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800282 if (localLOGV) Slog.v(TAG, "Collecting memory usage.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 collectMemory();
284 mHavePss = true;
285
Doug Zongkerf6888892010-01-06 16:38:14 -0800286 long memCheckRealtimeInterval = Settings.Secure.getLong(
287 mResolver, Settings.Secure.MEMCHECK_LOG_REALTIME_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL) * 1000;
289 long realtimeNow = SystemClock.elapsedRealtime();
290 if ((mLastMemCheckRealtime+memCheckRealtimeInterval) < realtimeNow) {
291 mLastMemCheckRealtime = realtimeNow;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800292 if (localLOGV) Slog.v(TAG, "Collecting global memory usage.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 collectGlobalMemory();
294 mHaveGlobalPss = true;
295 }
296 }
297
298 final int size = mMonitors.size();
299 for (int i = 0 ; i < size ; i++) {
300 mCurrentMonitor = mMonitors.get(i);
301 mCurrentMonitor.monitor();
302 }
303
304 synchronized (Watchdog.this) {
305 mCompleted = true;
306 mCurrentMonitor = null;
307 }
308 } break;
309 }
310 }
311 }
312
313 final class GlobalPssCollected implements Runnable {
314 public void run() {
315 mHandler.sendEmptyMessage(GLOBAL_PSS);
316 }
317 }
318
319 final class CheckupReceiver extends BroadcastReceiver {
320 @Override
321 public void onReceive(Context c, Intent intent) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800322 if (localLOGV) Slog.v(TAG, "Alarm went off, checking memory.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 checkMemory();
324 }
325 }
326
327 final class RebootReceiver extends BroadcastReceiver {
328 @Override
329 public void onReceive(Context c, Intent intent) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800330 if (localLOGV) Slog.v(TAG, "Alarm went off, checking reboot.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 checkReboot(true);
332 }
333 }
334
335 final class RebootRequestReceiver extends BroadcastReceiver {
336 @Override
337 public void onReceive(Context c, Intent intent) {
338 mReqRebootNoWait = intent.getIntExtra("nowait", 0) != 0;
339 mReqRebootInterval = intent.getIntExtra("interval", -1);
340 mReqRebootStartTime = intent.getIntExtra("startTime", -1);
341 mReqRebootWindow = intent.getIntExtra("window", -1);
342 mReqMinScreenOff = intent.getIntExtra("minScreenOff", -1);
343 mReqMinNextAlarm = intent.getIntExtra("minNextAlarm", -1);
344 mReqRecheckInterval = intent.getIntExtra("recheckInterval", -1);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800345 EventLog.writeEvent(EventLogTags.WATCHDOG_REQUESTED_REBOOT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 mReqRebootNoWait ? 1 : 0, mReqRebootInterval,
347 mReqRecheckInterval, mReqRebootStartTime,
348 mReqRebootWindow, mReqMinScreenOff, mReqMinNextAlarm);
349 checkReboot(true);
350 }
351 }
352
353 public interface Monitor {
354 void monitor();
355 }
356
357 public interface PssRequestor {
358 void requestPss();
359 }
360
361 public class PssStats {
362 public int mEmptyPss;
363 public int mEmptyCount;
364 public int mBackgroundPss;
365 public int mBackgroundCount;
366 public int mServicePss;
367 public int mServiceCount;
368 public int mVisiblePss;
369 public int mVisibleCount;
370 public int mForegroundPss;
371 public int mForegroundCount;
372
373 public int mNoPssCount;
374
375 public int mProcDeaths[] = new int[10];
376 }
377
378 public static Watchdog getInstance() {
379 if (sWatchdog == null) {
380 sWatchdog = new Watchdog();
381 }
382
383 return sWatchdog;
384 }
385
386 private Watchdog() {
387 super("watchdog");
388 mHandler = new HeartbeatHandler();
389 mGlobalPssCollected = new GlobalPssCollected();
390 }
391
392 public void init(Context context, BatteryService battery,
393 PowerManagerService power, AlarmManagerService alarm,
394 ActivityManagerService activity) {
395 mResolver = context.getContentResolver();
396 mBattery = battery;
397 mPower = power;
398 mAlarm = alarm;
399 mActivity = activity;
400
401 context.registerReceiver(new CheckupReceiver(),
402 new IntentFilter(CHECKUP_ACTION));
403 mCheckupIntent = PendingIntent.getBroadcast(context,
404 0, new Intent(CHECKUP_ACTION), 0);
405
406 context.registerReceiver(new RebootReceiver(),
407 new IntentFilter(REBOOT_ACTION));
408 mRebootIntent = PendingIntent.getBroadcast(context,
409 0, new Intent(REBOOT_ACTION), 0);
410
411 context.registerReceiver(new RebootRequestReceiver(),
412 new IntentFilter(Intent.ACTION_REBOOT),
413 android.Manifest.permission.REBOOT, null);
414
415 mBootTime = System.currentTimeMillis();
416 }
417
418 public void processStarted(PssRequestor req, String name, int pid) {
419 synchronized (this) {
420 if ("com.android.phone".equals(name)) {
421 mPhoneReq = req;
422 mPhonePid = pid;
423 mPhonePss = 0;
424 }
425 }
426 }
427
428 public void reportPss(PssRequestor req, String name, int pss) {
429 synchronized (this) {
430 if (mPhoneReq == req) {
431 mPhonePss = pss;
432 }
433 }
434 }
435
436 public void addMonitor(Monitor monitor) {
437 synchronized (this) {
438 if (isAlive()) {
439 throw new RuntimeException("Monitors can't be added while the Watchdog is running");
440 }
441 mMonitors.add(monitor);
442 }
443 }
444
445 /**
446 * Retrieve memory usage information from specific processes being
447 * monitored. This is an async operation, so must be done before doing
448 * memory checks.
449 */
450 void collectMemory() {
451 synchronized (this) {
452 if (mPhoneReq != null) {
453 mPhoneReq.requestPss();
454 }
455 }
456 }
457
458 /**
459 * Retrieve memory usage over all application processes. This is an
460 * async operation, so must be done before doing memory checks.
461 */
462 void collectGlobalMemory() {
463 mActivity.requestPss(mGlobalPssCollected);
464 }
465
466 /**
467 * Check memory usage in the system, scheduling kills/reboots as needed.
468 * This always runs on the mHandler thread.
469 */
470 void checkMemory() {
471 boolean needScheduledCheck;
472 long curTime;
473 long nextTime = 0;
474
Doug Zongkerf6888892010-01-06 16:38:14 -0800475 long recheckInterval = Settings.Secure.getLong(
476 mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000;
478
479 mSystemMemMonitor.retrieveSettings(mResolver);
480 mPhoneMemMonitor.retrieveSettings(mResolver);
481 retrieveBrutalityAmount();
482
483 synchronized (this) {
484 curTime = System.currentTimeMillis();
485 mNeedScheduledCheck = false;
486
487 // How is the system doing?
488 if (mSystemMemMonitor.checkLocked(curTime, Process.myPid(),
489 (int)Process.getPss(Process.myPid()))) {
490 // Not good! Time to suicide.
491 mForceKillSystem = true;
492 notifyAll();
493 return;
494 }
495
496 // How is the phone process doing?
497 if (mPhoneReq != null) {
498 if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid,
499 mPhonePss)) {
500 // Just kill the phone process and let it restart.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800501 Slog.i(TAG, "Watchdog is killing the phone process");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 Process.killProcess(mPhonePid);
503 }
504 } else {
505 mPhoneMemMonitor.clear();
506 }
507
508 needScheduledCheck = mNeedScheduledCheck;
509 if (needScheduledCheck) {
510 // Something is going bad, but now is not a good time to
511 // tear things down... schedule an alarm to check again soon.
512 nextTime = curTime + recheckInterval;
513 if (nextTime < mMemcheckExecStartTime) {
514 nextTime = mMemcheckExecStartTime;
515 } else if (nextTime >= mMemcheckExecEndTime){
516 // Need to check during next exec time... so that needs
517 // to be computed.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800518 if (localLOGV) Slog.v(TAG, "Computing next time range");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 computeMemcheckTimesLocked(nextTime);
520 nextTime = mMemcheckExecStartTime;
521 }
522
523 if (localLOGV) {
524 mCalendar.setTimeInMillis(nextTime);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800525 Slog.v(TAG, "Next Alarm Time: " + mCalendar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 }
527 }
528 }
529
530 if (needScheduledCheck) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800531 if (localLOGV) Slog.v(TAG, "Scheduling next memcheck alarm for "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 + ((nextTime-curTime)/1000/60) + "m from now");
533 mAlarm.remove(mCheckupIntent);
534 mAlarm.set(AlarmManager.RTC_WAKEUP, nextTime, mCheckupIntent);
535 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800536 if (localLOGV) Slog.v(TAG, "No need to schedule a memcheck alarm!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 mAlarm.remove(mCheckupIntent);
538 }
539 }
540
541 final PssStats mPssStats = new PssStats();
542 final String[] mMemInfoFields = new String[] {
543 "MemFree:", "Buffers:", "Cached:",
544 "Active:", "Inactive:",
545 "AnonPages:", "Mapped:", "Slab:",
546 "SReclaimable:", "SUnreclaim:", "PageTables:" };
547 final long[] mMemInfoSizes = new long[mMemInfoFields.length];
548 final String[] mVMStatFields = new String[] {
549 "pgfree ", "pgactivate ", "pgdeactivate ",
550 "pgfault ", "pgmajfault " };
551 final long[] mVMStatSizes = new long[mVMStatFields.length];
552 final long[] mPrevVMStatSizes = new long[mVMStatFields.length];
553 long mLastLogGlobalMemoryTime;
554
555 void logGlobalMemory() {
556 PssStats stats = mPssStats;
557 mActivity.collectPss(stats);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800558 EventLog.writeEvent(EventLogTags.WATCHDOG_PSS_STATS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 stats.mEmptyPss, stats.mEmptyCount,
560 stats.mBackgroundPss, stats.mBackgroundCount,
561 stats.mServicePss, stats.mServiceCount,
562 stats.mVisiblePss, stats.mVisibleCount,
563 stats.mForegroundPss, stats.mForegroundCount,
564 stats.mNoPssCount);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800565 EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_STATS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 stats.mProcDeaths[0], stats.mProcDeaths[1], stats.mProcDeaths[2],
567 stats.mProcDeaths[3], stats.mProcDeaths[4]);
568 Process.readProcLines("/proc/meminfo", mMemInfoFields, mMemInfoSizes);
569 for (int i=0; i<mMemInfoSizes.length; i++) {
570 mMemInfoSizes[i] *= 1024;
571 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800572 EventLog.writeEvent(EventLogTags.WATCHDOG_MEMINFO,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 (int)mMemInfoSizes[0], (int)mMemInfoSizes[1], (int)mMemInfoSizes[2],
574 (int)mMemInfoSizes[3], (int)mMemInfoSizes[4],
575 (int)mMemInfoSizes[5], (int)mMemInfoSizes[6], (int)mMemInfoSizes[7],
576 (int)mMemInfoSizes[8], (int)mMemInfoSizes[9], (int)mMemInfoSizes[10]);
577 long now = SystemClock.uptimeMillis();
578 long dur = now - mLastLogGlobalMemoryTime;
579 mLastLogGlobalMemoryTime = now;
580 Process.readProcLines("/proc/vmstat", mVMStatFields, mVMStatSizes);
581 for (int i=0; i<mVMStatSizes.length; i++) {
582 long v = mVMStatSizes[i];
583 mVMStatSizes[i] -= mPrevVMStatSizes[i];
584 mPrevVMStatSizes[i] = v;
585 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800586 EventLog.writeEvent(EventLogTags.WATCHDOG_VMSTAT, dur,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 (int)mVMStatSizes[0], (int)mVMStatSizes[1], (int)mVMStatSizes[2],
588 (int)mVMStatSizes[3], (int)mVMStatSizes[4]);
589 }
590
591 void checkReboot(boolean fromAlarm) {
592 int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval
Doug Zongkerf6888892010-01-06 16:38:14 -0800593 : Settings.Secure.getInt(
594 mResolver, Settings.Secure.REBOOT_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 REBOOT_DEFAULT_INTERVAL);
596 mRebootInterval = rebootInterval;
597 if (rebootInterval <= 0) {
598 // No reboot interval requested.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800599 if (localLOGV) Slog.v(TAG, "No need to schedule a reboot alarm!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 mAlarm.remove(mRebootIntent);
601 return;
602 }
603
604 long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime
Doug Zongkerf6888892010-01-06 16:38:14 -0800605 : Settings.Secure.getLong(
606 mResolver, Settings.Secure.REBOOT_START_TIME,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 REBOOT_DEFAULT_START_TIME);
608 long rebootWindowMillis = (mReqRebootWindow >= 0 ? mReqRebootWindow
Doug Zongkerf6888892010-01-06 16:38:14 -0800609 : Settings.Secure.getLong(
610 mResolver, Settings.Secure.REBOOT_WINDOW,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 REBOOT_DEFAULT_WINDOW)) * 1000;
612 long recheckInterval = (mReqRecheckInterval >= 0 ? mReqRecheckInterval
Doug Zongkerf6888892010-01-06 16:38:14 -0800613 : Settings.Secure.getLong(
614 mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 MEMCHECK_DEFAULT_RECHECK_INTERVAL)) * 1000;
616
617 retrieveBrutalityAmount();
618
619 long realStartTime;
620 long now;
621
622 synchronized (this) {
623 now = System.currentTimeMillis();
624 realStartTime = computeCalendarTime(mCalendar, now,
625 rebootStartTime);
626
627 long rebootIntervalMillis = rebootInterval*24*60*60*1000;
628 if (DB || mReqRebootNoWait ||
629 (now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) {
630 if (fromAlarm && rebootWindowMillis <= 0) {
631 // No reboot window -- just immediately reboot.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800632 EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 (int)rebootIntervalMillis, (int)rebootStartTime*1000,
634 (int)rebootWindowMillis, "");
635 rebootSystem("Checkin scheduled forced");
636 return;
637 }
638
639 // Are we within the reboot window?
640 if (now < realStartTime) {
641 // Schedule alarm for next check interval.
642 realStartTime = computeCalendarTime(mCalendar,
643 now, rebootStartTime);
644 } else if (now < (realStartTime+rebootWindowMillis)) {
645 String doit = shouldWeBeBrutalLocked(now);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800646 EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 (int)rebootInterval, (int)rebootStartTime*1000,
648 (int)rebootWindowMillis, doit != null ? doit : "");
649 if (doit == null) {
650 rebootSystem("Checked scheduled range");
651 return;
652 }
653
654 // Schedule next alarm either within the window or in the
655 // next interval.
656 if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) {
657 realStartTime = computeCalendarTime(mCalendar,
658 now + rebootIntervalMillis, rebootStartTime);
659 } else {
660 realStartTime = now + recheckInterval;
661 }
662 } else {
663 // Schedule alarm for next check interval.
664 realStartTime = computeCalendarTime(mCalendar,
665 now + rebootIntervalMillis, rebootStartTime);
666 }
667 }
668 }
669
Joe Onorato8a9b2202010-02-26 18:56:32 -0800670 if (localLOGV) Slog.v(TAG, "Scheduling next reboot alarm for "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 + ((realStartTime-now)/1000/60) + "m from now");
672 mAlarm.remove(mRebootIntent);
673 mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent);
674 }
675
676 /**
677 * Perform a full reboot of the system.
678 */
679 void rebootSystem(String reason) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800680 Slog.i(TAG, "Rebooting system because: " + reason);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800681 PowerManagerService pms = (PowerManagerService) ServiceManager.getService("power");
682 pms.reboot(reason);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 }
684
685 /**
686 * Load the current Gservices settings for when
687 * {@link #shouldWeBeBrutalLocked} will allow the brutality to happen.
688 * Must not be called with the lock held.
689 */
690 void retrieveBrutalityAmount() {
691 mMinScreenOff = (mReqMinScreenOff >= 0 ? mReqMinScreenOff
Doug Zongkerf6888892010-01-06 16:38:14 -0800692 : Settings.Secure.getInt(
693 mResolver, Settings.Secure.MEMCHECK_MIN_SCREEN_OFF,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 MEMCHECK_DEFAULT_MIN_SCREEN_OFF)) * 1000;
695 mMinAlarm = (mReqMinNextAlarm >= 0 ? mReqMinNextAlarm
Doug Zongkerf6888892010-01-06 16:38:14 -0800696 : Settings.Secure.getInt(
697 mResolver, Settings.Secure.MEMCHECK_MIN_ALARM,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 MEMCHECK_DEFAULT_MIN_ALARM)) * 1000;
699 }
700
701 /**
702 * Determine whether it is a good time to kill, crash, or otherwise
703 * plunder the current situation for the overall long-term benefit of
704 * the world.
705 *
706 * @param curTime The current system time.
707 * @return Returns null if this is a good time, else a String with the
708 * text of why it is not a good time.
709 */
710 String shouldWeBeBrutalLocked(long curTime) {
711 if (mBattery == null || !mBattery.isPowered()) {
712 return "battery";
713 }
714
715 if (mMinScreenOff >= 0 && (mPower == null ||
716 mPower.timeSinceScreenOn() < mMinScreenOff)) {
717 return "screen";
718 }
719
720 if (mMinAlarm >= 0 && (mAlarm == null ||
721 mAlarm.timeToNextAlarm() < mMinAlarm)) {
722 return "alarm";
723 }
724
725 return null;
726 }
727
728 /**
729 * Compute the times during which we next would like to perform process
730 * restarts.
731 *
732 * @param curTime The current system time.
733 */
734 void computeMemcheckTimesLocked(long curTime) {
735 if (mMemcheckLastTime == curTime) {
736 return;
737 }
738
739 mMemcheckLastTime = curTime;
740
Doug Zongkerf6888892010-01-06 16:38:14 -0800741 long memcheckExecStartTime = Settings.Secure.getLong(
742 mResolver, Settings.Secure.MEMCHECK_EXEC_START_TIME,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 MEMCHECK_DEFAULT_EXEC_START_TIME);
Doug Zongkerf6888892010-01-06 16:38:14 -0800744 long memcheckExecEndTime = Settings.Secure.getLong(
745 mResolver, Settings.Secure.MEMCHECK_EXEC_END_TIME,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 MEMCHECK_DEFAULT_EXEC_END_TIME);
747
748 mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
749 memcheckExecEndTime);
750 if (mMemcheckExecEndTime < curTime) {
751 memcheckExecStartTime += 24*60*60;
752 memcheckExecEndTime += 24*60*60;
753 mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
754 memcheckExecEndTime);
755 }
756 mMemcheckExecStartTime = computeCalendarTime(mCalendar, curTime,
757 memcheckExecStartTime);
758
759 if (localLOGV) {
760 mCalendar.setTimeInMillis(curTime);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800761 Slog.v(TAG, "Current Time: " + mCalendar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 mCalendar.setTimeInMillis(mMemcheckExecStartTime);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800763 Slog.v(TAG, "Start Check Time: " + mCalendar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 mCalendar.setTimeInMillis(mMemcheckExecEndTime);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800765 Slog.v(TAG, "End Check Time: " + mCalendar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 }
767 }
768
769 static long computeCalendarTime(Calendar c, long curTime,
770 long secondsSinceMidnight) {
771
772 // start with now
773 c.setTimeInMillis(curTime);
774
775 int val = (int)secondsSinceMidnight / (60*60);
776 c.set(Calendar.HOUR_OF_DAY, val);
777 secondsSinceMidnight -= val * (60*60);
778 val = (int)secondsSinceMidnight / 60;
779 c.set(Calendar.MINUTE, val);
780 c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60));
781 c.set(Calendar.MILLISECOND, 0);
782
783 long newTime = c.getTimeInMillis();
784 if (newTime < curTime) {
785 // The given time (in seconds since midnight) has already passed for today, so advance
786 // by one day (due to daylight savings, etc., the delta may differ from 24 hours).
787 c.add(Calendar.DAY_OF_MONTH, 1);
788 newTime = c.getTimeInMillis();
789 }
790
791 return newTime;
792 }
793
794 @Override
795 public void run() {
Christopher Tate6ee412d2010-05-28 12:01:56 -0700796 boolean waitedHalf = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 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
Christopher Tate6ee412d2010-05-28 12:01:56 -0700806 // to timeout on is asleep as well and won't have a chance to run, causing a false
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 // 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.
Christopher Tate6ee412d2010-05-28 12:01:56 -0700820 waitedHalf = false;
821 continue;
822 }
823
824 if (!waitedHalf) {
825 // We've waited half the deadlock-detection interval. Pull a stack
826 // trace and wait another half.
827 ArrayList pids = new ArrayList();
828 pids.add(Process.myPid());
829 File stack = ActivityManagerService.dumpStackTraces(true, pids);
830 waitedHalf = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 continue;
832 }
833 }
834
835 // If we got here, that means that the system is most likely hung.
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800836 // First collect stack traces from all threads of the system process.
837 // Then kill this process so that the system will restart.
838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null";
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800840 EventLog.writeEvent(EventLogTags.WATCHDOG, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800842 ArrayList pids = new ArrayList();
843 pids.add(Process.myPid());
Dan Egnor4bded072010-03-11 22:00:47 -0800844 if (mPhonePid > 0) pids.add(mPhonePid);
Christopher Tate6ee412d2010-05-28 12:01:56 -0700845 // Pass !waitedHalf so that just in case we somehow wind up here without having
846 // dumped the halfway stacks, we properly re-initialize the trace file.
847 File stack = ActivityManagerService.dumpStackTraces(!waitedHalf, pids);
Dan Egnor4bded072010-03-11 22:00:47 -0800848
849 // Give some extra time to make sure the stack traces get written.
850 // The system's been hanging for a minute, another second or two won't hurt much.
851 SystemClock.sleep(2000);
852
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800853 mActivity.addErrorToDropBox("watchdog", null, null, null, name, null, stack, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854
855 // Only kill the process if the debugger is not attached.
856 if (!Debug.isDebuggerConnected()) {
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800857 Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 Process.killProcess(Process.myPid());
Dan Egnor9bdc94b2010-03-04 14:20:31 -0800859 System.exit(10);
860 } else {
861 Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 }
Christopher Tate6ee412d2010-05-28 12:01:56 -0700863
864 waitedHalf = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 }
866 }
867}