• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.power;
18 
19 import android.app.ActivityManagerInternal;
20 import android.app.AppOpsManager;
21 import android.app.RetailDemoModeServiceInternal;
22 
23 import com.android.internal.app.IAppOpsService;
24 import com.android.internal.app.IBatteryStats;
25 import com.android.server.EventLogTags;
26 import com.android.server.LocalServices;
27 
28 import android.app.ActivityManagerNative;
29 import android.content.BroadcastReceiver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.hardware.input.InputManagerInternal;
33 import android.media.AudioManager;
34 import android.media.Ringtone;
35 import android.media.RingtoneManager;
36 import android.net.Uri;
37 import android.os.BatteryStats;
38 import android.os.Handler;
39 import android.os.Looper;
40 import android.os.Message;
41 import android.os.PowerManager;
42 import android.os.PowerManagerInternal;
43 import android.os.Process;
44 import android.os.RemoteException;
45 import android.os.SystemClock;
46 import android.os.UserHandle;
47 import android.os.WorkSource;
48 import android.provider.Settings;
49 import android.util.EventLog;
50 import android.util.Slog;
51 import android.view.WindowManagerPolicy;
52 import android.view.inputmethod.InputMethodManagerInternal;
53 
54 /**
55  * Sends broadcasts about important power state changes.
56  * <p>
57  * This methods of this class may be called by the power manager service while
58  * its lock is being held.  Internally it takes care of sending broadcasts to
59  * notify other components of the system or applications asynchronously.
60  * </p><p>
61  * The notifier is designed to collapse unnecessary broadcasts when it is not
62  * possible for the system to have observed an intermediate state.
63  * </p><p>
64  * For example, if the device wakes up, goes to sleep, wakes up again and goes to
65  * sleep again before the wake up notification is sent, then the system will
66  * be told about only one wake up and sleep.  However, we always notify the
67  * fact that at least one transition occurred.  It is especially important to
68  * tell the system when we go to sleep so that it can lock the keyguard if needed.
69  * </p>
70  */
71 final class Notifier {
72     private static final String TAG = "PowerManagerNotifier";
73 
74     private static final boolean DEBUG = false;
75 
76     private static final int INTERACTIVE_STATE_UNKNOWN = 0;
77     private static final int INTERACTIVE_STATE_AWAKE = 1;
78     private static final int INTERACTIVE_STATE_ASLEEP = 2;
79 
80     private static final int MSG_USER_ACTIVITY = 1;
81     private static final int MSG_BROADCAST = 2;
82     private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
83     private static final int MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED = 4;
84 
85     private final Object mLock = new Object();
86 
87     private final Context mContext;
88     private final IBatteryStats mBatteryStats;
89     private final IAppOpsService mAppOps;
90     private final SuspendBlocker mSuspendBlocker;
91     private final WindowManagerPolicy mPolicy;
92     private final ActivityManagerInternal mActivityManagerInternal;
93     private final InputManagerInternal mInputManagerInternal;
94     private final InputMethodManagerInternal mInputMethodManagerInternal;
95     private final RetailDemoModeServiceInternal mRetailDemoModeServiceInternal;
96 
97     private final NotifierHandler mHandler;
98     private final Intent mScreenOnIntent;
99     private final Intent mScreenOffIntent;
100     private final Intent mScreenBrightnessBoostIntent;
101 
102     // True if the device should suspend when the screen is off due to proximity.
103     private final boolean mSuspendWhenScreenOffDueToProximityConfig;
104 
105     // The current interactive state.  This is set as soon as an interactive state
106     // transition begins so as to capture the reason that it happened.  At some point
107     // this state will propagate to the pending state then eventually to the
108     // broadcasted state over the course of reporting the transition asynchronously.
109     private boolean mInteractive = true;
110     private int mInteractiveChangeReason;
111     private boolean mInteractiveChanging;
112 
113     // The pending interactive state that we will eventually want to broadcast.
114     // This is designed so that we can collapse redundant sequences of awake/sleep
115     // transition pairs while still guaranteeing that at least one transition is observed
116     // whenever this happens.
117     private int mPendingInteractiveState;
118     private boolean mPendingWakeUpBroadcast;
119     private boolean mPendingGoToSleepBroadcast;
120 
121     // The currently broadcasted interactive state.  This reflects what other parts of the
122     // system have observed.
123     private int mBroadcastedInteractiveState;
124     private boolean mBroadcastInProgress;
125     private long mBroadcastStartTime;
126 
127     // True if a user activity message should be sent.
128     private boolean mUserActivityPending;
129 
Notifier(Looper looper, Context context, IBatteryStats batteryStats, IAppOpsService appOps, SuspendBlocker suspendBlocker, WindowManagerPolicy policy)130     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
131             IAppOpsService appOps, SuspendBlocker suspendBlocker,
132             WindowManagerPolicy policy) {
133         mContext = context;
134         mBatteryStats = batteryStats;
135         mAppOps = appOps;
136         mSuspendBlocker = suspendBlocker;
137         mPolicy = policy;
138         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
139         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
140         mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
141         mRetailDemoModeServiceInternal = LocalServices.getService(RetailDemoModeServiceInternal.class);
142 
143         mHandler = new NotifierHandler(looper);
144         mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
145         mScreenOnIntent.addFlags(
146                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
147         mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
148         mScreenOffIntent.addFlags(
149                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
150         mScreenBrightnessBoostIntent =
151                 new Intent(PowerManager.ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED);
152         mScreenBrightnessBoostIntent.addFlags(
153                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
154 
155         mSuspendWhenScreenOffDueToProximityConfig = context.getResources().getBoolean(
156                 com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity);
157 
158         // Initialize interactive state for battery stats.
159         try {
160             mBatteryStats.noteInteractive(true);
161         } catch (RemoteException ex) { }
162     }
163 
164     /**
165      * Called when a wake lock is acquired.
166      */
onWakeLockAcquired(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag)167     public void onWakeLockAcquired(int flags, String tag, String packageName,
168             int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
169         if (DEBUG) {
170             Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
171                     + "\", packageName=" + packageName
172                     + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
173                     + ", workSource=" + workSource);
174         }
175 
176         final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
177         if (monitorType >= 0) {
178             try {
179                 final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
180                         && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
181                 if (workSource != null) {
182                     mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
183                             historyTag, monitorType, unimportantForLogging);
184                 } else {
185                     mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
186                             monitorType, unimportantForLogging);
187                     // XXX need to deal with disabled operations.
188                     mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
189                             AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
190                 }
191             } catch (RemoteException ex) {
192                 // Ignore
193             }
194         }
195     }
196 
onLongPartialWakeLockStart(String tag, int ownerUid, WorkSource workSource, String historyTag)197     public void onLongPartialWakeLockStart(String tag, int ownerUid, WorkSource workSource,
198             String historyTag) {
199         if (DEBUG) {
200             Slog.d(TAG, "onLongPartialWakeLockStart: ownerUid=" + ownerUid
201                     + ", workSource=" + workSource);
202         }
203 
204         try {
205             if (workSource != null) {
206                 final int N = workSource.size();
207                 for (int i=0; i<N; i++) {
208                     mBatteryStats.noteLongPartialWakelockStart(tag, historyTag, workSource.get(i));
209                 }
210             } else {
211                 mBatteryStats.noteLongPartialWakelockStart(tag, historyTag, ownerUid);
212             }
213         } catch (RemoteException ex) {
214             // Ignore
215         }
216     }
217 
onLongPartialWakeLockFinish(String tag, int ownerUid, WorkSource workSource, String historyTag)218     public void onLongPartialWakeLockFinish(String tag, int ownerUid, WorkSource workSource,
219             String historyTag) {
220         if (DEBUG) {
221             Slog.d(TAG, "onLongPartialWakeLockFinish: ownerUid=" + ownerUid
222                     + ", workSource=" + workSource);
223         }
224 
225         try {
226             if (workSource != null) {
227                 final int N = workSource.size();
228                 for (int i=0; i<N; i++) {
229                     mBatteryStats.noteLongPartialWakelockFinish(tag, historyTag, workSource.get(i));
230                 }
231             } else {
232                 mBatteryStats.noteLongPartialWakelockFinish(tag, historyTag, ownerUid);
233             }
234         } catch (RemoteException ex) {
235             // Ignore
236         }
237     }
238 
239     /**
240      * Called when a wake lock is changing.
241      */
onWakeLockChanging(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag, int newFlags, String newTag, String newPackageName, int newOwnerUid, int newOwnerPid, WorkSource newWorkSource, String newHistoryTag)242     public void onWakeLockChanging(int flags, String tag, String packageName,
243             int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
244             int newFlags, String newTag, String newPackageName, int newOwnerUid,
245             int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) {
246 
247         final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
248         final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags);
249         if (workSource != null && newWorkSource != null
250                 && monitorType >= 0 && newMonitorType >= 0) {
251             if (DEBUG) {
252                 Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag
253                         + "\", packageName=" + newPackageName
254                         + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid
255                         + ", workSource=" + newWorkSource);
256             }
257 
258             final boolean unimportantForLogging = newOwnerUid == Process.SYSTEM_UID
259                     && (newFlags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
260             try {
261                 mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag,
262                         monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag,
263                         newMonitorType, unimportantForLogging);
264             } catch (RemoteException ex) {
265                 // Ignore
266             }
267         } else {
268             onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag);
269             onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid,
270                     newWorkSource, newHistoryTag);
271         }
272     }
273 
274     /**
275      * Called when a wake lock is released.
276      */
onWakeLockReleased(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag)277     public void onWakeLockReleased(int flags, String tag, String packageName,
278             int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
279         if (DEBUG) {
280             Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
281                     + "\", packageName=" + packageName
282                     + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
283                     + ", workSource=" + workSource);
284         }
285 
286         final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
287         if (monitorType >= 0) {
288             try {
289                 if (workSource != null) {
290                     mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
291                             historyTag, monitorType);
292                 } else {
293                     mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
294                             historyTag, monitorType);
295                     mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
296                             AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
297                 }
298             } catch (RemoteException ex) {
299                 // Ignore
300             }
301         }
302     }
303 
getBatteryStatsWakeLockMonitorType(int flags)304     private int getBatteryStatsWakeLockMonitorType(int flags) {
305         switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
306             case PowerManager.PARTIAL_WAKE_LOCK:
307                 return BatteryStats.WAKE_TYPE_PARTIAL;
308 
309             case PowerManager.SCREEN_DIM_WAKE_LOCK:
310             case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
311                 return BatteryStats.WAKE_TYPE_FULL;
312 
313             case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
314                 if (mSuspendWhenScreenOffDueToProximityConfig) {
315                     return -1;
316                 }
317                 return BatteryStats.WAKE_TYPE_PARTIAL;
318 
319             case PowerManager.DRAW_WAKE_LOCK:
320                 return BatteryStats.WAKE_TYPE_DRAW;
321 
322             case PowerManager.DOZE_WAKE_LOCK:
323                 // Doze wake locks are an internal implementation detail of the
324                 // communication between dream manager service and power manager
325                 // service.  They have no additive battery impact.
326                 return -1;
327 
328             default:
329                 return -1;
330         }
331     }
332 
333     /**
334      * Notifies that the device is changing wakefulness.
335      * This function may be called even if the previous change hasn't finished in
336      * which case it will assume that the state did not fully converge before the
337      * next transition began and will recover accordingly.
338      */
onWakefulnessChangeStarted(final int wakefulness, int reason)339     public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
340         final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
341         if (DEBUG) {
342             Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
343                     + ", reason=" + reason + ", interactive=" + interactive);
344         }
345 
346         // Tell the activity manager about changes in wakefulness, not just interactivity.
347         // It needs more granularity than other components.
348         mHandler.post(new Runnable() {
349             @Override
350             public void run() {
351                 mActivityManagerInternal.onWakefulnessChanged(wakefulness);
352             }
353         });
354 
355         // Handle any early interactive state changes.
356         // Finish pending incomplete ones from a previous cycle.
357         if (mInteractive != interactive) {
358             // Finish up late behaviors if needed.
359             if (mInteractiveChanging) {
360                 handleLateInteractiveChange();
361             }
362 
363             // Start input as soon as we start waking up or going to sleep.
364             mInputManagerInternal.setInteractive(interactive);
365             mInputMethodManagerInternal.setInteractive(interactive);
366 
367             // Notify battery stats.
368             try {
369                 mBatteryStats.noteInteractive(interactive);
370             } catch (RemoteException ex) { }
371 
372             // Handle early behaviors.
373             mInteractive = interactive;
374             mInteractiveChangeReason = reason;
375             mInteractiveChanging = true;
376             handleEarlyInteractiveChange();
377         }
378     }
379 
380     /**
381      * Notifies that the device has finished changing wakefulness.
382      */
onWakefulnessChangeFinished()383     public void onWakefulnessChangeFinished() {
384         if (DEBUG) {
385             Slog.d(TAG, "onWakefulnessChangeFinished");
386         }
387 
388         if (mInteractiveChanging) {
389             mInteractiveChanging = false;
390             handleLateInteractiveChange();
391         }
392     }
393 
394     /**
395      * Handle early interactive state changes such as getting applications or the lock
396      * screen running and ready for the user to see (such as when turning on the screen).
397      */
handleEarlyInteractiveChange()398     private void handleEarlyInteractiveChange() {
399         synchronized (mLock) {
400             if (mInteractive) {
401                 // Waking up...
402                 mHandler.post(new Runnable() {
403                     @Override
404                     public void run() {
405                         EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
406                         mPolicy.startedWakingUp();
407                     }
408                 });
409 
410                 // Send interactive broadcast.
411                 mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
412                 mPendingWakeUpBroadcast = true;
413                 updatePendingBroadcastLocked();
414             } else {
415                 // Going to sleep...
416                 // Tell the policy that we started going to sleep.
417                 final int why = translateOffReason(mInteractiveChangeReason);
418                 mHandler.post(new Runnable() {
419                     @Override
420                     public void run() {
421                         mPolicy.startedGoingToSleep(why);
422                     }
423                 });
424             }
425         }
426     }
427 
428     /**
429      * Handle late interactive state changes once they are finished so that the system can
430      * finish pending transitions (such as turning the screen off) before causing
431      * applications to change state visibly.
432      */
handleLateInteractiveChange()433     private void handleLateInteractiveChange() {
434         synchronized (mLock) {
435             if (mInteractive) {
436                 // Finished waking up...
437                 mHandler.post(new Runnable() {
438                     @Override
439                     public void run() {
440                         mPolicy.finishedWakingUp();
441                     }
442                 });
443             } else {
444                 // Finished going to sleep...
445                 // This is a good time to make transitions that we don't want the user to see,
446                 // such as bringing the key guard to focus.  There's no guarantee for this
447                 // however because the user could turn the device on again at any time.
448                 // Some things may need to be protected by other mechanisms that defer screen on.
449 
450                 // Cancel pending user activity.
451                 if (mUserActivityPending) {
452                     mUserActivityPending = false;
453                     mHandler.removeMessages(MSG_USER_ACTIVITY);
454                 }
455 
456                 // Tell the policy we finished going to sleep.
457                 final int why = translateOffReason(mInteractiveChangeReason);
458                 mHandler.post(new Runnable() {
459                     @Override
460                     public void run() {
461                         EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
462                         mPolicy.finishedGoingToSleep(why);
463                     }
464                 });
465 
466                 // Send non-interactive broadcast.
467                 mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP;
468                 mPendingGoToSleepBroadcast = true;
469                 updatePendingBroadcastLocked();
470             }
471         }
472     }
473 
translateOffReason(int reason)474     private static int translateOffReason(int reason) {
475         switch (reason) {
476             case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
477                 return WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
478             case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
479                 return WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
480             default:
481                 return WindowManagerPolicy.OFF_BECAUSE_OF_USER;
482         }
483     }
484 
485     /**
486      * Called when screen brightness boost begins or ends.
487      */
onScreenBrightnessBoostChanged()488     public void onScreenBrightnessBoostChanged() {
489         if (DEBUG) {
490             Slog.d(TAG, "onScreenBrightnessBoostChanged");
491         }
492 
493         mSuspendBlocker.acquire();
494         Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED);
495         msg.setAsynchronous(true);
496         mHandler.sendMessage(msg);
497     }
498 
499     /**
500      * Called when there has been user activity.
501      */
onUserActivity(int event, int uid)502     public void onUserActivity(int event, int uid) {
503         if (DEBUG) {
504             Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
505         }
506 
507         try {
508             mBatteryStats.noteUserActivity(uid, event);
509         } catch (RemoteException ex) {
510             // Ignore
511         }
512 
513         synchronized (mLock) {
514             if (!mUserActivityPending) {
515                 mUserActivityPending = true;
516                 Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
517                 msg.setAsynchronous(true);
518                 mHandler.sendMessage(msg);
519             }
520         }
521     }
522 
523     /**
524      * Called when the screen has turned on.
525      */
onWakeUp(String reason, int reasonUid, String opPackageName, int opUid)526     public void onWakeUp(String reason, int reasonUid, String opPackageName, int opUid) {
527         if (DEBUG) {
528             Slog.d(TAG, "onWakeUp: event=" + reason + ", reasonUid=" + reasonUid
529                     + " opPackageName=" + opPackageName + " opUid=" + opUid);
530         }
531 
532         try {
533             mBatteryStats.noteWakeUp(reason, reasonUid);
534             if (opPackageName != null) {
535                 mAppOps.noteOperation(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName);
536             }
537         } catch (RemoteException ex) {
538             // Ignore
539         }
540 
541     }
542 
543     /**
544      * Called when wireless charging has started so as to provide user feedback.
545      */
onWirelessChargingStarted()546     public void onWirelessChargingStarted() {
547         if (DEBUG) {
548             Slog.d(TAG, "onWirelessChargingStarted");
549         }
550 
551         mSuspendBlocker.acquire();
552         Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
553         msg.setAsynchronous(true);
554         mHandler.sendMessage(msg);
555     }
556 
updatePendingBroadcastLocked()557     private void updatePendingBroadcastLocked() {
558         if (!mBroadcastInProgress
559                 && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
560                 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
561                         || mPendingInteractiveState != mBroadcastedInteractiveState)) {
562             mBroadcastInProgress = true;
563             mSuspendBlocker.acquire();
564             Message msg = mHandler.obtainMessage(MSG_BROADCAST);
565             msg.setAsynchronous(true);
566             mHandler.sendMessage(msg);
567         }
568     }
569 
finishPendingBroadcastLocked()570     private void finishPendingBroadcastLocked() {
571         mBroadcastInProgress = false;
572         mSuspendBlocker.release();
573     }
574 
sendUserActivity()575     private void sendUserActivity() {
576         synchronized (mLock) {
577             if (!mUserActivityPending) {
578                 return;
579             }
580             mUserActivityPending = false;
581         }
582         if (mRetailDemoModeServiceInternal != null) {
583             mRetailDemoModeServiceInternal.onUserActivity();
584         }
585         mPolicy.userActivity();
586     }
587 
sendNextBroadcast()588     private void sendNextBroadcast() {
589         final int powerState;
590         synchronized (mLock) {
591             if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
592                 // Broadcasted power state is unknown.  Send wake up.
593                 mPendingWakeUpBroadcast = false;
594                 mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
595             } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
596                 // Broadcasted power state is awake.  Send asleep if needed.
597                 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
598                         || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
599                     mPendingGoToSleepBroadcast = false;
600                     mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
601                 } else {
602                     finishPendingBroadcastLocked();
603                     return;
604                 }
605             } else {
606                 // Broadcasted power state is asleep.  Send awake if needed.
607                 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
608                         || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
609                     mPendingWakeUpBroadcast = false;
610                     mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
611                 } else {
612                     finishPendingBroadcastLocked();
613                     return;
614                 }
615             }
616 
617             mBroadcastStartTime = SystemClock.uptimeMillis();
618             powerState = mBroadcastedInteractiveState;
619         }
620 
621         EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
622 
623         if (powerState == INTERACTIVE_STATE_AWAKE) {
624             sendWakeUpBroadcast();
625         } else {
626             sendGoToSleepBroadcast();
627         }
628     }
629 
sendBrightnessBoostChangedBroadcast()630     private void sendBrightnessBoostChangedBroadcast() {
631         if (DEBUG) {
632             Slog.d(TAG, "Sending brightness boost changed broadcast.");
633         }
634 
635         mContext.sendOrderedBroadcastAsUser(mScreenBrightnessBoostIntent, UserHandle.ALL, null,
636                 mScreeBrightnessBoostChangedDone, mHandler, 0, null, null);
637     }
638 
639     private final BroadcastReceiver mScreeBrightnessBoostChangedDone = new BroadcastReceiver() {
640         @Override
641         public void onReceive(Context context, Intent intent) {
642             mSuspendBlocker.release();
643         }
644     };
645 
sendWakeUpBroadcast()646     private void sendWakeUpBroadcast() {
647         if (DEBUG) {
648             Slog.d(TAG, "Sending wake up broadcast.");
649         }
650 
651         if (ActivityManagerNative.isSystemReady()) {
652             mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
653                     mWakeUpBroadcastDone, mHandler, 0, null, null);
654         } else {
655             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
656             sendNextBroadcast();
657         }
658     }
659 
660     private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
661         @Override
662         public void onReceive(Context context, Intent intent) {
663             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
664                     SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
665             sendNextBroadcast();
666         }
667     };
668 
sendGoToSleepBroadcast()669     private void sendGoToSleepBroadcast() {
670         if (DEBUG) {
671             Slog.d(TAG, "Sending go to sleep broadcast.");
672         }
673 
674         if (ActivityManagerNative.isSystemReady()) {
675             mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
676                     mGoToSleepBroadcastDone, mHandler, 0, null, null);
677         } else {
678             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
679             sendNextBroadcast();
680         }
681     }
682 
683     private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
684         @Override
685         public void onReceive(Context context, Intent intent) {
686             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
687                     SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
688             sendNextBroadcast();
689         }
690     };
691 
playWirelessChargingStartedSound()692     private void playWirelessChargingStartedSound() {
693         final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
694                 Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0;
695         final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
696                 Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
697         if (enabled && soundPath != null) {
698             final Uri soundUri = Uri.parse("file://" + soundPath);
699             if (soundUri != null) {
700                 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
701                 if (sfx != null) {
702                     sfx.setStreamType(AudioManager.STREAM_SYSTEM);
703                     sfx.play();
704                 }
705             }
706         }
707 
708         mSuspendBlocker.release();
709     }
710 
711     private final class NotifierHandler extends Handler {
NotifierHandler(Looper looper)712         public NotifierHandler(Looper looper) {
713             super(looper, null, true /*async*/);
714         }
715 
716         @Override
handleMessage(Message msg)717         public void handleMessage(Message msg) {
718             switch (msg.what) {
719                 case MSG_USER_ACTIVITY:
720                     sendUserActivity();
721                     break;
722 
723                 case MSG_BROADCAST:
724                     sendNextBroadcast();
725                     break;
726 
727                 case MSG_WIRELESS_CHARGING_STARTED:
728                     playWirelessChargingStartedSound();
729                     break;
730                 case MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED:
731                     sendBrightnessBoostChangedBroadcast();
732                     break;
733             }
734         }
735     }
736 }
737