2 TelePhony启动代码分析:





1.1 Telephony启动流程图

结合代码分析过程,我们可以看出整个telephony的初始化流程如下,鉴于下面已经有分析过程,这里就不再对流程图做文字描述了。

需要注意的是,在每个类模块下面,类之间的上下关系表示初始化的前后顺序。

Android Telephony启动过程源码分析_第1张图片


2.1 Telephony关键类初始化

2.1.1 Phone进程启动

Phone就象个后台进程一样,开机即运行并一直存在(如果异常退出,它会自动重启)。

在系统开机启动时,由ActivityManagerService启动的。Phone的源码位于packages\apps\Phone。在Phone的AndroidManifest.xml文件配置了如下属性:

       

1.                  android:persistent="true"  

2.                  android:label="@string/dialerIconLabel"  

3.                  android:icon="@drawable/ic_launcher_phone">  

对于android:persistent="true" 的应用是在Android开机时启动的,在Android服务启动中,有三种启动方式(init.rc, persistent,BOOT_COMPLETED?),其中一种是在启动完成时通过调用systemReady函数来完成并通知服务启动。ActivityManagerService服务正是采用这种启动方式,对于属性android:persistent为true的应用是在ActivityManagerService服务启动完成后启动的:

1. public void systemReady(final Runnable goingCallback){  

2.     ......  

3.     if (goingCallback != null) goingCallback.run();  

4.     synchronized (this) {  

5.         if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {  

6.             try {  

7.                 //通过PackageManager查询到所有android:persistent属性为true的应用   

8.                 List apps = AppGlobals.getPackageManager().getPersistentApplications(STOCK_PM_FLAGS);  

9.                 if (apps != null) {  

10.                     int N = apps.size();  

11.                     int i;  

12.                     //遍历所有应用,并启动   

13.                     for (i=0; i

14.                         //得到每个应用的相关信息   

15.                         ApplicationInfo info= (ApplicationInfo)apps.get(i);  

16.                         //启动应用   

17.                         if (info != null &&!info.packageName.equals("android")) {  

18.                             addAppLocked(info);  

19.                         }  

20.                     }  

21.                 }  

22.             } catch (RemoteException ex) {  

23.                 // pm is in same process, this will never happen.   

24.             }  

25.         }  

26.         ........  

27.         mMainStack.resumeTopActivityLocked(null);  

28.     }  

29. }  

其中addAppLocked启动该应用,在调用startProcessLocked启动进程,PhoneAPP继承自Application,启动时调用它的onCreate函数,在里面则新建一个PhoneGlobals并调用它的onCreate函数。

    public PhoneApp() {

    }

    @Override

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

        }

    }

1.1.1 PhoneGlobals创建

如上,PhoneGlobals是在PhoneAPP创建,并调用它的onCreate函数,这里有一些重要的工作要做,如下,

Phone相关:

Phone实例没有创建的时候,对其进行相关的初始化,如果PhoneApp重启,因为之前phone实例已经创建过,则不需要再初始化,避免Telephony重新初始化,耗费资源和时间。

创建Phone实例,

PhoneFactory.makeDefaultPhones(this);

启动TelephonyDebugService

            Intent intent = new Intent(this, TelephonyDebugService.class);

            startService(intent);

registerPhone,主要工作是创建一个CallManager,并根据多卡支持,将Phone实例和其中的方法RingingCall、BackgroundCall、ForegroundCall添加到CallManager里面,然后通过registerForPhoneStates,向Phone注册相关事件。

    private void registerPhone() {

        mCM = CallManager.getInstance();

        if (GeminiUtils.isGeminiSupport()) {

            mCMGemini = MTKCallManager.getInstance();

            mCMGemini.registerPhoneGemini(phone);

        } else {

            mCM.registerPhone(phone);

        }

    }

public boolean registerPhone(Phone phone) {

registerOnePhone()

。。。

registerForPhoneStates() //向phone注册

}

    private boolean registerOnePhone(Phone phone) {

       boolean result = false;

        Phone basePhone = getPhoneBase(phone);

        if (basePhone != null && !mPhones.contains(basePhone)) {

            if (DBG) {

                Log.d(LOG_TAG, "[BSPPackage]registerPhone(" + phone.getPhoneName() + " " + phone + ")");

            }

            mPhones.add(basePhone);

            mRingingCalls.add(basePhone.getRingingCall());

            mBackgroundCalls.add(basePhone.getBackgroundCall());

            mForegroundCalls.add(basePhone.getForegroundCall()); 

            result = true;   

        }

        return result;

    }

NotificationMgr、PhoneInterfaceManager、PhoneInterfaceManagerEx的实例获取,如不存在则需要创建实例。

BluetoothPhoneService、Ringer、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:通话过程中的按钮功能以及来电接听时的滑动接听功能。
ManageConferenceUtils:管理多方通话的工具,包括部分UI元素。借助PhoneUtils实现其功能。
DTMFTwelveKeyDialer:通话状态时的拨号盘,用于发送DTMF。
DTMFTwelveKeyDialerView:DTMF拨号视图布局类。
InCallControlState:维护着一些状态信息,诸如是否Enable了Speaker声音免提、是否可以添加新的一路通话等等。它是MVC模式的数据部分。
InCallMenu:通话状态菜单,里面包含各个菜单项

