Android O CellLocation通知流程

CellLocation,即小区位置。它保存了设备当前所处网络的位置,对于不同的接入技术,其用来描述CellLocation的参数略有不同。  
 

3GPP:  
包含LAC(Location Area Code/位置区域码)、CID(Cell ID/小区ID)、PSC(Primary Scrambling Code/主扰码),  
其中PSC是UMTS专有的,  
另外,由于LTE中已不再使用LAC/RAC,取而代之的是TAC,因此在GsmCellLocation中直接把其TAC的值作为LAC来保存。  
一般来讲,一个位置区包含多个基站,一个基站对应一个或多个扇区,而一个扇区对应一个小区,但有时一个小区也可能由多个扇区组成。  

3GPP2:  
包含SID(System ID/系统ID)、NID(Network ID/网络ID)、BID(Base station ID/基站ID)、BS Longitude(基站经度)、BS Latitude(基站纬度),  
一个System下面包含多个Network,而一个Network下面又有多个BS。  

当查询voice注册状态时,返回的结果中就包含了CellLocation相关信息。  
我们直接来看ServiceStateTracker中查询voice注册状态的地方,有如下2个: 

public void handleMessage(Message msg) {
        ......
        case EVENT_LOCATION_UPDATES_ENABLED:
            ar = (AsyncResult) msg.obj;

            if (ar.exception == null) {
                mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE, null));
            }
            break;
        ......
}

public void pollState(boolean modemTriggered) {
            ......
            mCi.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION,
                    mPollingContext));
            ......
}

先来看第一个,通过RIL返回查询结果后触发EVENT_GET_LOC_DONE消息,然后就直接通过Phone往上通知CellLocation改变。  

public void handleMessage(Message msg) {
        ......
        case EVENT_GET_LOC_DONE:
            ar = (AsyncResult) msg.obj;
            if (ar.exception == null) {
                processCellLocationInfo(mCellLoc, (VoiceRegStateResult) ar.result);
                mPhone.notifyLocationChanged();
            }
        ......
}

再来看第二个查询voice注册状态的返回处理流程,触发EVENT_POLL_STATE_REGISTRATION消息,  

public void handleMessage(Message msg) {
        ......
        case EVENT_POLL_STATE_REGISTRATION:
        ......
            handlePollStateResult(msg.what, ar);
        ......
}

处理查询结果,  

protected void handlePollStateResult(int what, AsyncResult ar) {
    ......
    if (ar.exception != null) {
        ......
    } else try {
        handlePollStateResultMessage(what, ar);
    } catch (RuntimeException ex) {
        ......
    }

    mPollingContext[0]--;

    if (mPollingContext[0] == 0) {
        ......
        pollStateDone();
    }

}

会先调用handlePollStateResultMessage()更新查询结果,  

