3256 lines
129 KiB
Java
3256 lines
129 KiB
Java
/*
|
|
* Copyright (C) 2007 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;
|
|
|
|
import com.android.internal.app.IBatteryStats;
|
|
import com.android.internal.app.ShutdownThread;
|
|
import com.android.server.am.BatteryStatsService;
|
|
|
|
import android.app.ActivityManagerNative;
|
|
import android.app.IActivityManager;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.ContentQueryMap;
|
|
import android.content.ContentResolver;
|
|
import android.content.ContentValues;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.res.Resources;
|
|
import android.database.ContentObserver;
|
|
import android.database.Cursor;
|
|
import android.hardware.Sensor;
|
|
import android.hardware.SensorEvent;
|
|
import android.hardware.SensorEventListener;
|
|
import android.hardware.SensorManager;
|
|
import android.os.BatteryManager;
|
|
import android.os.BatteryStats;
|
|
import android.os.Binder;
|
|
import android.os.Environment;
|
|
import android.os.Handler;
|
|
import android.os.HandlerThread;
|
|
import android.os.IBinder;
|
|
import android.os.IPowerManager;
|
|
import android.os.LocalPowerManager;
|
|
import android.os.Power;
|
|
import android.os.PowerManager;
|
|
import android.os.Process;
|
|
import android.os.RemoteException;
|
|
import android.os.ServiceManager;
|
|
import android.os.SystemClock;
|
|
import android.os.WorkSource;
|
|
import android.os.SystemProperties;
|
|
import android.provider.Settings.SettingNotFoundException;
|
|
import android.provider.Settings;
|
|
import android.util.EventLog;
|
|
import android.util.Log;
|
|
import android.util.Slog;
|
|
import android.view.WindowManagerPolicy;
|
|
import static android.provider.Settings.System.DIM_SCREEN;
|
|
import static android.provider.Settings.System.SCREEN_BRIGHTNESS;
|
|
import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE;
|
|
import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
|
|
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
|
|
import static android.provider.Settings.System.STAY_ON_WHILE_PLUGGED_IN;
|
|
import static android.provider.Settings.System.WINDOW_ANIMATION_SCALE;
|
|
import static android.provider.Settings.System.TRANSITION_ANIMATION_SCALE;
|
|
|
|
import java.io.FileDescriptor;
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
import java.io.File;
|
|
import java.io.FileReader;
|
|
import java.io.BufferedReader;
|
|
import java.io.FileFilter;
|
|
import java.util.Iterator;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.Observable;
|
|
import java.util.Observer;
|
|
|
|
class PowerManagerService extends IPowerManager.Stub
|
|
implements LocalPowerManager, Watchdog.Monitor {
|
|
|
|
private static final String TAG = "PowerManagerService";
|
|
static final String PARTIAL_NAME = "PowerManagerService";
|
|
|
|
private static final boolean LOG_PARTIAL_WL = false;
|
|
|
|
// Indicates whether touch-down cycles should be logged as part of the
|
|
// LOG_POWER_SCREEN_STATE log events
|
|
private static final boolean LOG_TOUCH_DOWNS = true;
|
|
|
|
private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK
|
|
| PowerManager.SCREEN_DIM_WAKE_LOCK
|
|
| PowerManager.SCREEN_BRIGHT_WAKE_LOCK
|
|
| PowerManager.FULL_WAKE_LOCK
|
|
| PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK
|
|
| PowerManager.CPU_MAX_WAKE_LOCK;
|
|
|
|
// time since last state: time since last event:
|
|
// The short keylight delay comes from secure settings; this is the default.
|
|
private static final int SHORT_KEYLIGHT_DELAY_DEFAULT = 6000; // t+6 sec
|
|
private static final int MEDIUM_KEYLIGHT_DELAY = 15000; // t+15 sec
|
|
private static final int LONG_KEYLIGHT_DELAY = 6000; // t+6 sec
|
|
private static final int LONG_DIM_TIME = 7000; // t+N-5 sec
|
|
|
|
// How long to wait to debounce light sensor changes.
|
|
private static final int LIGHT_SENSOR_DELAY = 2000;
|
|
|
|
// For debouncing the proximity sensor.
|
|
private static final int PROXIMITY_SENSOR_DELAY = 1000;
|
|
|
|
// trigger proximity if distance is less than 5 cm
|
|
private static final float PROXIMITY_THRESHOLD = 5.0f;
|
|
|
|
// Cached secure settings; see updateSettingsValues()
|
|
private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT;
|
|
|
|
// Default timeout for screen off, if not found in settings database = 15 seconds.
|
|
private static final int DEFAULT_SCREEN_OFF_TIMEOUT = 15000;
|
|
|
|
// flags for setPowerState
|
|
private static final int SCREEN_ON_BIT = 0x00000001;
|
|
private static final int SCREEN_BRIGHT_BIT = 0x00000002;
|
|
private static final int BUTTON_BRIGHT_BIT = 0x00000004;
|
|
private static final int KEYBOARD_BRIGHT_BIT = 0x00000008;
|
|
private static final int BATTERY_LOW_BIT = 0x00000010;
|
|
|
|
// values for setPowerState
|
|
|
|
// SCREEN_OFF == everything off
|
|
private static final int SCREEN_OFF = 0x00000000;
|
|
|
|
// SCREEN_DIM == screen on, screen backlight dim
|
|
private static final int SCREEN_DIM = SCREEN_ON_BIT;
|
|
|
|
// SCREEN_BRIGHT == screen on, screen backlight bright
|
|
private static final int SCREEN_BRIGHT = SCREEN_ON_BIT | SCREEN_BRIGHT_BIT;
|
|
|
|
// SCREEN_BUTTON_BRIGHT == screen on, screen and button backlights bright
|
|
private static final int SCREEN_BUTTON_BRIGHT = SCREEN_BRIGHT | BUTTON_BRIGHT_BIT;
|
|
|
|
// SCREEN_BUTTON_BRIGHT == screen on, screen, button and keyboard backlights bright
|
|
private static final int ALL_BRIGHT = SCREEN_BUTTON_BRIGHT | KEYBOARD_BRIGHT_BIT;
|
|
|
|
// used for noChangeLights in setPowerState()
|
|
private static final int LIGHTS_MASK = SCREEN_BRIGHT_BIT | BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT;
|
|
|
|
boolean mAnimateScreenLights = true;
|
|
|
|
static final int ANIM_STEPS = 60/4;
|
|
// Slower animation for autobrightness changes
|
|
static final int AUTOBRIGHTNESS_ANIM_STEPS = 60;
|
|
|
|
// These magic numbers are the initial state of the LEDs at boot. Ideally
|
|
// we should read them from the driver, but our current hardware returns 0
|
|
// for the initial value. Oops!
|
|
static final int INITIAL_SCREEN_BRIGHTNESS = 255;
|
|
static final int INITIAL_BUTTON_BRIGHTNESS = Power.BRIGHTNESS_OFF;
|
|
static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF;
|
|
|
|
private final int MY_UID;
|
|
private final int MY_PID;
|
|
|
|
private boolean mDoneBooting = false;
|
|
private boolean mBootCompleted = false;
|
|
private int mStayOnConditions = 0;
|
|
private final int[] mBroadcastQueue = new int[] { -1, -1, -1 };
|
|
private final int[] mBroadcastWhy = new int[3];
|
|
private int mPartialCount = 0;
|
|
private int mCpuMaxCount = 0;
|
|
private int mPowerState;
|
|
// mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER,
|
|
// WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT or WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR
|
|
private int mScreenOffReason;
|
|
private int mUserState;
|
|
private boolean mKeyboardVisible = false;
|
|
private boolean mUserActivityAllowed = true;
|
|
private int mProximityWakeLockCount = 0;
|
|
private boolean mProximitySensorEnabled = false;
|
|
private boolean mProximitySensorActive = false;
|
|
private int mProximityPendingValue = -1; // -1 == nothing, 0 == inactive, 1 == active
|
|
private long mLastProximityEventTime;
|
|
private int mScreenOffTimeoutSetting;
|
|
private int mMaximumScreenOffTimeout = Integer.MAX_VALUE;
|
|
private int mKeylightDelay;
|
|
private int mDimDelay;
|
|
private int mScreenOffDelay;
|
|
private int mWakeLockState;
|
|
private long mLastEventTime = 0;
|
|
private long mScreenOffTime;
|
|
private volatile WindowManagerPolicy mPolicy;
|
|
private final LockList mLocks = new LockList();
|
|
private Intent mScreenOffIntent;
|
|
private Intent mScreenOnIntent;
|
|
private LightsService mLightsService;
|
|
private Context mContext;
|
|
private LightsService.Light mLcdLight;
|
|
private LightsService.Light mButtonLight;
|
|
private LightsService.Light mKeyboardLight;
|
|
private LightsService.Light mAttentionLight;
|
|
private UnsynchronizedWakeLock mBroadcastWakeLock;
|
|
private UnsynchronizedWakeLock mStayOnWhilePluggedInScreenDimLock;
|
|
private UnsynchronizedWakeLock mStayOnWhilePluggedInPartialLock;
|
|
private UnsynchronizedWakeLock mPreventScreenOnPartialLock;
|
|
private UnsynchronizedWakeLock mProximityPartialLock;
|
|
private HandlerThread mHandlerThread;
|
|
private HandlerThread mScreenOffThread;
|
|
private Handler mScreenOffHandler;
|
|
private Handler mHandler;
|
|
private final TimeoutTask mTimeoutTask = new TimeoutTask();
|
|
private final BrightnessState mScreenBrightness
|
|
= new BrightnessState(SCREEN_BRIGHT_BIT);
|
|
private boolean mStillNeedSleepNotification;
|
|
private boolean mIsPowered = false;
|
|
private IActivityManager mActivityService;
|
|
private IBatteryStats mBatteryStats;
|
|
private BatteryService mBatteryService;
|
|
private SensorManager mSensorManager;
|
|
private Sensor mProximitySensor;
|
|
private Sensor mLightSensor;
|
|
private boolean mLightSensorEnabled;
|
|
private float mLightSensorValue = -1;
|
|
private boolean mProxIgnoredBecauseScreenTurnedOff = false;
|
|
private int mHighestLightSensorValue = -1;
|
|
private float mLightSensorPendingValue = -1;
|
|
private int mLightSensorScreenBrightness = -1;
|
|
private int mLightSensorButtonBrightness = -1;
|
|
private int mLightSensorKeyboardBrightness = -1;
|
|
private boolean mDimScreen = true;
|
|
private boolean mIsDocked = false;
|
|
private long mNextTimeout;
|
|
private volatile int mPokey = 0;
|
|
private volatile boolean mPokeAwakeOnSet = false;
|
|
private volatile boolean mInitComplete = false;
|
|
private final HashMap<IBinder,PokeLock> mPokeLocks = new HashMap<IBinder,PokeLock>();
|
|
// mLastScreenOnTime is the time the screen was last turned on
|
|
private long mLastScreenOnTime;
|
|
private boolean mPreventScreenOn;
|
|
private int mScreenBrightnessOverride = -1;
|
|
private int mButtonBrightnessOverride = -1;
|
|
private boolean mUseSoftwareAutoBrightness;
|
|
private boolean mAutoBrightessEnabled;
|
|
private int[] mAutoBrightnessLevels;
|
|
private int[] mLcdBacklightValues;
|
|
private int[] mButtonBacklightValues;
|
|
private int[] mKeyboardBacklightValues;
|
|
private int mLightSensorWarmupTime;
|
|
boolean mUnplugTurnsOnScreen;
|
|
private int mWarningSpewThrottleCount;
|
|
private long mWarningSpewThrottleTime;
|
|
private int mAnimationSetting = ANIM_SETTING_OFF;
|
|
|
|
// Must match with the ISurfaceComposer constants in C++.
|
|
private static final int ANIM_SETTING_ON = 0x01;
|
|
private static final int ANIM_SETTING_OFF = 0x10;
|
|
|
|
// Used when logging number and duration of touch-down cycles
|
|
private long mTotalTouchDownTime;
|
|
private long mLastTouchDown;
|
|
private int mTouchCycles;
|
|
|
|
// could be either static or controllable at runtime
|
|
private static final boolean mSpew = false;
|
|
private static final boolean mSpewWl = true;
|
|
private static final boolean mDebugProximitySensor = (false || mSpew);
|
|
private static final boolean mDebugLightSensor = (false || mSpew);
|
|
|
|
private native void nativeInit();
|
|
private native void nativeSetPowerState(boolean screenOn, boolean screenBright);
|
|
private native void nativeStartSurfaceFlingerAnimation(int mode);
|
|
|
|
private PowerManagerService.SamplingRateAdjuster mSamplingRateAdjuster;
|
|
|
|
/*
|
|
static PrintStream mLog;
|
|
static {
|
|
try {
|
|
mLog = new PrintStream("/data/power.log");
|
|
}
|
|
catch (FileNotFoundException e) {
|
|
android.util.Slog.e(TAG, "Life is hard", e);
|
|
}
|
|
}
|
|
static class Log {
|
|
static void d(String tag, String s) {
|
|
mLog.println(s);
|
|
android.util.Slog.d(tag, s);
|
|
}
|
|
static void i(String tag, String s) {
|
|
mLog.println(s);
|
|
android.util.Slog.i(tag, s);
|
|
}
|
|
static void w(String tag, String s) {
|
|
mLog.println(s);
|
|
android.util.Slog.w(tag, s);
|
|
}
|
|
static void e(String tag, String s) {
|
|
mLog.println(s);
|
|
android.util.Slog.e(tag, s);
|
|
}
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* This class works around a deadlock between the lock in PowerManager.WakeLock
|
|
* and our synchronizing on mLocks. PowerManager.WakeLock synchronizes on its
|
|
* mToken object so it can be accessed from any thread, but it calls into here
|
|
* with its lock held. This class is essentially a reimplementation of
|
|
* PowerManager.WakeLock, but without that extra synchronized block, because we'll
|
|
* only call it with our own locks held.
|
|
*/
|
|
private class UnsynchronizedWakeLock {
|
|
int mFlags;
|
|
String mTag;
|
|
IBinder mToken;
|
|
int mCount = 0;
|
|
boolean mRefCounted;
|
|
boolean mHeld;
|
|
|
|
UnsynchronizedWakeLock(int flags, String tag, boolean refCounted) {
|
|
mFlags = flags;
|
|
mTag = tag;
|
|
mToken = new Binder();
|
|
mRefCounted = refCounted;
|
|
}
|
|
|
|
public void acquire() {
|
|
if (!mRefCounted || mCount++ == 0) {
|
|
long ident = Binder.clearCallingIdentity();
|
|
try {
|
|
PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
|
|
MY_UID, MY_PID, mTag, null);
|
|
mHeld = true;
|
|
} finally {
|
|
Binder.restoreCallingIdentity(ident);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void release() {
|
|
if (!mRefCounted || --mCount == 0) {
|
|
PowerManagerService.this.releaseWakeLockLocked(mToken, 0, false);
|
|
mHeld = false;
|
|
}
|
|
if (mCount < 0) {
|
|
throw new RuntimeException("WakeLock under-locked " + mTag);
|
|
}
|
|
}
|
|
|
|
public boolean isHeld()
|
|
{
|
|
return mHeld;
|
|
}
|
|
|
|
public String toString() {
|
|
return "UnsynchronizedWakeLock(mFlags=0x" + Integer.toHexString(mFlags)
|
|
+ " mCount=" + mCount + " mHeld=" + mHeld + ")";
|
|
}
|
|
}
|
|
|
|
private final class BatteryReceiver extends BroadcastReceiver {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
synchronized (mLocks) {
|
|
boolean wasPowered = mIsPowered;
|
|
mIsPowered = mBatteryService.isPowered();
|
|
|
|
if (mIsPowered != wasPowered) {
|
|
// update mStayOnWhilePluggedIn wake lock
|
|
updateWakeLockLocked();
|
|
|
|
// treat plugging and unplugging the devices as a user activity.
|
|
// users find it disconcerting when they unplug the device
|
|
// and it shuts off right away.
|
|
// to avoid turning on the screen when unplugging, we only trigger
|
|
// user activity when screen was already on.
|
|
// temporarily set mUserActivityAllowed to true so this will work
|
|
// even when the keyguard is on.
|
|
// However, you can also set config_unplugTurnsOnScreen to have it
|
|
// turn on. Some devices want this because they don't have a
|
|
// charging LED.
|
|
synchronized (mLocks) {
|
|
if (!wasPowered || (mPowerState & SCREEN_ON_BIT) != 0 ||
|
|
mUnplugTurnsOnScreen) {
|
|
forceUserActivityLocked();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private final class BootCompletedReceiver extends BroadcastReceiver {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
bootCompleted();
|
|
}
|
|
}
|
|
|
|
private final class DockReceiver extends BroadcastReceiver {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
|
|
Intent.EXTRA_DOCK_STATE_UNDOCKED);
|
|
dockStateChanged(state);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the setting that determines whether the device stays on when plugged in.
|
|
* The argument is a bit string, with each bit specifying a power source that,
|
|
* when the device is connected to that source, causes the device to stay on.
|
|
* See {@link android.os.BatteryManager} for the list of power sources that
|
|
* can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC}
|
|
* and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB}
|
|
* @param val an {@code int} containing the bits that specify which power sources
|
|
* should cause the device to stay on.
|
|
*/
|
|
public void setStayOnSetting(int val) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null);
|
|
Settings.System.putInt(mContext.getContentResolver(),
|
|
Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
|
|
}
|
|
|
|
public void setMaximumScreenOffTimeount(int timeMs) {
|
|
mContext.enforceCallingOrSelfPermission(
|
|
android.Manifest.permission.WRITE_SECURE_SETTINGS, null);
|
|
synchronized (mLocks) {
|
|
mMaximumScreenOffTimeout = timeMs;
|
|
// recalculate everything
|
|
setScreenOffTimeoutsLocked();
|
|
}
|
|
}
|
|
|
|
private class SettingsObserver implements Observer {
|
|
private int getInt(String name, int defValue) {
|
|
ContentValues values = mSettings.getValues(name);
|
|
Integer iVal = values != null ? values.getAsInteger(Settings.System.VALUE) : null;
|
|
return iVal != null ? iVal : defValue;
|
|
}
|
|
|
|
private float getFloat(String name, float defValue) {
|
|
ContentValues values = mSettings.getValues(name);
|
|
Float fVal = values != null ? values.getAsFloat(Settings.System.VALUE) : null;
|
|
return fVal != null ? fVal : defValue;
|
|
}
|
|
|
|
public void update(Observable o, Object arg) {
|
|
synchronized (mLocks) {
|
|
// STAY_ON_WHILE_PLUGGED_IN, default to when plugged into AC
|
|
mStayOnConditions = getInt(STAY_ON_WHILE_PLUGGED_IN,
|
|
BatteryManager.BATTERY_PLUGGED_AC);
|
|
updateWakeLockLocked();
|
|
|
|
// SCREEN_OFF_TIMEOUT, default to 15 seconds
|
|
mScreenOffTimeoutSetting = getInt(SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT);
|
|
|
|
// DIM_SCREEN
|
|
//mDimScreen = getInt(DIM_SCREEN) != 0;
|
|
|
|
// SCREEN_BRIGHTNESS_MODE, default to manual
|
|
setScreenBrightnessMode(getInt(SCREEN_BRIGHTNESS_MODE,
|
|
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL));
|
|
|
|
// recalculate everything
|
|
setScreenOffTimeoutsLocked();
|
|
|
|
final float windowScale = getFloat(WINDOW_ANIMATION_SCALE, 1.0f);
|
|
final float transitionScale = getFloat(TRANSITION_ANIMATION_SCALE, 1.0f);
|
|
mAnimationSetting = 0;
|
|
if (windowScale > 0.5f) {
|
|
mAnimationSetting |= ANIM_SETTING_OFF;
|
|
}
|
|
if (transitionScale > 0.5f) {
|
|
// Uncomment this if you want the screen-on animation.
|
|
// mAnimationSetting |= ANIM_SETTING_ON;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PowerManagerService() {
|
|
// Hack to get our uid... should have a func for this.
|
|
long token = Binder.clearCallingIdentity();
|
|
MY_UID = Process.myUid();
|
|
MY_PID = Process.myPid();
|
|
Binder.restoreCallingIdentity(token);
|
|
|
|
// XXX remove this when the kernel doesn't timeout wake locks
|
|
Power.setLastUserActivityTimeout(7*24*3600*1000); // one week
|
|
|
|
// assume nothing is on yet
|
|
mUserState = mPowerState = 0;
|
|
|
|
// Add ourself to the Watchdog monitors.
|
|
Watchdog.getInstance().addMonitor(this);
|
|
}
|
|
|
|
private ContentQueryMap mSettings;
|
|
|
|
void init(Context context, LightsService lights, IActivityManager activity,
|
|
BatteryService battery) {
|
|
mLightsService = lights;
|
|
mContext = context;
|
|
mActivityService = activity;
|
|
mBatteryStats = BatteryStatsService.getService();
|
|
mBatteryService = battery;
|
|
|
|
mLcdLight = lights.getLight(LightsService.LIGHT_ID_BACKLIGHT);
|
|
mButtonLight = lights.getLight(LightsService.LIGHT_ID_BUTTONS);
|
|
mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD);
|
|
mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
|
|
|
|
nativeInit();
|
|
synchronized (mLocks) {
|
|
updateNativePowerStateLocked();
|
|
}
|
|
|
|
mInitComplete = false;
|
|
mScreenOffThread = new HandlerThread("PowerManagerService.mScreenOffThread") {
|
|
@Override
|
|
protected void onLooperPrepared() {
|
|
mScreenOffHandler = new Handler();
|
|
synchronized (mScreenOffThread) {
|
|
mInitComplete = true;
|
|
mScreenOffThread.notifyAll();
|
|
}
|
|
}
|
|
};
|
|
mScreenOffThread.start();
|
|
|
|
synchronized (mScreenOffThread) {
|
|
while (!mInitComplete) {
|
|
try {
|
|
mScreenOffThread.wait();
|
|
} catch (InterruptedException e) {
|
|
// Ignore
|
|
}
|
|
}
|
|
}
|
|
|
|
mInitComplete = false;
|
|
mHandlerThread = new HandlerThread("PowerManagerService") {
|
|
@Override
|
|
protected void onLooperPrepared() {
|
|
super.onLooperPrepared();
|
|
initInThread();
|
|
}
|
|
};
|
|
mHandlerThread.start();
|
|
|
|
synchronized (mHandlerThread) {
|
|
while (!mInitComplete) {
|
|
try {
|
|
mHandlerThread.wait();
|
|
} catch (InterruptedException e) {
|
|
// Ignore
|
|
}
|
|
}
|
|
}
|
|
|
|
nativeInit();
|
|
synchronized (mLocks) {
|
|
updateNativePowerStateLocked();
|
|
}
|
|
}
|
|
|
|
void initInThread() {
|
|
mHandler = new Handler();
|
|
|
|
mBroadcastWakeLock = new UnsynchronizedWakeLock(
|
|
PowerManager.PARTIAL_WAKE_LOCK, "sleep_broadcast", true);
|
|
mStayOnWhilePluggedInScreenDimLock = new UnsynchronizedWakeLock(
|
|
PowerManager.SCREEN_DIM_WAKE_LOCK, "StayOnWhilePluggedIn Screen Dim", false);
|
|
mStayOnWhilePluggedInPartialLock = new UnsynchronizedWakeLock(
|
|
PowerManager.PARTIAL_WAKE_LOCK, "StayOnWhilePluggedIn Partial", false);
|
|
mPreventScreenOnPartialLock = new UnsynchronizedWakeLock(
|
|
PowerManager.PARTIAL_WAKE_LOCK, "PreventScreenOn Partial", false);
|
|
mProximityPartialLock = new UnsynchronizedWakeLock(
|
|
PowerManager.PARTIAL_WAKE_LOCK, "Proximity Partial", false);
|
|
|
|
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
|
|
mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
|
mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
|
|
mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
|
|
|
Resources resources = mContext.getResources();
|
|
|
|
mAnimateScreenLights = resources.getBoolean(
|
|
com.android.internal.R.bool.config_animateScreenLights);
|
|
|
|
mUnplugTurnsOnScreen = resources.getBoolean(
|
|
com.android.internal.R.bool.config_unplugTurnsOnScreen);
|
|
|
|
// read settings for auto-brightness
|
|
mUseSoftwareAutoBrightness = resources.getBoolean(
|
|
com.android.internal.R.bool.config_automatic_brightness_available);
|
|
if (mUseSoftwareAutoBrightness) {
|
|
mAutoBrightnessLevels = resources.getIntArray(
|
|
com.android.internal.R.array.config_autoBrightnessLevels);
|
|
mLcdBacklightValues = resources.getIntArray(
|
|
com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
|
|
mButtonBacklightValues = resources.getIntArray(
|
|
com.android.internal.R.array.config_autoBrightnessButtonBacklightValues);
|
|
mKeyboardBacklightValues = resources.getIntArray(
|
|
com.android.internal.R.array.config_autoBrightnessKeyboardBacklightValues);
|
|
mLightSensorWarmupTime = resources.getInteger(
|
|
com.android.internal.R.integer.config_lightSensorWarmupTime);
|
|
}
|
|
|
|
ContentResolver resolver = mContext.getContentResolver();
|
|
Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null,
|
|
"(" + Settings.System.NAME + "=?) or ("
|
|
+ Settings.System.NAME + "=?) or ("
|
|
+ Settings.System.NAME + "=?) or ("
|
|
+ Settings.System.NAME + "=?) or ("
|
|
+ Settings.System.NAME + "=?) or ("
|
|
+ Settings.System.NAME + "=?)",
|
|
new String[]{STAY_ON_WHILE_PLUGGED_IN, SCREEN_OFF_TIMEOUT, DIM_SCREEN,
|
|
SCREEN_BRIGHTNESS_MODE, WINDOW_ANIMATION_SCALE, TRANSITION_ANIMATION_SCALE},
|
|
null);
|
|
mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler);
|
|
SettingsObserver settingsObserver = new SettingsObserver();
|
|
mSettings.addObserver(settingsObserver);
|
|
|
|
// pretend that the settings changed so we will get their initial state
|
|
settingsObserver.update(mSettings, null);
|
|
|
|
// register for the battery changed notifications
|
|
IntentFilter filter = new IntentFilter();
|
|
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
|
mContext.registerReceiver(new BatteryReceiver(), filter);
|
|
filter = new IntentFilter();
|
|
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
|
|
mContext.registerReceiver(new BootCompletedReceiver(), filter);
|
|
filter = new IntentFilter();
|
|
filter.addAction(Intent.ACTION_DOCK_EVENT);
|
|
mContext.registerReceiver(new DockReceiver(), filter);
|
|
|
|
// Listen for secure settings changes
|
|
mContext.getContentResolver().registerContentObserver(
|
|
Settings.Secure.CONTENT_URI, true,
|
|
new ContentObserver(new Handler()) {
|
|
public void onChange(boolean selfChange) {
|
|
updateSettingsValues();
|
|
}
|
|
});
|
|
updateSettingsValues();
|
|
|
|
synchronized (mHandlerThread) {
|
|
mInitComplete = true;
|
|
mHandlerThread.notifyAll();
|
|
}
|
|
}
|
|
|
|
private class WakeLock implements IBinder.DeathRecipient
|
|
{
|
|
WakeLock(int f, IBinder b, String t, int u, int p) {
|
|
super();
|
|
flags = f;
|
|
binder = b;
|
|
tag = t;
|
|
uid = u == MY_UID ? Process.SYSTEM_UID : u;
|
|
pid = p;
|
|
if (u != MY_UID || (
|
|
!"KEEP_SCREEN_ON_FLAG".equals(tag)
|
|
&& !"KeyInputQueue".equals(tag))) {
|
|
monitorType = (f & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK
|
|
? BatteryStats.WAKE_TYPE_PARTIAL
|
|
: BatteryStats.WAKE_TYPE_FULL;
|
|
} else {
|
|
monitorType = -1;
|
|
}
|
|
try {
|
|
b.linkToDeath(this, 0);
|
|
} catch (RemoteException e) {
|
|
binderDied();
|
|
}
|
|
}
|
|
public void binderDied() {
|
|
synchronized (mLocks) {
|
|
releaseWakeLockLocked(this.binder, 0, true);
|
|
}
|
|
}
|
|
final int flags;
|
|
final IBinder binder;
|
|
final String tag;
|
|
final int uid;
|
|
final int pid;
|
|
final int monitorType;
|
|
WorkSource ws;
|
|
boolean activated = true;
|
|
int minState;
|
|
}
|
|
|
|
private void updateWakeLockLocked() {
|
|
if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {
|
|
// keep the device on if we're plugged in and mStayOnWhilePluggedIn is set.
|
|
mStayOnWhilePluggedInScreenDimLock.acquire();
|
|
mStayOnWhilePluggedInPartialLock.acquire();
|
|
} else {
|
|
mStayOnWhilePluggedInScreenDimLock.release();
|
|
mStayOnWhilePluggedInPartialLock.release();
|
|
}
|
|
}
|
|
|
|
private boolean isScreenLock(int flags)
|
|
{
|
|
int n = flags & LOCK_MASK;
|
|
return n == PowerManager.FULL_WAKE_LOCK
|
|
|| n == PowerManager.SCREEN_BRIGHT_WAKE_LOCK
|
|
|| n == PowerManager.SCREEN_DIM_WAKE_LOCK
|
|
|| n == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
|
|
}
|
|
|
|
void enforceWakeSourcePermission(int uid, int pid) {
|
|
if (uid == Process.myUid()) {
|
|
return;
|
|
}
|
|
mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
|
|
pid, uid, null);
|
|
}
|
|
|
|
public void acquireWakeLock(int flags, IBinder lock, String tag, WorkSource ws) {
|
|
int uid = Binder.getCallingUid();
|
|
int pid = Binder.getCallingPid();
|
|
if (uid != Process.myUid()) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
|
|
}
|
|
if (ws != null) {
|
|
enforceWakeSourcePermission(uid, pid);
|
|
}
|
|
long ident = Binder.clearCallingIdentity();
|
|
try {
|
|
synchronized (mLocks) {
|
|
acquireWakeLockLocked(flags, lock, uid, pid, tag, ws);
|
|
}
|
|
} finally {
|
|
Binder.restoreCallingIdentity(ident);
|
|
}
|
|
}
|
|
|
|
void noteStartWakeLocked(WakeLock wl, WorkSource ws) {
|
|
if (wl.monitorType >= 0) {
|
|
long origId = Binder.clearCallingIdentity();
|
|
try {
|
|
if (ws != null) {
|
|
mBatteryStats.noteStartWakelockFromSource(ws, wl.pid, wl.tag,
|
|
wl.monitorType);
|
|
} else {
|
|
mBatteryStats.noteStartWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
|
|
}
|
|
} catch (RemoteException e) {
|
|
// Ignore
|
|
} finally {
|
|
Binder.restoreCallingIdentity(origId);
|
|
}
|
|
}
|
|
}
|
|
|
|
void noteStopWakeLocked(WakeLock wl, WorkSource ws) {
|
|
if (wl.monitorType >= 0) {
|
|
long origId = Binder.clearCallingIdentity();
|
|
try {
|
|
if (ws != null) {
|
|
mBatteryStats.noteStopWakelockFromSource(ws, wl.pid, wl.tag,
|
|
wl.monitorType);
|
|
} else {
|
|
mBatteryStats.noteStopWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
|
|
}
|
|
} catch (RemoteException e) {
|
|
// Ignore
|
|
} finally {
|
|
Binder.restoreCallingIdentity(origId);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag,
|
|
WorkSource ws) {
|
|
if (mSpewWl) {
|
|
Slog.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag);
|
|
}
|
|
|
|
if (ws != null && ws.size() == 0) {
|
|
ws = null;
|
|
}
|
|
|
|
int index = mLocks.getIndex(lock);
|
|
WakeLock wl;
|
|
boolean newlock;
|
|
boolean diffsource;
|
|
WorkSource oldsource;
|
|
if (index < 0) {
|
|
wl = new WakeLock(flags, lock, tag, uid, pid);
|
|
switch (wl.flags & LOCK_MASK)
|
|
{
|
|
case PowerManager.FULL_WAKE_LOCK:
|
|
if (mUseSoftwareAutoBrightness) {
|
|
wl.minState = SCREEN_BRIGHT;
|
|
} else {
|
|
wl.minState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
|
|
}
|
|
break;
|
|
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
|
|
wl.minState = SCREEN_BRIGHT;
|
|
break;
|
|
case PowerManager.SCREEN_DIM_WAKE_LOCK:
|
|
wl.minState = SCREEN_DIM;
|
|
break;
|
|
case PowerManager.PARTIAL_WAKE_LOCK:
|
|
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
|
|
case PowerManager.CPU_MAX_WAKE_LOCK:
|
|
break;
|
|
default:
|
|
// just log and bail. we're in the server, so don't
|
|
// throw an exception.
|
|
Slog.e(TAG, "bad wakelock type for lock '" + tag + "' "
|
|
+ " flags=" + flags);
|
|
return;
|
|
}
|
|
mLocks.addLock(wl);
|
|
if (ws != null) {
|
|
wl.ws = new WorkSource(ws);
|
|
}
|
|
newlock = true;
|
|
diffsource = false;
|
|
oldsource = null;
|
|
} else {
|
|
wl = mLocks.get(index);
|
|
newlock = false;
|
|
oldsource = wl.ws;
|
|
if (oldsource != null) {
|
|
if (ws == null) {
|
|
wl.ws = null;
|
|
diffsource = true;
|
|
} else {
|
|
diffsource = oldsource.diff(ws);
|
|
}
|
|
} else if (ws != null) {
|
|
diffsource = true;
|
|
} else {
|
|
diffsource = false;
|
|
}
|
|
if (diffsource) {
|
|
wl.ws = new WorkSource(ws);
|
|
}
|
|
}
|
|
if (isScreenLock(flags)) {
|
|
// if this causes a wakeup, we reactivate all of the locks and
|
|
// set it to whatever they want. otherwise, we modulate that
|
|
// by the current state so we never turn it more on than
|
|
// it already is.
|
|
if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
|
|
mProximityWakeLockCount++;
|
|
if (mProximityWakeLockCount == 1) {
|
|
enableProximityLockLocked();
|
|
}
|
|
} else {
|
|
if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
|
|
int oldWakeLockState = mWakeLockState;
|
|
mWakeLockState = mLocks.reactivateScreenLocksLocked();
|
|
if (mSpew) {
|
|
Slog.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
|
|
+ " mWakeLockState=0x"
|
|
+ Integer.toHexString(mWakeLockState)
|
|
+ " previous wakeLockState=0x"
|
|
+ Integer.toHexString(oldWakeLockState));
|
|
}
|
|
} else {
|
|
if (mSpew) {
|
|
Slog.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState)
|
|
+ " mLocks.gatherState()=0x"
|
|
+ Integer.toHexString(mLocks.gatherState())
|
|
+ " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
|
|
}
|
|
mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState();
|
|
}
|
|
setPowerState(mWakeLockState | mUserState);
|
|
}
|
|
}
|
|
else if ((flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
|
|
if (newlock) {
|
|
mPartialCount++;
|
|
if (mPartialCount == 1) {
|
|
if (LOG_PARTIAL_WL) EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 1, tag);
|
|
}
|
|
}
|
|
Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
|
|
}
|
|
else if ((flags & LOCK_MASK) == PowerManager.CPU_MAX_WAKE_LOCK) {
|
|
mCpuMaxCount++;
|
|
if(mCpuMaxCount == 1)
|
|
Power.acquireCpuWakeLock();
|
|
}
|
|
|
|
if (diffsource) {
|
|
// If the lock sources have changed, need to first release the
|
|
// old ones.
|
|
noteStopWakeLocked(wl, oldsource);
|
|
}
|
|
if (newlock || diffsource) {
|
|
noteStartWakeLocked(wl, ws);
|
|
}
|
|
}
|
|
|
|
public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) {
|
|
int uid = Binder.getCallingUid();
|
|
int pid = Binder.getCallingPid();
|
|
if (ws != null && ws.size() == 0) {
|
|
ws = null;
|
|
}
|
|
if (ws != null) {
|
|
enforceWakeSourcePermission(uid, pid);
|
|
}
|
|
synchronized (mLocks) {
|
|
int index = mLocks.getIndex(lock);
|
|
if (index < 0) {
|
|
throw new IllegalArgumentException("Wake lock not active");
|
|
}
|
|
WakeLock wl = mLocks.get(index);
|
|
WorkSource oldsource = wl.ws;
|
|
wl.ws = ws != null ? new WorkSource(ws) : null;
|
|
noteStopWakeLocked(wl, oldsource);
|
|
noteStartWakeLocked(wl, ws);
|
|
}
|
|
}
|
|
|
|
public void releaseWakeLock(IBinder lock, int flags) {
|
|
int uid = Binder.getCallingUid();
|
|
if (uid != Process.myUid()) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
|
|
}
|
|
|
|
synchronized (mLocks) {
|
|
releaseWakeLockLocked(lock, flags, false);
|
|
}
|
|
}
|
|
|
|
private void releaseWakeLockLocked(IBinder lock, int flags, boolean death) {
|
|
WakeLock wl = mLocks.removeLock(lock);
|
|
if (wl == null) {
|
|
return;
|
|
}
|
|
|
|
if (mSpewWl) {
|
|
Slog.d(TAG, "releaseWakeLock flags=0x"
|
|
+ Integer.toHexString(wl.flags) + " tag=" + wl.tag);
|
|
}
|
|
|
|
if (isScreenLock(wl.flags)) {
|
|
if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
|
|
mProximityWakeLockCount--;
|
|
if (mProximityWakeLockCount == 0) {
|
|
if (mProximitySensorActive &&
|
|
((flags & PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE) != 0)) {
|
|
// wait for proximity sensor to go negative before disabling sensor
|
|
if (mDebugProximitySensor) {
|
|
Slog.d(TAG, "waiting for proximity sensor to go negative");
|
|
}
|
|
} else {
|
|
disableProximityLockLocked();
|
|
}
|
|
}
|
|
} else {
|
|
mWakeLockState = mLocks.gatherState();
|
|
// goes in the middle to reduce flicker
|
|
if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) {
|
|
userActivity(SystemClock.uptimeMillis(), -1, false, OTHER_EVENT, false);
|
|
}
|
|
setPowerState(mWakeLockState | mUserState);
|
|
}
|
|
}
|
|
else if ((wl.flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
|
|
mPartialCount--;
|
|
if (mPartialCount == 0) {
|
|
if (LOG_PARTIAL_WL) EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
|
|
Power.releaseWakeLock(PARTIAL_NAME);
|
|
}
|
|
}
|
|
else if ((wl.flags & LOCK_MASK) == PowerManager.CPU_MAX_WAKE_LOCK) {
|
|
mCpuMaxCount--;
|
|
if (mCpuMaxCount == 0)
|
|
Power.releaseCpuWakeLock();
|
|
}
|
|
// Unlink the lock from the binder.
|
|
wl.binder.unlinkToDeath(wl, 0);
|
|
|
|
noteStopWakeLocked(wl, wl.ws);
|
|
}
|
|
|
|
private class PokeLock implements IBinder.DeathRecipient
|
|
{
|
|
PokeLock(int p, IBinder b, String t) {
|
|
super();
|
|
this.pokey = p;
|
|
this.binder = b;
|
|
this.tag = t;
|
|
try {
|
|
b.linkToDeath(this, 0);
|
|
} catch (RemoteException e) {
|
|
binderDied();
|
|
}
|
|
}
|
|
public void binderDied() {
|
|
setPokeLock(0, this.binder, this.tag);
|
|
}
|
|
int pokey;
|
|
IBinder binder;
|
|
String tag;
|
|
boolean awakeOnSet;
|
|
}
|
|
|
|
public void setPokeLock(int pokey, IBinder token, String tag) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
if (token == null) {
|
|
Slog.e(TAG, "setPokeLock got null token for tag='" + tag + "'");
|
|
return;
|
|
}
|
|
|
|
if ((pokey & POKE_LOCK_TIMEOUT_MASK) == POKE_LOCK_TIMEOUT_MASK) {
|
|
throw new IllegalArgumentException("setPokeLock can't have both POKE_LOCK_SHORT_TIMEOUT"
|
|
+ " and POKE_LOCK_MEDIUM_TIMEOUT");
|
|
}
|
|
|
|
synchronized (mLocks) {
|
|
if (pokey != 0) {
|
|
PokeLock p = mPokeLocks.get(token);
|
|
int oldPokey = 0;
|
|
if (p != null) {
|
|
oldPokey = p.pokey;
|
|
p.pokey = pokey;
|
|
} else {
|
|
p = new PokeLock(pokey, token, tag);
|
|
mPokeLocks.put(token, p);
|
|
}
|
|
int oldTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK;
|
|
int newTimeout = pokey & POKE_LOCK_TIMEOUT_MASK;
|
|
if (((mPowerState & SCREEN_ON_BIT) == 0) && (oldTimeout != newTimeout)) {
|
|
p.awakeOnSet = true;
|
|
}
|
|
} else {
|
|
PokeLock rLock = mPokeLocks.remove(token);
|
|
if (rLock != null) {
|
|
token.unlinkToDeath(rLock, 0);
|
|
}
|
|
}
|
|
|
|
int oldPokey = mPokey;
|
|
int cumulative = 0;
|
|
boolean oldAwakeOnSet = mPokeAwakeOnSet;
|
|
boolean awakeOnSet = false;
|
|
for (PokeLock p: mPokeLocks.values()) {
|
|
cumulative |= p.pokey;
|
|
if (p.awakeOnSet) {
|
|
awakeOnSet = true;
|
|
}
|
|
}
|
|
mPokey = cumulative;
|
|
mPokeAwakeOnSet = awakeOnSet;
|
|
|
|
int oldCumulativeTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK;
|
|
int newCumulativeTimeout = pokey & POKE_LOCK_TIMEOUT_MASK;
|
|
|
|
if (oldCumulativeTimeout != newCumulativeTimeout) {
|
|
setScreenOffTimeoutsLocked();
|
|
// reset the countdown timer, but use the existing nextState so it doesn't
|
|
// change anything
|
|
setTimeoutLocked(SystemClock.uptimeMillis(), mTimeoutTask.nextState);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static String lockType(int type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case PowerManager.FULL_WAKE_LOCK:
|
|
return "FULL_WAKE_LOCK ";
|
|
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
|
|
return "SCREEN_BRIGHT_WAKE_LOCK ";
|
|
case PowerManager.SCREEN_DIM_WAKE_LOCK:
|
|
return "SCREEN_DIM_WAKE_LOCK ";
|
|
case PowerManager.PARTIAL_WAKE_LOCK:
|
|
return "PARTIAL_WAKE_LOCK ";
|
|
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
|
|
return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
|
|
case PowerManager.CPU_MAX_WAKE_LOCK:
|
|
return "CPU_MAX_WAKE_LOCK";
|
|
default:
|
|
return "??? ";
|
|
}
|
|
}
|
|
|
|
private static String dumpPowerState(int state) {
|
|
return (((state & KEYBOARD_BRIGHT_BIT) != 0)
|
|
? "KEYBOARD_BRIGHT_BIT " : "")
|
|
+ (((state & SCREEN_BRIGHT_BIT) != 0)
|
|
? "SCREEN_BRIGHT_BIT " : "")
|
|
+ (((state & SCREEN_ON_BIT) != 0)
|
|
? "SCREEN_ON_BIT " : "")
|
|
+ (((state & BATTERY_LOW_BIT) != 0)
|
|
? "BATTERY_LOW_BIT " : "");
|
|
}
|
|
|
|
@Override
|
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
|
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
|
|
!= PackageManager.PERMISSION_GRANTED) {
|
|
pw.println("Permission Denial: can't dump PowerManager from from pid="
|
|
+ Binder.getCallingPid()
|
|
+ ", uid=" + Binder.getCallingUid());
|
|
return;
|
|
}
|
|
|
|
long now = SystemClock.uptimeMillis();
|
|
|
|
synchronized (mLocks) {
|
|
pw.println("Power Manager State:");
|
|
pw.println(" mIsPowered=" + mIsPowered
|
|
+ " mPowerState=" + mPowerState
|
|
+ " mScreenOffTime=" + (SystemClock.elapsedRealtime()-mScreenOffTime)
|
|
+ " ms");
|
|
pw.println(" mPartialCount=" + mPartialCount);
|
|
pw.println(" mWakeLockState=" + dumpPowerState(mWakeLockState));
|
|
pw.println(" mUserState=" + dumpPowerState(mUserState));
|
|
pw.println(" mPowerState=" + dumpPowerState(mPowerState));
|
|
pw.println(" mLocks.gather=" + dumpPowerState(mLocks.gatherState()));
|
|
pw.println(" mNextTimeout=" + mNextTimeout + " now=" + now
|
|
+ " " + ((mNextTimeout-now)/1000) + "s from now");
|
|
pw.println(" mDimScreen=" + mDimScreen
|
|
+ " mStayOnConditions=" + mStayOnConditions);
|
|
pw.println(" mScreenOffReason=" + mScreenOffReason
|
|
+ " mUserState=" + mUserState);
|
|
pw.println(" mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1]
|
|
+ ',' + mBroadcastQueue[2] + "}");
|
|
pw.println(" mBroadcastWhy={" + mBroadcastWhy[0] + ',' + mBroadcastWhy[1]
|
|
+ ',' + mBroadcastWhy[2] + "}");
|
|
pw.println(" mPokey=" + mPokey + " mPokeAwakeonSet=" + mPokeAwakeOnSet);
|
|
pw.println(" mKeyboardVisible=" + mKeyboardVisible
|
|
+ " mUserActivityAllowed=" + mUserActivityAllowed);
|
|
pw.println(" mKeylightDelay=" + mKeylightDelay + " mDimDelay=" + mDimDelay
|
|
+ " mScreenOffDelay=" + mScreenOffDelay);
|
|
pw.println(" mPreventScreenOn=" + mPreventScreenOn
|
|
+ " mScreenBrightnessOverride=" + mScreenBrightnessOverride
|
|
+ " mButtonBrightnessOverride=" + mButtonBrightnessOverride);
|
|
pw.println(" mScreenOffTimeoutSetting=" + mScreenOffTimeoutSetting
|
|
+ " mMaximumScreenOffTimeout=" + mMaximumScreenOffTimeout);
|
|
pw.println(" mLastScreenOnTime=" + mLastScreenOnTime);
|
|
pw.println(" mBroadcastWakeLock=" + mBroadcastWakeLock);
|
|
pw.println(" mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
|
|
pw.println(" mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock);
|
|
pw.println(" mPreventScreenOnPartialLock=" + mPreventScreenOnPartialLock);
|
|
pw.println(" mProximityPartialLock=" + mProximityPartialLock);
|
|
pw.println(" mProximityWakeLockCount=" + mProximityWakeLockCount);
|
|
pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled);
|
|
pw.println(" mProximitySensorActive=" + mProximitySensorActive);
|
|
pw.println(" mProximityPendingValue=" + mProximityPendingValue);
|
|
pw.println(" mLastProximityEventTime=" + mLastProximityEventTime);
|
|
pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
|
|
pw.println(" mLightSensorValue=" + mLightSensorValue
|
|
+ " mLightSensorPendingValue=" + mLightSensorPendingValue);
|
|
pw.println(" mLightSensorScreenBrightness=" + mLightSensorScreenBrightness
|
|
+ " mLightSensorButtonBrightness=" + mLightSensorButtonBrightness
|
|
+ " mLightSensorKeyboardBrightness=" + mLightSensorKeyboardBrightness);
|
|
pw.println(" mUseSoftwareAutoBrightness=" + mUseSoftwareAutoBrightness);
|
|
pw.println(" mAutoBrightessEnabled=" + mAutoBrightessEnabled);
|
|
mScreenBrightness.dump(pw, " mScreenBrightness: ");
|
|
|
|
int N = mLocks.size();
|
|
pw.println();
|
|
pw.println("mLocks.size=" + N + ":");
|
|
for (int i=0; i<N; i++) {
|
|
WakeLock wl = mLocks.get(i);
|
|
String type = lockType(wl.flags & LOCK_MASK);
|
|
String acquireCausesWakeup = "";
|
|
if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
|
|
acquireCausesWakeup = "ACQUIRE_CAUSES_WAKEUP ";
|
|
}
|
|
String activated = "";
|
|
if (wl.activated) {
|
|
activated = " activated";
|
|
}
|
|
pw.println(" " + type + " '" + wl.tag + "'" + acquireCausesWakeup
|
|
+ activated + " (minState=" + wl.minState + ", uid=" + wl.uid
|
|
+ ", pid=" + wl.pid + ")");
|
|
}
|
|
|
|
pw.println();
|
|
pw.println("mPokeLocks.size=" + mPokeLocks.size() + ":");
|
|
for (PokeLock p: mPokeLocks.values()) {
|
|
pw.println(" poke lock '" + p.tag + "':"
|
|
+ ((p.pokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0
|
|
? " POKE_LOCK_IGNORE_CHEEK_EVENTS" : "")
|
|
+ ((p.pokey & POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS) != 0
|
|
? " POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS" : "")
|
|
+ ((p.pokey & POKE_LOCK_SHORT_TIMEOUT) != 0
|
|
? " POKE_LOCK_SHORT_TIMEOUT" : "")
|
|
+ ((p.pokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0
|
|
? " POKE_LOCK_MEDIUM_TIMEOUT" : ""));
|
|
}
|
|
|
|
pw.println();
|
|
}
|
|
}
|
|
|
|
private void setTimeoutLocked(long now, int nextState) {
|
|
setTimeoutLocked(now, -1, nextState);
|
|
}
|
|
|
|
// If they gave a timeoutOverride it is the number of seconds
|
|
// to screen-off. Figure out where in the countdown cycle we
|
|
// should jump to.
|
|
private void setTimeoutLocked(long now, final long originalTimeoutOverride, int nextState) {
|
|
long timeoutOverride = originalTimeoutOverride;
|
|
if (mBootCompleted) {
|
|
synchronized (mLocks) {
|
|
long when = 0;
|
|
if (timeoutOverride <= 0) {
|
|
switch (nextState)
|
|
{
|
|
case SCREEN_BRIGHT:
|
|
when = now + mKeylightDelay;
|
|
break;
|
|
case SCREEN_DIM:
|
|
if (mDimDelay >= 0) {
|
|
when = now + mDimDelay;
|
|
break;
|
|
} else {
|
|
Slog.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim");
|
|
}
|
|
case SCREEN_OFF:
|
|
synchronized (mLocks) {
|
|
when = now + mScreenOffDelay;
|
|
}
|
|
break;
|
|
default:
|
|
when = now;
|
|
break;
|
|
}
|
|
} else {
|
|
override: {
|
|
if (timeoutOverride <= mScreenOffDelay) {
|
|
when = now + timeoutOverride;
|
|
nextState = SCREEN_OFF;
|
|
break override;
|
|
}
|
|
timeoutOverride -= mScreenOffDelay;
|
|
|
|
if (mDimDelay >= 0) {
|
|
if (timeoutOverride <= mDimDelay) {
|
|
when = now + timeoutOverride;
|
|
nextState = SCREEN_DIM;
|
|
break override;
|
|
}
|
|
timeoutOverride -= mDimDelay;
|
|
}
|
|
|
|
when = now + timeoutOverride;
|
|
nextState = SCREEN_BRIGHT;
|
|
}
|
|
}
|
|
if (mSpew) {
|
|
Slog.d(TAG, "setTimeoutLocked now=" + now
|
|
+ " timeoutOverride=" + timeoutOverride
|
|
+ " nextState=" + nextState + " when=" + when);
|
|
}
|
|
|
|
mHandler.removeCallbacks(mTimeoutTask);
|
|
mTimeoutTask.nextState = nextState;
|
|
mTimeoutTask.remainingTimeoutOverride = timeoutOverride > 0
|
|
? (originalTimeoutOverride - timeoutOverride)
|
|
: -1;
|
|
mHandler.postAtTime(mTimeoutTask, when);
|
|
mNextTimeout = when; // for debugging
|
|
}
|
|
}
|
|
}
|
|
|
|
private void cancelTimerLocked()
|
|
{
|
|
mHandler.removeCallbacks(mTimeoutTask);
|
|
mTimeoutTask.nextState = -1;
|
|
}
|
|
|
|
private class TimeoutTask implements Runnable
|
|
{
|
|
int nextState; // access should be synchronized on mLocks
|
|
long remainingTimeoutOverride;
|
|
public void run()
|
|
{
|
|
synchronized (mLocks) {
|
|
if (mSpew) {
|
|
Slog.d(TAG, "user activity timeout timed out nextState=" + this.nextState);
|
|
}
|
|
|
|
if (nextState == -1) {
|
|
return;
|
|
}
|
|
|
|
mUserState = this.nextState;
|
|
setPowerState(this.nextState | mWakeLockState);
|
|
|
|
long now = SystemClock.uptimeMillis();
|
|
|
|
switch (this.nextState)
|
|
{
|
|
case SCREEN_BRIGHT:
|
|
if (mDimDelay >= 0) {
|
|
setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_DIM);
|
|
break;
|
|
}
|
|
case SCREEN_DIM:
|
|
setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_OFF);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void sendNotificationLocked(boolean on, int why)
|
|
{
|
|
if (!on) {
|
|
mStillNeedSleepNotification = false;
|
|
}
|
|
|
|
// Add to the queue.
|
|
int index = 0;
|
|
while (mBroadcastQueue[index] != -1) {
|
|
index++;
|
|
}
|
|
mBroadcastQueue[index] = on ? 1 : 0;
|
|
mBroadcastWhy[index] = why;
|
|
|
|
// If we added it position 2, then there is a pair that can be stripped.
|
|
// If we added it position 1 and we're turning the screen off, we can strip
|
|
// the pair and do nothing, because the screen is already off, and therefore
|
|
// keyguard has already been enabled.
|
|
// However, if we added it at position 1 and we're turning it on, then position
|
|
// 0 was to turn it off, and we can't strip that, because keyguard needs to come
|
|
// on, so have to run the queue then.
|
|
if (index == 2) {
|
|
// While we're collapsing them, if it's going off, and the new reason
|
|
// is more significant than the first, then use the new one.
|
|
if (!on && mBroadcastWhy[0] > why) {
|
|
mBroadcastWhy[0] = why;
|
|
}
|
|
mBroadcastQueue[0] = on ? 1 : 0;
|
|
mBroadcastQueue[1] = -1;
|
|
mBroadcastQueue[2] = -1;
|
|
mBroadcastWakeLock.release();
|
|
mBroadcastWakeLock.release();
|
|
index = 0;
|
|
}
|
|
if (index == 1 && !on) {
|
|
mBroadcastQueue[0] = -1;
|
|
mBroadcastQueue[1] = -1;
|
|
index = -1;
|
|
// The wake lock was being held, but we're not actually going to do any
|
|
// broadcasts, so release the wake lock.
|
|
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
|
|
mBroadcastWakeLock.release();
|
|
}
|
|
|
|
// Now send the message.
|
|
if (index >= 0) {
|
|
// Acquire the broadcast wake lock before changing the power
|
|
// state. It will be release after the broadcast is sent.
|
|
// We always increment the ref count for each notification in the queue
|
|
// and always decrement when that notification is handled.
|
|
mBroadcastWakeLock.acquire();
|
|
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, mBroadcastWakeLock.mCount);
|
|
mHandler.post(mNotificationTask);
|
|
}
|
|
}
|
|
|
|
private Runnable mNotificationTask = new Runnable()
|
|
{
|
|
public void run()
|
|
{
|
|
while (true) {
|
|
int value;
|
|
int why;
|
|
WindowManagerPolicy policy;
|
|
synchronized (mLocks) {
|
|
value = mBroadcastQueue[0];
|
|
why = mBroadcastWhy[0];
|
|
for (int i=0; i<2; i++) {
|
|
mBroadcastQueue[i] = mBroadcastQueue[i+1];
|
|
mBroadcastWhy[i] = mBroadcastWhy[i+1];
|
|
}
|
|
policy = getPolicyLocked();
|
|
}
|
|
if (value == 1) {
|
|
mScreenOnStart = SystemClock.uptimeMillis();
|
|
|
|
policy.screenTurnedOn();
|
|
try {
|
|
ActivityManagerNative.getDefault().wakingUp();
|
|
} catch (RemoteException e) {
|
|
// ignore it
|
|
}
|
|
|
|
if (mSpew) {
|
|
Slog.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock);
|
|
}
|
|
if (mContext != null && ActivityManagerNative.isSystemReady()) {
|
|
mContext.sendOrderedBroadcast(mScreenOnIntent, null,
|
|
mScreenOnBroadcastDone, mHandler, 0, null, null);
|
|
} else {
|
|
synchronized (mLocks) {
|
|
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2,
|
|
mBroadcastWakeLock.mCount);
|
|
mBroadcastWakeLock.release();
|
|
}
|
|
}
|
|
}
|
|
else if (value == 0) {
|
|
mScreenOffStart = SystemClock.uptimeMillis();
|
|
|
|
policy.screenTurnedOff(why);
|
|
try {
|
|
ActivityManagerNative.getDefault().goingToSleep();
|
|
} catch (RemoteException e) {
|
|
// ignore it.
|
|
}
|
|
|
|
if (mContext != null && ActivityManagerNative.isSystemReady()) {
|
|
mContext.sendOrderedBroadcast(mScreenOffIntent, null,
|
|
mScreenOffBroadcastDone, mHandler, 0, null, null);
|
|
} else {
|
|
synchronized (mLocks) {
|
|
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3,
|
|
mBroadcastWakeLock.mCount);
|
|
mBroadcastWakeLock.release();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// If we're in this case, then this handler is running for a previous
|
|
// paired transaction. mBroadcastWakeLock will already have been released.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
long mScreenOnStart;
|
|
private BroadcastReceiver mScreenOnBroadcastDone = new BroadcastReceiver() {
|
|
public void onReceive(Context context, Intent intent) {
|
|
synchronized (mLocks) {
|
|
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
|
|
SystemClock.uptimeMillis() - mScreenOnStart, mBroadcastWakeLock.mCount);
|
|
mBroadcastWakeLock.release();
|
|
}
|
|
}
|
|
};
|
|
|
|
private static class SamplingRateAdjuster {
|
|
private static final String CPU_DIR_PATH = "/sys/devices/system/cpu";
|
|
private static final String REL_SAMPLING_RATE_PATH = "cpufreq/ondemand/sampling_rate";
|
|
private static final String DEFAULT_RAMP_UP_SAMPLING_RATE = "500000";
|
|
private HashMap<File, String> mSamplingRateTable = null;
|
|
private HashMap<File, PrintWriter> mPrintWriterTable = null;
|
|
|
|
/**
|
|
* Checks if the sampling rate files are still readable and writable.
|
|
*/
|
|
private boolean checkSamplingRateTableValidity () {
|
|
Iterator<File> samplingRateFileIterator = mSamplingRateTable.keySet().iterator();
|
|
|
|
while (samplingRateFileIterator.hasNext()) {
|
|
try{
|
|
File samplingRateFile = samplingRateFileIterator.next();
|
|
|
|
if (!(samplingRateFile.canRead() && samplingRateFile.canWrite())) {
|
|
return false;
|
|
}
|
|
} catch (Exception exception) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Increases sampling rates for all cores. Sets them to the default ramp up rate.
|
|
*/
|
|
public void increaseSamplingRate () {
|
|
if (SystemProperties.getInt("dev.pm.dyn_samplingrate", 0) == 0) {
|
|
return;
|
|
}
|
|
|
|
if (mSamplingRateTable == null) {
|
|
populateSamplingRateTable();
|
|
}
|
|
|
|
if (mSamplingRateTable != null) {
|
|
if (!checkSamplingRateTableValidity()) {
|
|
mSamplingRateTable = null;
|
|
|
|
return;
|
|
}
|
|
|
|
Iterator<File> samplingRateFileIterator = mSamplingRateTable.keySet().iterator();
|
|
|
|
while (samplingRateFileIterator.hasNext()) {
|
|
try{
|
|
File samplingRateFile = samplingRateFileIterator.next();
|
|
PrintWriter printWriter = mPrintWriterTable.get(samplingRateFile);
|
|
|
|
printWriter.print(DEFAULT_RAMP_UP_SAMPLING_RATE);
|
|
printWriter.flush();
|
|
Log.i(TAG, "Increasing sampling rate.");
|
|
} catch (Exception exception) {
|
|
Log.e(TAG, exception.getMessage());
|
|
|
|
mSamplingRateTable = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Decreases sampling rates for all cores. Sets them to the saved rates.
|
|
*/
|
|
public void decreaseSamplingRate () {
|
|
if (SystemProperties.getInt("dev.pm.dyn_samplingrate", 0) == 0) {
|
|
return;
|
|
}
|
|
|
|
if (mSamplingRateTable != null) {
|
|
if (!checkSamplingRateTableValidity()) {
|
|
mSamplingRateTable = null;
|
|
|
|
return;
|
|
}
|
|
|
|
Iterator<File> samplingRateFileIterator = mSamplingRateTable.keySet().iterator();
|
|
|
|
while (samplingRateFileIterator.hasNext()) {
|
|
try{
|
|
File samplingRateFile = samplingRateFileIterator.next();
|
|
String samplingRate = mSamplingRateTable.get(samplingRateFile);
|
|
PrintWriter printWriter = mPrintWriterTable.get(samplingRateFile);
|
|
|
|
printWriter.print(samplingRate);
|
|
printWriter.flush();
|
|
Log.i(TAG, "Decreasing sampling rate.");
|
|
} catch (Exception exception) {
|
|
Log.e(TAG, exception.getMessage());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Populates the sampling rate table.
|
|
*/
|
|
private void populateSamplingRateTable () {
|
|
// Get a list of all directories in CPU_DIR_PATH
|
|
File dirCPU = new File(CPU_DIR_PATH);
|
|
|
|
if (!dirCPU.isDirectory()) {
|
|
Log.e(TAG, "populateSamplingRateTable failed.. doesn't exist.");
|
|
return;
|
|
}
|
|
|
|
File[] dirCPUCores = dirCPU.listFiles(new CPUFreqDirFileFilter());
|
|
|
|
if (dirCPUCores.length == 0) {
|
|
Log.e(TAG, "No CPUFreq directories found.");
|
|
return;
|
|
}
|
|
|
|
try{
|
|
File fileSamplingRateGeneric = new File(CPU_DIR_PATH + "/" + REL_SAMPLING_RATE_PATH);
|
|
|
|
if (fileSamplingRateGeneric.canRead() && fileSamplingRateGeneric.canWrite()) {
|
|
BufferedReader samplingRateReaderGeneric = new BufferedReader(new FileReader(fileSamplingRateGeneric));
|
|
|
|
if (mSamplingRateTable == null) {
|
|
mSamplingRateTable = new HashMap<File, String> ();
|
|
mPrintWriterTable = new HashMap<File, PrintWriter>();
|
|
}
|
|
|
|
mSamplingRateTable.put(fileSamplingRateGeneric, samplingRateReaderGeneric.readLine());
|
|
mPrintWriterTable.put(fileSamplingRateGeneric, new PrintWriter(fileSamplingRateGeneric));
|
|
samplingRateReaderGeneric.close();
|
|
} else {
|
|
// Check to make sure all sampling rate files are readable and writable.
|
|
int dirCPUCoresOffset;
|
|
|
|
for (dirCPUCoresOffset = 0; dirCPUCoresOffset < dirCPUCores.length; dirCPUCoresOffset++) {
|
|
File fileSamplingRate = new File(dirCPUCores[dirCPUCoresOffset].getPath() + "/" + REL_SAMPLING_RATE_PATH);
|
|
|
|
if (fileSamplingRate.canRead() && fileSamplingRate.canWrite()) {
|
|
BufferedReader samplingRateReader = new BufferedReader(new FileReader(fileSamplingRate));
|
|
|
|
if (mSamplingRateTable == null) {
|
|
mSamplingRateTable = new HashMap<File, String> ();
|
|
mPrintWriterTable = new HashMap<File, PrintWriter>();
|
|
}
|
|
|
|
mSamplingRateTable.put(fileSamplingRate, samplingRateReader.readLine());
|
|
mPrintWriterTable.put(fileSamplingRate, new PrintWriter(fileSamplingRate));
|
|
samplingRateReader.close();
|
|
}
|
|
}
|
|
}
|
|
} catch (Exception exception) {
|
|
// If any failure happens, make the sampling rate reference null.
|
|
Log.e(TAG, "Failed to get current sampling rates. " + exception.getMessage());
|
|
|
|
mSamplingRateTable = null;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Closes open files.
|
|
*/
|
|
protected void finalize () throws Throwable {
|
|
try {
|
|
if (mSamplingRateTable != null) {
|
|
Iterator<File> samplingRateFileIterator = mSamplingRateTable.keySet().iterator();
|
|
|
|
while (samplingRateFileIterator.hasNext()) {
|
|
File samplingRateFile = samplingRateFileIterator.next();
|
|
PrintWriter printWriter = mPrintWriterTable.get(samplingRateFile);
|
|
|
|
printWriter.close();
|
|
}
|
|
}
|
|
} catch (Exception exception) {
|
|
Log.e(TAG, "Error occurred while closing files.");
|
|
} finally {
|
|
super.finalize();
|
|
}
|
|
}
|
|
|
|
private static class CPUFreqDirFileFilter implements FileFilter {
|
|
private static final String PREFIX = "cpu";
|
|
|
|
public boolean accept (File file) {
|
|
// Check if the directory name is "cpux" where x is a number
|
|
String filename = file.getName();
|
|
|
|
if (filename.startsWith(PREFIX) && filename.length() > PREFIX.length()) {
|
|
String suffix = filename.substring(PREFIX.length());
|
|
|
|
try {
|
|
Integer.parseInt(suffix);
|
|
} catch (NumberFormatException numberFormatException) {
|
|
return false;
|
|
}
|
|
|
|
// All characters in the suffix are integers.
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
long mScreenOffStart;
|
|
private BroadcastReceiver mScreenOffBroadcastDone = new BroadcastReceiver() {
|
|
public void onReceive(Context context, Intent intent) {
|
|
synchronized (mLocks) {
|
|
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
|
|
SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount);
|
|
mBroadcastWakeLock.release();
|
|
|
|
if ((mPowerState & SCREEN_ON_BIT) == 0) {
|
|
// Increase sampling rate here.
|
|
if (mSamplingRateAdjuster == null) {
|
|
mSamplingRateAdjuster = new PowerManagerService.SamplingRateAdjuster();
|
|
}
|
|
|
|
mSamplingRateAdjuster.increaseSamplingRate();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void logPointerUpEvent() {
|
|
if (LOG_TOUCH_DOWNS) {
|
|
mTotalTouchDownTime += SystemClock.elapsedRealtime() - mLastTouchDown;
|
|
mLastTouchDown = 0;
|
|
}
|
|
}
|
|
|
|
void logPointerDownEvent() {
|
|
if (LOG_TOUCH_DOWNS) {
|
|
// If we are not already timing a down/up sequence
|
|
if (mLastTouchDown == 0) {
|
|
mLastTouchDown = SystemClock.elapsedRealtime();
|
|
mTouchCycles++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prevents the screen from turning on even if it *should* turn on due
|
|
* to a subsequent full wake lock being acquired.
|
|
* <p>
|
|
* This is a temporary hack that allows an activity to "cover up" any
|
|
* display glitches that happen during the activity's startup
|
|
* sequence. (Specifically, this API was added to work around a
|
|
* cosmetic bug in the "incoming call" sequence, where the lock screen
|
|
* would flicker briefly before the incoming call UI became visible.)
|
|
* TODO: There ought to be a more elegant way of doing this,
|
|
* probably by having the PowerManager and ActivityManager
|
|
* work together to let apps specify that the screen on/off
|
|
* state should be synchronized with the Activity lifecycle.
|
|
* <p>
|
|
* Note that calling preventScreenOn(true) will NOT turn the screen
|
|
* off if it's currently on. (This API only affects *future*
|
|
* acquisitions of full wake locks.)
|
|
* But calling preventScreenOn(false) WILL turn the screen on if
|
|
* it's currently off because of a prior preventScreenOn(true) call.
|
|
* <p>
|
|
* Any call to preventScreenOn(true) MUST be followed promptly by a call
|
|
* to preventScreenOn(false). In fact, if the preventScreenOn(false)
|
|
* call doesn't occur within 5 seconds, we'll turn the screen back on
|
|
* ourselves (and log a warning about it); this prevents a buggy app
|
|
* from disabling the screen forever.)
|
|
* <p>
|
|
* TODO: this feature should really be controlled by a new type of poke
|
|
* lock (rather than an IPowerManager call).
|
|
*/
|
|
public void preventScreenOn(boolean prevent) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
|
|
synchronized (mLocks) {
|
|
if (prevent) {
|
|
// First of all, grab a partial wake lock to
|
|
// make sure the CPU stays on during the entire
|
|
// preventScreenOn(true) -> preventScreenOn(false) sequence.
|
|
mPreventScreenOnPartialLock.acquire();
|
|
|
|
// Post a forceReenableScreen() call (for 5 seconds in the
|
|
// future) to make sure the matching preventScreenOn(false) call
|
|
// has happened by then.
|
|
mHandler.removeCallbacks(mForceReenableScreenTask);
|
|
mHandler.postDelayed(mForceReenableScreenTask, 5000);
|
|
|
|
// Finally, set the flag that prevents the screen from turning on.
|
|
// (Below, in setPowerState(), we'll check mPreventScreenOn and
|
|
// we *won't* call setScreenStateLocked(true) if it's set.)
|
|
mPreventScreenOn = true;
|
|
} else {
|
|
// (Re)enable the screen.
|
|
mPreventScreenOn = false;
|
|
|
|
// We're "undoing" a the prior preventScreenOn(true) call, so we
|
|
// no longer need the 5-second safeguard.
|
|
mHandler.removeCallbacks(mForceReenableScreenTask);
|
|
|
|
// Forcibly turn on the screen if it's supposed to be on. (This
|
|
// handles the case where the screen is currently off because of
|
|
// a prior preventScreenOn(true) call.)
|
|
if (!mProximitySensorActive && (mPowerState & SCREEN_ON_BIT) != 0) {
|
|
if (mSpew) {
|
|
Slog.d(TAG,
|
|
"preventScreenOn: turning on after a prior preventScreenOn(true)!");
|
|
}
|
|
int err = setScreenStateLocked(true);
|
|
if (err != 0) {
|
|
Slog.w(TAG, "preventScreenOn: error from setScreenStateLocked(): " + err);
|
|
}
|
|
}
|
|
|
|
// Release the partial wake lock that we held during the
|
|
// preventScreenOn(true) -> preventScreenOn(false) sequence.
|
|
mPreventScreenOnPartialLock.release();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setScreenBrightnessOverride(int brightness) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
|
|
if (mSpew) Slog.d(TAG, "setScreenBrightnessOverride " + brightness);
|
|
synchronized (mLocks) {
|
|
if (mScreenBrightnessOverride != brightness) {
|
|
mScreenBrightnessOverride = brightness;
|
|
if (isScreenOn()) {
|
|
updateLightsLocked(mPowerState, SCREEN_ON_BIT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setButtonBrightnessOverride(int brightness) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
|
|
if (mSpew) Slog.d(TAG, "setButtonBrightnessOverride " + brightness);
|
|
synchronized (mLocks) {
|
|
if (mButtonBrightnessOverride != brightness) {
|
|
mButtonBrightnessOverride = brightness;
|
|
if (isScreenOn()) {
|
|
updateLightsLocked(mPowerState, BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sanity-check that gets called 5 seconds after any call to
|
|
* preventScreenOn(true). This ensures that the original call
|
|
* is followed promptly by a call to preventScreenOn(false).
|
|
*/
|
|
private void forceReenableScreen() {
|
|
// We shouldn't get here at all if mPreventScreenOn is false, since
|
|
// we should have already removed any existing
|
|
// mForceReenableScreenTask messages...
|
|
if (!mPreventScreenOn) {
|
|
Slog.w(TAG, "forceReenableScreen: mPreventScreenOn is false, nothing to do");
|
|
return;
|
|
}
|
|
|
|
// Uh oh. It's been 5 seconds since a call to
|
|
// preventScreenOn(true) and we haven't re-enabled the screen yet.
|
|
// This means the app that called preventScreenOn(true) is either
|
|
// slow (i.e. it took more than 5 seconds to call preventScreenOn(false)),
|
|
// or buggy (i.e. it forgot to call preventScreenOn(false), or
|
|
// crashed before doing so.)
|
|
|
|
// Log a warning, and forcibly turn the screen back on.
|
|
Slog.w(TAG, "App called preventScreenOn(true) but didn't promptly reenable the screen! "
|
|
+ "Forcing the screen back on...");
|
|
preventScreenOn(false);
|
|
}
|
|
|
|
private Runnable mForceReenableScreenTask = new Runnable() {
|
|
public void run() {
|
|
forceReenableScreen();
|
|
}
|
|
};
|
|
|
|
private int setScreenStateLocked(boolean on) {
|
|
int err = Power.setScreenState(on);
|
|
if (err == 0) {
|
|
mLastScreenOnTime = (on ? SystemClock.elapsedRealtime() : 0);
|
|
if (mUseSoftwareAutoBrightness) {
|
|
enableLightSensor(on);
|
|
if (!on) {
|
|
// make sure button and key backlights are off too
|
|
mButtonLight.turnOff();
|
|
mKeyboardLight.turnOff();
|
|
// clear current value so we will update based on the new conditions
|
|
// when the sensor is reenabled.
|
|
mLightSensorValue = -1;
|
|
// reset our highest light sensor value when the screen turns off
|
|
mHighestLightSensorValue = -1;
|
|
}
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
private void setPowerState(int state)
|
|
{
|
|
setPowerState(state, false, WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT);
|
|
}
|
|
|
|
private void setPowerState(int newState, boolean noChangeLights, int reason)
|
|
{
|
|
synchronized (mLocks) {
|
|
int err;
|
|
|
|
if (mSpew) {
|
|
Slog.d(TAG, "setPowerState: mPowerState=0x" + Integer.toHexString(mPowerState)
|
|
+ " newState=0x" + Integer.toHexString(newState)
|
|
+ " noChangeLights=" + noChangeLights
|
|
+ " reason=" + reason);
|
|
}
|
|
|
|
if (noChangeLights) {
|
|
newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK);
|
|
}
|
|
if (mProximitySensorActive) {
|
|
// don't turn on the screen when the proximity sensor lock is held
|
|
newState = (newState & ~SCREEN_BRIGHT);
|
|
}
|
|
|
|
if (batteryIsLow()) {
|
|
newState |= BATTERY_LOW_BIT;
|
|
} else {
|
|
newState &= ~BATTERY_LOW_BIT;
|
|
}
|
|
if (newState == mPowerState) {
|
|
return;
|
|
}
|
|
|
|
if (!mBootCompleted && !mUseSoftwareAutoBrightness) {
|
|
newState |= ALL_BRIGHT;
|
|
}
|
|
|
|
boolean oldScreenOn = (mPowerState & SCREEN_ON_BIT) != 0;
|
|
boolean newScreenOn = (newState & SCREEN_ON_BIT) != 0;
|
|
|
|
if (mSpew) {
|
|
Slog.d(TAG, "setPowerState: mPowerState=" + mPowerState
|
|
+ " newState=" + newState + " noChangeLights=" + noChangeLights);
|
|
Slog.d(TAG, " oldKeyboardBright=" + ((mPowerState & KEYBOARD_BRIGHT_BIT) != 0)
|
|
+ " newKeyboardBright=" + ((newState & KEYBOARD_BRIGHT_BIT) != 0));
|
|
Slog.d(TAG, " oldScreenBright=" + ((mPowerState & SCREEN_BRIGHT_BIT) != 0)
|
|
+ " newScreenBright=" + ((newState & SCREEN_BRIGHT_BIT) != 0));
|
|
Slog.d(TAG, " oldButtonBright=" + ((mPowerState & BUTTON_BRIGHT_BIT) != 0)
|
|
+ " newButtonBright=" + ((newState & BUTTON_BRIGHT_BIT) != 0));
|
|
Slog.d(TAG, " oldScreenOn=" + oldScreenOn
|
|
+ " newScreenOn=" + newScreenOn);
|
|
Slog.d(TAG, " oldBatteryLow=" + ((mPowerState & BATTERY_LOW_BIT) != 0)
|
|
+ " newBatteryLow=" + ((newState & BATTERY_LOW_BIT) != 0));
|
|
}
|
|
|
|
if (mPowerState != newState) {
|
|
updateLightsLocked(newState, 0);
|
|
mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK);
|
|
}
|
|
|
|
if (oldScreenOn != newScreenOn) {
|
|
if (newScreenOn) {
|
|
// When the user presses the power button, we need to always send out the
|
|
// notification that it's going to sleep so the keyguard goes on. But
|
|
// we can't do that until the screen fades out, so we don't show the keyguard
|
|
// too early.
|
|
if (mStillNeedSleepNotification) {
|
|
sendNotificationLocked(false, WindowManagerPolicy.OFF_BECAUSE_OF_USER);
|
|
}
|
|
|
|
// Turn on the screen UNLESS there was a prior
|
|
// preventScreenOn(true) request. (Note that the lifetime
|
|
// of a single preventScreenOn() request is limited to 5
|
|
// seconds to prevent a buggy app from disabling the
|
|
// screen forever; see forceReenableScreen().)
|
|
boolean reallyTurnScreenOn = true;
|
|
if (mSpew) {
|
|
Slog.d(TAG, "- turning screen on... mPreventScreenOn = "
|
|
+ mPreventScreenOn);
|
|
}
|
|
|
|
if (mPreventScreenOn) {
|
|
if (mSpew) {
|
|
Slog.d(TAG, "- PREVENTING screen from really turning on!");
|
|
}
|
|
reallyTurnScreenOn = false;
|
|
}
|
|
if (reallyTurnScreenOn) {
|
|
// Increase sampling rate here.
|
|
if (mSamplingRateAdjuster == null) {
|
|
mSamplingRateAdjuster = new PowerManagerService.SamplingRateAdjuster();
|
|
}
|
|
|
|
mSamplingRateAdjuster.decreaseSamplingRate();
|
|
|
|
err = setScreenStateLocked(true);
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteScreenBrightness(getPreferredBrightness());
|
|
mBatteryStats.noteScreenOn();
|
|
} catch (RemoteException e) {
|
|
Slog.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
} else {
|
|
setScreenStateLocked(false);
|
|
// But continue as if we really did turn the screen on...
|
|
err = 0;
|
|
}
|
|
|
|
mLastTouchDown = 0;
|
|
mTotalTouchDownTime = 0;
|
|
mTouchCycles = 0;
|
|
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, reason,
|
|
mTotalTouchDownTime, mTouchCycles);
|
|
if (err == 0) {
|
|
mPowerState |= SCREEN_ON_BIT;
|
|
sendNotificationLocked(true, -1);
|
|
}
|
|
} else {
|
|
// cancel light sensor task
|
|
mHandler.removeCallbacks(mAutoBrightnessTask);
|
|
mScreenOffTime = SystemClock.elapsedRealtime();
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteScreenOff();
|
|
} catch (RemoteException e) {
|
|
Slog.w(TAG, "RemoteException calling noteScreenOff on BatteryStatsService", e);
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
mPowerState &= ~SCREEN_ON_BIT;
|
|
mScreenOffReason = reason;
|
|
if (!mScreenBrightness.animating) {
|
|
err = screenOffFinishedAnimatingLocked(reason);
|
|
} else {
|
|
err = 0;
|
|
mLastTouchDown = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
updateNativePowerStateLocked();
|
|
}
|
|
}
|
|
|
|
private void updateNativePowerStateLocked() {
|
|
nativeSetPowerState(
|
|
(mPowerState & SCREEN_ON_BIT) != 0,
|
|
(mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
|
|
}
|
|
|
|
private int screenOffFinishedAnimatingLocked(int reason) {
|
|
// I don't think we need to check the current state here because all of these
|
|
// Power.setScreenState and sendNotificationLocked can both handle being
|
|
// called multiple times in the same state. -joeo
|
|
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, reason, mTotalTouchDownTime,
|
|
mTouchCycles);
|
|
mLastTouchDown = 0;
|
|
int err = setScreenStateLocked(false);
|
|
if (err == 0) {
|
|
mScreenOffReason = reason;
|
|
sendNotificationLocked(false, reason);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
private boolean batteryIsLow() {
|
|
return (!mIsPowered &&
|
|
mBatteryService.getBatteryLevel() <= Power.LOW_BATTERY_THRESHOLD);
|
|
}
|
|
|
|
private void updateLightsLocked(int newState, int forceState) {
|
|
final int oldState = mPowerState;
|
|
if ((newState & SCREEN_ON_BIT) != 0) {
|
|
// Only turn on the buttons or keyboard if the screen is also on.
|
|
// We should never see the buttons on but not the screen.
|
|
newState = applyButtonState(newState);
|
|
newState = applyKeyboardState(newState);
|
|
}
|
|
final int realDifference = (newState ^ oldState);
|
|
final int difference = realDifference | forceState;
|
|
if (difference == 0) {
|
|
return;
|
|
}
|
|
|
|
int offMask = 0;
|
|
int dimMask = 0;
|
|
int onMask = 0;
|
|
|
|
int preferredBrightness = getPreferredBrightness();
|
|
|
|
if ((difference & KEYBOARD_BRIGHT_BIT) != 0) {
|
|
if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
|
|
offMask |= KEYBOARD_BRIGHT_BIT;
|
|
} else {
|
|
onMask |= KEYBOARD_BRIGHT_BIT;
|
|
}
|
|
}
|
|
|
|
if ((difference & BUTTON_BRIGHT_BIT) != 0) {
|
|
if ((newState & BUTTON_BRIGHT_BIT) == 0) {
|
|
offMask |= BUTTON_BRIGHT_BIT;
|
|
} else {
|
|
onMask |= BUTTON_BRIGHT_BIT;
|
|
}
|
|
}
|
|
|
|
if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
|
|
int nominalCurrentValue = -1;
|
|
// If there was an actual difference in the light state, then
|
|
// figure out the "ideal" current value based on the previous
|
|
// state. Otherwise, this is a change due to the brightness
|
|
// override, so we want to animate from whatever the current
|
|
// value is.
|
|
if ((realDifference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
|
|
switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) {
|
|
case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT:
|
|
nominalCurrentValue = preferredBrightness;
|
|
break;
|
|
case SCREEN_ON_BIT:
|
|
nominalCurrentValue = Power.BRIGHTNESS_DIM;
|
|
break;
|
|
case 0:
|
|
nominalCurrentValue = Power.BRIGHTNESS_OFF;
|
|
break;
|
|
case SCREEN_BRIGHT_BIT:
|
|
default:
|
|
// not possible
|
|
nominalCurrentValue = (int)mScreenBrightness.curValue;
|
|
break;
|
|
}
|
|
}
|
|
int brightness = preferredBrightness;
|
|
int steps = ANIM_STEPS;
|
|
if ((newState & SCREEN_BRIGHT_BIT) == 0) {
|
|
// dim or turn off backlight, depending on if the screen is on
|
|
// the scale is because the brightness ramp isn't linear and this biases
|
|
// it so the later parts take longer.
|
|
final float scale = 1.5f;
|
|
float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness);
|
|
if (ratio > 1.0f) ratio = 1.0f;
|
|
if ((newState & SCREEN_ON_BIT) == 0) {
|
|
if ((oldState & SCREEN_BRIGHT_BIT) != 0) {
|
|
// was bright
|
|
steps = ANIM_STEPS;
|
|
} else {
|
|
// was dim
|
|
steps = (int)(ANIM_STEPS*ratio*scale);
|
|
}
|
|
brightness = Power.BRIGHTNESS_OFF;
|
|
} else {
|
|
if ((oldState & SCREEN_ON_BIT) != 0) {
|
|
// was bright
|
|
steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale);
|
|
} else {
|
|
// was dim
|
|
steps = (int)(ANIM_STEPS*ratio);
|
|
}
|
|
if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {
|
|
// If the "stay on while plugged in" option is
|
|
// turned on, then the screen will often not
|
|
// automatically turn off while plugged in. To
|
|
// still have a sense of when it is inactive, we
|
|
// will then count going dim as turning off.
|
|
mScreenOffTime = SystemClock.elapsedRealtime();
|
|
}
|
|
brightness = Power.BRIGHTNESS_DIM;
|
|
}
|
|
}
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteScreenBrightness(brightness);
|
|
} catch (RemoteException e) {
|
|
// Nothing interesting to do.
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
mScreenBrightness.setTargetLocked(brightness, steps,
|
|
INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
|
|
}
|
|
|
|
if (mSpew) {
|
|
Slog.d(TAG, "offMask=0x" + Integer.toHexString(offMask)
|
|
+ " dimMask=0x" + Integer.toHexString(dimMask)
|
|
+ " onMask=0x" + Integer.toHexString(onMask)
|
|
+ " difference=0x" + Integer.toHexString(difference)
|
|
+ " realDifference=0x" + Integer.toHexString(realDifference)
|
|
+ " forceState=0x" + Integer.toHexString(forceState)
|
|
);
|
|
}
|
|
|
|
if (offMask != 0) {
|
|
if (mSpew) Slog.i(TAG, "Setting brightess off: " + offMask);
|
|
setLightBrightness(offMask, Power.BRIGHTNESS_OFF);
|
|
}
|
|
if (dimMask != 0) {
|
|
int brightness = Power.BRIGHTNESS_DIM;
|
|
if ((newState & BATTERY_LOW_BIT) != 0 &&
|
|
brightness > Power.BRIGHTNESS_LOW_BATTERY) {
|
|
brightness = Power.BRIGHTNESS_LOW_BATTERY;
|
|
}
|
|
if (mSpew) Slog.i(TAG, "Setting brightess dim " + brightness + ": " + dimMask);
|
|
setLightBrightness(dimMask, brightness);
|
|
}
|
|
if (onMask != 0) {
|
|
int brightness = getPreferredBrightness();
|
|
if ((newState & BATTERY_LOW_BIT) != 0 &&
|
|
brightness > Power.BRIGHTNESS_LOW_BATTERY) {
|
|
brightness = Power.BRIGHTNESS_LOW_BATTERY;
|
|
}
|
|
if (mSpew) Slog.i(TAG, "Setting brightess on " + brightness + ": " + onMask);
|
|
setLightBrightness(onMask, brightness);
|
|
}
|
|
}
|
|
|
|
private void setLightBrightness(int mask, int value) {
|
|
int brightnessMode = (mAutoBrightessEnabled
|
|
? LightsService.BRIGHTNESS_MODE_SENSOR
|
|
: LightsService.BRIGHTNESS_MODE_USER);
|
|
if ((mask & SCREEN_BRIGHT_BIT) != 0) {
|
|
mLcdLight.setBrightness(value, brightnessMode);
|
|
}
|
|
if ((mask & BUTTON_BRIGHT_BIT) != 0) {
|
|
mButtonLight.setBrightness(value);
|
|
}
|
|
if ((mask & KEYBOARD_BRIGHT_BIT) != 0) {
|
|
mKeyboardLight.setBrightness(value);
|
|
}
|
|
}
|
|
|
|
class BrightnessState implements Runnable {
|
|
final int mask;
|
|
|
|
boolean initialized;
|
|
int targetValue;
|
|
float curValue;
|
|
float delta;
|
|
boolean animating;
|
|
|
|
BrightnessState(int m) {
|
|
mask = m;
|
|
}
|
|
|
|
public void dump(PrintWriter pw, String prefix) {
|
|
pw.println(prefix + "animating=" + animating
|
|
+ " targetValue=" + targetValue
|
|
+ " curValue=" + curValue
|
|
+ " delta=" + delta);
|
|
}
|
|
|
|
void setTargetLocked(int target, int stepsToTarget, int initialValue,
|
|
int nominalCurrentValue) {
|
|
if (!initialized) {
|
|
initialized = true;
|
|
curValue = (float)initialValue;
|
|
} else if (targetValue == target) {
|
|
return;
|
|
}
|
|
targetValue = target;
|
|
delta = (targetValue -
|
|
(nominalCurrentValue >= 0 ? nominalCurrentValue : curValue))
|
|
/ stepsToTarget;
|
|
if (mSpew) {
|
|
String noticeMe = nominalCurrentValue == curValue ? "" : " ******************";
|
|
Slog.i(TAG, "setTargetLocked mask=" + mask + " curValue=" + curValue
|
|
+ " target=" + target + " targetValue=" + targetValue + " delta=" + delta
|
|
+ " nominalCurrentValue=" + nominalCurrentValue
|
|
+ noticeMe);
|
|
}
|
|
animating = true;
|
|
|
|
if (mSpew) {
|
|
Slog.i(TAG, "scheduling light animator");
|
|
}
|
|
mScreenOffHandler.removeCallbacks(this);
|
|
mScreenOffHandler.post(this);
|
|
}
|
|
|
|
boolean stepLocked() {
|
|
if (!animating) return false;
|
|
if (false && mSpew) {
|
|
Slog.i(TAG, "Step target " + mask + ": cur=" + curValue
|
|
+ " target=" + targetValue + " delta=" + delta);
|
|
}
|
|
curValue += delta;
|
|
int curIntValue = (int)curValue;
|
|
boolean more = true;
|
|
if (delta == 0) {
|
|
curValue = curIntValue = targetValue;
|
|
more = false;
|
|
} else if (delta > 0) {
|
|
if (curIntValue >= targetValue) {
|
|
curValue = curIntValue = targetValue;
|
|
more = false;
|
|
}
|
|
} else {
|
|
if (curIntValue <= targetValue) {
|
|
curValue = curIntValue = targetValue;
|
|
more = false;
|
|
}
|
|
}
|
|
if (mSpew) Slog.d(TAG, "Animating curIntValue=" + curIntValue + ": " + mask);
|
|
setLightBrightness(mask, curIntValue);
|
|
finishAnimationLocked(more, curIntValue);
|
|
return more;
|
|
}
|
|
|
|
void jumpToTargetLocked() {
|
|
if (mSpew) Slog.d(TAG, "jumpToTargetLocked targetValue=" + targetValue + ": " + mask);
|
|
setLightBrightness(mask, targetValue);
|
|
final int tv = targetValue;
|
|
curValue = tv;
|
|
targetValue = -1;
|
|
finishAnimationLocked(false, tv);
|
|
}
|
|
|
|
private void finishAnimationLocked(boolean more, int curIntValue) {
|
|
animating = more;
|
|
if (!more) {
|
|
if (mask == SCREEN_BRIGHT_BIT && curIntValue == Power.BRIGHTNESS_OFF) {
|
|
screenOffFinishedAnimatingLocked(mScreenOffReason);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void run() {
|
|
if (mAnimateScreenLights) {
|
|
synchronized (mLocks) {
|
|
long now = SystemClock.uptimeMillis();
|
|
boolean more = mScreenBrightness.stepLocked();
|
|
if (more) {
|
|
mScreenOffHandler.postAtTime(this, now+(1000/60));
|
|
}
|
|
}
|
|
} else {
|
|
synchronized (mLocks) {
|
|
// we're turning off
|
|
final boolean animate = animating && targetValue == Power.BRIGHTNESS_OFF;
|
|
if (animate) {
|
|
// It's pretty scary to hold mLocks for this long, and we should
|
|
// redesign this, but it works for now.
|
|
nativeStartSurfaceFlingerAnimation(
|
|
mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR
|
|
? 0 : mAnimationSetting);
|
|
}
|
|
mScreenBrightness.jumpToTargetLocked();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private int getPreferredBrightness() {
|
|
try {
|
|
if (mScreenBrightnessOverride >= 0) {
|
|
return mScreenBrightnessOverride;
|
|
} else if (mLightSensorScreenBrightness >= 0 && mUseSoftwareAutoBrightness
|
|
&& mAutoBrightessEnabled) {
|
|
return mLightSensorScreenBrightness;
|
|
}
|
|
final int brightness = Settings.System.getInt(mContext.getContentResolver(),
|
|
SCREEN_BRIGHTNESS);
|
|
// Don't let applications turn the screen all the way off
|
|
return Math.max(brightness, Power.BRIGHTNESS_DIM);
|
|
} catch (SettingNotFoundException snfe) {
|
|
return Power.BRIGHTNESS_ON;
|
|
}
|
|
}
|
|
|
|
private int applyButtonState(int state) {
|
|
int brightness = -1;
|
|
if ((state & BATTERY_LOW_BIT) != 0) {
|
|
// do not override brightness if the battery is low
|
|
return state;
|
|
}
|
|
if (mButtonBrightnessOverride >= 0) {
|
|
brightness = mButtonBrightnessOverride;
|
|
} else if (mLightSensorButtonBrightness >= 0 && mUseSoftwareAutoBrightness) {
|
|
brightness = mLightSensorButtonBrightness;
|
|
}
|
|
if (brightness > 0) {
|
|
return state | BUTTON_BRIGHT_BIT;
|
|
} else if (brightness == 0) {
|
|
return state & ~BUTTON_BRIGHT_BIT;
|
|
} else {
|
|
return state;
|
|
}
|
|
}
|
|
|
|
private int applyKeyboardState(int state) {
|
|
int brightness = -1;
|
|
if ((state & BATTERY_LOW_BIT) != 0) {
|
|
// do not override brightness if the battery is low
|
|
return state;
|
|
}
|
|
if (!mKeyboardVisible) {
|
|
brightness = 0;
|
|
} else if (mButtonBrightnessOverride >= 0) {
|
|
brightness = mButtonBrightnessOverride;
|
|
} else if (mLightSensorKeyboardBrightness >= 0 && mUseSoftwareAutoBrightness) {
|
|
brightness = mLightSensorKeyboardBrightness;
|
|
}
|
|
if (brightness > 0) {
|
|
return state | KEYBOARD_BRIGHT_BIT;
|
|
} else if (brightness == 0) {
|
|
return state & ~KEYBOARD_BRIGHT_BIT;
|
|
} else {
|
|
return state;
|
|
}
|
|
}
|
|
|
|
public boolean isScreenOn() {
|
|
synchronized (mLocks) {
|
|
return (mPowerState & SCREEN_ON_BIT) != 0;
|
|
}
|
|
}
|
|
|
|
boolean isScreenBright() {
|
|
synchronized (mLocks) {
|
|
return (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT;
|
|
}
|
|
}
|
|
|
|
private boolean isScreenTurningOffLocked() {
|
|
return (mScreenBrightness.animating && mScreenBrightness.targetValue == 0);
|
|
}
|
|
|
|
private boolean shouldLog(long time) {
|
|
synchronized (mLocks) {
|
|
if (time > (mWarningSpewThrottleTime + (60*60*1000))) {
|
|
mWarningSpewThrottleTime = time;
|
|
mWarningSpewThrottleCount = 0;
|
|
return true;
|
|
} else if (mWarningSpewThrottleCount < 30) {
|
|
mWarningSpewThrottleCount++;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void forceUserActivityLocked() {
|
|
if (isScreenTurningOffLocked()) {
|
|
// cancel animation so userActivity will succeed
|
|
mScreenBrightness.animating = false;
|
|
}
|
|
boolean savedActivityAllowed = mUserActivityAllowed;
|
|
mUserActivityAllowed = true;
|
|
userActivity(SystemClock.uptimeMillis(), false);
|
|
mUserActivityAllowed = savedActivityAllowed;
|
|
}
|
|
|
|
public void userActivityWithForce(long time, boolean noChangeLights, boolean force) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
userActivity(time, -1, noChangeLights, OTHER_EVENT, force);
|
|
}
|
|
|
|
public void userActivity(long time, boolean noChangeLights) {
|
|
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
|
|
!= PackageManager.PERMISSION_GRANTED) {
|
|
if (shouldLog(time)) {
|
|
Slog.w(TAG, "Caller does not have DEVICE_POWER permission. pid="
|
|
+ Binder.getCallingPid() + " uid=" + Binder.getCallingUid());
|
|
}
|
|
return;
|
|
}
|
|
|
|
userActivity(time, -1, noChangeLights, OTHER_EVENT, false);
|
|
}
|
|
|
|
public void userActivity(long time, boolean noChangeLights, int eventType) {
|
|
userActivity(time, -1, noChangeLights, eventType, false);
|
|
}
|
|
|
|
public void userActivity(long time, boolean noChangeLights, int eventType, boolean force) {
|
|
userActivity(time, -1, noChangeLights, eventType, force);
|
|
}
|
|
|
|
/*
|
|
* Reset the user activity timeout to now + timeout. This overrides whatever else is going
|
|
* on with user activity. Don't use this function.
|
|
*/
|
|
public void clearUserActivityTimeout(long now, long timeout) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
Slog.i(TAG, "clearUserActivity for " + timeout + "ms from now");
|
|
userActivity(now, timeout, false, OTHER_EVENT, false);
|
|
}
|
|
|
|
private void userActivity(long time, long timeoutOverride, boolean noChangeLights,
|
|
int eventType, boolean force) {
|
|
|
|
if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)
|
|
&& (eventType == CHEEK_EVENT)) {
|
|
if (false) {
|
|
Slog.d(TAG, "dropping cheek event mPokey=0x" + Integer.toHexString(mPokey));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (((mPokey & POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS) != 0)
|
|
&& (eventType == TOUCH_EVENT || eventType == TOUCH_UP_EVENT
|
|
|| eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT)) {
|
|
if (false) {
|
|
Slog.d(TAG, "dropping touch mPokey=0x" + Integer.toHexString(mPokey));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (false) {
|
|
if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)) {
|
|
Slog.d(TAG, "userActivity !!!");//, new RuntimeException());
|
|
} else {
|
|
Slog.d(TAG, "mPokey=0x" + Integer.toHexString(mPokey));
|
|
}
|
|
}
|
|
|
|
synchronized (mLocks) {
|
|
if (mSpew) {
|
|
Slog.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time
|
|
+ " mUserActivityAllowed=" + mUserActivityAllowed
|
|
+ " mUserState=0x" + Integer.toHexString(mUserState)
|
|
+ " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)
|
|
+ " mProximitySensorActive=" + mProximitySensorActive
|
|
+ " timeoutOverride=" + timeoutOverride
|
|
+ " force=" + force);
|
|
}
|
|
// ignore user activity if we are in the process of turning off the screen
|
|
if (isScreenTurningOffLocked()) {
|
|
Slog.d(TAG, "ignoring user activity while turning off screen");
|
|
return;
|
|
}
|
|
// Disable proximity sensor if if user presses power key while we are in the
|
|
// "waiting for proximity sensor to go negative" state.
|
|
if (mProximitySensorActive && mProximityWakeLockCount == 0) {
|
|
mProximitySensorActive = false;
|
|
}
|
|
if (mLastEventTime <= time || force) {
|
|
mLastEventTime = time;
|
|
if ((mUserActivityAllowed && !mProximitySensorActive) || force) {
|
|
// Only turn on button backlights if a button was pressed
|
|
// and auto brightness is disabled
|
|
if (eventType == BUTTON_EVENT && !mUseSoftwareAutoBrightness) {
|
|
mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
|
|
} else {
|
|
// don't clear button/keyboard backlights when the screen is touched.
|
|
mUserState |= SCREEN_BRIGHT;
|
|
}
|
|
|
|
int uid = Binder.getCallingUid();
|
|
long ident = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteUserActivity(uid, eventType);
|
|
} catch (RemoteException e) {
|
|
// Ignore
|
|
} finally {
|
|
Binder.restoreCallingIdentity(ident);
|
|
}
|
|
|
|
mWakeLockState = mLocks.reactivateScreenLocksLocked();
|
|
setPowerState(mUserState | mWakeLockState, noChangeLights,
|
|
WindowManagerPolicy.OFF_BECAUSE_OF_USER);
|
|
setTimeoutLocked(time, timeoutOverride, SCREEN_BRIGHT);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mPolicy != null) {
|
|
mPolicy.userActivity();
|
|
}
|
|
}
|
|
|
|
private int getAutoBrightnessValue(int sensorValue, int[] values) {
|
|
try {
|
|
int i;
|
|
for (i = 0; i < mAutoBrightnessLevels.length; i++) {
|
|
if (sensorValue < mAutoBrightnessLevels[i]) {
|
|
break;
|
|
}
|
|
}
|
|
return values[i];
|
|
} catch (Exception e) {
|
|
// guard against null pointer or index out of bounds errors
|
|
Slog.e(TAG, "getAutoBrightnessValue", e);
|
|
return 255;
|
|
}
|
|
}
|
|
|
|
private Runnable mProximityTask = new Runnable() {
|
|
public void run() {
|
|
synchronized (mLocks) {
|
|
if (mProximityPendingValue != -1) {
|
|
proximityChangedLocked(mProximityPendingValue == 1);
|
|
mProximityPendingValue = -1;
|
|
}
|
|
if (mProximityPartialLock.isHeld()) {
|
|
mProximityPartialLock.release();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
private Runnable mAutoBrightnessTask = new Runnable() {
|
|
public void run() {
|
|
synchronized (mLocks) {
|
|
int value = (int)mLightSensorPendingValue;
|
|
if (value >= 0) {
|
|
mLightSensorPendingValue = -1;
|
|
lightSensorChangedLocked(value);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
private void dockStateChanged(int state) {
|
|
synchronized (mLocks) {
|
|
mIsDocked = (state != Intent.EXTRA_DOCK_STATE_UNDOCKED);
|
|
if (mIsDocked) {
|
|
mHighestLightSensorValue = -1;
|
|
}
|
|
if ((mPowerState & SCREEN_ON_BIT) != 0) {
|
|
// force lights recalculation
|
|
int value = (int)mLightSensorValue;
|
|
mLightSensorValue = -1;
|
|
lightSensorChangedLocked(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void lightSensorChangedLocked(int value) {
|
|
if (mDebugLightSensor) {
|
|
Slog.d(TAG, "lightSensorChangedLocked " + value);
|
|
}
|
|
|
|
// Don't do anything if the screen is off.
|
|
if ((mPowerState & SCREEN_ON_BIT) == 0) {
|
|
if (mDebugLightSensor) {
|
|
Slog.d(TAG, "dropping lightSensorChangedLocked because screen is off");
|
|
}
|
|
return;
|
|
}
|
|
|
|
// do not allow light sensor value to decrease
|
|
if (mHighestLightSensorValue < value) {
|
|
mHighestLightSensorValue = value;
|
|
}
|
|
|
|
if (mLightSensorValue != value) {
|
|
mLightSensorValue = value;
|
|
if ((mPowerState & BATTERY_LOW_BIT) == 0) {
|
|
// use maximum light sensor value seen since screen went on for LCD to avoid flicker
|
|
// we only do this if we are undocked, since lighting should be stable when
|
|
// stationary in a dock.
|
|
int lcdValue = getAutoBrightnessValue(
|
|
(mIsDocked ? value : mHighestLightSensorValue),
|
|
mLcdBacklightValues);
|
|
int buttonValue = getAutoBrightnessValue(value, mButtonBacklightValues);
|
|
int keyboardValue;
|
|
if (mKeyboardVisible) {
|
|
keyboardValue = getAutoBrightnessValue(value, mKeyboardBacklightValues);
|
|
} else {
|
|
keyboardValue = 0;
|
|
}
|
|
mLightSensorScreenBrightness = lcdValue;
|
|
mLightSensorButtonBrightness = buttonValue;
|
|
mLightSensorKeyboardBrightness = keyboardValue;
|
|
|
|
if (mDebugLightSensor) {
|
|
Slog.d(TAG, "lcdValue " + lcdValue);
|
|
Slog.d(TAG, "buttonValue " + buttonValue);
|
|
Slog.d(TAG, "keyboardValue " + keyboardValue);
|
|
}
|
|
|
|
if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) {
|
|
mScreenBrightness.setTargetLocked(lcdValue, AUTOBRIGHTNESS_ANIM_STEPS,
|
|
INITIAL_SCREEN_BRIGHTNESS, (int)mScreenBrightness.curValue);
|
|
}
|
|
if (mButtonBrightnessOverride < 0) {
|
|
mButtonLight.setBrightness(buttonValue);
|
|
}
|
|
if (mButtonBrightnessOverride < 0 || !mKeyboardVisible) {
|
|
mKeyboardLight.setBrightness(keyboardValue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The user requested that we go to sleep (probably with the power button).
|
|
* This overrides all wake locks that are held.
|
|
*/
|
|
public void goToSleep(long time)
|
|
{
|
|
goToSleepWithReason(time, WindowManagerPolicy.OFF_BECAUSE_OF_USER);
|
|
}
|
|
|
|
/**
|
|
* The user requested that we go to sleep (probably with the power button).
|
|
* This overrides all wake locks that are held.
|
|
*/
|
|
public void goToSleepWithReason(long time, int reason)
|
|
{
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
synchronized (mLocks) {
|
|
goToSleepLocked(time, reason);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reboot the device immediately, passing 'reason' (may be null)
|
|
* to the underlying __reboot system call. Should not return.
|
|
*/
|
|
public void reboot(String reason)
|
|
{
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
|
|
|
|
if (mHandler == null || !ActivityManagerNative.isSystemReady()) {
|
|
throw new IllegalStateException("Too early to call reboot()");
|
|
}
|
|
|
|
final String finalReason = reason;
|
|
Runnable runnable = new Runnable() {
|
|
public void run() {
|
|
synchronized (this) {
|
|
ShutdownThread.reboot(mContext, finalReason, false);
|
|
}
|
|
|
|
}
|
|
};
|
|
// ShutdownThread must run on a looper capable of displaying the UI.
|
|
mHandler.post(runnable);
|
|
|
|
// PowerManager.reboot() is documented not to return so just wait for the inevitable.
|
|
synchronized (runnable) {
|
|
while (true) {
|
|
try {
|
|
runnable.wait();
|
|
} catch (InterruptedException e) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crash the runtime (causing a complete restart of the Android framework).
|
|
* Requires REBOOT permission. Mostly for testing. Should not return.
|
|
*/
|
|
public void crash(final String message)
|
|
{
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
|
|
Thread t = new Thread("PowerManagerService.crash()") {
|
|
public void run() { throw new RuntimeException(message); }
|
|
};
|
|
try {
|
|
t.start();
|
|
t.join();
|
|
} catch (InterruptedException e) {
|
|
Log.wtf(TAG, e);
|
|
}
|
|
}
|
|
|
|
private void goToSleepLocked(long time, int reason) {
|
|
|
|
if (mLastEventTime <= time) {
|
|
mLastEventTime = time;
|
|
// cancel all of the wake locks
|
|
mWakeLockState = SCREEN_OFF;
|
|
int N = mLocks.size();
|
|
int numCleared = 0;
|
|
boolean proxLock = false;
|
|
for (int i=0; i<N; i++) {
|
|
WakeLock wl = mLocks.get(i);
|
|
if (isScreenLock(wl.flags)) {
|
|
if (((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
|
|
&& reason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
|
|
proxLock = true;
|
|
} else {
|
|
mLocks.get(i).activated = false;
|
|
numCleared++;
|
|
}
|
|
}
|
|
}
|
|
if (!proxLock) {
|
|
mProxIgnoredBecauseScreenTurnedOff = true;
|
|
if (mDebugProximitySensor) {
|
|
Slog.d(TAG, "setting mProxIgnoredBecauseScreenTurnedOff");
|
|
}
|
|
}
|
|
EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numCleared);
|
|
mStillNeedSleepNotification = true;
|
|
mUserState = SCREEN_OFF;
|
|
setPowerState(SCREEN_OFF, false, reason);
|
|
cancelTimerLocked();
|
|
}
|
|
}
|
|
|
|
public long timeSinceScreenOn() {
|
|
synchronized (mLocks) {
|
|
if ((mPowerState & SCREEN_ON_BIT) != 0) {
|
|
return 0;
|
|
}
|
|
return SystemClock.elapsedRealtime() - mScreenOffTime;
|
|
}
|
|
}
|
|
|
|
public void setKeyboardVisibility(boolean visible) {
|
|
synchronized (mLocks) {
|
|
if (mSpew) {
|
|
Slog.d(TAG, "setKeyboardVisibility: " + visible);
|
|
}
|
|
if (mKeyboardVisible != visible) {
|
|
mKeyboardVisible = visible;
|
|
// don't signal user activity if the screen is off; other code
|
|
// will take care of turning on due to a true change to the lid
|
|
// switch and synchronized with the lock screen.
|
|
if ((mPowerState & SCREEN_ON_BIT) != 0) {
|
|
if (mUseSoftwareAutoBrightness) {
|
|
// force recompute of backlight values
|
|
if (mLightSensorValue >= 0) {
|
|
int value = (int)mLightSensorValue;
|
|
mLightSensorValue = -1;
|
|
lightSensorChangedLocked(value);
|
|
}
|
|
}
|
|
userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* When the keyguard is up, it manages the power state, and userActivity doesn't do anything.
|
|
* When disabling user activity we also reset user power state so the keyguard can reset its
|
|
* short screen timeout when keyguard is unhidden.
|
|
*/
|
|
public void enableUserActivity(boolean enabled) {
|
|
if (mSpew) {
|
|
Slog.d(TAG, "enableUserActivity " + enabled);
|
|
}
|
|
synchronized (mLocks) {
|
|
mUserActivityAllowed = enabled;
|
|
if (!enabled) {
|
|
// cancel timeout and clear mUserState so the keyguard can set a short timeout
|
|
setTimeoutLocked(SystemClock.uptimeMillis(), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void setScreenBrightnessMode(int mode) {
|
|
boolean enabled = (mode == SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
|
|
if (mUseSoftwareAutoBrightness && mAutoBrightessEnabled != enabled) {
|
|
mAutoBrightessEnabled = enabled;
|
|
if (isScreenOn()) {
|
|
// force recompute of backlight values
|
|
if (mLightSensorValue >= 0) {
|
|
int value = (int)mLightSensorValue;
|
|
mLightSensorValue = -1;
|
|
lightSensorChangedLocked(value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Sets the screen off timeouts:
|
|
* mKeylightDelay
|
|
* mDimDelay
|
|
* mScreenOffDelay
|
|
* */
|
|
private void setScreenOffTimeoutsLocked() {
|
|
if ((mPokey & POKE_LOCK_SHORT_TIMEOUT) != 0) {
|
|
mKeylightDelay = mShortKeylightDelay; // Configurable via secure settings
|
|
mDimDelay = -1;
|
|
mScreenOffDelay = 0;
|
|
} else if ((mPokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0) {
|
|
mKeylightDelay = MEDIUM_KEYLIGHT_DELAY;
|
|
mDimDelay = -1;
|
|
mScreenOffDelay = 0;
|
|
} else {
|
|
int totalDelay = mScreenOffTimeoutSetting;
|
|
if (totalDelay > mMaximumScreenOffTimeout) {
|
|
totalDelay = mMaximumScreenOffTimeout;
|
|
}
|
|
mKeylightDelay = LONG_KEYLIGHT_DELAY;
|
|
if (totalDelay < 0) {
|
|
mScreenOffDelay = Integer.MAX_VALUE;
|
|
} else if (mKeylightDelay < totalDelay) {
|
|
// subtract the time that the keylight delay. This will give us the
|
|
// remainder of the time that we need to sleep to get the accurate
|
|
// screen off timeout.
|
|
mScreenOffDelay = totalDelay - mKeylightDelay;
|
|
} else {
|
|
mScreenOffDelay = 0;
|
|
}
|
|
if (mDimScreen && totalDelay >= (LONG_KEYLIGHT_DELAY + LONG_DIM_TIME)) {
|
|
mDimDelay = mScreenOffDelay - LONG_DIM_TIME;
|
|
mScreenOffDelay = LONG_DIM_TIME;
|
|
} else {
|
|
mDimDelay = -1;
|
|
}
|
|
}
|
|
if (mSpew) {
|
|
Slog.d(TAG, "setScreenOffTimeouts mKeylightDelay=" + mKeylightDelay
|
|
+ " mDimDelay=" + mDimDelay + " mScreenOffDelay=" + mScreenOffDelay
|
|
+ " mDimScreen=" + mDimScreen);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Refreshes cached secure settings. Called once on startup, and
|
|
* on subsequent changes to secure settings.
|
|
*/
|
|
private void updateSettingsValues() {
|
|
mShortKeylightDelay = Settings.Secure.getInt(
|
|
mContext.getContentResolver(),
|
|
Settings.Secure.SHORT_KEYLIGHT_DELAY_MS,
|
|
SHORT_KEYLIGHT_DELAY_DEFAULT);
|
|
// Slog.i(TAG, "updateSettingsValues(): mShortKeylightDelay now " + mShortKeylightDelay);
|
|
}
|
|
|
|
private class LockList extends ArrayList<WakeLock>
|
|
{
|
|
void addLock(WakeLock wl)
|
|
{
|
|
int index = getIndex(wl.binder);
|
|
if (index < 0) {
|
|
this.add(wl);
|
|
}
|
|
}
|
|
|
|
WakeLock removeLock(IBinder binder)
|
|
{
|
|
int index = getIndex(binder);
|
|
if (index >= 0) {
|
|
return this.remove(index);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
int getIndex(IBinder binder)
|
|
{
|
|
int N = this.size();
|
|
for (int i=0; i<N; i++) {
|
|
if (this.get(i).binder == binder) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int gatherState()
|
|
{
|
|
int result = 0;
|
|
int N = this.size();
|
|
for (int i=0; i<N; i++) {
|
|
WakeLock wl = this.get(i);
|
|
if (wl.activated) {
|
|
if (isScreenLock(wl.flags)) {
|
|
result |= wl.minState;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int reactivateScreenLocksLocked()
|
|
{
|
|
int result = 0;
|
|
int N = this.size();
|
|
for (int i=0; i<N; i++) {
|
|
WakeLock wl = this.get(i);
|
|
if (isScreenLock(wl.flags)) {
|
|
wl.activated = true;
|
|
result |= wl.minState;
|
|
}
|
|
}
|
|
if (mDebugProximitySensor) {
|
|
Slog.d(TAG, "reactivateScreenLocksLocked mProxIgnoredBecauseScreenTurnedOff="
|
|
+ mProxIgnoredBecauseScreenTurnedOff);
|
|
}
|
|
mProxIgnoredBecauseScreenTurnedOff = false;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
void setPolicy(WindowManagerPolicy p) {
|
|
synchronized (mLocks) {
|
|
mPolicy = p;
|
|
mLocks.notifyAll();
|
|
}
|
|
}
|
|
|
|
WindowManagerPolicy getPolicyLocked() {
|
|
while (mPolicy == null || !mDoneBooting) {
|
|
try {
|
|
mLocks.wait();
|
|
} catch (InterruptedException e) {
|
|
// Ignore
|
|
}
|
|
}
|
|
return mPolicy;
|
|
}
|
|
|
|
void systemReady() {
|
|
mSensorManager = new SensorManager(mHandlerThread.getLooper());
|
|
mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
|
// don't bother with the light sensor if auto brightness is handled in hardware
|
|
if (mUseSoftwareAutoBrightness) {
|
|
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
|
|
enableLightSensor(true);
|
|
}
|
|
|
|
// wait until sensors are enabled before turning on screen.
|
|
// some devices will not activate the light sensor properly on boot
|
|
// unless we do this.
|
|
if (mUseSoftwareAutoBrightness) {
|
|
// turn the screen on
|
|
setPowerState(SCREEN_BRIGHT);
|
|
} else {
|
|
// turn everything on
|
|
setPowerState(ALL_BRIGHT);
|
|
}
|
|
|
|
synchronized (mLocks) {
|
|
Slog.d(TAG, "system ready!");
|
|
mDoneBooting = true;
|
|
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteScreenBrightness(getPreferredBrightness());
|
|
mBatteryStats.noteScreenOn();
|
|
} catch (RemoteException e) {
|
|
// Nothing interesting to do.
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
}
|
|
}
|
|
|
|
void bootCompleted() {
|
|
Slog.d(TAG, "bootCompleted");
|
|
synchronized (mLocks) {
|
|
mBootCompleted = true;
|
|
userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
|
|
updateWakeLockLocked();
|
|
mLocks.notifyAll();
|
|
}
|
|
}
|
|
|
|
// for watchdog
|
|
public void monitor() {
|
|
synchronized (mLocks) { }
|
|
}
|
|
|
|
public int getSupportedWakeLockFlags() {
|
|
int result = PowerManager.PARTIAL_WAKE_LOCK
|
|
| PowerManager.FULL_WAKE_LOCK
|
|
| PowerManager.SCREEN_DIM_WAKE_LOCK
|
|
| PowerManager.CPU_MAX_WAKE_LOCK;
|
|
|
|
if (mProximitySensor != null) {
|
|
result |= PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public void setBacklightBrightness(int brightness) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
// Don't let applications turn the screen all the way off
|
|
synchronized (mLocks) {
|
|
brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
|
|
mLcdLight.setBrightness(brightness);
|
|
mKeyboardLight.setBrightness(mKeyboardVisible ? brightness : 0);
|
|
mButtonLight.setBrightness(brightness);
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mBatteryStats.noteScreenBrightness(brightness);
|
|
} catch (RemoteException e) {
|
|
Slog.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e);
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
|
|
// update our animation state
|
|
synchronized (mLocks) {
|
|
mScreenBrightness.targetValue = brightness;
|
|
mScreenBrightness.jumpToTargetLocked();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setAttentionLight(boolean on, int color) {
|
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
|
|
mAttentionLight.setFlashing(color, LightsService.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
|
|
}
|
|
|
|
private void enableProximityLockLocked() {
|
|
if (mDebugProximitySensor) {
|
|
Slog.d(TAG, "enableProximityLockLocked");
|
|
}
|
|
if (!mProximitySensorEnabled) {
|
|
// clear calling identity so sensor manager battery stats are accurate
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mSensorManager.registerListener(mProximityListener, mProximitySensor,
|
|
SensorManager.SENSOR_DELAY_NORMAL);
|
|
mProximitySensorEnabled = true;
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void disableProximityLockLocked() {
|
|
if (mDebugProximitySensor) {
|
|
Slog.d(TAG, "disableProximityLockLocked");
|
|
}
|
|
if (mProximitySensorEnabled) {
|
|
// clear calling identity so sensor manager battery stats are accurate
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
mSensorManager.unregisterListener(mProximityListener);
|
|
mHandler.removeCallbacks(mProximityTask);
|
|
if (mProximityPartialLock.isHeld()) {
|
|
mProximityPartialLock.release();
|
|
}
|
|
mProximitySensorEnabled = false;
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
if (mProximitySensorActive) {
|
|
mProximitySensorActive = false;
|
|
if (mDebugProximitySensor) {
|
|
Slog.d(TAG, "disableProximityLockLocked mProxIgnoredBecauseScreenTurnedOff="
|
|
+ mProxIgnoredBecauseScreenTurnedOff);
|
|
}
|
|
if (!mProxIgnoredBecauseScreenTurnedOff) {
|
|
forceUserActivityLocked();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void proximityChangedLocked(boolean active) {
|
|
if (mDebugProximitySensor) {
|
|
Slog.d(TAG, "proximityChangedLocked, active: " + active);
|
|
}
|
|
if (!mProximitySensorEnabled) {
|
|
Slog.d(TAG, "Ignoring proximity change after sensor is disabled");
|
|
return;
|
|
}
|
|
if (active) {
|
|
if (mDebugProximitySensor) {
|
|
Slog.d(TAG, "b mProxIgnoredBecauseScreenTurnedOff="
|
|
+ mProxIgnoredBecauseScreenTurnedOff);
|
|
}
|
|
if (!mProxIgnoredBecauseScreenTurnedOff) {
|
|
goToSleepLocked(SystemClock.uptimeMillis(),
|
|
WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR);
|
|
}
|
|
mProximitySensorActive = true;
|
|
} else {
|
|
// proximity sensor negative events trigger as user activity.
|
|
// temporarily set mUserActivityAllowed to true so this will work
|
|
// even when the keyguard is on.
|
|
mProximitySensorActive = false;
|
|
if (mDebugProximitySensor) {
|
|
Slog.d(TAG, "b mProxIgnoredBecauseScreenTurnedOff="
|
|
+ mProxIgnoredBecauseScreenTurnedOff);
|
|
}
|
|
if (!mProxIgnoredBecauseScreenTurnedOff) {
|
|
forceUserActivityLocked();
|
|
}
|
|
|
|
if (mProximityWakeLockCount == 0) {
|
|
// disable sensor if we have no listeners left after proximity negative
|
|
disableProximityLockLocked();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void enableLightSensor(boolean enable) {
|
|
if (mDebugLightSensor) {
|
|
Slog.d(TAG, "enableLightSensor " + enable);
|
|
}
|
|
if (mSensorManager != null && mLightSensorEnabled != enable) {
|
|
mLightSensorEnabled = enable;
|
|
// clear calling identity so sensor manager battery stats are accurate
|
|
long identity = Binder.clearCallingIdentity();
|
|
try {
|
|
if (enable) {
|
|
mSensorManager.registerListener(mLightListener, mLightSensor,
|
|
SensorManager.SENSOR_DELAY_NORMAL);
|
|
} else {
|
|
mSensorManager.unregisterListener(mLightListener);
|
|
mHandler.removeCallbacks(mAutoBrightnessTask);
|
|
}
|
|
} finally {
|
|
Binder.restoreCallingIdentity(identity);
|
|
}
|
|
}
|
|
}
|
|
|
|
SensorEventListener mProximityListener = new SensorEventListener() {
|
|
public void onSensorChanged(SensorEvent event) {
|
|
long milliseconds = SystemClock.elapsedRealtime();
|
|
synchronized (mLocks) {
|
|
float distance = event.values[0];
|
|
long timeSinceLastEvent = milliseconds - mLastProximityEventTime;
|
|
mLastProximityEventTime = milliseconds;
|
|
mHandler.removeCallbacks(mProximityTask);
|
|
boolean proximityTaskQueued = false;
|
|
|
|
// compare against getMaximumRange to support sensors that only return 0 or 1
|
|
boolean active = (distance >= 0.0 && distance < PROXIMITY_THRESHOLD &&
|
|
distance < mProximitySensor.getMaximumRange());
|
|
|
|
if (mDebugProximitySensor) {
|
|
Slog.d(TAG, "mProximityListener.onSensorChanged active: " + active);
|
|
}
|
|
if (timeSinceLastEvent < PROXIMITY_SENSOR_DELAY) {
|
|
// enforce delaying atleast PROXIMITY_SENSOR_DELAY before processing
|
|
mProximityPendingValue = (active ? 1 : 0);
|
|
mHandler.postDelayed(mProximityTask, PROXIMITY_SENSOR_DELAY - timeSinceLastEvent);
|
|
proximityTaskQueued = true;
|
|
} else {
|
|
// process the value immediately
|
|
mProximityPendingValue = -1;
|
|
proximityChangedLocked(active);
|
|
}
|
|
|
|
// update mProximityPartialLock state
|
|
boolean held = mProximityPartialLock.isHeld();
|
|
if (!held && proximityTaskQueued) {
|
|
// hold wakelock until mProximityTask runs
|
|
mProximityPartialLock.acquire();
|
|
} else if (held && !proximityTaskQueued) {
|
|
mProximityPartialLock.release();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
|
// ignore
|
|
}
|
|
};
|
|
|
|
SensorEventListener mLightListener = new SensorEventListener() {
|
|
public void onSensorChanged(SensorEvent event) {
|
|
synchronized (mLocks) {
|
|
// ignore light sensor while screen is turning off
|
|
if (isScreenTurningOffLocked()) {
|
|
return;
|
|
}
|
|
|
|
int value = (int)event.values[0];
|
|
long milliseconds = SystemClock.elapsedRealtime();
|
|
if (mDebugLightSensor) {
|
|
Slog.d(TAG, "onSensorChanged: light value: " + value);
|
|
}
|
|
mHandler.removeCallbacks(mAutoBrightnessTask);
|
|
if (mLightSensorValue != value) {
|
|
if (mLightSensorValue == -1 ||
|
|
milliseconds < mLastScreenOnTime + mLightSensorWarmupTime) {
|
|
// process the value immediately if screen has just turned on
|
|
lightSensorChangedLocked(value);
|
|
} else {
|
|
// delay processing to debounce the sensor
|
|
mLightSensorPendingValue = value;
|
|
mHandler.postDelayed(mAutoBrightnessTask, LIGHT_SENSOR_DELAY);
|
|
}
|
|
} else {
|
|
mLightSensorPendingValue = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
|
// ignore
|
|
}
|
|
};
|
|
}
|