1.1.1         Phone进程启动

 

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就象个后台进程一样,开机即运行并一直存在(如果异常退出,它会自动重启)。

 

 

1.1.2         PhoneGlobals创建

如上,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等相关类创建和初始化。

 

 

1.1.3         PhoneFactory

 

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创建实例的过程。

 

1.1.4         Phone创建

通过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);

 

 

1.1.5         TelephonyGlobals创建

 

TelephonyGlobals5.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,通过TelecomAccountRegistrysetupOnBoot完成两个功能,一个是注册一个接收器接收账号信息,一个是通过TelephonyManager监听网络服务状态的改变。

 

 

 

1.1.6         CallManager

 

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的内部类CallManagerHandlerPhone实例关联起来,每个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);

}          

 

 

1.1.7         ITelephonyRegistry

 

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。

 

 

1.1.8         TelephonyRegistry

 

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和TelephonyRegistrybinder方式的注册,虽然他们运行在同一个进程。

 

当终端有状态消息改变时,Phone实例调用PhoneNotifier,通过binder接口,将消息通知到TelephonyRegistryTelephonyRegistry使用之前注册的状态监听器IPhoneStateListener,再通过IPhoneStateListenerbinder,将消息通知到PhoneStateListener,最后通知到应用。

 

所以我们可以看到,TelephonyRegistrybinder服务端,它向两侧提供了binder接口,起到承上启下的作用。

 

 

 

1.1.1         PhoneNotifier初始化

 

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"));

    }

 

 

1.1.2         TelephonyManager

 

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发送通知给当前客户端

 

 

1.1.3         Service

上面提到了两种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的相关文档。

 

 

1.1.4         ITelephony

 

ITelephony是一个服务接口,通过binder通信,所以它有服务端和客户端。并根据其服务端和客户端的实现位置,可以判断这个服务接口是一个底层服务,其CS对象都是框架层实体。

它的启动过程和提供服务的示例图如下:

1

PhoneInterfaceManagerITelephony的服务端实现,

 public class PhoneInterfaceManager extends ITelephony.Stub {

 

它所在的目录为(packages\services\telephony\src\com\android\phone),和PhoneGlobals都位于package.service下面,包名为 com.android.phone

 

 

PhoneInterfaceManager的实例创建和初始化是在前面提到的PhoneGlobals.OnCreate()里面,在PhoneGlobals只是创建了这个实例,并未有使用其方法的地方,因为PhoneInterfaceManagerITelephony服务的服务端,所以其接口都是客户端通过远程方法进行的。

 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"));         

 

 

1.1.1         IPhoneSubInfo

 

在之前的分析中,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);

 

PhoneSubInfoProxyPhoneProxy里面创建,之后通过getPhoneSubInfoProxy方法被PhoneSubInfoController调用,就可以使用它的方法了。

    public PhoneProxy(PhoneBase phone) {

                mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo(), simId);   

}

 

    public PhoneSubInfoProxy getPhoneSubInfoProxy(){

        return mPhoneSubInfoProxy;

    }      

 

 

PhoneSubInfo是在Phone实例GSMPhoneCDMAPhone等类构造函数里面创建的,之后被PhoneSubInfoProxy获取到其引用并操作它。

    GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {

           mSubInfo = new PhoneSubInfo(this);

        }

 

    public PhoneSubInfo getPhoneSubInfo(){

        return mSubInfo;

    }

 

其初始化如下,

 

 

1.1.1         SIMRecords初始化

 

SIMRecords实例由UiccCardApplication创建:

 

 

1.1.1         PhoneId相关

为了识别Phone等各个实例,使用了PhoneId

 

PhoneId是在PhoneFactory. makeDefaultPhones创建Phone实例的时候,作为参数传递给GSMPhoneGSMPhone再通过父类PhoneBasemPhoneId赋值。一般值为01,是一个下标值。

                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相等的valuesubthe slot which the SIM is inserted),返回其keysimthe IccId of the SIM card),就是我们需要的PhoneId,通过它,就能进一步获取到Phone实例。

 

剩下3个问题:mSimInfo的赋值,subId的来源,Phone实例的查找。

1mSimInfo是在addSubInfoRecord里面添加的。

 

2Phone实例通过PhoneFactory. getPhonesProxyPhones[phoneId]里获取,先得到PhoneProxy实例,再通过其成员变量获取到GsmPhoneCDMAPhone,它们是在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()获得,accountHandleConnectionRequest类的,

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);

        }

mTargetPhoneAccountHandlesetTargetPhoneAccount设置,被几个地方调用,

a) 在Call类创建被调用,但一个MO呼叫发起时,Call在CallsManager startOutgoingCall被创建,这里给PhoneAccountHandle赋值为null

b) 在CallsManager  startOutgoingCall被调用。这里先判断参数里的PhoneAccountHandle是否为空,不为空再本地创建PhoneAccountHandle

 

参数里的PhoneAccountHandle来自processOutgoingCallIntent,向上追溯到CallUtil.getCallIntent,再到拨号盘,其PhoneAccountHandle参数为null

 

CallsManager本地用mPhoneAccountRegistrar.getDefaultOutgoingPhoneAccount得到一个PhoneAccountHandle

 

 



如果觉得我的文章对您有用,请打赏。您的支持是对我莫大的认可



更多相关文章

  1. android的对话框
  2. android 快速入门之一 “Hello world”,以及debug和日志输出
  3. Android(安卓)JNI简单实例
  4. Android(安卓)OpenGL ES学习笔记之实现OpenGL ES接口
  5. Binder解析
  6. android语音识别之科大讯飞语音API的使用
  7. 博客技术资料整理
  8. 设置listview的背景颜色
  9. SDK中模拟器创建命令行!!!

随机推荐

  1. 理性思维VS中二晚期,二次元程序员调查报告
  2. 技术管理从0到1,并没有你想象的那么难!
  3. 当别人用月薪去衡量程序员时,我们自己应该
  4. 假如程序员会武功?
  5. 虽然难用,但12306面临的业务场景复杂度可
  6. 请注意,容器技术圈已迈入后Kubernetes时代
  7. 科普:QUIC协议原理分析
  8. 让互联网更快的协议,QUIC在腾讯的实践及性
  9. 佛系程序员的月薪五万指南
  10. 每日数亿次微信视频通话背后,靠什么技术支