FileDocCategorySizeDatePackage
Notifier.javaAPI DocAndroid 5.1 API21860Thu Mar 12 22:22:42 GMT 2015com.android.server.power

Notifier

public final class Notifier extends Object
Sends broadcasts about important power state changes.

This methods of this class may be called by the power manager service while its lock is being held. Internally it takes care of sending broadcasts to notify other components of the system or applications asynchronously.

The notifier is designed to collapse unnecessary broadcasts when it is not possible for the system to have observed an intermediate state.

For example, if the device wakes up, goes to sleep, wakes up again and goes to sleep again before the wake up notification is sent, then the system will be told about only one wake up and sleep. However, we always notify the fact that at least one transition occurred. It is especially important to tell the system when we go to sleep so that it can lock the keyguard if needed.

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
private static final int
INTERACTIVE_STATE_UNKNOWN
private static final int
INTERACTIVE_STATE_AWAKE
private static final int
INTERACTIVE_STATE_ASLEEP
private static final int
MSG_USER_ACTIVITY
private static final int
MSG_BROADCAST
private static final int
MSG_WIRELESS_CHARGING_STARTED
private final Object
mLock
private final android.content.Context
mContext
private final com.android.internal.app.IBatteryStats
mBatteryStats
private final com.android.internal.app.IAppOpsService
mAppOps
private final SuspendBlocker
mSuspendBlocker
private final android.view.WindowManagerPolicy
mPolicy
private final android.app.ActivityManagerInternal
mActivityManagerInternal
private final android.hardware.input.InputManagerInternal
mInputManagerInternal
private final NotifierHandler
mHandler
private final android.content.Intent
mScreenOnIntent
private final android.content.Intent
mScreenOffIntent
private int
mActualInteractiveState
private int
mLastReason
private boolean
mPendingWakeUpBroadcast
private boolean
mPendingGoToSleepBroadcast
private int
mBroadcastedInteractiveState
private boolean
mBroadcastInProgress
private long
mBroadcastStartTime
private boolean
mUserActivityPending
private final android.content.BroadcastReceiver
mWakeUpBroadcastDone
private final android.content.BroadcastReceiver
mGoToSleepBroadcastDone
Constructors Summary
public Notifier(android.os.Looper looper, android.content.Context context, com.android.internal.app.IBatteryStats batteryStats, com.android.internal.app.IAppOpsService appOps, SuspendBlocker suspendBlocker, android.view.WindowManagerPolicy policy)


          
               
              
        mContext = context;
        mBatteryStats = batteryStats;
        mAppOps = appOps;
        mSuspendBlocker = suspendBlocker;
        mPolicy = policy;
        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);

        mHandler = new NotifierHandler(looper);
        mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
        mScreenOnIntent.addFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
        mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
        mScreenOffIntent.addFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);

        // Initialize interactive state for battery stats.
        try {
            mBatteryStats.noteInteractive(true);
        } catch (RemoteException ex) { }
    
Methods Summary
private voidfinishPendingBroadcastLocked()

        mBroadcastInProgress = false;
        mSuspendBlocker.release();
    
private static intgetBatteryStatsWakeLockMonitorType(int flags)

        switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
            case PowerManager.PARTIAL_WAKE_LOCK:
            case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                return BatteryStats.WAKE_TYPE_PARTIAL;
            default:
                return BatteryStats.WAKE_TYPE_FULL;
        }
    