void handlePollStateResultMessage(int what, AsyncResult ar) {
    int ints[];
    switch (what) {
        case EVENT_POLL_STATE_REGISTRATION: {
            ......
            processCellLocationInfo(mNewCellLoc, voiceRegStateResult);
        ......
}

根据不同接入技术获取相应的CellLocation参数,并将结果更新到ServiceStateTracker.mNewCellLoc中。

private void processCellLocationInfo(CellLocation cellLocation,
                                     VoiceRegStateResult voiceRegStateResult) {
    if (mPhone.isPhoneTypeGsm()) {
        ......
        switch(voiceRegStateResult.cellIdentity.cellInfoType) {
            case CellInfoType.GSM: {
                if (voiceRegStateResult.cellIdentity.cellIdentityGsm.size() == 1) {
                    android.hardware.radio.V1_0.CellIdentityGsm cellIdentityGsm =
                            voiceRegStateResult.cellIdentity.cellIdentityGsm.get(0);
                    cid = cellIdentityGsm.cid;
                    lac = cellIdentityGsm.lac;
                }
                break;
            }
            case CellInfoType.WCDMA: {
                if (voiceRegStateResult.cellIdentity.cellIdentityWcdma.size() == 1) {
                    android.hardware.radio.V1_0.CellIdentityWcdma cellIdentityWcdma =
                            voiceRegStateResult.cellIdentity.cellIdentityWcdma.get(0);
                    cid = cellIdentityWcdma.cid;
                    lac = cellIdentityWcdma.lac;
                    psc = cellIdentityWcdma.psc;
                }
                break;
            }
            case CellInfoType.TD_SCDMA: {
                if (voiceRegStateResult.cellIdentity.cellIdentityTdscdma.size() == 1) {
                    android.hardware.radio.V1_0.CellIdentityTdscdma
                            cellIdentityTdscdma =
                            voiceRegStateResult.cellIdentity.cellIdentityTdscdma.get(0);
                    cid = cellIdentityTdscdma.cid;
                    lac = cellIdentityTdscdma.lac;
                }
                break;
            }
            case CellInfoType.LTE: {
                if (voiceRegStateResult.cellIdentity.cellIdentityLte.size() == 1) {
                    android.hardware.radio.V1_0.CellIdentityLte cellIdentityLte =
                            voiceRegStateResult.cellIdentity.cellIdentityLte.get(0);
                    cid = cellIdentityLte.ci;

                    /* Continuing the historical behaviour of using tac as lac. */
                    lac = cellIdentityLte.tac;
                }
                break;
            }
            default: {
                break;
            }
        }
        // LAC and CID are -1 if not avail
        ((GsmCellLocation) cellLocation).setLacAndCid(lac, cid);
        ((GsmCellLocation) cellLocation).setPsc(psc);
    } else {
        ......
        switch(voiceRegStateResult.cellIdentity.cellInfoType) {
            case CellInfoType.CDMA: {
                if (voiceRegStateResult.cellIdentity.cellIdentityCdma.size() == 1) {
                    android.hardware.radio.V1_0.CellIdentityCdma cellIdentityCdma =
                            voiceRegStateResult.cellIdentity.cellIdentityCdma.get(0);
                    baseStationId = cellIdentityCdma.baseStationId;
                    baseStationLatitude = cellIdentityCdma.latitude;
                    baseStationLongitude = cellIdentityCdma.longitude;
                    systemId = cellIdentityCdma.systemId;
                    networkId = cellIdentityCdma.networkId;
                }
                break;
            }
            default: {
                break;
            }
        }
        ......
        ((CdmaCellLocation) cellLocation).setCellLocationData(baseStationId,
                baseStationLatitude, baseStationLongitude, systemId, networkId);
    }
}

再回到handlePollStateResult()中,更新完查询结果后继续调用pollStateDone(),  

如果CellLocation和当前值不同,那就通过Phone发送通知,  
这就与最开始处理EVENT_GET_LOC_DONE的流程相同了。  

private void pollStateDone() {
    ......
    boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
    ......
    if (hasLocationChanged) {
        mPhone.notifyLocationChanged();
    }
    ......
}

GsmCdmaPhone中没有任何额外处理,继续向上通知。  

public void notifyLocationChanged() {
    mNotifier.notifyCellLocation(this);
}

然后来到DefaultPhoneNotifier中,继续通知TelephonyRegistry,  

public void notifyCellLocation(Phone sender) {
    ......
            mRegistry.notifyCellLocationForSubscriber(subId, data);
    ......
}

然后就在TelephonyRegistry中查询注册了LISTEN_CELL_LOCATION的对象,并进行回调。  

public void notifyCellLocationForSubscriber(int subId, Bundle cellLocation) {
    ......
            for (Record r : mRecords) {
                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
                        idMatch(r.subId, subId, phoneId)) {
                        ......
                        r.callback.onCellLocationChanged(new Bundle(cellLocation));
    ......
}

通过搜索代码,发现共有如下2个地方注册监听了LISTEN_CELL_LOCATION事件。  
一个是和紧急呼叫相关的,在手机启动及关闭飞行模式时进行监听。  
EmergencyAffordanceService.java  

public void onBootPhase(int phase) {
    ......
        startScanning();
    ......
}

private BroadcastReceiver mAirplaneModeReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Settings.Global.getInt(context.getContentResolver(),
                Settings.Global.AIRPLANE_MODE_ON, 0) == 0) {
            startScanning();
            requestCellScan();
        }
    }
};

private void startScanning() {
    mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_INFO
            | PhoneStateListener.LISTEN_CELL_LOCATION);
}

另一个就是在Settings中,  
RadioInfo.java  

protected void onResume() {
    ......
    mTelephonyManager.listen(mPhoneStateListener,
              ......
            | PhoneStateListener.LISTEN_CELL_LOCATION
            ......);
    ......
}
 
 
G
M
T
 
 
Detect languageAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBengaliBosnianBulgarianCatalanCebuanoChichewaChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEsperantoEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekGujaratiHaitian CreoleHausaHebrewHindiHmongHungarianIcelandicIgboIndonesianIrishItalianJapaneseJavaneseKannadaKazakhKhmerKoreanLaoLatinLatvianLithuanianMacedonianMalagasyMalayMalayalamMalteseMaoriMarathiMongolianMyanmar (Burmese)NepaliNorwegianPersianPolishPortuguesePunjabiRomanianRussianSerbianSesothoSinhalaSlovakSlovenianSomaliSpanishSundaneseSwahiliSwedishTajikTamilTeluguThaiTurkishUkrainianUrduUzbekVietnameseWelshYiddishYorubaZulu
 
AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBengaliBosnianBulgarianCatalanCebuanoChichewaChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEsperantoEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekGujaratiHaitian CreoleHausaHebrewHindiHmongHungarianIcelandicIgboIndonesianIrishItalianJapaneseJavaneseKannadaKazakhKhmerKoreanLaoLatinLatvianLithuanianMacedonianMalagasyMalayMalayalamMalteseMaoriMarathiMongolianMyanmar (Burmese)NepaliNorwegianPersianPolishPortuguesePunjabiRomanianRussianSerbianSesothoSinhalaSlovakSlovenianSomaliSpanishSundaneseSwahiliSwedishTajikTamilTeluguThaiTurkishUkrainianUrduUzbekVietnameseWelshYiddishYorubaZulu
 
 
 
 
 
 
 
 
 
Text-to-speech function is limited to 200 characters
 
 
Options : History : Feedback : Donate Close

猜你喜欢

转载自my.oschina.net/igiantpanda/blog/1627463
今日推荐