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