1 /*
2  * Copyright (C) 2021 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.scheduling;
18 
19 import android.Manifest;
20 import android.annotation.CurrentTimeMillisLong;
21 import android.app.ActivityManager;
22 import android.app.ActivityManager.RunningServiceInfo;
23 import android.app.AlarmManager;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.pm.PackageManager;
29 import android.net.TetheredClient;
30 import android.net.TetheringManager;
31 import android.net.TetheringManager.TetheringEventCallback;
32 import android.os.Binder;
33 import android.os.Handler;
34 import android.os.Looper;
35 import android.os.ParcelFileDescriptor;
36 import android.os.PowerManager;
37 import android.os.RemoteCallback;
38 import android.os.RemoteCallbackList;
39 import android.os.RemoteException;
40 import android.os.SystemClock;
41 import android.os.UserHandle;
42 import android.provider.DeviceConfig;
43 import android.scheduling.IRebootReadinessManager;
44 import android.scheduling.IRequestRebootReadinessStatusListener;
45 import android.scheduling.RebootReadinessManager;
46 import android.util.ArraySet;
47 import android.util.Log;
48 import android.util.SparseArray;
49 
50 import com.android.internal.annotations.GuardedBy;
51 import com.android.internal.annotations.VisibleForTesting;
52 import com.android.modules.utils.HandlerExecutor;
53 import com.android.server.SystemService;
54 
55 import java.io.FileDescriptor;
56 import java.io.PrintWriter;
57 import java.util.ArrayList;
58 import java.util.Collection;
59 import java.util.List;
60 import java.util.concurrent.CountDownLatch;
61 import java.util.concurrent.Executor;
62 import java.util.concurrent.TimeUnit;
63 
64 /**
65  * Implementation of service that analyzes device state to detect if the device is in a suitable
66  * state to reboot.
67  *
68  * @hide
69  */
70 public class RebootReadinessManagerService extends IRebootReadinessManager.Stub {
71     private static final String TAG = "RebootReadinessManager";
72 
73     private final RemoteCallbackList<IRequestRebootReadinessStatusListener> mCallbacks =
74             new RemoteCallbackList<IRequestRebootReadinessStatusListener>();
75     private final Handler mHandler;
76     private final Executor mExecutor;
77 
78     private final Object mLock = new Object();
79 
80     private final Context mContext;
81 
82     private final ActivityManager mActivityManager;
83 
84     private final AlarmManager mAlarmManager;
85 
86     private final RebootReadinessLogger mRebootReadinessLogger;
87 
88     // For testing purposes only. Listeners whose names start with this prefix will be able to
89     // inform the reboot signal, even if subsystem checks are disabled for testing.
90     private static final String TEST_CALLBACK_PREFIX = "TESTCOMPONENT";
91 
92     // DeviceConfig properties
93     private static final String PROPERTY_ACTIVE_POLLING_INTERVAL_MS = "active_polling_interval_ms";
94     private static final String PROPERTY_INTERACTIVITY_THRESHOLD_MS = "interactivity_threshold_ms";
95     private static final String PROPERTY_DISABLE_INTERACTIVITY_CHECK =
96             "disable_interactivity_check";
97     private static final String PROPERTY_DISABLE_APP_ACTIVITY_CHECK = "disable_app_activity_check";
98     private static final String PROPERTY_DISABLE_SUBSYSTEMS_CHECK = "disable_subsystems_check";
99     private static final String PROPERTY_ALARM_CLOCK_THRESHOLD_MS = "alarm_clock_threshold_ms";
100     private static final String PROPERTY_LOGGING_BLOCKING_ENTITY_THRESHOLD_MS =
101             "logging_blocking_entity_threshold_ms";
102 
103 
104     private static final long DEFAULT_POLLING_INTERVAL_WHILE_ACTIVE_MS =
105             TimeUnit.MINUTES.toMillis(5);
106     private static final long DEFAULT_INTERACTIVITY_THRESHOLD_MS = TimeUnit.MINUTES.toMillis(30);
107     private static final long DEFAULT_ALARM_CLOCK_THRESHOLD_MS = TimeUnit.MINUTES.toMillis(10);
108     private static final long DEFAULT_LOGGING_BLOCKING_ENTITY_THRESHOLD_MS =
109             TimeUnit.HOURS.toMillis(1);
110 
111     @GuardedBy("mLock")
112     private long mActivePollingIntervalMs = DEFAULT_POLLING_INTERVAL_WHILE_ACTIVE_MS;
113 
114     @GuardedBy("mLock")
115     private long mInteractivityThresholdMs = DEFAULT_INTERACTIVITY_THRESHOLD_MS;
116 
117     @GuardedBy("mLock")
118     private boolean mDisableInteractivityCheck = false;
119 
120     @GuardedBy("mLock")
121     private boolean mReadyToReboot = false;
122 
123     @GuardedBy("mLock")
124     private boolean mDisableAppActivityCheck = false;
125 
126     @GuardedBy("mLock")
127     private boolean mDisableSubsystemsCheck = false;
128 
129     @GuardedBy("mLock")
130     private long mAlarmClockThresholdMs = DEFAULT_ALARM_CLOCK_THRESHOLD_MS;
131 
132     @GuardedBy("mLock")
133     private long mLoggingBlockingEntityThresholdMs = DEFAULT_LOGGING_BLOCKING_ENTITY_THRESHOLD_MS;
134 
135     // A mapping of uid to package name for uids which have called markRebootPending. Reboot
136     // readiness state changed broadcasts will only be sent to the values in this map.
137     @GuardedBy("mLock")
138     private final SparseArray<ArraySet<String>> mCallingUidToPackageMap = new SparseArray<>();
139 
140     // When true, reboot readiness checks should not be performed.
141     @GuardedBy("mLock")
142     private boolean mCanceled = false;
143 
144     // The last time the device stopped being in an interactive state, in relation to the time
145     // since the system booted. If the device is currently interactive, this will be MAX_VALUE.
146     @GuardedBy("mLock")
147     private long mLastTimeNotInteractiveMs = Long.MAX_VALUE;
148 
149 
150     // Metadata to be stored for use in metrics.
151     @GuardedBy("mLock")
152     @CurrentTimeMillisLong
153     private long mPollingStartTimeMs;
154 
155     @GuardedBy("mLock")
156     private int mTimesBlockedByInteractivity;
157 
158     @GuardedBy("mLock")
159     private int mTimesBlockedBySubsystems;
160 
161     @GuardedBy("mLock")
162     private int mTimesBlockedByAppActivity;
163 
164     @GuardedBy("mLock")
165     private boolean mBlockedByTethering = false;
166 
167     private final TetheringEventCallback mTetheringEventCallback = new TetheringEventCallback() {
168         @Override
169         public void onClientsChanged(Collection<TetheredClient> clients) {
170             synchronized (mLock) {
171                 mBlockedByTethering = clients.size() > 0;
172             }
173         }
174     };
175 
176     private final BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
177         @Override
178         public void onReceive(Context context, Intent intent) {
179             handleUserPresent();
180         }
181     };
182 
183     private final AlarmManager.OnAlarmListener mPollStateListener = () -> {
184         synchronized (mLock) {
185             if (!mCanceled) {
186                 pollRebootReadinessState();
187             } else {
188                 Log.w(TAG, "Received poll state callback while canceled.");
189             }
190         }
191     };
192 
RebootReadinessManagerService(Context context)193     RebootReadinessManagerService(Context context) {
194         this(context, new RebootReadinessLogger(context));
195     }
196 
197     @VisibleForTesting
RebootReadinessManagerService(Context context, RebootReadinessLogger logger)198     RebootReadinessManagerService(Context context, RebootReadinessLogger logger) {
199         // TODO(b/161353402): Consolidate mHandler and mExecutor
200         mHandler = new Handler(Looper.getMainLooper());
201         mExecutor = new HandlerExecutor(mHandler);
202         mRebootReadinessLogger = logger;
203         updateConfigs();
204         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_REBOOT_READINESS,
205                 mExecutor, properties -> updateConfigs());
206         BroadcastReceiver interactivityChangedReceiver = new BroadcastReceiver() {
207             @Override
208             public void onReceive(Context context, Intent intent) {
209                 String action = intent.getAction();
210                 if (action.equals(Intent.ACTION_SCREEN_ON)) {
211                     noteInteractivityStateChanged(true);
212                 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
213                     noteInteractivityStateChanged(false);
214                 }
215             }
216         };
217         IntentFilter interactivityFilter = new IntentFilter();
218         interactivityFilter.addAction(Intent.ACTION_SCREEN_ON);
219         interactivityFilter.addAction(Intent.ACTION_SCREEN_OFF);
220         context.registerReceiver(interactivityChangedReceiver, interactivityFilter);
221         PowerManager powerManager = context.getSystemService(PowerManager.class);
222         if (powerManager != null) {
223             noteInteractivityStateChanged(powerManager.isInteractive());
224         }
225 
226         IntentFilter userPresentFilter = new IntentFilter();
227         userPresentFilter.addAction(Intent.ACTION_USER_PRESENT);
228         context.registerReceiver(mUserPresentReceiver, userPresentFilter);
229         mActivityManager = context.getSystemService(ActivityManager.class);
230         mAlarmManager = context.getSystemService(AlarmManager.class);
231         TetheringManager mTetheringManager = context.getSystemService(TetheringManager.class);
232         if (mTetheringManager != null) {
233             mTetheringManager.registerTetheringEventCallback(mExecutor, mTetheringEventCallback);
234         }
235         mHandler.post(mRebootReadinessLogger::readMetricsPostReboot);
236         mContext = context;
237     }
238 
239     @Override
handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out, ParcelFileDescriptor err, String[] args)240     public int handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out,
241             ParcelFileDescriptor err, String[] args) {
242         return new RebootReadinessShellCommand(this, mContext).exec(this, in.getFileDescriptor(),
243                 out.getFileDescriptor(), err.getFileDescriptor(), args);
244     }
245 
246     /**
247      * Lifecycle class for RebootReadinessManagerService.
248      */
249     public static class Lifecycle extends SystemService {
250 
Lifecycle(Context context)251         public Lifecycle(Context context) {
252             super(context);
253         }
254 
255         @Override
onStart()256         public void onStart() {
257             RebootReadinessManagerService rebootReadinessManagerService =
258                     new RebootReadinessManagerService(getContext());
259             publishBinderService(Context.REBOOT_READINESS_SERVICE, rebootReadinessManagerService);
260         }
261     }
262 
263     @Override
markRebootPending(String callingPackage)264     public void markRebootPending(String callingPackage) {
265         mContext.enforceCallingPermission(Manifest.permission.REBOOT,
266                 "Caller does not have REBOOT permission.");
267         synchronized (mLock) {
268             Log.i(TAG, "Starting reboot readiness checks for package: " + callingPackage);
269             // If there are existing clients waiting for a broadcast, reboot readiness checks
270             // are already ongoing.
271             if (mCallingUidToPackageMap.size() == 0) {
272                 mCanceled = false;
273                 resetMetrics();
274                 mHandler.removeCallbacksAndMessages(null);
275                 mHandler.post(this::pollRebootReadinessState);
276             } else {
277                 sendRebootReadyBroadcast(callingPackage,
278                         Binder.getCallingUserHandle(), mReadyToReboot);
279             }
280             ArraySet<String> packagesForUid =
281                     mCallingUidToPackageMap.get(Binder.getCallingUid(), new ArraySet<>());
282             packagesForUid.add(callingPackage);
283             mCallingUidToPackageMap.put(Binder.getCallingUid(), packagesForUid);
284         }
285     }
286 
287     @Override
cancelPendingReboot(String callingPackage)288     public void cancelPendingReboot(String callingPackage) {
289         mContext.enforceCallingPermission(Manifest.permission.REBOOT,
290                 "Caller does not have REBOOT permission");
291         final int callingUid = Binder.getCallingUid();
292         synchronized (mLock) {
293             ArraySet<String> packagesForUid =
294                     mCallingUidToPackageMap.get(callingUid, new ArraySet<>());
295             if (packagesForUid.contains(callingPackage)) {
296                 Log.i(TAG, "Canceling reboot readiness checks for package: " + callingPackage);
297                 packagesForUid.remove(callingPackage);
298                 if (packagesForUid.size() == 0) {
299                     // No remaining clients exist for this calling uid
300                     mCallingUidToPackageMap.remove(callingUid);
301                 }
302 
303                 // Only cancel readiness checks if there are no more uids with packages
304                 // waiting for broadcasts
305                 if (mCallingUidToPackageMap.size() == 0) {
306                     mHandler.removeCallbacksAndMessages(null);
307                     mAlarmManager.cancel(mPollStateListener);
308                     mCanceled = true;
309                     // Delete any logging information if the device is ready to reboot, since an
310                     // unattended reboot should not take place if the checks are cancelled.
311                     if (mReadyToReboot) {
312                         mRebootReadinessLogger.deleteLoggingInformation();
313                     }
314                     mReadyToReboot = false;
315                 }
316             } else {
317                 Log.w(TAG, "Package " + callingPackage + " tried to cancel reboot readiness"
318                         + " checks but was not a client of this service.");
319             }
320         }
321     }
322 
323     @Override
isReadyToReboot()324     public boolean isReadyToReboot() {
325         mContext.enforceCallingPermission(Manifest.permission.REBOOT,
326                 "Caller does not have REBOOT permission.");
327         synchronized (mLock) {
328             return mReadyToReboot;
329         }
330     }
331 
332     @Override
addRequestRebootReadinessStatusListener( IRequestRebootReadinessStatusListener callback)333     public void addRequestRebootReadinessStatusListener(
334             IRequestRebootReadinessStatusListener callback) {
335         mContext.enforceCallingPermission(Manifest.permission.SIGNAL_REBOOT_READINESS,
336                 "Caller does not have SIGNAL_REBOOT_READINESS permission.");
337         mCallbacks.register(callback);
338         try {
339             callback.asBinder().linkToDeath(
340                     () -> removeRequestRebootReadinessStatusListener(callback), 0);
341         } catch (RemoteException e) {
342             removeRequestRebootReadinessStatusListener(callback);
343         }
344     }
345 
346     @Override
removeRequestRebootReadinessStatusListener( IRequestRebootReadinessStatusListener callback)347     public void removeRequestRebootReadinessStatusListener(
348             IRequestRebootReadinessStatusListener callback) {
349         mContext.enforceCallingPermission(Manifest.permission.SIGNAL_REBOOT_READINESS,
350                 "Caller does not have SIGNAL_REBOOT_READINESS permission.");
351         mCallbacks.unregister(callback);
352     }
353 
pollRebootReadinessState()354     private void pollRebootReadinessState() {
355         synchronized (mLock) {
356             final boolean previousRebootReadiness = mReadyToReboot;
357             final boolean currentRebootReadiness = getRebootReadinessLocked();
358             if (previousRebootReadiness != currentRebootReadiness) {
359                 noteRebootReadinessStateChanged(currentRebootReadiness);
360             }
361             if (!mCanceled && !currentRebootReadiness) {
362                 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP,
363                         System.currentTimeMillis()
364                                 + mActivePollingIntervalMs,
365                         "poll_reboot_readiness", mPollStateListener, mHandler);
366             }
367         }
368     }
369 
370     @GuardedBy("mLock")
getRebootReadinessLocked()371     private boolean getRebootReadinessLocked() {
372         if (!(mDisableInteractivityCheck || checkDeviceInteractivity())) {
373             mTimesBlockedByInteractivity++;
374             Log.v(TAG, "Reboot blocked by device interactivity");
375             return false;
376         }
377 
378         if (!checkSystemComponentsState()) {
379             mTimesBlockedBySubsystems++;
380             return false;
381         }
382 
383         if (!(mDisableAppActivityCheck || checkBackgroundAppActivity())) {
384             mTimesBlockedByAppActivity++;
385             return false;
386         }
387 
388         return true;
389     }
390 
391     @VisibleForTesting
392     @GuardedBy("mLock")
checkSystemComponentsState()393     boolean checkSystemComponentsState() {
394         if (!mDisableSubsystemsCheck) {
395             if (mBlockedByTethering) {
396                 return false;
397             }
398 
399             AlarmManager.AlarmClockInfo alarmClockInfo = mAlarmManager.getNextAlarmClock();
400             final long now = System.currentTimeMillis();
401             if (alarmClockInfo != null
402                     && (alarmClockInfo.getTriggerTime() - now) < mAlarmClockThresholdMs) {
403                 return false;
404             }
405         }
406 
407         final List<IRequestRebootReadinessStatusListener> blockingCallbacks = new ArrayList<>();
408         final List<String> blockingCallbackNames = new ArrayList<>();
409         int i = mCallbacks.beginBroadcast();
410         CountDownLatch latch = new CountDownLatch(i);
411         while (i > 0) {
412             i--;
413             final IRequestRebootReadinessStatusListener callback = mCallbacks.getBroadcastItem(i);
414             try {
415                 RemoteCallback remoteCallback = new RemoteCallback(
416                         result -> {
417                             boolean isReadyToReboot = result.getBoolean(
418                                     RebootReadinessManager.IS_REBOOT_READY_KEY);
419                             String name = result.getString(
420                                     RebootReadinessManager.SUBSYSTEM_NAME_KEY);
421                             if (!isReadyToReboot && (!mDisableSubsystemsCheck
422                                     || name.startsWith(TEST_CALLBACK_PREFIX))) {
423                                 blockingCallbacks.add(callback);
424                                 blockingCallbackNames.add(name);
425                             }
426                             latch.countDown();
427                         }
428                 );
429                 callback.onRequestRebootReadinessStatus(remoteCallback);
430             } catch (RemoteException e) {
431                 Log.e(TAG, "Could not resolve state of RebootReadinessCallback: " + e);
432                 return false;
433             }
434         }
435         try {
436             latch.await(1, TimeUnit.MINUTES);
437         } catch (InterruptedException ignore) {
438         }
439         mCallbacks.finishBroadcast();
440         mRebootReadinessLogger.maybeLogLongBlockingComponents(blockingCallbackNames,
441                 mLoggingBlockingEntityThresholdMs);
442         if (blockingCallbacks.size() > 0) {
443             Log.v(TAG, "Reboot blocked by subsystems: " + String.join(",", blockingCallbackNames));
444             return false;
445         }
446         return true;
447     }
448 
449     @VisibleForTesting
checkDeviceInteractivity()450     boolean checkDeviceInteractivity() {
451         final long now = SystemClock.elapsedRealtime();
452         synchronized (mLock) {
453             return (now - mLastTimeNotInteractiveMs) > mInteractivityThresholdMs;
454         }
455     }
456 
457     /**
458      * Check for important app activity in the background by querying the running services on the
459      * device.
460      */
461     @VisibleForTesting
checkBackgroundAppActivity()462     boolean checkBackgroundAppActivity() {
463         if (mActivityManager != null) {
464             final List<RunningServiceInfo> serviceInfos =
465                     mActivityManager.getRunningServices(Integer.MAX_VALUE);
466             List<Integer> blockingUids = new ArrayList<>();
467             for (int i = 0; i < serviceInfos.size(); i++) {
468                 RunningServiceInfo info = serviceInfos.get(i);
469                 if (info.foreground) {
470                     blockingUids.add(info.uid);
471                 }
472             }
473             mRebootReadinessLogger.maybeLogLongBlockingApps(blockingUids,
474                     mLoggingBlockingEntityThresholdMs);
475             if (blockingUids.size() > 0) {
476                 Log.v(TAG, "Reboot blocked by app uids: " + blockingUids.toString());
477                 return false;
478             }
479             return true;
480         }
481         return false;
482     }
483 
noteRebootReadinessStateChanged(boolean isReadyToReboot)484     private void noteRebootReadinessStateChanged(boolean isReadyToReboot) {
485         synchronized (mLock) {
486             Log.i(TAG, "Reboot readiness state changed to " + isReadyToReboot);
487             mReadyToReboot = isReadyToReboot;
488 
489             // Send state change broadcast to any packages which have a pending update
490             for (int i = 0; i < mCallingUidToPackageMap.size(); i++) {
491                 UserHandle user = UserHandle.getUserHandleForUid(mCallingUidToPackageMap.keyAt(i));
492                 ArraySet<String> packageNames = mCallingUidToPackageMap.valueAt(i);
493                 for (int j = 0; j < packageNames.size(); j++) {
494                     sendRebootReadyBroadcast(packageNames.valueAt(j), user, isReadyToReboot);
495                 }
496             }
497             if (mReadyToReboot) {
498                 mRebootReadinessLogger.writeAfterRebootReadyBroadcast(
499                         mPollingStartTimeMs, System.currentTimeMillis(),
500                         mTimesBlockedByInteractivity, mTimesBlockedBySubsystems,
501                         mTimesBlockedByAppActivity);
502 
503                 AlarmManager.AlarmClockInfo alarmClockInfo = mAlarmManager.getNextAlarmClock();
504                 if (alarmClockInfo != null) {
505                     // Schedule a state check before the next alarm clock is triggered. This check
506                     // is triggered within the alarm clock threshold window (plus a small tolerance)
507                     // to ensure that this alarm clock will block the reboot at that time.
508                     long stateCheckTriggerTime = alarmClockInfo.getTriggerTime()
509                             - (mAlarmClockThresholdMs - TimeUnit.SECONDS.toMillis(1));
510                     if (stateCheckTriggerTime > System.currentTimeMillis()) {
511                         mAlarmManager.setExact(AlarmManager.RTC_WAKEUP,
512                                 stateCheckTriggerTime, "poll_reboot_readiness",
513                                 mPollStateListener, mHandler);
514                     }
515                 }
516             } else {
517                 mRebootReadinessLogger.writeAfterNotRebootReadyBroadcast();
518             }
519         }
520     }
521 
522     @GuardedBy("mLock")
sendRebootReadyBroadcast(String packageName, UserHandle user, boolean isReadyToReboot)523     private void sendRebootReadyBroadcast(String packageName, UserHandle user,
524             boolean isReadyToReboot) {
525         Log.i(TAG, "Sending REBOOT_READY broadcast to package " + packageName
526                 + " for user " + user.getIdentifier());
527         Intent intent = new Intent(RebootReadinessManager.ACTION_REBOOT_READY);
528         intent.putExtra(RebootReadinessManager.EXTRA_IS_READY_TO_REBOOT, isReadyToReboot);
529         intent.setPackage(packageName);
530         mContext.sendBroadcastAsUser(intent, user, Manifest.permission.REBOOT);
531     }
532 
updateConfigs()533     private void updateConfigs() {
534         synchronized (mLock) {
535             mActivePollingIntervalMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_REBOOT_READINESS,
536                     PROPERTY_ACTIVE_POLLING_INTERVAL_MS, DEFAULT_POLLING_INTERVAL_WHILE_ACTIVE_MS);
537             mInteractivityThresholdMs = DeviceConfig.getLong(
538                     DeviceConfig.NAMESPACE_REBOOT_READINESS, PROPERTY_INTERACTIVITY_THRESHOLD_MS,
539                     DEFAULT_INTERACTIVITY_THRESHOLD_MS);
540             mDisableInteractivityCheck = DeviceConfig.getBoolean(
541                     DeviceConfig.NAMESPACE_REBOOT_READINESS,
542                     PROPERTY_DISABLE_INTERACTIVITY_CHECK, false);
543             mDisableAppActivityCheck = DeviceConfig.getBoolean(
544                     DeviceConfig.NAMESPACE_REBOOT_READINESS,
545                     PROPERTY_DISABLE_APP_ACTIVITY_CHECK, false);
546             mDisableSubsystemsCheck = DeviceConfig.getBoolean(
547                     DeviceConfig.NAMESPACE_REBOOT_READINESS,
548                     PROPERTY_DISABLE_SUBSYSTEMS_CHECK, false);
549             mAlarmClockThresholdMs = DeviceConfig.getLong(
550                     DeviceConfig.NAMESPACE_REBOOT_READINESS,
551                     PROPERTY_ALARM_CLOCK_THRESHOLD_MS, DEFAULT_ALARM_CLOCK_THRESHOLD_MS);
552             mLoggingBlockingEntityThresholdMs = DeviceConfig.getLong(
553                     DeviceConfig.NAMESPACE_REBOOT_READINESS,
554                     PROPERTY_LOGGING_BLOCKING_ENTITY_THRESHOLD_MS,
555                     DEFAULT_LOGGING_BLOCKING_ENTITY_THRESHOLD_MS);
556         }
557     }
558 
noteInteractivityStateChanged(boolean isInteractive)559     private void noteInteractivityStateChanged(boolean isInteractive) {
560         synchronized (mLock) {
561             if (isInteractive) {
562                 mLastTimeNotInteractiveMs = Long.MAX_VALUE;
563                 if (!mCanceled && mReadyToReboot) {
564                     Log.i(TAG, "Device became interactive while reboot-ready");
565                     pollRebootReadinessState();
566                 }
567             } else {
568                 mLastTimeNotInteractiveMs = SystemClock.elapsedRealtime();
569             }
570         }
571     }
572 
handleUserPresent()573     private void handleUserPresent() {
574         mContext.unregisterReceiver(mUserPresentReceiver);
575         mRebootReadinessLogger.writePostRebootMetrics();
576     }
577 
578     @GuardedBy("mLock")
resetMetrics()579     private void resetMetrics() {
580         mPollingStartTimeMs = System.currentTimeMillis();
581         mTimesBlockedByInteractivity = 0;
582         mTimesBlockedBySubsystems = 0;
583         mTimesBlockedByAppActivity = 0;
584     }
585 
586     @VisibleForTesting
getCallingPackages()587     SparseArray<ArraySet<String>> getCallingPackages() {
588         synchronized (mLock) {
589             return mCallingUidToPackageMap;
590         }
591     }
592 
593     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)594     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
595         if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
596                 != PackageManager.PERMISSION_GRANTED) {
597             return;
598         }
599 
600         synchronized (mLock) {
601             mRebootReadinessLogger.dump(pw);
602             if (mCallingUidToPackageMap.size() > 0) {
603                 pw.print("Packages awaiting REBOOT_READY broadcast:");
604                 for (int i = 0; i < mCallingUidToPackageMap.size(); i++) {
605                     ArraySet<String> packageNames = mCallingUidToPackageMap.valueAt(i);
606                     for (int j = 0; j < packageNames.size(); j++) {
607                         pw.print(" " + packageNames.valueAt(j));
608                     }
609                 }
610                 pw.println();
611                 pw.println("Current reboot readiness state: " + mReadyToReboot);
612             }
613         }
614     }
615 
616     /** Writes information about any UIDs which are blocking the reboot. */
writeBlockingUids(PrintWriter pw)617     void writeBlockingUids(PrintWriter pw) {
618         mRebootReadinessLogger.writeBlockingUids(pw);
619     }
620 
621     /** Writes information about any subsystems which are blocking the reboot. */
writeBlockingSubsystems(PrintWriter pw)622     void writeBlockingSubsystems(PrintWriter pw) {
623         mRebootReadinessLogger.writeBlockingSubsystems(pw);
624     }
625 }
626