Android的Phone设计的相当复杂,只有了解了Phone的设计框架才能把握电话的拨号或来电流程,在Android电话拨打流程源码分析中已经分析介绍了电话拨打流程,这里介绍一下电话的来电流程。

要理解这节内容,首先要知道Android电话的层次设计


Framework层的RIL中的RILReceiver线程从rild服务进程中读取modem发送上来的来电消息等信息,通过消息注册-响应机制来通知上层处理,上图清晰地显示了各层之间的消息处理关系,CallManager连接Framework层和应用层的Phone,

CallManager处理GSMPhone注册的消息事件,并且触发CallManager注册的消息事件,而CallNotifier处理CallManager消息,这样就将RIL层的消息一级一级传送的应用层的Phone了。

RIL层事件注册过程

frameworks\base\telephony\java\com\android\internal\telephony\ PhoneFactory.java

public static void makeDefaultPhone(Context context) {synchronized(Phone.class) {if (!sMadeDefaults) {sLooper = Looper.myLooper();sContext = context;if (sLooper == null) {throw new RuntimeException("PhoneFactory.makeDefaultPhone must be called from Looper thread");}int retryCount = 0;for(;;) {boolean hasException = false;retryCount ++;try {new LocalServerSocket("com.android.internal.telephony");} catch (java.io.IOException ex) {hasException = true;}if ( !hasException ) {break;} else if (retryCount > SOCKET_OPEN_MAX_RETRY) {throw new RuntimeException("PhoneFactory probably already running");} else {try {Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);} catch (InterruptedException er) {}}}sPhoneNotifier = new DefaultPhoneNotifier();// Get preferred network modeint preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {preferredNetworkMode = Phone.NT_MODE_GLOBAL;}//从数据库中读取网络模式int networkMode = Settings.Global.getInt(context.getContentResolver(),Settings.Global.PREFERRED_NETWORK_MODE, preferredNetworkMode);Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode));int cdmaSubscription;        int lteOnCdma = TelephonyManager.getLteOnCdmaModeStatic();switch (lteOnCdma) {case PhoneConstants.LTE_ON_CDMA_FALSE:cdmaSubscription = CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV;Log.i(LOG_TAG, "lteOnCdma is 0 use SUBSCRIPTION_FROM_NV");break;case PhoneConstants.LTE_ON_CDMA_TRUE:cdmaSubscription = CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM;Log.i(LOG_TAG, "lteOnCdma is 1 use SUBSCRIPTION_FROM_RUIM");break;case PhoneConstants.LTE_ON_CDMA_UNKNOWN:default://Get cdmaSubscription mode from Settings.SystemcdmaSubscription = Settings.Global.getInt(context.getContentResolver(),Settings.Global.PREFERRED_CDMA_SUBSCRIPTION,preferredCdmaSubscription);Log.i(LOG_TAG, "lteOnCdma not set, using PREFERRED_CDMA_SUBSCRIPTION");break;}Log.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);//reads the system properties and makes commandsinterfacesCommandsInterface = new RIL(context, networkMode, cdmaSubscription);// Instantiate UiccController so that all other classes can just call getInstance()UiccController.make(context, sCommandsInterface);  //根据网络模式得到电话类型int phoneType = TelephonyManager.getPhoneType(networkMode);//根据电话类型创建对应类型的Phone对象,并且使用创建的Phone对象来构造PhoneProxy代理对象if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {Log.i(LOG_TAG, "Creating GSMPhone");sProxyPhone = new PhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {switch (TelephonyManager.getLteOnCdmaModeStatic()) {case PhoneConstants.LTE_ON_CDMA_TRUE:Log.i(LOG_TAG, "Creating CDMALTEPhone");sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,sCommandsInterface, sPhoneNotifier));break;case PhoneConstants.LTE_ON_CDMA_FALSE:default:Log.i(LOG_TAG, "Creating CDMAPhone");sProxyPhone = new PhoneProxy(new CDMAPhone(context,sCommandsInterface, sPhoneNotifier));break;}}sMadeDefaults = true;}}}
在PhoneFactory的makeDefaultPhone函数中,首先构造一个DefaultPhoneNotifier对象和RIL对象,然后从数据库中读取网络模式,根据网络模式得到对应的电话类型,从而构造对应的Phone对象,并为该Phone对象创建一个PhoneProxy代理对象。对于GSM网络,会构造一个GSMPhone对象

frameworks\base\telephony\java\com\android\internal\telephony\gsm\ GSMPhone.java

public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {super(notifier, context, ci, unitTestMode);mCM.setPhoneType(Phone.PHONE_TYPE_GSM);mIccCard.set(MsUiccController.getInstance(this).getIccCard());mIccRecords = mIccCard.get().getIccRecords();mCT = new GsmCallTracker(this);mSST = new GsmServiceStateTracker (this);mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);if (!unitTestMode) {mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);mSubInfo = new PhoneSubInfo(this);}mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);registerForSimRecordEvents();mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);mCM.registerForOn(this, EVENT_RADIO_ON, null);mCM.setOnUSSD(this, EVENT_USSD, null);mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);mHandlerThread = new HandlerThread("GSMPhone_AsyncThread");mHandlerThread.start();mAsyncThread = new AsyncThread(mHandlerThread.getLooper());if (false) {try {//debugSocket = new LocalServerSocket("com.android.internal.telephony.debug");debugSocket = new ServerSocket();debugSocket.setReuseAddress(true);debugSocket.bind (new InetSocketAddress("127.0.0.1", 6666));debugPortThread= new Thread(new Runnable() {public void run() {for(;;) {try {Socket sock;sock = debugSocket.accept();Log.i(LOG_TAG, "New connection; resetting radio");mCM.resetRadio(null);sock.close();} catch (IOException ex) {Log.w(LOG_TAG,"Exception accepting socket", ex);}}}},"GSMPhone debug");debugPortThread.start();} catch (IOException ex) {Log.w(LOG_TAG, "Failure to open com.android.internal.telephony.debug socket", ex);}}//Change the system propertySystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,new Integer(Phone.PHONE_TYPE_GSM).toString());}
在构造GSMPhone对象时,首先使用父类的成员变量CommandsInterfac mCM设置电话类型,由于RIL类实现了CommandsInterfac接口,因此mCM引用RIL对象。在构造GSMPhone对象时通过参数传入并设置父类PhoneBase的成员变量mCM。

frameworks\base\telephony\java\com\android\internal\telephony\ PhoneBase.java

protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,boolean unitTestMode) {this.mNotifier = notifier;this.mContext = context;mLooper = Looper.myLooper();mCM = ci;setPropertiesByCarrier();setUnitTestMode(unitTestMode);SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);mCM.setOnCallRing(this, EVENT_CALL_RING, null);mIsVoiceCapable = mContext.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);mDoesRilSendMultipleCallRing = SystemProperties.getBoolean(TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true);Log.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);mCallRingDelay = SystemProperties.getInt(TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);Log.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);// Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.mSmsStorageMonitor = new SmsStorageMonitor(this);mSmsUsageMonitor = new SmsUsageMonitor(context);}
构造GSMPhone对象同时也会创建一个GsmCallTracker对象,GSMCallTracker实现了电话的拨打(Dial)、接听/拒绝(accept/reject)、挂断(hangup)、保持(hold)、切换以及电话会议等功能,它还负责查询Modem当前有多少路通话,维护电话状态等功能。GSMCallTracker中包含了GsmConnection、RegistrantList、 GSMCall和Phone.State等类的对象实例。在GSMCallTracker构造函数中向RIL类实例注册了RegistrantList,当通话状态及射频Radio状态变化时,就会通知GSMCallTracker。
frameworks\base\telephony\java\com\android\internal\telephony\gsm\ GsmCallTracker.java
GsmCallTracker (GSMPhone phone) {this.phone = phone;cm = phone.mCM;cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);cm.registerForVideoCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null);cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);sendEmptyMessage(EVENT_INITIALIZE);}
cm引用RIL对象,在这里注册了电话状态改变事件,视频电话状态改变事件,无线开关事件等。由于RIL实现了CommandsInterface接口,并继承于BaseCommands抽象类,registerForCallStateChanged函数实现在RIL的父类BaseCommands中

这里为RIL注册了一些消息事件,并指定GsmCallTracker来处理这些消息。
frameworks\base\telephony\java\com\android\internal\telephony\BaseCommands.java

public void registerForCallStateChanged(Handler h, int what, Object obj) {Registrant r = new Registrant (h, what, obj);mCallStateRegistrants.add(r);}
该函数通过Handler及对应的事件消息来构造一个Registrant对象,并将其注册到mCallStateRegistrants对象中,mCallStateRegistrants为RegistrantList类型变量,定义在RIL的父类BaseCommands中,RegistrantList类是用于保存注册的处理指定消息的所有Handler,RegistrantList类首先将某个消息及处理该消息的Handler封装成Registrant对象,并将该对象保存到成员变量registrants动态数组中。
frameworks\base\core\java\android\os\RegistrantList.java

ArrayList   registrants = new ArrayList();     public synchronized void add(Handler h, int what, Object obj){add(new Registrant(h, what, obj));}public synchronized void add(Registrant r){removeCleared();registrants.add(r);}
对于电话状态改变事件,注册的Handle对象为GsmCallTracker,因此在电话状态改变事件到来时,GsmCallTracker将处理EVENT_CALL_STATE_CHANGE消息事件。


GsmCallTracker有三个成员变量:

GsmCall ringingCall = new GsmCall(this) 前台Call,其中对应的Connection是ACTIVE,DIALING,ALERTING状态的,即激活状态
GsmCall foregroundCall = new GsmCall(this)后台Call,其中对应的Connection是HOLDING状态的,即保持状态
GsmCall backgroundCall = new GsmCall(this)来电Call,其中对应的Connection是INCOMING,WAITING状态的,即来电状态