PhoneGlobalsBroadcastReceiver、MediaButtonReceiver的注册。

其他的处理:

AudioManager等创建。

SimAssociateHandler创建并加载数据。

cellConnMgr、SIMInfoWrapper、CallHistoryDatabaseHelper、PhoneNumberUtil等相关类创建和初始化。

1.1.1 PhoneFactory创建

在PhoneGlobals.java (packages\services\telephony\src\com\android\phone)文件的onCreate()方法中,调用PhoneFactory.makeDefaultPhones来创建Phone相关实例,通过getDefaultPhone获取实例引用。

         if (phone == null) {

            // Initialize the telephony framework

            PhoneFactory.makeDefaultPhones(this);

            // Get the default phone

            phone = PhoneFactory.getDefaultPhone();

1.1.2 Phone创建

通过PhoneFactory.makeDefaultPhones就创建了Phone实例,创建中主要完成的工作有:

(MTK代码有封装,参考googl原生代码。)

public static void makeDefaultPhone(Context context) {

                sLooper = Looper.myLooper(); //创建一个looper

                sContext = context;   // 赋值context

                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接口

                UiccController.make(context, sCommandsInterface); //卡操作实例

                 // 新建phone示例,实际就是PhoneProxy实例,同时新建一个GSMPhone做参数

                sProxyPhone = new PhoneProxy(new GSMPhone(context,

                            sCommandsInterface, sPhoneNotifier));

1.1.3 SIMRecords初始化

SIMRecords实例由UiccCardApplication创建:

UiccCardApplication.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)

     private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) {

        if(DBG) log("createIccRecords, AppType = " + type);

        if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {

            return new SIMRecords(this, c, ci);

。。。

UiccCardApplication实例由UiccCard创建:

UiccCard.java (frameworks\opt\telephony\src\java\com\android\internal\telephony):

                         mUiccApplications[i] = new UiccCardApplication(this,

                                ics.mApplications[i], mContext, mCi);

UiccCard实例由UiccController创建:

UiccController.java (frameworks\opt\telephony\src\java\com\android\internal\telephony\uicc)

    private synchronized void onGetIccCardStatusDone(AsyncResult ar) {

        if (mUiccCard == null) {

            //Create new card

            mUiccCard = new UiccCard(mContext, mCi, status, mSimId);

        } else {

            //Update already existing card

            mUiccCard.update(mContext, mCi , status);

        }

。。。

UiccController实例由UiccController.make()创建,UiccController.make()在PhoneFactory里被调用:

PhoneFactory.java (frameworks\opt\telephony\src\java\com\android\internal\telephony):

    public static void makeDefaultPhone(Context context) {

。。。

                // Instantiate UiccController so that all other classes can just call getInstance()

                UiccController.make(context, sCommandsInterface);

1.1.4 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.5 ITelephonyRegistry

ItelephonyRegistry是一个接口,继承自IInterface,它有一个static类型的抽象内部类Stub,继承自Binder并实现了它本身,通过StubasInterface能够获取接口实例。接口里方法的实现最终是通过Stub的子类Proxy实现的,

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而来,后面分析其初始化过程。

1.1.6 TelephonyRegistryServiceManager注册

在SystemServer.java文件,在ServerThread.run()里面,为每张卡向ServiceManager注册了一个telephonyRegistry,这个注册过程实际上就是绑定了一个Ibinder

             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

TelephonyRegistry是一个服务,就需要去向ServiceManager先注册自己。再作为一个服务为客户提供注册,注册的过程其实就是把客户端添加到一个叫做mRecords的列表中,当Phone状态改变后,TelephonyRegistry会遍历mRecords中的客户端,分别调用他们当初注册的回调函数。mRecordsTelephonyRegistry核心维护的列表,其中每一项元素都是一个Record型的数据结构,代表着一个客户端

    根据Record的数据结构,客户端注册监听器时,需要提供一个IPhoneStateListener类型的对象,IPhoneStateListener接口定义了有关Phone各个状态的监听器的回调函数。

     private static class Record {

        String pkgForDebug;

        IBinder binder;

        IPhoneStateListener callback;

        int callerUid;

        int events;

    }               

客户端指定了自己所关注的状态,同时提供自己对该状态的回调函数,当相应的事件发生时,TelephonyRegistry就会去调用客户端的回调函数IPhoneStateListener。

1.1.7 TelephonyManager

TelephonyManager的创建比较特殊,有两种实例创建,

其一是在ContextImpl里面,创建TelephonyManager实例,并向context注册,方便后面能够通过context.getSystemService获取到实例。

                registerService(TELEPHONY_SERVICE, new ServiceFetcher() {

                public Object createService(ContextImpl ctx) {

                    return new TelephonyManager(ctx.getOuterContext());

                }});

还一种是在TelephonyManager类文件里,new一个实例,其他一些应用中,使用getDefault获得引用,进行方法调用。

     private static TelephonyManager sInstance = new TelephonyManager();

    /** @hide

    /* @deprecated - use getSystemService as described above */

    public static TelephonyManager getDefault() {

        return sInstance;

    }

至于为什么new出两个实例,具体是如何分别使用的,尚不清楚。

在TelephonyManager通过getITelephony获取服务实例,

    private ITelephony getITelephony() {

        return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));

    } 

通过listen为客户提供向getITelephony注册的服务。也就是说,客户端 如果想要实现对TelephonyRegistry的监听,可以先得到TelephonyManager的服务,然后通过这个服务调用其listen方法 把当前客户端注册给TelephonyRegistry,当Phone状态改变时,再由TelephonyRegistry发送通知给当前客户端

1.1.8 Service

上面提到了两种service,这里简单比较一下。

TelephonyManager所属的service通过在context 创建, 通过registerService存放在一个hashMap里面,通过context.getSystemService获取到实例,是一个普通类。

TelephonyRegistry所属的service通过在ServiceManager创建,通过ServiceManager.addService存放在hashMap里,通过ServiceManager.getService获取到实例,用IBinder方式使用。

1.1.9 Message加载

对比Phone应用的启动方式,查看MMSmanifest文件,发现并没有persistent的属性, 

    

            android:label="@string/app_label"

            android:icon="@mipmap/ic_launcher_smsmms"

            android:taskAffinity="android.task.mms"

            android:allowTaskReparenting="true"

            android:supportsRtl="true">

显然它不是用和Phone相同方式启动的。

应用启动还有一种方式,就是在manifest文件里注册RECEIVE_BOOT_COMPLETED,

然后定义一个receiver,继承自BroadcastReceiver,接收到事件BOOT_COMPLETED后,启动相关服务。在6572,有三个这样的receiver

1.1.10 Isms 

Isms

接口,继承自IInterface,它有一个static类型的抽象内部类Stub,继承自Binder,并通过proxy实现了它本身。

  IccSmsInterfaceManager

抽象类,继承自ISms.Stub,实现了stub的方法。实现发送短信、操作SIM卡上短信相关数据等功能。

    SimSmsInterfaceManager

类,继承自IccSmsInterfaceManager,是实例创建的真正对象。内有handler处理事件。

  IccSmsInterfaceManagerProxy

类,继承自ISms.Stub,实现了stub的方法。方法的实现实际是对IccSmsInterfaceManager的一层封装,给上层提供了统一的借口,实际的功能还是通过IccSmsInterfaceManager来完成的。

Isms相关的类有IccSmsInterfaceManager,SimSmsInterfaceManager,IccSmsInterfaceManagerProxy,以及SMSDispatcher。在这些类中关系如下, 

 

Android Telephony启动过程源码分析_第2张图片

 

我们IccSmsInterfaceManagerProxy负责向上层的接口,SimSmsInterfaceManager本层功能实现,SMSDispatcher提供下一层的功能支撑。

这些对象的实例化过程如下:

SimSmsInterfaceManager的实例是在GsmPhone里面创建的,

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

            mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);

            mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);

            mSubInfo = new PhoneSubInfo(this);

