android移植wifi后,在statusbar上信号老是只显示一格,这个问题碰到好多久了,由于最近做项目要修改这个,所以要解决,研究了一个多星期终于解决了,虽然还没有怎么弄懂,但是大致的说一下,希望对碰到这个问题的兄弟有帮助,写的不对的地方请大家多多指点,其实我也只有一点懂。
最开始我一直怀疑是framework的问题,所以研究了好久的framework。相关代码在如下目录(android2.3)
statusbar源码在framework/base/packages/SystemUI/src/com/android/systemui/statusbar中
设置中的wifi部分源码在packages/apps/Settings/src/com/android/settings/wifi中
我出现的问题是这样的,当wifi连接上后statusbar上面的wifi信号老是只显示一格,而setting里面的wifi信号有时候显示一格,有时候显示又是正常的,下面简单说下整个过程.
在statusbar源码目录中有一个StatusBarPolicy.java的文件,找到updateConnectivity函数,请看如下代码:
case ConnectivityManager.TYPE_WIFI:
mInetCondition = inetCondition;
if (info.isConnected()) {
mIsWifiConnected = true;
int iconId;
if (mLastWifiSignalLevel == -1) {
iconId = sWifiSignalImages[mInetCondition][0];
} else {
iconId = sWifiSignalImages[mInetCondition][mLastWifiSignalLevel];
}
mService.setIcon("wifi", iconId, 0);
// Show the icon since wi-fi is connected
mService.setIconVisibility("wifi", true);
} else {
mLastWifiSignalLevel = -1;
mIsWifiConnected = false;
int iconId = sWifiSignalImages[0][0];
mService.setIcon("wifi", iconId, 0);
// Hide the icon since we're not connected
mService.setIconVisibility("wifi", false);
}
updateSignalStrength(); // apply any change in mInetCondition
break;
这是wifi的连接上后的一个处理过程,整个过程就不好讲了,我就说下这个地方,当wifi连接成功因为mLastWifiSignalLevel初始化是-1,如
mLastWifiSignalLevel没有发生变化信号强度就只会显示一格,如果没有连接上wifi信号显示图标是不可见的。mService.setIconVisibility("wifi
", false);这个将图标设置为不可见状态。
那mLastWifiSignalLevel在哪里会变化了,我们找到updateWifi这个函数,里面有这样一段代码:
else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
int iconId;
final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
sWifiSignalImages[0].length);
if (newSignalLevel != mLastWifiSignalLevel) {
mLastWifiSignalLevel = newSignalLevel;
if (mIsWifiConnected) {
iconId = sWifiSignalImages[mInetCondition][newSignalLevel];
} else {
iconId = sWifiTemporarilyNotConnectedImage;
}
mService.setIcon("wifi", iconId, 0);
}
}
这个会改变
mLastWifiSignalLevel同时也会更新wifi信号图标.
而updateWifi就是在onReceive里被调用,代码如下:
else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
updateWifi(intent);
}
当有这三个广播的时候才会执行updateWifi,就是说当有RSSI_CHANGED_ACTION时,信号显示图标才会发生变化,但是我把打印信息打开发现,没有这个广播产生。所以我又想到会不会是HAL层的问题,于是我又看了下HAL层,基本函数是差不多的,主要返回的相关信息应该是在这个函数里面:
int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)
{
int ret;
if (ctrl_conn == NULL) {
LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
return -1;
}
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);
if (ret == -2) {
LOGD("'%s' command timed out.\n", cmd);
return -2;
} else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
return -1;
}
if (strncmp(cmd, "PING", 4) == 0) {
reply[*reply_len] = '\0';
}
return 0;
}
加上打印信息,发现wpa根本就没有发生获取信号的命令,问题终于找到了。
wpa的源码在external/wpa_supplicant中发送命令给HAL层是在driver_wext.c中的wpa_driver_priv_driver_cmd函数中,具体修改如下:
sdio 8686将此函数修改为:
static int wpa_driver_priv_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len)
{
struct wpa_driver_wext_data *drv = priv;
int ret = -1;
wpa_printf(MSG_DEBUG, "%s %s", __func__, cmd);
if (os_strcasecmp(cmd, "start") == 0) {
wpa_printf(MSG_DEBUG,"Start command");
return (ret);
}
if (os_strcasecmp(cmd, "stop") == 0) {
wpa_printf(MSG_DEBUG,"Stop command");
}
else if (os_strcasecmp(cmd, "macaddr") == 0) {
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
os_strncpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) < 0) {
perror("ioctl[SIOCGIFHWADDR]");
ret = -1;
} else {
u8 *macaddr = (u8 *) ifr.ifr_hwaddr.sa_data;
ret = snprintf(buf, buf_len, "Macaddr = " MACSTR "\n",
MAC2STR(macaddr));
}
}
else if (os_strcasecmp(cmd, "scan-passive") == 0) {
wpa_printf(MSG_DEBUG,"Scan Passive command");
}
else if (os_strcasecmp(cmd, "scan-active") == 0) {
wpa_printf(MSG_DEBUG,"Scan Active command");
}
else if (os_strcasecmp(cmd, "linkspeed") == 0) {
wpa_printf(MSG_DEBUG,"Link Speed command");
}
else if (os_strncasecmp(cmd, "scan-channels", 13) == 0) {
}
#if 0 //add by dao
else if (os_strcasecmp(cmd, "rssi") == 0) {
#else
else if ((os_strcasecmp(cmd, "rssi") == 0) || (os_strcasecmp(cmd, "rssi-approx") == 0)){
#endif
struct iwreq wrq;
struct iw_statistics stats;
signed int rssi;
wrq.u.data.pointer = (caddr_t) &stats;
wrq.u.data.length = sizeof(stats);
wrq.u.data.flags = 1; /* Clear updated flag */
strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &wrq) < 0) {
perror("ioctl[SIOCGIWSTATS]");
ret = -1;
} else {
#if 0 //add by dao
stats.qual.updated |= IW_QUAL_DBM;
#endif
if (stats.qual.updated & IW_QUAL_DBM) {
/* Values in dBm, stored in u8 with range 63 : -192 */
rssi = ( stats.qual.level > 63 ) ?
stats.qual.level - 0x100 :
stats.qual.level;
} else {
rssi = stats.qual.level;
}
if (drv->ssid_len != 0 && drv->ssid_len < buf_len) {
os_memcpy((void *) buf, (void *) (drv->ssid),
drv->ssid_len );
ret = drv->ssid_len;
ret += snprintf(&buf[ret], buf_len-ret,
" rssi %d\n", rssi);
if (ret < (int)buf_len) {
return( ret );
}
ret = -1;
}
}
}
else if (os_strncasecmp(cmd, "powermode", 9) == 0) {
}
else if (os_strncasecmp(cmd, "getpower", 8) == 0) {
}
else if (os_strncasecmp(cmd, "get-rts-threshold", 17) == 0) {
struct iwreq wrq;
unsigned int rtsThreshold;
strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &wrq) < 0) {
perror("ioctl[SIOCGIWRTS]");
ret = -1;
} else {
rtsThreshold = wrq.u.rts.value;
wpa_printf(MSG_DEBUG,"Get RTS Threshold command = %d",
rtsThreshold);
ret = snprintf(buf, buf_len, "rts-threshold = %u\n",
rtsThreshold);
if (ret < (int)buf_len) {
return( ret );
}
}
}
else if (os_strncasecmp(cmd, "set-rts-threshold", 17) == 0) {
struct iwreq wrq;
unsigned int rtsThreshold;
char *cp = cmd + 17;
char *endp;
strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ);
if (*cp != '\0') {
rtsThreshold = (unsigned int)strtol(cp, &endp, 0);
if (endp != cp) {
wrq.u.rts.value = rtsThreshold;
wrq.u.rts.fixed = 1;
wrq.u.rts.disabled = 0;
if (ioctl(drv->ioctl_sock, SIOCSIWRTS, &wrq) < 0) {
perror("ioctl[SIOCGIWRTS]");
ret = -1;
} else {
rtsThreshold = wrq.u.rts.value;
wpa_printf(MSG_DEBUG,"Set RTS Threshold command = %d", rtsThreshold);
ret = 0;
}
}
}
}
else if (os_strcasecmp(cmd, "btcoexscan-start") == 0) {
}
else if (os_strcasecmp(cmd, "btcoexscan-stop") == 0) {
}
else if (os_strcasecmp(cmd, "rxfilter-start") == 0) {
wpa_printf(MSG_DEBUG,"Rx Data Filter Start command");
}
else if (os_strcasecmp(cmd, "rxfilter-stop") == 0) {
wpa_printf(MSG_DEBUG,"Rx Data Filter Stop command");
}
else if (os_strcasecmp(cmd, "rxfilter-statistics") == 0) {
}
else if (os_strncasecmp(cmd, "rxfilter-add", 12) == 0 ) {
}
else if (os_strncasecmp(cmd, "rxfilter-remove",15) == 0) {
}
else if (os_strcasecmp(cmd, "snr") == 0) {
struct iwreq wrq;
struct iw_statistics stats;
int snr, rssi, noise;
wrq.u.data.pointer = (caddr_t) &stats;
wrq.u.data.length = sizeof(stats);
wrq.u.data.flags = 1; /* Clear updated flag */
strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &wrq) < 0) {
perror("ioctl[SIOCGIWSTATS]");
ret = -1;
} else {
stats.qual.updated |= IW_QUAL_DBM;
if (stats.qual.updated & IW_QUAL_DBM) {
/* Values in dBm, stored in u8 with range 63 : -192 */
rssi = ( stats.qual.level > 63 ) ?
stats.qual.level - 0x100 :
stats.qual.level;
noise = ( stats.qual.noise > 63 ) ?
stats.qual.noise - 0x100 :
stats.qual.noise;
} else {
rssi = stats.qual.level;
noise = stats.qual.noise;
}
snr = rssi - noise;
ret = snprintf(buf, buf_len, "snr = %u\n", (unsigned int)snr);
if (ret < (int)buf_len) {
return( ret );
}
}
}
else if (os_strncasecmp(cmd, "btcoexmode", 10) == 0) {
}
else if( os_strcasecmp(cmd, "btcoexstat") == 0 ) {
}
else {
wpa_printf(MSG_DEBUG,"Unsupported command");
}
return (ret);
}
rtl8192cu修改为如下:
static int wpa_driver_priv_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len)
{
struct wpa_driver_wext_data *drv = priv;
struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx);
struct iwreq iwr;
int ret = 0, flags;
wpa_printf(MSG_DEBUG, "%s %s len = %d", __func__, cmd, buf_len);
if (os_strcasecmp(cmd, "RSSI-APPROX") == 0) {
os_strncpy(cmd, "RSSI", MAX_DRV_CMD_SIZE);
}
else if( os_strncasecmp(cmd, "SCAN-CHANNELS", 13) == 0 ) {
int no_of_chan;
no_of_chan = atoi(cmd + 13);
os_snprintf(cmd, MAX_DRV_CMD_SIZE, "COUNTRY %s",
wpa_driver_get_country_code(no_of_chan));
}
else if (os_strcasecmp(cmd, "STOP") == 0) {
if ((wpa_driver_wext_get_ifflags(drv, &flags) == 0) &&
(flags & IFF_UP)) {
wpa_printf(MSG_ERROR, "WEXT: %s when iface is UP", cmd);
wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
}
}
else if( os_strcasecmp(cmd, "RELOAD") == 0 ) {
wpa_printf(MSG_DEBUG,"Reload command");
wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
return ret;
}
os_memset(&iwr, 0, sizeof(iwr));
os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
os_memcpy(buf, cmd, strlen(cmd) + 1);
iwr.u.data.pointer = buf;
iwr.u.data.length = buf_len;
if ((ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr)) < 0) {
perror("ioctl[SIOCSIWPRIV]");
}
if (ret < 0) {
wpa_printf(MSG_ERROR, "%s failed", __func__);
drv->errors++;
if (drv->errors > WEXT_NUMBER_SEQUENTIAL_ERRORS) {
drv->errors = 0;
wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
}
}
else {
drv->errors = 0;
ret = 0;
if ((os_strcasecmp(cmd, "RSSI") == 0) ||
(os_strcasecmp(cmd, "LINKSPEED") == 0) ||
(os_strcasecmp(cmd, "MACADDR") == 0)) {
ret = strlen(buf);
}
/* else if (os_strcasecmp(cmd, "START") == 0) {
os_sleep(0, WPA_DRIVER_WEXT_WAIT_US);
wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
}
else if (os_strcasecmp(cmd, "STOP") == 0) {
wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
}*/
wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf));
}
return ret;
}
重新编译wpa后,安装系统,结果正常,statusbar与settting中的信号显示都正常了。还有一些没有说清楚的地方,有空在研究。