private voidhandleWakefulnessChange(int wakefulness, boolean interactive, int reason)

        // Tell the activity manager about changes in wakefulness, not just interactivity.
        // It needs more granularity than other components.
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mActivityManagerInternal.onWakefulnessChanged(wakefulness);
            }
        });

        // Handle changes in the overall interactive state.
        boolean interactiveChanged = false;
        synchronized (mLock) {
            // Broadcast interactive state changes.
            if (interactive) {
                // Waking up...
                interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_AWAKE);
                if (interactiveChanged) {
                    mActualInteractiveState = INTERACTIVE_STATE_AWAKE;
                    mPendingWakeUpBroadcast = true;
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
                            mPolicy.wakingUp();
                        }
                    });
                    updatePendingBroadcastLocked();
                }
            } else {
                // Going to sleep...
                // This is a good time to make transitions that we don't want the user to see,
                // such as bringing the key guard to focus.  There's no guarantee for this,
                // however because the user could turn the device on again at any time.
                // Some things may need to be protected by other mechanisms that defer screen on.
                interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_ASLEEP);
                if (interactiveChanged) {
                    mActualInteractiveState = INTERACTIVE_STATE_ASLEEP;
                    mPendingGoToSleepBroadcast = true;
                    if (mUserActivityPending) {
                        mUserActivityPending = false;
                        mHandler.removeMessages(MSG_USER_ACTIVITY);
                    }
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
                            switch (reason) {
                                case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
                                    why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
                                    break;
                                case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
                                    why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
                                    break;
                            }
                            EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
                            mPolicy.goingToSleep(why);
                        }
                    });
                    updatePendingBroadcastLocked();
                }
            }
        }

        // Notify battery stats.
        if (interactiveChanged) {
            try {
                mBatteryStats.noteInteractive(interactive);
            } catch (RemoteException ex) { }
        }
    
public voidonUserActivity(int event, int uid)
Called when there has been user activity.

        if (DEBUG) {
            Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
        }

        try {
            mBatteryStats.noteUserActivity(uid, event);
        } catch (RemoteException ex) {
            // Ignore
        }

        synchronized (mLock) {
            if (!mUserActivityPending) {
                mUserActivityPending = true;
                Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
                msg.setAsynchronous(true);
                mHandler.sendMessage(msg);
            }
        }
    
public voidonWakeLockAcquired(int flags, java.lang.String tag, java.lang.String packageName, int ownerUid, int ownerPid, android.os.WorkSource workSource, java.lang.String historyTag)
Called when a wake lock is acquired.

        if (DEBUG) {
            Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
                    + "\", packageName=" + packageName
                    + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
                    + ", workSource=" + workSource);
        }

        try {
            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
            boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
                    && ownerUid == Process.SYSTEM_UID;
            if (workSource != null) {
                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, historyTag,
                        monitorType, unimportantForLogging);
            } else {
                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
                        monitorType, unimportantForLogging);
                // XXX need to deal with disabled operations.
                mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
                        AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
            }
        } catch (RemoteException ex) {
            // Ignore
        }
    
public voidonWakeLockChanging(int flags, java.lang.String tag, java.lang.String packageName, int ownerUid, int ownerPid, android.os.WorkSource workSource, java.lang.String historyTag, int newFlags, java.lang.String newTag, java.lang.String newPackageName, int newOwnerUid, int newOwnerPid, android.os.WorkSource newWorkSource, java.lang.String newHistoryTag)
Called when a wake lock is changing.


        if (workSource != null && newWorkSource != null) {
            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
            final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags);
            boolean unimportantForLogging = (newFlags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
                    && newOwnerUid == Process.SYSTEM_UID;
            if (DEBUG) {
                Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag
                        + "\", packageName=" + newPackageName
                        + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid
                        + ", workSource=" + newWorkSource);
            }
            try {
                mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag,
                        monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag,
                        newMonitorType, unimportantForLogging);
            } catch (RemoteException ex) {
                // Ignore
            }
        } else {
            onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag);
            onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid,
                    newWorkSource, newHistoryTag);
        }
    
public voidonWakeLockReleased(int flags, java.lang.String tag, java.lang.String packageName, int ownerUid, int ownerPid, android.os.WorkSource workSource, java.lang.String historyTag)
Called when a wake lock is released.

        if (DEBUG) {
            Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
                    + "\", packageName=" + packageName
                    + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
                    + ", workSource=" + workSource);
        }

        try {
            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
            if (workSource != null) {
                mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, historyTag,
                        monitorType);
            } else {
                mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, historyTag, monitorType);
                mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
                        AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
            }
        } catch (RemoteException ex) {
            // Ignore
        }
    
