android系统启动起来后,在 telephony framework层,该启动 CDMAPhone 还是 GSMPhone ?
先从网上摘一段说明:
Phone描述了对电话的所有操作接口。PhoneBase直接从Phone 派生而来。而另外两个类,CDMAPhone和GSMPhone,又从PhoneBase派生而来,分别代表对CDMA 和GSM的操作。
PhoneProxy也从Phone直接派生而来。当前不需要区分具体是CDMA Phone还是GSM Phone时,可使用PhoneProxy。GSMPhone和CDMAPhone实现了Phone中定义的接口。接口类Phone定义了一套API,这套API用于使用RIL发送AT命令请求,也还有一套register和unregister函数;当调用者对一些内部状态感兴趣时,可以调用对应的register函数,当状态变化时可以得到及时通知。
PhoneBase实现了Phone接口中定义的部分函数,还有一部分由其子类GSMPhone和CDMAPhone实现。honeProxy是GSMPhone和CDMAPhone的代理,让使用者不用关注手机到底是GSM还是CDMA,它遵守Phone定义的API接口,因此继承Phone。
PhoneFactory在创建Phone对象时,拥有的是PhoneProxy对象,PhoneProxy根据实际的网络类型创建对应的GSMPhone或CDMAPhone。PhoneFactory同样拥有CommandInterface的接口对象,即RIL的实例,该RIL实例将被传递给GSMPhone或CDMAPhone,即GSMPhone或CDMAPhone引用它,实现与rild的交互。
GSMPhone和CDMAPhone继承自PhoneBase,它们(包括PhoneProxy)都是一个Handler。这样,它们就可以在线程的循环Looper.loop中处理来自RILJ或自身发送的各种Message。PhoneFactory负责创建各个Phone实例,其成员及成员函数为static,可以保证创建的实例在系统运行时的唯一性。
详细介绍请查看 Android Phone设计介绍
查看了好多资料,都没有看到介绍如何来配置当前系统的Phone类型,大多数都是先假设为GSMPhone类型,然后继续讲解RIL流程。
下面我们就来分析下android中系统中是如何确定Phone类型的:
1 在 packages\apps\Phone\src\com\android\phone\PhoneApp.java的oncreate函数中
onCreate() {
...
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
// Get the default phone
phone = PhoneFactory.getDefaultPhone();
...
}
2 我们跳转到PhoneFactory.java中的makeDefaultPhones函数,在此函数中继续调用makeDefaultPhone(context)
makeDefaultPhone(Context context) {
...
int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;
int networkMode = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode);
...
int phoneType = getPhoneType(networkMode);
if (phoneType == Phone.PHONE_TYPE_GSM) {
Log.d(LOG_TAG, "Creating GSMPhone");
sProxyPhone = new PhoneProxy(new GSMPhone(context,
sCommandsInterface, sPhoneNotifier));
} else if (phoneType == Phone.PHONE_TYPE_CDMA) {
switch (BaseCommands.getLteOnCdmaModeStatic()) {
case Phone.LTE_ON_CDMA_TRUE:
Log.d(LOG_TAG, "Creating CDMALTEPhone");
sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,
sCommandsInterface, sPhoneNotifier));
break;
case Phone.LTE_ON_CDMA_FALSE:
default:
Log.d(LOG_TAG, "Creating CDMAPhone");
sProxyPhone = new PhoneProxy(new CDMAPhone(context,
sCommandsInterface, sPhoneNotifier));
break;
}
}
...
}
在RILConstants.java中有定义
int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */
int NETWORK_MODE_CDMA = 4; /* CDMA and EvDo (auto mode, according to PRL)
int PREFERRED_NETWORK_MODE = NETWORK_MODE_WCDMA_PREF;
在frameworks\base\core\java\android\provider\Settings.java中有定义
public static final String PREFERRED_NETWORK_MODE = "preferred_network_mode";
所以,preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;是先设置默认为GSMPhone类型
从 Settings.Secure.getInt(context.getContentResolver(),Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode);
我们可以知道判断Phone类型时从secure数据库中读取"preferred_network_mode"字段的取值来确定的getPhoneType(networkMode)是将读到的值转换为Phone类型值,这个很简单不分析啦!
接下来要分析的是什么地方会写secure数据库中"preferred_network_mode"字段的值呢?
3 secure数据库是在首次开机的时候创建的,我们可以通过恢复出厂设置来模拟首次开机的情况
在frameworks\base\packages\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java的Oncreate函数中有:
createSecureTable(db);
loadSettings(db);
private void createSecureTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE secure (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"name TEXT UNIQUE ON CONFLICT REPLACE," +
"value TEXT" +
");");
db.execSQL("CREATE INDEX secureIndex1 ON secure (name);");
}
private void loadSettings(SQLiteDatabase db) {
loadSystemSettings(db);
loadSecureSettings(db); //我们要分析的是这里
}
在loadSecureSettings函数中:
int type;
if (BaseCommands.getLteOnCdmaModeStatic() == Phone.LTE_ON_CDMA_TRUE) {
type = Phone.NT_MODE_GLOBAL;
} else {
type = SystemProperties.getInt("ro.telephony.default_network",
RILConstants.PREFERRED_NETWORK_MODE);
}
loadSetting(stmt, Settings.Secure.PREFERRED_NETWORK_MODE, type);
看到这里,我们知道Phone类型是由上面的type取值决定的
BaseCommands.getLteOnCdmaModeStatic( ) 一般返回Phone.LTE_ON_CDMA_FALSE,目前还没碰到为LTE_ON_CDMA_TRUE的情况,暂不分析这个。
那么我们看下面的分支:
SystemProperties.getInt("ro.telephony.default_network", RILConstants.PREFERRED_NETWORK_MODE);
分析到这里就知道了 Phone类型最终是由 系统属性"ro.telephony.default_network"来配置的
好啦,我们可以配置Phone的类型啦:
GSMPhone:
设置 ro.telephony.default_network=0 //即 NETWORK_MODE_WCDMA_PREF
或者 不添加系统属性ro.telephony.default_network,这样就直接用默认值PREFERRED_NETWORK_MODE
CDMAPhone:
设置 ro.telephony.default_network=4 //即 NETWORK_MODE_CDMA