点击SystuemUI的下拉栏的省电模式按钮,首先调用的是BatteryControllerImpl.java的setPowerSaveMode()
@Override
public void setPowerSaveMode(boolean powerSave) {
BatterySaverUtils.setPowerSaveMode(mContext, powerSave, /*needFirstTimeWarning*/ true);
}
启动省电模式的话,这里的参数powerSave
将会被置为true,BatterySaverUtils是SettingsLib
中的一个类
public static synchronized boolean setPowerSaveMode(Context context,
boolean enable, boolean needFirstTimeWarning) {
if (DEBUG) {
Log.d(TAG, "Battery saver turning " + (enable ? "ON" : "OFF"));
}
final ContentResolver cr = context.getContentResolver();
if (enable && needFirstTimeWarning && maybeShowBatterySaverConfirmation(context)) {
return false;
}
if (enable && !needFirstTimeWarning) {
setBatterySaverConfirmationAcknowledged(context);
}
if (context.getSystemService(PowerManager.class).setPowerSaveMode(enable)) {
if (enable) {
final int count =
Secure.getInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 0) + 1;
Secure.putInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, count);
final Parameters parameters = new Parameters(context);
if ((count >= parameters.startNth)
&& (count <= parameters.endNth)
&& Global.getInt(cr, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) == 0
&& Secure.getInt(cr,
Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 0) == 0) {
showAutoBatterySaverSuggestion(context);
}
}
return true;
}
return false;
}
这个类里面,实现的方法主要为context.getSystemService(PowerManager.class).setPowerSaveMode(enable)。
会通过getSystemService去拿到PowerManager的对象,然后去调用setPowerSaveMode的函数进行具体的设置。
PowerManager.java-->setPowerSaveMode()
public boolean setPowerSaveMode(boolean mode) {
try {
return mService.setPowerSaveMode(mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
PowerManagerService.java-->setPowerSaveMode()
@Override // Binder call
public boolean setPowerSaveMode(boolean enabled) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final long ident = Binder.clearCallingIdentity();
try {
return setLowPowerModeInternal(enabled);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
先调用enforceCallingOrSelfPermission检查权限,然后调用setLowPowerModeInternal()
private boolean setLowPowerModeInternal(boolean enabled) {
synchronized (mLock) {
if (DEBUG) {
Slog.d(TAG, "setLowPowerModeInternal " + enabled + " mIsPowered=" + mIsPowered);
}
mBatterySaverStateMachine.setBatterySaverEnabledManually(enabled);
return true;
}
}
手动开关 省电模式:
BatterySaverStateMachine.java-->setBatterySaverEnabledManually()
public void setBatterySaverEnabledManually(boolean enabled) {
if (DEBUG) {
Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled);
}
synchronized (mLock) {
enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
(enabled ? BatterySaverController.REASON_MANUAL_ON
: BatterySaverController.REASON_MANUAL_OFF),
(enabled ? "Manual ON" : "Manual OFF"));
}
}
BatterySaverStateMachine.java-->enableBatterySaverLocked()
/**
* Actually enable / disable battery saver. Write the new state to the global settings
* and propagate it to {@link #mBatterySaverController}.
*/
private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason,
String strReason) {
if (DEBUG) {
Slog.d(TAG, "enableBatterySaver: enable=" + enable + " manual=" + manual
+ " reason=" + strReason + "(" + intReason + ")");
}
final boolean wasEnabled = mBatterySaverController.isEnabled();
//省电模式状态没有改变的话直接return
if (wasEnabled == enable) {
if (DEBUG) {
Slog.d(TAG, "Already " + (enable ? "enabled" : "disabled"));
}
return;
}
//充电情况下尝试打开 省电模式 直接return
if (enable && mIsPowered) {
if (DEBUG) Slog.d(TAG, "Can't enable: isPowered");
return;
}
//记录此次改变省电模式状态的 reason ,各个 reason 的值定义在 BatterySaverController 中
mLastChangedIntReason = intReason;
mLastChangedStrReason = strReason;
//mBatterySaverSnoozing 主要是用于记录 低电量情况下,用户是否手动关闭 了省电模式,防止用户手动关闭 省电模式后,又被自动打开
if (manual) {
if (enable) {
updateSnoozingLocked(false, "Manual snooze OFF");
} else {
// When battery saver is disabled manually (while battery saver is enabled)
// when the battery level is low, we "snooze" BS -- i.e. disable auto battery saver.
// We resume auto-BS once the battery level is not low, or the device is plugged in.
if (isBatterySaverEnabled() && mIsBatteryLevelLow) {
updateSnoozingLocked(true, "Manual snooze");
}
}
}
mSettingBatterySaverEnabled = enable;
//更新 省电模式状态 到 settings 数据库字段中
putGlobalSetting(Global.LOW_POWER_MODE, enable ? 1 : 0);
if (manual) {
mSettingBatterySaverEnabledSticky = enable;
putGlobalSetting(Global.LOW_POWER_MODE_STICKY, enable ? 1 : 0);
}
//好了,前面这些全部都是前戏,这里才开始真正的做 省电的动作
mBatterySaverController.enableBatterySaver(enable, intReason);
if (DEBUG) {
Slog.d(TAG, "Battery saver: Enabled=" + enable
+ " manual=" + manual
+ " reason=" + strReason + "(" + intReason + ")");
}
}
1.wasEnabled首先会去判断是否之前已经是enable的状态,如果是的话,那么就return。
2.isPowered如果为true的话的也是会直接返回。
3.mLastChangedIntReason ,mLastChangedStrReason的值会被保存为之前传进来的值,也就是 mLastChangedIntReason=2,mLastChangedStrReason="Manual ON".
4.manual和enable都是true的状态,所以会upateSnoozingLocked.而这个函数,其实只是设置mBatterySaverSnoozing的值为ture。而这个值的使用,我们后续还会遇到。
5.putGlobalSetting(Global.LOW_POWER_MODE, enable ? 1 : 0);,将LOW_POWER_MODE的值在数据库中置为1.
6.putGlobalSetting(Global.LOW_POWER_MODE_STICKY, enable ? 1 : 0);,将LOW_POWER_MODE_STICKY的值在数据库中置为1.
7.mBatterySaverController.enableBatterySaver(enable, intReason); 在保存完相应的数据库之后,将会调用这个函数进行真正的操作。
BatterySaverController.java-->enableBatterySaver()
/**
* Called by {@link PowerManagerService} to update the battery saver stete.
*/
public void enableBatterySaver(boolean enable, int reason) {
synchronized (mLock) {
if (mEnabled == enable) {
return;
}
mEnabled = enable;
mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
}
}
在调用controller的enableBatterySaver函数中,主要是讲mEnable设置为true。并且将实际的reason给传递到Handler里面。
public void postStateChanged(boolean sendBroadcast, int reason) {
obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, reason).sendToTarget();
}
@Override
public void dispatchMessage(Message msg) {
switch (msg.what) {
case MSG_STATE_CHANGED:
handleBatterySaverStateChanged(
msg.arg1 == ARG_SEND_BROADCAST,
msg.arg2);
break;
case MSG_SYSTEM_READY:
for (Plugin p : mPlugins) {
p.onSystemReady(BatterySaverController.this);
}
break;
}
}
BatterySaverController.java-->handleBatterySaverStateChanged()
/**
* Dispatch power save events to the listeners.
*
* This method is always called on the handler thread.
*
* This method is called only in the following cases:
* - When battery saver becomes activated.
* - When battery saver becomes deactivated.
* - When battery saver is on the interactive state changes.
* - When battery saver is on the battery saver policy changes.
*/
void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) {
final LowPowerModeListener[] listeners;
final boolean enabled;
//isInteractive 用于标志设备是否处于可交互状态
final boolean isInteractive = getPowerManager().isInteractive();
final ArrayMap fileValues;
synchronized (mLock) {
//battery_saver_mode: [1,0,1,,1] event log的格式,大致含义根据变量名就可以看出来
EventLogTags.writeBatterySaverMode(
mPreviouslyEnabled ? 1 : 0, // Previously off or on.
mEnabled ? 1 : 0, // Now off or on.
isInteractive ? 1 : 0, // Device interactive state.
mEnabled ? mBatterySaverPolicy.toEventLogString() : "",
reason);
mPreviouslyEnabled = mEnabled;
listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
enabled = mEnabled;
mIsInteractive = isInteractive;
if (enabled) {
fileValues = mBatterySaverPolicy.getFileValues(isInteractive);
} else {
fileValues = null;
}
}
//似乎是 CPU 频率相关的设置,下面是 到JNI里,没有去跟
final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
if (pmi != null) {
pmi.powerHint(PowerHint.LOW_POWER, enabled ? 1 : 0);
}
updateBatterySavingStats();
if (ArrayUtils.isEmpty(fileValues)) {
mFileUpdater.restoreDefault();
} else {
mFileUpdater.writeFiles(fileValues);
}
//目前来看,原生的代码里只有一种 BatterySaverLocationPlugin
// plugins.add(new BatterySaverLocationPlugin(mContext));
for (Plugin p : mPlugins) {
p.onBatterySaverChanged(this);
}
if (sendBroadcast) {
if (DEBUG) {
Slog.i(TAG, "Sending broadcasts for mode: " + enabled);
}
// Send the broadcasts and notify the listeners. We only do this when the battery saver
// mode changes, but not when only the screen state changes.
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
.putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, enabled)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
// Send internal version that requires signature permission.
intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
Manifest.permission.DEVICE_POWER);
//回调 所有注册了 LowPowerModeListener 的client
//主要有 VibratorService,NetworkPolicyManagerService,WindowManagerService
for (LowPowerModeListener listener : listeners) {
final PowerSaveState result =
mBatterySaverPolicy.getBatterySaverPolicy(
listener.getServiceType(), enabled);
listener.onLowPowerModeChanged(result);
}
}
}
1,首先调用final boolean isInteractive = getPowerManager().isInteractive();
public static boolean isInteractive(int wakefulness) {
return wakefulness == WAKEFULNESS_AWAKE || wakefulness == WAKEFULNESS_DREAMING;
}
其实就是在判断wakefulness
的值是否为WAKEFULNESS_AWAKE
或者WAKEFULNESS_DREAMING
,那么这个值代表什么呢?
WAKEFULNESS_ASLEEP:表示系统当前处于休眠状态,只能被wakeUp()调用唤醒。
WAKEFULNESS_AWAKE:表示系统目前处于正常运行状态。
WAKEFULNESS_DREAMING:表示系统当前正处于互动屏保的状态。
WAKEFULNESS_DOZING:表示系统正处于“doze”状态
2,listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
这里的mListeners其实是之前注册的时候,所有添加LowPowerModeListener的service。包含了VibratorService,NetworkPolicyManagerService等。这些内容都会进行一次保存,方便后面的消息分发。
3,下面看updateBatterySavingStats()
private void updateBatterySavingStats() {
final PowerManager pm = getPowerManager();
if (pm == null) {
Slog.wtf(TAG, "PowerManager not initialized");
return;
}
final boolean isInteractive = pm.isInteractive();
final int dozeMode =
pm.isDeviceIdleMode() ? DozeState.DEEP
: pm.isLightDeviceIdleMode() ? DozeState.LIGHT
: DozeState.NOT_DOZING;
synchronized (mLock) {
if (mIsPluggedIn) {
mBatterySavingStats.startCharging();
return;
}
mBatterySavingStats.transitionState(
mEnabled ? BatterySaverState.ON : BatterySaverState.OFF,
isInteractive ? InteractiveState.INTERACTIVE : InteractiveState.NON_INTERACTIVE,
dozeMode);
}
}
这个函数的核心在于transitionState
,但是只是用于保存当前的状态,所以我们不深究。
fileValues
默认为空,我们也不处理分析。 for (Plugin p : mPlugins) {
p.onBatterySaverChanged(this);
}
但是真正的实现,aosp只实现了一种:
onBatterySaverChanged
frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
这里的具体实现为:
@Override
public void onBatterySaverChanged(BatterySaverController caller) {
if (DEBUG) {
Slog.d(TAG, "onBatterySaverChanged");
}
updateLocationState(caller);
}
private void updateLocationState(BatterySaverController caller) {
final boolean kill =
(caller.getBatterySaverPolicy().getGpsMode()
== PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF) &&
caller.isEnabled() && !caller.isInteractive();
boolean gpsMode = (caller.getBatterySaverPolicy().getGpsMode() == PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
if (DEBUG) {
Slog.d(TAG, "Battery saver " + (kill ? "stopping" : "restoring") + " location.");
}
Settings.Global.putInt(mContext.getContentResolver(),
Global.LOCATION_GLOBAL_KILL_SWITCH, kill ? 1 : 0);
}
我们接下来对着三个广播进行一对一的分析。
ACTION_POWER_SAVE_MODE_CHANGING
FLAG_RECEIVER_REGISTERED_ONLY
,表示了只有动态注册的接收才可以。BatterySaverReceiver.java (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action))
BatteryControllerImpl.java (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING))
一个是位于Packages/apps/Settings
一个是frameworks/base/packages/SystemUI/
对于BatterySaverReceiver来说这里更新的主要是settings里面的状态。
对于sBatteryControllerImpl来说,这里的调用为
private void setPowerSave(boolean powerSave) {
if (powerSave == mPowerSave) return;
mPowerSave = powerSave;
// AOD power saving setting might be different from PowerManager power saving mode.
PowerSaveState state = mPowerManager.getPowerSaveState(PowerManager.ServiceType.AOD);
mAodPowerSave = state.batterySaverEnabled;
if (DEBUG) Log.d(TAG, "Power save is " + (mPowerSave ? "on" : "off"));
firePowerSaveChanged();
}
这里的会对PowerSave
的状态进行保存,并且调用firePowerSaveChanged
方法来进行实现。
private void firePowerSaveChanged() {
synchronized (mChangeCallbacks) {
final int N = mChangeCallbacks.size();
for (int i = 0; i < N; i++) {
mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave);
}
}
}
这里会去遍历mChangeCallbacks
,并且回调onPowerSaveChanged
的方法。
实现回调的方法主要为:
BatteryMeterView.java
StatusBar.java
KeyguardStatusBarView.java
LightBarController.java
BatterySaverTile.java
这边主要是SystemUI和界面显示上面的一些操作。
ACTION_POWER_SAVE_MODE_CHANGED
该广播和之前的一样,也是增加了一个Flag:
FLAG_RECEIVER_REGISTERED_ONLY
接收方的主要操作为:
BatteryBroadcastReceiver.java
(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())
BatteryControllerImpl.java
(action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED))
PowerUI.java
(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action))
DeviceStateMonitor.java
case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
SoundTriggerHelper.java
if (!PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
GnssLocationProvider.java
PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
而这个六个接收广播的地方都分别做了什么事情呢?
DeviceStateMonitor
的最终调用如下:
/**
* Send the device state to the modem.
*
* @param type Device state type. See DeviceStateType defined in types.hal.
* @param state True if enabled/on, otherwise disabled/off
*/
private void sendDeviceState(int type, boolean state) {
log("send type: " + deviceTypeToString(type) + ", state=" + state, true);
mPhone.mCi.sendDeviceState(type, state, null);
}
SoundTriggerHelper
的实现是去改了mIsPowerSaveMode
的值,作用如下:
// Whether we are allowed to run any recognition at all. The conditions that let us run
// a recognition include: no active phone call or not being in a power save mode. Also,
// the native service should be enabled.
private boolean isRecognitionAllowed() {
return !mCallActive && !mServiceDisabled && !mIsPowerSaveMode;
}
GnssLocationProvider
的调用,实现如下,从comments里面可以很容易的读懂。
private void updateLowPowerMode() {
// Disable GPS if we are in device idle mode.
boolean disableGps = mPowerManager.isDeviceIdleMode();
final PowerSaveState result =
mPowerManager.getPowerSaveState(ServiceType.GPS);
switch (result.gpsMode) {
case PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
// If we are in battery saver mode and the screen is off, disable GPS.
disableGps |= result.batterySaverEnabled && !mPowerManager.isInteractive();
break;
}
if (disableGps != mDisableGps) {
mDisableGps = disableGps;
updateRequirements();
}
}
最后是之前保存的一个数组回调函数:
for (LowPowerModeListener listener : listeners) {
final PowerSaveState result =
mBatterySaverPolicy.getBatterySaverPolicy(
listener.getServiceType(), enabled);
listener.onLowPowerModeChanged(result);
}
Listeners在我们前面的文章中也提到过,这边详细的总结一下:
类 | 作用 |
---|---|
VibratorService.java | 取消手机的震动效果 |
NetworkPolicyManagerService.java | 更新白名单以及应用对网络访问的限制 |
WindowManagerService.java | 取消窗口动画 |
NetworkPolicyManagerService
的调用如下
// NOTE: since both fw_dozable and fw_powersave uses the same map
// (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
private void updateRulesForWhitelistedPowerSaveUL(boolean enabled, int chain,
SparseIntArray rules) {
if (enabled) {
// Sync the whitelists before enabling the chain. We don't care about the rules if
// we are disabling the chain.
final SparseIntArray uidRules = rules;
uidRules.clear();
final List users = mUserManager.getUsers();
for (int ui = users.size() - 1; ui >= 0; ui--) {
UserInfo user = users.get(ui);
updateRulesForWhitelistedAppIds(uidRules, mPowerSaveTempWhitelistAppIds, user.id);
updateRulesForWhitelistedAppIds(uidRules, mPowerSaveWhitelistAppIds, user.id);
if (chain == FIREWALL_CHAIN_POWERSAVE) {
updateRulesForWhitelistedAppIds(uidRules,
mPowerSaveWhitelistExceptIdleAppIds, user.id);
}
}
for (int i = mUidState.size() - 1; i >= 0; i--) {
if (isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.valueAt(i))) {
uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
}
}
setUidFirewallRulesUL(chain, uidRules, CHAIN_TOGGLE_ENABLE);
} else {
setUidFirewallRulesUL(chain, null, CHAIN_TOGGLE_DISABLE);
}
}
private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, boolean paroled) {
if (!isUidValidForBlacklistRules(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
return RULE_NONE;
}
final boolean isIdle = !paroled && isUidIdle(uid);
final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
final boolean isWhitelisted = isWhitelistedBatterySaverUL(uid, mDeviceIdleMode);
final int oldRule = oldUidRules & MASK_ALL_NETWORKS;
int newRule = RULE_NONE;
// First step: define the new rule based on user restrictions and foreground state.
// NOTE: if statements below could be inlined, but it's easier to understand the logic
// by considering the foreground and non-foreground states.
if (isForeground) {
if (restrictMode) {
newRule = RULE_ALLOW_ALL;
}
} else if (restrictMode) {
newRule = isWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL;
}
final int newUidRules = (oldUidRules & MASK_METERED_NETWORKS) | newRule;
if (LOGV) {
Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
+ ", isIdle: " + isIdle
+ ", mRestrictPower: " + mRestrictPower
+ ", mDeviceIdleMode: " + mDeviceIdleMode
+ ", isForeground=" + isForeground
+ ", isWhitelisted=" + isWhitelisted
+ ", oldRule=" + uidRulesToString(oldRule)
+ ", newRule=" + uidRulesToString(newRule)
+ ", newUidRules=" + uidRulesToString(newUidRules)
+ ", oldUidRules=" + uidRulesToString(oldUidRules));
}
// Second step: notify listeners if state changed.
if (newRule != oldRule) {
if (newRule == RULE_NONE || hasRule(newRule, RULE_ALLOW_ALL)) {
if (LOGV) Log.v(TAG, "Allowing non-metered access for UID " + uid);
} else if (hasRule(newRule, RULE_REJECT_ALL)) {
if (LOGV) Log.v(TAG, "Rejecting non-metered access for UID " + uid);
} else {
// All scenarios should have been covered above
Log.wtf(TAG, "Unexpected change of non-metered UID state for " + uid
+ ": foreground=" + isForeground
+ ", whitelisted=" + isWhitelisted
+ ", newRule=" + uidRulesToString(newUidRules)
+ ", oldRule=" + uidRulesToString(oldUidRules));
}
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
}
return newUidRules;
}
isUidValidForBlacklistRules
当uid
是media
或者drm
类型的不需要,或者之前已经授权INTERNET网络访问的app,不许用更新
// TODO: the MEDIA / DRM restriction might not be needed anymore, in which case both
// methods below could be merged into a isUidValidForRules() method.
private boolean isUidValidForBlacklistRules(int uid) {
// allow rules on specific system services, and any apps
if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
|| (UserHandle.isApp(uid) && hasInternetPermissions(uid))) {
return true;
}
return false;
}
if (isForeground) {
if (restrictMode) {
newRule = RULE_ALLOW_ALL;
}
} else if (restrictMode) {
newRule = isWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL;
}
针对WindowManagerService
来说,作用是取消窗口动画的效果。
@Override
public void onLowPowerModeChanged(PowerSaveState result) {
synchronized (mWindowMap) {
final boolean enabled = result.batterySaverEnabled;
if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {
mAnimationsDisabled = enabled;
dispatchNewAnimatorScaleLocked(null);
}
}
}
限制振动 VibratorService.java
VibratorService.java中回调:
public void systemReady() {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
try {
..........................
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
public int getServiceType() {
return ServiceType.VIBRATION;
}
@Override
public void onLowPowerModeChanged(PowerSaveState result) {
updateVibrators();//更改低电量状态
}
});
..........................
}
private void updateVibrators() {
synchronized (mLock) {
boolean devicesUpdated = updateInputDeviceVibratorsLocked();
boolean lowPowerModeUpdated = updateLowPowerModeLocked();//更改低电量状态
updateVibrationIntensityLocked();
if (devicesUpdated || lowPowerModeUpdated) {
// If the state changes out from under us then just reset.
doCancelVibrateLocked();
}
}
}
private boolean updateLowPowerModeLocked() {
boolean lowPowerMode = mPowerManagerInternal
.getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;//看看这个值怎么拿到的
if (lowPowerMode != mLowPowerMode) {
mLowPowerMode = lowPowerMode;//mLowPowerMode这个变量判断要不要震动会用到
return true;
}
return false;
}
frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java :
@Override
public PowerSaveState getLowPowerState(@ServiceType int serviceType) {
return mBatterySaverPolicy.getBatterySaverPolicy(serviceType,
mBatterySaverController.isEnabled());//这个方法根据传入的serviceType 决定要不要对省电模式做出反应,很关键的方法
}
frameworks\base\services\core\java\com\android\server\power\BatterySaverPolicy.java :
/**
* Get the {@link PowerSaveState} based on {@paramref type} and {@paramref realMode}.
* The result will have {@link PowerSaveState#batterySaverEnabled} and some other
* parameters when necessary.
*
* @param type type of the service, one of {@link ServiceType}
* @param realMode whether the battery saver is on by default
* @return State data that contains battery saver data
*/
public PowerSaveState getBatterySaverPolicy(@ServiceType int type, boolean realMode) {
synchronized (mLock) {
final PowerSaveState.Builder builder = new PowerSaveState.Builder()
.setGlobalBatterySaverEnabled(realMode);
if (!realMode) {
return builder.setBatterySaverEnabled(realMode)
.build();
}
switch (type) {
case ServiceType.GPS:
return builder.setBatterySaverEnabled(realMode)
.setGpsMode(mGpsMode)
.build();
case ServiceType.ANIMATION:
return builder.setBatterySaverEnabled(mAnimationDisabled)
.build();//mVibrationDisabledEffective决定省电模式下要不要取消动画
case ServiceType.FULL_BACKUP:
return builder.setBatterySaverEnabled(mFullBackupDeferred)
.build();
case ServiceType.KEYVALUE_BACKUP:
return builder.setBatterySaverEnabled(mKeyValueBackupDeferred)
.build();
case ServiceType.NETWORK_FIREWALL:
return builder.setBatterySaverEnabled(!mFireWallDisabled)
.build();
case ServiceType.SCREEN_BRIGHTNESS:
return builder.setBatterySaverEnabled(!mAdjustBrightnessDisabled)
.setBrightnessFactor(mAdjustBrightnessFactor)
.build();
case ServiceType.DATA_SAVER:
return builder.setBatterySaverEnabled(!mDataSaverDisabled)
.build();
case ServiceType.SOUND:
return builder.setBatterySaverEnabled(mSoundTriggerDisabled)
.build();
case ServiceType.VIBRATION:
return builder.setBatterySaverEnabled(mVibrationDisabledEffective)
.build();//mVibrationDisabledEffective决定省电模式下要不要禁止振动
case ServiceType.FORCE_ALL_APPS_STANDBY:
return builder.setBatterySaverEnabled(mForceAllAppsStandby)
.build();
case ServiceType.FORCE_BACKGROUND_CHECK:
return builder.setBatterySaverEnabled(mForceBackgroundCheck)
.build();
case ServiceType.OPTIONAL_SENSORS:
return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
.build();
case ServiceType.AOD:
return builder.setBatterySaverEnabled(mAodDisabled)
.build();
default:
return builder.setBatterySaverEnabled(realMode)
.build();
}
}
}
BatterySaverPolicy.java 这个类很关键,所有关于省电模式的默认配置都在这个类里面初始化,如果要定制省电模式行为的话,这个类会被用到。
回调的流程的最终目的就是根据配置修改了 mLowPowerMode 变量的值,这个值会在调用振动时使用,用以决定要不要振动。
@GuardedBy("mLock")
private void startVibrationLocked(final Vibration vib) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
try {
//关于省电模式下是否允许振动在这个方法里判断
if (!isAllowedToVibrateLocked(vib)) {
return;
}
//
final int intensity = getCurrentIntensityLocked(vib);
if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
return;
}
//如果是来电且响铃时振动开关未打开,则不振动
if (vib.isRingtone() && !shouldVibrateForRingtone()) {
if (DEBUG) {
Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
}
return;
}
........................
}
private boolean isAllowedToVibrateLocked(Vibration vib) {
//如果不在省电模式则允许振动,如果在省电模式,排除掉以下几种情况外都不允许震动
if (!mLowPowerMode) {
return true;
}
//省电模式对铃声振动不影响
if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
return true;
}
//省电模式对 闹钟,辅助功能和 VoIP通话,视频通话 的振动不影响
if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
return true;
}
return false;
}
2. 降低屏幕亮度
frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java :
/**
* Updates the display power state asynchronously.
* When the update is finished, mDisplayReady will be set to true. The display
* controller posts a message to tell us when the actual display power state
* has been updated so we come back here to double-check and finish up.
*
* This function recalculates the display power state each time.
*
* @return True if the display became ready.
*/
private boolean updateDisplayPowerStateLocked(int dirty) {
.......................
updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);
..........................
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
..........................
}
@VisibleForTesting
void updatePowerRequestFromBatterySaverPolicy(DisplayPowerRequest displayPowerRequest) {
PowerSaveState state = mBatterySaverPolicy.
getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS,
mBatterySaverController.isEnabled());
displayPowerRequest.lowPowerMode = state.batterySaverEnabled;
displayPowerRequest.screenLowPowerBrightnessFactor = state.brightnessFactor;
}
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java :
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mSyncRoot) {
return mDisplayPowerController.requestPowerState(request,
waitForNegativeProximity);
}
}
frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
................................
if (changed && !mPendingRequestChangedLocked) {
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked();
}
.................................
}
}
sendUpdatePowerStateLocked 内部交由 Handler 消息处理,最终会调用 updatePowerState 方法:
private void updatePowerState() {
............................
// If low power mode is enabled, scale brightness by screenLowPowerBrightnessFactor
// as long as it is above the minimum threshold.
if (mPowerRequest.lowPowerMode) {
if (brightness > mScreenBrightnessRangeMinimum) {
final float brightnessFactor =
Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1);// 亮度缩放比例
final int lowPowerBrightness = (int) (brightness * brightnessFactor);
brightness = Math.max(lowPowerBrightness, mScreenBrightnessRangeMinimum);
}
}
............................
}
BatterySaverPolicy.java 中定义的 默认亮度缩放比例是 0.5,亮度降低一半
mAdjustBrightnessDisabled = parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, true); //原生的配置是省电模式情况下默认不调节亮度
mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
3. WindowManagerService 动画
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java :
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
public int getServiceType() {
return ServiceType.ANIMATION;
}
@Override
public void onLowPowerModeChanged(PowerSaveState result) {
synchronized (mWindowMap) {
//BatterySaverPolicy中配置的是否要在低电量中关闭动画,android P上是 false,默认不关闭动画,8.0上是true的
final boolean enabled = result.batterySaverEnabled;
//mAllowAnimationsInLowPowerMode代表是否在允许在低电模式下继续使用动画(默认是false,就是不允许),如果在低电模式下会把WMS的动画都关闭
if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {
mAnimationsDisabled = enabled;
dispatchNewAnimatorScaleLocked(null);
}
}
}
});
9.0上低电量模式下是不关闭动画的,8.0上是关闭的。
4. NetworkPolicyManagerService.java 网络防火墙
frameworks\base\services\core\java\com\android\server\net\NetworkPolicyManagerService.java
private void updateRulesForRestrictPowerUL() {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL");
try {
updateRulesForDeviceIdleUL();
updateRulesForPowerSaveUL();
updateRulesForAllAppsUL(TYPE_RESTRICT_POWER);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
低电量模式下主要就是去更新网络访问的规则,没仔细研究,不敢妄言,Android P上也是默认没有打开限制的,开启低电量模式不去限制网络。
5. GPS 位置信息相关限制
private void updateLocationState(BatterySaverController caller) {
final boolean kill =
(caller.getBatterySaverPolicy().getGpsMode()
== PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF) &&
caller.isEnabled() && !caller.isInteractive();
if (DEBUG) {
Slog.d(TAG, "Battery saver " + (kill ? "stopping" : "restoring") + " location.");
}
Settings.Global.putInt(mContext.getContentResolver(),
Global.LOCATION_GLOBAL_KILL_SWITCH, kill ? 1 : 0);
}
/**
* If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link Secure#LOCATION_MODE_OFF}
* temporarily for all users.
*
* @hide
*/
@TestApi
public static final String LOCATION_GLOBAL_KILL_SWITCH =
"location_global_kill_switch";
低电量情况下,灭屏后会关闭GPS,临时限制所有应用访问位置信息。
以上都是 开启低电量模式后,BatterySaverController.java 中主动去回调的,以下是 各模块自己监听 ACTION_POWER_SAVE_MODE_CHANGED 广播后自己处理的
6. 语音互动的功能
frameworks\base\services\voiceinteraction\java\com\android\server\soundtrigger\SoundTriggerHelper.java :
// A single routine that implements the start recognition logic for both generic and keyphrase
// models.
private int startRecognitionLocked(ModelData modelData, boolean notify) {
...........................
if (!isRecognitionAllowed()) {
// Nothing to do here.
Slog.w(TAG, "startRecognition requested but not allowed.");
MetricsLogger.count(mContext, "sth_start_recognition_not_allowed", 1);
return STATUS_OK;
}
}
// Whether we are allowed to run any recognition at all. The conditions that let us run
// a recognition include: no active phone call or not being in a power save mode. Also,
// the native service should be enabled.
private boolean isRecognitionAllowed() {
return !mCallActive && !mServiceDisabled && !mIsPowerSaveMode;
}
低电量模式下不识别语音
其他各上层模块,如settings,systemUI 也监听了 ACTION_POWER_SAVE_MODE_CHANGED 广播,主要是做一些 UI上的变化