关闭

Android 5.0 Telephony关键类初始化和相互关系

标签: Android5.0telephony
7528人阅读 评论(2) 收藏 举报
分类:

 

1.1.1         Phone进程启动

 

Phone进程是在系统开机时启动的,它由ActivityManagerService启动。

 

在5.0,PhoneApp的源码位于(packages\services\telephony\src\com\android\phone),不再在packages\apps\Phone。在(packages\services\Telephony\AndroidManifest.xml)文件配置了如下属性:

    <application android:name="PhoneApp"

                 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<N; 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<Phone>();

        mRingingCalls = new ArrayList<Call>();

        mBackgroundCalls = new ArrayList<Call>();

        mForegroundCalls = new ArrayList<Call>();

        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

 

 



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



3
0

猜你在找
深度学习基础与TensorFlow实践
【在线峰会】前端开发重点难点技术剖析与创新实践
【在线峰会】一天掌握物联网全栈开发之道
【在线峰会】如何高质高效的进行Android技术开发
机器学习40天精英计划
Python数据挖掘与分析速成班
微信小程序开发实战
JFinal极速开发企业实战
备战2017软考 系统集成项目管理工程师 学习套餐
Python大型网络爬虫项目开发实战(全套)
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:133807次
    • 积分:2144
    • 等级:
    • 排名:第16719名
    • 原创:85篇
    • 转载:20篇
    • 译文:0篇
    • 评论:44条
    最新评论