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