cmsdk: Refactor the PerformanceManager

* Remove all code and configuration into CMSDK.
 * Deprecate the properties-based API

Change-Id: Ib14ce5b8623cb368e6b545d1f82bc9c58580e13b
This commit is contained in:
Steve Kondik 2015-11-02 17:43:44 -08:00
parent 5e522e6805
commit 620c35bd6b
11 changed files with 639 additions and 3 deletions

View File

@ -193,7 +193,7 @@ LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:= build/tools/droiddoc/templates-sdk
LOCAL_DROIDDOC_OPTIONS:= \
-stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/cmsdk_stubs_current_intermediates/src \
-stubpackages cyanogenmod.alarmclock:cyanogenmod.app:cyanogenmod.content:cyanogenmod.hardware:cyanogenmod.media:cyanogenmod.os:cyanogenmod.profiles:cyanogenmod.providers:cyanogenmod.platform:org.cyanogenmod.platform \
-stubpackages cyanogenmod.alarmclock:cyanogenmod.app:cyanogenmod.content:cyanogenmod.hardware:cyanogenmod.media:cyanogenmod.os:cyanogenmod.profiles:cyanogenmod.providers:cyanogenmod.platform:cyanogenmod.power:org.cyanogenmod.platform \
-api $(INTERNAL_CM_PLATFORM_API_FILE) \
-removedApi $(INTERNAL_CM_PLATFORM_REMOVED_API_FILE) \
-nodocs \
@ -222,7 +222,7 @@ LOCAL_MODULE := cm-system-api-stubs
LOCAL_DROIDDOC_OPTIONS:=\
-stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/cmsdk_system_stubs_current_intermediates/src \
-stubpackages cyanogenmod.alarmclock:cyanogenmod.app:cyanogenmod.content:cyanogenmod.hardware:cyanogenmod.media:cyanogenmod.os:cyanogenmod.profiles:cyanogenmod.providers:cyanogenmod.platform:org.cyanogenmod.platform \
-stubpackages cyanogenmod.alarmclock:cyanogenmod.app:cyanogenmod.content:cyanogenmod.hardware:cyanogenmod.media:cyanogenmod.os:cyanogenmod.profiles:cyanogenmod.providers:cyanogenmod.platform:cyanogenmod.power:org.cyanogenmod.platform \
-showAnnotation android.annotation.SystemApi \
-api $(INTERNAL_CM_PLATFORM_SYSTEM_API_FILE) \
-removedApi $(INTERNAL_CM_PLATFORM_SYSTEM_REMOVED_API_FILE) \

View File

