Phone进程是在系统开机时启动的,它由ActivityManagerService启动。
在5.0,PhoneApp的源码位于(packages\services\telephony\src\com\android\phone),不再在packages\apps\Phone。在(packages\services\Telephony\AndroidManifest.xml)文件配置了如下属性:
android:persistent="true" android:label="@string/phoneAppLabel" android:icon="@mipmap/ic_launcher_phone" android:allowBackup="false" android:supportsRtl="true">
对于android:persistent="true" 的应用是在Android开机时启动的,在Android服务启动中,有三种启动方式(init.rc, persistent,BOOT_COMPLETED?),其中一种是在启动完成时通过调用systemReady函数来完成并通知服务启动。ActivityManagerService服务正是采用这种启动方式,对于属性android:persistent为true的应用是在ActivityManagerService服务启动完成后启动的:
public void systemReady(final Runnable goingCallback) {
…
synchronized (this) {
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
try {
//通过PackageManager查询到所有android:persistent属性为true的应用
List apps = AppGlobals.getPackageManager().
getPersistentApplications(STOCK_PM_FLAGS);
if (apps != null) {
int N = apps.size();
int i;
for (i=0; i ApplicationInfo info = (ApplicationInfo)apps.get(i); if (info != null && !info.packageName.equals("android")) { addAppLocked(info, false, null /* ABI override */); //遍历所有应用,并启动 } } } } catch (RemoteException ex) { // pm is in same process, this will never happen. } } // Start up initial activity. mBooting = true; startHomeActivityLocked(mCurrentUserId);
其中addAppLocked启动该应用,再调用startProcessLocked启动进程,PhoneAPP继承自Application,启动时调用它的onCreate函数,在里面则新建一个PhoneGlobals和一个TelephonyGlobals,并调用它们的onCreate函数。
public class PhoneApp extends Application {
public PhoneApp() {
}
public void onCreate() {
if (UserHandle.myUserId() == 0) {
// We are running as the primary user, so should bring up the
// global phone state.
mPhoneGlobals = new PhoneGlobals(this);
mPhoneGlobals.onCreate();
mTelephonyGlobals = new TelephonyGlobals(this);
mTelephonyGlobals.onCreate();
}
}
Phone就象个后台进程一样,开机即运行并一直存在(如果异常退出,它会自动重启)。
如上,PhoneGlobals是在PhoneAPP创建,并调用它的onCreate函数,在5.0下,PhoneApp.java 文件位于(packages\services\telephony\src\com\android\phone),下面是它的一些重要的相关类,这些类相互关联起来才能实现telephony的通信功能。
private static PhoneGlobals sMe;
CallController callController;
CallManager mCM;
CallNotifier notifier;
CallerInfoCache callerInfoCache;
NotificationMgr notificationMgr;
Phone phone;
PhoneInterfaceManager phoneMgr;
onCreate完成的工作如下,
Phone相关:
1)创建Phone实例,Phone实例没有创建的时候,对其进行相关的初始化,如果PhoneApp重启,因为之前phone实例已经创建过,则不需要再初始化,避免Telephony重新初始化,耗费资源和时间。
PhoneFactory.makeDefaultPhones(this);
2)启动TelephonyDebugService
Intent intent = new Intent(this, TelephonyDebugService.class);
startService(intent);
3)创建PhoneProxy数组,根据Phone的数目,创建数组,并通过getPhones为数组成员赋值,PhoneProxy实例是在PhoneFactory里面创建的,
之后关联相关关键类实例,下面高亮的类是比较关键的类,它们会协调完成框架的通信功能和业务模块,
mPhones = new PhoneProxy[numPhones];
mPhones = PhoneFactory.getPhones();
public PhoneProxy(PhoneBase phone) {
mActivePhone = phone;
mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(
TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);
mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(
phone.getIccPhoneBookInterfaceManager());
mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo());
mCommandsInterface = ((PhoneBase)mActivePhone).mCi;
mCommandsInterface.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
mCommandsInterface.registerForOn(this, EVENT_RADIO_ON, null);
mCommandsInterface.registerForVoiceRadioTechChanged(
this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
mPhoneId = phone.getPhoneId();
mIccSmsInterfaceManager =
new IccSmsInterfaceManager((PhoneBase)this.mActivePhone);
mIccCardProxy = new IccCardProxy(mActivePhone.getContext(), mCommandsInterface, mActivePhone.getPhoneId());
if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
// For the purpose of IccCardProxy we only care about the technology family
mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
} else if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
}
}
4)registerPhone,主要工作是创建一个CallManager,并根据多卡支持,将Phone实例和其中的方法RingingCall、BackgroundCall、ForegroundCall添加到CallManager里面,然后通过registerForPhoneStates,向Phone注册相关事件。
public boolean registerPhone(Phone phone) {
Phone basePhone = getPhoneBase(phone);
if (basePhone != null && !mPhones.contains(basePhone)) {
if (mPhones.isEmpty()) {
mDefaultPhone = basePhone;
}
mPhones.add(basePhone);
mRingingCalls.add(basePhone.getRingingCall());
mBackgroundCalls.add(basePhone.getBackgroundCall());
mForegroundCalls.add(basePhone.getForegroundCall());
registerForPhoneStates(basePhone);
return true;
}
return false;
}
5)NotificationMgr、callController、callStateMonitor的实例获取,如不存在则需要创建实例,并初始化,
发送一个EVENT_START_SIP_SERVICE消息启动SIP服务。
6) BluetoothPhoneService、Ringer、PhoneInterfaceManager、IccCard、PowerManager、KeyguardManager、IPowerManager、InCallUiState、CallerInfoCache、CallNotifier、PhoneUtils等类初始化。
CallNotifier是一个Handler,它为PhoneApp处理各个主动上报来的一些消息。它监听来自Telephony层phone状态变化和其它各种事件,从而作出反应 如各种UI行为:启动铃音播放和来电显示UI、播放正在通话时的来电提示、更新状态栏提示(通过NotificationMgr)、通话记录添加等。在PhoneBase中提供了一些RegistrantList,CallNotifier可以将自己作为一个感兴趣者注册进去,这样,当状态变化时,CallNotifier将得到通知,然后在线程中对其处理,作出UI方面的响应。
NotificationMgr以静态成员函数的方式为PhoneApp用于Phone进程在状态栏中通知用户消息的功能,诸如:有未接电话、正在通话、是否静音等信息。它使用系统提供的API类NotificationManager和StatusBarManager完成通知功能。每项通知对应着通知、更新通知和取消通知的函数。当收到Message时,PhoneApp的Handler的handleMessage会使用NotificationMgr更新状态栏信息。
InCallScreen它是手机正在通话时的Activity。当有来电、开始拨号或正在通话时,运行的是该Activity,InCallScreen需要处理来电时跳过键盘锁直接可以接听电话、是否有耳机插入的情况、是否用蓝牙接听电话、需要监听并维护更新通话状态并显示给用户、需要支持通话过程中的某些功能(如发送DTMF、电话会议、分离一路通话)操作、OTA Call等。CallCard是InCallScreen中的一个call(可能是当前的Call或保持的Call或来电Call)。当需要接听电话或拨打电话时,上层发来intent,然后InCallScreen收到intent时它的InCallScreen.onNewIntent函数被调用,解析intent,要么调用placeCall拨打电话,要么调用internalAnswerCall接听电话。InCallTouchUi:通话过程中的按钮功能以及来电接听时的滑动接听功能。
其他的处理:
PreferenceManager配置类处理。
AudioManager等创建。
cdmaOtaProvisionData等相关类创建和初始化。
在PhoneGlobals.java文件的onCreate()方法中,调用PhoneFactory.makeDefaultPhones来创建Phone相关实例,通过getDefaultPhone获取实例引用。
if (phone == null) {
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
// Get the default phone
phone = PhoneFactory.getDefaultPhone();
PhoneFactory里面的方法都是静态类,所以都是直接引用,没有为PhoneFactory创建实例的过程。
通过PhoneFactory.makeDefaultPhones就创建了Phone实例,创建中主要完成的工作有:
(参考google原生代码 或高通代码,MTK代码有封装。)
public static void makeDefaultPhone(Context context) {
TelephonyDevController.create();//新建设备控制器
new LocalServerSocket("com.android.internal.telephony"); //新建一个socket,用for语句保证socket一定能分配,否则phone实例不能创建
sPhoneNotifier = new DefaultPhoneNotifier(); //创建notifier实例
//reads the system properties and makes commandsinterface
sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);//ril接口实例创建,根据Phone个数的多少创建对应的RIL实例
UiccController.make(context, sCommandsInterface); //卡操作实例
// 新建phone实例,根据网络模式,新建一个GSMPhone实例或CDMALTEPhone实例,做为参数再创建PhoneProxy实例,
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
phone = new GSMPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i);
} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
phone = new CDMALTEPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i);
}
Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
sProxyPhones[i] = new PhoneProxy(phone);
mProxyController = ProxyController.getInstance(context, sProxyPhones,
mUiccController, sCommandsInterfaces); //代理控制器
SmsApplication.initSmsPackageMonitor(context);//sms应用检测
sSubInfoRecordUpdater = new SubInfoRecordUpdater(context,
sProxyPhones, sCommandsInterfaces);
TelephonyGlobals是5.0新添加的类,在packages\services\Telephony\src\com\android\services \telephony,作用是处理PSTN呼叫,
public void onCreate() {
// TODO: Make this work with Multi-SIM devices
Phone phone = PhoneFactory.getDefaultPhone();
if (phone != null) {
mTtyManager = new TtyManager(mContext, phone);
}
TelecomAccountRegistry.getInstance(mContext).setupOnBoot();
}
其代码实现比较简单,在onCreate里创建了一个TtyManager对象,TtyManager里面则是一个handler,处理其内部类TtyBroadcastReceiver这个广播接收器发出的消息。
另外,在onCreate,通过TelecomAccountRegistry的setupOnBoot完成两个功能,一个是注册一个接收器接收账号信息,一个是通过TelephonyManager监听网络服务状态的改变。
CallManager的功能描述如下:
* CallManager class provides an abstract layer for PhoneApp to access
* and control calls. It implements Phone interface.
*
* CallManager provides call and connection control as well as
* channel capability.
*
* There are three categories of APIs CallManager provided
*
* 1. Call control and operation, such as dial() and hangup()
* 2. Channel capabilities, such as CanConference()
* 3. Register notification
CallManager位于(frameworks\opt\telephony\src\java\com\android\internal\telephony)目录下,所在包为com.android.internal.telephony,
其实例化是直接通过静态语句实现的,其构造函数则初始了其关键的成员变量类,这些关键的关联类是Call、Phone、Connection,
private static final CallManager INSTANCE = new CallManager();
private CallManager() {
mPhones = new ArrayList
mRingingCalls = new ArrayList
mBackgroundCalls = new ArrayList
mForegroundCalls = new ArrayList
mDefaultPhone = null;
}
通过前面描述的registerPhone,将Phone实例如GsmPhone的各种Calls的方法添加到CallManager的数组里面,这样CallManager就可以操作GsmPhone方法,实现了和Phone的关联。
通过registerForPhoneStates,将CallManager的内部类CallManagerHandler和Phone实例关联起来,每个Phone对应一个handler,通过注册,handler处理Phone的对应事件。
private void registerForPhoneStates(Phone phone) {
CallManagerHandler handler = mHandlerMap.get(phone);
handler = new CallManagerHandler();
mHandlerMap.put(phone, handler);
phone.registerForPreciseCallStateChanged(handler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
phone.registerForDisconnect(handler, EVENT_DISCONNECT, null);
phone.registerForNewRingingConnection(handler, EVENT_NEW_RINGING_CONNECTION, null);
…
}
ItelephonyRegistry是一个接口,继承自IInterface,它有一个static类型的抽象内部类Stub,继承自Binder并实现了它本身,通过Stub的asInterface能够获取接口实例。接口里方法的实现最终是通过Stub的子类Proxy实现的,
(ItelephonyRegistry.java在out目录下,是自动生成的文件。)
public static com.android.internal.telephony.ITelephonyRegistry asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.android.internal.telephony.ITelephonyRegistry))) {
return ((com.android.internal.telephony.ITelephonyRegistry)iin);
}
return new com.android.internal.telephony.ITelephonyRegistry.Stub.Proxy(obj);
}
可以看出,ItelephonyRegistry对应的实例是从Binder而来,后面分析其初始化过程。
在实际使用中,ItelephonyRegistry作为binder通信的接口,它有服务端和客户端。服务端的实现在TelephonyRegistry,客户端使用接口的方式在TelephonyManager或DefaultPhoneNotifier。
TelephonyRegistry.java 位置在(frameworks\base\services\core\java\com\android \server)目录下,所在包名为com.android.server,它实现了接口ITelephonyRegistry.Stub
class TelephonyRegistry extends ITelephonyRegistry.Stub {
TelephonyRegistry是一个服务,就需要去向ServiceManager先注册自己。
在SystemServer.java文件,在ServerThread.run()里面,5.0创建了一个telephonyRegistry实例(MTK的处理逻辑是为每张卡向ServiceManager注册了一个telephonyRegistry,见灰色部分),这个注册过程实际上就是绑定了一个Ibinder。
Slog.i(TAG, "Telephony Registry");
telephonyRegistry = new TelephonyRegistry(context);
ServiceManager.addService("telephony.registry", telephonyRegistry);
Slog.i(TAG, "Telephony Registry Phone1");
telephonyRegistry = new TelephonyRegistry(context);
ServiceManager.addService("telephony.registry", telephonyRegistry);
Slog.i(TAG, "Telephony Registry Phone2");
telephonyRegistry2 = new TelephonyRegistry(context, PhoneConstants.GEMINI_SIM_2);
ServiceManager.addService("telephony.registry2", telephonyRegistry2);
///M: We create phone registry for each SIM card. ex: registry 1~3 for 3SIM_SUPPORT, registry 1~4 for 4SIM_SUPPORT
if(FeatureOption.MTK_GEMINI_3SIM_SUPPORT || FeatureOption.MTK_GEMINI_4SIM_SUPPORT){
Slog.i(TAG, "Telephony Registry Phone3");
telephonyRegistry3 = new TelephonyRegistry(context, PhoneConstants.GEMINI_SIM_3);
ServiceManager.addService("telephony.registry3", telephonyRegistry3);
///M: Support up to 4 SIM cards
if(FeatureOption.MTK_GEMINI_4SIM_SUPPORT){
Slog.i(TAG, "Telephony Registry Phone4");
telephonyRegistry4 = new TelephonyRegistry(context, PhoneConstants.GEMINI_SIM_4);
ServiceManager.addService("telephony.registry4", telephonyRegistry4);
}
}
其中,TelephonyRegistry是继承自ITelephonyRegistry.Stub,ITelephonyRegistry.Stub是继承自Ibinder,所以TelephonyRegistry实际是一个Ibinder。
它是AIDL的服务端实现,通过binder,向客户端提供远程接口。通过ItelephonyRegistry进行接口访问的都是其客户端,如TelephonyManager。
它作为一个服务为其客户提供注册,注册过程也是一个binder远程调用,其客户注册的过程其实就是把客户端添加到一个叫做mRecords的列表中,当Phone状态改变后,TelephonyRegistry会遍历mRecords中的客户端,分别调用他们当初注册的回调函数。mRecords是TelephonyRegistry核心维护的列表,其中每一项元素都是一个Record型的数据结构,代表着一个客户端。
根据Record的数据结构,客户端注册监听器时,需要提供一个IPhoneStateListener类型的对象,IPhoneStateListener接口定义了有关Phone各个状态的监听器的回调函数。
private static class Record {
String pkgForDebug;
IBinder binder;
IPhoneStateListener callback;
int callerUid;
int events;
}
public TelephonyManager(Context context) {
…
sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
}
TelephonyManager对外提供注册方法listen,让其他应用间接来向TelephonyRegistry注册。MTK平台会为每张卡注册一个监听器。
客户端指定了自己所关注的状态,同时提供自己对该状态的回调函数,当相应的事件发生时,TelephonyRegistry就会去调用客户端的回调函数IPhoneStateListener。
TelephonyRegistry还有一个客户端实现在DefaultPhoneNotifier,它位于framework/opt目录下,所在包为com.android.internal.telephony,
通过代码分析,我们能总结出TelephonyRegistry的注册和使用过程的实例图如下:
首先是CallNotifier作为客户端,通过TelephonyManager向注册TelephonyRegistry注册一个状态监听器PhoneStateListener,TelephonyManager和TelephonyRegistry是binder方式的注册,虽然他们运行在同一个进程。
当终端有状态消息改变时,Phone实例调用PhoneNotifier,通过binder接口,将消息通知到TelephonyRegistry,TelephonyRegistry使用之前注册的状态监听器IPhoneStateListener,再通过IPhoneStateListener的binder,将消息通知到PhoneStateListener,最后通知到应用。
所以我们可以看到,TelephonyRegistry是binder服务端,它向两侧提供了binder接口,起到承上启下的作用。
PhoneNotifier也是在PhoneFactory里创建的,实际是创建的DefaultPhoneNotifier的实例。
...
sPhoneNotifier = new DefaultPhoneNotifier();
...
int phoneType = TelephonyManager.getPhoneType(networkMode);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
Log.i(LOG_TAG, "Creating GSMPhone");
sProxyPhone = new PhoneProxy(new GSMPhone(context,
sCommandsInterface, sPhoneNotifier));
}
...
在DefaultPhoneNotifier的构造函数里,获取了ItelephonyRegistry的服务,将Phone底层的消息通过ItelephonyRegistry上报。
public DefaultPhoneNotifier() {
mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
}
TelephonyManager 目录在(frameworks\base\telephony\java\android\telephony),所在包名package android.telephony,运行在Phone进程里面,提供telephony相关的服务。
TelephonyManager的创建比较特殊,有两种实例创建过程,
其一是在ContextImpl里面,创建TelephonyManager实例,并向context注册,方便后面能够通过context.getSystemService获取到实例。
registerService(TELEPHONY_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new TelephonyManager(ctx.getOuterContext());
}});
还一种是在TelephonyManager类文件里,new一个实例,其他一些应用中,使用getDefault获得引用,进行方法调用。这个TelephonyManager的实例是静态语句创建的,也就是在第一个实例创建过程中创建的。
private static TelephonyManager sInstance = new TelephonyManager();
/** @hide
/* @deprecated - use getSystemService as described above */
public static TelephonyManager getDefault() {
return sInstance;
}
至于为什么new出两个实例,在哪种情况下该使用哪个实例?这个问题困扰了我很久,经过反复思考和项目实践,初步分析,原因在于mContext,当某些环境下,需要使用telephony服务时,有获取不到Context对象,则可以使用第二种方法创建的实例,在实际开发中,特别是从事telephony的开发中,,我们经常会发现需要使用一个底层对象,但往往没有接口获取到Context,得想不同方法去获取到实例。
TelephonyManager的提供的服务并不是本身实现的,而主要是通过ITelephonyRegistry、ITelephony、ITelecomService、IPhoneSubInfo这四个接口提供服务,TelephonyManager只是对这些接口的封装,或者说是客户端实现。
在TelephonyManager通过getITelephony获取ITelephony服务实例,
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
}
通过listen为客户提供向getITelephony注册的服务。也就是说,客户端 如果想要实现对TelephonyRegistry的监听,可以先得到TelephonyManager的服务,然后通过这个服务调用其listen方法把当前客户端注册给TelephonyRegistry,当Phone状态改变时,再由TelephonyRegistry发送通知给当前客户端。
上面提到了两种service,为什么会有两种Service,区别在哪里呢,入门Android的时候,本人从没有意识到两者的差异、意识到有差异但不明白为什么,到现在有个初步理解?这里简单陈述一下。
TelephonyManager所属的service通过在context 创建, 通过registerService存放在一个hashMap里面,通过context.getSystemService获取到实例,是一个普通类。它实现的目的就是作为一个单一的实例,为系统内需要这个服务的所有客户提供相同服务,不需要所有客户单独创建实例,减少系统负载。
TelephonyRegistry所属的service通过在ServiceManager创建,通过ServiceManager.addService获取底层支持,进行服务注册,通过ServiceManager.getService获取到服务实例,用IBinder方式使用。这种服务设计的目的是实现进程间通信,优化软件架构。
ServiceManager会获取ServiceManagerNative实例, ServiceManagerNative实现了IServiceManager接口,并且它使用了ServiceManagerProxy,和binder通信,完成实际的业务功能。
至于Java的binder是如何与C++的binder关联起来的,在ServiceManagerNative实例创建时,使用了BinderInternal.getContextObject(),getContextObject是一个native方法,它能获取到C++层的Binder实例,并通过Binder的transact()方法将当前请求传递给Binder驱动进行处理。从下面的代码片段可见一斑。
ServiceManager.java:
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
ServiceManagerNative.java:
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ServiceManagerProxy(obj);
}
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
对于这个知识点的详细分析,请参看Binder的相关文档。
ITelephony是一个服务接口,通过binder通信,所以它有服务端和客户端。并根据其服务端和客户端的实现位置,可以判断这个服务接口是一个底层服务,其CS对象都是框架层实体。
它的启动过程和提供服务的示例图如下:
1)
PhoneInterfaceManager是ITelephony的服务端实现,
public class PhoneInterfaceManager extends ITelephony.Stub {
它所在的目录为(packages\services\telephony\src\com\android\phone),和PhoneGlobals都位于package.service下面,包名为 com.android.phone,
PhoneInterfaceManager的实例创建和初始化是在前面提到的PhoneGlobals.OnCreate()里面,在PhoneGlobals只是创建了这个实例,并未有使用其方法的地方,因为PhoneInterfaceManager是ITelephony服务的服务端,所以其接口都是客户端通过远程方法进行的。
PhoneGlobals.OnCreate():
phoneMgr = PhoneInterfaceManager.init(this, phone);
PhoneInterfaceManager:
/* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
synchronized (PhoneInterfaceManager.class) {
if (sInstance == null) {
sInstance = new PhoneInterfaceManager(app, phone);
…
return sInstance;
}
}
PhoneInterfaceManager几个关键的相关类如下,它通过这些类的实例提供服务。
PhoneGlobals mApp;
Phone mPhone;
CallManager mCM;
AppOpsManager mAppOps;
MainThreadHandler mMainThreadHandler;
2)
ITelephony的客户端有很多,都是通过下面的方式获取到接口实例,然后使用服务的远程接口完成相关功能。TelephonyManager是比较常用的客户端。
ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
在之前的分析中,TelephonyManager用到了IPhoneSubInfo接口,实现这个接口的地方有如下两个,使用接口的只有TelephonyManager,
PhoneSubInfoController.java (frameworks\opt\telephony\src\java\com\android\internal\telephony):
public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
PhoneSubInfoProxy.java (frameworks\opt\telephony\src\java\com\android\internal\telephony):
public class PhoneSubInfoProxy extends IPhoneSubInfo.Stub {
为什么创建两个类实例,实现相同的接口,原因尚不很明确。
PhoneSubInfoController是通过使用PhoneSubInfoProxy,来完成接口功能的,PhoneSubInfoProxy也没有直接实现什么功能,它使用了PhoneSubInfo的对象进行实际操作,PhoneSubInfo又使用了Phone实例提供的接口。其调用逻辑如下图所示:
PhoneSubInfoController的创建过程在ProxyController的构造函数里,再向上追溯,可以看到PhoneFactory. makeDefaultPhone通过ProxyController. getInstance创建了ProxyController实例。注意所有相关类都位于(frameworks\opt\telephony\src\java\com\android\ internal\telephony)目录下,
private ProxyController(Context context, Phone[] phoneProxy, UiccController uiccController,
CommandsInterface[] ci) {
mDctController = DctController.makeDctController((PhoneProxy[])phoneProxy, t.getLooper());
mUiccPhoneBookController = new UiccPhoneBookController(mProxyPhones);
mPhoneSubInfoController = new PhoneSubInfoController(mProxyPhones);
mUiccSmsController = new UiccSmsController(mProxyPhones);
}
PhoneFactory. makeDefaultPhone:
mProxyController = ProxyController.getInstance(context, sProxyPhones,
mUiccController, sCommandsInterfaces);
PhoneSubInfoProxy在PhoneProxy里面创建,之后通过getPhoneSubInfoProxy方法被PhoneSubInfoController调用,就可以使用它的方法了。
public PhoneProxy(PhoneBase phone) {
…
mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo(), simId);
}
public PhoneSubInfoProxy getPhoneSubInfoProxy(){
return mPhoneSubInfoProxy;
}
PhoneSubInfo是在Phone实例GSMPhone、CDMAPhone等类构造函数里面创建的,之后被PhoneSubInfoProxy获取到其引用并操作它。
GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {
…
mSubInfo = new PhoneSubInfo(this);
}
public PhoneSubInfo getPhoneSubInfo(){
return mSubInfo;
}
其初始化如下,
SIMRecords实例由UiccCardApplication创建:
为了识别Phone等各个实例,使用了PhoneId,
PhoneId是在PhoneFactory. makeDefaultPhones创建Phone实例的时候,作为参数传递给GSMPhone,GSMPhone再通过父类PhoneBase给mPhoneId赋值。一般值为0,1,是一个下标值。
for (int i = 0; i < numPhones; i++) {
PhoneBase phone = null;
int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
phone = new GSMPhone(context,
sCommandsInterfaces[i], sPhoneNotifier,i);
} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
phone = new CDMALTEPhone(context,
sCommandsInterfaces[i], sPhoneNotifier,i);
}
Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
sProxyPhones[i] = new PhoneProxy(phone);
}
在呼叫中,在TelephonyConnectionService.java的onCreateOutgoingConnection,通过getPhoneForAccount能获取到Phone实例,是GSMPhone、CDMAPhone还是IMSPhone?
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
final ConnectionRequest request) {
final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber);
placeOutgoingConnection(connection, phone, request);
}
getPhoneForAccount
private Phone getPhoneForAccount(PhoneAccountHandle accountHandle, boolean isEmergency) {
if (isEmergency) {
return PhoneFactory.getPhone(getPhoneIdForECall());
}
if (Objects.equals(mExpectedComponentName, accountHandle.getComponentName())) {
if (accountHandle.getId() != null) {
try {
int phoneId = SubscriptionController.getInstance().getPhoneId(
Long.parseLong(accountHandle.getId()));
return PhoneFactory.getPhone(phoneId);
} catch (NumberFormatException e) {
Log.w(this, "Could not get subId from account: " + accountHandle.getId());
}
}
}
return null;
}
其中使用,
在getPhoneId里面,排除异常处理后,其主要过程是从mSimInfo这个hashMap里面,找到和subId相等的value值sub(the slot which the SIM is inserted),返回其key值sim(the IccId of the SIM card),就是我们需要的PhoneId,通过它,就能进一步获取到Phone实例。
剩下3个问题:mSimInfo的赋值,subId的来源,Phone实例的查找。
1)mSimInfo是在addSubInfoRecord里面添加的。
2)Phone实例通过PhoneFactory. getPhone在sProxyPhones[phoneId]里获取,先得到PhoneProxy实例,再通过其成员变量获取到GsmPhone或CDMAPhone,它们是在PhoneFactory创建好实例后传递给PhoneProxy的,
PhoneFactory:
sProxyPhones[i] = new PhoneProxy(phone);
PhoneProxy:
public PhoneProxy(PhoneBase phone) {
mActivePhone = phone;
对于ImsPhone呼叫,在拨号时,先使用PhoneProxy获取到代理,然后通过mActivePhone成员GSMPhone继续使用dial拨号,最后判断videoState和mImsPhone成员,使用imsPhone.dial
3)subId的来源,通过accountHandle.getId()获得,accountHandle是ConnectionRequest类的,
ConnectionRequest来源于aidl接口createConnection的参数ConnectionRequest,
mServiceInterface.createConnection(
call.getConnectionManagerPhoneAccount(),
callId,
new ConnectionRequest(
call.getTargetPhoneAccount(),
call.getHandle(),
extras,
call.getVideoState()),
call.isIncoming(),
call.isUnknown());
call.getTargetPhoneAccount()就是我们需要的accountHandle,只有call.getTargetPhoneAccount()不为空,才能建立连接,所以在call实例创建的时候就有PhoneAccountHandle了。
if (call.getTargetPhoneAccount() != null || isEmergencyCall) {
if (!isEmergencyCall) {
updateLchStatus(call.getTargetPhoneAccount().getId());
}
// If the account has been set, proceed to place the outgoing call.
// Otherwise the connection will be initiated when the account is set by the user.
call.startCreateConnection(mPhoneAccountRegistrar);
}
mTargetPhoneAccountHandle被setTargetPhoneAccount设置,被几个地方调用,
a) 在Call类创建被调用,但一个MO呼叫发起时,Call在CallsManager startOutgoingCall被创建,这里给PhoneAccountHandle赋值为null。
b) 在CallsManager startOutgoingCall被调用。这里先判断参数里的PhoneAccountHandle是否为空,不为空再本地创建PhoneAccountHandle。
参数里的PhoneAccountHandle来自processOutgoingCallIntent,向上追溯到CallUtil.getCallIntent,再到拨号盘,其PhoneAccountHandle参数为null。
CallsManager本地用mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount得到一个PhoneAccountHandle
如果觉得我的文章对您有用,请打赏。您的支持是对我莫大的认可!