- 由 b178903294创建, 最后修改于9月 01, 2020
当用户在settings打开省电模式的开关后,系统会进入到省电模式,在各种方面进行限制以尽可能的省电。今天我们来分析一下,省电模式限制网络连接的逻辑。
前言:首先分析一下打开省电模式按钮之后发生了什么:
1、先来看一下Battery saver的switch开关,当我们打开Battery saver的时候
//packages/apps/Settings/src/com/android/settings/fuelgauge/BatterySaverSettings.java
private void trySetPowerSaveMode( boolean mode) {
if (!mPowerManager.setPowerSaveMode(mode)) {
… } |
2.当应用调用了PMS的setPowerSaveMode进行省电模式,会进入PowerManagerService.java,里面主要包括权限检查和进一步设置
//PowerManagerService.java
public boolean setPowerSaveMode( boolean mode) {
//这个操作需要调用者用有DEVICE_POWER权限 mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null ); //...... //进行省电模式内部设置 return setLowPowerModeInternal(mode); } |
3.省电模式内部设置setLowPowerModeInternal,里面包含省电模式标志位LOW_POWER_MODE的设置,省电模式mLowPowerModeSetting的设置
private boolean setLowPowerModeInternal( boolean mode) {
…… //此时会设置省电模式标志位LOW_POWER_MODE设置 Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE, mode ? 1 : 0 ); mLowPowerModeSetting = mode; //省电模式设置 …… updateLowPowerModeLocked(); //省电模式 return true ; } |
4.
更新省电模式相关设置updateLowPowerModeLocked,该函数包括了大部分省电模式的逻辑处理。
1) 如果在充电中或者”非低电而且没有开完机”情况下是不允许进入省电模式
2) 自动打开省电模式的条件是:不在充电状态 && 设置了自动进入省电模式 && 用户没有主动在低电下关闭低电模式 && 低电状态
3) 只要手动设置省电模式mLowPowerModeSetting,或者自动进入省电模式,那么省电模式lowPowerModeEnabled将会给打开
4) 进行Power HAL的设置,android默认的default Power HAL是power.default.so,里面的内容默认都是置空,也就是没有任何操作。
5) 进行省电模式模式切换前会发生一个ACTION_POWER_SAVE_MODE_CHANGING的广播,然后回调所有监听了省电模式的监听器,最后切换成功后会发生ACTION_POWER_SAVE_MODE_CHANGED的广播。
6) 会将mLowPowerModeListeners低电模式的监听onLowPowerModeChanged全部回调一遍
展开源码
正文
看看powersave怎么控制网络的
一、网络限制的开启与规则更新
1.首先回调下面的LowPowerModeObserver 将mRestrictPower赋值为true此时则打开了乐网络限制模式,调用updateRulesForRestrictPowerUL()进行规则更新
frameworks/base/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
mPowerManagerInternal.registerLowPowerModeObserver( new PowerManagerInternal.LowPowerModeListener() {
@Override public int getServiceType() {
return ServiceType.NETWORK_FIREWALL; } @Override public void onLowPowerModeChanged(PowerSaveState result) {
final boolean enabled = result.batterySaverEnabled; if (LOGD) {
Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")" ); } synchronized (mUidRulesFirstLock) {
if (mRestrictPower != enabled) {
mRestrictPower = enabled; updateRulesForRestrictPowerUL(); } } } }); |
updateRulesForRestrictPowerUL() 有分别调用了三个函数进行不同规则的更新:
// TODO: rename / document to make it clear these are global (not app-specific) rules private void updateRulesForRestrictPowerUL() {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL" ); try {
updateRulesForDeviceIdleUL(); //调用updateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE, mUidFirewallDozableRules); 开关网络限制 并更新 updateRulesForDeviceIdleUL规则 updateRulesForPowerSaveUL(); //调用updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,mUidFirewallPowerSaveRules); 开关网络限制 更新updateRulesForPowerSaveUL规则 updateRulesForAllAppsUL(TYPE_RESTRICT_POWER); // 设置mUidRules 并通过INetworkManagementService 设置setUidMeteredNetworkWhitelist 允许网络状态查询. } finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } } |
下面我们来分析updateRulesForWhitelistedPowerSaveUL 开关 powersave流程
// 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 (chain != FIREWALL_CHAIN_POWERSAVE && enabled) {
// EASICLASS-13069 seewo bijunqiang allows internet use in LowPowerMode // 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<UserInfo> 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); //关闭 } |
通过调用setUidFirewallRulesUL进行开关
private void setUidFirewallRulesUL( int chain, @Nullable SparseIntArray uidRules, @ChainToggleType int toggle) {
if (uidRules != null ) {
setUidFirewallRulesUL(chain, uidRules); } if (toggle != CHAIN_TOGGLE_NONE) {
enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE); } } |
继续调用enableFirewallChainUL
/** ¦* Add or remove a uid to the firewall blacklist for all network ifaces. ¦*/ private void enableFirewallChainUL( int chain, boolean enable) {
if (mFirewallChainStates.indexOfKey(chain) >= 0 && mFirewallChainStates.get(chain) == enable) {
// All is the same, nothing to do. return ; } mFirewallChainStates.put(chain, enable); try {
mNetworkManager.setFirewallChainEnabled(chain, enable); mLogger.firewallChainEnabled(chain, enable); } catch (IllegalStateException e) {
Log.wtf(TAG, "problem enable firewall chain" , e); } catch (RemoteException e) {
// ignored; service lives in system_server } } |
继续调用 mNetworkManager.setFirewallChainEnabled(chain, enable);
NetworkManagementService.java
@Override public void setFirewallChainEnabled( int chain, boolean enable) {
enforceSystemUid();
|