/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.power; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.RetailDemoModeServiceInternal; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.EventLogTags; import com.android.server.LocalServices; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.hardware.input.InputManagerInternal; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.metrics.LogMaker; import android.net.Uri; import android.os.BatteryStats; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.PowerManagerInternal; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; import android.util.EventLog; import android.util.Slog; import android.view.WindowManagerPolicy; import android.view.inputmethod.InputMethodManagerInternal; /** * 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. *

*/ final class Notifier { private static final String TAG = "PowerManagerNotifier"; private static final boolean DEBUG = false; private static final int INTERACTIVE_STATE_UNKNOWN = 0; private static final int INTERACTIVE_STATE_AWAKE = 1; private static final int INTERACTIVE_STATE_ASLEEP = 2; private static final int MSG_USER_ACTIVITY = 1; private static final int MSG_BROADCAST = 2; private static final int MSG_WIRELESS_CHARGING_STARTED = 3; private static final int MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED = 4; private final Object mLock = new Object(); private final Context mContext; private final IBatteryStats mBatteryStats; private final IAppOpsService mAppOps; private final SuspendBlocker mSuspendBlocker; private final WindowManagerPolicy mPolicy; private final ActivityManagerInternal mActivityManagerInternal; private final InputManagerInternal mInputManagerInternal; private final InputMethodManagerInternal mInputMethodManagerInternal; private final RetailDemoModeServiceInternal mRetailDemoModeServiceInternal; private final NotifierHandler mHandler; private final Intent mScreenOnIntent; private final Intent mScreenOffIntent; private final Intent mScreenBrightnessBoostIntent; // True if the device should suspend when the screen is off due to proximity. private final boolean mSuspendWhenScreenOffDueToProximityConfig; // The current interactive state. This is set as soon as an interactive state // transition begins so as to capture the reason that it happened. At some point // this state will propagate to the pending state then eventually to the // broadcasted state over the course of reporting the transition asynchronously. private boolean mInteractive = true; private int mInteractiveChangeReason; private boolean mInteractiveChanging; // The pending interactive state that we will eventually want to broadcast. // This is designed so that we can collapse redundant sequences of awake/sleep // transition pairs while still guaranteeing that at least one transition is observed // whenever this happens. private int mPendingInteractiveState; private boolean mPendingWakeUpBroadcast; private boolean mPendingGoToSleepBroadcast; // The currently broadcasted interactive state. This reflects what other parts of the // system have observed. private int mBroadcastedInteractiveState; private boolean mBroadcastInProgress; private long mBroadcastStartTime; // True if a user activity message should be sent. private boolean mUserActivityPending; public Notifier(Looper looper, Context context, IBatteryStats batteryStats, IAppOpsService appOps, SuspendBlocker suspendBlocker, WindowManagerPolicy policy) { mContext = context; mBatteryStats = batteryStats; mAppOps = appOps; mSuspendBlocker = suspendBlocker; mPolicy = policy; mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class); mRetailDemoModeServiceInternal = LocalServices.getService(RetailDemoModeServiceInternal.class); mHandler = new NotifierHandler(looper); mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON); mScreenOnIntent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); mScreenOffIntent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); mScreenBrightnessBoostIntent = new Intent(PowerManager.ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED); mScreenBrightnessBoostIntent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); mSuspendWhenScreenOffDueToProximityConfig = context.getResources().getBoolean( com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity); // Initialize interactive state for battery stats. try { mBatteryStats.noteInteractive(true); } catch (RemoteException ex) { } } /** * Called when a wake lock is acquired. */ public void onWakeLockAcquired(int flags, String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String historyTag) { if (DEBUG) { Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag + "\", packageName=" + packageName + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid + ", workSource=" + workSource); } final int monitorType = getBatteryStatsWakeLockMonitorType(flags); if (monitorType >= 0) { try { final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0; 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 void onLongPartialWakeLockStart(String tag, int ownerUid, WorkSource workSource, String historyTag) { if (DEBUG) { Slog.d(TAG, "onLongPartialWakeLockStart: ownerUid=" + ownerUid + ", workSource=" + workSource); } try { if (workSource != null) { final int N = workSource.size(); for (int i=0; i