应用后台网络管控机制

概述

在维护手管应用时,经常遇到与应用后台网络控制相关的问题,在解决这些问题的过程中,学习了下应用后台网络控制的流程以及一些日志的分析方法,现在把它总结一下,方便自己以及他人的学习。

网络管控流程

对于后台网络管控主要的参与者如下:

com.meizu.safe:NetworkManager
frameworks/base/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
frameworks/base/services/core/java/com/android/server/NetworkManagementService.java

注:这里其实还有个底层的网络守护进程的参与,但是我们这里不做太多描述,只描述框架层以上的逻辑。

在介绍总的流程时,先简单的介绍下NetworkManager,顾名思义其是手管中用以控制网络管理的组件,而在应用后台管理时,主要有三种模式,如下。

从上图可以看出,三种模式中,智能模式其实是在应用规则前做了一层逻辑判断,但最终也是调用禁止或允许的接口,就不在赘述。

下面大致介绍下后台网络管控的流程。


public void updateBackgroundAppInfo(String pkgName, final int controlType, final int uid) {int uid_key = -1;//获取转换后的过滤uid值if (-1 != uid) {uid_key = uid;} else {//to do parse fensheng app uidLog.d("myTemp66", "app install updateBackgroundAppInfo uid = -1");uid_key = transPkgToUid(mContext, pkgName);}//更新数据库boolean updateResult = trafficDataBase.updateAppControllType(uid, pkgName, controlType);Log.d("myTemp66", "updateBackgroundAppInfo --> updateResult:" + updateResult+ " pkgName:" + pkgName + " controlType:" + controlType + " uid:" + uid_key);if (TrafficConst.STATUS_VALUE_INTELLIGENCE == controlType && updateResult) {//当为智能类型时,才用获取智能模式下的后台联网设置状态AppAlphameInfo alphameInfo = trafficAlphameManager.doQueryAlpmeApp(pkgName, TrafficConst.STATUS_BACKGROUND);Log.d("myTemp66", "intelligence status: " + alphameInfo.toString());appBackGourndNetControl(uid_key, alphameInfo.isWifiState(), alphameInfo.isMobileState());} else if (TrafficConst.STATUS_VALUE_REJECT == controlType && updateResult) {appBackGourndNetControl(uid_key, false, false);Mtj.onEvent(mContext, Mtj.CLICK_TRAFFIC_BGD_APP_BAN, "后台联网应用禁止点击次数");} else if (TrafficConst.STATUS_VALUE_ALLOW == controlType && updateResult) {appBackGourndNetControl(uid_key, true, true);Mtj.onEvent(mContext, Mtj.CLICK_TRAFFIC_BGD_APP_ALLOW, "后台联网应用允许点击次数");}
}

首先,在用户修改模式后,NetworkManager组件会调用updateBackgroundAppInfo()方法,而在这个方法中会调用updateAppControllType()方法去更新数据库,然后再调用appBackGourndNetControl()去设置后台网络控制。