Phone层事件注册过程

在Phone进程启动的时,PhoneApp的onCreate函数首先被调用,PhoneApp会构造各种全局对象,同时也会注册一些事件。
mCM = CallManager.getInstance();mCM.registerPhone(phone);
函数registerPhone为构造的相应类型的phone对象注册一些事件 frameworks\base\telephony\java\com\android\internal\telephony\CallManager.java
public boolean registerPhone(Phone phone) {    Phone basePhone = getPhoneBase(phone);    if (basePhone != null && !mPhones.contains(basePhone)) {        if (DBG) {            Log.d(LOG_TAG, "registerPhone(" +                    phone.getPhoneName() + " " + phone + ")");        }        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;}
registerForPhoneStates函数用于注册电话状态变化事件
private void registerForPhoneStates(Phone phone) {    // for common events supported by all phones    phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);    phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);    phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);    phone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null);    phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);    phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);    phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);    phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);    phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);    phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);    phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);    phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);    phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);    phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);    phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);    // for events supported only by GSM and CDMA phone    if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ||            phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {        phone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL_CHARACTER, null);    }    // for events supported only by CDMA phone    if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ){        phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);        phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);        phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);        phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);    }}
此时的Phone类型为GsmPhone,其父类为PhoneBase,这里为PhoneBase注册了一些消息事件,并指定CallManager类的mHandler来处理这些消息。

CallManager层事件注册过程

在启动PhoneApp时,同样也会创建一个CallNotifier对象
notifier = CallNotifier.init(this, phone, ringer, mBtHandsfree, new CallLogAsync());
参数phone是通过PhoneFactory.getDefaultPhone()创建而来的,创建过程在前面已经详细介绍了。
参数ringer的构造过程如下:
ringer = Ringer.init(this);static Ringer init(Context context) {    synchronized (Ringer.class) {        if (sInstance == null) {            sInstance = new Ringer(context);        } else {            Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);        }        return sInstance;    }}private Ringer(Context context) {    mContext = context;    mPowerManager = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));    mVibrator = new SystemVibrator();}
参数mBtHandsfree的构造过程如下:
mBtHandsfree = BluetoothHandsfree.init(this, mCM);static BluetoothHandsfree init(Context context, CallManager cm) {    synchronized (BluetoothHandsfree.class) {        if (sInstance == null) {            sInstance = new BluetoothHandsfree(context, cm);        } else {            Log.wtf(TAG, "init() called multiple times!  sInstance = " + sInstance);        }        return sInstance;    }}
CallNotifier对象构造过程:
packages\apps\Phone\src\com\android\phone\CallNotifier.java
static CallNotifier init(PhoneApp app, Phone phone, Ringer ringer,                                       BluetoothHandsfree btMgr, CallLogAsync callLog) {    synchronized (CallNotifier.class) {        if (sInstance == null) {            sInstance = new CallNotifier(app, phone, ringer, btMgr, callLog);        } else {            Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);        }        return sInstance;    }}protected CallNotifier(PhoneApp app, Phone phone, Ringer ringer,                     BluetoothHandsfree btMgr, CallLogAsync callLog) {    mApplication = app;    mCM = app.mCM;    mCallLog = callLog;    mLndAsync = new LndAsync();    telMgr = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);    mAudioManager = (AudioManager) mApplication.getSystemService(Context.AUDIO_SERVICE);    registerForNotifications();    try {        mSignalInfoToneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL,                TONE_RELATIVE_VOLUME_SIGNALINFO);    } catch (RuntimeException e) {        Log.e(LOG_TAG, "CallNotifier: Exception caught while creating " +                "mSignalInfoToneGenerator: " + e);        mSignalInfoToneGenerator = null;    }    mRinger = ringer;    mBluetoothHandsfree = btMgr;    listen();}
这构造CallNotifier对象过程中,为CallManager层注册了一些消息事件,并指定CallNotifier来处理这些消息
private void registerForNotifications() {    mCM.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);    mCM.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null);    mCM.registerForDisconnect(this, PHONE_DISCONNECT, null);    mCM.registerForUnknownConnection(this, PHONE_UNKNOWN_CONNECTION_APPEARED, null);    mCM.registerForIncomingRing(this, PHONE_INCOMING_RING, null);    mCM.registerForCdmaOtaStatusChange(this, EVENT_OTA_PROVISION_CHANGE, null);    mCM.registerForCallWaiting(this, PHONE_CDMA_CALL_WAITING, null);    mCM.registerForDisplayInfo(this, PHONE_STATE_DISPLAYINFO, null);    mCM.registerForSignalInfo(this, PHONE_STATE_SIGNALINFO, null);    mCM.registerForInCallVoicePrivacyOn(this, PHONE_ENHANCED_VP_ON, null);    mCM.registerForInCallVoicePrivacyOff(this, PHONE_ENHANCED_VP_OFF, null);    mCM.registerForRingbackTone(this, PHONE_RINGBACK_TONE, null);    mCM.registerForResendIncallMute(this, PHONE_RESEND_MUTE, null);}
1.当有PHONE_NEW_RINGING_CONNECTION类型消息到来时,意味着一个RINGING或WAITING的连接(connection)出现,此时handleMessage函数调用onNewRingingConnection来处理。后者先检查Settings里的设置是否可以接听电话;然后进 行响铃(见InCallTonePlayer)和显示InCallScreen的UI,见PhoneUtils.showIncomingCallUi()和PhoneApp.displayCallScreen()两个函数。通话过程中的铃音提示由线程类InCallTonePlayer完成。
2.当有PHONE_INCOMING_RING类型的消息到来时,意味着RIL层受到Ring,此处播放铃音。它使用的是Ringer.ring()函数,它会创建一个线程去播放铃音,见Ringer.makeLooper函数。
3.当有PHONE_STATE_CHANGED消息时,表明Phone的状态发生了改变,比如响铃后接通了电话,此时处理函数是onPhoneStateChanged,比如再次确认停止铃音、更新状态栏列的状态通知等。
4.当有PHONE_DISCONNECT消息时,表明电话连接已挂断或RingCall断掉。其处理函数是onDisconnect。它清理现场诸如音频通道恢复、来电响铃的停止确认、对InCallScreen的UI清理、若有未接电话须在状态栏显示等。
CallManager类的消息注册方法:

