android 와이파이 이식statusbar 신호가 한 칸만 표시되는 문제

12849 단어
와이파이를 이식한 후에 statusbar에서 신호가 항상 한 칸만 보입니다. 이 문제는 여러 해 동안 만났습니다. 최근에 프로젝트를 진행하면서 이것을 수정해야 하기 때문에 해결해야 합니다. 일주일 넘게 연구한 끝에 해결되었습니다. 아직 잘 모르겠지만 대체적으로 말씀드리지만 이 문제에 부딪힌 형제에게 도움이 되었으면 합니다. 잘못 쓴 부분은 많이 지적해 주십시오.사실 나도 조금밖에 모른다.
처음에 나는 줄곧 프레임워크의 문제라고 의심했기 때문에 오랫동안 프레임워크를 연구했다.관련 코드는 아래 디렉터리에 있습니다 (android2.3)
statusbar 소스는 프레임워크/base/packages/SystemUI/src/com/android/systemui/statusbar에서
설정 중인 와이파이 부분 원본은packages/apps/Settings/src/com/android/settings/wifi에 있습니다
내가 발생한 문제는 이렇다. 와이파이가 연결된 후statusbar 위의 와이파이 신호는 항상 한 칸만 보이고 setting 안의 와이파이 신호는 때로는 한 칸을 보이고 때로는 정상적인 것을 나타낸다. 다음은 전체 과정을 간단하게 설명한다.
statusbar 원본 디렉터리에 StatusBarPolicy가 있습니다.java 파일에서 업데이트Connectivity 함수를 찾았습니다. 다음 코드를 보십시오.
        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;
이것은 와이파이의 연결 후의 처리 과정이다. 전체 과정은 말하기 어렵다. 나는 이 곳을 말한다. 와이파이 연결이 성공하면 mLast 와이파이 시그널 Level이 초기화되었기 때문이다. 예를 들어 -1이다.
mLastWifiSignal Level은 신호의 강도를 바꾸지 않으면 한 칸만 표시됩니다. 와이파이 신호에 연결되지 않으면 아이콘이 보이지 않습니다.mService.setIconVisibility("wifi
, false). 아이콘을 보이지 않는 상태로 설정합니다.
그럼 mLast Wifi Signal Level은 어디에서 바뀔까요? 업데이트 Wifi라는 함수를 찾았는데 그 안에 이런 코드가 있습니다.
 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);
            }
        }
이게 바뀔 거예요.
mLastWifi Signal Level은 와이파이 신호 아이콘도 업데이트합니다.
업데이트와이파이는 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);
            }
이 세 개의 방송이 있을 때만 업데이트 와이파이를 실행한다. 즉, RSSICHANGED_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.
", cmd); return -1; } ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL); if (ret == -2) { LOGD("'%s' command timed out.
", 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/wpasupplicant에서 HAL 레이어에 명령을 보내는 것은 driverwext.c의 wpadriver_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 "
", 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
", 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
", 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
", (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와setting의 신호가 모두 정상적으로 나타났다.아직 분명하게 말하지 못한 부분이 있어서 틈이 나면 연구하고 있다.

좋은 웹페이지 즐겨찾기