定义:
APN (access point name) 简单的可以理解为数据上网的接入点名称,是访问数据的必须要配置的参数。该参数的配置直接决定了访问数据的接入方式。
参数:
"中国移动 (China Mobile) WAP"
mcc="460"
mnc="00"
apn="cmwap"
proxy="10.0.0.172"
port="80"
type="default,supl"
/>
名称 | 说明 |
---|---|
carrier | 该APN的名称(在手机上可以看到) |
mccmnc | 手机的mccmnc |
apn | 接入点 |
proxy | 代理 |
port | 端口 |
type | 该条apn可以入网的类型 |
配置:
apn 由google定义了一套可供各运营商使用的默认配置,其默认存放位置在device/sample/etc/apns-full-conf.xml里。编译后会copy到system/etc/apns-conf.xml.针对不同的运营商需求,可以在apns-full-conf.xml里更改。
在手机中,apn存在于telephony.db中。具体位置为:content://telephony/carriers
加载:
在device 检测到simcard load完成后,经过一系列的调用:
protected void onRecordsLoadedOrSubIdChanged() {
...
createAllApnList();//从数据库中获取所有符合标准的apn
setInitialAttachApn();//设置初始accach的apn
...
}
/**
* Based on the sim operator numeric, create a list for all possible
* Data Connections and setup the preferredApn.
*/
protected void createAllApnList() {
mMvnoMatched = false;//虚拟运营商相关的,尚未遇到过
mAllApnSettings = new ArrayList();
IccRecords r = mIccRecords.get();
String operator = mPhone.getOperatorNumeric();
if (operator != null) {
String selection = "numeric = '" + operator + "'";
String orderBy = "_id";
// query only enabled apn.
// carrier_enabled : 1 means enabled apn, 0 disabled apn.
// selection += " and carrier_enabled = 1";
if (DBG) log("createAllApnList: selection=" + selection);
//通过mccmnc筛选出apn集合
Cursor cursor = mPhone.getContext().getContentResolver().query(
Telephony.Carriers.CONTENT_URI, null, selection, null, orderBy);
if (cursor != null) {
if (cursor.getCount() > 0) {
//得到所有合适的apn
mAllApnSettings = createApnList(cursor);
}
cursor.close();
}
}
//添加Emergency APN settings
addEmergencyApnSetting();
//去除重复的apn
dedupeApnSettings();
if (mAllApnSettings.isEmpty()) {
if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
mPreferredApn = null;
// TODO: What is the right behavior?
//notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN);
} else {
mPreferredApn = getPreferredApn();
if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
mPreferredApn = null;
setPreferredApn(-1);
}
if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn);
}
if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings);
setDataProfilesAsNeeded();
}
ApnSetting 可以简单看成是APN的构造函数(?),在查询数据库时,主要以ApnSetting 形式存储。其参数分别对应着telephony.db carrier表里的各项。
构造函数:
public ApnSetting(int id, String numeric, String carrier, String apn,
String proxy, String port,
String mmsc, String mmsProxy, String mmsPort,
String user, String password, int authType, String[] types,
String protocol, String roamingProtocol, boolean carrierEnabled, int bearer,
int bearerBitmask, int profileId, boolean modemCognitive, int maxConns, int waitTime,
int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) {
this.id = id; //数据库里的标识ID
this.numeric = numeric; // mccmnc
this.carrier = carrier; //该apn的名称(即在settings里显示)
this.apn = apn; //接入点
this.proxy = proxy; //apn 的代理
this.port = port; //apn 的端口号
this.mmsc = mmsc; //彩信中心地址
this.mmsProxy = mmsProxy; //彩信代理
this.mmsPort = mmsPort; //彩信端口
this.user = user; //没看懂(to be update)
this.password = password; //没看懂(to be update)
this.authType = authType; //没看懂(to be update)
this.types = new String[types.length]; //该apn适用的data类型
for (int i = 0; i < types.length; i++) {
this.types[i] = types[i].toLowerCase(Locale.ROOT);
}
this.protocol = protocol;
this.roamingProtocol = roamingProtocol;
this.carrierEnabled = carrierEnabled;
this.bearer = bearer;//能够处理的网络类型(?)
this.bearerBitmask = (bearerBitmask | ServiceState.getBitmaskForTech(bearer));
this.profileId = profileId;
this.modemCognitive = modemCognitive;
this.maxConns = maxConns;
this.waitTime = waitTime;
this.maxConnsTime = maxConnsTime;
this.mtu = mtu;
this.mvnoType = mvnoType;
this.mvnoMatchData = mvnoMatchData;
}
重点接口:
/**
* 判断传递过来的type是否能够处理。
* 通常在不同运营商上有不同的需求,这块需要特殊处理
*/
public boolean canHandleType(String type) {
if (!carrierEnabled) return false;
for (String t : types) {
// DEFAULT handles all, and HIPRI is handled by DEFAULT
if (t.equalsIgnoreCase(type) ||
t.equalsIgnoreCase(PhoneConstants.APN_TYPE_ALL) ||
(t.equalsIgnoreCase(PhoneConstants.APN_TYPE_DEFAULT) &&
type.equalsIgnoreCase(PhoneConstants.APN_TYPE_HIPRI))) {
return true;
}
}
return false;
}
APN & ApnSetting 均为配置参数,而ApnContext 则是操作APN or ApnSetting. 在Dctracker 或者DataConnection 等跟数据相关主要的相关类中,主要操作ApnContext来读取或设置APN相关信息。
常用的接口:
接口 | 返回值 | 说明 |
---|---|---|
getApnSetting | ApnSetting | 返回当前所有APN |
getApnType | String | 返回当前APN类型 |
getState | DctConstants.State | 返回该条apn对应网络的状态 |
isConnectedOrConnecting | boolean | 返回当前apn对应的网络是否连接 |
… | … | … |
系统调用:
/**
* 判断传递过来的type 是否允许访问数据
*/
public boolean isDataPossible(String apnType) {
ApnContext apnContext = mApnContexts.get(apnType);
if (apnContext == null) {
return false;
}
boolean apnContextIsEnabled = apnContext.isEnabled();
DctConstants.State apnContextState = apnContext.getState();
boolean apnTypePossible = !(apnContextIsEnabled &&
(apnContextState == DctConstants.State.FAILED));
boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
// Set the emergency APN availability status as TRUE irrespective of conditions checked in
// isDataAllowed() like IN_SERVICE, MOBILE DATA status etc.
boolean dataAllowed = isEmergencyApn || isDataAllowed(null);
boolean possible = dataAllowed && apnTypePossible;
if ((apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
|| apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA))
&& (mPhone.getServiceState().getRilDataRadioTechnology()
== ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) {
log("Default data call activation not possible in iwlan.");
possible = false;
}
if (VDBG) {
log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " +
"apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s",
apnType, possible, dataAllowed, apnTypePossible,
apnContextIsEnabled, apnContextState));
}
return possible;
}