/*** 设置底层后台流量数据控制接口(通讯组接口)* @param uid 应用的UID* @param isWifiControl WIFI控制:true为打开,false为关闭* @param isMobileControl Mobile控制(与wifi类似)*/
public void appBackGourndNetControl(int uid, boolean isWifiControl, boolean isMobileControl) {Log.i(TAG, "appBackGourndNetControl: uid:" + uid + " wifi:" + isWifiControl + " mobile:" + isMobileControl);if (isWifiControl) {//打开wifiif (!networkControllManager.isAppWifiBackgroundUsageOpened(uid)) {Log.d(TAG, "appBackGourndNetControl: change wifibackground open:" + uid);networkControllManager.openAppWifiBackgroundUsage(uid);}} else {//关闭wifiif (networkControllManager.isAppWifiBackgroundUsageOpened(uid)) {Log.d(TAG, "appBackGourndNetControl: change wifibackground close:" + uid);networkControllManager.closeAppWifiBackgroundUsage(uid);}}if (isMobileControl) {//打开后台移动网络if (!networkControllManager.isAppMobileBackgroundUsageOpened(uid)) {Log.d(TAG, "appBackGourndNetControl: change mobilebackground open:" + uid);networkControllManager.openAppMobileBackgroundUsage(uid);}} else {//关闭后台移动网络if (networkControllManager.isAppMobileBackgroundUsageOpened(uid)) {Log.d(TAG, "appBackGourndNetControl: change mobilebackground close:" + uid);networkControllManager.closeAppMobileBackgroundUsage(uid);}}
}public void closeAppWifiBackgroundUsage(String pkName) {int uid = PackageManagerUtil.getUid(pkName);Log.i(TAG, "close uid=" + uid + " background wifi net");addUidPolicy(new Object[]{uid, getPolicyRejectAppBackgroundNetWifi()});
}/*** 关闭网络.* @param args*/
private void addUidPolicy(Object... args) {Method addUidPolicyMethod = getAddUidPolicyMethod();try {addUidPolicyMethod.invoke(mNetWorkPolicyManager, args);} catch (IllegalAccessException e) {Log.e(TrafficConst.TRAFFIC_EXCEPTION, TAG + ":addUidPolicy --> " + e.toString());} catch (IllegalArgumentException e) {Log.e(TrafficConst.TRAFFIC_EXCEPTION, TAG + ":addUidPolicy --> " + e.toString());} catch (Exception e) {Log.e(TrafficConst.TRAFFIC_EXCEPTION, TAG + ":addUidPolicy --> " + e.toString());}
}

在appBackGourndNetControl()方法中会通过NetworkControllManager类去调用关闭后台联网的接口,最终通过反射调用到框架层NetworkPolicyManagerService(NPMS)类中的addUidPolicy()方法。

@Override
public void addUidPolicy(int uid, int policy) {mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);if (!UserHandle.isApp(uid)) {throw new IllegalArgumentException("cannot apply policy to UID " + uid);}synchronized (mRulesLock) {final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);policy |= oldPolicy;if (oldPolicy != policy) {setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);}}
}private void setUidPolicyUncheckedLocked(int uid, int policy, boolean persist) {mLastUidPolicy = getUidPolicy(uid);mUidPolicy.put(uid, policy);Slog.d(TAG, "mLastUidPolicy " + mLastUidPolicy + " " + policy);updateRulesForUidWifiAndMobileLocked(uid);// uid policy changed, recompute rules and persist policy.updateRulesForDataUsageRestrictionsLocked(uid);if (persist) {writePolicyLocked();}
}

在addUidPolicy()方法中,最主要的是调用了setUidPolicyUncheckedLocked()方法,在这方法中,flyme系统添加了updateRulesForUidWifiAndMobileLocked()方法,去设置对应UID进程的网络的规则变化。而对于应用前后台状态改变网络管理,最主要的是updateRulesForDataUsageRestrictionsLocked()方法的管控,下面我们来看下该方法:


