diff options
author | Jeff Brown <jeffbrown@google.com> | 2014-01-30 21:47:47 -0800 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2014-02-20 13:39:13 -0800 |
commit | 2687550272ba061448f5d5b914700dc335299ee7 (patch) | |
tree | fc68c5ecec24ec2aa120ccf490d7a56573704a73 /services/core | |
parent | d43ad2f35abcc647f7985abd09ed9de5899faf18 (diff) | |
download | frameworks_base-2687550272ba061448f5d5b914700dc335299ee7.zip frameworks_base-2687550272ba061448f5d5b914700dc335299ee7.tar.gz frameworks_base-2687550272ba061448f5d5b914700dc335299ee7.tar.bz2 |
Add a new "doze mode" based on Dream components.
When a doze component has been specified in a config.xml resource
overlay, the power manager will try to start a preconfigured dream
whenever it would have otherwise gone to sleep and turned the
screen off. The dream should render whatever it intends to show
then call startDozing() to tell the power manager to put the display
into a low power "doze" state and allow the application processor
to be suspended. The dream may wake up periodically using the
alarm manager or other features to update the contents of the display.
Added several new config.xml resources related to dreams and dozing.
In particular for dozing there are two new resources that pertain to
decoupling auto-suspend mode and interactive mode from the display
state. This is a requirement to enable the application processor
and other components to be suspended while dozing. Most devices
do not support these features today.
Consolidated the power manager's NAPPING and DREAMING states into one
to simplify the logic. The NAPPING state was mostly superfluous
and simply indicated that the power manager should attempt to start
a new dream. This state is now tracked in the mSandmanSummoned field.
Added a new DOZING state which is analoguous to DREAMING. The normal
state transition is now: AWAKE -> DREAMING -> DOZING -> ASLEEP.
The PowerManager.goToSleep() method now enters the DOZING state instead
of immediately going to sleep.
While in the doze state, the screen remains on. However, we actually
tell the rest of the system that the screen is off. This is somewhat
unfortunate but much of the system makes inappropriate assumptions
about what it means for the screen to be on or off. In particular,
screen on is usually taken to indicate an interactive state where
the user is present but that's not at all true for dozing (and is
only sometimes true while dreaming). We will probably need to add
some more precise externally visible states at some point.
The DozeHardware interface encapsulates a generic microcontroller
interface to allow a doze dream for off-loading rendering or other
functions while dozing. If the device possesses an MCU HAL for dozing
then it is exposed to the DreamService here.
Removed a number of catch blocks in DreamService that caught Throwable
and attempted to cause the dream to finish itself. We actually just
want to let the process crash. Cleanup will happen automatically if
needed. Catching these exceptions results in mysterious undefined
behavior and broken dreams.
Bug: 12494706
Change-Id: Ie78336b37dde7250d1ce65b3d367879e3bfb2b8b
Diffstat (limited to 'services/core')
12 files changed, 671 insertions, 170 deletions
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java index 85ef33e..649b5c9 100644 --- a/services/core/java/com/android/server/dreams/DreamController.java +++ b/services/core/java/com/android/server/dreams/DreamController.java @@ -85,6 +85,7 @@ final class DreamController { pw.println(" mToken=" + mCurrentDream.mToken); pw.println(" mName=" + mCurrentDream.mName); pw.println(" mIsTest=" + mCurrentDream.mIsTest); + pw.println(" mCanDoze=" + mCurrentDream.mCanDoze); pw.println(" mUserId=" + mCurrentDream.mUserId); pw.println(" mBound=" + mCurrentDream.mBound); pw.println(" mService=" + mCurrentDream.mService); @@ -94,15 +95,18 @@ final class DreamController { } } - public void startDream(Binder token, ComponentName name, boolean isTest, int userId) { + public void startDream(Binder token, ComponentName name, + boolean isTest, boolean canDoze, int userId) { stopDream(); // Close the notification shade. Don't need to send to all, but better to be explicit. mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL); - Slog.i(TAG, "Starting dream: name=" + name + ", isTest=" + isTest + ", userId=" + userId); + Slog.i(TAG, "Starting dream: name=" + name + + ", isTest=" + isTest + ", canDoze=" + canDoze + + ", userId=" + userId); - mCurrentDream = new DreamRecord(token, name, isTest, userId); + mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId); try { mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM); @@ -140,7 +144,8 @@ final class DreamController { final DreamRecord oldDream = mCurrentDream; mCurrentDream = null; Slog.i(TAG, "Stopping dream: name=" + oldDream.mName - + ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId); + + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze + + ", userId=" + oldDream.mUserId); mHandler.removeCallbacks(mStopUnconnectedDreamRunnable); @@ -187,7 +192,7 @@ final class DreamController { private void attach(IDreamService service) { try { service.asBinder().linkToDeath(mCurrentDream, 0); - service.attach(mCurrentDream.mToken); + service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze); } catch (RemoteException ex) { Slog.e(TAG, "The dream service died unexpectedly.", ex); stopDream(); @@ -213,6 +218,7 @@ final class DreamController { public final Binder mToken; public final ComponentName mName; public final boolean mIsTest; + public final boolean mCanDoze; public final int mUserId; public boolean mBound; @@ -221,10 +227,11 @@ final class DreamController { public boolean mSentStartBroadcast; public DreamRecord(Binder token, ComponentName name, - boolean isTest, int userId) { + boolean isTest, boolean canDoze, int userId) { mToken = token; mName = name; mIsTest = isTest; + mCanDoze = canDoze; mUserId = userId; } diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index ffb113c..fd2f8a1 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -30,16 +30,20 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.PowerManager; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.service.dreams.DreamManagerInternal; import android.service.dreams.DreamService; +import android.service.dreams.IDozeHardware; import android.service.dreams.IDreamManager; +import android.text.TextUtils; import android.util.Slog; import java.io.FileDescriptor; @@ -64,11 +68,16 @@ public final class DreamManagerService extends SystemService { private final DreamHandler mHandler; private final DreamController mController; private final PowerManager mPowerManager; + private final PowerManager.WakeLock mDozeWakeLock; + private final McuHal mMcuHal; // synchronized on self private Binder mCurrentDreamToken; private ComponentName mCurrentDreamName; private int mCurrentDreamUserId; private boolean mCurrentDreamIsTest; + private boolean mCurrentDreamCanDoze; + private boolean mCurrentDreamIsDozing; + private DozeHardwareWrapper mCurrentDreamDozeHardware; public DreamManagerService(Context context) { super(context); @@ -77,6 +86,12 @@ public final class DreamManagerService extends SystemService { mController = new DreamController(context, mHandler, mControllerListener); mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG); + + mMcuHal = McuHal.open(); + if (mMcuHal != null) { + mMcuHal.reset(); + } } @Override @@ -103,10 +118,15 @@ public final class DreamManagerService extends SystemService { pw.println("DREAM MANAGER (dumpsys dreams)"); pw.println(); + pw.println("mMcuHal=" + mMcuHal); + pw.println(); pw.println("mCurrentDreamToken=" + mCurrentDreamToken); pw.println("mCurrentDreamName=" + mCurrentDreamName); pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId); pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest); + pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze); + pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing); + pw.println("mCurrentDreamDozeHardware=" + mCurrentDreamDozeHardware); pw.println(); DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() { @@ -163,16 +183,16 @@ public final class DreamManagerService extends SystemService { private void testDreamInternal(ComponentName dream, int userId) { synchronized (mLock) { - startDreamLocked(dream, true /*isTest*/, userId); + startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId); } } - private void startDreamInternal() { - int userId = ActivityManager.getCurrentUser(); - ComponentName dream = chooseDreamForUser(userId); + private void startDreamInternal(boolean doze) { + final int userId = ActivityManager.getCurrentUser(); + final ComponentName dream = doze ? getDozeComponent() : chooseDreamForUser(userId); if (dream != null) { synchronized (mLock) { - startDreamLocked(dream, false /*isTest*/, userId); + startDreamLocked(dream, false /*isTest*/, doze, userId); } } } @@ -183,6 +203,44 @@ public final class DreamManagerService extends SystemService { } } + private void startDozingInternal(IBinder token) { + if (DEBUG) { + Slog.d(TAG, "Dream requested to start dozing: " + token); + } + + synchronized (mLock) { + if (mCurrentDreamToken == token && mCurrentDreamCanDoze + && !mCurrentDreamIsDozing) { + mCurrentDreamIsDozing = true; + mDozeWakeLock.acquire(); + } + } + } + + private void stopDozingInternal(IBinder token) { + if (DEBUG) { + Slog.d(TAG, "Dream requested to stop dozing: " + token); + } + + synchronized (mLock) { + if (mCurrentDreamToken == token && mCurrentDreamIsDozing) { + mCurrentDreamIsDozing = false; + mDozeWakeLock.release(); + } + } + } + + private IDozeHardware getDozeHardwareInternal(IBinder token) { + synchronized (mLock) { + if (mCurrentDreamToken == token && mCurrentDreamCanDoze + && mCurrentDreamDozeHardware == null && mMcuHal != null) { + mCurrentDreamDozeHardware = new DozeHardwareWrapper(); + return mCurrentDreamDozeHardware; + } + return null; + } + } + private ComponentName chooseDreamForUser(int userId) { ComponentName[] dreams = getDreamComponentsForUser(userId); return dreams != null && dreams.length != 0 ? dreams[0] : null; @@ -231,6 +289,20 @@ public final class DreamManagerService extends SystemService { return name == null ? null : ComponentName.unflattenFromString(name); } + private ComponentName getDozeComponent() { + // Read the component from a system property to facilitate debugging. + // Note that for production devices, the dream should actually be declared in + // a config.xml resource. + String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null; + if (TextUtils.isEmpty(name)) { + // Read the component from a config.xml resource. + // The value should be specified in a resource overlay for the product. + name = mContext.getResources().getString( + com.android.internal.R.string.config_dozeComponent); + } + return TextUtils.isEmpty(name) ? null : ComponentName.unflattenFromString(name); + } + private boolean serviceExists(ComponentName name) { try { return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null; @@ -240,9 +312,10 @@ public final class DreamManagerService extends SystemService { } private void startDreamLocked(final ComponentName name, - final boolean isTest, final int userId) { + final boolean isTest, final boolean canDoze, final int userId) { if (Objects.equal(mCurrentDreamName, name) && mCurrentDreamIsTest == isTest + && mCurrentDreamCanDoze == canDoze && mCurrentDreamUserId == userId) { return; } @@ -255,12 +328,13 @@ public final class DreamManagerService extends SystemService { mCurrentDreamToken = newToken; mCurrentDreamName = name; mCurrentDreamIsTest = isTest; + mCurrentDreamCanDoze = canDoze; mCurrentDreamUserId = userId; mHandler.post(new Runnable() { @Override public void run() { - mController.startDream(newToken, name, isTest, userId); + mController.startDream(newToken, name, isTest, canDoze, userId); } }); } @@ -284,7 +358,16 @@ public final class DreamManagerService extends SystemService { mCurrentDreamToken = null; mCurrentDreamName = null; mCurrentDreamIsTest = false; + mCurrentDreamCanDoze = false; mCurrentDreamUserId = 0; + if (mCurrentDreamIsDozing) { + mCurrentDreamIsDozing = false; + mDozeWakeLock.release(); + } + if (mCurrentDreamDozeHardware != null) { + mCurrentDreamDozeHardware.release(); + mCurrentDreamDozeHardware = null; + } } private void checkPermission(String permission) { @@ -473,12 +556,57 @@ public final class DreamManagerService extends SystemService { Binder.restoreCallingIdentity(ident); } } + + @Override // Binder call + public void startDozing(IBinder token) { + // Requires no permission, called by Dream from an arbitrary process. + if (token == null) { + throw new IllegalArgumentException("token must not be null"); + } + + final long ident = Binder.clearCallingIdentity(); + try { + startDozingInternal(token); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public void stopDozing(IBinder token) { + // Requires no permission, called by Dream from an arbitrary process. + if (token == null) { + throw new IllegalArgumentException("token must not be null"); + } + + final long ident = Binder.clearCallingIdentity(); + try { + stopDozingInternal(token); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public IDozeHardware getDozeHardware(IBinder token) { + // Requires no permission, called by Dream from an arbitrary process. + if (token == null) { + throw new IllegalArgumentException("token must not be null"); + } + + final long ident = Binder.clearCallingIdentity(); + try { + return getDozeHardwareInternal(token); + } finally { + Binder.restoreCallingIdentity(ident); + } + } } private final class LocalService extends DreamManagerInternal { @Override - public void startDream() { - startDreamInternal(); + public void startDream(boolean doze) { + startDreamInternal(doze); } @Override @@ -491,4 +619,37 @@ public final class DreamManagerService extends SystemService { return isDreamingInternal(); } } + + private final class DozeHardwareWrapper extends IDozeHardware.Stub { + private boolean mReleased; + + public void release() { + synchronized (mMcuHal) { + if (!mReleased) { + mReleased = true; + mMcuHal.reset(); + } + } + } + + @Override // Binder call + public byte[] sendMessage(String msg, byte[] arg) { + if (msg == null) { + throw new IllegalArgumentException("msg must not be null"); + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mMcuHal) { + if (mReleased) { + throw new IllegalStateException("This operation cannot be performed " + + "because the dream has ended."); + } + return mMcuHal.sendMessage(msg, arg); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } } diff --git a/services/core/java/com/android/server/dreams/McuHal.java b/services/core/java/com/android/server/dreams/McuHal.java new file mode 100644 index 0000000..1dc79c7 --- /dev/null +++ b/services/core/java/com/android/server/dreams/McuHal.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 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.dreams; + +import android.service.dreams.DozeHardware; + +/** + * Provides access to the low-level microcontroller hardware abstraction layer. + */ +final class McuHal { + private final long mPtr; + + private static native long nativeOpen(); + private static native byte[] nativeSendMessage(long ptr, String msg, byte[] arg); + + private McuHal(long ptr) { + mPtr = ptr; + } + + public static McuHal open() { + long ptr = nativeOpen(); + return ptr != 0 ? new McuHal(ptr) : null; + } + + public void reset() { + sendMessage(DozeHardware.MSG_ENABLE_MCU, DozeHardware.VALUE_OFF); + } + + public byte[] sendMessage(String msg, byte[] arg) { + return nativeSendMessage(mPtr, msg, arg); + } +} diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 69281bc..73033e0 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -1329,8 +1329,9 @@ public class InputManagerService extends IInputManager.Stub } // Native callback. - private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { - return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); + private int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) { + return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff( + whenNanos, policyFlags); } // Native callback. @@ -1491,7 +1492,7 @@ public class InputManagerService extends IInputManager.Stub public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn); - public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags); + public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags); public long interceptKeyBeforeDispatching(InputWindowHandle focus, KeyEvent event, int policyFlags); diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java index f1be504..bd9acb9 100644 --- a/services/core/java/com/android/server/power/DisplayPowerController.java +++ b/services/core/java/com/android/server/power/DisplayPowerController.java @@ -193,6 +193,9 @@ final class DisplayPowerController { // The light sensor, or null if not available or needed. private Sensor mLightSensor; + // The doze screen brightness. + private final int mScreenBrightnessDozeConfig; + // The dim screen brightness. private final int mScreenBrightnessDimConfig; @@ -364,6 +367,9 @@ final class DisplayPowerController { final Resources resources = context.getResources(); + mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger( + com.android.internal.R.integer.config_screenBrightnessDoze)); + mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger( com.android.internal.R.integer.config_screenBrightnessDim)); @@ -559,7 +565,7 @@ final class DisplayPowerController { final boolean mustNotify; boolean mustInitialize = false; boolean updateAutoBrightness = mTwilightChanged; - boolean wasDim = false; + boolean wasDimOrDoze = false; mTwilightChanged = false; synchronized (mLock) { @@ -579,7 +585,8 @@ final class DisplayPowerController { != mPendingRequestLocked.screenAutoBrightnessAdjustment) { updateAutoBrightness = true; } - wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM); + wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM + || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE); mPowerRequest.copyFrom(mPendingRequestLocked); mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; mPendingWaitForNegativeProximityLocked = false; @@ -626,12 +633,12 @@ final class DisplayPowerController { // Turn on the light sensor if needed. if (mLightSensor != null) { - setLightSensorEnabled(mPowerRequest.useAutoBrightness - && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness); + setLightSensorEnabled(mPowerRequest.wantLightSensorEnabled(), + updateAutoBrightness); } // Set the screen brightness. - if (wantScreenOn(mPowerRequest.screenState)) { + if (mPowerRequest.wantScreenOnAny()) { int target; boolean slow; if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) { @@ -648,12 +655,16 @@ final class DisplayPowerController { slow = false; mUsingScreenAutoBrightness = false; } - if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) { + if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) { + // Dim quickly to the doze state. + target = mScreenBrightnessDozeConfig; + slow = false; + } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) { // Dim quickly by at least some minimum amount. target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION, mScreenBrightnessDimConfig); slow = false; - } else if (wasDim) { + } else if (wasDimOrDoze) { // Brighten quickly. slow = false; } @@ -666,7 +677,7 @@ final class DisplayPowerController { // Animate the screen on or off. if (!mScreenOffBecauseOfProximity) { - if (wantScreenOn(mPowerRequest.screenState)) { + if (mPowerRequest.wantScreenOnAny()) { // Want screen on. // Wait for previous off animation to complete beforehand. // It is relatively short but if we cancel it and switch to the @@ -1211,6 +1222,7 @@ final class DisplayPowerController { pw.println(); pw.println("Display Controller Configuration:"); + pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig); pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig); pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum); pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum); @@ -1288,15 +1300,6 @@ final class DisplayPowerController { } } - private static boolean wantScreenOn(int state) { - switch (state) { - case DisplayPowerRequest.SCREEN_STATE_BRIGHT: - case DisplayPowerRequest.SCREEN_STATE_DIM: - return true; - } - return false; - } - /** * Asynchronous callbacks from the power controller to the power manager service. */ diff --git a/services/core/java/com/android/server/power/DisplayPowerRequest.java b/services/core/java/com/android/server/power/DisplayPowerRequest.java index 22f17d7..6061a40 100644 --- a/services/core/java/com/android/server/power/DisplayPowerRequest.java +++ b/services/core/java/com/android/server/power/DisplayPowerRequest.java @@ -30,10 +30,11 @@ import android.os.PowerManager; */ final class DisplayPowerRequest { public static final int SCREEN_STATE_OFF = 0; - public static final int SCREEN_STATE_DIM = 1; - public static final int SCREEN_STATE_BRIGHT = 2; + public static final int SCREEN_STATE_DOZE = 1; + public static final int SCREEN_STATE_DIM = 2; + public static final int SCREEN_STATE_BRIGHT = 3; - // The requested minimum screen power state: off, dim or bright. + // The requested minimum screen power state: off, doze, dim or bright. public int screenState; // If true, the proximity sensor overrides the screen state when an object is @@ -75,6 +76,23 @@ final class DisplayPowerRequest { copyFrom(other); } + // Returns true if we want the screen on in any mode, including doze. + public boolean wantScreenOnAny() { + return screenState != SCREEN_STATE_OFF; + } + + // Returns true if we want the screen on in a normal mode, excluding doze. + // This is usually what we want to tell the rest of the system. For compatibility + // reasons, we pretend the screen is off when dozing. + public boolean wantScreenOnNormal() { + return screenState == SCREEN_STATE_DIM || screenState == SCREEN_STATE_BRIGHT; + } + + public boolean wantLightSensorEnabled() { + // Specifically, we don't want the light sensor while dozing. + return useAutoBrightness && wantScreenOnNormal(); + } + public void copyFrom(DisplayPowerRequest other) { screenState = other.screenState; useProximitySensor = other.useProximitySensor; diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 3dec234..16b09bc 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -83,7 +83,7 @@ public final class PowerManagerService extends com.android.server.SystemService // Message: Sent when a user activity timeout occurs to update the power state. private static final int MSG_USER_ACTIVITY_TIMEOUT = 1; - // Message: Sent when the device enters or exits a napping or dreaming state. + // Message: Sent when the device enters or exits a dreaming or dozing state. private static final int MSG_SANDMAN = 2; // Message: Sent when the screen on blocker is released. private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3; @@ -117,19 +117,21 @@ public final class PowerManagerService extends com.android.server.SystemService // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp(). // The screen should be off or in the process of being turned off by the display controller. + // The device typically passes through the dozing state first. private static final int WAKEFULNESS_ASLEEP = 0; // Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep(). - // When the user activity timeout expires, the device may start napping or go to sleep. + // When the user activity timeout expires, the device may start dreaming or go to sleep. private static final int WAKEFULNESS_AWAKE = 1; - // Wakefulness: The device is napping. It is deciding whether to dream or go to sleep - // but hasn't gotten around to it yet. It can be awoken by a call to wakeUp(), which - // ends the nap. User activity may brighten the screen but does not end the nap. - private static final int WAKEFULNESS_NAPPING = 2; // Wakefulness: The device is dreaming. It can be awoken by a call to wakeUp(), // which ends the dream. The device goes to sleep when goToSleep() is called, when // the dream ends or when unplugged. // User activity may brighten the screen but does not end the dream. - private static final int WAKEFULNESS_DREAMING = 3; + private static final int WAKEFULNESS_DREAMING = 2; + // Wakefulness: The device is dozing. It is almost asleep but is allowing a special + // low-power "doze" dream to run which keeps the display on but lets the application + // processor be suspended. It can be awoken by a call to wakeUp() which ends the dream. + // The device fully goes to sleep if the dream cannot be started or ends on its own. + private static final int WAKEFULNESS_DOZING = 3; // Summarizes the state of all active wakelocks. private static final int WAKE_LOCK_CPU = 1 << 0; @@ -138,6 +140,7 @@ public final class PowerManagerService extends com.android.server.SystemService private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3; private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4; private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake + private static final int WAKE_LOCK_DOZE = 1 << 6; // Summarizes the user activity state. private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0; @@ -164,11 +167,6 @@ public final class PowerManagerService extends com.android.server.SystemService // Poll interval in milliseconds for watching boot animation finished. private static final int BOOT_ANIMATION_POLL_INTERVAL = 200; - // If the battery level drops by this percentage and the user activity timeout - // has expired, then assume the device is receiving insufficient current to charge - // effectively and terminate the dream. - private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5; - private final Context mContext; private LightsManager mLightsManager; private BatteryService mBatteryService; @@ -195,6 +193,10 @@ public final class PowerManagerService extends com.android.server.SystemService // This is distinct from the screen power state, which is managed separately. private int mWakefulness; + // True if the sandman has just been summoned for the first time since entering the + // dreaming or dozing state. Indicates whether a new dream should begin. + private boolean mSandmanSummoned; + // True if MSG_SANDMAN has been scheduled. private boolean mSandmanScheduled; @@ -265,6 +267,14 @@ public final class PowerManagerService extends com.android.server.SystemService // True if boot completed occurred. We keep the screen on until this happens. private boolean mBootCompleted; + // True if auto-suspend mode is enabled. + // Refer to autosuspend.h. + private boolean mAutoSuspendModeEnabled; + + // True if interactive mode is enabled. + // Refer to power.h. + private boolean mInteractiveModeEnabled; + // True if the device is plugged into a power source. private boolean mIsPowered; @@ -282,6 +292,12 @@ public final class PowerManagerService extends com.android.server.SystemService // The current dock state. private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + // True to decouple auto-suspend mode from the display state. + private boolean mDecoupleAutoSuspendModeFromDisplayConfig; + + // True to decouple interactive mode from the display state. + private boolean mDecoupleInteractiveModeFromDisplayConfig; + // True if the device should wake up when plugged or unplugged. private boolean mWakeUpWhenPluggedOrUnpluggedConfig; @@ -300,6 +316,22 @@ public final class PowerManagerService extends com.android.server.SystemService // Default value for dreams activate-on-dock private boolean mDreamsActivatedOnDockByDefaultConfig; + // True if dreams can run while not plugged in. + private boolean mDreamsEnabledOnBatteryConfig; + + // Minimum battery level to allow dreaming when powered. + // Use -1 to disable this safety feature. + private int mDreamsBatteryLevelMinimumWhenPoweredConfig; + + // Minimum battery level to allow dreaming when not powered. + // Use -1 to disable this safety feature. + private int mDreamsBatteryLevelMinimumWhenNotPoweredConfig; + + // If the battery level drops by this percentage and the user activity timeout + // has expired, then assume the device is receiving insufficient current to charge + // effectively and terminate the dream. Use -1 to disable this safety feature. + private int mDreamsBatteryLevelDrainCutoffConfig; + // True if dreams are enabled by the user. private boolean mDreamsEnabledSetting; @@ -523,6 +555,10 @@ public final class PowerManagerService extends com.android.server.SystemService private void readConfigurationLocked() { final Resources resources = mContext.getResources(); + mDecoupleAutoSuspendModeFromDisplayConfig = resources.getBoolean( + com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay); + mDecoupleInteractiveModeFromDisplayConfig = resources.getBoolean( + com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay); mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean( com.android.internal.R.bool.config_unplugTurnsOnScreen); mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean( @@ -535,6 +571,14 @@ public final class PowerManagerService extends com.android.server.SystemService com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault); mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean( com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault); + mDreamsEnabledOnBatteryConfig = resources.getBoolean( + com.android.internal.R.bool.config_dreamsEnabledOnBattery); + mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger( + com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenPowered); + mDreamsBatteryLevelMinimumWhenNotPoweredConfig = resources.getInteger( + com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenNotPowered); + mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger( + com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff); } private void updateSettingsLocked() { @@ -762,6 +806,7 @@ public final class PowerManagerService extends com.android.server.SystemService case PowerManager.SCREEN_DIM_WAKE_LOCK: case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: case PowerManager.FULL_WAKE_LOCK: + case PowerManager.DOZE_WAKE_LOCK: return true; case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: @@ -794,7 +839,8 @@ public final class PowerManagerService extends com.android.server.SystemService } if (eventTime < mLastSleepTime || eventTime < mLastWakeTime - || mWakefulness == WAKEFULNESS_ASLEEP || !mBootCompleted || !mSystemReady) { + || mWakefulness == WAKEFULNESS_ASLEEP || mWakefulness == WAKEFULNESS_DOZING + || !mBootCompleted || !mSystemReady) { return false; } @@ -843,18 +889,21 @@ public final class PowerManagerService extends com.android.server.SystemService switch (mWakefulness) { case WAKEFULNESS_ASLEEP: Slog.i(TAG, "Waking up from sleep..."); - sendPendingNotificationsLocked(); - mNotifier.onWakeUpStarted(); - mSendWakeUpFinishedNotificationWhenReady = true; break; case WAKEFULNESS_DREAMING: Slog.i(TAG, "Waking up from dream..."); break; - case WAKEFULNESS_NAPPING: - Slog.i(TAG, "Waking up from nap..."); + case WAKEFULNESS_DOZING: + Slog.i(TAG, "Waking up from dozing..."); break; } + if (mWakefulness != WAKEFULNESS_DREAMING) { + sendPendingNotificationsLocked(); + mNotifier.onWakeUpStarted(); + mSendWakeUpFinishedNotificationWhenReady = true; + } + mLastWakeTime = eventTime; mWakefulness = WAKEFULNESS_AWAKE; mDirty |= DIRTY_WAKEFULNESS; @@ -877,13 +926,17 @@ public final class PowerManagerService extends com.android.server.SystemService } } + // This method is called goToSleep for historical reasons but we actually start + // dozing before really going to sleep. @SuppressWarnings("deprecation") private boolean goToSleepNoUpdateLocked(long eventTime, int reason) { if (DEBUG_SPEW) { Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason); } - if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP + if (eventTime < mLastWakeTime + || mWakefulness == WAKEFULNESS_ASLEEP + || mWakefulness == WAKEFULNESS_DOZING || !mBootCompleted || !mSystemReady) { return false; } @@ -907,7 +960,8 @@ public final class PowerManagerService extends com.android.server.SystemService mLastSleepTime = eventTime; mDirty |= DIRTY_WAKEFULNESS; - mWakefulness = WAKEFULNESS_ASLEEP; + mWakefulness = WAKEFULNESS_DOZING; + mSandmanSummoned = true; // Report the number of wake locks that will be cleared by going to sleep. int numWakeLocksCleared = 0; @@ -947,7 +1001,26 @@ public final class PowerManagerService extends com.android.server.SystemService Slog.i(TAG, "Nap time..."); mDirty |= DIRTY_WAKEFULNESS; - mWakefulness = WAKEFULNESS_NAPPING; + mWakefulness = WAKEFULNESS_DREAMING; + mSandmanSummoned = true; + return true; + } + + // Done dozing, drop everything and go to sleep. + private boolean reallyGoToSleepNoUpdateLocked(long eventTime) { + if (DEBUG_SPEW) { + Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime); + } + + if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP + || !mBootCompleted || !mSystemReady) { + return false; + } + + Slog.i(TAG, "Sleeping..."); + + mDirty |= DIRTY_WAKEFULNESS; + mWakefulness = WAKEFULNESS_ASLEEP; return true; } @@ -1023,7 +1096,7 @@ public final class PowerManagerService extends com.android.server.SystemService mPlugType = mBatteryService.getPlugType(); mBatteryLevel = mBatteryService.getBatteryLevel(); - if (DEBUG) { + if (DEBUG_SPEW) { Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered + ", mIsPowered=" + mIsPowered + ", oldPlugType=" + oldPlugType @@ -1083,8 +1156,7 @@ public final class PowerManagerService extends com.android.server.SystemService } // If already dreaming and becoming powered, then don't wake. - if (mIsPowered && (mWakefulness == WAKEFULNESS_NAPPING - || mWakefulness == WAKEFULNESS_DREAMING)) { + if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) { return false; } @@ -1131,35 +1203,45 @@ public final class PowerManagerService extends com.android.server.SystemService mWakeLockSummary |= WAKE_LOCK_CPU; break; case PowerManager.FULL_WAKE_LOCK: - if (mWakefulness != WAKEFULNESS_ASLEEP) { + if (mWakefulness == WAKEFULNESS_AWAKE + || mWakefulness == WAKEFULNESS_DREAMING) { mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT; - if (mWakefulness == WAKEFULNESS_AWAKE) { - mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE; - } + } + if (mWakefulness == WAKEFULNESS_AWAKE) { + mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE; } break; case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: - if (mWakefulness != WAKEFULNESS_ASLEEP) { + if (mWakefulness == WAKEFULNESS_AWAKE + || mWakefulness == WAKEFULNESS_DREAMING) { mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT; - if (mWakefulness == WAKEFULNESS_AWAKE) { - mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE; - } + } + if (mWakefulness == WAKEFULNESS_AWAKE) { + mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE; } break; case PowerManager.SCREEN_DIM_WAKE_LOCK: - if (mWakefulness != WAKEFULNESS_ASLEEP) { + if (mWakefulness == WAKEFULNESS_AWAKE + || mWakefulness == WAKEFULNESS_DREAMING) { mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM; - if (mWakefulness == WAKEFULNESS_AWAKE) { - mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE; - } + } + if (mWakefulness == WAKEFULNESS_AWAKE) { + mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE; } break; case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: - if (mWakefulness != WAKEFULNESS_ASLEEP) { + if (mWakefulness == WAKEFULNESS_AWAKE + || mWakefulness == WAKEFULNESS_DREAMING + || mWakefulness == WAKEFULNESS_DOZING) { mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF; } break; + case PowerManager.DOZE_WAKE_LOCK: + if (mWakefulness == WAKEFULNESS_DOZING) { + mWakeLockSummary |= WAKE_LOCK_DOZE; + } + break; } } @@ -1184,7 +1266,8 @@ public final class PowerManagerService extends com.android.server.SystemService mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT); long nextTimeout = 0; - if (mWakefulness != WAKEFULNESS_ASLEEP) { + if (mWakefulness == WAKEFULNESS_AWAKE + || mWakefulness == WAKEFULNESS_DREAMING) { final int screenOffTimeout = getScreenOffTimeoutLocked(); final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout); @@ -1205,8 +1288,7 @@ public final class PowerManagerService extends com.android.server.SystemService && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) { nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout; if (now < nextTimeout - && mDisplayPowerRequest.screenState - != DisplayPowerRequest.SCREEN_STATE_OFF) { + && mDisplayPowerRequest.wantScreenOnNormal()) { mUserActivitySummary = mDisplayPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT ? USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM; @@ -1268,7 +1350,7 @@ public final class PowerManagerService extends com.android.server.SystemService /** * Updates the wakefulness of the device. * - * This is the function that decides whether the device should start napping + * This is the function that decides whether the device should start dreaming * based on the current wake locks and user activity state. It may modify mDirty * if the wakefulness changes. * @@ -1357,7 +1439,7 @@ public final class PowerManagerService extends com.android.server.SystemService } /** - * Called when the device enters or exits a napping or dreaming state. + * Called when the device enters or exits a dreaming or dozing state. * * We do this asynchronously because we must call out of the power manager to start * the dream and we don't want to hold our lock while doing so. There is a risk that @@ -1365,46 +1447,60 @@ public final class PowerManagerService extends com.android.server.SystemService */ private void handleSandman() { // runs on handler thread // Handle preconditions. - boolean startDreaming = false; + final boolean startDreaming; + final int wakefulness; synchronized (mLock) { mSandmanScheduled = false; - boolean canDream = canDreamLocked(); - if (DEBUG_SPEW) { - Slog.d(TAG, "handleSandman: canDream=" + canDream - + ", mWakefulness=" + wakefulnessToString(mWakefulness)); - } - - if (canDream && mWakefulness == WAKEFULNESS_NAPPING) { - startDreaming = true; + wakefulness = mWakefulness; + if (mSandmanSummoned) { + startDreaming = ((wakefulness == WAKEFULNESS_DREAMING && canDreamLocked()) + || wakefulness == WAKEFULNESS_DOZING); + mSandmanSummoned = false; + } else { + startDreaming = false; } } // Start dreaming if needed. // We only control the dream on the handler thread, so we don't need to worry about // concurrent attempts to start or stop the dream. - boolean isDreaming = false; + final boolean isDreaming; if (mDreamManager != null) { + // Restart the dream whenever the sandman is summoned. if (startDreaming) { - mDreamManager.startDream(); + mDreamManager.stopDream(); + mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING); } isDreaming = mDreamManager.isDreaming(); + } else { + isDreaming = false; } // Update dream state. - // We might need to stop the dream again if the preconditions changed. - boolean continueDreaming = false; synchronized (mLock) { - if (isDreaming && canDreamLocked()) { - if (mWakefulness == WAKEFULNESS_NAPPING) { - mWakefulness = WAKEFULNESS_DREAMING; - mDirty |= DIRTY_WAKEFULNESS; - mBatteryLevelWhenDreamStarted = mBatteryLevel; - updatePowerStateLocked(); - continueDreaming = true; - } else if (mWakefulness == WAKEFULNESS_DREAMING) { - if (!isBeingKeptAwakeLocked() + // Remember the initial battery level when the dream started. + if (startDreaming && isDreaming) { + mBatteryLevelWhenDreamStarted = mBatteryLevel; + if (wakefulness == WAKEFULNESS_DOZING) { + Slog.i(TAG, "Dozing..."); + } else { + Slog.i(TAG, "Dreaming..."); + } + } + + // If preconditions changed, wait for the next iteration to determine + // whether the dream should continue (or be restarted). + if (mSandmanSummoned || mWakefulness != wakefulness) { + return; // wait for next cycle + } + + // Determine whether the dream should continue. + if (wakefulness == WAKEFULNESS_DREAMING) { + if (isDreaming && canDreamLocked()) { + if (mDreamsBatteryLevelDrainCutoffConfig >= 0 && mBatteryLevel < mBatteryLevelWhenDreamStarted - - DREAM_BATTERY_LEVEL_DRAIN_CUTOFF) { + - mDreamsBatteryLevelDrainCutoffConfig + && !isBeingKeptAwakeLocked()) { // If the user activity timeout expired and the battery appears // to be draining faster than it is charging then stop dreaming // and go to sleep. @@ -1414,53 +1510,64 @@ public final class PowerManagerService extends com.android.server.SystemService + mBatteryLevelWhenDreamStarted + "%. " + "Battery level now: " + mBatteryLevel + "%."); } else { - continueDreaming = true; + return; // continue dreaming } } - } - if (!continueDreaming) { - handleDreamFinishedLocked(); + + // Dream has ended or will be stopped. Update the power state. + if (isItBedTimeYetLocked()) { + goToSleepNoUpdateLocked(SystemClock.uptimeMillis(), + PowerManager.GO_TO_SLEEP_REASON_TIMEOUT); + updatePowerStateLocked(); + } else { + wakeUpNoUpdateLocked(SystemClock.uptimeMillis()); + updatePowerStateLocked(); + } + } else if (wakefulness == WAKEFULNESS_DOZING) { + if (isDreaming) { + return; // continue dozing + } + + // Doze has ended or will be stopped. Update the power state. + reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis()); + updatePowerStateLocked(); } } - // Stop dreaming if needed. - // It's possible that something else changed to make us need to start the dream again. - // If so, then the power manager will have posted another message to the handler - // to take care of it later. - if (mDreamManager != null) { - if (!continueDreaming) { - mDreamManager.stopDream(); - } + // Stop dream. + if (isDreaming) { + mDreamManager.stopDream(); } } /** - * Returns true if the device is allowed to dream in its current state - * assuming that it is currently napping or dreaming. + * Returns true if the device is allowed to dream in its current state. + * This function is not called when dozing. */ private boolean canDreamLocked() { - return mDreamsSupportedConfig - && mDreamsEnabledSetting - && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF - && mBootCompleted - && (mIsPowered || isBeingKeptAwakeLocked()); - } - - /** - * Called when a dream is ending to figure out what to do next. - */ - private void handleDreamFinishedLocked() { - if (mWakefulness == WAKEFULNESS_NAPPING - || mWakefulness == WAKEFULNESS_DREAMING) { - if (isItBedTimeYetLocked()) { - goToSleepNoUpdateLocked(SystemClock.uptimeMillis(), - PowerManager.GO_TO_SLEEP_REASON_TIMEOUT); - updatePowerStateLocked(); - } else { - wakeUpNoUpdateLocked(SystemClock.uptimeMillis()); - updatePowerStateLocked(); + if (mWakefulness != WAKEFULNESS_DREAMING + || !mDreamsSupportedConfig + || !mDreamsEnabledSetting + || !mDisplayPowerRequest.wantScreenOnNormal() + || !mBootCompleted) { + return false; + } + if (!isBeingKeptAwakeLocked()) { + if (!mIsPowered && !mDreamsEnabledByDefaultConfig) { + return false; + } + if (!mIsPowered + && mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0 + && mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) { + return false; + } + if (mIsPowered + && mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0 + && mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) { + return false; } } + return true; } private void handleScreenOnBlockerReleased() { @@ -1482,11 +1589,11 @@ public final class PowerManagerService extends com.android.server.SystemService if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) { - int newScreenState = getDesiredScreenPowerStateLocked(); + final int newScreenState = getDesiredScreenPowerStateLocked(); if (newScreenState != mDisplayPowerRequest.screenState) { mDisplayPowerRequest.screenState = newScreenState; nativeSetPowerState( - newScreenState != DisplayPowerRequest.SCREEN_STATE_OFF, + mDisplayPowerRequest.wantScreenOnNormal(), newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT); } @@ -1555,6 +1662,10 @@ public final class PowerManagerService extends com.android.server.SystemService return DisplayPowerRequest.SCREEN_STATE_OFF; } + if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) { + return DisplayPowerRequest.SCREEN_STATE_DOZE; + } + if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0 || (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0 || !mBootCompleted) { @@ -1606,7 +1717,18 @@ public final class PowerManagerService extends com.android.server.SystemService */ private void updateSuspendBlockerLocked() { final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0); - final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker(); + final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked(); + final boolean autoSuspend = !needDisplaySuspendBlocker; + + // Disable auto-suspend if needed. + if (!autoSuspend) { + if (mDecoupleAutoSuspendModeFromDisplayConfig) { + setAutoSuspendModeLocked(false); + } + if (mDecoupleInteractiveModeFromDisplayConfig) { + setInteractiveModeLocked(true); + } + } // First acquire suspend blockers if needed. if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) { @@ -1627,17 +1749,27 @@ public final class PowerManagerService extends com.android.server.SystemService mDisplaySuspendBlocker.release(); mHoldingDisplaySuspendBlocker = false; } + + // Enable auto-suspend if needed. + if (autoSuspend) { + if (mDecoupleInteractiveModeFromDisplayConfig) { + setInteractiveModeLocked(false); + } + if (mDecoupleAutoSuspendModeFromDisplayConfig) { + setAutoSuspendModeLocked(true); + } + } } /** * Return true if we must keep a suspend blocker active on behalf of the display. * We do so if the screen is on or is in transition between states. */ - private boolean needDisplaySuspendBlocker() { + private boolean needDisplaySuspendBlockerLocked() { if (!mDisplayReady) { return true; } - if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) { + if (mDisplayPowerRequest.wantScreenOnNormal()) { // If we asked for the screen to be on but it is off due to the proximity // sensor then we may suspend but only if the configuration allows it. // On some hardware it may not be safe to suspend because the proximity @@ -1647,13 +1779,34 @@ public final class PowerManagerService extends com.android.server.SystemService return true; } } + // Let the system suspend if the screen is off or dozing. return false; } + private void setAutoSuspendModeLocked(boolean enable) { + if (enable != mAutoSuspendModeEnabled) { + if (DEBUG) { + Slog.d(TAG, "Setting auto-suspend mode to " + enable); + } + mAutoSuspendModeEnabled = enable; + nativeSetAutoSuspend(enable); + } + } + + private void setInteractiveModeLocked(boolean enable) { + if (enable != mInteractiveModeEnabled) { + if (DEBUG) { + Slog.d(TAG, "Setting interactive mode to " + enable); + } + mInteractiveModeEnabled = enable; + nativeSetInteractive(enable); + } + } + private boolean isScreenOnInternal() { synchronized (mLock) { return !mSystemReady - || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF; + || mDisplayPowerRequest.wantScreenOnNormal(); } } @@ -1871,10 +2024,13 @@ public final class PowerManagerService extends com.android.server.SystemService pw.println(" mProximityPositive=" + mProximityPositive); pw.println(" mBootCompleted=" + mBootCompleted); pw.println(" mSystemReady=" + mSystemReady); + pw.println(" mAutoSuspendModeEnabled=" + mAutoSuspendModeEnabled); + pw.println(" mInteactiveModeEnabled=" + mInteractiveModeEnabled); pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)); pw.println(" mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)); pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity); pw.println(" mSandmanScheduled=" + mSandmanScheduled); + pw.println(" mSandmanSummoned=" + mSandmanSummoned); pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime)); pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime)); pw.println(" mSendWakeUpFinishedNotificationWhenReady=" @@ -1890,6 +2046,10 @@ public final class PowerManagerService extends com.android.server.SystemService pw.println(); pw.println("Settings and Configuration:"); + pw.println(" mDecoupleAutoSuspendModeFromDisplayConfig=" + + mDecoupleAutoSuspendModeFromDisplayConfig); + pw.println(" mDecoupleInteractiveModeFromDisplayConfig=" + + mDecoupleInteractiveModeFromDisplayConfig); pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig=" + mWakeUpWhenPluggedOrUnpluggedConfig); pw.println(" mSuspendWhenScreenOffDueToProximityConfig=" @@ -1900,6 +2060,14 @@ public final class PowerManagerService extends com.android.server.SystemService + mDreamsActivatedOnSleepByDefaultConfig); pw.println(" mDreamsActivatedOnDockByDefaultConfig=" + mDreamsActivatedOnDockByDefaultConfig); + pw.println(" mDreamsEnabledOnBatteryConfig=" + + mDreamsEnabledOnBatteryConfig); + pw.println(" mDreamsBatteryLevelMinimumWhenPoweredConfig=" + + mDreamsBatteryLevelMinimumWhenPoweredConfig); + pw.println(" mDreamsBatteryLevelMinimumWhenNotPoweredConfig=" + + mDreamsBatteryLevelMinimumWhenNotPoweredConfig); + pw.println(" mDreamsBatteryLevelDrainCutoffConfig=" + + mDreamsBatteryLevelDrainCutoffConfig); pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting); pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting); pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting); @@ -1975,8 +2143,8 @@ public final class PowerManagerService extends com.android.server.SystemService return "Awake"; case WAKEFULNESS_DREAMING: return "Dreaming"; - case WAKEFULNESS_NAPPING: - return "Napping"; + case WAKEFULNESS_DOZING: + return "Dozing"; default: return Integer.toString(wakefulness); } @@ -2153,6 +2321,7 @@ public final class PowerManagerService extends com.android.server.SystemService + " (uid=" + mOwnerUid + ", pid=" + mOwnerPid + ", ws=" + mWorkSource + ")"; } + @SuppressWarnings("deprecation") private String getLockLevelString() { switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) { case PowerManager.FULL_WAKE_LOCK: @@ -2165,6 +2334,8 @@ public final class PowerManagerService extends com.android.server.SystemService return "PARTIAL_WAKE_LOCK "; case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: return "PROXIMITY_SCREEN_OFF_WAKE_LOCK"; + case PowerManager.DOZE_WAKE_LOCK: + return "DOZE_WAKE_LOCK "; default: return "??? "; } @@ -2295,16 +2466,24 @@ public final class PowerManagerService extends com.android.server.SystemService synchronized (this) { mBlanked = true; mDisplayManagerInternal.blankAllDisplaysFromPowerManager(); - nativeSetInteractive(false); - nativeSetAutoSuspend(true); + if (!mDecoupleInteractiveModeFromDisplayConfig) { + setInteractiveModeLocked(false); + } + if (!mDecoupleAutoSuspendModeFromDisplayConfig) { + setAutoSuspendModeLocked(true); + } } } @Override public void unblankAllDisplays() { synchronized (this) { - nativeSetAutoSuspend(false); - nativeSetInteractive(true); + if (!mDecoupleAutoSuspendModeFromDisplayConfig) { + setAutoSuspendModeLocked(false); + } + if (!mDecoupleInteractiveModeFromDisplayConfig) { + setInteractiveModeLocked(true); + } mDisplayManagerInternal.unblankAllDisplaysFromPowerManager(); mBlanked = false; } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 803b9ac..4aae5c1 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -364,8 +364,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { * motion event processing when the screen is off since these events are normally * dropped. */ @Override - public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { - return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); + public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) { + return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(whenNanos, policyFlags); } /* Provides an opportunity for the window manager policy to process a key before diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index 1a3ce63..d1cfff4 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -6,6 +6,7 @@ LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \ $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \ $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \ $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \ diff --git a/services/core/jni/com_android_server_dreams_McuHal.cpp b/services/core/jni/com_android_server_dreams_McuHal.cpp new file mode 100644 index 0000000..a6d9297 --- /dev/null +++ b/services/core/jni/com_android_server_dreams_McuHal.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014 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. + */ + +#define LOG_TAG "McuHal" + +//#define LOG_NDEBUG 0 + +#include "JNIHelp.h" +#include "jni.h" + +#include <ScopedUtfChars.h> +#include <ScopedPrimitiveArray.h> + +#include <utils/Errors.h> +#include <utils/Log.h> +#include <hardware/mcu.h> + +namespace android { + +static jlong nativeOpen(JNIEnv* env, jclass clazz) { + mcu_module_t* module = NULL; + status_t err = hw_get_module(MCU_HARDWARE_MODULE_ID, + (hw_module_t const**)&module); + if (err) { + ALOGE("Couldn't load %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err)); + return 0; + } + + err = module->init(module); + if (err) { + ALOGE("Couldn't initialize %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err)); + return 0; + } + + return reinterpret_cast<jlong>(module); +} + +static jbyteArray nativeSendMessage(JNIEnv* env, jclass clazz, + jlong ptr, jstring msgStr, jbyteArray argArray) { + mcu_module_t* module = reinterpret_cast<mcu_module_t*>(ptr); + + ScopedUtfChars msg(env, msgStr); + ALOGV("Sending message %s to MCU", msg.c_str()); + + void* result = NULL; + size_t resultSize = 0; + status_t err; + if (argArray) { + ScopedByteArrayRO arg(env, argArray); + err = module->sendMessage(module, msg.c_str(), arg.get(), arg.size(), + &result, &resultSize); + } else { + err = module->sendMessage(module, msg.c_str(), NULL, 0, &result, &resultSize); + } + if (err) { + ALOGE("Couldn't send message to MCU (%s)", strerror(-err)); + return NULL; + } + + if (!result) { + return NULL; + } + + jbyteArray resultArray = env->NewByteArray(resultSize); + if (resultArray) { + env->SetByteArrayRegion(resultArray, 0, resultSize, static_cast<jbyte*>(result)); + } + free(result); + return resultArray; +} + +static JNINativeMethod gMcuHalMethods[] = { + /* name, signature, funcPtr */ + { "nativeOpen", "()J", + (void*) nativeOpen }, + { "nativeSendMessage", "(JLjava/lang/String;[B)[B", + (void*) nativeSendMessage }, +}; + +int register_android_server_dreams_McuHal(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "com/android/server/dreams/McuHal", + gMcuHalMethods, NELEM(gMcuHalMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + return 0; +} + +} /* namespace android */ diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 0542ce0..697f56d 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -144,8 +144,6 @@ static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t styl enum { WM_ACTION_PASS_TO_USER = 1, - WM_ACTION_WAKE_UP = 2, - WM_ACTION_GO_TO_SLEEP = 4, }; @@ -834,7 +832,7 @@ void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& p JNIEnv* env = jniEnv(); jint wmActions = env->CallIntMethod(mServiceObj, gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff, - policyFlags); + when, policyFlags); if (checkAndClearExceptionFromCallback(env, "interceptMotionBeforeQueueingWhenScreenOff")) { wmActions = 0; @@ -850,20 +848,6 @@ void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& p void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags) { - if (wmActions & WM_ACTION_GO_TO_SLEEP) { -#if DEBUG_INPUT_DISPATCHER_POLICY - ALOGD("handleInterceptActions: Going to sleep."); -#endif - android_server_PowerManagerService_goToSleep(when); - } - - if (wmActions & WM_ACTION_WAKE_UP) { -#if DEBUG_INPUT_DISPATCHER_POLICY - ALOGD("handleInterceptActions: Waking up."); -#endif - android_server_PowerManagerService_wakeUp(when); - } - if (wmActions & WM_ACTION_PASS_TO_USER) { policyFlags |= POLICY_FLAG_PASS_TO_USER; } else { @@ -1402,7 +1386,7 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff, clazz, - "interceptMotionBeforeQueueingWhenScreenOff", "(I)I"); + "interceptMotionBeforeQueueingWhenScreenOff", "(JI)I"); GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz, "interceptKeyBeforeDispatching", diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index efc34a2..00986d5 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -36,6 +36,7 @@ int register_android_server_location_GpsLocationProvider(JNIEnv* env); int register_android_server_location_FlpHardwareProvider(JNIEnv* env); int register_android_server_connectivity_Vpn(JNIEnv* env); int register_android_server_AssetAtlasService(JNIEnv* env); +int register_android_server_dreams_McuHal(JNIEnv* env); }; using namespace android; @@ -67,7 +68,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) register_android_server_connectivity_Vpn(env); register_android_server_AssetAtlasService(env); register_android_server_ConsumerIrService(env); - + register_android_server_dreams_McuHal(env); return JNI_VERSION_1_4; } |