电话状态改变事件处理

我们已经知道在RIL中分别创建了两个线程,一个用于往rild套接字中写入数据,一个用于从该套接字中读取rild服务进程发送上来的数据。对于来电事件,RILReceiver会读取到rild发送过来的来电信息。

frameworks\base\telephony\java\com\android\internal\telephony\RIL.java

try {InputStream is = mSocket.getInputStream();for (;;) {Parcel p;//从rild套接字中读取消息length = readRilMessage(is, buffer);if (length < 0) {// End-of-stream reachedbreak;}//将读取到的数据序列化到Parcel对象中p = Parcel.obtain();p.unmarshall(buffer, 0, length);p.setDataPosition(0);//数据处理processResponse(p);p.recycle();}} catch (java.io.IOException ex) {Log.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed", ex);} catch (Throwable tr) {Log.e(LOG_TAG, "Uncaught exception read length=" + length +"Exception:" + tr.toString());}
这段代码是RILReceiver线程不断循环读取来自rild的AT Response,调用processResponse进行处理,根据返回结果中不同的Request号,调用到相应的responseXXX函数簇,获取AT执行结果。

private void processResponse (Parcel p) {int type;type = p.readInt();if (type == RESPONSE_UNSOLICITED) {processUnsolicited (p);} else if (type == RESPONSE_SOLICITED) {processSolicited (p);}releaseWakeLockIfDone();}

在Android之rild进程启动源码分析介绍了,rild服务进程会接收到两种类型的消息,一种是Ap向Bp发送请求,Bp给Ap发送回复消息,一种是Bp主动给Ap发送事件,对于请求响应事件,调用processSolicited函数来处理,而对于BP主动发起的事件则调用processUnsolicited函数来处理。来电属于BP主动发起的请求事件,因此processUnsolicited函数将处理来电请求

protected void processUnsolicited (Parcel p) {int response;Object ret;response = p.readInt();try {switch(response) {case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret =  responseVoid(p); break;         default:throw new RuntimeException("Unrecognized unsol response: " + response);}} catch (Throwable tr) {Log.e(LOG_TAG, "Exception processing unsol response: " + response +"Exception:" + tr.toString());return;}switch(response) {case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:if (RILJ_LOGD) unsljLog(response);mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));break;}}
mCallStateRegistrants为RegistrantList类型变量,前面已经介绍了消息注册过程,这里调用RegistrantList的notifyRegistrants函数来通知所有注册过该消息的Handler处理该消息。

frameworks\base\core\java\android\os\RegistrantList.java

public void  notifyRegistrants(){internalNotifyRegistrants(null, null);}private synchronized void  internalNotifyRegistrants (Object result, Throwable exception){   for (int i = 0, s = registrants.size(); i < s ; i++) {Registrant  r = (Registrant) registrants.get(i);r.internalNotifyRegistrant(result, exception);   }}
这里循环遍历成员变量registrants中保存的所有Registrant对象,前面介绍到,在注册某个Handler处理指定消息时,首先将其封装为Registrant对象,这里取出该消息对应的所有Registrant对象,并调用该对象的internalNotifyRegistrant函数来触发注册的Handler处理该消息。
frameworks\base\core\java\android\os\Registrant.java
void internalNotifyRegistrant (Object result, Throwable exception){Handler h = getHandler();if (h == null) {clear();} else {Message msg = Message.obtain();msg.what = what;msg.obj = new AsyncResult(userObj, result, exception);h.sendMessage(msg);}}
该函数其是就是向注册的Handler中发送消息,消息为注册的消息类型。由于在构造GsmCallTracker对象时,已经在BaseCommands中注册了EVENT_CALL_STATE_CHANGE消息的处理Handler为GsmCallTracker对象本身,

cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);

因此mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null))将向GsmCallTracker对象发送EVENT_CALL_STATE_CHANGE的消息

frameworks\base\telephony\java\com\android\internal\telephony\CallTracker.java

public void handleMessage (Message msg) {     AsyncResult ar;     switch (msg.what) {       case EVENT_CALL_STATE_CHANGE:            pollCallsWhenSafe();          break;     }}
函数最终调用pollCallsWhenSafe来处理EVENT_CALL_STATE_CHANGE消息,pollCallsWhenSafe用于查询当前的通话状态。

protected void pollCallsWhenSafe() {needsPoll = true;if (checkNoOperationsPending()) {lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);cm.getCurrentCalls(lastRelevantPoll);}}
函数checkNoOperationsPending就是判断变量pendingOperations是否等于0,如果等于0,则调用CommandsInterface的getCurrentCalls函数来发送一个EVENT_POLL_CALLS_RESULT消息,该函数实现在RIL.java中。

AT命令CLCC查询结果对应于Connection类中的成员变量,一 路电话对应一个对象。

frameworks\base\telephony\java\com\android\internal\telephony\RIL.java

public void getCurrentCalls (Message result) {RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));send(rr);}

函数首先根据传进来的参数获取一个RILRequest请求对象,并调用send函数通过RILSender线程向rild服务进程发送RIL_REQUEST_GET_CURRENT_CALLS请求,请求查询当前所有的电话连接,使用CLCC 命令查询,底层返回来的查询结果如下 格式 |序号|0表示来电、1表示去电|电话状态|数据业务还是语音业务|是否是视频会议|号码

CLCC : 1、 0、 2、 0、 0 1881234578 …..

每个通话连接用通话列表用DriverCall类表示。

这里介绍一下RILRequest数据结构

Android使用了一个RILRequest对象池来管理RILRequest


static RILRequest obtain(int request, Message result) {    RILRequest rr = null;    synchronized(sPoolSync) {        if (sPool != null) {            rr = sPool;            sPool = rr.mNext;            rr.mNext = null;            sPoolSize--;        }    }    if (rr == null) {        rr = new RILRequest();    }    synchronized(sSerialMonitor) {        rr.mSerial = sNextSerial++;    }    rr.mRequest = request;    rr.mResult = result;    rr.mp = Parcel.obtain();    if (result != null && result.getTarget() == null) {        throw new NullPointerException("Message target must not be null");    }    rr.mp.writeInt(request);    rr.mp.writeInt(rr.mSerial);    return rr;}
当Phone进程从framework层向rild服务进程发送完RIL_REQUEST_GET_CURRENT_CALLS请求后,就等待接收rild返回对该消息的处理结果,RILReceiver线程将读取到该消息事件,并调用processSolicited函数来处理。

frameworks\base\telephony\java\com\android\internal\telephony\RIL.java

protected void processSolicited (Parcel p) {    int serial, error;    boolean found = false;    serial = p.readInt();    error = p.readInt();    RILRequest rr;    rr = findAndRemoveRequestFromList(serial);    if (rr == null) {        Log.w(LOG_TAG, "Unexpected solicited response! sn: "+ serial + " error: " + error);        return;    }    Object ret = null;    if (error == 0 || p.dataAvail() > 0) {        try {          switch (rr.mRequest) {case RIL_REQUEST_GET_CURRENT_CALLS: ret =  responseCallList(p); break;}} catch (Throwable tr) {            if (rr.mResult != null) {                AsyncResult.forMessage(rr.mResult, null, tr);                rr.mResult.sendToTarget();            }            rr.release();            return;        }    }    if (error != 0) {        rr.onError(error, ret);        rr.release();        return;    }    if (rr.mResult != null) {        AsyncResult.forMessage(rr.mResult, ret, null);        rr.mResult.sendToTarget();    }    rr.release();}

读取RIL请求序列号并依次在RILRequest列表中查找已发送过的RILRequest请求

