测试时关注到bw_costly_链
因为和iface有关。猜测这个链是动态生成的。
开关数据业务测试,果然关闭数据业务后,bw_OUTPUT中不再会调用bw_costly_rmnet_data3,也没有bw_costly_rmnet_data3这个链了。
再次打开数据业务后出现了bw_costly_rmnet_data2。说明上次上网的rmnet_data3口,这此上网的rmnet_data2。
cpp
:/ # iptables -t filter -nvL bw_OUTPUT
Chain bw_OUTPUT (1 references)
pkts bytes target prot opt in out source destination
24 1909 bw_global_alert all -- * * 0.0.0.0/0 0.0.0.0/0
2 120 bw_costly_rmnet_data3 all -- * rmnet_data3 0.0.0.0/0 0.0.0.0/0
是netd模块自己检测上网状态后,自己添加的吗?
查看代码是netd的BandwidthController生成。
cpp
int BandwidthController::setInterfaceQuota(const std::string& iface, int64_t maxBytes) {
const std::string& cost = iface;
....
/* Insert ingress quota. */
auto it = mQuotaIfaces.find(iface);
if (it != mQuotaIfaces.end()) {
if (int res = updateQuota(cost, maxBytes)) {
ALOGE("Failed update quota for %s", iface.c_str());
removeInterfaceQuota(iface);
return res;
}
it->second.quota = maxBytes;
return 0;
}
const std::string chain = "bw_costly_" + iface;
const int ruleInsertPos = (mGlobalAlertBytes) ? 2 : 1;
std::vector<std::string> cmds = {
"*filter",
StringPrintf(":%s -", chain.c_str()),
StringPrintf("-A %s -j bw_penalty_box", chain.c_str()),
StringPrintf("-I bw_INPUT %d -i %s -j %s", ruleInsertPos, iface.c_str(), chain.c_str()),
StringPrintf("-I bw_OUTPUT %d -o %s -j %s", ruleInsertPos, iface.c_str(),
chain.c_str()),
StringPrintf("-A bw_FORWARD -i %s -j %s", iface.c_str(), chain.c_str()),
StringPrintf("-A bw_FORWARD -o %s -j %s", iface.c_str(), chain.c_str()),
StringPrintf("-A %s -m quota2 ! --quota %" PRId64 " --name %s -j REJECT", chain.c_str(),
maxBytes, cost.c_str()),
"COMMIT\n",
};
if (iptablesRestoreFunction(V4V6, Join(cmds, "\n"), nullptr) != 0) {
ALOGE("Failed set quota rule");
removeInterfaceQuota(iface);
return -EREMOTEIO;
}
mQuotaIfaces[iface] = QuotaInfo{maxBytes, 0};
return 0;
}
netd 向上提供此接口,内部除了ndc模块通过控制台可以调用,没有自动关注网络状态,调用setInterfaceQuota的地方:
cpp
binder::Status NetdNativeService::bandwidthSetInterfaceQuota(const std::string& ifName,
int64_t bytes) {
NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
int res = gCtls->bandwidthCtrl.setInterfaceQuota(ifName, bytes);
return statusFromErrcode(res);
}
继续在android代码中搜索:
framework的NetworkManagementService.java中调用
mNetdService.bandwidthSetInterfaceQuota
cpp
public void setInterfaceQuota(String iface, long quotaBytes) {
NetworkStack.checkNetworkStackPermission(mContext);
synchronized (mQuotaLock) {
if (mActiveQuotas.containsKey(iface)) {
throw new IllegalStateException("iface " + iface + " already has quota");
}
try {
// TODO: support quota shared across interfaces
mNetdService.bandwidthSetInterfaceQuota(iface, quotaBytes);
mActiveQuotas.put(iface, quotaBytes);
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
synchronized (mTetheringStatsProviders) {
for (ITetheringStatsProvider provider : mTetheringStatsProviders.keySet()) {
try {
provider.setInterfaceQuota(iface, quotaBytes);
} catch (RemoteException e) {
Log.e(TAG, "Problem setting tethering data limit on provider " +
mTetheringStatsProviders.get(provider) + ": " + e);
}
}
}
}
}
调用序列是:
NatworkManagementService:
NatworkManagementService.systemReady->prepareNativeDaemon()->setInterfaceQuota->mNetdService.bandwidthSetInterfaceQuota
下一步分析数据业务开关后,是什么流程触发NatworkManagementService的setInterfaceQuota和removeInterfaceQuota的调用。
参考链接:
Android系统中iptables的应用(二)BandwidthController https://blog.csdn.net/xiaokeweng/article/details/48810049