diff options
Diffstat (limited to 'services')
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; } |