private void updateRulesForDataUsageRestrictionsLocked(int uid, boolean uidDeleted) {...//获取进程的策略final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);//获取进程旧规则final int oldUidRules = mUidRules.get(uid, RULE_NONE);//判断应用进程的前后台状态final boolean isForeground = isUidForegroundOnRestrictBackgroundLocked(uid);//表示是否在黑名单final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;//表示是否在白名单final boolean isWhitelisted = mRestrictBackgroundWhitelistUids.get(uid);//旧规则final int oldRule = oldUidRules & MASK_METERED_NETWORKS;//新规则int newRule = RULE_NONE;// First step: define the new rule based on user restrictions and foreground state.//第一步,根据用户设置与前后台状态定义新网络规则if (isForeground) {if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) {//暂时允许规则newRule = RULE_TEMPORARY_ALLOW_METERED;} else if (isWhitelisted) {//允许规则newRule = RULE_ALLOW_METERED;}} else {if (isBlacklisted) {//拒绝规则newRule = RULE_REJECT_METERED;} else if (mRestrictBackground && isWhitelisted) {newRule = RULE_ALLOW_METERED;}}//获取新的进程规则int newUidRules = newRule | (oldUidRules & MASK_ALL_NETWORKS);if (LOGV) {Slog.i(TAG, "updateRuleForRestrictBackgroundLocked(" + uid + ")"+ ": isForeground=" +isForeground+ ", isBlacklisted=" + isBlacklisted+ ", isWhitelisted=" + isWhitelisted+ ", oldRule=" + uidRulesToString(oldRule)+ ", newRule=" + uidRulesToString(newRule)+ ", newUidRules=" + uidRulesToString(newUidRules)+ ", oldUidRules=" + uidRulesToString(oldUidRules));}if (!isForeground && (uidPolicy & POLICY_REJECT_APP_BACKGROUND_NET_MOBILE) != 0) {newUidRules |= RULE_REJECT_BACKGROUND_MOBILE;}if (!isForeground && (uidPolicy & POLICY_REJECT_APP_BACKGROUND_NET_WIFI) != 0) {newUidRules |= RULE_REJECT_BACKGROUND_WIFI;}boolean rule3gBackgroundChanged = false;boolean ruleWifiBackgroundChanged = false;//第二步,根据状态的改变应用后台网控规则// Second step: apply bw changes based on change of state.//获取网络规则变化rule3gBackgroundChanged = ((oldUidRules & RULE_REJECT_BACKGROUND_MOBILE)^ (newUidRules & RULE_REJECT_BACKGROUND_MOBILE)) != 0;ruleWifiBackgroundChanged = ((oldUidRules & RULE_REJECT_BACKGROUND_WIFI)^ (newUidRules & RULE_REJECT_BACKGROUND_WIFI)) != 0;Slog.i(TAG, "rule3gBackgroundChanged " + uid + " " + rule3gBackgroundChanged);Slog.i(TAG, "ruleWifiBackgroundChanged " + uid + " " + ruleWifiBackgroundChanged);if (rule3gBackgroundChanged) {//获取移动数网络状态final boolean allow = (newUidRules & RULE_REJECT_BACKGROUND_MOBILE) == 0;Slog.i(TAG, "rule3gBackgroundChanged " + allow);try {//将规则设置到网络守护进程mNetworkManagerFlyme.setFirewallUidChainRule(uid, TYPE_MOBILE, allow);} catch (IllegalStateException e) {e.printStackTrace();} catch (RemoteException e) {e.printStackTrace();}}if (ruleWifiBackgroundChanged) {//获取无线网络状态final boolean allow = (newUidRules & RULE_REJECT_BACKGROUND_WIFI) == 0;Slog.i(TAG, "ruleWifiBackgroundChanged " + allow);try {//将规则设置到网络守护进程mNetworkManagerFlyme.setFirewallUidChainRule(uid, TYPE_WIFI, allow);} catch (IllegalStateException e) {e.printStackTrace();} catch (RemoteException e) {e.printStackTrace();}}// @}if (newUidRules == RULE_NONE) {mUidRules.delete(uid);} else {mUidRules.put(uid, newUidRules);}...//分发回调接口// Dispatch changed rule to existing listeners.mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();}

根据以上的代码,可以看到,后台网络控制主要分为两步:

  1. 第一步,根据用户设置与前后台状态定义新网络规则;
  2. 第二步,根据状态的改变应用后台网控规则;
  3. 第三步,回调状态改变消息。

在第一步里,有个判断进程前后台状态的方法isUidForegroundOnRestrictBackgroundLocked(),其最终调用的是isProcStateAllowedWhileOnRestrictBackgroundLocked()方法会根据进程的运状态去判断进程前后台的状态,当应用的状态小于等于所设定的值,系统即不认为应用处于后台状态,反之则是。


private boolean isUidForegroundOnRestrictBackgroundLocked(int uid) {final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);return isProcStateAllowedWhileOnRestrictBackgroundLocked(procState);
}static boolean isProcStateAllowedWhileOnRestrictBackgroundLocked(int procState) {// return procState <= ActivityManager.PROCESS_STATE_TOP;return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;}

注:这里可能会是大多数应用现在无法被限制后台联网的原因,这是由于之前Google的GMS还未接入我们系统时,我们的设定的临界指是ActivityManager.PROCESS_STATE_TOP = 2,而接入Google的GMS后,由于要过CTS,用例要求我们需要将临界值修改为ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE = 4;

这里需要提下:应用进入后台时,AMS通过Binder通知NPMS, 然后NPMS检测应用是否在后台(查看 AMS 传递过来的processState),在禁止后台联网情况下,应用若在后台,则禁止访问网络;否则就允许。这块的代码逻辑如下


final private IUidObserver mUidObserver = new IUidObserver.Stub() {@Override public void onUidStateChanged(int uid, int procState) throws RemoteException {Slog.i(TAG, "onUidStateChanged uid=" + uid + " " + procState);synchronized (mRulesLock) {updateUidStateLocked(uid, procState);}updateNetworkStats(uid, isUidStateForegroundLocked(procState));}@Override public void onUidGone(int uid) throws RemoteException {synchronized (mRulesLock) {removeUidStateLocked(uid);}updateNetworkStats(uid, false);}@Override public void onUidActive(int uid) throws RemoteException {}@Override public void onUidIdle(int uid) throws RemoteException {}
};private void updateUidStateLocked(int uid, int uidState) {final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);if (oldUidState != uidState) {// state changed, push updated rulesmUidState.put(uid, uidState);updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState, uidState);if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)!= isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {if (isUidIdle(uid)) {updateRuleForAppIdleLocked(uid);}if (mDeviceIdleMode) {updateRuleForDeviceIdleLocked(uid);}if (mRestrictPower) {updateRuleForRestrictPowerLocked(uid);}updateRulesForPowerRestrictionsLocked(uid);}}
}

第二步中,获取到的新规则会通过Binder通信,调用网络管理服务NetworkManagementService(以下简称NMS)中的setFirewallUidChainRule方法,如下:


public void setFirewallUidChainRule(int uid, int networkType, boolean allow) {//enforceSystemUid();final String MOBILE = "mobile";final String WIFI = "wifi";final String rule = allow ? "allow" : "deny";final String chain = (networkType == 1) ? WIFI : MOBILE;try {//向网络守护进程发送执行事件mFlymeDaemonConnector.execute("firewall", "set_uid_fw_rule", uid, chain, rule);} catch (NativeDaemonConnectorException e) {throw e.rethrowAsParcelableException();}
}

紧接着NMS会通过守护进程的连接者NativeDaemonConnector(NDC)使用Socket通信向守护进程发送对应的事件,从而让底层去根据事件来做出对应的反馈。

注:这里的通信流程由于代码比较多,就不附上了,有兴趣的可以搜索源码中NativeDaemonConnector这个类去查看。

第三步,设置完规则后,NPMS会回调进程网络规则改变的接口,通知整个Android该应用的规则改变,从而完成后台网络控制。

简单的绘制了下该过程的流程,如下。

日志分析

在分析这类网络问题的时候,学习了下日志分析方法,把它总结出来,以便学习查阅。

准备前提

  1. 使用logreport抓取Log(包括NetWork Log);
  2. 使用以下指令抓取应用的前后台状态oom_adj;
while [ 1 ];do date +%Y-%m-%d-%H:%M:%S-%N;adb shell dumpsys activity oom| sed -En -e '/Proc .* trm:.*com.*\.youku/,/state: /p';printf "\n";sleep 1;done >oom_adj.txt

注:这里的.youku需要换成指定应用的包名信息

  1. 使用以下指令抓取网络访问流量情况。
adb shell "while [ 1 ];do cat /proc/net/xt_qtaguid/stats |grep \"wlan0.*10081\";sleep 1;done"

注:10081指的是应用进程的uid,根据不同的应用进行修改

分析

Log

对于Log,最主要的是mainlog、netpolicy以及辅助的eventlog(用以查看应用前后台状态)。

分析mainlog时,首先从上层手管应用开始。


01-22 16:55:52.671 9321 9536 D myTemp66: 更新应用后台网络控制类型 记录已存在,更新 pkName=com.tencent.qqmusic, uid=10092
01-22 16:55:52.676 9321 9536 D myTemp66: updateBackgroundAppInfo --> updateResult:true pkgName:com.tencent.qqmusic controlType:0 uid:1009201-22 16:55:52.676 9321 9536 I TrafficControlImpl: appBackGourndNetControl: uid:10092 wifi:false mobile:false
01-22 16:55:52.676 9321 9536 D TrafficControlImpl: appBackGourndNetControl: change wifibackground close:10092
01-22 16:55:52.676 9321 9536 I trafficNetworkControll: close uid=10092 background wifi net
01-22 16:55:52.715 9321 9536 D TrafficControlImpl: appBackGourndNetControl: change mobilebackground close:10092
01-22 16:55:52.715 9321 9536 D trafficNetworkControll: close uid=10092 background modern net

其中myTemp66指的是在修改模式后,手管去更新数据的打印日志,会根据更新的情况反馈不同的信息日志;TrafficControlImpl则是设置底层后台流量数据控制接口的日志;trafficNetworkControll则是成功调用底层接口的标志,从这些log上我们可以了解上层应用逻辑是否存在问题。

其次是分析框架层日志。

//NPMS检测到优酷进入后台,
01-22 16:55:53.926702 3172 3172 D WifiService: onReceive, action:android.intent.action.SCREEN_OFF
01-22 16:55:53.932184 3172 3188 D NetworkPolicy: rule3gBackgroundChanged 10081 true
01-22 16:55:53.932238 3172 3188 D NetworkPolicy: ruleWifiBackgroundChanged 10081 true
01-22 16:55:53.973140 3172 3188 D NetworkPolicy: ruleWifiBackgroundChanged false // 禁止10081访问网络,并设定iptable
01-10 16:24:53.985761 321 3172 I iptables: /system/bin/iptables -I wifi -m owner --uid-owner 10081 -j REJECT --reject-with icmp-net-prohibited// 但是很快又检测到 优酷到了前台,
01-22 16:55:54.067005 3172 3172 D WifiStateMachine: onReceive, action:android.intent.action.SCREEN_ON
01-22 16:55:54.082619 3172 3188 D NetworkPolicy: rule3gBackgroundChanged 10081 true
01-22 16:55:54.082675 3172 3188 D NetworkPolicy: ruleWifiBackgroundChanged 10081 true
01-22 16:55:54.117942 3172 3188 D NetworkPolicy: ruleWifiBackgroundChanged true // 设定 优酷 允许访问网络
01-22 16:55:54.133298 321 3172 I iptables: /system/bin/iptables -D wifi -m owner --uid-owner 10081 -j REJECT --reject-with icmp-net-prohibited01-22 16:56:01.537 3172 3188 I NetworkPolicy: onUidStateChanged uid=10081 2//前台进程UID状态
01-22 16:56:19.745 3172 3188 I NetworkPolicy: onUidStateChanged uid=10081 3//后台进程UID状态

NetworkPolicy: ruleWifiBackgroundChanged/rule3gBackgroundChanged false通过这条日志,可以判断进程在后台时的wifi或移动数据的状态,true表示可以联网,false表示禁止联网。iptables: /system/bin/iptables -I wifi -m owner --uid-owner 10081 -j REJECT --reject-with icmp-net-prohibited将联网信息设定到iptable中。通过以上日志就可以分析出,出问题应用进程在后台联网的状态。

然后再根据dump中的netpolicy日志中的UID=10081 policy=[]REJECT_APP_BACKGROUND_NET_MOBILE
REJECT_APP_BACKGROUND_NET_WIFI
进一步确认后台联网规则。

从以上日志里,基本上可以提炼出一个应用进程从上层到框架层的后台联网信息。

注:上面的日志最后两条,onUidStateChanged,表示的就是AMS向NPMS发送进程状态改变的消息,最后一列的值表示进程在的状态值具体参考以下数据。


/** @hide Process is a persistent system process. */
public static final int PROCESS_STATE_PERSISTENT = 0;/** @hide Process is a persistent system process and is doing UI. */
public static final int PROCESS_STATE_PERSISTENT_UI = 1;/** @hide Process is hosting the current top activities.  Note that this covers* all activities that are visible to the user. */
public static final int PROCESS_STATE_TOP = 2;/** @hide Process is hosting a foreground service due to a system binding. */
public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 3;/** @hide Process is hosting a foreground service. */
public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;/** @hide Same as {@link #PROCESS_STATE_TOP} but while device is sleeping. */
public static final int PROCESS_STATE_TOP_SLEEPING = 5;/** @hide Process is important to the user, and something they are aware of. */
public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 6;/** @hide Process is important to the user, but not something they are aware of. */
public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 7;/** @hide Process is in the background running a backup/restore operation. */
public static final int PROCESS_STATE_BACKUP = 8;/** @hide Process is in the background, but it can't restore its state so we want* to try to avoid killing it. */
public static final int PROCESS_STATE_HEAVY_WEIGHT = 9;/** @hide Process is in the background running a service.  Unlike oom_adj, this level* is used for both the normal running in background state and the executing* operations state. */
public static final int PROCESS_STATE_SERVICE = 10;/** @hide Process is in the background running a receiver.   Note that from the* perspective of oom_adj receivers run at a higher foreground level, but for our* prioritization here that is not necessary and putting them below services means* many fewer changes in some process states as they receive broadcasts. */
public static final int PROCESS_STATE_RECEIVER = 11;/** @hide Process is in the background but hosts the home activity. */
public static final int PROCESS_STATE_HOME = 12;/** @hide Process is in the background but hosts the last shown activity. */
public static final int PROCESS_STATE_LAST_ACTIVITY = 13;/** @hide Process is being cached for later use and contains activities. */
public static final int PROCESS_STATE_CACHED_ACTIVITY = 14;/** @hide Process is being cached for later use and is a client of another cached* process that contains activities. */
public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 15;/** @hide Process is being cached for later use and is empty. */
public static final int PROCESS_STATE_CACHED_EMPTY = 16;

oom_adj分析

oom_adj是dumpsys activity p 中表示应用进程状态的信息,以下是截取的QQ应用以及微信在N机器的上的前后台信息。

QQ前台状态
2018-02-06-15:01:10-625398404
Proc # 0: fore T/A/T trm: 0 16235:com.tencent.mobileqq/u0a100 (top-activity)
oom: max=1001 curRaw=0 setRaw=0 cur=0 set=0
state: cur=T set=T lastPss=166MB lastSwapPss=11MB lastCachedPss=0.00
Proc # 6: vis F/ /T trm: 0 18259:com.tencent.mobileqq:TMAssistantDownloadSDKService/u0a100 (service)
com.tencent.mobileqq/com.tencent.tmdownloader.TMAssistantDownloadService<=Proc{16235:com.tencent.mobileqq/u0a100}
oom: max=1001 curRaw=100 setRaw=100 cur=100 set=100
state: cur=T set=T lastPss=21MB lastSwapPss=603KB lastCachedPss=0.00
Proc # 1: vis F/ /SB trm: 0 16285:com.tencent.mobileqq:MSF/u0a100 (service)
com.tencent.mobileqq/.msf.service.MsfService<=Proc{21231:com.tencent.mobileqq:qzone/u0a100}
oom: max=1001 curRaw=100 setRaw=100 cur=100 set=100
state: cur=SB set=SB lastPss=28MB lastSwapPss=4.3MB lastCachedPss=0.00
Proc # 5: svc B/ /S trm: 0 21231:com.tencent.mobileqq:qzone/u0a100 (started-services)
oom: max=1001 curRaw=500 setRaw=500 cur=500 set=500
state: cur=S set=S lastPss=0.00 lastSwapPss=0.00 lastCachedPss=0.00QQ后台状态2018-02-06-15:01:11-698162429
Proc # 6: prcp F/ /SB trm: 0 18259:com.tencent.mobileqq:TMAssistantDownloadSDKService/u0a100 (service)
com.tencent.mobileqq/com.tencent.tmdownloader.TMAssistantDownloadService<=Proc{16235:com.tencent.mobileqq/u0a100}
oom: max=1001 curRaw=200 setRaw=200 cur=200 set=200
state: cur=SB set=SB lastPss=21MB lastSwapPss=603KB lastCachedPss=0.00
Proc # 2: prcp F/ /SB trm: 0 16285:com.tencent.mobileqq:MSF/u0a100 (service)
com.tencent.mobileqq/.msf.service.MsfService<=Proc{16235:com.tencent.mobileqq/u0a100}
oom: max=1001 curRaw=200 setRaw=200 cur=200 set=200
state: cur=SB set=SB lastPss=28MB lastSwapPss=4.3MB lastCachedPss=0.00
Proc # 1: prcp F/S/SB trm: 0 16235:com.tencent.mobileqq/u0a100 (fg-service)
oom: max=1001 curRaw=200 setRaw=200 cur=200 set=200
state: cur=SB set=SB lastPss=166MB lastSwapPss=11MB lastCachedPss=0.00
Proc # 5: svc B/ /S trm: 0 21231:com.tencent.mobileqq:qzone/u0a100 (started-services)
oom: max=1001 curRaw=500 setRaw=500 cur=500 set=500
state: cur=S set=S lastPss=0.00 lastSwapPss=0.00 lastCachedPss=0.00微信前台状态
2018-02-06-15:55:22-743317581
Proc # 0: fore T/A/T trm: 0 23765:com.tencent.mm/u0a99 (top-activity)
oom: max=1001 curRaw=0 setRaw=0 cur=0 set=0
state: cur=T set=T lastPss=138MB lastSwapPss=8.8MB lastCachedPss=76MB
Proc # 3: vis F/ /SB trm: 0 14557:com.tencent.mm:push/u0a99 (service)
com.tencent.mm/.booter.CoreService<=Proc{23765:com.tencent.mm/u0a99}
oom: max=1001 curRaw=100 setRaw=100 cur=100 set=100
state: cur=SB set=SB lastPss=15MB lastSwapPss=3.4MB lastCachedPss=0.00
Proc #36: svcb B/ /S trm: 0 24482:com.tencent.mm:sandbox/u0a99 (started-services)
oom: max=1001 curRaw=800 setRaw=800 cur=800 set=800
state: cur=S set=S lastPss=24MB lastSwapPss=308KB lastCachedPss=0.00
Proc # 5: cch B/ /CE trm: 0 25785:com.tencent.mm:appbrand0/u0a99 (cch-empty)
oom: max=1001 curRaw=900 setRaw=900 cur=900 set=900
state: cur=CE set=CE lastPss=14MB lastSwapPss=240KB lastCachedPss=14MB
Proc #19: cch+2 B/ /CE trm: 0 25918:com.tencent.mm:tools/u0a99 (cch-empty)
oom: max=1001 curRaw=902 setRaw=902 cur=902 set=902
state: cur=CE set=CE lastPss=17MB lastSwapPss=255KB lastCachedPss=17MB微信后台状态
2018-02-06-15:55:23-830229592
Proc # 3: svc B/ /S trm: 0 14557:com.tencent.mm:push/u0a99 (started-services)
oom: max=1001 curRaw=500 setRaw=500 cur=500 set=500
state: cur=S set=S lastPss=15MB lastSwapPss=3.4MB lastCachedPss=0.00
Proc # 1: prev B/ /S trm: 0 23765:com.tencent.mm/u0a99 (cch-started-ui-services)
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
state: cur=S set=S lastPss=138MB lastSwapPss=8.8MB lastCachedPss=76MB
Proc #36: svcb B/ /S trm: 0 24482:com.tencent.mm:sandbox/u0a99 (started-services)
oom: max=1001 curRaw=800 setRaw=800 cur=800 set=800
state: cur=S set=S lastPss=24MB lastSwapPss=308KB lastCachedPss=0.00
Proc # 5: cch B/ /CE trm: 0 25785:com.tencent.mm:appbrand0/u0a99 (cch-empty)
oom: max=1001 curRaw=900 setRaw=900 cur=900 set=900
state: cur=CE set=CE lastPss=14MB lastSwapPss=240KB lastCachedPss=14MB
Proc #19: cch+2 B/ /CE trm: 0 25918:com.tencent.mm:tools/u0a99 (cch-empty)
oom: max=1001 curRaw=902 setRaw=902 cur=902 set=902
state: cur=CE set=CE lastPss=17MB lastSwapPss=255KB lastCachedPss=17MB

从log中可以清楚的看到状态信息的变化,从这边的结果看,QQ是无法正常禁止后台联网,微信可以(微信可能第一个消息收的到,后面发的消息收不到)。而产生这个问题的原因是这样的,谷歌CTS要求我们的网控机制判断应用前后台的状态的临界点是ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE = 4,qq退到后台的状态是ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 3,不满足我们禁网的条件;微信退到后台的状态是ActivityManager.PROCESS_STATE_SERVICE = 10,满足禁网的条件,所以才会导致这样的问题。

因此以后遇到这类的问题,可以先从这步入手。

流量log
   抓这个log主要是为了查看应用在后台联网时,是否有流量的使用,直接上图吧。

结语

基本上一个应用的后台联网问题,可以通过以上分析方法去分析,然后根据结果去找对应的人设去处理,上述分析,如有问题或者疑问可以相互交流。

Android应用后台网络管控机制相关推荐

  1. Android 怎么防止多并发请求?比如说一个页面需要请求多个接口,可以跟后台网络交互能做哪些性能优化

    Android 本来就是要做并发请求,开线程池在里面发网络请求,如果真要防止并发,那就弄个排队的线程池就行了.可以参考 AsyncTask 在高版本的实现,就是排队. 跟后台网络交互的优化,列出来了如 ...

  2. Android后台杀死系列之一:FragmentActivity及PhoneWindow后台杀死处理机制

    App在后台久置后,再次从桌面或最近的任务列表唤醒时经常会发生崩溃,这往往是App在后台被系统杀死,再次恢复的时候遇到了问题,而在使用FragmentActivity+Fragment的时候会更加频繁 ...

  3. 【Android】Android网络评分机制简单总结

    文章参考于: 三.Android 网络评分机制 - 简书在前两节简单介绍了连接管理的大致框架,数据链接的准备工作,包括APN的初始化与默认APN使能,DcTracker的构造,包括各种事件的注册等工作 ...

  4. android 手机内存uri_Android消息机制Handler原理解析

    关注[搜狐技术产品]公众号,第一时间获取技术干货 导读 在Android中,Handler一直是一个热点,在开发过程中,它的使用频率很高,而且在Android源码中Handler都是常客.那么Hand ...

  5. Android中后台线程如何与UI线程交互

    我想关于这个话题已经有很多前辈讨论过了.今天算是一次学习总结吧. 在android的设计思想中,为了确保用户顺滑的操作体验.一些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务.因此我们必须 ...

  6. Android心跳包(一)——心跳机制

    转自:http://blog.csdn.net/rabbit_in_android/article/details/50119809 在写之前,我们首先了解一下为什么android维护长连接需要心跳机 ...

  7. 图形引擎实战:手游Android端后台下载技术分享

    一.功能特点 手游android端后台下载SDK是畅游自主研发的一款移动平台android端后台文件下载工具包,它主要提供网络文件的后台下载功能,功能完善,性能高,可以满足游戏制作有关后台下载文件的需 ...

  8. Android编程获取网络连接状态及调用网络配置界面

    获取网络连接状态 随着3G和Wifi的推广,越来越多的Android应用程序需要调用网络资源,检测网络连接状态也就成为网络应用程序所必备的功能. Android平台提供了ConnectivityMan ...

  9. Android 实现无网络传输文件(2)

    在我的上一篇文章:Android 实现无网络传输文件,我介绍了通过 Wifi Direct(Wifi 直连)实现 Android 设备之间进行文件传输的方法,可以在无移动网络的情况下实现点对点的文件传 ...

最新文章

  1. Android Studio无法打开解决方法
  2. 什么是CRM Sales category
  3. 函数_月隐学python第9课
  4. Hello Blazor:(13)查找HTML元素对应.razor文件
  5. C#中的Explicit和Implicit了解一下吧
  6. SpringBoot 配置文件bootstrap和application的区别
  7. 印度不只有开挂火车,还有一开挂的数学家,凭一己之力单刷数学界
  8. cad在哪里设置图幅大小_CAD教程之如何设置十字光标大小及颜色
  9. win32调用系统颜色对话框
  10. 宁波大学计算机网络实验五,宁波大学计算机网络实验四.doc
  11. 扩展-视图 View
  12. https://www.jianshu.com/p/5b710cc25f81
  13. matlab10的阶层怎么输入,matlab阶乘和程序
  14. 进华为你必须了解的——华为精神
  15. [视频]AI 机器学习 深度学习 视频教程汇总
  16. 网络隔离下的几种数据交换技术比较
  17. 关于python的ppt_用Python玩转PPT
  18. 如何用Python进行数据分析
  19. PAKDD 2019 都有哪些重要看点?看这篇文章就够了!...
  20. Android传感器的使用开发、简易指南针

热门文章

  1. [转载]BitComet 加速篇
  2. c语言项目手机通讯录系统
  3. java计算机毕业设计ssm高校校友信息管理系统
  4. 冒死潜入某个外包公司获得的珍贵Java基础笔试题(附答案)
  5. mybatis-plus 关联查询
  6. Android通知栏介绍与适配总结
  7. 从长远来看,这 4 个区块链项目能够为你带来 10 倍的回报
  8. 后羿 02 ‖ 嫦娥
  9. git push origin master提交报错解决办法
  10. Linux 仅安装mysql客户端