diff options
author | Steve Kondik <steve@cyngn.com> | 2013-11-04 02:59:16 +0000 |
---|---|---|
committer | Steve Kondik <steve@cyngn.com> | 2015-11-01 05:06:16 -0800 |
commit | 41be9385e036bcfb7a1c8c5a86bb60addfaec657 (patch) | |
tree | 5510209512d60dc02fb360d40feadb8213c005c2 | |
parent | 2e724e9fe80ccf4ba8f2a98963279e4182485a60 (diff) | |
download | frameworks_base-41be9385e036bcfb7a1c8c5a86bb60addfaec657.zip frameworks_base-41be9385e036bcfb7a1c8c5a86bb60addfaec657.tar.gz frameworks_base-41be9385e036bcfb7a1c8c5a86bb60addfaec657.tar.bz2 |
power: Add CM performance manager
Squashed commit of:
power: Add CPU boosting interface
* Boosts CPU using Power HAL for the given duration.
* Duration is given in microseconds.
* Power HAL must implement POWER_HINT_CPU_BOOST.
Add CPU boosting hooks
* Send boost hint during scrolling
* Still relevant on even high-end hardware
perf: Send a boost hint when a key on the navbar is pressed
* A lot of stuff happens, especially when invoking recents.
* Get ahead of the storm by sending a boost hint before
kicking off the animations.
perf: Send boost hint during initial launch
perf: Per-app performance profiles
* Performance Profiles is going to grow into a much more powerful
feature which can apply advanced optimizations or power saving
techniques depending on both the state of the hardware as well
as the current applications in use.
* Refactor the original code and move it into PowerManager so
that it's managed from the same place.
* Implement "automatic performance profiles". This feature will
automatically select a profile when specific activities are
running. Currently this list is static and engages performance
mode for several benchmarks (trollface).
* Added support for a new power hint, POWER_HINT_SET_PROFILE.
Currently, these profiles are fired using a property trigger
in init. This is easy, but the PowerHAL can do more.
* Moved the setting to Settings.Secure and also wrapped calls
to the service in the DEVICE_POWER permission. Nobody should
mess with this stuff except the system.
* Powersave profile will automatically activate Android's built-in
low power mode.
* Original patch by Jorge Ruesga
TODO:
* Implement API for per-app configuration by user
* Quicksettings tile
perf: Boost during animations
* Reduce animation jank by preemptively boostin the CPUs.
* Original idea taken from CodeAurora, modified for CM perf control.
systemui: Boost when expanding the notification shade
power: Add a new power hint for application launches
* Some devices may prefer a different behavior when launching apps,
particularly to avoid priority inversion issues. Add support
for a new LAUNCH_BOOST hint which can be handled in the PowerHAL.
power: Boost improvements
* Boost when opening the panelview
* Adjust launch boost to handle relaunch correctly
PowerManager: change performance profile when disabling battery saver
We need to be sure to update the performance profile when the system
disables battery saver mode.
This fixes the perf tile becoming out of sync - changing it to low power
mode triggers power saver, but turning power saver off does not trigger
the tile.
Ref: CYNGNOS-1156
Signed-off-by: Roman Birg <roman@cyngn.com>
base: cache power profiles support
Signed-off-by: Jorge Ruesga <jorge@ruesga.com>
perf: Add support for additional power profiles
* Add support for bias power (efficiency) and bias performance (quick)
modes if supported by a device.
Change-Id: Id3a53eaacdaf6ae93ee899835cfcb21279d35ad4
18 files changed, 551 insertions, 4 deletions
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index d0ac6ce..6aab6cd 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -68,4 +68,12 @@ interface IPowerManager void setKeyboardLight(boolean on, int key); void wakeUpWithProximityCheck(long time, String reason, String opPackageName); + + void cpuBoost(int duration); + void launchBoost(); + + boolean setPowerProfile(String profile); + String getPowerProfile(); + + void activityResumed(String componentName); } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 2c131ca..dbbc4a0 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -18,7 +18,10 @@ package android.os; import android.annotation.SdkConstant; import android.annotation.SystemApi; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; import android.util.Log; /** @@ -388,9 +391,35 @@ public final class PowerManager { */ public static final String REBOOT_RECOVERY = "recovery"; + /** + * Power save profile + * @hide + */ + public static final String PROFILE_POWER_SAVE = "0"; + + /** + * Balanced power profile + * @hide + */ + public static final String PROFILE_BALANCED = "1"; + + /** + * High-performance profile + * @hide + */ + public static final String PROFILE_HIGH_PERFORMANCE = "2"; + + /** + * Broadcast sent when profile is changed + * @hide + */ + public static final String POWER_PROFILE_CHANGED = + "com.cyanogenmod.power.PROFILE_CHANGED"; + final Context mContext; final IPowerManager mService; final Handler mHandler; + private final boolean mHasPowerProfilesSupport; IDeviceIdleController mIDeviceIdleController; @@ -401,6 +430,10 @@ public final class PowerManager { mContext = context; mService = service; mHandler = handler; + + mHasPowerProfilesSupport = !TextUtils.isEmpty(getDefaultPowerProfile()) && + !TextUtils.isEmpty(mContext.getResources().getString( + com.android.internal.R.string.config_perf_profile_prop)); } /** @@ -949,6 +982,40 @@ public final class PowerManager { } catch (RemoteException e) { } } + + /** + * Boost the CPU. Boosts the cpu for the given duration in microseconds. + * Requires the {@link android.Manifest.permission#CPU_BOOST} permission. + * + * @param duration in microseconds to boost the CPU + * + * @hide + */ + public void cpuBoost(int duration) + { + try { + if (mService != null) { + mService.cpuBoost(duration); + } + } catch (RemoteException e) { + } + } + + /** + * Boost the CPU for an application launch. + * Requires the {@link android.Manifest.permission#CPU_BOOST} permission. + * + * @hide + */ + public void launchBoost() + { + try { + if (mService != null) { + mService.launchBoost(); + } + } catch (RemoteException e) { + } + } /** * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes. @@ -1006,6 +1073,89 @@ public final class PowerManager { = "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED"; /** + * True if the system supports power profiles + * + * @hide + */ + public boolean hasPowerProfiles() { + return mHasPowerProfilesSupport; + } + + /** + * Gets the default power profile for the device. + * + * Returns null if not enabled. + * + * @hide + */ + public String getDefaultPowerProfile() { + return mContext.getResources().getString( + com.android.internal.R.string.config_perf_profile_default_entry); + } + + /** + * Set the system power profile + * + * @throws IllegalArgumentException if invalid + * @hide + */ + public boolean setPowerProfile(String profile) { + if (!hasPowerProfiles()) { + throw new IllegalArgumentException("Power profiles not enabled on this system!"); + } + + boolean changed = false; + try { + if (mService != null) { + changed = mService.setPowerProfile(profile); + } + } catch (RemoteException e) { + throw new IllegalArgumentException(e); + } + return changed; + } + + /** + * Gets the current power profile + * + * Returns null if power profiles are not enabled + * @hide + */ + public String getPowerProfile() { + String ret = null; + if (hasPowerProfiles()) { + try { + if (mService != null) { + ret = mService.getPowerProfile(); + } + } catch (RemoteException e) { + // nothing + } + } + return ret; + } + + /** + * Update profile for resumed app, called from ActivityStack + * @hide + */ + public void activityResumed(Intent intent) { + String ret = null; + if (hasPowerProfiles()) { + try { + if (intent != null && mService != null) { + ComponentName cn = intent.getComponent(); + if (cn != null) { + mService.activityResumed(cn.flattenToString()); + } + } + } catch (RemoteException e) { + // nothing + } + } + } + + /** * A wake lock is a mechanism to indicate that your application needs * to have the device stay on. * <p> diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d92d3d0..7ab1be3 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6596,6 +6596,19 @@ public final class Settings { public static final String THEME_PREV_BOOT_API_LEVEL = "theme_prev_boot_api_level"; /** + * Performance profile + * @see config_perf_profile_prop in frameworks/base/core/res/res/values/config.xml + * @hide + */ + public static final String PERFORMANCE_PROFILE = "performance_profile"; + + /** + * App-based performance profile selection + * @hide + */ + public static final String APP_PERFORMANCE_PROFILES_ENABLED = "app_perf_profiles_enabled"; + + /** * This are the settings to be backed up. * * NOTE: Settings are backed up and restored in the order they appear diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java index 50569d7..9130d9a 100644 --- a/core/java/android/widget/OverScroller.java +++ b/core/java/android/widget/OverScroller.java @@ -18,6 +18,7 @@ package android.widget; import android.content.Context; import android.hardware.SensorManager; +import android.os.PowerManager; import android.util.Log; import android.view.ViewConfiguration; import android.view.animation.AnimationUtils; @@ -599,6 +600,8 @@ public class OverScroller { private static final int CUBIC = 1; private static final int BALLISTIC = 2; + private final PowerManager mPm; + static { float x_min = 0.0f; float y_min = 0.0f; @@ -643,6 +646,7 @@ public class OverScroller { * 39.37f // inch/meter * ppi * 0.84f; // look and feel tuning + mPm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); } void updateScroll(float q) { @@ -760,6 +764,7 @@ public class OverScroller { if (velocity != 0) { mDuration = mSplineDuration = getSplineFlingDuration(velocity); totalDistance = getSplineFlingDistance(velocity); + mPm.cpuBoost(mDuration * 1000); } mSplineDistance = (int) (totalDistance * Math.signum(velocity)); diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java index 357c9c3..a968eae 100644 --- a/core/java/android/widget/Scroller.java +++ b/core/java/android/widget/Scroller.java @@ -19,6 +19,7 @@ package android.widget; import android.content.Context; import android.hardware.SensorManager; import android.os.Build; +import android.os.PowerManager; import android.view.ViewConfiguration; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; @@ -108,6 +109,8 @@ public class Scroller { private float mDeceleration; private final float mPpi; + private final PowerManager mPm; + // A context-specific coefficient adjusted to physical values. private float mPhysicalCoeff; @@ -178,6 +181,8 @@ public class Scroller { mFlywheel = flywheel; mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning + + mPm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); } /** @@ -395,6 +400,8 @@ public class Scroller { mDeltaX = dx; mDeltaY = dy; mDurationReciprocal = 1.0f / (float) mDuration; + + mPm.cpuBoost(duration * 1000); } /** diff --git a/core/res/res/values/cm_arrays.xml b/core/res/res/values/cm_arrays.xml index c413a12..225dd0a 100644 --- a/core/res/res/values/cm_arrays.xml +++ b/core/res/res/values/cm_arrays.xml @@ -212,4 +212,17 @@ <item>@string/app_ops_su</item> </string-array> + <!-- Performance profiles --> + <string-array name="perf_profile_entries" translatable="false"> + <item>@string/perf_profile_pwrsv</item> + <item>@string/perf_profile_bal</item> + <item>@string/perf_profile_perf</item> + </string-array> + + <string-array name="perf_profile_values" translatable="false"> + <item>0</item> + <item>1</item> + <item>2</item> + </string-array> + </resources> diff --git a/core/res/res/values/cm_strings.xml b/core/res/res/values/cm_strings.xml index 19b71ef..d37942b 100644 --- a/core/res/res/values/cm_strings.xml +++ b/core/res/res/values/cm_strings.xml @@ -221,4 +221,12 @@ <string name="app_ops_get_accounts">get device accounts</string> <string name="app_ops_wifi_change">change WiFI state</string> <string name="app_ops_su">get Superuser access</string> + + <!-- Performance profile modes --> + <string name="perf_profile_pwrsv">Power save</string> + <string name="perf_profile_bal">Balanced</string> + <string name="perf_profile_perf">Performance</string> + <string name="perf_profile_bias_power">Efficiency</string> + <string name="perf_profile_bias_perf">Quick</string> + </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 0dd4b40..11d1572 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2461,4 +2461,20 @@ <string-array name="config_restrict_to_region_locked_devices" translatable="false"> </string-array> + <!-- Defines the system property to set for performance profile xe: sys.cpu.modes. Leave it + blank if the device do not support performance profiles --> + <string name="config_perf_profile_prop" translatable="false"></string> + + <!-- When config_perf_profile_prop is defined, this value MUST be the index of + one of the listes values in frameworks/base/core/res/res/values/cm_arrays.xml + for "perf_profile_values" array. Leave it blank if the device do not support + performance profiles --> + <string name="config_perf_profile_default_entry" translatable="false"></string> + + <!-- Automatic power profile management per app. + Each item should list the fully-qualified activity + name and the power profile id, separated by a comma. --> + <string-array name="config_auto_perf_activities" translatable="false"> + </string-array> + </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 1173069..5372320 100755..100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2394,4 +2394,15 @@ <java-symbol type="anim" name="last_app_in" /> <java-symbol type="anim" name="last_app_out" /> + <!-- Performance Profiles --> + <java-symbol type="string" name="config_perf_profile_prop" /> + <java-symbol type="string" name="config_perf_profile_default_entry" /> + <java-symbol type="array" name="perf_profile_entries" /> + <java-symbol type="array" name="perf_profile_values" /> + <java-symbol type="string" name="perf_profile_pwrsv" /> + <java-symbol type="string" name="perf_profile_bal" /> + <java-symbol type="string" name="perf_profile_perf" /> + + <!-- Array of default activities with custom power management --> + <java-symbol type="array" name="config_auto_perf_activities" /> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index ff6ae8d..ae3f89c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -23,6 +23,7 @@ import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.os.PowerManager; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -86,6 +87,8 @@ public abstract class PanelView extends FrameLayout { private VelocityTrackerInterface mVelocityTracker; private FlingAnimationUtils mFlingAnimationUtils; + private final PowerManager mPm; + /** * Whether an instant expand request is currently pending and we are just waiting for layout. */ @@ -202,6 +205,8 @@ public abstract class PanelView extends FrameLayout { mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); mBounceInterpolator = new BounceInterpolator(); + + mPm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); } protected void loadDimens() { @@ -671,6 +676,9 @@ public abstract class PanelView extends FrameLayout { / collapseSpeedUpFactor)); } } + + mPm.cpuBoost((int)animator.getDuration() * 1000); + animator.addListener(new AnimatorListenerAdapter() { private boolean mCancelled; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index bc2be8d..e4c9dab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -25,6 +25,7 @@ import android.content.res.TypedArray; import android.hardware.input.InputManager; import android.media.AudioManager; import android.os.Bundle; +import android.os.PowerManager; import android.os.SystemClock; import android.util.AttributeSet; import android.view.HapticFeedbackConstants; @@ -54,6 +55,8 @@ public class KeyButtonView extends ImageView { private boolean mGestureAborted; private boolean mPerformedLongClick; + private PowerManager mPm; + private final Runnable mCheckLongPress = new Runnable() { public void run() { if (isPressed()) { @@ -90,6 +93,7 @@ public class KeyButtonView extends ImageView { mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); setBackground(new KeyButtonRipple(context, this)); + mPm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); } @Override @@ -160,6 +164,9 @@ public class KeyButtonView extends ImageView { return false; } + // A lot of stuff is about to happen. Lets get ready. + mPm.cpuBoost(750000); + switch (action) { case MotionEvent.ACTION_DOWN: mDownTime = SystemClock.uptimeMillis(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 23d9b9f..aa3d97d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -22,6 +22,7 @@ import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PointF; +import android.os.PowerManager; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; @@ -208,6 +209,9 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mDelegateToScrollView; private boolean mDisallowScrollingInThisMotion; private long mGoToFullShadeDelay; + + private final PowerManager mPm; + private ViewTreeObserver.OnPreDrawListener mChildrenUpdater = new ViewTreeObserver.OnPreDrawListener() { @Override @@ -254,6 +258,8 @@ public class NotificationStackScrollLayout extends ViewGroup mExpandHelper.setEventSource(this); mExpandHelper.setScrollAdapter(this); + mPm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext()); mSwipeHelper.setLongPressListener(mLongPressListener); initView(context); @@ -839,6 +845,11 @@ public class NotificationStackScrollLayout extends ViewGroup && !mOnlyScrollingInThisMotion) { horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev); } + + if (expandWantsIt && mIsBeingDragged) { + mPm.cpuBoost(200 * 1000); + } + return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev); } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 218ee02..8cbf6e0 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1685,6 +1685,9 @@ final class ActivityStack { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); + // Some activities may want to alter the system power management + mStackSupervisor.mPm.activityResumed(next.intent); + // If we are currently pausing an activity, then don't do anything // until that is done. if (!mStackSupervisor.allPausedActivitiesComplete()) { @@ -1817,6 +1820,9 @@ final class ActivityStack { mWindowManager.prepareAppTransition(prev.task == next.task ? AppTransition.TRANSIT_ACTIVITY_CLOSE : AppTransition.TRANSIT_TASK_CLOSE, false); + if (prev.task != next.task) { + mStackSupervisor.mPm.cpuBoost(2000 * 1000); + } } mWindowManager.setAppWillBeHidden(prev.appToken); mWindowManager.setAppVisibility(prev.appToken, false); @@ -1832,6 +1838,9 @@ final class ActivityStack { : next.mLaunchTaskBehind ? AppTransition.TRANSIT_TASK_OPEN_BEHIND : AppTransition.TRANSIT_TASK_OPEN, false); + if (prev.task != next.task) { + mStackSupervisor.mPm.cpuBoost(2000 * 1000); + } } } if (false) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index d20a9c4..b66e88c 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -273,6 +273,8 @@ public final class ActivityStackSupervisor implements DisplayListener { * setWindowManager is called. **/ private boolean mLeanbackOnlyDevice; + PowerManager mPm; + /** * Is the privacy guard currently enabled? Shared between ActivityStacks */ @@ -354,9 +356,9 @@ public final class ActivityStackSupervisor implements DisplayListener { * initialized. So we initialize our wakelocks afterwards. */ void initPowerManagement() { - PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); - mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep"); - mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*launch*"); + mPm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); + mGoingToSleep = mPm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep"); + mLaunchingActivity = mPm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*launch*"); mLaunchingActivity.setReferenceCounted(false); } @@ -1434,6 +1436,8 @@ public final class ActivityStackSupervisor implements DisplayListener { Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) : (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY : container.mActivityDisplay.mDisplayId))); + /* Acquire perf lock during new app launch */ + mPm.launchBoost(); } ActivityRecord sourceRecord = null; @@ -2779,6 +2783,12 @@ public final class ActivityStackSupervisor implements DisplayListener { } void findTaskToMoveToFrontLocked(TaskRecord task, int flags, Bundle options, String reason) { + ActivityRecord top = task.stack.topRunningActivityLocked(null); + /* App is launching from recent apps and it's a new process */ + if(top != null && top.state == ActivityState.DESTROYED) { + mPm.launchBoost(); + } + if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) { mUserLeaving = true; } @@ -3060,11 +3070,16 @@ public final class ActivityStackSupervisor implements DisplayListener { } final ActivityRecord ar = stack.findTaskLocked(r); if (ar != null) { + if (ar.state == ActivityState.DESTROYED) { + mPm.launchBoost(); + } return ar; } } } if (DEBUG_TASKS) Slog.d(TAG_TASKS, "No task found"); + mPm.launchBoost(); + return null; } diff --git a/services/core/java/com/android/server/power/PerformanceManager.java b/services/core/java/com/android/server/power/PerformanceManager.java new file mode 100644 index 0000000..3ab94b9 --- /dev/null +++ b/services/core/java/com/android/server/power/PerformanceManager.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2014 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.power; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.SystemProperties; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; + +import java.util.regex.Pattern; + +class PerformanceManager { + private static final String TAG = "PerformanceManager"; + + private final Context mContext; + + private final String mPerfProfileDefault; + private final String mPerfProfileProperty; + + private Pattern[] mPatterns = null; + private String[] mProfiles = null; + + private String mCurrentProfile = null; + + private boolean mProfileSetByUser = false; + private boolean mProfilesEnabled = false; + private boolean mUsePowerHAL = false; + + private Object mLock = new Object(); + + PerformanceManager(Context context) { + mContext = context; + + String[] activities = context.getResources().getStringArray( + com.android.internal.R.array.config_auto_perf_activities); + if (activities != null && activities.length > 0) { + mPatterns = new Pattern[activities.length]; + mProfiles = new String[activities.length]; + for (int i = 0; i < activities.length; i++) { + String[] info = activities[i].split(","); + if (info.length == 2) { + mPatterns[i] = Pattern.compile(info[0]); + mProfiles[i] = info[1]; + } + } + } + + mPerfProfileDefault = context.getResources().getString( + com.android.internal.R.string.config_perf_profile_default_entry); + mPerfProfileProperty = context.getResources().getString( + com.android.internal.R.string.config_perf_profile_prop); + mProfilesEnabled = !TextUtils.isEmpty(mPerfProfileDefault) && + !TextUtils.isEmpty(mPerfProfileProperty); + + if (mProfilesEnabled) { + // Magic value- this will use a power hint instead of relying on + // a property trigger via init. This will become the default + // after devices have been updated. + mUsePowerHAL = "powerhal".equals(mPerfProfileProperty); + } + } + + void reset() { + if (mProfilesEnabled) { + // Reset the stored value to the default profile when we are initialized. + // We currently do not want to support booting in perf or powersave modes. + setPowerProfileLocked(mPerfProfileDefault); + } + } + + private void selectProfile(String profile) { + mCurrentProfile = profile; + + if (mUsePowerHAL) { + PowerManagerService.nativeSetPowerProfile(Integer.valueOf(profile)); + } else { + SystemProperties.set(mPerfProfileProperty, profile); + } + } + private boolean hasAppProfiles() { + return mProfilesEnabled && mPatterns != null && + (Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.APP_PERFORMANCE_PROFILES_ENABLED, 1) == 1); + } + + boolean setPowerProfile(String profile) { + if (!mProfilesEnabled) { + Log.e(TAG, "Power profiles not enabled on this device"); + return false; + } + if (profile == null || profile.equals(getPowerProfile())) { + return false; + } + synchronized (mLock) { + mProfileSetByUser = !profile.equals(mPerfProfileDefault); + setPowerProfileLocked(profile); + } + return true; + } + + private void setPowerProfileLocked(String profile) { + long token = Binder.clearCallingIdentity(); + + selectProfile(profile); + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.PERFORMANCE_PROFILE, profile); + Binder.restoreCallingIdentity(token); + } + + String getPowerProfile() { + return mCurrentProfile; + } + + private String getProfileForActivity(String componentName) { + if (componentName != null) { + for (int i = 0; i < mPatterns.length; i++) { + if (mPatterns[i].matcher(componentName).matches()) { + return mProfiles[i]; + } + } + } + return mPerfProfileDefault; + } + + void activityResumed(String componentName) { + if (!hasAppProfiles()) { + return; + } + + synchronized (mLock) { + // Don't mess with it if the user has manually set a profile + if (mProfileSetByUser) { + return; + } + + String forApp = getProfileForActivity(componentName); + if (forApp.equals(mCurrentProfile)) { + return; + } + + setPowerProfileLocked(forApp); + } + } +} diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index aca795c..4111cd5 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -171,6 +171,9 @@ public final class PowerManagerService extends SystemService private static final float PROXIMITY_NEAR_THRESHOLD = 5.0f; + // Max time (microseconds) to allow a CPU boost for + private static final int MAX_CPU_BOOST_TIME = 5000000; + private final Context mContext; private final ServiceThread mHandlerThread; private final PowerManagerHandler mHandler; @@ -497,6 +500,9 @@ public final class PowerManagerService extends SystemService private static native void nativeSetAutoSuspend(boolean enable); private static native void nativeSendPowerHint(int hintId, int data); private static native void nativeSetFeature(int featureId, int data); + private static native void nativeCpuBoost(int duration); + private static native void nativeLaunchBoost(); + static native void nativeSetPowerProfile(int profile); private boolean mKeyboardVisible = false; private SensorManager mSensorManager; @@ -507,6 +513,8 @@ public final class PowerManagerService extends SystemService android.os.PowerManager.WakeLock mProximityWakeLock; SensorEventListener mProximityListener; + private PerformanceManager mPerformanceManager; + public PowerManagerService(Context context) { super(context); mContext = context; @@ -514,6 +522,7 @@ public final class PowerManagerService extends SystemService Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/); mHandlerThread.start(); mHandler = new PowerManagerHandler(mHandlerThread.getLooper()); + mPerformanceManager = new PerformanceManager(context); synchronized (mLock) { mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks"); @@ -676,6 +685,8 @@ public final class PowerManagerService extends SystemService Settings.Global.WAKE_WHEN_PLUGGED_OR_UNPLUGGED), false, mSettingsObserver, UserHandle.USER_ALL); + mPerformanceManager.reset(); + // Go. readConfigurationLocked(); updateSettingsLocked(); @@ -831,6 +842,8 @@ public final class PowerManagerService extends SystemService // Turn setting off if powered Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE, 0); + // update performance profile + mPerformanceManager.setPowerProfile(PowerManager.PROFILE_BALANCED); mLowPowerModeSetting = false; } final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured @@ -3507,10 +3520,32 @@ public final class PowerManagerService extends SystemService android.Manifest.permission.DEVICE_POWER, null); final long ident = Binder.clearCallingIdentity(); try { - return setLowPowerModeInternal(mode); + boolean changed = setLowPowerModeInternal(mode); + if (changed) { + mPerformanceManager.setPowerProfile(mLowPowerModeEnabled ? + PowerManager.PROFILE_POWER_SAVE : PowerManager.PROFILE_BALANCED); + } + return changed; + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call + public boolean setPowerProfile(String profile) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); + final long ident = Binder.clearCallingIdentity(); + try { + setLowPowerModeInternal(PowerManager.PROFILE_POWER_SAVE.equals(profile)); } finally { Binder.restoreCallingIdentity(ident); } + return mPerformanceManager.setPowerProfile(profile); + } + + @Override + public String getPowerProfile() { + return mPerformanceManager.getPowerProfile(); } @Override // Binder call @@ -3524,6 +3559,42 @@ public final class PowerManagerService extends SystemService } /** + * Boost the CPU + * @param duration Duration to boost the CPU for, in milliseconds. + * @hide + */ + @Override + public void cpuBoost(int duration) { + if (duration > 0 && duration <= MAX_CPU_BOOST_TIME) { + // Don't send boosts if we're in another power profile + String profile = mPerformanceManager.getPowerProfile(); + if (profile == null || profile.equals(PowerManager.PROFILE_BALANCED)) { + nativeCpuBoost(duration); + } + } else { + Slog.e(TAG, "Invalid boost duration: " + duration); + } + } + + /** + * Boost the CPU for an app launch + * @hide + */ + @Override + public void launchBoost() { + // Don't send boosts if we're in another power profile + String profile = mPerformanceManager.getPowerProfile(); + if (profile == null || profile.equals(PowerManager.PROFILE_BALANCED)) { + nativeLaunchBoost(); + } + } + + @Override + public void activityResumed(String componentName) { + mPerformanceManager.activityResumed(componentName); + } + + /** * Reboots the device. * * @param confirm If true, shows a reboot confirmation dialog. diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index 1662755..1ceb6f1 100644 --- a/services/core/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -164,6 +164,28 @@ static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint dat } } +static void nativeCpuBoost(JNIEnv *env, jobject clazz, jint duration) { + // Tell the Power HAL to boost the CPU + if (gPowerModule && gPowerModule->powerHint) { + gPowerModule->powerHint(gPowerModule, POWER_HINT_CPU_BOOST, (void *) duration); + } +} + +static void nativeLaunchBoost(JNIEnv *env, jobject clazz) { + // Tell the Power HAL to boost the CPU + if (gPowerModule && gPowerModule->powerHint) { + gPowerModule->powerHint(gPowerModule, POWER_HINT_LAUNCH_BOOST, NULL); + } +} + +static void nativeSetPowerProfile(JNIEnv *env, jobject clazz, jint profile) { + // Tell the Power HAL to select a power profile + if (gPowerModule && gPowerModule->powerHint) { + gPowerModule->powerHint(gPowerModule, POWER_HINT_SET_PROFILE, (void *) profile); + } +} + + // ---------------------------------------------------------------------------- static JNINativeMethod gPowerManagerServiceMethods[] = { @@ -182,6 +204,12 @@ static JNINativeMethod gPowerManagerServiceMethods[] = { (void*) nativeSendPowerHint }, { "nativeSetFeature", "(II)V", (void*) nativeSetFeature }, + { "nativeCpuBoost", "(I)V", + (void*) nativeCpuBoost }, + { "nativeLaunchBoost", "()V", + (void*) nativeLaunchBoost }, + { "nativeSetPowerProfile", "(I)V", + (void*) nativeSetPowerProfile }, }; #define FIND_CLASS(var, className) \ diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java index c0a9d25..947f99c 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java @@ -158,6 +158,11 @@ public class BridgePowerManager implements IPowerManager { @Override public void setKeyboardVisibility(boolean visible) { + // pass for now. + } + + @Override + public void cpuBoost(int duration) throws RemoteException { // pass for now } |