blob: ee69715391b9263a693b25b1f16d0538f290e261 [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;
Joe Onorato8a9b2202010-02-26 18:56:32 -080037import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
39import java.io.IOException;
40import java.util.ArrayList;
41import java.util.Calendar;
42
43/** This class calls its monitor every minute. Killing this process if they don't return **/
44public class Watchdog extends Thread {
45 static final String TAG = "Watchdog";
46 static final boolean localLOGV = false || Config.LOGV;
47
48 // Set this to true to use debug default values.
49 static final boolean DB = false;
50
51 static final int MONITOR = 2718;
52 static final int GLOBAL_PSS = 2719;
53
54 static final int TIME_TO_WAIT = DB ? 15*1000 : 60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
56 static final int MEMCHECK_DEFAULT_INTERVAL = DB ? 30 : 30*60; // 30 minutes
57 static final int MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL = DB ? 60 : 2*60*60; // 2 hours
58 static final int MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD = (DB ? 10:16)*1024*1024; // 16MB
59 static final int MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD = (DB ? 14:20)*1024*1024; // 20MB
60 static final int MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD = (DB ? 4:8)*1024*1024; // 8MB
61 static final int MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD = (DB ? 8:12)*1024*1024; // 12MB
62
63 static final int MEMCHECK_DEFAULT_EXEC_START_TIME = 1*60*60; // 1:00am
64 static final int MEMCHECK_DEFAULT_EXEC_END_TIME = 5*60*60; // 5:00am
65 static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60; // 5 minutes
66 static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60; // 3 minutes
67 static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes
68
69 static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0; // never force reboot
70 static final int REBOOT_DEFAULT_START_TIME = 3*60*60; // 3:00am
71 static final int REBOOT_DEFAULT_WINDOW = 60*60; // within 1 hour
72
73 static final String CHECKUP_ACTION = "com.android.service.Watchdog.CHECKUP";
74 static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";
75
76 static Watchdog sWatchdog;
77
78 /* This handler will be used to post message back onto the main thread */
79 final Handler mHandler;
80 final Runnable mGlobalPssCollected;
81 final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
82 ContentResolver mResolver;
83 BatteryService mBattery;
84 PowerManagerService mPower;
85 AlarmManagerService mAlarm;
86 ActivityManagerService mActivity;
87 boolean mCompleted;
88 boolean mForceKillSystem;
89 Monitor mCurrentMonitor;
90
91 PssRequestor mPhoneReq;
92 int mPhonePid;
93 int mPhonePss;
94
95 long mLastMemCheckTime = -(MEMCHECK_DEFAULT_INTERVAL*1000);
96 boolean mHavePss;
97 long mLastMemCheckRealtime = -(MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL*1000);
98 boolean mHaveGlobalPss;
99 final MemMonitor mSystemMemMonitor = new MemMonitor("system",
Doug Zongkerf6888892010-01-06 16:38:14 -0800100 Settings.Secure.MEMCHECK_SYSTEM_ENABLED,
101 Settings.Secure.MEMCHECK_SYSTEM_SOFT_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD,
Doug Zongkerf6888892010-01-06 16:38:14 -0800103 Settings.Secure.MEMCHECK_SYSTEM_HARD_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD);
105 final MemMonitor mPhoneMemMonitor = new MemMonitor("com.android.phone",
Doug Zongkerf6888892010-01-06 16:38:14 -0800106 Settings.Secure.MEMCHECK_PHONE_ENABLED,
107 Settings.Secure.MEMCHECK_PHONE_SOFT_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD,
Doug Zongkerf6888892010-01-06 16:38:14 -0800109 Settings.Secure.MEMCHECK_PHONE_HARD_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD);
111
112 final Calendar mCalendar = Calendar.getInstance();
113 long mMemcheckLastTime;
114 long mMemcheckExecStartTime;
115 long mMemcheckExecEndTime;
116 int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF;
117 int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM;
118 boolean mNeedScheduledCheck;
119 PendingIntent mCheckupIntent;
120 PendingIntent mRebootIntent;
121
122 long mBootTime;
123 int mRebootInterval;
124
125 boolean mReqRebootNoWait; // should wait for one interval before reboot?
126 int mReqRebootInterval = -1; // >= 0 if a reboot has been requested
127 int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested
128 int mReqRebootWindow = -1; // >= 0 if a specific window has been requested
129 int mReqMinScreenOff = -1; // >= 0 if a specific screen off time has been requested
130 int mReqMinNextAlarm = -1; // >= 0 if specific time to next alarm has been requested
131 int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested
132
133 /**
134 * This class monitors the memory in a particular process.
135 */
136 final class MemMonitor {
137 final String mProcessName;
138 final String mEnabledSetting;
139 final String mSoftSetting;
140 final String mHardSetting;
141
142 int mSoftThreshold;
143 int mHardThreshold;
144 boolean mEnabled;
145 long mLastPss;
146
147 static final int STATE_OK = 0;
148 static final int STATE_SOFT = 1;
149 static final int STATE_HARD = 2;
150 int mState;
151
152 MemMonitor(String processName, String enabledSetting,
153 String softSetting, int defSoftThreshold,
154 String hardSetting, int defHardThreshold) {
155 mProcessName = processName;
156 mEnabledSetting = enabledSetting;
157 mSoftSetting = softSetting;
158 mHardSetting = hardSetting;
159 mSoftThreshold = defSoftThreshold;
160 mHardThreshold = defHardThreshold;
161 }
162
163 void retrieveSettings(ContentResolver resolver) {
Doug Zongkerf6888892010-01-06 16:38:14 -0800164 mSoftThreshold = Settings.Secure.getInt(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 resolver, mSoftSetting, mSoftThreshold);
Doug Zongkerf6888892010-01-06 16:38:14 -0800166 mHardThreshold = Settings.Secure.getInt(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 resolver, mHardSetting, mHardThreshold);
Doug Zongkerf6888892010-01-06 16:38:14 -0800168 mEnabled = Settings.Secure.getInt(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 resolver, mEnabledSetting, 0) != 0;
170 }
171
172 boolean checkLocked(long curTime, int pid, int pss) {
173 mLastPss = pss;
174 if (mLastPss < mSoftThreshold) {
175 mState = STATE_OK;
176 } else if (mLastPss < mHardThreshold) {
177 mState = STATE_SOFT;
178 } else {
179 mState = STATE_HARD;
180 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800181 EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_PSS, mProcessName, pid, mLastPss);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182
183 if (mState == STATE_OK) {
184 // Memory is good, don't recover.
185 return false;
186 }
187
188 if (mState == STATE_HARD) {
189 // Memory is really bad, kill right now.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800190 EventLog.writeEvent(EventLogTags.WATCHDOG_HARD_RESET, mProcessName, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 mHardThreshold, mLastPss);
192 return mEnabled;
193 }
194
195 // It is time to schedule a reset...
196 // Check if we are currently within the time to kill processes due
197 // to memory use.
198 computeMemcheckTimesLocked(curTime);
199 String skipReason = null;
200 if (curTime < mMemcheckExecStartTime || curTime > mMemcheckExecEndTime) {
201 skipReason = "time";
202 } else {
203 skipReason = shouldWeBeBrutalLocked(curTime);
204 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800205 EventLog.writeEvent(EventLogTags.WATCHDOG_SOFT_RESET, mProcessName, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 mSoftThreshold, mLastPss, skipReason != null ? skipReason : "");
207 if (skipReason != null) {
208 mNeedScheduledCheck = true;
209 return false;
210 }
211 return mEnabled;
212 }
213
214 void clear() {
215 mLastPss = 0;
216 mState = STATE_OK;
217 }
218 }
219
220 /**
221 * Used for scheduling monitor callbacks and checking memory usage.
222 */
223 final class HeartbeatHandler extends Handler {
224 @Override
225 public void handleMessage(Message msg) {
226 switch (msg.what) {
227 case GLOBAL_PSS: {
228 if (mHaveGlobalPss) {
229 // During the last pass we collected pss information, so
230 // now it is time to report it.
231 mHaveGlobalPss = false;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800232 if (localLOGV) Slog.v(TAG, "Received global pss, logging.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 logGlobalMemory();
234 }
235 } break;
236
237 case MONITOR: {
238 if (mHavePss) {
239 // During the last pass we collected pss information, so
240 // now it is time to report it.
241 mHavePss = false;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800242 if (localLOGV) Slog.v(TAG, "Have pss, checking memory.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 checkMemory();
244 }
245
246 if (mHaveGlobalPss) {
247 // During the last pass we collected pss information, so
248 // now it is time to report it.
249 mHaveGlobalPss = false;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800250 if (localLOGV) Slog.v(TAG, "Have global pss, logging.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 logGlobalMemory();
252 }
253
254 long now = SystemClock.uptimeMillis();
255
256 // See if we should force a reboot.
257 int rebootInterval = mReqRebootInterval >= 0
Doug Zongkerf6888892010-01-06 16:38:14 -0800258 ? mReqRebootInterval : Settings.Secure.getInt(
259 mResolver, Settings.Secure.REBOOT_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 REBOOT_DEFAULT_INTERVAL);
261 if (mRebootInterval != rebootInterval) {
262 mRebootInterval = rebootInterval;
263 // We have been running long enough that a reboot can
264 // be considered...
265 checkReboot(false);
266 }
267
268 // See if we should check memory conditions.
Doug Zongkerf6888892010-01-06 16:38:14 -0800269 long memCheckInterval = Settings.Secure.getLong(
270 mResolver, Settings.Secure.MEMCHECK_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 MEMCHECK_DEFAULT_INTERVAL) * 1000;
272 if ((mLastMemCheckTime+memCheckInterval) < now) {
273 // It is now time to collect pss information. This
274 // is async so we won't report it now. And to keep
275 // things simple, we will assume that everyone has
276 // reported back by the next MONITOR message.
277 mLastMemCheckTime = now;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800278 if (localLOGV) Slog.v(TAG, "Collecting memory usage.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 collectMemory();
280 mHavePss = true;
281
Doug Zongkerf6888892010-01-06 16:38:14 -0800282 long memCheckRealtimeInterval = Settings.Secure.getLong(
283 mResolver, Settings.Secure.MEMCHECK_LOG_REALTIME_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL) * 1000;
285 long realtimeNow = SystemClock.elapsedRealtime();
286 if ((mLastMemCheckRealtime+memCheckRealtimeInterval) < realtimeNow) {
287 mLastMemCheckRealtime = realtimeNow;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800288 if (localLOGV) Slog.v(TAG, "Collecting global memory usage.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 collectGlobalMemory();
290 mHaveGlobalPss = true;
291 }
292 }
293
294 final int size = mMonitors.size();
295 for (int i = 0 ; i < size ; i++) {
296 mCurrentMonitor = mMonitors.get(i);
297 mCurrentMonitor.monitor();
298 }
299
300 synchronized (Watchdog.this) {
301 mCompleted = true;
302 mCurrentMonitor = null;
303 }
304 } break;
305 }
306 }
307 }
308
309 final class GlobalPssCollected implements Runnable {
310 public void run() {
311 mHandler.sendEmptyMessage(GLOBAL_PSS);
312 }
313 }
314
315 final class CheckupReceiver extends BroadcastReceiver {
316 @Override
317 public void onReceive(Context c, Intent intent) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800318 if (localLOGV) Slog.v(TAG, "Alarm went off, checking memory.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 checkMemory();
320 }
321 }
322
323 final class RebootReceiver extends BroadcastReceiver {
324 @Override
325 public void onReceive(Context c, Intent intent) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800326 if (localLOGV) Slog.v(TAG, "Alarm went off, checking reboot.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 checkReboot(true);
328 }
329 }
330
331 final class RebootRequestReceiver extends BroadcastReceiver {
332 @Override
333 public void onReceive(Context c, Intent intent) {
334 mReqRebootNoWait = intent.getIntExtra("nowait", 0) != 0;
335 mReqRebootInterval = intent.getIntExtra("interval", -1);
336 mReqRebootStartTime = intent.getIntExtra("startTime", -1);
337 mReqRebootWindow = intent.getIntExtra("window", -1);
338 mReqMinScreenOff = intent.getIntExtra("minScreenOff", -1);
339 mReqMinNextAlarm = intent.getIntExtra("minNextAlarm", -1);
340 mReqRecheckInterval = intent.getIntExtra("recheckInterval", -1);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800341 EventLog.writeEvent(EventLogTags.WATCHDOG_REQUESTED_REBOOT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 mReqRebootNoWait ? 1 : 0, mReqRebootInterval,
343 mReqRecheckInterval, mReqRebootStartTime,
344 mReqRebootWindow, mReqMinScreenOff, mReqMinNextAlarm);
345 checkReboot(true);
346 }
347 }
348
349 public interface Monitor {
350 void monitor();
351 }
352
353 public interface PssRequestor {
354 void requestPss();
355 }
356
357 public class PssStats {
358 public int mEmptyPss;
359 public int mEmptyCount;
360 public int mBackgroundPss;
361 public int mBackgroundCount;
362 public int mServicePss;
363 public int mServiceCount;
364 public int mVisiblePss;
365 public int mVisibleCount;
366 public int mForegroundPss;
367 public int mForegroundCount;
368
369 public int mNoPssCount;
370
371 public int mProcDeaths[] = new int[10];
372 }
373
374 public static Watchdog getInstance() {
375 if (sWatchdog == null) {
376 sWatchdog = new Watchdog();
377 }
378
379 return sWatchdog;
380 }
381
382 private Watchdog() {
383 super("watchdog");
384 mHandler = new HeartbeatHandler();
385 mGlobalPssCollected = new GlobalPssCollected();
386 }
387
388 public void init(Context context, BatteryService battery,
389 PowerManagerService power, AlarmManagerService alarm,
390 ActivityManagerService activity) {
391 mResolver = context.getContentResolver();
392 mBattery = battery;
393 mPower = power;
394 mAlarm = alarm;
395 mActivity = activity;
396
397 context.registerReceiver(new CheckupReceiver(),
398 new IntentFilter(CHECKUP_ACTION));
399 mCheckupIntent = PendingIntent.getBroadcast(context,
400 0, new Intent(CHECKUP_ACTION), 0);
401
402 context.registerReceiver(new RebootReceiver(),
403 new IntentFilter(REBOOT_ACTION));
404 mRebootIntent = PendingIntent.getBroadcast(context,
405 0, new Intent(REBOOT_ACTION), 0);
406
407 context.registerReceiver(new RebootRequestReceiver(),
408 new IntentFilter(Intent.ACTION_REBOOT),
409 android.Manifest.permission.REBOOT, null);
410
411 mBootTime = System.currentTimeMillis();
412 }
413
414 public void processStarted(PssRequestor req, String name, int pid) {
415 synchronized (this) {
416 if ("com.android.phone".equals(name)) {
417 mPhoneReq = req;
418 mPhonePid = pid;
419 mPhonePss = 0;
420 }
421 }
422 }
423
424 public void reportPss(PssRequestor req, String name, int pss) {
425 synchronized (this) {
426 if (mPhoneReq == req) {
427 mPhonePss = pss;
428 }
429 }
430 }
431
432 public void addMonitor(Monitor monitor) {
433 synchronized (this) {
434 if (isAlive()) {
435 throw new RuntimeException("Monitors can't be added while the Watchdog is running");
436 }
437 mMonitors.add(monitor);
438 }
439 }
440
441 /**
442 * Retrieve memory usage information from specific processes being
443 * monitored. This is an async operation, so must be done before doing
444 * memory checks.
445 */
446 void collectMemory() {
447 synchronized (this) {
448 if (mPhoneReq != null) {
449 mPhoneReq.requestPss();
450 }
451 }
452 }
453
454 /**
455 * Retrieve memory usage over all application processes. This is an
456 * async operation, so must be done before doing memory checks.
457 */
458 void collectGlobalMemory() {
459 mActivity.requestPss(mGlobalPssCollected);
460 }
461
462 /**
463 * Check memory usage in the system, scheduling kills/reboots as needed.
464 * This always runs on the mHandler thread.
465 */
466 void checkMemory() {
467 boolean needScheduledCheck;
468 long curTime;
469 long nextTime = 0;
470
Doug Zongkerf6888892010-01-06 16:38:14 -0800471 long recheckInterval = Settings.Secure.getLong(
472 mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000;
474
475 mSystemMemMonitor.retrieveSettings(mResolver);
476 mPhoneMemMonitor.retrieveSettings(mResolver);
477 retrieveBrutalityAmount();
478
479 synchronized (this) {
480 curTime = System.currentTimeMillis();
481 mNeedScheduledCheck = false;
482
483 // How is the system doing?
484 if (mSystemMemMonitor.checkLocked(curTime, Process.myPid(),
485 (int)Process.getPss(Process.myPid()))) {
486 // Not good! Time to suicide.
487 mForceKillSystem = true;
488 notifyAll();
489 return;
490 }
491
492 // How is the phone process doing?
493 if (mPhoneReq != null) {
494 if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid,
495 mPhonePss)) {
496 // Just kill the phone process and let it restart.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800497 Slog.i(TAG, "Watchdog is killing the phone process");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 Process.killProcess(mPhonePid);
499 }
500 } else {
501 mPhoneMemMonitor.clear();
502 }
503
504 needScheduledCheck = mNeedScheduledCheck;
505 if (needScheduledCheck) {
506 // Something is going bad, but now is not a good time to
507 // tear things down... schedule an alarm to check again soon.
508 nextTime = curTime + recheckInterval;
509 if (nextTime < mMemcheckExecStartTime) {
510 nextTime = mMemcheckExecStartTime;
511 } else if (nextTime >= mMemcheckExecEndTime){
512 // Need to check during next exec time... so that needs
513 // to be computed.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800514 if (localLOGV) Slog.v(TAG, "Computing next time range");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 computeMemcheckTimesLocked(nextTime);
516 nextTime = mMemcheckExecStartTime;
517 }
518
519 if (localLOGV) {
520 mCalendar.setTimeInMillis(nextTime);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800521 Slog.v(TAG, "Next Alarm Time: " + mCalendar);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 }
523 }
524 }
525
526 if (needScheduledCheck) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800527 if (localLOGV) Slog.v(TAG, "Scheduling next memcheck alarm for "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 + ((nextTime-curTime)/1000/60) + "m from now");
529 mAlarm.remove(mCheckupIntent);
530 mAlarm.set(AlarmManager.RTC_WAKEUP, nextTime, mCheckupIntent);
531 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800532 if (localLOGV) Slog.v(TAG, "No need to schedule a memcheck alarm!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 mAlarm.remove(mCheckupIntent);
534 }
535 }
536
537 final PssStats mPssStats = new PssStats();
538 final String[] mMemInfoFields = new String[] {
539 "MemFree:", "Buffers:", "Cached:",
540 "Active:", "Inactive:",
541 "AnonPages:", "Mapped:", "Slab:",
542 "SReclaimable:", "SUnreclaim:", "PageTables:" };
543 final long[] mMemInfoSizes = new long[mMemInfoFields.length];
544 final String[] mVMStatFields = new String[] {
545 "pgfree ", "pgactivate ", "pgdeactivate ",
546 "pgfault ", "pgmajfault " };
547 final long[] mVMStatSizes = new long[mVMStatFields.length];
548 final long[] mPrevVMStatSizes = new long[mVMStatFields.length];
549 long mLastLogGlobalMemoryTime;
550
551 void logGlobalMemory() {
552 PssStats stats = mPssStats;
553 mActivity.collectPss(stats);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800554 EventLog.writeEvent(EventLogTags.WATCHDOG_PSS_STATS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 stats.mEmptyPss, stats.mEmptyCount,
556 stats.mBackgroundPss, stats.mBackgroundCount,
557 stats.mServicePss, stats.mServiceCount,
558 stats.mVisiblePss, stats.mVisibleCount,
559 stats.mForegroundPss, stats.mForegroundCount,
560 stats.mNoPssCount);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800561 EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_STATS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 stats.mProcDeaths[0], stats.mProcDeaths[1], stats.mProcDeaths[2],
563 stats.mProcDeaths[3], stats.mProcDeaths[4]);
564 Process.readProcLines("/proc/meminfo", mMemInfoFields, mMemInfoSizes);
565 for (int i=0; i<mMemInfoSizes.length; i++) {
566 mMemInfoSizes[i] *= 1024;
567 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800568 EventLog.writeEvent(EventLogTags.WATCHDOG_MEMINFO,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 (int)mMemInfoSizes[0], (int)mMemInfoSizes[1], (int)mMemInfoSizes[2],
570 (int)mMemInfoSizes[3], (int)mMemInfoSizes[4],
571 (int)mMemInfoSizes[5], (int)mMemInfoSizes[6], (int)mMemInfoSizes[7],
572 (int)mMemInfoSizes[8], (int)mMemInfoSizes[9], (int)mMemInfoSizes[10]);
573 long now = SystemClock.uptimeMillis();
574 long dur = now - mLastLogGlobalMemoryTime;
575 mLastLogGlobalMemoryTime = now;
576 Process.readProcLines("/proc/vmstat", mVMStatFields, mVMStatSizes);
577 for (int i=0; i<mVMStatSizes.length; i++) {
578 long v = mVMStatSizes[i];
579 mVMStatSizes[i] -= mPrevVMStatSizes[i];
580 mPrevVMStatSizes[i] = v;
581 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800582 EventLog.writeEvent(EventLogTags.WATCHDOG_VMSTAT, dur,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 (int)mVMStatSizes[0], (int)mVMStatSizes[1], (int)mVMStatSizes[2],
584 (int)mVMStatSizes[3], (int)mVMStatSizes[4]);
585 }
586
587 void checkReboot(boolean fromAlarm) {
588 int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval
Doug Zongkerf6888892010-01-06 16:38:14 -0800589 : Settings.Secure.getInt(
590 mResolver, Settings.Secure.REBOOT_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 REBOOT_DEFAULT_INTERVAL);
592 mRebootInterval = rebootInterval;
593 if (rebootInterval <= 0) {
594 // No reboot interval requested.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800595 if (localLOGV) Slog.v(TAG, "No need to schedule a reboot alarm!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 mAlarm.remove(mRebootIntent);
597 return;
598 }
599
600 long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime
Doug Zongkerf6888892010-01-06 16:38:14 -0800601 : Settings.Secure.getLong(
602 mResolver, Settings.Secure.REBOOT_START_TIME,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 REBOOT_DEFAULT_START_TIME);
604 long rebootWindowMillis = (mReqRebootWindow >= 0 ? mReqRebootWindow
Doug Zongkerf6888892010-01-06 16:38:14 -0800605 : Settings.Secure.getLong(
606 mResolver, Settings.Secure.REBOOT_WINDOW,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 REBOOT_DEFAULT_WINDOW)) * 1000;
608 long recheckInterval = (mReqRecheckInterval >= 0 ? mReqRecheckInterval
Doug Zongkerf6888892010-01-06 16:38:14 -0800609 : Settings.Secure.getLong(
610 mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 MEMCHECK_DEFAULT_RECHECK_INTERVAL)) * 1000;
612
613 retrieveBrutalityAmount();
614
615 long realStartTime;
616 long now;
617
618 synchronized (this) {
619 now = System.currentTimeMillis();
620 realStartTime = computeCalendarTime(mCalendar, now,
621 rebootStartTime);
622
623 long rebootIntervalMillis = rebootInterval*24*60*60*1000;
624 if (DB || mReqRebootNoWait ||
625 (now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) {
626 if (fromAlarm && rebootWindowMillis <= 0) {
627 // No reboot window -- just immediately reboot.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800628 EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 (int)rebootIntervalMillis, (int)rebootStartTime*1000,
630 (int)rebootWindowMillis, "");
631 rebootSystem("Checkin scheduled forced");
632 return;
633 }
634
635 // Are we within the reboot window?
636 if (now < realStartTime) {
637 // Schedule alarm for next check interval.
638 realStartTime = computeCalendarTime(mCalendar,
639 now, rebootStartTime);
640 } else if (now < (realStartTime+rebootWindowMillis)) {
641 String doit = shouldWeBeBrutalLocked(now);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800642 EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 (int)rebootInterval, (int)rebootStartTime*1000,
644 (int)rebootWindowMillis, doit != null ? doit : "");
645 if (doit == null) {
646 rebootSystem("Checked scheduled range");
647 return;
648 }
649
650 // Schedule next alarm either within the window or in the
651 // next interval.
652 if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) {
653 realStartTime = computeCalendarTime(mCalendar,
654 now + rebootIntervalMillis, rebootStartTime);
655 } else {
656 realStartTime = now + recheckInterval;
657 }
658 } else {
659 // Schedule alarm for next check interval.
660 realStartTime = computeCalendarTime(mCalendar,
661 now + rebootIntervalMillis, rebootStartTime);
662 }
663 }
664 }
665
Joe Onorato8a9b2202010-02-26 18:56:32 -0800666 if (localLOGV) Slog.v(TAG, "Scheduling next reboot alarm for "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 + ((realStartTime-now)/1000/60) + "m from now");
668 mAlarm.remove(mRebootIntent);
669 mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent);
670 }
671
672 /**
673 * Perform a full reboot of the system.
674 */
675 void rebootSystem(String reason) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800676 Slog.i(TAG, "Rebooting system because: " + reason);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 try {
678 android.os.Power.reboot(reason);
679 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800680 Slog.e(TAG, "Reboot failed!", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 }
682 }
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();
807 do {
808 try {
809 wait(timeout);
810 } catch (InterruptedException e) {
811 if (SystemProperties.getBoolean("ro.secure", false)) {
812 // If this is a secure build, just log the error.
Joe Onorato8a9b2202010-02-26 18:56:32 -0800813 Slog.e("WatchDog", "Woof! Woof! Interrupter!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 } else {
815 throw new AssertionError("Someone interrupted the watchdog");
816 }
817 }
818 timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
819 } while (timeout > 0 && !mForceKillSystem);
820
821 if (mCompleted && !mForceKillSystem) {
822 // The monitors have returned.
823 continue;
824 }
825 }
826
827 // If we got here, that means that the system is most likely hung.
828 // First send a SIGQUIT so that we can see where it was hung. Then
829 // kill this process so that the system will restart.
830 String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null";
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800831 EventLog.writeEvent(EventLogTags.WATCHDOG, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT);
833
834 // Wait a bit longer before killing so we can make sure that the stacks are captured.
835 try {
836 Thread.sleep(10*1000);
837 } catch (InterruptedException e) {
838 }
839
840 // Only kill the process if the debugger is not attached.
841 if (!Debug.isDebuggerConnected()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800842 Slog.i(TAG, "Watchdog is killing the system process");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 Process.killProcess(Process.myPid());
844 }
845 }
846 }
847}