資料業務建立流程之APN引數的啟用(原)
阿新 • • 發佈:2019-02-04
APN引數在前面《資料業務建立流程之常規APN引數的建立》一文中已經都被建立完畢並存入mAllApnSettings的陣列中,但是這些APN引數預設都是沒有被Enable的,只有當APN被Enable之後,該APN才可以被使用,下面我們就來看如何將一個APN引數啟用。
APN的Enable是通過TelephonyNetworkFactory中的needNetworkFor()方法觸發的,我們在《網路連線評分機制之NetworkFactory》文章中介紹過,噹噹前網路的評分比其他網路高時,就會通過needNetworkFor()方法觸發當前網路的建立。比如當前WIFI斷開時,如果發現數據網路是開啟的,此時就會通過該方法啟用資料流量,從而實現從WIFI到資料的轉換過程。
而當needNetworkFor()被觸發時,就會引發APN的Enable過程:
APN的Enable是通過TelephonyNetworkFactory中的needNetworkFor()方法觸發的,我們在《網路連線評分機制之NetworkFactory》文章中介紹過,噹噹前網路的評分比其他網路高時,就會通過needNetworkFor()方法觸發當前網路的建立。比如當前WIFI斷開時,如果發現數據網路是開啟的,此時就會通過該方法啟用資料流量,從而實現從WIFI到資料的轉換過程。
而當needNetworkFor()被觸發時,就會引發APN的Enable過程:
由於不同網路需求可能需要不同的APN引數,因此先要經過apnContextForNetworkRequest()來尋找合適的APN,對於上網來說,其尋找到的APN型別為TYPE_MOBILE,然後通過incRefCount()來Enable當前的APN:protected void needNetworkFor(NetworkRequest networkRequest, int score) { //根據網路需求尋找合適APN ApnContext apnContext = apnContextForNetworkRequest(networkRequest); //Enable上網用的APN if (apnContext != null) apnContext.incRefCount(); }
這裡需要用到DcTracker父類DcTrackerBase中的setEnabled()方法來將APN開啟:@ApnContext.java public void incRefCount() { synchronized (mRefCountLock) { if (mRefCount++ == 0) { //設定Enable mDcTracker.setEnabled(mDcTracker.apnTypeToId(mApnType), true); } } }
這裡傳送了一條EVENT_ENABLE_NEW_APN的訊息,該訊息將會在DcTrackerBase中handleMessage()中被處理:@DcTrackerBase.java protected void setEnabled(int id, boolean enable) { Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN); msg.arg1 = id; msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED); sendMessage(msg); }
@DcTrackerBase.java
public void handleMessage(Message msg) {
switch (msg.what) {
case DctConstants.EVENT_ENABLE_NEW_APN:
onEnableApn(msg.arg1, msg.arg2);
break;
}
}
這裡的onEnableApn()在子類DcTracker中被覆蓋: @DcTracker.java
protected void onEnableApn(int apnId, int enabled) {
ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
if (apnContext == null) {
loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
return;
}
//開啟APN
applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet());
}
繼續看applyNewState()過程,這裡傳遞的第二個引數為true,第二個引數是從networkAttributes陣列中讀取的,預設都為true。 private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
boolean cleanup = false;
boolean trySetup = false;
if (apnContext.isReady()) {
//APN如果已經被Enable
} else {
if (enabled && met) {
//APN需要被Enable
if (apnContext.isEnabled()) {
apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
} else {
//設定reason為REASON_DATA_ENABLED
apnContext.setReason(Phone.REASON_DATA_ENABLED);
}
if (apnContext.getState() == DctConstants.State.FAILED) {
apnContext.setState(DctConstants.State.IDLE);
}
trySetup = true;
}
}
//Enable當前APN
apnContext.setEnabled(enabled);
//設定其mDependencyMet屬性也為true
apnContext.setDependencyMet(met);
//清除當前連線
if (cleanup) cleanUpConnection(true, apnContext);
//建立資料連線
if (trySetup) trySetupData(apnContext);
}
由於enabled、met兩個引數此時都為true,因此將會設定APN的Reason為REASON_DATA_ENABLED,並且其mDataEnabled和mDependencyMet屬性都為true: public void setEnabled(boolean enabled) {
mDataEnabled.set(enabled);
}
public void setDependencyMet(boolean met) {
mDependencyMet.set(met);
}
再來看一下該APN引數isReady的判斷: public boolean isReady() {
return mDataEnabled.get() && mDependencyMet.get();
}
由此可知,以後當判斷該APN是否isReady()時,將會得到true的狀態,也就是說,當前APN已經準備就緒。