android 8.0
android/base/packages/SystemUI/src/com/android/systemui/
statusbar/SignalClusterView.java
android 9.0
statusbar/StatusBarWifiView.java
与手机信号栏的控制一致, 由
NetworkControllerImpl 和 WifiSignalControll
NetworkControllerImpl.java{
public void onReceive(Context context, Intent intent) {
if (CHATTY) {
Log.d(TAG, "onReceive: intent=" + intent);
}
final String action = intent.getAction();
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
updateConnectivity();
.........
} else {
// No sub id, must be for the wifi.
mWifiSignalController.handleBroadcast(intent);
}
}
/**
* Update the Inet conditions and what network we are connected to.
*/
//更新 inet
private void updateConnectivity() {
mConnectedTransports.clear();
mValidatedTransports.clear();
//获取当前网络功能接口, 得到当前连接的网络类型以及是否有效 ------查看具体api
for (NetworkCapabilities nc :mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) {
for (int transportType : nc.getTransportTypes()) {
//验证传输是否连接
mConnectedTransports.set(transportType);
if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) {
// 验证传输是否有效
mValidatedTransports.set(transportType);
}
}
}
if (CHATTY) {
Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports);
Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
}
mInetCondition = !mValidatedTransports.isEmpty();
pushConnectivityToSignals();
}
/**
* Pushes the current connectivity state to all SignalControllers.
*/
private void pushConnectivityToSignals() {
// We want to update all the icons, all at once, for any condition change
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
}
mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
}
}
/frameworks/base/services/core/java/com/android/server/ConnectivityService.java
/**
* Update the NetworkCapabilities for {@code networkAgent} to {@code networkCapabilities}
* augmented with any stateful capabilities implied from {@code networkAgent}
* (e.g., validated status and captive portal status).
*
* @param oldScore score of the network before any of the changes that prompted us
* to call this function.
* @param nai the network having its capabilities updated.
* @param networkCapabilities the new network capabilities.
*/
private void updateCapabilities(
int oldScore, NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
// Once a NetworkAgent is connected, complain if some immutable capabilities are removed.
if (nai.everConnected && !nai.networkCapabilities.satisfiedByImmutableNetworkCapabilities(
networkCapabilities)) {
// TODO: consider not complaining when a network agent degrade its capabilities if this
// does not cause any request (that is not a listen) currently matching that agent to
// stop being matched by the updated agent.
String diff = nai.networkCapabilities.describeImmutableDifferences(networkCapabilities);
if (!TextUtils.isEmpty(diff)) {
Slog.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
}
}
// Don't modify caller's NetworkCapabilities.
networkCapabilities = new NetworkCapabilities(networkCapabilities);
if (nai.lastValidated) {
networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
} else {
networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED);
}
if (nai.lastCaptivePortalDetected) {
networkCapabilities.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
} else {
networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
}
if (nai.isBackgroundNetwork()) {
networkCapabilities.removeCapability(NET_CAPABILITY_FOREGROUND);
} else {
networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
}
if (Objects.equals(nai.networkCapabilities, networkCapabilities)) return;
final String oldPermission = getNetworkPermission(nai.networkCapabilities);
final String newPermission = getNetworkPermission(networkCapabilities);
if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {
try {
mNetd.setNetworkPermission(nai.network.netId, newPermission);
} catch (RemoteException e) {
loge("Exception in setNetworkPermission: " + e);
}
}
final NetworkCapabilities prevNc = nai.networkCapabilities;
synchronized (nai) {
nai.networkCapabilities = networkCapabilities;
}
if (nai.getCurrentScore() == oldScore &&
networkCapabilities.equalRequestableCapabilities(prevNc)) {
// If the requestable capabilities haven't changed, and the score hasn't changed, then
// the change we're processing can't affect any requests, it can only affect the listens
// on this network. We might have been called by rematchNetworkAndRequests when a
// network changed foreground state.
processListenRequests(nai, true);
} else {
// If the requestable capabilities have changed or the score changed, we can't have been
// called by rematchNetworkAndRequests, so it's safe to start a rematch.
rematchAllNetworksAndRequests(nai, oldScore);
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
}
private void maybeHandleNetworkAgentMessage(Message msg) {
NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
if (nai == null) {
if (VDBG) {
log(String.format("%s from unknown NetworkAgent", eventName(msg.what)));
}
return;
}
switch (msg.what) {
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
final NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) ||
networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) ||
networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) {
Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
}
//调用他的地方
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
break;
}
.....
......
}
private boolean maybeHandleNetworkMonitorMessage(Message msg) {
switch (msg.what) {
default:
return false;
case NetworkMonitor.EVENT_NETWORK_TESTED: {
final NetworkAgentInfo nai;
synchronized (mNetworkForNetId) {
nai = mNetworkForNetId.get(msg.arg2);
}
if (nai != null) {
//是否 valid 的值是通过参数 NetworkMonitor.NETWORK_TEST_RESULT_VALID 判断的
final boolean valid =
(msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
final boolean wasValidated = nai.lastValidated;
if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
(msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
if (valid != nai.lastValidated) {
final int oldScore = nai.getCurrentScore();
//设置 valid
nai.lastValidated = valid;
nai.everValidated |= valid;
//设置进值
updateCapabilities(oldScore, nai, nai.networkCapabilities);
// If score has changed, rebroadcast to NetworkFactories. b/17726566
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
}
..........
...........
}
进入 /frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
//这个类也是很重要的, 网络监控类
// Being in the ValidatedState State indicates a Network is:
// - Successfully validated, or
// - Wanted "as is" by the user, or
// - Does not satisfy the default NetworkRequest and so validation has been skipped.
private class ValidatedState extends State {
@Override
public void enter() {
maybeLogEvaluationResult(
networkEventType(validationStage(), EvaluationResult.VALIDATED));
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
NETWORK_TEST_RESULT_VALID, mNetId, null));
mValidations++;
}
@Override
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_NETWORK_CONNECTED:
transitionTo(mValidatedState);
return HANDLED;
default:
return NOT_HANDLED;
}
}
}
通过网络连接,验证网络
// Being in the EvaluatingState State indicates the Network is being evaluated for internet
// connectivity, or that the user has indicated that this network is unwanted.
private class EvaluatingState extends State {
private int mReevaluateDelayMs;
private int mAttempts;
@Override
public void enter() {
// If we have already started to track time spent in EvaluatingState
// don't reset the timer due simply to, say, commands or events that
// cause us to exit and re-enter EvaluatingState.
if (!mEvaluationTimer.isStarted()) {
mEvaluationTimer.start();
}
sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
if (mUidResponsibleForReeval != INVALID_UID) {
TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
mUidResponsibleForReeval = INVALID_UID;
}
mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
mAttempts = 0;
}
@Override
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_REEVALUATE:
if (message.arg1 != mReevaluateToken || mUserDoesNotWant)
return HANDLED;
// Don't bother validating networks that don't satisify the default request.
// This includes:
// - VPNs which can be considered explicitly desired by the user and the
// user's desire trumps whether the network validates.
// - Networks that don't provide internet access. It's unclear how to
// validate such networks.
// - Untrusted networks. It's unsafe to prompt the user to sign-in to
// such networks and the user didn't express interest in connecting to
// such networks (an app did) so the user may be unhappily surprised when
// asked to sign-in to a network they didn't want to connect to in the
// first place. Validation could be done to adjust the network scores
// however these networks are app-requested and may not be intended for
// general usage, in which case general validation may not be an accurate
// measure of the network's quality. Only the app knows how to evaluate
// the network so don't bother validating here. Furthermore sending HTTP
// packets over the network may be undesirable, for example an extremely
// expensive metered network, or unwanted leaking of the User Agent string.
if (!mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities(
mNetworkAgentInfo.networkCapabilities)) {
validationLog("Network would not satisfy default request, not validating");
transitionTo(mValidatedState);
return HANDLED;
}
mAttempts++;
// Note: This call to isCaptivePortal() could take up to a minute. Resolving the
// server's IP addresses could hit the DNS timeout, and attempting connections
// to each of the server's several IP addresses (currently one IPv4 and one
// IPv6) could each take SOCKET_TIMEOUT_MS. During this time this StateMachine
// will be unresponsive. isCaptivePortal() could be executed on another Thread
// if this is found to cause problems.
//从此处判断网络是否是可用的
CaptivePortalProbeResult probeResult = isCaptivePortal();
if (probeResult.isSuccessful()) {
transitionTo(mValidatedState);
} else if (probeResult.isPortal()) {
@VisibleForTesting
protected CaptivePortalProbeResult isCaptivePortal() {
.............
........
}
public abstract class SignalController<T extends SignalController.State,
I extends SignalController.IconGroup> {
public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
mCurrentState.inetCondition = validatedTransports.get(mTransportType) ? 1 : 0;
notifyListenersIfNecessary();
}
public void notifyListenersIfNecessary() {
if (isDirty()) {
saveLastState();
notifyListeners();
}
}
}
、WifiSignalController.java
public class WifiSignalController extends
SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
private final WifiManager mWifiManager;
private final AsyncChannel mWifiChannel;
private final boolean mHasMobileData;
private final WifiStatusTracker mWifiTracker;
public WifiSignalController(Context context, boolean hasMobileData,
CallbackHandler callbackHandler, NetworkControllerImpl networkController) {
super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
callbackHandler, networkController);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mWifiTracker = new WifiStatusTracker(mWifiManager);
mHasMobileData = hasMobileData;
Handler handler = new WifiHandler(Looper.getMainLooper());
mWifiChannel = new AsyncChannel();
Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
if (wifiMessenger != null) {
mWifiChannel.connect(context, handler, wifiMessenger);
}
// WiFi only has one state.
mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
"Wi-Fi Icons",
WifiIcons.WIFI_SIGNAL_STRENGTH,
WifiIcons.QS_WIFI_SIGNAL_STRENGTH,
AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
WifiIcons.WIFI_NO_NETWORK,
WifiIcons.QS_WIFI_NO_NETWORK,
WifiIcons.WIFI_NO_NETWORK,
WifiIcons.QS_WIFI_NO_NETWORK,
AccessibilityContentDescriptions.WIFI_NO_CONNECTION
);
}/**
* Handler to receive the data activity on wifi.
*/
private class WifiHandler extends Handler {
WifiHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
mWifiChannel.sendMessage(Message.obtain(this,
AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
} else {
Log.e(mTag, "Failed to connect to wifi");
}
break;
case WifiManager.DATA_ACTIVITY_NOTIFICATION:
//得到framework 层发来的消息
setActivity(msg.arg1);
break;
default:
// Ignore
break;
}
}
}
@VisibleForTesting
void setActivity(int wifiActivity) {
mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
|| wifiActivity == WifiManager.DATA_ACTIVITY_IN;
mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
|| wifiActivity == WifiManager.DATA_ACTIVITY_OUT;
notifyListenersIfNecessary();
}
}
public class AsyncChannel {
.....
// 看注释便能理解,链接
srcHandler 与 dstMessenger
public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
if (DBG) log("connect srcHandler to the dstMessenger E");
// We are connected
connected(srcContext, srcHandler, dstMessenger);
// Tell source we are half connected
replyHalfConnected(STATUS_SUCCESSFUL);
if (DBG) log("connect srcHandler to the dstMessenger X");
}
public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
if (DBG) log("connected srcHandler to the dstMessenger E");
// Initialize source fields
mSrcContext = srcContext;
mSrcHandler = srcHandler;
//利用 messenegr 进行跨进成通信
mSrcMessenger = new Messenger(mSrcHandler);
// Initialize destination fields
mDstMessenger = dstMessenger;
//从log 可以看出来是 目的messenger 与 srcHandler 进行数据交互
if (DBG) log("connected srcHandler to the dstMessenger X");
}
/**
* Send a message to the destination handler.
* @param msg
*/
public void sendMessage(Message msg) {
msg.replyTo = mSrcMessenger;
try {
mDstMessenger.send(msg);
} catch (RemoteException e) {
replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
}
}
/**
* Reply to the src handler that we're half connected.
* see: CMD_CHANNEL_HALF_CONNECTED for message contents
*
* @param status to be stored in msg.arg1
*/
private void replyHalfConnected(int status) {
Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
msg.arg1 = status;
msg.obj = this;
msg.replyTo = mDstMessenger;
if (!linkToDeathMonitor()) {
// Override status to indicate failure
msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
}
mSrcHandler.sendMessage(msg);
}
}
public class WifiServiceImpl extends IWifiManager.Stub {
/**
* Handles client connections
*/
private class ClientHandler extends WifiHandler {
ClientHandler(String tag, Looper looper) {
super(tag, looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
//这个msg 是 AsyncChannel 里的 发过来的
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
// We track the clients by the Messenger
// since it is expected to be always available
//在这里add client
mTrafficPoller.addClient(msg.replyTo);
} else {
Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
}
......
.......
......
}
/**
* Get a reference to handler. This is used by a client to establish
* an AsyncChannel communication with WifiService
*/
// 上面得到 messenger的对象
@Override
public Messenger getWifiServiceMessenger() {
enforceAccessPermission();
enforceChangePermission();
if (mVerboseLoggingEnabled) {
mLog.info("getWifiServiceMessenger uid=%").c(Binder.getCallingUid()).flush();
}
return new Messenger(mClientHandler);
}
}
handleMessage中接收的消息又是哪里发出的呢
/frameworks/base/services/java/com/android/server/wifi/WifiTrafficPoller.java
public class WifiTrafficPoller {
WifiTrafficPoller(Context context, Looper looper, String iface) {
mInterface = iface;
mTrafficHandler = new TrafficHandler(looper);
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
context.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(
intent.getAction())) {
mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
WifiManager.EXTRA_NETWORK_INFO);
} else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
mScreenOn.set(false);
} else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
mScreenOn.set(true);
}
//如果监听到广播,则
evaluateTrafficStatsPolling();
}
}, filter);
}
private void evaluateTrafficStatsPolling() {
Message msg;
if (mNetworkInfo == null) return;
if (mNetworkInfo.getDetailedState() == CONNECTED && mScreenOn.get()) {
msg = Message.obtain(mTrafficHandler,
ENABLE_TRAFFIC_STATS_POLL, 1, 0);
} else {
msg = Message.obtain(mTrafficHandler,
ENABLE_TRAFFIC_STATS_POLL, 0, 0);
}
//发送handler消息,最终再调用 notifyOnDataActivity
msg.sendToTarget();
}
//根据流量的上行还是下行选择出图片并将消息发送出去
private void notifyOnDataActivity() {
long sent, received;
//保存当前的上下行数据包的数量
long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
//通过如下的方法获取当前的上下行的数据包的数量
mTxPkts = TrafficStats.getTxPackets(mInterface);
mRxPkts = TrafficStats.getRxPackets(mInterface);
if (DBG) {
Log.d(TAG, " packet count Tx="
+ Long.toString(mTxPkts)
+ " Rx="
+ Long.toString(mRxPkts));
}
if (preTxPkts > 0 || preRxPkts > 0) {
sent = mTxPkts - preTxPkts;
received = mRxPkts - preRxPkts;
//如果是发送数据
if (sent > 0) {
dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
}
//接受数据
if (received > 0) {
dataActivity |= WifiManager.DATA_ACTIVITY_IN;
}
if (dataActivity != mDataActivity && mScreenOn.get()) {
mDataActivity = dataActivity;
if (mVerboseLoggingEnabled) {
Log.e(TAG, "notifying of data activity "
+ Integer.toString(mDataActivity));
}
for (Messenger client : mClients) {
Message msg = Message.obtain();
msg.what = WifiManager.DATA_ACTIVITY_NOTIFICATION;
msg.arg1 = mDataActivity;
try {
client.send(msg);
} catch (RemoteException e) {
// Failed to reach, skip
// Client removal is handled in WifiService
}
}
}
}
}
/home/lilei/work/WingRom2/android/frameworks/base/core/java/android/net/TrafficStats.java
public class TrafficStats {
/**
* The return value to indicate that the device does not support the statistic.
*/
public final static int UNSUPPORTED = -1;
/** @hide */
public static final long KB_IN_BYTES = 1024;
/** @hide */
public static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
/** @hide */
public static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
/** @hide */
public static final long TB_IN_BYTES = GB_IN_BYTES * 1024;
/** @hide */
public static final long PB_IN_BYTES = TB_IN_BYTES * 1024;
//调用 native方法得到数据
/** {@hide} */
public static long getTxPackets(String iface) {
return nativeGetIfaceStat(iface, TYPE_TX_PACKETS);
}
}
LINUX/android/frameworks/base/core/jni/android_net_TrafficStats.cpp文件中
其中mInterface是在LINUX/android/frameworks/base//services/java/com
/android/server/wifi/WifiService.java中如下的代码实现了接口获取:
mInterfaceName = SystemProperties.get("wifi.interface","wlan0");
mTrafficPoller = newWifiTrafficPoller(mContext, mInterfaceName);
那么TrafficStats.getTxPackets具体是怎么获取流量包数据的呢?解释:(4);
4、LINUX/android/frameworks/base/core/java/android/net/TrafficStats.java文件中
//getTxPackets的具体实现是通过nativeGetIfaceStat实现
public static long getTxPackets(String iface) {
return nativeGetIfaceStat(iface, TYPE_TX_PACKETS);
}
//通过全局搜索 nativeGetIfaceStat
关键字, 找到
LINUX/android/frameworks/base/core/jni/android_net_TrafficStats.cpp文件中
// nativeGetIfaceStat是通过 getIfaceStat实现
static JNINativeMethod gMethods[] = {
{"nativeGetIfaceStat", "(Ljava/lang/String;I)J",(void*) getIfaceStat}
}
static jlong getIfaceStat(JNIEnv* env,jclass clazz, jstring iface, jint type) {
ScopedUtfChars iface8(env, iface);
if (parseIfaceStats(iface8.c_str(), &stats) == 0)
}
LINUX/android/libnativehelper/include/nativehelper/ScopedUtfChars.h中
const char* c_str() const {
//utf_chars_的值为wlan0
return utf_chars_;
}
LINUX/android/frameworks/base/core/jni/android_net_TrafficStats.cpp文件中
QTAGUID_IFACE_STATS ="/proc/net/xt_qtaguid/iface_stat_fmt";
static int parseIfaceStats(const char* iface, struct Stats* stats) {
FILE *fp = fopen(QTAGUID_IFACE_STATS, "r");
if (fp == NULL) {
return -1;
}
char buffer[384];
char cur_iface[32];
bool foundTcp = false;
uint64_t rxBytes, rxPackets, txBytes, txPackets, tcpRxPackets, tcpTxPackets;
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
int matched = sscanf(buffer, "%31s %" SCNu64 " %" SCNu64 " %" SCNu64
" %" SCNu64 " " "%*u %" SCNu64 " %*u %*u %*u %*u "
"%*u %" SCNu64 " %*u %*u %*u %*u", cur_iface, &rxBytes,
&rxPackets, &txBytes, &txPackets, &tcpRxPackets, &tcpTxPackets);
if (matched >= 5) {
if (matched == 7) {
foundTcp = true;
}
if (!iface || !strcmp(iface, cur_iface)) {
stats->rxBytes += rxBytes;
stats->rxPackets += rxPackets;
stats->txBytes += txBytes;
stats->txPackets += txPackets;
if (matched == 7) {
stats->tcpRxPackets += tcpRxPackets;
stats->tcpTxPackets += tcpTxPackets;
}
}
}
}
if (!foundTcp) {
stats->tcpRxPackets = UNKNOWN;
stats->tcpTxPackets = UNKNOWN;
}
if (fclose(fp) != 0) {
return -1;
}
return 0;
}
那么iface_stat_fmt又是如何创建的呢?解释:5
5、LINUX/android/kernel/net/netfilter/xt_qtaguid.c中
通过如下的方法创建 iface_stat_fmt
static const char*iface_stat_fmt_procfilename = "iface_stat_fmt";
iface_stat_fmt_procfile = proc_create_data(iface_stat_fmt_procfilename,
proc_iface_perms,
parent_procdir,
&proc_iface_stat_fmt_fops,
(void *)2 /* fmt2 */);