android手机修改当前Apn接入点信息,主要涉及源码目录/packages/providers/TelephonyProvider,其中涉及到apn的是TelephonyProvider.java,它是一个ContentProvider,关联的数据库名为:telephony.db
其中提供的uri有
s_urlMatcher.addURI("telephony", "carriers", URL_TELEPHONY);
s_urlMatcher.addURI("telephony", "carriers/current", URL_CURRENT);
s_urlMatcher.addURI("telephony", "carriers/#", URL_ID);
s_urlMatcher.addURI("telephony", "carriers/restore", URL_RESTOREAPN);
s_urlMatcher.addURI("telephony", "carriers/preferapn", URL_PREFERAPN);
对于该db的操作中,查询不需要权限,其他操作需要权限:
1.查询
@Override
public Cursor query(Uri url, String[] projectionIn, String selection,
String[] selectionArgs, String sort) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables("carriers");
int match = s_urlMatcher.match(url);
switch (match) {
// do nothing
case URL_TELEPHONY: {
break;
}
case URL_CURRENT: {
qb.appendWhere("current IS NOT NULL");
// do not ignore the selection since MMS may use it.
//selection = null;
break;
}
case URL_ID: {
qb.appendWhere("_id = " + url.getPathSegments().get(1));
break;
}
case URL_PREFERAPN: {
qb.appendWhere("_id = " + getPreferredApnId());
break;
}
default: {
return null;
}
}
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort);
ret.setNotificationUri(getContext().getContentResolver(), url);
return ret;
}
2.插入
@Override
public Uri insert(Uri url, ContentValues initialValues)
{
Uri result = null;
checkPermission();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int match = s_urlMatcher.match(url);
boolean notify = false;
switch (match)
{
.
....
3.删除
@Override
public int delete(Uri url, String where, String[] whereArgs)
{
int count;
checkPermission();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int match = s_urlMatcher.match(url);
switch (match)
{
case URL_TELEPHONY:
{
.....
4.更新
@Override
public int update(Uri url, ContentValues values, String where, String[] whereArgs)
{
int count = 0;
checkPermission();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int match = s_urlMatcher.match(url);
switch (match)
{
case URL_TELEPHONY:
{
......
其中上述操作中checkPermission();就是权限检测
private void checkPermission() {
// Check the permissions
getContext().enforceCallingOrSelfPermission("android.permission.WRITE_APN_SETTINGS",
"No permission to write APN settings");
}
目前android手机存在以下情况:
1.虽然从一开始,android就说明不允许第三方程序WRITE_APN_SETTINGS,
但事实上是从android 4.0开始,才屏蔽了<uses-permission android:name="android.permission.WRITE_APN_SETTINGS">权限,换句话说即使配置了该权限,程序也不会按照预期完成对应的功能。(经过测试2.x可以正确使用该权限完成相应apn修改操作,不会产生异常,1.x因为几乎看不到,所以未做测试)。在4.x手机上将会产生如下异常:
在手机未root的情况下,目前第三方应用(非system/app下面,不具有系统签名的)将无法直接修改Apn设置信息。注意这里即使手机root之后,通过常规的方法进行apn修改的操作也是会抛出该异常。这里我使用了小米1(4.1),步步高x-play(4.2.2),小米2(4.1),三星GTS752I(4.04),其中三星是已root。上述手机都抛出了该异常。但在测试过程中,测试了一款华为手机(c8815 已root),能够正确的执行apn操作,具体原因尚不明确,初步猜测是华为在这方面做了一些改动,例如没有进行权限检查。当然可能也有其他的方式,但尚未可知。此外不排除因为android自身漏洞而存在能修改Apn信息又不会异常的可能。
~~~~~~~~~~~~~~~~~~~~~~~~~~
其他备注:
用户通过setting程序
1.填写错误的apn参数,当apn类型为default时,也能够正常连接外网。此时连接的网络类型为mobile。
2.apn填写正确的apn(我这里填写的cmsip,cmsip是中国移动提供的一条内网网络,需要手机号开通才能使用),类型为default时,若手机卡开通了cmsip,则手机可以连接通内网(外网不通,即没法登陆使用QQ等一切使用公网网络的程序),若手机卡未开通,此时手机也能正常连接外网(无法连接内网)连接的网络类型为mobile.