Android应用后台网络管控机制

article/2025/10/8 4:23:47

应用后台网络管控机制

概述

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

网络管控流程

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

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主要是为了查看应用在后台联网时,是否有流量的使用,直接上图吧。
流量使用

结语

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


http://chatgpt.dhexx.cn/article/1CD1s1ih.shtml

相关文章

Android将后台应用唤起到前台的方法

在我们开发的过程中&#xff0c;经常遇到app进入后台&#xff0c;或者切换到前台的情况。 比如&#xff1a; 从后台切换到前台显示全屏广告实践来电显示从后台切换到前台 如图显示&#xff1a;压后台10秒钟&#xff0c;自动弹出 实现主要分为两个步骤&#xff1a; 第一步通…

后台功能

#&#x1f30c; 后台功能 后台功能模块&#xff0c;包含主控面板&#xff0c;开发管理&#xff0c;日志管理&#xff0c;系统监控&#xff0c;通知公告&#xff0c;文件管理&#xff0c;定时任务。 #1. 主控面饭 主控面板展示了系统的一些统计信息&#xff0c;采用默认的ant…

如何让应用保持后台运行,做到保活?

其实&#xff0c;我们无法做到真正意义上的保活&#xff0c;应为系统进程会自动杀死占用过大内存的某个应用。 但我们还有一种选择&#xff0c;就是过滤该应用的包名&#xff0c;做到后台任务键清理不掉它&#xff0c;单独去除不掉它&#xff0c;只有返回键才能做到真正的退出…

【已解决】Android 如何让应用在后台运行

应用在后台跑&#xff0c;这种说法可能不够准确&#xff0c;就是说应用没有finish退出&#xff0c;但也不在前台的状态&#xff0c;例如应用执行中点击了home键一样。如何实现呢&#xff1f; 要点&#xff1a; 退回后台是执行了home键&#xff0c;activity分别执行了onPause和…

如何让安卓APP一直在后台运行?

本文摘自微信公众号“android高心星的私塾” 一 声明 1 网上很多的保活手段&#xff0c;但是不靠谱的居多 2 本文只是进行保活知识的推广&#xff0c;不是在教你做永生不死的进程 二 保活手段 1 业界保活手段&#xff1a;黑色保活&#xff0c;灰色保活&#xff0c;白色保活 2…

Android | 判断App处于前台还是后台的方案

很多场景下&#xff0c;都需要判断某个App处于前台还是后台。本文集网上编写的前台判断方案于一体。 目前&#xff0c;有6种方案&#xff1a; 方 法 判断原理需要权限可以判断其他应用位于前台特点①RunningTask否Andorid4.0系列可以&#xff0c;5.0以上机器不行Android5.0此方…

fastapi_No.18_后台应用

文章目录 简介使用场景 创建后台应用步骤第一步&#xff1a;定义后台应用函数第二步&#xff1a;使用后台应用函数 在依赖项中的后台应用示例代码示例代码说明 简介 后台应用就是在发送响应后运行的函数。通常用在请求后需要耗费较长时间处理&#xff0c;且客户端不需要在接收…

win11如何禁用后台应用权限 Windows11禁用后台应用权限的设置方法

我在使用Win11系统的电脑时经常会遇到自动打开应用程序情况&#xff0c;很多小伙伴都不知道到如何关闭&#xff0c;那么遇到这种情况应该要如何解决呢?下面就和小编一起来看看Win11系统要如何去禁用软件的后台权限吧。更多windows11系统教程&#xff0c;可以参考小白一键重装网…

提高软件CPU占用率

案例&#xff1a; 独立线程以5ms一包的速率接收指令&#xff08;一共大概70-80种指令类型&#xff09;&#xff0c;并放入一个队列A 主线程中&#xff0c;根据定时器去队列A中取数据&#xff0c;并解析/计算/显示&#xff08;速率&#xff1a;200包/秒&#xff09; 现象&…

CPU使用率100%,如何解决

文章目录 CPU使用率概念CPU使用率的重要指标计算公式 查看CPU使用率CPU 使用率过高总结 CPU使用率 概念 单位时间内CPU使用情况的统计&#xff0c;以百分比方式显示 Linux是一个多任务操作系统&#xff0c;将每个CPU的时间划分为很短的时间片&#xff0c;通过调度器轮流分配…