@ -0,0 +1,314 @@
/*
* 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 org.cyanogenmod.platform.internal;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.Watchdog;
import cyanogenmod.app.CMContextConstants;
import cyanogenmod.power.IPerformanceManager;
import cyanogenmod.power.PerformanceManager;
import cyanogenmod.power.PerformanceManagerInternal;
import cyanogenmod.providers.CMSettings;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Pattern;
public class PerformanceManagerService extends SystemService {
private static final String TAG = "PerformanceManager";
private final Context mContext;
private Pattern[] mPatterns = null;
private int[] mProfiles = null;
private int mCurrentProfile = -1;
private boolean mProfileSetByUser = false;
private int mNumProfiles = 0;
private final ServiceThread mHandlerThread;
private final PerformanceManagerHandler mHandler;
// keep in sync with hardware/libhardware/include/hardware/power.h
private final int POWER_HINT_CPU_BOOST = 0x00000010;
private final int POWER_HINT_LAUNCH_BOOST = 0x00000011;
private final int POWER_HINT_SET_PROFILE = 0x00000030;
private final int POWER_FEATURE_SUPPORTED_PROFILES = 0x00001000;
private PowerManagerInternal mPm;
private boolean mLowPowerModeEnabled = false;
// Max time (microseconds) to allow a CPU boost for
private static final int MAX_CPU_BOOST_TIME = 5000000;
public PerformanceManagerService(Context context) {
super(context);
mContext = context;
String[] activities = context.getResources().getStringArray(
R.array.config_auto_perf_activities);
if (activities != null && activities.length > 0) {
mPatterns = new Pattern[activities.length];
mProfiles = new int[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] = Integer.valueOf(info[1]);
}
}
}
// We need a high priority thread to handle these requests in front of
// everything else asynchronously
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_URGENT_DISPLAY + 1, false /*allowIo*/);
mHandlerThread.start();
mHandler = new PerformanceManagerHandler(mHandlerThread.getLooper());
}
@Override
public void onStart() {
publishBinderService(CMContextConstants.CM_PERFORMANCE_SERVICE, mBinder);
publishLocalService(PerformanceManagerInternal.class, new LocalService());
}
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
synchronized (this) {
mPm = getLocalService(PowerManagerInternal.class);
mNumProfiles = mPm.getFeature(POWER_FEATURE_SUPPORTED_PROFILES);
Slog.d(TAG, "Supported profiles: " + mNumProfiles);
if (mNumProfiles > 0) {
int profile = CMSettings.Secure.getInt(mContext.getContentResolver(),
CMSettings.Secure.PERFORMANCE_PROFILE,
PerformanceManager.PROFILE_BALANCED);
if (profile == PerformanceManager.PROFILE_HIGH_PERFORMANCE) {
profile = PerformanceManager.PROFILE_BALANCED;
}
setPowerProfileInternal(profile, true);
mPm.registerLowPowerModeObserver(mLowPowerModeListener);
}
}
}
}
private boolean hasAppProfiles() {
return mNumProfiles > 0 && mPatterns != null &&
(CMSettings.Secure.getInt(mContext.getContentResolver(),
CMSettings.Secure.APP_PERFORMANCE_PROFILES_ENABLED, 1) == 1);
}
private synchronized boolean setPowerProfileInternal(int profile, boolean fromUser) {
if (profile == mCurrentProfile) {
return false;
}
if (profile < 0 || profile > mNumProfiles) {
Slog.e(TAG, "Invalid profile: " + profile);
return false;
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
long token = Binder.clearCallingIdentity();
if (fromUser) {
CMSettings.Secure.putInt(mContext.getContentResolver(),
CMSettings.Secure.PERFORMANCE_PROFILE, profile);
}
mCurrentProfile = profile;
mHandler.removeMessages(MSG_CPU_BOOST);
mHandler.removeMessages(MSG_LAUNCH_BOOST);
mHandler.sendMessage(
Message.obtain(mHandler, MSG_SET_PROFILE, profile,
(fromUser ? 1 : 0)));
Binder.restoreCallingIdentity(token);
return true;
}
private int getProfileForActivity(String componentName) {
if (componentName != null) {
for (int i = 0; i < mPatterns.length; i++) {
if (mPatterns[i].matcher(componentName).matches()) {
return mProfiles[i];
}
}
}
return PerformanceManager.PROFILE_BALANCED;
}
private void cpuBoostInternal(int duration) {
if (duration > 0 && duration <= MAX_CPU_BOOST_TIME) {
// Don't send boosts if we're in another power profile
if (mCurrentProfile == PerformanceManager.PROFILE_POWER_SAVE ||
mCurrentProfile == PerformanceManager.PROFILE_HIGH_PERFORMANCE) {
return;
}
mHandler.removeMessages(MSG_CPU_BOOST);
mHandler.sendMessage(Message.obtain(mHandler, MSG_CPU_BOOST, duration, 0));
} else {
Slog.e(TAG, "Invalid boost duration: " + duration);
}
}
private final IBinder mBinder = new IPerformanceManager.Stub() {
@Override
public boolean setPowerProfile(int profile) {
return setPowerProfileInternal(profile, true);
}
/**
* Boost the CPU
*
* @param duration Duration to boost the CPU for, in milliseconds.
* @hide
*/
@Override
public void cpuBoost(int duration) {
cpuBoostInternal(duration);
}
@Override
public int getPowerProfile() {
return CMSettings.Secure.getInt(mContext.getContentResolver(),
CMSettings.Secure.PERFORMANCE_PROFILE,
PerformanceManager.PROFILE_BALANCED);
}
@Override
public int getNumberOfProfiles() {
return mNumProfiles;
}
};
private final class LocalService implements PerformanceManagerInternal {
@Override
public void cpuBoost(int duration) {
cpuBoostInternal(duration);
}
@Override
public void launchBoost() {
// Don't send boosts if we're in another power profile
if (mCurrentProfile == PerformanceManager.PROFILE_POWER_SAVE ||
mCurrentProfile == PerformanceManager.PROFILE_HIGH_PERFORMANCE) {
return;
}
mHandler.removeMessages(MSG_CPU_BOOST);
mHandler.removeMessages(MSG_LAUNCH_BOOST);
mHandler.sendEmptyMessage(MSG_LAUNCH_BOOST);
}
@Override
public void activityResumed(Intent intent) {
if (!hasAppProfiles() || intent == null || mProfileSetByUser) {
return;
}
final ComponentName cn = intent.getComponent();
if (cn == null) {
return;
}
int forApp = getProfileForActivity(cn.flattenToString());
if (forApp == mCurrentProfile) {
return;
}
setPowerProfileInternal(forApp, false);
}
}
private static final int MSG_CPU_BOOST = 1;
private static final int MSG_LAUNCH_BOOST = 2;
private static final int MSG_SET_PROFILE = 3;
/**
* Handler for asynchronous operations performed by the performance manager.
*/
private final class PerformanceManagerHandler extends Handler {
public PerformanceManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
}
@Override
public void handleMessage(Message msg) {
Slog.d(TAG, "handler what=" + msg.what + " arg=" + msg.arg1);
switch (msg.what) {
case MSG_CPU_BOOST:
mPm.powerHint(POWER_HINT_CPU_BOOST, msg.arg1);
break;
case MSG_LAUNCH_BOOST:
mPm.powerHint(POWER_HINT_LAUNCH_BOOST, 0);
break;
case MSG_SET_PROFILE:
mPm.powerHint(POWER_HINT_SET_PROFILE, msg.arg1);
break;
}
}
}
private final PowerManagerInternal.LowPowerModeListener mLowPowerModeListener = new
PowerManagerInternal.LowPowerModeListener() {
@Override
public void onLowPowerModeChanged(boolean enabled) {
if (mNumProfiles < 1) {
return;
}
if (enabled == mLowPowerModeEnabled) {
return;
}
if (enabled && mCurrentProfile != PerformanceManager.PROFILE_POWER_SAVE) {
setPowerProfileInternal(PerformanceManager.PROFILE_POWER_SAVE, true);
} else if (!enabled && mCurrentProfile == PerformanceManager.PROFILE_POWER_SAVE) {
setPowerProfileInternal(PerformanceManager.PROFILE_BALANCED, true);
}
}
};
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Performance profiles -->
<string-array name="perf_profile_entries" translatable="false">
<item>@string/perf_profile_pwrsv</item>
<item>@string/perf_profile_bias_power</item>
<item>@string/perf_profile_bal</item>
<item>@string/perf_profile_bias_perf</item>
<item>@string/perf_profile_perf</item>
</string-array>
<!-- These values are intentionally out of ordert to give an "ascending"
view of the modes while allowing devices to easily omit the bias
modes if they are not applicable or needed. These values correspond
to the enumeration in PerformanceManager. -->
<integer-array name="perf_profile_values" translatable="false">
<item>0</item>
<item>3</item>
<item>1</item>
<item>4</item>
<item>2</item>
</integer-array>
</resources>