protected RILRequest findAndRemoveRequestFromList(int serial) {    synchronized (mRequestsList) {    // 通过序号从变量列表mRequestsList中查找出指定的RILRequest        for (int i = 0, s = mRequestsList.size() ; i < s ; i++) {            RILRequest rr = mRequestsList.get(i);            if (rr.mSerial == serial) {                mRequestsList.remove(i);                if (mRequestMessagesWaiting > 0)                    mRequestMessagesWaiting--;                return rr;            }        }    }    return null;}
若AT执行成功并有结果数据需要获取,则进入到switch-case语句根据请求号调用相应的responseXXX函数获得AT执行结果数据,放置在Object对象ret中;在取AT执行结果时若有异常发生,则ret保持为null空值。若AT执行发生错误时,则调用RILRequest的onError函数,这里的请求号为RIL_REQUEST_GET_CURRENT_CALLS,因此通过函数responseCallList读取查询结果

protected Object responseCallList(Parcel p) {    int num;    int voiceSettings;    ArrayList<DriverCall> response; //保存通话列表    DriverCall dc;    num = p.readInt();//读取通话列表数目    response = new ArrayList<DriverCall>(num);    //根据CLCC查询到的通话列表创建DriverCall    for (int i = 0 ; i < num ; i++) {        dc = new DriverCall();        dc.state = DriverCall.stateFromCLCC(p.readInt());        dc.index = p.readInt();        dc.TOA = p.readInt();        dc.isMpty = (0 != p.readInt());        dc.isMT = (0 != p.readInt());        dc.als = p.readInt();        voiceSettings = p.readInt();        dc.isVoice = (0 == voiceSettings) ? false : true;        dc.isVoicePrivacy = (0 != p.readInt());        dc.number = p.readString();        int np = p.readInt();        dc.numberPresentation = DriverCall.presentationFromCLIP(np);        dc.name = p.readString();        dc.namePresentation = p.readInt();        int uusInfoPresent = p.readInt();        if (uusInfoPresent == 1) {            dc.uusInfo = new UUSInfo();            dc.uusInfo.setType(p.readInt());            dc.uusInfo.setDcs(p.readInt());            byte[] userData = p.createByteArray();            dc.uusInfo.setUserData(userData);            riljLogv(String.format("Incoming UUS : type=%d, dcs=%d, length=%d",                            dc.uusInfo.getType(), dc.uusInfo.getDcs(),                            dc.uusInfo.getUserData().length));            riljLogv("Incoming UUS : data (string)="                    + new String(dc.uusInfo.getUserData()));            riljLogv("Incoming UUS : data (hex): "                    + IccUtils.bytesToHexString(dc.uusInfo.getUserData()));        } else {            riljLogv("Incoming UUS : NOT present!");        }        // Make sure there's a leading + on addresses with a TOA of 145        dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA);        response.add(dc);        if (dc.isVoicePrivacy) {            mVoicePrivacyOnRegistrants.notifyRegistrants();            riljLog("InCall VoicePrivacy is enabled");        } else {            mVoicePrivacyOffRegistrants.notifyRegistrants();            riljLog("InCall VoicePrivacy is disabled");        }    }    Collections.sort(response);    if ((num == 0) && mTestingEmergencyCall.getAndSet(false)) {        if (mEmergencyCallbackModeRegistrant != null) {            riljLog("responseCallList: call ended, testing emergency call," +                        " notify ECM Registrants");            mEmergencyCallbackModeRegistrant.notifyRegistrant();        }    }    return response;}

GsmConnection的集合connections集合对象是一个数组,数组编号是从0开始的,所以我们会看到会有一个dc.index == i+1;的操作,对应关系就是这里建立的。之后会把底层查的DriverCall对象和GsmCallTracker中保存的GsmConnection对象进行比较。如DriverCall对象为空,我们本地保持的GsmConnection对象存在,很显然,是这路电话挂断了,反之如过DriverCall对象有,GsmConnection对象不存在,则是一个来电。最后使用forMessage函数将返回的结果封装到Message中的 obj中,并发送的消息的目标Handler处理,前面发送的是RIL_REQUEST_GET_CURRENT_CALLS请求,该请求中包含的一个EVENT_POLL_CALLS_RESULT消息。由于EVENT_POLL_CALLS_RESULT消息是从CallTracker中发出来的,而CallTracker是个抽象类,其handleMessage函数是由其子类GsmCallTracker实现的,因此EVENT_POLL_CALLS_RESULT是由GsmCallTracker来处理

frameworks\base\telephony\java\com\android\internal\telephony\gsm\GsmCallTracker.java

public void handleMessage (Message msg) {AsyncResult ar;switch (msg.what) {case EVENT_POLL_CALLS_RESULT:ar = (AsyncResult)msg.obj;if (msg == lastRelevantPoll) {needsPoll = false;lastRelevantPoll = null;handlePollCalls((AsyncResult)msg.obj);mMoveToBack = false;}break;}}

msg.obj中保存了查询到的所有DriverCall,函数直接调用handlePollCalls进行处理

protected synchronized void handlePollCalls(AsyncResult ar) {    List polledCalls;    if (ar.exception == null) {        polledCalls = (List)ar.result;    } else if (isCommandExceptionRadioNotAvailable(ar.exception)) {        // just a dummy empty ArrayList to cause the loop        // to hang up all the calls        polledCalls = new ArrayList();    } else {        // Radio probably wasn't ready--try again in a bit        // But don't keep polling if the channel is closed        pollCallsAfterDelay();        return;    }    Connection newRinging = null; //or waiting    boolean hasNonHangupStateChanged = false;   // Any change besides    boolean needsPollDelay = false;    boolean unknownConnectionAppeared = false;    for (int i = 0, curDC = 0, dcSize = polledCalls.size(); i < connections.length; i++) {        GsmConnection conn = connections[i];        DriverCall dc = null;        // polledCall list is sparse        if (curDC < dcSize) {            dc = (DriverCall) polledCalls.get(curDC);            if (dc.index == i+1) {                curDC++;            } else {                dc = null;            }        }        if (conn == null && dc != null) {            // Connection appeared in CLCC response that we don't know about            if (pendingMO != null && pendingMO.compareTo(dc)) {                if (DBG_POLL) log("poll: pendingMO=" + pendingMO);                // It's our pending mobile originating call                connections[i] = pendingMO;                pendingMO.index = i;                pendingMO.update(dc);                pendingMO = null;                // Someone has already asked to hangup this call                if (hangupPendingMO) {                    hangupPendingMO = false;                    try {                        hangup(connections[i]);                    } catch (CallStateException ex) {                        Log.e(LOG_TAG, "unexpected error on hangup");                    }                    return;                }            } else {                connections[i] = new GsmConnection(phone.getContext(), dc, this, i);                // it's a ringing call                if (connections[i].getCall() == ringingCall) {                    newRinging = connections[i];                } else {                    if (dc.state != DriverCall.State.ALERTING                            && dc.state != DriverCall.State.DIALING) {                        connections[i].connectTime = System.currentTimeMillis();                    }                    unknownConnectionAppeared = true;                }            }            hasNonHangupStateChanged = true;        } else if (conn != null && dc == null) {            // Connection missing in CLCC response that we were            // tracking.            droppedDuringPoll.add(conn);            // Dropped connections are removed from the CallTracker            // list but kept in the GsmCall list            connections[i] = null;        } else if (conn != null && dc != null && !conn.compareTo(dc)) {            // Connection in CLCC response does not match what            // we were tracking. Assume dropped call and new call            droppedDuringPoll.add(conn);            connections[i] = new GsmConnection (phone.getContext(), dc, this, i);            if (connections[i].getCall() == ringingCall) {                newRinging = connections[i];            } // else something strange happened            hasNonHangupStateChanged = true;        } else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */            boolean changed;            changed = conn.update(dc);            hasNonHangupStateChanged = hasNonHangupStateChanged || changed;        }        if (REPEAT_POLLING) {            if (dc != null) {                // FIXME with RIL, we should not need this anymore                if ((dc.state == DriverCall.State.DIALING                        /*&& cm.getOption(cm.OPTION_POLL_DIALING)*/)                    || (dc.state == DriverCall.State.ALERTING                        /*&& cm.getOption(cm.OPTION_POLL_ALERTING)*/)                    || (dc.state == DriverCall.State.INCOMING                        /*&& cm.getOption(cm.OPTION_POLL_INCOMING)*/)                    || (dc.state == DriverCall.State.WAITING                        /*&& cm.getOption(cm.OPTION_POLL_WAITING)*/)                ) {                    // Sometimes there's no unsolicited notification                    // for state transitions                    needsPollDelay = true;                }            }        }    }    // This is the first poll after an ATD.    // We expect the pending call to appear in the list    // If it does not, we land here    if (pendingMO != null) {        droppedDuringPoll.add(pendingMO);        pendingMO = null;        hangupPendingMO = false;    }    if (newRinging != null) {        phone.notifyNewRingingConnection(newRinging);    }    // clear the "local hangup" and "missed/rejected call"    // cases from the "dropped during poll" list    // These cases need no "last call fail" reason    for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) {        GsmConnection conn = droppedDuringPoll.get(i);        if (conn.isIncoming() && conn.getConnectTime() == 0) {            // Missed or rejected call            Connection.DisconnectCause cause;            if (conn.cause == Connection.DisconnectCause.LOCAL) {                cause = Connection.DisconnectCause.INCOMING_REJECTED;            } else {                cause = Connection.DisconnectCause.INCOMING_MISSED;            }            droppedDuringPoll.remove(i);            conn.onDisconnect(cause);        } else if (conn.cause == Connection.DisconnectCause.LOCAL) {            // Local hangup            droppedDuringPoll.remove(i);            conn.onDisconnect(Connection.DisconnectCause.LOCAL);        } else if (conn.cause ==            Connection.DisconnectCause.INVALID_NUMBER) {            droppedDuringPoll.remove(i);            conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER);        }    }    // Any non-local disconnects: determine cause    if (droppedDuringPoll.size() > 0) {        cm.getLastCallFailCause(obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE));    }    if (needsPollDelay) {        pollCallsAfterDelay();    }    // Cases when we can no longer keep disconnected Connection's    // with their previous calls    // 1) the phone has started to ring    // 2) A Call/Connection object has changed state...    //    we may have switched or held or answered (but not hung up)    if (newRinging != null || hasNonHangupStateChanged) {        internalClearDisconnected();    }    updatePhoneState();    if (unknownConnectionAppeared) {        phone.notifyUnknownConnection();    }    if (hasNonHangupStateChanged || newRinging != null) {        phone.notifyPreciseCallStateChanged();    }}
对于新的来电使用phone.notifyNewRingingConnection(newRinging)触发CallManager中的mHandler来处理该消息,在前面介绍了在构造PhoneApp的onCreate函数中,首先得到CallManager实例对象,然后调用该对象的registerPhone方法为Phone层注册消息事件,注册的处理消息的Handler为CallManager的变量mHandler。

frameworks\base\telephony\java\com\android\internal\telephony\CallManager.java

public void handleMessage(Message msg) {switch (msg.what) {    case EVENT_NEW_RINGING_CONNECTION:        if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)");        if (getActiveFgCallState().isDialing() || hasMoreThanOneRingingCall()) {            Connection c = (Connection) ((AsyncResult) msg.obj).result;            try {                Log.d(LOG_TAG, "silently drop incoming call: " + c.getCall());                c.getCall().hangup();            } catch (CallStateException e) {                Log.w(LOG_TAG, "new ringing connection", e);            }        } else {            mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);        }        break;}}
mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj)将触发mNewRingingConnectionRegistrants中注册的handler处理PHONE_NEW_RINGING_CONNECTION消息,在前面我们也介绍了,在PhoneApp的onCreate函数中构造CallNotifier对象时,通过registerForNotifications函数注册了CallNotifier来处理该消息。

packages\apps\Phone\src\com\android\phone\CallNotifier.java

public void handleMessage(Message msg) {    switch (msg.what) {        case PHONE_NEW_RINGING_CONNECTION:            log("RINGING... (new)");            onNewRingingConnection((AsyncResult) msg.obj);            mSilentRingerRequested = false;    }}
该函数直接调用onNewRingingConnection来处理来电

private void onNewRingingConnection(AsyncResult r) {    Connection c = (Connection) r.result;    log("onNewRingingConnection(): state = " + mCM.getState() + ", conn = { " + c + " }");    Call ringing = c.getCall();    Phone phone = ringing.getPhone();    // Check for a few cases where we totally ignore incoming calls.    if (ignoreAllIncomingCalls(phone)) {        PhoneUtils.hangupRingingCall(ringing);        return;    }    if (!c.isRinging()) {        Log.i(LOG_TAG, "CallNotifier.onNewRingingConnection(): connection not ringing!");        return;    }    // Stop any signalInfo tone being played on receiving a Call    stopSignalInfoTone();    Call.State state = c.getState();    if (VDBG) log("- connection is ringing!  state = " + state);    if (VDBG) log("Holding wake lock on new incoming connection.");    mApplication.requestWakeState(PhoneGlobals.WakeState.PARTIAL);        if (PhoneUtils.isRealIncomingCall(state)) {        startIncomingCallQuery(c);    } else {        if (VDBG) log("- starting call waiting tone...");        if (mCallWaitingTonePlayer == null) {            mCallWaitingTonePlayer = new InCallTonePlayer(InCallTonePlayer.TONE_CALL_WAITING);            mCallWaitingTonePlayer.start();        }        if (DBG) log("- showing incoming call (this is a WAITING call)...");        showIncomingCall();    }    if (VDBG) log("- onNewRingingConnection() done.");}
通过函数showIncomingCall来启动InCallScreen界面,并开启来电铃声

private void showIncomingCall() {    log("showIncomingCall()...  phone state = " + mCM.getState());    try {        ActivityManagerNative.getDefault().closeSystemDialogs("call");    } catch (RemoteException e) {    }    mApplication.requestWakeState(PhoneGlobals.WakeState.FULL);    if (DBG) log("- updating notification from showIncomingCall()...");    mApplication.notificationMgr.updateNotificationAndLaunchIncomingCallUi();}
最后通过NotificationMgr类来启动来电界面

public void updateNotificationAndLaunchIncomingCallUi() {    updateInCallNotification(true);}
在函数updateInCallNotification中通过以下语句来启动来电界面

Intent inCallIntent = mApp.createInCallIntent(currentCall.getPhone().getPhoneId());PendingIntent inCallPendingIntent =PendingIntent.getActivity(mContext, 0, inCallIntent, 0);builder.setContentIntent(inCallPendingIntent);

更多相关文章

  1. 关于Android(安卓)的内存泄露及分析
  2. Android进阶-Android(安卓)Handler消息机制的源码详解
  3. Android应用程序资源管理器(Asset Manager)的创建过程分析
  4. Android系统服务-简介
  5. Android(安卓)React Native使用原生模块
  6. Android连载之:第三章第二节:Android用户界面
  7. 【Android的从零单排开发日记】之入门篇(十一)——Android的Intent
  8. 箭头函数的基础使用
  9. 类和 Json对象

随机推荐

  1. Web API身份认证解决方案之Basic基础认证
  2. C#内置泛型委托之Action委托
  3. php7和php5的详细对比
  4. C++设计模式中的观察者模式一起来看看
  5. [Android] 动态语言切换
  6. spotlight android app which likes spot
  7. Android用户定位Google Map显示地图
  8. Android(安卓)SSO 相关文章
  9. Android(安卓)ScrollView + ListView嵌套
  10. android cupcake源码编译问题