一、背景介绍
打开wifi连接上ap在状态栏里面期望图标显示如下:
以下图片所在的目录为:LINUX/android/base/packages/SystemUI/res/drawable-xhdpi
二、流程跟踪
1、LINUX/android/base/packages/SystemUI/src/com/android/systemui/
statusbar/SignalClusterView.java文件中
调用如下代码实现上下行流量的图标:
public void setWifiIndicators(booleanvisible, int strengthIcon, int activityIcon, String contentDescription) {
mMobileActivityId = activityIcon;
apply();
}
private void apply() {
//显示图标
mMobileActivity.setImageResource(mMobileActivityId);
}
具体显示哪一个要根据 mMobileActivityId的值来确定;那么mMobileActivityId是怎么确定出来的呢?解释:2;
2、LINUX/android/framework/base/packages/SystemUI/src/com/android/
systemui/statusbar/policy/NetworkController.java
首先接收了一个消息并对消息进行了处理:
class WifiHandler extends Handler {
public void handleMessage(Message msg) {
//获取消息里面的内容
mWifiActivity = msg.arg1;
//调用方法刷新显示
refreshViews();
}
}
void refreshViews() {
//根据 mWifiActivity的值具体选择需要显示哪张图片
switch (mWifiActivity) {
caseWifiManager.DATA_ACTIVITY_IN:
mWifiActivityIconId =R.drawable.stat_sys_wifi_in;
break;
…..省略代码....
}
//调用如下方法传递参数给1去刷新图标
refreshSignalCluster(cluster);
}
public voidrefreshSignalCluster(SignalCluster cluster) {
cluster.setWifiIndicators(mWifiEnabled && (mWifiConnected ||
!mHasMobileDataFeature || mAppOpsStrictEnabled), mWifiIconId,
mWifiActivityIconId, mContentDescriptionWifi);
}
到此处就可以实现上下行图标的刷新显示;那么 handleMessage中接收的消息又是哪里发出的呢?解释:3;
3、LINUX/android/frameworks/base/services/java/com/android/server/wifi/
WifiTrafficPoller.java
//根据流量的上行还是下行选择出图片并将消息发送出去
private void notifyOnDataActivity() {
//保存当前的上下行数据包的数量
long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
//通过如下的方法获取当前的上下行的数据包的数量
mTxPkts = TrafficStats.getTxPackets(mInterface);
mRxPkts = TrafficStats.getRxPackets(mInterface);
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;
}
…...省略代码......
//将消息发送出去
msg.what = WifiManager.DATA_ACTIVITY_NOTIFICATION;
msg.arg1 = mDataActivity;
client.send(msg);
}
}
其中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);
}
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");
剩下的就是对fp进行操作代码省略
}
那么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 =create_proc_entry(iface_stat_fmt_procfilename,
proc_iface_perms,
parent_procdir);
三、流程图