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中的信号显示都正常了。还有一些没有说清楚的地方,有空在研究。