public voidonWakefulnessChangeFinished(int wakefulness)
Notifies that the device has finished changing wakefulness.

        if (DEBUG) {
            Slog.d(TAG, "onWakefulnessChangeFinished: wakefulness=" + wakefulness);
        }

        // Handle interactive state changes once they are finished so that the system can
        // finish pending transitions (such as turning the screen off) before causing
        // applications to change state visibly.
        final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
        if (!interactive) {
            handleWakefulnessChange(wakefulness, interactive, mLastReason);
        }
    
public voidonWakefulnessChangeStarted(int wakefulness, int reason)
Notifies that the device is changing wakefulness.

        if (DEBUG) {
            Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
                    + ", reason=" + reason);
        }

        // We handle interactive state changes once they start so that the system can
        // set everything up or the user to begin interacting with applications.
        final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
        if (interactive) {
            handleWakefulnessChange(wakefulness, interactive, reason);
        } else {
            mLastReason = reason;
        }

        // Start input as soon as we start waking up or going to sleep.
        mInputManagerInternal.setInteractive(interactive);
    
public voidonWirelessChargingStarted()
Called when wireless charging has started so as to provide user feedback.

        if (DEBUG) {
            Slog.d(TAG, "onWirelessChargingStarted");
        }

        mSuspendBlocker.acquire();
        Message msg = mHandler.obtainMessage(MSG_WIRELESS_CHARGING_STARTED);
        msg.setAsynchronous(true);
        mHandler.sendMessage(msg);
    
private voidplayWirelessChargingStartedSound()


       
        final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
                Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
        if (soundPath != null) {
            final Uri soundUri = Uri.parse("file://" + soundPath);
            if (soundUri != null) {
                final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
                if (sfx != null) {
                    sfx.setStreamType(AudioManager.STREAM_SYSTEM);
                    sfx.play();
                }
            }
        }

        mSuspendBlocker.release();
    
private voidsendGoToSleepBroadcast()


       
        if (DEBUG) {
            Slog.d(TAG, "Sending go to sleep broadcast.");
        }

        if (ActivityManagerNative.isSystemReady()) {
            mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
                    mGoToSleepBroadcastDone, mHandler, 0, null, null);
        } else {
            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
            sendNextBroadcast();
        }
    
private voidsendNextBroadcast()

        final int powerState;
        synchronized (mLock) {
            if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
                // Broadcasted power state is unknown.  Send wake up.
                mPendingWakeUpBroadcast = false;
                mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
            } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
                // Broadcasted power state is awake.  Send asleep if needed.
                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mActualInteractiveState == INTERACTIVE_STATE_ASLEEP) {
                    mPendingGoToSleepBroadcast = false;
                    mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
                } else {
                    finishPendingBroadcastLocked();
                    return;
                }
            } else {
                // Broadcasted power state is asleep.  Send awake if needed.
                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mActualInteractiveState == INTERACTIVE_STATE_AWAKE) {
                    mPendingWakeUpBroadcast = false;
                    mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
                } else {
                    finishPendingBroadcastLocked();
                    return;
                }
            }

            mBroadcastStartTime = SystemClock.uptimeMillis();
            powerState = mBroadcastedInteractiveState;
        }

        EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);

        if (powerState == INTERACTIVE_STATE_AWAKE) {
            sendWakeUpBroadcast();
        } else {
            sendGoToSleepBroadcast();
        }
    
private voidsendUserActivity()

        synchronized (mLock) {
            if (!mUserActivityPending) {
                return;
            }
            mUserActivityPending = false;
        }

        mPolicy.userActivity();
    
private voidsendWakeUpBroadcast()

        if (DEBUG) {
            Slog.d(TAG, "Sending wake up broadcast.");
        }

        if (ActivityManagerNative.isSystemReady()) {
            mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
                    mWakeUpBroadcastDone, mHandler, 0, null, null);
        } else {
            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
            sendNextBroadcast();
        }
    
private voidupdatePendingBroadcastLocked()

        if (!mBroadcastInProgress
                && mActualInteractiveState != INTERACTIVE_STATE_UNKNOWN
                && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mActualInteractiveState != mBroadcastedInteractiveState)) {
            mBroadcastInProgress = true;
            mSuspendBlocker.acquire();
            Message msg = mHandler.obtainMessage(MSG_BROADCAST);
            msg.setAsynchronous(true);
            mHandler.sendMessage(msg);
        }