Android APN配置

weixin_34119545發表於2019-01-08

 

APN概念      


APN(Access Point Name),即“接入點名稱”,用來標識GPRS的業務種類,目前分為兩大類:CMWAP(通過GPRS訪問WAP業務)、CMNET(除了WAP以外的服務目前都用CMNET,比如連線因特網等)。是通過手機上網時必須配置的一個引數,它決定了您的手機通過哪種接入方式來訪問網路。業務流程GPRS專網系統終端上網登入伺服器平臺的流程為:
1)使用者發出GPRS登入請求,請求中包括由移動公司為GPRS專網系統專門分配的專網APN;
2)根據請求中的APN,SGSN向DNS伺服器發出查詢請求,找到與企業伺服器平臺連線的GGSN,並將使用者請求通過GTP隧道封裝送給GGSN;
3)GGSN將使用者認證資訊(包括手機號碼、使用者賬號、密碼等)通過專線送至Radius進行認證;
4)Radius認證伺服器看到手機號等認證資訊,確認是合法使用者發來的請求,向DHCP伺服器請求分配使用者地址;
5)Radius認證通過後,由Radius向GGSN傳送攜帶使用者地址的確認資訊;
6)使用者得到了IP地址,就可以攜帶資料包,對GPRS專網系統資訊查詢和業務處理平臺進行訪問。

 

Android自帶的內部APN配置檔案


frameworks/base/core/res/res/xml/apns.xml檔案內容:

 

<!-- If you edit this version, also edit the version in the partner-supplied
    apns-conf.xml configuration file -->
<apns version="7">

</apns>

 

該檔案被編譯到res.apk中,通過android的資源管理器進行訪問。

第三方提供的APN配置檔案

在Android原始碼build目錄下,通過搜尋apns-conf.xml可以找到在各個board中分別有配置:


在編譯該product時會將device/generic/goldfish/data/etc/apns-conf.xml檔案拷貝到system/etc/目錄下,最後打包到system.img中。

APN配置載入


android通過telephony.db資料庫中的 carriers表來儲存所有的APN配置資訊


packages/providers/TelephonyProvider/src/com/android/providers/telephony/TelephonyProvider.java檔案中的內部類DatabaseHelper用於建立telephony.db資料庫

 

public void onCreate(SQLiteDatabase db) {
	// Set up the database schema
	db.execSQL("CREATE TABLE " + CARRIERS_TABLE +
		"(_id INTEGER PRIMARY KEY," +
			"name TEXT," +
			"numeric TEXT," +
			"mcc TEXT," +
			"mnc TEXT," +
			"apn TEXT," +
			"user TEXT," +
			"server TEXT," +
			"password TEXT," +
			"proxy TEXT," +
			"port TEXT," +
			"mmsproxy TEXT," +
			"mmsport TEXT," +
			"mmsc TEXT," +
			"authtype INTEGER," +
			"type TEXT," +
			"current INTEGER," +
			"protocol TEXT," +
			"roaming_protocol TEXT," +
			"carrier_enabled BOOLEAN," +
	"preset BOOLEAN default false," +
			"bearer INTEGER);");
	//從APN配置xml檔案中讀取APN配置,並儲存到資料表carriers中
	initDatabase(db);
}

APN配置資訊載入分為兩部分,首先從Android自帶的內部APN配置檔案中讀取配置資訊,然後在讀取第三方提供的APN配置檔案資訊。

 

 

private void initDatabase(SQLiteDatabase db) {
	// Read internal APNS data
	Resources r = mContext.getResources();
	//讀取frameworks/base/core/res/res/xml/apns.xml檔案
	XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
	int publicversion = -1;
	try {
		XmlUtils.beginDocument(parser, "apns");
		//讀取APN配置版本資訊
		publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
		//載入APN配置資訊,並儲存到資料表中
		loadApns(db, parser);
	} catch (Exception e) {
		Log.e(TAG, "Got exception while loading APN database.", e);
	} finally {
		parser.close();
	}

   // Read external APNS data (partner-provided)
	XmlPullParser confparser = null;
	// Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
	//讀取system/etc/apns-conf.xml檔案
	File confFile = new File(Environment.getRootDirectory(), PARTNER_APNS_PATH);
	FileReader confreader = null;
	try {
		confreader = new FileReader(confFile);
		confparser = Xml.newPullParser();
		confparser.setInput(confreader);
		XmlUtils.beginDocument(confparser, "apns");
		// 讀取第三方提供的APN配置版本號
		int confversion = Integer.parseInt(confparser.getAttributeValue(null, "version"));
		//判斷第三方提供的APN配置版本號是否與Android自帶的APN配置版本號相同
		if (publicversion != confversion) {
			throw new IllegalStateException("Internal APNS file version doesn't match "
					+ confFile.getAbsolutePath());
		}
		//如果版本號相同,讀取APN配置資訊
		loadApns(db, confparser);
	} catch (FileNotFoundException e) {
		// It's ok if the file isn't found. It means there isn't a confidential file
		// Log.e(TAG, "File not found: '" + confFile.getAbsolutePath() + "'");
	} catch (Exception e) {
		Log.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
	} finally {
		try { if (confreader != null) confreader.close(); } catch (IOException e) { }
	}
}

從APN資訊載入原始碼中可以知道,第三方提供的APN配置資訊版本必須與內部APN配置資訊的版本相同。自此APN配置資訊就儲存在carriers表中了,並且通過TelephonyProvider向外提供訪問介面。

 

 

相關文章