Home | History | Annotate | Download | only in power
      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 
     22 import com.android.internal.app.IAppOpsService;
     23 import com.android.internal.app.IBatteryStats;
     24 import com.android.server.EventLogTags;
     25 import com.android.server.LocalServices;
     26 
     27 import android.app.ActivityManagerNative;
     28 import android.content.BroadcastReceiver;
     29 import android.content.Context;
     30 import android.content.Intent;
     31 import android.hardware.input.InputManagerInternal;
     32 import android.media.AudioManager;
     33 import android.media.Ringtone;
     34 import android.media.RingtoneManager;
     35 import android.net.Uri;
     36 import android.os.BatteryStats;
     37 import android.os.Handler;
     38 import android.os.Looper;
     39 import android.os.Message;
     40 import android.os.PowerManager;
     41 import android.os.PowerManagerInternal;
     42 import android.os.Process;
     43 import android.os.RemoteException;
     44 import android.os.SystemClock;
     45 import android.os.UserHandle;
     46 import android.os.WorkSource;
     47 import android.provider.Settings;
     48 import android.util.EventLog;
     49 import android.util.Slog;
     50 import android.view.WindowManagerPolicy;
     51 
     52 /**
     53  * Sends broadcasts about important power state changes.
     54  * <p>
     55  * This methods of this class may be called by the power manager service while
     56  * its lock is being held.  Internally it takes care of sending broadcasts to
     57  * notify other components of the system or applications asynchronously.
     58  * </p><p>
     59  * The notifier is designed to collapse unnecessary broadcasts when it is not
     60  * possible for the system to have observed an intermediate state.
     61  * </p><p>
     62  * For example, if the device wakes up, goes to sleep, wakes up again and goes to
     63  * sleep again before the wake up notification is sent, then the system will
     64  * be told about only one wake up and sleep.  However, we always notify the
     65  * fact that at least one transition occurred.  It is especially important to
     66  * tell the system when we go to sleep so that it can lock the keyguard if needed.
     67  * </p>
     68  */
     69 final class Notifier {
     70     private static final String TAG = "PowerManagerNotifier";
     71 
     72     private static final boolean DEBUG = false;
     73 
     74     private static final int INTERACTIVE_STATE_UNKNOWN = 0;
     75     private static final int INTERACTIVE_STATE_AWAKE = 1;
     76     private static final int INTERACTIVE_STATE_ASLEEP = 2;
     77 
     78     private static final int MSG_USER_ACTIVITY = 1;
     79     private static final int MSG_BROADCAST = 2;
     80     private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
     81 
     82     private final Object mLock = new Object();
     83 
     84     private final Context mContext;
     85     private final IBatteryStats mBatteryStats;
     86     private final IAppOpsService mAppOps;
     87     private final SuspendBlocker mSuspendBlocker;
     88     private final WindowManagerPolicy mPolicy;
     89     private final ActivityManagerInternal mActivityManagerInternal;
     90     private final InputManagerInternal mInputManagerInternal;
     91 
     92     private final NotifierHandler mHandler;
     93     private final Intent mScreenOnIntent;
     94     private final Intent mScreenOffIntent;
     95 
     96     // The current interactive state.
     97     private int mActualInteractiveState;
     98     private int mLastReason;
     99 
    100     // True if there is a pending transition that needs to be reported.
    101     private boolean mPendingWakeUpBroadcast;
    102     private boolean mPendingGoToSleepBroadcast;
    103 
    104     // The currently broadcasted interactive state.  This reflects what other parts of the
    105     // system have observed.
    106     private int mBroadcastedInteractiveState;
    107     private boolean mBroadcastInProgress;
    108     private long mBroadcastStartTime;
    109 
    110     // True if a user activity message should be sent.
    111     private boolean mUserActivityPending;
    112 
    113     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
    114             IAppOpsService appOps, SuspendBlocker suspendBlocker,
    115             WindowManagerPolicy policy) {
    116         mContext = context;
    117         mBatteryStats = batteryStats;
    118         mAppOps = appOps;
    119         mSuspendBlocker = suspendBlocker;
    120         mPolicy = policy;
    121         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
    122         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
    123 
    124         mHandler = new NotifierHandler(looper);
    125         mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
    126         mScreenOnIntent.addFlags(
    127                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
    128         mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
    129         mScreenOffIntent.addFlags(
    130                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
    131 
    132         // Initialize interactive state for battery stats.
    133         try {
    134             mBatteryStats.noteInteractive(true);
    135         } catch (RemoteException ex) { }
    136     }
    137 
    138     /**
    139      * Called when a wake lock is acquired.
    140      */
    141     public void onWakeLockAcquired(int flags, String tag, String packageName,
    142             int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
    143         if (DEBUG) {
    144             Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
    145                     + "\", packageName=" + packageName
    146                     + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
    147                     + ", workSource=" + workSource);
    148         }
    149 
    150         try {
    151             final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
    152             boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
    153                     && ownerUid == Process.SYSTEM_UID;
    154             if (workSource != null) {
    155                 mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, historyTag,
    156                         monitorType, unimportantForLogging);
    157             } else {
    158                 mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
    159                         monitorType, unimportantForLogging);
    160                 // XXX need to deal with disabled operations.
    161                 mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
    162                         AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
    163             }
    164         } catch (RemoteException ex) {
    165             // Ignore
    166         }
    167     }
    168 
    169     /**
    170      * Called when a wake lock is changing.
    171      */
    172     public void onWakeLockChanging(int flags, String tag, String packageName,
    173             int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
    174             int newFlags, String newTag, String newPackageName, int newOwnerUid,
    175             int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) {
    176 
    177         if (workSource != null && newWorkSource != null) {
    178             final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
    179             final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags);
    180             boolean unimportantForLogging = (newFlags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
    181                     && newOwnerUid == Process.SYSTEM_UID;
    182             if (DEBUG) {
    183                 Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag
    184                         + "\", packageName=" + newPackageName
    185                         + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid
    186                         + ", workSource=" + newWorkSource);
    187             }
    188             try {
    189                 mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag,
    190                         monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag,
    191                         newMonitorType, unimportantForLogging);
    192             } catch (RemoteException ex) {
    193                 // Ignore
    194             }
    195         } else {
    196             onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag);
    197             onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid,
    198                     newWorkSource, newHistoryTag);
    199         }
    200     }
    201 
    202     /**
    203      * Called when a wake lock is released.
    204      */
    205     public void onWakeLockReleased(int flags, String tag, String packageName,
    206             int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
    207         if (DEBUG) {
    208             Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
    209                     + "\", packageName=" + packageName
    210                     + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
    211                     + ", workSource=" + workSource);
    212         }
    213 
    214         try {
    215             final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
    216             if (workSource != null) {
    217                 mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, historyTag,
    218                         monitorType);
    219             } else {
    220                 mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, historyTag, monitorType);
    221                 mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
    222                         AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
    223             }
    224         } catch (RemoteException ex) {
    225             // Ignore
    226         }
    227     }
    228 
    229     private static int getBatteryStatsWakeLockMonitorType(int flags) {
    230         switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
    231             case PowerManager.PARTIAL_WAKE_LOCK:
    232             case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
    233                 return BatteryStats.WAKE_TYPE_PARTIAL;
    234             default:
    235                 return BatteryStats.WAKE_TYPE_FULL;
    236         }
    237     }
    238 
    239     /**
    240      * Notifies that the device is changing wakefulness.
    241      */
    242     public void onWakefulnessChangeStarted(int wakefulness, int reason) {
    243         if (DEBUG) {
    244             Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
    245                     + ", reason=" + reason);
    246         }
    247 
    248         // We handle interactive state changes once they start so that the system can
    249         // set everything up or the user to begin interacting with applications.
    250         final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
    251         if (interactive) {
    252             handleWakefulnessChange(wakefulness, interactive, reason);
    253         } else {
    254             mLastReason = reason;
    255         }
    256 
    257         // Start input as soon as we start waking up or going to sleep.
    258         mInputManagerInternal.setInteractive(interactive);
    259     }
    260 
    261     /**
    262      * Notifies that the device has finished changing wakefulness.
    263      */
    264     public void onWakefulnessChangeFinished(int wakefulness) {
    265         if (DEBUG) {
    266             Slog.d(TAG, "onWakefulnessChangeFinished: wakefulness=" + wakefulness);
    267         }
    268 
    269         // Handle interactive state changes once they are finished so that the system can
    270         // finish pending transitions (such as turning the screen off) before causing
    271         // applications to change state visibly.
    272         final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
    273         if (!interactive) {
    274             handleWakefulnessChange(wakefulness, interactive, mLastReason);
    275         }
    276     }
    277 
    278     private void handleWakefulnessChange(final int wakefulness, boolean interactive,
    279             final int reason) {
    280         // Tell the activity manager about changes in wakefulness, not just interactivity.
    281         // It needs more granularity than other components.
    282         mHandler.post(new Runnable() {
    283             @Override
    284             public void run() {
    285                 mActivityManagerInternal.onWakefulnessChanged(wakefulness);
    286             }
    287         });
    288 
    289         // Handle changes in the overall interactive state.
    290         boolean interactiveChanged = false;
    291         synchronized (mLock) {
    292             // Broadcast interactive state changes.
    293             if (interactive) {
    294                 // Waking up...
    295                 interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_AWAKE);
    296                 if (interactiveChanged) {
    297                     mActualInteractiveState = INTERACTIVE_STATE_AWAKE;
    298                     mPendingWakeUpBroadcast = true;
    299                     mHandler.post(new Runnable() {
    300                         @Override
    301                         public void run() {
    302                             EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
    303                             mPolicy.wakingUp();
    304                         }
    305                     });
    306                     updatePendingBroadcastLocked();
    307                 }
    308             } else {
    309                 // Going to sleep...
    310                 // This is a good time to make transitions that we don't want the user to see,
    311                 // such as bringing the key guard to focus.  There's no guarantee for this,
    312                 // however because the user could turn the device on again at any time.
    313                 // Some things may need to be protected by other mechanisms that defer screen on.
    314                 interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_ASLEEP);
    315                 if (interactiveChanged) {
    316                     mActualInteractiveState = INTERACTIVE_STATE_ASLEEP;
    317                     mPendingGoToSleepBroadcast = true;
    318                     if (mUserActivityPending) {
    319                         mUserActivityPending = false;
    320                         mHandler.removeMessages(MSG_USER_ACTIVITY);
    321                     }
    322                     mHandler.post(new Runnable() {
    323                         @Override
    324                         public void run() {
    325                             int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
    326                             switch (reason) {
    327                                 case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
    328                                     why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
    329                                     break;
    330                                 case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
    331                                     why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
    332                                     break;
    333                             }
    334                             EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
    335                             mPolicy.goingToSleep(why);
    336                         }
    337                     });
    338                     updatePendingBroadcastLocked();
    339                 }
    340             }
    341         }
    342 
    343         // Notify battery stats.
    344         if (interactiveChanged) {
    345             try {
    346                 mBatteryStats.noteInteractive(interactive);
    347             } catch (RemoteException ex) { }
    348         }
    349     }
    350 
    351     /**
    352      * Called when there has been user activity.
    353      */
    354     public void onUserActivity(int event, int uid) {
    355         if (DEBUG) {
    356             Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
    357         }
    358 
    359         try {
    360             mBatteryStats.noteUserActivity(uid, event);
    361         } catch (RemoteException ex) {
    362             // Ignore
    363         }
    364 
    365         synchronized (mLock) {
    366             if (!mUserActivityPending) {
    367                 mUserActivityPending = true;
    368                 Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
    369                 msg.setAsynchronous(true);
    370                 mHandler.sendMessage(msg);
    371             }
    372         }
    373     }
    374 
    375     /**
    376      * Called when wireless charging has started so as to provide user feedback.
    377      */
    378     public void onWirelessChargingStarted() {
    379         if (DEBUG) {
    380             Slog.d(TAG, "onWirelessChargingStarted");
    381         }
    382 
    383         mSuspendBlocker.acquire();
    384         Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
    385         msg.setAsynchronous(true);
    386         mHandler.sendMessage(msg);
    387     }
    388 
    389     private void updatePendingBroadcastLocked() {
    390         if (!mBroadcastInProgress
    391                 && mActualInteractiveState != INTERACTIVE_STATE_UNKNOWN
    392                 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
    393                         || mActualInteractiveState != mBroadcastedInteractiveState)) {
    394             mBroadcastInProgress = true;
    395             mSuspendBlocker.acquire();
    396             Message msg = mHandler.obtainMessage(MSG_BROADCAST);
    397             msg.setAsynchronous(true);
    398             mHandler.sendMessage(msg);
    399         }
    400     }
    401 
    402     private void finishPendingBroadcastLocked() {
    403         mBroadcastInProgress = false;
    404         mSuspendBlocker.release();
    405     }
    406 
    407     private void sendUserActivity() {
    408         synchronized (mLock) {
    409             if (!mUserActivityPending) {
    410                 return;
    411             }
    412             mUserActivityPending = false;
    413         }
    414 
    415         mPolicy.userActivity();
    416     }
    417 
    418     private void sendNextBroadcast() {
    419         final int powerState;
    420         synchronized (mLock) {
    421             if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
    422                 // Broadcasted power state is unknown.  Send wake up.
    423                 mPendingWakeUpBroadcast = false;
    424                 mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
    425             } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
    426                 // Broadcasted power state is awake.  Send asleep if needed.
    427                 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
    428                         || mActualInteractiveState == INTERACTIVE_STATE_ASLEEP) {
    429                     mPendingGoToSleepBroadcast = false;
    430                     mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
    431                 } else {
    432                     finishPendingBroadcastLocked();
    433                     return;
    434                 }
    435             } else {
    436                 // Broadcasted power state is asleep.  Send awake if needed.
    437                 if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
    438                         || mActualInteractiveState == INTERACTIVE_STATE_AWAKE) {
    439                     mPendingWakeUpBroadcast = false;
    440                     mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
    441                 } else {
    442                     finishPendingBroadcastLocked();
    443                     return;
    444                 }
    445             }
    446 
    447             mBroadcastStartTime = SystemClock.uptimeMillis();
    448             powerState = mBroadcastedInteractiveState;
    449         }
    450 
    451         EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
    452 
    453         if (powerState == INTERACTIVE_STATE_AWAKE) {
    454             sendWakeUpBroadcast();
    455         } else {
    456             sendGoToSleepBroadcast();
    457         }
    458     }
    459 
    460     private void sendWakeUpBroadcast() {
    461         if (DEBUG) {
    462             Slog.d(TAG, "Sending wake up broadcast.");
    463         }
    464 
    465         if (ActivityManagerNative.isSystemReady()) {
    466             mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
    467                     mWakeUpBroadcastDone, mHandler, 0, null, null);
    468         } else {
    469             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
    470             sendNextBroadcast();
    471         }
    472     }
    473 
    474     private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
    475         @Override
    476         public void onReceive(Context context, Intent intent) {
    477             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
    478                     SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
    479             sendNextBroadcast();
    480         }
    481     };
    482 
    483     private void sendGoToSleepBroadcast() {
    484         if (DEBUG) {
    485             Slog.d(TAG, "Sending go to sleep broadcast.");
    486         }
    487 
    488         if (ActivityManagerNative.isSystemReady()) {
    489             mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
    490                     mGoToSleepBroadcastDone, mHandler, 0, null, null);
    491         } else {
    492             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
    493             sendNextBroadcast();
    494         }
    495     }
    496 
    497     private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
    498         @Override
    499         public void onReceive(Context context, Intent intent) {
    500             EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
    501                     SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
    502             sendNextBroadcast();
    503         }
    504     };
    505 
    506     private void playWirelessChargingStartedSound() {
    507         final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
    508                 Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
    509         if (soundPath != null) {
    510             final Uri soundUri = Uri.parse("file://" + soundPath);
    511             if (soundUri != null) {
    512                 final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
    513                 if (sfx != null) {
    514                     sfx.setStreamType(AudioManager.STREAM_SYSTEM);
    515                     sfx.play();
    516                 }
    517             }
    518         }
    519 
    520         mSuspendBlocker.release();
    521     }
    522 
    523     private final class NotifierHandler extends Handler {
    524         public NotifierHandler(Looper looper) {
    525             super(looper, null, true /*async*/);
    526         }
    527 
    528         @Override
    529         public void handleMessage(Message msg) {
    530             switch (msg.what) {
    531                 case MSG_USER_ACTIVITY:
    532                     sendUserActivity();
    533                     break;
    534 
    535                 case MSG_BROADCAST:
    536                     sendNextBroadcast();
    537                     break;
    538 
    539                 case MSG_WIRELESS_CHARGING_STARTED:
    540                     playWirelessChargingStartedSound();
    541                     break;
    542             }
    543         }
    544     }
    545 }
    546