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 */);