解决 服务器cpu使用率100%,变成矿鸡之我与病毒crypto斗智斗勇,宝塔面板cpu使用率100%爆红

关于 简单解决宝塔面板显示CPU使用率 100%&#xff0c;但top却没找到相关进程这件事&#xff01;&#xff01;&#xff01; 如图&#xff1a; 作为一个小白&#xff0c;我只是想简单的搭建一个个人网站&#xff0c;结果碰到这个闹心的事。 服务器: 阿里云服务器 面板&#xff…

linux的mysql占用cpu过高_关于在Linux环境下,Mysql占用CPU使用率100%的优化

今天使用 MobaXterml 连接上一台物联网的Linux服务器的使用&#xff0c;发现该服务器的CPU使用率一直在100%左右。 使用top 命令发现Mysql占用了大量的CPU 用数据库工具 Navicat premium 以 root 的身份连接数据库&#xff0c;执行查询语句&#xff1a; show PROCESSLIST; 发现…

CPU使用率到100%,有哪些因素影响?

关注星标公众号&#xff0c;不错过精彩内容 转自 | 涛哥依旧 最近&#xff0c;一位同事急匆匆跑过来跟我说&#xff1a;糟糕了&#xff0c;服务器CPU的使用率达100%了。 我心想不可能啊&#xff0c;CPU有那么多核&#xff0c;怎会跑满&#xff1f;于是看了一眼&#xff0c;结果…

记一次golang cpu 占用100%

最近重新部署了下测试服务器&#xff0c;发现其负载达到了4.*&#xff0c; cpu 使用率达到了100%&#xff0c;吓的瑟瑟发抖&#xff0c;马上起来查看情况。 1&#xff0c; 想到了使用go性能查看工具&#xff1a; pprof&#xff0c;因为项目是用gin开发的&#xff0c;所在直接安…

Mysql CPU占用100%查询

这几天每天都会收到服务器负载报警&#xff0c;抽出时间查看一下原因。 进入到服务器使用top命令查看&#xff1a; 能够看到是mysql常年霸居榜首&#xff0c;导致服务器负载变高。理论上来讲&#xff0c;数据量没有那么大&#xff0c;因为很多数据都是没用的&#xff0c;前一段…

【故障排查】如何排查CPU占用100%

线上后台报警CPU占用100%&#xff0c;CPU占用过高&#xff0c;本文介绍一下如何排查CPU占用过高原因。 步骤1. top 输入top命令&#xff0c;找到占用CPU最高的进程。按ShiftP键排序&#xff1a; 可以看到CPU占用最高的pid是92129。 步骤2. top -Hp pid 查看指定进程内线程信…

vmware虚拟机WinXp sp3的系统cpu占用100%的解决方案

0x00 问题场景 1. 环境配置 角色版本位数备注虚拟机软件VMware Workstation15\原始版本12&#xff0c;升到15Host OSWindows 7 Professional6.1.7601, Service Pack 164-bit\Guest OSWindows XPservice Pack 332 bit\ 2. 环境说明 VMware在很久以前是version12&#xff0c;…

Win10环境VMware开WinXP虚拟机CPU占用100%

解决办法 网上试了各种方法&#xff0c;还是不太行&#xff0c;最后莫名其妙的好了。而这之前我只做了一件事&#xff0c;在windows的功能里打开hyper-V服务。 后续 某一天&#xff0c;windows系统自动更新了&#xff0c;然后本来运行得好好的win xp虚拟机变得巨卡。我在w…

IDEACPU占用100%_卡顿 解决办法

解决IDEA占用CPU100%的问题 直接上答案为什么会占用CPU如何查找占用CPU的原因 直接上答案 绝大部分的原因是你打开了一个有非常非常多的代码的类&#xff0c;并且你并不编辑这个类&#xff0c;你只是打开了。。。 当然&#xff0c;如果不是这样&#xff0c;你才能去排查是不是…

linux的cpu使用率100%?

1&#xff1a;背景 在linux环境中&#xff0c;我们都会通过top指令获取当前实例的进场占用cpu情况&#xff0c;如下所示 [123456789root ~]$ top top - 11:48:13 up 622 days, 15:51, 2 users, load average: 0.22, 0.19, 0.11 Tasks: 788 total, 1 running, 787 sleepin…