您的位置:首页 > 移动开发 > Android开发

Android Telephony启动过程源码分析

2014-10-27 20:20 162 查看



2 TelePhony启动代码分析:


1.1 Telephony启动流程图

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

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




2.1 Telephony关键类初始化


2.1.1 Phone进程启动

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

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

<application android:name="PhoneApp"

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<N; 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并实现了它本身,通过Stub的asInterface能够获取接口实例。接口里方法的实现最终是通过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 TelephonyRegistry向ServiceManager注册

在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中的客户端,分别调用他们当初注册的回调函数。mRecords是TelephonyRegistry核心维护的列表,其中每一项元素都是一个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应用的启动方式,查看MMS的manifest文件,发现并没有persistent的属性,

<application android:name="MmsApp"

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,

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

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

<receiver android:name=".transaction.MmsSystemEventReceiver">

<receiver android:name=".transaction.SmsReceiver">

<receiver android:name=".transaction.WapPushReceiver">


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。在这些类中关系如下,







我们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的初始化流程如下,鉴于上面已经有分析过程了,这里就不再对流程图做文字描述了。

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: