概述
20:12:08.774420 [20:12:03.149290] [000000002A1ADFB1] [wpa_s] wlan: [I :HDD] hdd_driver_command: Received COUNTRY CN cmd from Wi-Fi GUI***
20:12:08.774457 [20:12:03.149318] [000000002A1AE1BC] [wpa_s] wlan: [I :SME] sme_ChangeCountryCode: 5688: called
20:12:08.774490 [20:12:03.149334] [000000002A1AE2FD] [wpa_s] wlan: [I :SME] sme_ChangeCountryCode: 5728: returned
20:12:08.774520 [20:12:03.149476] [000000002A1AEDA0] [VosMC] wlan: [IH:VOS] vos_timer_stop: Timer Addr inside voss_stop : 0xbf3733d4
20:12:08.774550 [20:12:03.149494] [000000002A1AEF01] [VosMC] wlan: [I :WDA] <------ WDA_UpdateChReqCallback
20:12:08.774580 [20:12:03.149564] [000000002A1AF43B] [VosMC] wlan: [I :WDA] <------ WDA_UpdateScanParamsReqCallback, wdiStatus: 0
20:12:08.774609 [20:12:03.149574] [000000002A1AF4F8] [VosMC] wlan: [IH:VOS] Timer Addr inside voss_start : 0xbf3733d4
20:12:08.774639 [20:12:03.149598] [000000002A1AF6C1] [VosMC] wlan: [I :VOS] VosMCThread: Servicing the VOS SME MC Message queue
20:12:08.774668 [20:12:03.149616] [000000002A1AF819] [VosMC] wlan: [I :VOS] regdomain request
20:12:08.774943 [20:12:03.149624] [000000002A1AF8AB] [VosMC] wlan: [W :VOS] get country information from kernel db
20:12:08.774984 [20:12:03.443815] [000000002A71293C] [VosMC] wlan: [I :VOS] runtime country code : CN is found in kernel db
20:12:08.775014 [20:12:03.443894] [000000002A712F06] [wpa_s] wlan: [I :HDD] Exit:hdd_driver_command
20:12:08.775045 [20:12:03.443903] [000000002A712FA2] [VosMC] wlan: [IH:VOS] vos_timer_stop: Timer Addr inside voss_stop : 0xbf3733d4
20:12:08.775075 [20:12:03.443907] [000000002A712FE7] [wpa_s] wlan: [I :HDD] Exit:__hdd_ioctl
20:12:08.775106 [20:12:03.443920] [000000002A7130E9] [VosMC] wlan: [I :WDA] <------ WDA_UpdateScanParamsRespCallback
20:12:08.775136 [20:12:03.443937] [000000002A71322C] [VosMC] wlan: [IH:VOS] vos_list_remove_front: list empty
20:12:08.775165 [20:12:03.444199] [000000002A7145E2] [kwork] wlan: [I :VOS] cfg80211 reg notifier callback for country for initiator 1
20:12:08.775195 [20:12:03.444211] [000000002A7146B3] [kwork] wlan: [I :VOS] __wlan_hdd_linux_reg_notifier: Req initiator 1 CC=CN
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
不同国家,WIFI使用的信道是不同的,2.4G一共有14个信道,中国使用1-13信道,美国则使用1-11信道。因此,我们需要指定WIFI的国家码,来确定WIFI在扫描和连接过程中,可以在哪些信道上进行。
设置国家码有三种方法,我们逐一介绍:
1.通过设置prop设置
oem产商设置国家码在
device/qcom/msm8909w/system.prop
- 1
文件中设置一个prop就可以了。
ro.boot.wificountrycode=CN
- 1
设置好prop后,我们分析下国家码的设置过程。
在SystemServer起来后,会加载WifiServiceImpl,即WIFI服务。在WIFI服务中,将获取设置的WIFI国家码属性。并作为参数传给WifiStateMachine的构造函数中。
public WifiServiceImpl(Context context) {
mCountryCode = new WifiCountryCode(
WifiNative.getWlanNativeInterface(),
SystemProperties.get(BOOT_DEFAULT_WIFI_COUNTRY_CODE),
mFacade.getStringSetting(mContext, Settings.Global.WIFI_COUNTRY_CODE),
mContext.getResources().getBoolean(
R.bool.config_wifi_revert_country_code_on_cellular_loss));
mWifiStateMachine = new WifiStateMachine(mContext, mFacade,
wifiStateMachineThread.getLooper(), mUserManager, mWifiInjector,
new BackupManagerProxy(), mCountryCode);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
此处首先构造了WifiCountryCode对象,我们看构造方法:
public WifiCountryCode( WifiNative wifiNative, String oemDefaultCountryCode, String persistentCountryCode, boolean revertCountryCodeOnCellularLoss) {
mWifiNative = wifiNative; mRevertCountryCodeOnCellularLoss = revertCountryCodeOnCellularLoss; if (!TextUtils.isEmpty(persistentCountryCode)) { mDefaultCountryCode = persistentCountryCode.toUpperCase(); } else if (!TextUtils.isEmpty(oemDefaultCountryCode)) { mDefaultCountryCode = oemDefaultCountryCode.toUpperCase(); } else { if (mRevertCountryCodeOnCellularLoss) { Log.w(TAG, "config_wifi_revert_country_code_on_cellular_loss is set, " + "but there is no default country code."); mRevertCountryCodeOnCellularLoss = false; return; } } if (mRevertCountryCodeOnCellularLoss) { Log.d(TAG, "Country code will be reverted to " + mDefaultCountryCode + " on MCC loss"); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
oemDefaultCountryCode就是我们从属性设置的国家码。另外还有一个persistentCountryCode,这个是从设置中获取的国家码。从构造方法可以看到,从设置文件中取到的国家码如果存在,直接将其赋值给mDefaultCountryCode,否则将oemDefaultCountryCode赋值给mDefaultCountryCode。设置中的国家码优先级大于属性中的国家码。
mCountryCode传递给WifiStateMachine中。WifiStateMachine在wpa_supplicant启动起来后,取设置国家码。
public WifiStateMachine(Context context, FrameworkFacade facade, Looper looper, UserManager userManager, WifiInjector wifiInjector,
BackupManagerProxy backupManagerProxy,
WifiCountryCode countryCode) {
mCountryCode = countryCode;
}
class SupplicantStartedState extends State {
@Override
public void enter() {
/* Wifi is available as long as we have a connection to supplicant */
mNetworkInfo.setIsAvailable(true);
if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
int defaultInterval = mContext.getResources().getInteger(
R.integer.config_wifi_supplicant_scan_interval);
mCountryCode.setReadyForChange(true);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
此处mCountryCode.setReadyForChange()方法就是用来设置国家码的。我们大致看起实现方法:
public synchronized void setReadyForChange(boolean ready) {
if (DBG) Log.d(TAG, "Set ready: " + ready);
mReady = ready;
// We are ready to set country code now.
// We need to post pending country code request.
if (mReady) {
updateCountryCode();
}
}
private void updateCountryCode() {
String country = pickCountryCode();
if (country != null) {
setCountryCodeNative(country);
}
}
private String pickCountryCode() {
if (mTelephonyCountryCode != null) {
return mTelephonyCountryCode;
}
if (mDefaultCountryCode != null) {
return mDefaultCountryCode;
}
// If there is no candidate country code we will return null.
return null;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
在pickCountryCode中我们首先选择使用那个CountryCode,如果mTelephonyCountryCode有设置,就使用mTelephonyCountryCode对应的code。mTelephonyCountryCode在检测电话卡后,通过WifiManager设置进来的。不插卡时,mTelephonyCountryCode为null。如果不插卡,mTelephonyCountryCode不会被pick到,则会返回mDefaultCountryCode。mDefaultCountryCode在WifiCountryCode构造是传入的。mDefaultCountryCode被设置成设置值或者属性值。我们假设没有设置值,只有OEM的属性值。则此处pick到我们属性中设置的属性值。
在pick到国家码后,使用setCountryCodeNative进行设置。否则不做任何设置,不做设置是不插卡不在设置中设置国家码也没有属性的情况。属于第三种情况。
public boolean setCountryCode(String countryCode) {
if (countryCode != null)
return doBooleanCommand("DRIVER COUNTRY " + countryCode.toUpperCase(Locale.ROOT));
else
return doBooleanCommand("DRIVER COUNTRY");
}
- 1
- 2
- 3
- 4
- 5
- 6
"DRIVER COUNTRY"通过JNI传递给wpa_supplicant处理。
else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
reply_size);
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.driver_cmd = wpa_driver_nl80211_driver_cmd,
}
int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
size_t buf_len )
{
if ((ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) {
wpa_printf(MSG_ERROR, “%s: failed to issue private commandsn”, func);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
通过ioctl发送指令给驱动程序。驱动程序在对应ioctl中接收。
static struct net_device_ops wlan_drv_ops = {
.ndo_open = hdd_open,
.ndo_do_ioctl = hdd_ioctl,
}
int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
switch (cmd) {
case (SIOCDEVPRIVATE + 1):
if (is_compat_task())
ret = hdd_driver_compat_ioctl(pAdapter, ifr);
else
ret = hdd_driver_ioctl(pAdapter, ifr);
break;
}
static int hdd_driver_command(hdd_adapter_t *pAdapter,
hdd_priv_data_t *ppriv_data)
{
else if ( strncasecmp(command, “COUNTRY”, 7) == 0 )
{
char *country_code;
country_code = command + 8;
INIT_COMPLETION(pAdapter->change_country_code);
hdd_checkandupdate_dfssetting(pAdapter, country_code);
#ifndef CONFIG_ENABLE_LINUX_REG
hdd_checkandupdate_phymode(pAdapter, country_code);
#endif
ret = (int)sme_ChangeCountryCode(pHddCtx->hHal,
(void *)(tSmeChangeCountryCallback)
wlan_hdd_change_country_code_callback,
country_code, pAdapter, pHddCtx->pvosContext, eSIR_TRUE, eSIR_TRUE);
if (eHAL_STATUS_SUCCESS == ret)
{
ret = wait_for_completion_interruptible_timeout(
&pAdapter->change_country_code,
msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY));
if (0 >= ret)
{
hddLog(VOS_TRACE_LEVEL_ERROR, “%s: SME while setting country code timed out %d”,
func, ret);
}
}
else
{
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
“%s: SME Change Country code fail ret=%d”, func, ret);
ret = -EINVAL;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
sme_ChangeCountryCode函数将构造一个消息,消息中包括国家码信息,消息的队列ID,消息类型等内容,然后 将消息发送到VOSS中进一步处理。这正是高通驱动的消息基本处理方式。
@/device/qcom/common/opensource/wlan/prima/CORE/SME/src/sme_common/sme_Api.c eHalStatus sme_ChangeCountryCode( tHalHandle hHal, tSmeChangeCountryCallback callback, tANI_U8 *pCountry, void *pContext, void* pVosContext, tAniBool countryFromUserSpace, tAniBool sendRegHint ) { vos_msg_t msg; tAniChangeCountryCodeReq *pMsg;
5709 pMsg->msgType = pal_cpu_to_be16((tANI_U16)eWNI_SME_CHANGE_COUNTRY_CODE); pMsg = vos_mem_malloc(sizeof(tAniChangeCountryCodeReq)); pMsg->msgLen = (tANI_U16)sizeof(tAniChangeCountryCodeReq); vos_mem_copy(pMsg->countryCode, pCountry, 3); pMsg->countryFromUserSpace = countryFromUserSpace; pMsg->sendRegHint = sendRegHint; pMsg->changeCCCallback = callback; pMsg->pDevContext = pContext; pMsg->pVosContext = pVosContext; msg.type = eWNI_SME_CHANGE_COUNTRY_CODE; msg.bodyptr = pMsg; msg.reserved = 0; if(VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MQ_ID_SME, &msg)) return (status);
}
VOS_STATUS vos_mq_post_message( VOS_MQ_ID msgQueueId, vos_msg_t pMsg )
{
switch (msgQueueId)
{
case VOS_MQ_ID_SME:
{
pTargetMq = &(gpVosContext->vosSched.smeMcMq);
break;
}
}
pMsgWrapper = vos_mq_get(&gpVosContext->freeVosMq);
/
** Copy the message now
/
vos_mem_copy( (v_VOID_t)pMsgWrapper->pVosMsg,
(v_VOID_t*)pMsg, sizeof(vos_msg_t));
vos_mq_put(pTargetMq, pMsgWrapper);
set_bit(MC_POST_EVENT, &gpVosContext->vosSched.mcEventFlag);
wake_up_interruptible(&gpVosContext->vosSched.mcWaitQueue);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
将消息拷贝到MsgWrapper->pVosMsg中,然后唤醒vosSched.mcWaitQueue。我们直接进入mcWaitQueue这个等待队列看唤醒后的操作。
eHalStatus sme_ProcessMsg(tHalHandle hHal, vos_msg_t* pMsg)
{
case eWNI_SME_CHANGE_COUNTRY_CODE:
if(pMsg->bodyptr)
{
status = sme_HandleChangeCountryCode((void *)pMac, pMsg->bodyptr);
vos_mem_free(pMsg->bodyptr);
}
break;
}
eHalStatus sme_HandleChangeCountryCode(tpAniSirGlobal pMac, void *pMsgBuf)
{
v_REGDOMAIN_t domainIdIoctl;
static uNvTables nvTables;
pMsg = (tAniChangeCountryCodeReq *)pMsgBuf;
/* Set Current Country code and Current Regulatory domain */
status = csrSetCountryCode(pMac, pMsg->countryCode, NULL);
/* overwrite the defualt country code */
vos_mem_copy(pMac->scan.countryCodeDefault,
pMac->scan.countryCodeCurrent,
WNI_CFG_COUNTRY_CODE_LEN);
/* Get Domain ID from country code */
status = csrGetRegulatoryDomainForCountry(pMac,
pMac->scan.countryCodeCurrent,
(v_REGDOMAIN_t *) &domainIdIoctl,
COUNTRY_QUERY);
status = WDA_SetRegDomain(pMac, domainIdIoctl, pMsg->sendRegHint);
/* get the channels based on new cc */
status = csrInitGetChannels( pMac );
/* reset info based on new cc, and we are done */
csrResetCountryInformation(pMac, eANI_BOOLEAN_TRUE, eANI_BOOLEAN_TRUE);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
sme_HandleChangeCountryCode设置好国家码,并通过国家码重新设置scan的信道。文章开始的log就是这里打印处理的。
2.通过WifiManager提供的结构设置
在安装上电话卡,Android设备可以从电话卡找到位置信息。然后会自动设置国家码。
private static void setWifiCountryCodeFromMcc(Context context, int mcc) {
String country = MccTable.countryCodeForMcc(mcc);
Slog.d(LOG_TAG, "WIFI_COUNTRY_CODE set to " + country);
WifiManager wM = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wM.setCountryCode(country, false);
}
- 1
- 2
- 3
- 4
- 5
- 6
这里通过WifiManager来设置国家码。参数中除了国家码外,还有一个是否固化国家码的boolean类型参数。固化为ture,我们就会把国家码写入到设置中固化下来,以后优先使用该国家码。我们这里不会固化。
public void setCountryCode(String countryCode, boolean persist) {
Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
" with persist set to " + persist);
enforceConnectivityInternalPermission();
final long token = Binder.clearCallingIdentity();
try {
if (mCountryCode.setCountryCode(countryCode, persist) && persist) {
// Save this country code to persistent storage
mFacade.setStringSetting(mContext,
Settings.Global.WIFI_COUNTRY_CODE,
countryCode);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
这里的countryCode将被吸入到mTelephonyCountryCode。前面已经提过,TelephonyCountryCode优先级高于mDefaultCountryCode。
public synchronized boolean setCountryCode(String countryCode, boolean persist) {
if (DBG) Log.d(TAG, "Receive set country code request: " + countryCode);
// Ignore empty country code.
if (TextUtils.isEmpty(countryCode)) {
if (DBG) Log.d(TAG, "Ignore empty country code");
return false;
}
if (persist) {
mDefaultCountryCode = countryCode;
}
mTelephonyCountryCode = countryCode.toUpperCase();
// If wpa_supplicant is ready we set the country code now, otherwise it will be
// set once wpa_supplicant is ready.
if (mReady) {
updateCountryCode();
}
return true;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
剩下的内容updateCountryCode和1中设置方法相同了。
3.从扫描结果过去国家码
如果Android设备没有设置国家码prop,也没有插卡,则开机后设备是没有国家码的,这个时候将从扫描的WIFI结果中,寻找国家信息,自动设定一个国家码。这样设置可能会有误。
驱动中打印的log如下:
17:32:05.033088 [17:32:04.731383] [000000007E40829B] [VosMC] wlan: [I :SME] Scan received 3 unique BSS scan reason is 9
17:32:05.033129 [17:32:04.731430] [000000007E408625] [VosMC] wlan: [W :SME] csrMoveTempScanResultsToMainList: 3250: 11d AP Bssid 00:35:1a:db:f7:02 chan= 8, rssi = -63, countryCode CN
17:32:05.033171 [17:32:04.731474] [000000007E408978] [VosMC] wlan: [W :SME] csrMoveTempScanResultsToMainList: 3250: 11d AP Bssid 00:35:1a:db:f7:00 chan= 8, rssi = -63, countryCode CN
17:32:05.033211 [17:32:04.731510] [000000007E408C1A] [VosMC] wlan: [I :SME] Selected Country is CN With count 2
17:32:05.033283 [17:32:04.731521] [000000007E408CEE] [VosMC] wlan: [I :VOS] regdomain request
17:32:05.033323 [17:32:04.731528] [000000007E408D7F] [VosMC] wlan: [W :VOS] get country information from kernel db
17:32:05.033363 [17:32:04.731776] [000000007E40A023] [kwork] wlan: [I :VOS] cfg80211 reg notifier callback for country for initiator 1
17:32:05.033403 [17:32:04.731788] [000000007E40A101] [kwork] wlan: [I :VOS] __wlan_hdd_linux_reg_notifier: Req initiator 1 CC=CN
17:32:05.033443 [17:32:05.022912] [000000007E95EB75] [VosMC] wlan: [I :VOS] runtime country code : CN is found in kernel db
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
基本调用流程就是从扫描结果中选取一个国家码,如果扫描结果中只有一个国家码,就设置这个国家码,如果有多个,就随机选择一个。
csrScanComplete
csrSaveScanResults
csrMoveTempScanResultsToMainList
csrElectedCountryInfo(pMac);
csrLearnCountryInformation( pMac, NULL, NULL, eANI_BOOLEAN_TRUE );
- 1
- 2
- 3
- 4
- 5
在csrElectedCountryInfo中选择国家码,在csrLearnCountryInformation设置国家码。
tANI_BOOLEAN csrLearnCountryInformation( tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc,tDot11fBeaconIEs *pIes, tANI_BOOLEAN fForce) { if (eANI_BOOLEAN_FALSE == useVoting) pCountryCodeSelected = pIesLocal->Country.country; else pCountryCodeSelected = pMac->scan.countryCodeElected;
status = csrGetRegulatoryDomainForCountry(pMac, pCountryCodeSelected, &domainId, COUNTRY_IE); /* updating 11d Country Code with Country code selected. */ vos_mem_copy(pMac->scan.countryCode11d, pCountryCodeSelected, WNI_CFG_COUNTRY_CODE_LEN);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
在__wlan_hdd_linux_reg_notifier()方法中设置通过从scan结果选择的国家码。
通常为了保证能够正确指定扫描的信道,需要OEM产商在porp中设置国家码,防止出现国家码设置异常,扫描不到某些热点的情况。
</div>
最后
以上就是激动马里奥为你收集整理的[转载]高通Android7.1 WIFI国家码问题的全部内容,希望文章能够帮你解决[转载]高通Android7.1 WIFI国家码问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复