View File

@ -38,4 +38,11 @@
<string-array name="config_appSuggestProviderPackageNames" translatable="false">
<item>com.cyanogen.app.suggest</item>
</string-array>
</resources>
<!-- 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>

View File

@ -96,4 +96,11 @@
<!-- Name of wildcard profile. -->
<string name="wildcardProfile">Other</string>
<!-- Performance profiles -->
<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>

View File

@ -29,4 +29,16 @@
<java-symbol type="xml" name="profile_default" />
<java-symbol type="string" name="wildcardProfile" />
<!-- Performance Profiles -->
<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" />
<java-symbol type="string" name="perf_profile_bias_power" />
<java-symbol type="string" name="perf_profile_bias_perf" />
<!-- Array of default activities with custom power management -->
<java-symbol type="array" name="config_auto_perf_activities" />
</resources>

View File

@ -90,4 +90,11 @@ public final class CMContextConstants {
* @hide
*/
public static final String CM_APP_SUGGEST_SERVICE = "cmappsuggest";
/**
* Control device power profile and characteristics.
*
* @hide
*/
public static final String CM_PERFORMANCE_SERVICE = "cmperformance";
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2015, 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 cyanogenmod.power;
/** @hide */
interface IPerformanceManager {
oneway void cpuBoost(int duration);
boolean setPowerProfile(int profile);
int getPowerProfile();
int getNumberOfProfiles();
}

View File

@ -0,0 +1,181 @@
/*
* Copyright (C) 2015 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 cyanogenmod.power;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import cyanogenmod.app.CMContextConstants;
/**
*
*/
public class PerformanceManager {
public static final String TAG = "PerformanceManager";
/**
* Power save profile
*
* This mode sacrifices performance for maximum power saving.
*/
public static final int PROFILE_POWER_SAVE = 0;
/**
* Balanced power profile
*
* The default mode for balanced power savings and performance
*/
public static final int PROFILE_BALANCED = 1;
/**
* High-performance profile
*
* This mode sacrifices power for maximum performance
*/
public static final int PROFILE_HIGH_PERFORMANCE = 2;
/**
* Power save bias profile
*
* This mode decreases performance slightly to improve
* power savings.
*/
public static final int PROFILE_BIAS_POWER_SAVE = 3;
/**
* Performance bias profile
*
* This mode improves performance at the cost of some power.
*/
public static final int PROFILE_BIAS_PERFORMANCE = 4;
private int mNumberOfProfiles = 0;
/**
* Broadcast sent when profile is changed
*/
public static final String POWER_PROFILE_CHANGED = "cyanogenmod.power.PROFILE_CHANGED";
private static IPerformanceManager sService;
private static PerformanceManager sInstance;
private PerformanceManager(Context context) {
sService = getService();
try {
if (sService != null) {
mNumberOfProfiles = sService.getNumberOfProfiles();
}
} catch (RemoteException e) {
}
}
public static PerformanceManager getInstance(Context context) {
if (sInstance == null) {
sInstance = new PerformanceManager(context);
}
return sInstance;
}
private static IPerformanceManager getService() {
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService(CMContextConstants.CM_PERFORMANCE_SERVICE);
if (b != null) {
sService = IPerformanceManager.Stub.asInterface(b);
return sService;
}
return null;
}
private boolean checkService() {
if (sService == null) {
Log.w(TAG, "not connected to PerformanceManagerService");
return false;
}
return true;
}
/**
* 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 (checkService()) {
sService.cpuBoost(duration);
}
} catch (RemoteException e) {
}
}
/**
* Returns the number of supported profiles, zero if unsupported
* This is queried via the PowerHAL.
*/
public int getNumberOfProfiles() {
return mNumberOfProfiles;
}
/**
* Set the system power profile
*
* @throws IllegalArgumentException if invalid
*/
public boolean setPowerProfile(int profile) {
if (mNumberOfProfiles < 1) {
throw new IllegalArgumentException("Power profiles not enabled on this system!");
}
boolean changed = false;
try {
if (checkService()) {
changed = sService.setPowerProfile(profile);
}
} catch (RemoteException e) {
throw new IllegalArgumentException(e);
}
return changed;
}
/**
* Gets the current power profile
*
* Returns null if power profiles are not enabled
*/
public int getPowerProfile() {
int ret = -1;
if (mNumberOfProfiles > 0) {
try {
if (checkService()) {
ret = sService.getPowerProfile();
}
} catch (RemoteException e) {
// nothing
}
}
return ret;
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2015 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 cyanogenmod.power;
import android.content.Intent;
/** {@hide} */
public interface PerformanceManagerInternal {
void activityResumed(Intent intent);
void cpuBoost(int duration);
void launchBoost();
}

View File

@ -1178,6 +1178,18 @@ public final class CMSettings {
@Deprecated
public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
/**
* Performance profile
* @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";
// endregion
}