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