• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.server;
18 
19 import com.android.server.am.ActivityManagerService;
20 
21 import android.app.AlarmManager;
22 import android.app.PendingIntent;
23 import android.content.BroadcastReceiver;
24 import android.content.ContentResolver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.os.Debug;
29 import android.os.Handler;
30 import android.os.Message;
31 import android.os.Process;
32 import android.os.SystemClock;
33 import android.os.SystemProperties;
34 import android.provider.Settings;
35 import android.util.Config;
36 import android.util.EventLog;
37 import android.util.Log;
38 
39 import java.io.IOException;
40 import java.util.ArrayList;
41 import java.util.Calendar;
42 
43 /** This class calls its monitor every minute. Killing this process if they don't return **/
44 public 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 
MemMonitor(String processName, String enabledSetting, String softSetting, int defSoftThreshold, String hardSetting, int defHardThreshold)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 
retrieveSettings(ContentResolver resolver)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 
checkLocked(long curTime, int pid, int pss)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 
clear()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
handleMessage(Message msg)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 {
run()320         public void run() {
321             mHandler.sendEmptyMessage(GLOBAL_PSS);
322         }
323     }
324 
325     final class CheckupReceiver extends BroadcastReceiver {
326         @Override
onReceive(Context c, Intent intent)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
onReceive(Context c, Intent intent)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
onReceive(Context c, Intent intent)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 {
monitor()360         void monitor();
361     }
362 
363     public interface PssRequestor {
requestPss()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 
getInstance()384     public static Watchdog getInstance() {
385         if (sWatchdog == null) {
386             sWatchdog = new Watchdog();
387         }
388 
389         return sWatchdog;
390     }
391 
Watchdog()392     private Watchdog() {
393         super("watchdog");
394         mHandler = new HeartbeatHandler();
395         mGlobalPssCollected = new GlobalPssCollected();
396     }
397 
init(Context context, BatteryService battery, PowerManagerService power, AlarmManagerService alarm, ActivityManagerService activity)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 
processStarted(PssRequestor req, String name, int pid)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 
reportPss(PssRequestor req, String name, int pss)434     public void reportPss(PssRequestor req, String name, int pss) {
435         synchronized (this) {
436             if (mPhoneReq == req) {
437                 mPhonePss = pss;
438             }
439         }
440     }
441 
addMonitor(Monitor monitor)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      */
collectMemory()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      */
collectGlobalMemory()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      */
checkMemory()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 
logGlobalMemory()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 
checkReboot(boolean fromAlarm)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      */
rebootSystem(String reason)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      */
retrieveBrutalityAmount()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      */
shouldWeBeBrutalLocked(long curTime)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      */
computeMemcheckTimesLocked(long curTime)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 
computeCalendarTime(Calendar c, long curTime, long secondsSinceMidnight)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
run()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