IccSmsInterfaceManagerProxy在PhoneProxy里面创建,之后通过IccSmsInterfaceManager的实例进行实际操作,

    public PhoneProxy(PhoneBase phone) {

。。。

             mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy(

                    phone.getIccSmsInterfaceManager(), simId);

1.1.1 Contact加载

IccPhoneBookInterfaceManagerProxy在PhoneProxy里面创建,之后通过IccPhoneBookInterfaceManager的对象进行实际操作

    public PhoneProxy(PhoneBase phone) {

。。。

           mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(

                    phone.getIccPhoneBookInterfaceManager(), simId);            

1.1.2 PhoneSubInfo

PhoneSubInfoProxy在PhoneProxy里面创建,之后通过PhoneSubInfo的对象进行实际操作

    public PhoneProxy(PhoneBase phone) {

。。。

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

 

1.1 Telephony启动流程图

结合上面的代码分析过程,我们可以看出整个telephony的初始化流程如下,鉴于上面已经有分析过程了,这里就不再对流程图做文字描述了。

需要注意的是,在每个类模块下面,类之间的上下关系表示初始化的前后顺序。

Android Telephony启动过程源码分析_第3张图片

更多相关文章

  1. Android Gesture 手势识别使用实例
  2. Android 手写签名实例
  3. Android AIDL实例
  4. 使用表格布局编写登录页面实例
  5. Android自定义View之一:初探实例
  6. Android 动态注册监听网络变化实例详解

随机推荐

  1. MySQL 5.7忘记root密码后修改的详细教程
  2. MySQL execute、executeUpdate、executeQ
  3. MySQL绿色版设置编码以及1067错误详解
  4. Linux下MySQL5.7.18二进制包安装教程(无默
  5. Mysql 服务 1067 错误 的解决方法:修改my
  6. Mysql 5.7.18 解压版下载安装及启动mysql
  7. 解决Win7 x64安装解压版mysql 5.7.18 win
  8. Linux/Mac MySQL忘记密码命令行修改密码的
  9. MySQL对中文进行排序详解及实例
  10. Python MySQL进行数据库表变更和查询