Android6.0的phone应用源码分析(4)——phone拨号流程分析

1.1   Dialer拨号

拨打电话需要开启Dialer(拨号盘),当用户触发onClick事件,DialtactsActivity的onClick()方法被触发:

public void onClick(View view) {

        switch (view.getId()) {//对触发的buttonID进行判断

            case R.id.floating_action_button://此处可认为是点击“拨号”按钮

                if (mListsFragment.getCurrentTabIndex()//通过电话簿拨号

                        == ListsFragment.TAB_INDEX_ALL_CONTACTS && !mInRegularSearch) {

                    DialerUtils.startActivityWithErrorToast(

                            this,

                            IntentUtil.getNewContactIntent(),

                            R.string.add_contact_not_available);

                }else if (!mIsDialpadShown) {//拨号界面未显示,显示拨号界面

                    mInCallDialpadUp = false;

                    showDialpadFragment(true);//这里实际上是交给了DialPadFrament去处理

                }

break;

            case R.id.voice_search_button://声控搜索

                try {

                    startActivityForResult(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH),

                            ACTIVITY_REQUEST_CODE_VOICE_SEARCH);

                } catch (ActivityNotFoundException e) {

                    Toast.makeText(DialtactsActivity.this, R.string.voice_search_not_available,

                            Toast.LENGTH_SHORT).show();

                }

                break;

            case R.id.dialtacts_options_menu_button://设置按钮

                mOverflowMenu.show();

                break;

            default: {

                Log.wtf(TAG, "Unexpected onClick event from " + view);

                break;

            }

       }

    }

注意到上面的程序中并没有对搜索按钮进行处理,因为压根就没有也不需要这个按钮,Android在输入内容的同时自动搜索。

进入到DialPadFragment,注意到Android6.0中其实有两个DialPadFragment.java文件,一个当然是拨号时显示,另一个是来电时显示的。找到拨号的那一个DialPadFragment.java,此类主要负责与键盘拨号相关的动作的处理、输入校验和输入结果提交等逻辑。数字按键事件捕获:

    @Override

    public boolean onKey(View view, int keyCode, KeyEvent event) {

        switch (view.getId()) {

            case R.id.digits:

                if (keyCode == KeyEvent.KEYCODE_ENTER) {//如果是KEYCODE_ENTER,开始拨打

                    handleDialButtonPressed();

                    return true;//自己处理了

                }

                break;

        }

        return false;//返回false由系统进行处理

    }

本人对Android的应用开发不太了解,百度得知onKey()如果返回 false会交由系统处理,本人猜测处理函数就是本类的OnPressed()。不知是否正确,希望指正。

/**

     * When a key is pressed, we start playing DTMF tone, do vibration, and enter the digit

     * immediately. When a key is released, we stop the tone. Note that the "key press" event will

     * be delivered by the system with certain amount of delay, it won't be synced with user's

     * actual "touch-down" behavior.

     */

    @Override

    public void onPressed(View view, boolean pressed) {

        if (DEBUG) Log.d(TAG, "onPressed(). view: " + view + ", pressed: " + pressed);

        if (pressed) {

            switch (view.getId()) {

                case R.id.one: {

                    keyPressed(KeyEvent.KEYCODE_1);//这里根据设置可能会有tone音,并触发//EditTextonKeyDown方法,下类似

                    break;

                }

                case R.id.two: {

                    keyPressed(KeyEvent.KEYCODE_2);

                    break;

                }

                case R.id.three: {

                    keyPressed(KeyEvent.KEYCODE_3);

                    break;

                }

                case R.id.four: {

                    keyPressed(KeyEvent.KEYCODE_4);

                    break;

                }

                case R.id.five: {

                    keyPressed(KeyEvent.KEYCODE_5);

                    break;

                }

                case R.id.six: {

                    keyPressed(KeyEvent.KEYCODE_6);

                    break;

                }

                case R.id.seven: {

                    keyPressed(KeyEvent.KEYCODE_7);

                    break;

                }

                case R.id.eight: {

                    keyPressed(KeyEvent.KEYCODE_8);

                    break;

                }

                case R.id.nine: {

                    keyPressed(KeyEvent.KEYCODE_9);

                    break;

                }

                case R.id.zero: {

                    keyPressed(KeyEvent.KEYCODE_0);

                    break;

                }

                case R.id.pound: {

                    keyPressed(KeyEvent.KEYCODE_POUND);

                    break;

                }

                case R.id.star: {

                    keyPressed(KeyEvent.KEYCODE_STAR);

                    break;

                }

                default: {

                    Log.wtf(TAG, "Unexpected onTouch(ACTION_DOWN) event from: " + view);

                    break;

                }

            }

            mPressedDialpadKeys.add(view);

        } else {

            mPressedDialpadKeys.remove(view);

            if (mPressedDialpadKeys.isEmpty()) {

                stopTone();

            }

        }

    }

此时假设号码已经输入完毕,DialPadFragment类内部的onKey()和onClick()方法都将触发handleDialButtonPressed(),以onClick()为例;

    public void onClick(View view) {

        switch (view.getId()) {

            case R.id.dialpad_floating_action_button://拨打按钮

                mHaptic.vibrate();

                handleDialButtonPressed();//负责处理button pressed消息

                break;

            case R.id.deleteButton: {//del按钮

                keyPressed(KeyEvent.KEYCODE_DEL);

                break;

            }

            case R.id.digits: {//数字显示框,聚焦

                if (!isDigitsEmpty()) {

                    mDigits.setCursorVisible(true);

                }

                break;

            }

            case R.id.dialpad_overflow: {//滑动拨号盘?

                mOverflowPopupMenu.show();

                break;

            }

            default: {

                Log.wtf(TAG, "Unexpected onClick() event from: " + view);

                return;

            }

        }

    }

值得一说的是,DialPadFragment还处理了一类DTMF(双音多频)按键事件,这种信令方式是在拨打一些特殊的服务台电话时候使用的,比如拨打10086,接着按0进入人工服务。

接着之前的Onclick(),进入handleDialButtonPressed()

private void handleDialButtonPressed() {

        if (isDigitsEmpty()) { //如果没有数字输入

            handleDialButtonClickWithEmptyDigits();

        } else {

            final String number = mDigits.getText().toString();//获取输入的电话号码

            if (number != null

                    && !TextUtils.isEmpty(mProhibitedPhoneNumberRegexp)

                    && number.matches(mProhibitedPhoneNumberRegexp)) {//number过滤

                Log.i(TAG, "The phone number is prohibited explicitly by a rule.");

                if (getActivity() != null) {

                    DialogFragment dialogFragment = ErrorDialogFragment.newInstance(

                            R.string.dialog_phone_call_prohibited_message);

                    dialogFragment.show(getFragmentManager(), "phone_prohibited_dialog");

                }

                clearDialpad();//清除数字

            } else {//如果number通过了检查

               //取得一个Callintent

                final Intent intent = CallUtil.getCallIntent(number,

                        (getActivity() instanceof DialtactsActivity ?

                                ((DialtactsActivity) getActivity()).getCallOrigin() : null));

               //交给DialerUtils去处理

                DialerUtils.startActivityWithErrorToast(getActivity(), intent);

                hideAndClearDialpad(false);

            }

        }

    }

进入DialerUtils.startActivityWithErrorToast()法,此方法有多个重载方法,满参数实现方法如下:

public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) {

        try {//判断Intent是否是ACTION_CALL,这里当然是

            if (Intent.ACTION_CALL.equals(intent.getAction())) {

                // All dialer-initiated calls should pass the touch point to the InCallUI

                Point touchPoint = TouchPointManager.getInstance().getPoint();

                if (touchPoint.x != 0 || touchPoint.y != 0) {

                    Bundle extras = new Bundle();

                    extras.putParcelable(TouchPointManager.TOUCH_POINT, touchPoint);

                    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);

                }

                final TelecomManager tm = (TelecomManager)//获取TelecomManager服务

context.getSystemService(Context.TELECOM_SERVICE); //开启Activity,此处和5.0

              tm.placeCall(intent.getData(), intent.getExtras());//不一样

            } else {

                context.startActivity(intent);

            }

        } catch (ActivityNotFoundException e) {

            Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show();

        }

    }

此时的Context其实是一个CallActivity。此处比5.0更直接的进入了TelecomService(当然是通过Binder)。进入TelecomManager.placeCall()

public void placeCall(Uri address, Bundle extras) {

        ITelecomService service = getTelecomService();//获取TelecomService服务

        if (service != null) {

            if (address == null) {

                Log.w(TAG, "Cannot place call to empty address.");

            }

            try {

                service.placeCall(address, extras == null ? new Bundle() : extras,

                        mContext.getOpPackageName());//交给Service去处理,进入Server

            } catch (RemoteException e) {

                Log.e(TAG, "Error calling ITelecomService#placeCall", e);

            }

        }

    }

1.2   TelecomService

TelecommService的placeCall()方法在TelecommServiceImpl中找到。代码如下:

@Override

        public void placeCall(Uri handle, Bundle extras, String callingPackage) {

            enforceCallingPackage(callingPackage);

            if (!canCallPhone(callingPackage, "placeCall")) {

                throw new SecurityException("Package " + callingPackage

                        + " is not allowed to place phone calls");

            }

            final boolean hasCallAppOp = mAppOpsManager.noteOp(AppOpsManager.OP_CALL_PHONE,

                    Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED; //应用程序级别的拨打非紧急电话允许标志

 

            final boolean hasCallPermission =          //电话权限检查mContext.checkCallingPermission(CALL_PHONE) ==      //和上面的标志共同决

                    PackageManager.PERMISSION_GRANTED;//定是否可以拨打非紧急电话

 

            synchronized (mLock) {

                final UserHandle userHandle = Binder.getCallingUserHandle();

                long token = Binder.clearCallingIdentity();

                try {

                    final Intent intent = new Intent(Intent.ACTION_CALL, handle);

                    intent.putExtras(extras);

                    new UserCallIntentProcessor(mContext,//交给UserCallIntentProcessor userHandle).processIntent(intent,

                            callingPackage, hasCallAppOp && hasCallPermission);

                } finally {

                    Binder.restoreCallingIdentity(token);

                }

            }

        }

进入UserCallIntentProcessor的processIntent();

   public void processIntent(Intent intent, String callingPackageName,

            boolean canCallNonEmergency) {

        if (!isVoiceCapable()) {

            return;

        }

        String action = intent.getAction();//得到intentAction

        if (Intent.ACTION_CALL.equals(action) ||

                Intent.ACTION_CALL_PRIVILEGED.equals(action) ||

                Intent.ACTION_CALL_EMERGENCY.equals(action)) {//如果是这三种类型的Call

            processOutgoingCallIntent(intent, callingPackageName,//程序进入这里canCallNonEmergency);

        }

    }

进processOutgoingCallIntent():

private void processOutgoingCallIntent(Intent intent, String callingPackageName,

            boolean canCallNonEmergency) {

        Uri handle = intent.getData();

        String scheme = handle.getScheme();

        String uriString = handle.getSchemeSpecificPart();

 

        if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {

            handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?

                    PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);

        }

 

        final UserManager userManager =//再次获取服务,此时是userManager

                (UserManager) mContext.getSystemService(Context.USER_SERVICE);

        if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, mUserHandle)

                && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {

            //被应用程序级别的权限拦截处理

            showErrorDialogForRestrictedOutgoingCall(mContext,

                    R.string.outgoing_call_not_allowed_user_restriction);

            Log.w(this, "Rejecting non-emergency phone call due to DISALLOW_OUTGOING_CALLS "

                    + "restriction");

            return;

        }

 

        if (!canCallNonEmergency && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {//被系统级别的权限拦截处理

            showErrorDialogForRestrictedOutgoingCall(mContext,

                    R.string.outgoing_call_not_allowed_no_permission);

            Log.w(this, "Rejecting non-emergency phone call because "

                    + android.Manifest.permission.CALL_PHONE + " permission is not granted.");

            return;

        }

        //权限检查OK

        int videoState = intent.getIntExtra(

                TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,

                VideoProfile.STATE_AUDIO_ONLY);

        Log.d(this, "processOutgoingCallIntent videoState = " + videoState);

 

        if (VideoProfile.isVideo(videoState)//是视频?且需紧急处理

                && TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {

            Log.d(this, "Emergency call...Converting video call to voice...");

            videoState = VideoProfile.STATE_AUDIO_ONLY;

            intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,

                    videoState);

        }

 

        if (VideoProfile.isVideo(videoState) && isTtyModeEnabled()) {//是视频且TTY

            Toast.makeText(mContext, mContext.getResources().getString(R.string.

                    video_call_not_allowed_if_tty_enabled), Toast.LENGTH_SHORT).show();

            Log.d(this, "Rejecting video calls as tty is enabled");

            return;

        }

        //对于非残疾人(非TTY),在普通情况下的处理

        intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,

                isDefaultOrSystemDialer(callingPackageName));

        sendBroadcastToReceiver(intent);//广播拨号Intent

    }

在初级Receiver:PrimaryCallReceiver的onReceive()中被接收。

    public void onReceive(Context context, Intent intent) {

        synchronized (getTelecomSystem().getLock()) {

            getTelecomSystem().getCallIntentProcessor().processIntent(intent);

        }

    }

接着CallIntentProcessor. processIntent(intent)

       public void processIntent(Intent intent) {

        final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);

        Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall);

 

        Trace.beginSection("processNewCallCallIntent");

        if (isUnknownCall) {//如果是并不知道的电话号码,如空号

            processUnknownCallIntent(mCallsManager, intent);

        } else {//通过Unknown检测

            processOutgoingCallIntent(mContext, mCallsManager, intent);//进入这里

        }

        Trace.endSection();

    }

接着processOutgoingCallIntent()

    static void processOutgoingCallIntent(

            Context context,

            CallsManager callsManager,

            Intent intent) {

        if (shouldPreventDuplicateVideoCall(context, callsManager, intent)) {

            return;

        }

 

        Uri handle = intent.getData();

        String scheme = handle.getScheme();

        String uriString = handle.getSchemeSpecificPart();

 

        if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {

            handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?

                    PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);

        }

 

        PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(

                TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);

 

        Bundle clientExtras = null;

        if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) {

            clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);

        }

        if (clientExtras == null) {

            clientExtras = new Bundle();

        }

 

        final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);

 

        //这里新建了一个Call,这是个很重要的入口,开启了InCallUI

        Call call = callsManager.startOutgoingCall(handle, phoneAccountHandle, clientExtras);//下一章在这里扩展!!

        if (call != null) {//获得的Call不为空

//新建一个NewOutgoingCallIntentBroadcaster的实例,并调用其processIntent()

            NewOutgoingCallIntentBroadcaster broadcaster = newNewOutgoingCallIntentBroadcaster(

                    context, callsManager, call, intent, isPrivilegedDialer);

            final int result = broadcaster.processIntent();

            final boolean success = result == DisconnectCause.NOT_DISCONNECTED;

 

            if (!success && call != null) {

                disconnectCallAndShowErrorDialog(context, call, result);

            }

        }

    }

进入broadcaster.processIntent(),此方法将处理3类电话权限,分别为第三方Call,系统Call,和紧急Call。这三类Call的区别:首先可以想到,拨打Emergency call是不需要卡的(当然,现在基本上的手机都已经不支持无卡紧急拨号了,主要原因在运营商)。应该走的是一种特殊的链路,或者更直白的将应该是一条更快捷的链路。Emergency call 可以被两种Intent所触发:   

Intent.ACTION_CALL_EMERGENCY

Intent.ACTION_CALL_PRIVILEGED

CALL_PRIVILEGED是被系统级的应用所发起的,而CALL_EMERGENCY Intent 是从紧急呼叫的拨号盘里发起的,就是手机在没有SIM卡的模式下显示的拨号盘。CALL_PRIVILEGED这个intent 接到后会检查号码是否是emergencynumber, 如果是紧急电话的号码就会把intent的action 替换为ACTION_CALL_EMERGENCY, 如果不是就替换成ACTION_CALL。由此可看,虽然我们有三种call的intent action, 但是我们实际有效果的就是上述两种

CALL_PRIVILEGED这种action的call的作用的是能把紧急电话的号码带给phone app去处理,而普通的call action的intent是不可以的。

processIntent实现里用一个flag变量callImmediately来控制是否拨打电话,callImmediately在满足拨打emengency call的时候被置为true。

 3rd App是没有权限拨打Emergency call的,如果3rd App对应的Intent.ACTION_CALL里带有Emergency number,会被阻止。

  int processIntent() {

        Log.v(this, "Processing call intent in OutgoingCallIntentBroadcaster.");

 

        Intent intent = mIntent;

        String action = intent.getAction();

        final Uri handle = intent.getData();

 

        if (handle == null) {

            Log.w(this, "Empty handle obtained from the call intent.");

            return DisconnectCause.INVALID_NUMBER;

        }

 

        boolean isVoicemailNumber = PhoneAccount.SCHEME_VOICEMAIL.equals(handle.getScheme());

        if (isVoicemailNumber) {//语音信箱号码,直接拨号

            if (Intent.ACTION_CALL.equals(action)

                    || Intent.ACTION_CALL_PRIVILEGED.equals(action)) {

                // Voicemail calls will be handled directly by the telephony connection manager

                Log.i(this, "Placing call immediately instead of waiting for "

                        + " OutgoingCallBroadcastReceiver: %s", intent);

 

                boolean speakerphoneOn = mIntent.getBooleanExtra(

                        TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);

                mCallsManager.placeOutgoingCall(mCall, handle, null, speakerphoneOn,

                        VideoProfile.STATE_AUDIO_ONLY);

 

                return DisconnectCause.NOT_DISCONNECTED;

            } else {

                Log.i(this, "Unhandled intent %s. Ignoring and not placing call.", intent);

                return DisconnectCause.OUTGOING_CANCELED;

            }

        }

 

        String number = PhoneNumberUtils.getNumberFromIntent(intent, mContext);

        if (TextUtils.isEmpty(number)) {

            Log.w(this, "Empty number obtained from the call intent.");

            return DisconnectCause.NO_PHONE_NUMBER_SUPPLIED;

        }

 

        boolean isUriNumber = PhoneNumberUtils.isUriNumber(number);

        if (!isUriNumber) {

            number = PhoneNumberUtils.convertKeypadLettersToDigits(number);

            number = PhoneNumberUtils.stripSeparators(number);

        }

        //只有CALL_PRIVILEGEDCALL_EMERGENCY才有可能成为紧急号码

        final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);

        Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);

//根据是否为紧急号码,重写intent以便后续做判断

        //此后,只存在两种类型的电话了,一个是普通电话,另一个为紧急电话ALL_PRIVILEGED

        //被转化成了这两种电话的一种(根据number)

        rewriteCallIntentAction(intent, isPotentialEmergencyNumber);

        action = intent.getAction();

        // True for certain types of numbers that are not intended to be intercepted or

        // modified by third parties (e.g. emergency nmbers).

        boolean callImmediately = false; //通过第三方来源检查,且为紧急号后设置为true,需//立即处理

        if (Intent.ACTION_CALL.equals(action)) {//Action_Call进行处理

            if (isPotentialEmergencyNumber) {

                if (!mIsDefaultOrSystemPhoneApp) {//普通拨号也可能是紧急电话,但是如果是紧//急电话,第三方软件无权拨打

                    Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "

                            + "unless caller is system or default dialer.", number, intent);

                    launchSystemDialer(intent.getData());//弹出系统拨号盘供拨打紧急电话

                    return DisconnectCause.OUTGOING_CANCELED;

                } else {

                    callImmediately = true; //如果是紧急电话设置紧急电话标志

                }

            }

        } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {//对紧急拨号的处理

            if (!isPotentialEmergencyNumber) {//紧急拨号盘拨打的并不是紧急电话

                Log.w(this, "Cannot call non-potential-emergency number %s with EMERGENCY_CALL "

                        + "Intent %s.", number, intent);

                return DisconnectCause.OUTGOING_CANCELED;

            }

            callImmediately = true; //设置紧急电话标志

        } else {

            Log.w(this, "Unhandled Intent %s. Ignoring and not placing call.", intent);

            return DisconnectCause.INVALID_NUMBER;

        }

 

        if (callImmediately) {//开始处理紧急号码

            Log.i(this, "Placing call immediately instead of waiting for "

                    + " OutgoingCallBroadcastReceiver: %s", intent);

            String scheme = isUriNumber ? PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL;

            boolean speakerphoneOn = mIntent.getBooleanExtra(

                    TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);

            int videoState = mIntent.getIntExtra(

                    TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,

                    VideoProfile.STATE_AUDIO_ONLY);

            mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,

                    speakerphoneOn, videoState);//紧急电话快速处理

 

// Don't return but instead continue and send the ACTION_NEW_OUTGOING_CALL broadcast

// so that third parties can still inspect (but not intercept) the outgoing call. When

// the broadcast finally reaches the OutgoingCallBroadcastReceiver, we'll know not to

// initiate the call again because of the presence of the EXTRA_ALREADY_CALLED extra.

        }

        Log.i(this, "Sending NewOutgoingCallBroadcast for %s", mCall);

        //对普通号码的处理

    broadcastIntent(intent, number, !callImmediately);//广播ACTION_NEW_OUTGOING_CALL

        return DisconnectCause.NOT_DISCONNECTED;

    }

从上可以看出,对于这三类电话,broadcaster()做了甄别处理,对number和号码来源进行分析,将PRIVILEGED CALL转化成普通拨号或紧急拨号,并屏蔽第三方APP的紧急拨号,接着将紧急号码直接交给mCallsManagerd的placeOutgoingCall()方法去做进一步处理,而普通号码为了可以通知给发起拨号的第三方APP需要进行广播。内容为ACTION_NEW_OUTGOING_CALL型的 Intent。此广播将在NewOutgoingCallIntentBroadcaster(其实就是自己的一个内部类)中接收。onReceive()对广播的内容作了一定的甄别判断后,将处理权交给了mCallsManager的placeOutgoingCall()。对比之前对紧急电话的处理也是交给了这个方法,可以看出此方法为处理去电的一个关口方法。

void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo, boolean speakerphoneOn,int videoState) {

        ……

        call.setHandle(uriHandle);//设置一些信息

        call.setGatewayInfo(gatewayInfo);

        call.setStartWithSpeakerphoneOn(speakerphoneOn);

        call.setVideoState(videoState);

        ……

        if (call.getTargetPhoneAccount() != null || isEmergencyCall) {

            call.startCreateConnection(mPhoneAccountRegistrar);//创建并开启连接

        }

    }

进入Call的startCreateConnection(),此后都是围绕Connection展开的,因为这里可以认为是客户端,而真正的Connection由Android后台服务控制,所以Connection对于客户端来说就是获取远程服务,在Android中这明显会用Binder机制获取服务的远程代理对象。(注意android文件系统中有多个不同的Call.java):

void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {

        Preconditions.checkState(mCreateConnectionProcessor == null);

        //新建一个创建连接的processor

        mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this, phoneAccountRegistrar, mContext);

        mCreateConnectionProcessor.process();//将连接任务交给preocessor去处理

    }

进入CreateConnectionProcessor.process():

    void process() {

        Log.v(this, "process");

        mAttemptRecords = new ArrayList<>();

        if (mCall.getTargetPhoneAccount() != null) {

            mAttemptRecords.add(new CallAttemptRecord(

                    mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));

        }

        adjustAttemptsForConnectionManager();

        adjustAttemptsForEmergency();

        mAttemptRecordIterator = mAttemptRecords.iterator();

        attemptNextPhoneAccount();//这里通过包装类调用了ServicecreateConnection方法,//而这个包装类是IConnectionService的子类

    }

进入attempNextPhoneAccount:

   private void attemptNextPhoneAccount() {

        ……

        if (mResponse != null && attempt != null) {

            Log.i(this, "Trying attempt %s", attempt);

            PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;

            ConnectionServiceWrapper service =//再次获取服务,这次是ConnectionService

                    mRepository.getService(

                            phoneAccount.getComponentName(),

                            phoneAccount.getUserHandle());

            if (service == null) {//有效性判断

                Log.i(this, "Found no connection service for attempt %s", attempt);

                attemptNextPhoneAccount();

            } else {

       mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);

                mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);

                mCall.setConnectionService(service);

                setTimeoutIfNeeded(service, attempt);

 

                service.createConnection(mCall, new Response(service));//进入这里

            }

……

        }

    }

进入ConnectionServiceWrapper.createConnection();

   void createConnection(final Call call, final CreateConnectionResponse response) {

        Log.d(this, "createConnection(%s) via %s.", call, getComponentName());

//这里new了一个Callbackconnect的结果进行处理(错了,这里应该是对bind()的处理结果的回调)

        BindCallback callback = new BindCallback() {

            @Override

            public void onSuccess() {//连接成功时的回调方法

                String callId = mCallIdMapper.getCallId(call);

                mPendingResponses.put(callId, response);

 

                GatewayInfo gatewayInfo = call.getGatewayInfo();

                Bundle extras = call.getExtras();

                if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&

                        gatewayInfo.getOriginalAddress() != null) {

                    extras = (Bundle) extras.clone();

                    extras.putString(

                            TelecomManager.GATEWAY_PROVIDER_PACKAGE,

                            gatewayInfo.getGatewayProviderPackageName());

                    extras.putParcelable(

                            TelecomManager.GATEWAY_ORIGINAL_ADDRESS,

                            gatewayInfo.getOriginalAddress());

                }

                Log.event(call, Log.Events.START_CONNECTION, Log.piiHandle(call.getHandle()));

                try {

                    mServiceInterface.createConnection(//利用远程对象调用Service服务

                            call.getConnectionManagerPhoneAccount(),

                            callId,

                            new ConnectionRequest(

                                    call.getTargetPhoneAccount(),

                                    call.getHandle(),

                                    extras,

                                    call.getVideoState()),

                            call.isIncoming(),

                            call.isUnknown());

                } catch (RemoteException e) {

                    Log.e(this, e, "Failure to createConnection -- %s", getComponentName());

                    mPendingResponses.remove(callId).handleCreateConnectionFailure(

                            new DisconnectCause(DisconnectCause.ERROR, e.toString()));

                }

            }

            @Override

            public void onFailure() {

                Log.e(this, new Exception(), "Failure to call %s", getComponentName());

                response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR));

            }

        };

        //绑定callbackcall

        mBinder.bind(callback, call);

    }

此方法实际上是建立了一个callBack,然后进行了bind。bind()在ServiceBinder中实现:

void bind(BindCallback callback, Call call) {

            Log.d(ServiceBinder.this, "bind()");

            // Reset any abort request if we're asked to bind again.

            clearAbort();

            if (!mCallbacks.isEmpty()) {

             // Binding already in progress, append to the list of callbacks and bail out.

                mCallbacks.add(callback);

                return;

            }

            mCallbacks.add(callback);

            if (mServiceConnection == null) {//如果还没有获取mServiceConnection,获取它

                Intent serviceIntent = new   //首先构造Intent以便后续的绑定检测Intent(mServiceAction).setComponent(mComponentName);

                //call为参数新建ServiceConnection实例

                ServiceConnection connection = new ServiceBinderConnection(call);

 

                Log.event(call, Log.Events.BIND_CS, mComponentName);

                final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;

                final boolean isBound;

                if (mUserHandle != null) {//mUserHandle的绑定

                    isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags, mUserHandle);

                } else {//不带mUserHandle的绑定

                    isBound = mContext.bindService(serviceIntent, connection, bindingFlags);

                }

//绑定失败则返回isBound=false,绑定成功暂时不返回,回//onServiceConnected方法,这部分逻辑很奇怪,这里也仅仅是我的推测

                if (!isBound) {//绑定失败,个人觉得绑定失败也应该弄个回调,好理解好维护

                    handleFailedConnection();

                    return;

                }

            } else {//老早之前就绑定了,意味着后续的不少处理可以直接跳过,直接处理

                Log.d(ServiceBinder.this, "Service is already bound.");

                Preconditions.checkNotNull(mBinder);

                handleSuccessfulConnection();//这里一定要看清楚else所对应的if

            }

        }

ServiceBinderConnection是一个内部类,其内部并没有变量域。如果绑定成功的话,在ServiceBinder的内部类ServiceBinderConnection的onServiceConnected()方法就被触发调用。

        public void onServiceConnected(ComponentName componentName, IBinder binder) {

            synchronized (mLock) {

                Log.i(this, "Service bound %s", componentName);

                Log.event(mCall, Log.Events.CS_BOUND, componentName);

                mCall = null;

 

                // 如果Unbind请求在队列中,立即Unbind

                if (mIsBindingAborted) {

                    clearAbort();

                    logServiceDisconnected("onServiceConnected");

                    mContext.unbindService(this);

                    handleFailedConnection();

                    return;

                }

 

                mServiceConnection = this;

                setBinder(binder);//主要逻辑就是获得远程服务代理:mServiceInterface =//IConnectionService.Stub.asInterface(binder);

                handleSuccessfulConnection();//②连接成功处理,回调CallbackOnSuccess()

            }

        }

①    进入setBinder

   private void setBinder(IBinder binder) {

        if (mBinder != binder) {

            mBinder = binder;

            setServiceInterface(binder);//此方法为抽象方法

            if (binder == null) {

                for (Listener l : mListeners) {

                    l.onUnbind(this);

                }

            }

        }

    }

进入setServiceIntenterface(),回调的是ConnectionServiceWrapper的实现。

    protected void setServiceInterface(IBinder binder) {

        if (binder == null) {

            handleConnectionServiceDeath();

            CallsManager.getInstance().handleConnectionServiceDeath(this);

            mServiceInterface = null;

        } else {//获得所需Service的远程引用

            mServiceInterface = IConnectionService.Stub.asInterface(binder);//服务代理

            addConnectionServiceAdapter(mAdapter);

        }

    }

②    进入handleSuccessfuconnection()

    private void handleSuccessfulConnection() {

        for (BindCallback callback : mCallbacks) {

            callback.onSuccess();

        }

        mCallbacks.clear();

    }

这里很明显的意图是处理connection成功状态,回调了之前设立的callback()(查看之前代码)这里之前的分析错了,应该是处理Binder获取服务的结果,如果服务获取成功,就在callback的OnSuccess中开始connection。于是程序又回到ConnectionServiceWrapper的createConnection()方法。由此进入TelecommFramework。

1.3   TelecommFramework

ConnectionServiceWrapper从名字上来看应该是ConnectionService的一个包装,此类的createConnection()方法最终调用了mServiceInterface.createConnection(),通过Android的Binder通信机制,这里实际上可以理解为RPC,如果了解Binder机制和Looper机制的话,就知道它最终调用的肯定是Service进程(当然也可能是线程)端的同名方法,这里调用的远程服务方法为ConnectionService.java的createConnection()方法,如下。。

    private void createConnection(

            final PhoneAccountHandle callManagerAccount,

            final String callId,

            final ConnectionRequest request,

            boolean isIncoming,

            boolean isUnknown) {

        Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +

                "isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request, isIncoming,

                isUnknown);

 

        Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)

                : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)

                : onCreateOutgoingConnection(callManagerAccount, request);//去电在这里

        Log.d(this, "createConnection, connection: %s", connection);

        if (connection == null) {//创建connection失败

            connection = Connection.createFailedConnection(

                    new DisconnectCause(DisconnectCause.ERROR));

        }

 

        if (connection.getState() != Connection.STATE_DISCONNECTED) {//connection成功

            addConnection(callId, connection);//添加到连接队列

        }

 

        Uri address = connection.getAddress();

        String number = address == null ? "null" : address.getSchemeSpecificPart();

        Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s",

                Connection.toLogSafePhoneNumber(number),

                Connection.stateToString(connection.getState()),

                Connection.capabilitiesToString(connection.getConnectionCapabilities()));

 

        Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId);

        mAdapter.handleCreateConnectionComplete(

                callId,

                request,

                new ParcelableConnection(

                        request.getAccountHandle(),

                        connection.getState(),

                        connection.getConnectionCapabilities(),

                        connection.getAddress(),

                        connection.getAddressPresentation(),

                        connection.getCallerDisplayName(),

                        connection.getCallerDisplayNamePresentation(),

                        connection.getVideoProvider() == null ?

                                null : connection.getVideoProvider().getInterface(),

                        connection.getVideoState(),

                        connection.isRingbackRequested(),

                        connection.getAudioModeIsVoip(),

                        connection.getConnectTimeMillis(),

                        connection.getStatusHints(),

                        connection.getDisconnectCause(),

                        createIdList(connection.getConferenceables()),

                        connection.getExtras()));

    }

onCreateOutgoingConnection()在ConnectionService类中为空方法,它将在TelephonyConnectionService中被重写,因此进入TelephonyConnectionService的同名方法中。

1.4   TelephonyService

TelephonyConnectionService做了一定的处理之后交给了本类的placeOutgoingConnection()进行进一步的处理:

private void placeOutgoingConnection(

        TelephonyConnection connection, Phone phone, ConnectionRequest request) {

        String number = connection.getAddress().getSchemeSpecificPart();

 

        com.android.internal.telephony.Connection originalConnection;

        try {//由此进入TelephonyFramework,后续的内容围绕phone展开

            originalConnection =phone.dial(number, null, request.getVideoState(), request.getExtras());

        } catch (CallStateException e) {

            Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);

            int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE;

            if (e.getError() == CallStateException.ERROR_DISCONNECTED) {

                cause = android.telephony.DisconnectCause.OUT_OF_SERVICE;

            }

            connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(

                    cause, e.getMessage()));

            return;

        }

 

        if (originalConnection == null) {

            int telephonyDisconnectCause = android.telephony.DisconnectCause.OUTGOING_FAILURE;

            // GSMPhone,null connection意味着拨打MMI code

            if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {

                Log.d(this, "dialed MMI code");

                telephonyDisconnectCause = android.telephony.DisconnectCause.DIALED_MMI;

                final Intent intent = new Intent(this, MMIDialogActivity.class);

                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |

                        Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);

                startActivity(intent);

            }

            Log.d(this, "placeOutgoingConnection, phone.dial returned null");

            connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(

                    telephonyDisconnectCause, "Connection is null"));

        } else {

            connection.setOriginalConnection(originalConnection);

        }

    }

由此进入TelephonyFramework层

1.5   TelephonyFramework

在TelephonyFramework层所涉及到的类相对来说比较少,以CDMA为例,主要包括CDMAPhone,CDMACallTracker和与RIL层交互的RIL.java。

接着前上节的分析,程序进入TelephonyFramework层首先执行的是dial(),这里需要假定之前通过phoneFactory获得的是一个CDMAPhone,那么此处调用的是CDMAPhone.dial()。

    public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)

            throws CallStateException {

        if (uusInfo != null) {

            throw new CallStateException("Sending UUS information NOT supported in CDMA!");

        }

 

        boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(dialString);

        ImsPhone imsPhone = mImsPhone;

 

        boolean imsUseEnabled = isImsUseEnabled()

                 && imsPhone != null

                 && (imsPhone.isVolteEnabled() || imsPhone.isVowifiEnabled())

                 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);

 

        boolean useImsForEmergency = ImsManager.isVolteEnabledByPlatform(mContext)

                && imsPhone != null

                && isEmergency

                &&  mContext.getResources().getBoolean(

                        com.android.internal.R.bool.useImsAlwaysForEmergencyCall)

                && ImsManager.isNonTtyOrTtyOnVolteEnabled(mContext)

                && (imsPhone.getServiceState().getState() != ServiceState.STATE_POWER_OFF);

 

        if (DBG) {

            Rlog.d(LOG_TAG, "imsUseEnabled=" + imsUseEnabled

                    + ", useImsForEmergency=" + useImsForEmergency

                    + ", imsPhone=" + imsPhone

                    + ", imsPhone.isVolteEnabled()="

                    + ((imsPhone != null) ? imsPhone.isVolteEnabled() : "N/A")

                    + ", imsPhone.isVowifiEnabled()="

                    + ((imsPhone != null) ? imsPhone.isVowifiEnabled() : "N/A")

                    + ", imsPhone.getServiceState().getState()="

                    + ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A"));

        }

 

        ImsPhone.checkWfcWifiOnlyModeBeforeDial(mImsPhone, mContext);

 

        if (imsUseEnabled || useImsForEmergency) {

            try {

                if (DBG) Rlog.d(LOG_TAG, "Trying IMS PS call");

                return imsPhone.dial(dialString, uusInfo, videoState, intentExtras);

            } catch (CallStateException e) {

                if (DBG) Rlog.d(LOG_TAG, "IMS PS call exception " + e +

                        "imsUseEnabled =" + imsUseEnabled + ", imsPhone =" + imsPhone);

                if (!ImsPhone.CS_FALLBACK.equals(e.getMessage())) {

                    CallStateException ce = new CallStateException(e.getMessage());

                    ce.setStackTrace(e.getStackTrace());

                    throw ce;

                }

            }

        }

 

        if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE

                && mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && !isEmergency) {

            throw new CallStateException("cannot dial in current state");

        }

        if (DBG) Rlog.d(LOG_TAG, "Trying (non-IMS) CS call");

        return dialInternal(dialString, null, videoState, intentExtras);

    }

接着进入dialInternal()

protected Connection dialInternal (String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)

            throws CallStateException {

        // 对电话号码作解析

        String newDialString = PhoneNumberUtils.stripSeparators(dialString);

        return mCT.dial(newDialString); //注意这里的mCT的类型为CallTracker

由于是CDMA,调用的自然是CDMACallTracker的dial(),此类有两个dial(),满参实现为:

    Connection dial (String dialString, int clirMode) throws CallStateException {

        // 清除掉disconnected状态

        clearDisconnected();

        if (!canDial()) {

            throw new CallStateException("cannot dial in current state");

        }

 

        TelephonyManager tm =//又一次获取服务,这次是TelephonyManager

                (TelephonyManager) mPhone.getContext().getSystemService(Context.TELEPHONY_SERVICE);

        String origNumber = dialString;

        String operatorIsoContry = tm.getNetworkCountryIsoForPhone(mPhone.getPhoneId());

        String simIsoContry = tm.getSimCountryIsoForPhone(mPhone.getPhoneId());

        boolean internationalRoaming = !TextUtils.isEmpty(operatorIsoContry)

                && !TextUtils.isEmpty(simIsoContry)

                && !simIsoContry.equals(operatorIsoContry);

        if (internationalRoaming) {

            if ("us".equals(simIsoContry)) {

                internationalRoaming = internationalRoaming && !"vi".equals(operatorIsoContry);

            } else if ("vi".equals(simIsoContry)) {

                internationalRoaming = internationalRoaming && !"us".equals(operatorIsoContry);

            }

        }

        if (internationalRoaming) {

            dialString = convertNumberIfNecessary(mPhone, dialString);

        }

 

        String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");

        boolean isPhoneInEcmMode = inEcm.equals("true");

        boolean isEmergencyCall =

                PhoneNumberUtils.isLocalEmergencyNumber(mPhone.getContext(), dialString);

 

        // Cancel Ecm timer if a second emergency call is originating in Ecm mode

        if (isPhoneInEcmMode && isEmergencyCall) {

            handleEcmTimer(CDMAPhone.CANCEL_ECM_TIMER);

        }

 

        // We are initiating a call therefore even if we previously

        // didn't know the state (i.e. Generic was true) we now know

        // and therefore can set Generic to false.

        mForegroundCall.setGeneric(false);

 

        // The new call must be assigned to the foreground call.

        // That call must be idle, so place anything that's

        // there on hold

        if (mForegroundCall.getState() == CdmaCall.State.ACTIVE) {

            return dialThreeWay(dialString);

        }

 

        mPendingMO = new CdmaConnection(mPhone.getContext(),//建立连接,默认为前景CallcheckForTestEmergencyNumber(dialString),

                this, mForegroundCall);

        mHangupPendingMO = false;

 

        if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0

                || mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0 ) {

            // Phone number is invalid

            mPendingMO.mCause = DisconnectCause.INVALID_NUMBER;

 

            // handlePollCalls() will notice this call not present

            // and will mark it as dropped.

            pollCallsWhenSafe();

        } else {

            // Always unmute when initiating a new call

            setMute(false);

 

            // Check data call

            disableDataCallInEmergencyCall(dialString);

 

            // In Ecm mode, if another emergency call is dialed, Ecm mode will not exit.

            if(!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) {

                //mCi的类型为CommandsInterface,在创建phone的时候作为参数,实际上执行的是//RIL.dial()

mCi.dial(mPendingMO.getAddress(), clirMode, obtainCompleteMessage());

            } else {

                mPhone.exitEmergencyCallbackMode();

                mPhone.setOnEcbModeExitResponse(this,EVENT_EXIT_ECM_RESPONSE_CDMA, null);

                mPendingCallClirMode=clirMode;

                mPendingCallInEcm=true;

            }

        }

 

        if (mNumberConverted) {

            mPendingMO.setConverted(origNumber);

            mNumberConverted = false;

        }

         //更新phone状态

        updatePhoneState();

        //发起phone状态变化通知

        mPhone.notifyPreciseCallStateChanged();

        //返回通话连接

        return mPendingMO;

    }

标红且背景为金黄色的地方,以默认参数EVENT_OPERATION_COMPLETE进入obtainCompeleteMessage()的满参实现,它返回了一个消息。

private Message obtainCompleteMessage(int what) {//默认为EVENT_OPERATION_COMPLETE

        mPendingOperations++;

        mLastRelevantPoll = null;

        mNeedsPoll = true;

 

        if (DBG_POLL) log("obtainCompleteMessage: pendingOperations=" +

                mPendingOperations + ", needsPoll=" + mNeedsPoll);

 

        return obtainMessage(what);

    }

仔细分析mCi的来龙去脉,可以锁定,其调用的dial方法就是RIL.java的dial方法。此方法同样有两个重载方法,其中满参重载方法如下:

public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {

       //创建了一个RILRequest对象rr,这里的result为之前发送的EVENT_OPERATION_COMPLETE

        RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);

 

        rr.mParcel.writeString(address);

        rr.mParcel.writeInt(clirMode);

 

        if (uusInfo == null) {

            rr.mParcel.writeInt(0); // UUS information is absent

        } else {

            rr.mParcel.writeInt(1); // UUS information is present

            rr.mParcel.writeInt(uusInfo.getType());

            rr.mParcel.writeInt(uusInfo.getDcs());

            rr.mParcel.writeByteArray(uusInfo.getUserData());

        }

        //打印日志

        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

        //rr发送给RILC,此时的rr内部为RIL_REQUEST_DIAL

        //RILC层处理完成后会调用RILJprocessSolicited方法

        send(rr);

    }

RILJ从名字可以看出他是RILC在java层的实现,负责了Framework层与RIL层的交互,上层发送rr到底层处理,而底层通过RILJ将处理结果上报。RILJ的processSolicited(),此方法负责接收并处理RILC层回传上来的消息。Android6.0的phone的底层结构并没有多大变化,下面是一个老版本的图,Android6.0可能小有不同,不过大体应该一致:

Android6.0的phone应用源码分析(4)——phone拨号流程分析_第1张图片

图 phone底层结构图

在RIL层中的数据交互使用基于Socket网络连接的方式,当然这种socket并不是网络socket而是localSocket。消息数据按其处理方式的不同可以分为两类:

1,Solicited消息。这类消息如dial拨号,answer接听电话等主动操作请求。Solicited请求类的RIL消息,根据其动作行为,可再细分为SolicitedRequest和Solicited Response。正常情况下这两类消息成对出现,请求和应答一一对应。

2,UnSolicited消息。这类消息为底层主动上报的消息,如来电,接受短信等等。此消息由于是底层Modem主动上报,因此没有Request只有Response。

以下函数充分证明了这一点:

    private void processResponse (Parcel p) {

        int type;

        type = p.readInt();

        if (type == RESPONSE_UNSOLICITED) {

            processUnsolicited (p);//处理Unsolicited消息

        } else if (type == RESPONSE_SOLICITED) {

            RILRequest rr = processSolicited (p);//处理Unsolicited消息

            if (rr != null) {

                rr.release();

                decrementWakeLock();

            }

        }

    }

RIL.dial()最后send(rr),很明显,上层下发了一个rr,底层处理接受并处理之后还会回发一个Respose以表明处理结果,其处理结果根据上面的介绍,将在processSolicited()中进行处理:

  private RILRequest processSolicited (Parcel p) {

        int serial, error;

        boolean found = false;

 

        serial = p.readInt();

        error = p.readInt();

 

        RILRequest rr;

 

        rr = findAndRemoveRequestFromList(serial);

 

        if (rr == null) {

            Rlog.w(RILJ_LOG_TAG, "Unexpected solicited response! sn: "

                            + serial + " error: " + error);

            return null;

        }

 

        Object ret = null;

 

        if (error == 0 || p.dataAvail() > 0) {

            // either command succeeds or command fails but with data payload

            try {switch (rr.mRequest) {

            /*

 cat libs/telephony/ril_commands.h \

 | egrep "^ *{RIL_" \

 | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/'

             */

            case RIL_REQUEST_GET_SIM_STATUS: ret =  responseIccCardStatus(p); break;

            case RIL_REQUEST_ENTER_SIM_PIN: ret =  responseInts(p); break;

            case RIL_REQUEST_ENTER_SIM_PUK: ret =  responseInts(p); break;

            case RIL_REQUEST_ENTER_SIM_PIN2: ret =  responseInts(p); break;

            case RIL_REQUEST_ENTER_SIM_PUK2: ret =  responseInts(p); break;

            case RIL_REQUEST_CHANGE_SIM_PIN: ret =  responseInts(p); break;

            case RIL_REQUEST_CHANGE_SIM_PIN2: ret =  responseInts(p); break;

            case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret =  responseInts(p); break;

            case RIL_REQUEST_GET_CURRENT_CALLS: ret =  responseCallList(p); break;

            case RIL_REQUEST_DIAL: ret =  responseVoid(p); break;//这里

            case RIL_REQUEST_GET_IMSI: ret =  responseString(p); break;

            case RIL_REQUEST_HANGUP: ret =  responseVoid(p); break;

            case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: ret =  responseVoid(p); break;

            case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: {

                if (mTestingEmergencyCall.getAndSet(false)) {

                    if (mEmergencyCallbackModeRegistrant != null) {

                        riljLog("testing emergency call, notify ECM Registrants");

                        mEmergencyCallbackModeRegistrant.notifyRegistrant();

                    }

                }

                ret =  responseVoid(p);

                break;

            }

            case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: ret =  responseVoid(p); break;

            case RIL_REQUEST_CONFERENCE: ret =  responseVoid(p); break;

            case RIL_REQUEST_UDUB: ret =  responseVoid(p); break;

            case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: ret =  responseFailCause(p); break;

            case RIL_REQUEST_SIGNAL_STRENGTH: ret =  responseSignalStrength(p); break;

            case RIL_REQUEST_VOICE_REGISTRATION_STATE: ret =  responseStrings(p); break;

            case RIL_REQUEST_DATA_REGISTRATION_STATE: ret =  responseStrings(p); break;

            case RIL_REQUEST_OPERATOR: ret =  responseStrings(p); break;

            case RIL_REQUEST_RADIO_POWER: ret =  responseVoid(p); break;

            case RIL_REQUEST_DTMF: ret =  responseVoid(p); break;

            case RIL_REQUEST_SEND_SMS: ret =  responseSMS(p); break;

            case RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret =  responseSMS(p); break;

            case RIL_REQUEST_SETUP_DATA_CALL: ret =  responseSetupDataCall(p); break;

            case RIL_REQUEST_SIM_IO: ret =  responseICC_IO(p); break;

            case RIL_REQUEST_SEND_USSD: ret =  responseVoid(p); break;

            case RIL_REQUEST_CANCEL_USSD: ret =  responseVoid(p); break;

            case RIL_REQUEST_GET_CLIR: ret =  responseInts(p); break;

            case RIL_REQUEST_SET_CLIR: ret =  responseVoid(p); break;

            case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: ret =  responseCallForward(p); break;

            case RIL_REQUEST_SET_CALL_FORWARD: ret =  responseVoid(p); break;

            case RIL_REQUEST_QUERY_CALL_WAITING: ret =  responseInts(p); break;

            case RIL_REQUEST_SET_CALL_WAITING: ret =  responseVoid(p); break;

            case RIL_REQUEST_SMS_ACKNOWLEDGE: ret =  responseVoid(p); break;

            case RIL_REQUEST_GET_IMEI: ret =  responseString(p); break;

            case RIL_REQUEST_GET_IMEISV: ret =  responseString(p); break;

            case RIL_REQUEST_ANSWER: ret =  responseVoid(p); break;

            case RIL_REQUEST_DEACTIVATE_DATA_CALL: ret =  responseVoid(p); break;

            case RIL_REQUEST_QUERY_FACILITY_LOCK: ret =  responseInts(p); break;

            case RIL_REQUEST_SET_FACILITY_LOCK: ret =  responseInts(p); break;

            case RIL_REQUEST_CHANGE_BARRING_PASSWORD: ret =  responseVoid(p); break;

            case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: ret =  responseInts(p); break;

            case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: ret =  responseVoid(p); break;

            case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: ret =  responseVoid(p); break;

            case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS : ret =  responseOperatorInfos(p); break;

            case RIL_REQUEST_DTMF_START: ret =  responseVoid(p); break;

            case RIL_REQUEST_DTMF_STOP: ret =  responseVoid(p); break;

            case RIL_REQUEST_BASEBAND_VERSION: ret =  responseString(p); break;

            case RIL_REQUEST_SEPARATE_CONNECTION: ret =  responseVoid(p); break;

            case RIL_REQUEST_SET_MUTE: ret =  responseVoid(p); break;

            case RIL_REQUEST_GET_MUTE: ret =  responseInts(p); break;

            case RIL_REQUEST_QUERY_CLIP: ret =  responseInts(p); break;

            case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: ret =  responseInts(p); break;

            case RIL_REQUEST_DATA_CALL_LIST: ret =  responseDataCallList(p); break;

            case RIL_REQUEST_RESET_RADIO: ret =  responseVoid(p); break;

            case RIL_REQUEST_OEM_HOOK_RAW: ret =  responseRaw(p); break;

            case RIL_REQUEST_OEM_HOOK_STRINGS: ret =  responseStrings(p); break;

            case RIL_REQUEST_SCREEN_STATE: ret =  responseVoid(p); break;

            case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret =  responseVoid(p); break;

            case RIL_REQUEST_WRITE_SMS_TO_SIM: ret =  responseInts(p); break;

            case RIL_REQUEST_DELETE_SMS_ON_SIM: ret =  responseVoid(p); break;

            case RIL_REQUEST_SET_BAND_MODE: ret =  responseVoid(p); break;

            case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret =  responseInts(p); break;

            case RIL_REQUEST_STK_GET_PROFILE: ret =  responseString(p); break;

            case RIL_REQUEST_STK_SET_PROFILE: ret =  responseVoid(p); break;

            case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret =  responseString(p); break;

            case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret =  responseVoid(p); break;

            case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret =  responseInts(p); break;

            case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret =  responseVoid(p); break;

            case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret =  responseVoid(p); break;

            case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret =  responseGetPreferredNetworkType(p); break;

            case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseCellList(p); break;

            case RIL_REQUEST_SET_LOCATION_UPDATES: ret =  responseVoid(p); break;

            case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE: ret =  responseVoid(p); break;

            case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: ret =  responseVoid(p); break;

            case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: ret =  responseInts(p); break;

            case RIL_REQUEST_SET_TTY_MODE: ret =  responseVoid(p); break;

            case RIL_REQUEST_QUERY_TTY_MODE: ret =  responseInts(p); break;

            case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: ret =  responseVoid(p); break;

            case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: ret =  responseInts(p); break;

            case RIL_REQUEST_CDMA_FLASH: ret =  responseVoid(p); break;

            case RIL_REQUEST_CDMA_BURST_DTMF: ret =  responseVoid(p); break;

            case RIL_REQUEST_CDMA_SEND_SMS: ret =  responseSMS(p); break;

            case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: ret =  responseVoid(p); break;

            case RIL_REQUEST_GSM_GET_BROADCAST_CONFIG: ret =  responseGmsBroadcastConfig(p); break;

            case RIL_REQUEST_GSM_SET_BROADCAST_CONFIG: ret =  responseVoid(p); break;

            case RIL_REQUEST_GSM_BROADCAST_ACTIVATION: ret =  responseVoid(p); break;

            case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: ret =  responseCdmaBroadcastConfig(p); break;

            case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: ret =  responseVoid(p); break;

            case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: ret =  responseVoid(p); break;

            case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY: ret =  responseVoid(p); break;

            case RIL_REQUEST_CDMA_SUBSCRIPTION: ret =  responseStrings(p); break;

            case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret =  responseInts(p); break;

            case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret =  responseVoid(p); break;

            case RIL_REQUEST_DEVICE_IDENTITY: ret =  responseStrings(p); break;

            case RIL_REQUEST_GET_SMSC_ADDRESS: ret = responseString(p); break;

            case RIL_REQUEST_SET_SMSC_ADDRESS: ret = responseVoid(p); break;

            case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break;

            case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: ret = responseVoid(p); break;

            case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: ret = responseVoid(p); break;

            case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE: ret =  responseInts(p); break;

            case RIL_REQUEST_ISIM_AUTHENTICATION: ret =  responseString(p); break;

            case RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU: ret = responseVoid(p); break;

            case RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS: ret = responseICC_IO(p); break;

            case RIL_REQUEST_VOICE_RADIO_TECH: ret = responseInts(p); break;

            case RIL_REQUEST_GET_CELL_INFO_LIST: ret = responseCellInfoList(p); break;

            case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE: ret = responseVoid(p); break;

            case RIL_REQUEST_SET_INITIAL_ATTACH_APN: ret = responseVoid(p); break;

            case RIL_REQUEST_SET_DATA_PROFILE: ret = responseVoid(p); break;

            case RIL_REQUEST_IMS_REGISTRATION_STATE: ret = responseInts(p); break;

            case RIL_REQUEST_IMS_SEND_SMS: ret =  responseSMS(p); break;

            case RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC: ret =  responseICC_IO(p); break;

            case RIL_REQUEST_SIM_OPEN_CHANNEL: ret  = responseInts(p); break;

            case RIL_REQUEST_SIM_CLOSE_CHANNEL: ret  = responseVoid(p); break;

            case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL: ret = responseICC_IO(p); break;

            case RIL_REQUEST_NV_READ_ITEM: ret = responseString(p); break;

            case RIL_REQUEST_NV_WRITE_ITEM: ret = responseVoid(p); break;

            case RIL_REQUEST_NV_WRITE_CDMA_PRL: ret = responseVoid(p); break;

            case RIL_REQUEST_NV_RESET_CONFIG: ret = responseVoid(p); break;

            case RIL_REQUEST_SET_UICC_SUBSCRIPTION: ret = responseVoid(p); break;

            case RIL_REQUEST_ALLOW_DATA: ret = responseVoid(p); break;

            case RIL_REQUEST_GET_HARDWARE_CONFIG: ret = responseHardwareConfig(p); break;

            case RIL_REQUEST_SIM_AUTHENTICATION: ret =  responseICC_IOBase64(p); break;

            case RIL_REQUEST_SHUTDOWN: ret = responseVoid(p); break;

            case RIL_REQUEST_GET_RADIO_CAPABILITY: ret =  responseRadioCapability(p); break;

            case RIL_REQUEST_SET_RADIO_CAPABILITY: ret =  responseRadioCapability(p); break;

            case RIL_REQUEST_START_LCE: ret = responseLceStatus(p); break;

            case RIL_REQUEST_STOP_LCE: ret = responseLceStatus(p); break;

            case RIL_REQUEST_PULL_LCEDATA: ret = responseLceData(p); break;

            case RIL_REQUEST_GET_ACTIVITY_INFO: ret = responseActivityData(p); break;

            default:

                throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest);

            //break;

            }} catch (Throwable tr) {

                // Exceptions here usually mean invalid RIL responses

 

                Rlog.w(RILJ_LOG_TAG, rr.serialString() + "< "

                        + requestToString(rr.mRequest)

                        + " exception, possible invalid RIL response", tr);

 

                if (rr.mResult != null) {

                    AsyncResult.forMessage(rr.mResult, null, tr);

                    rr.mResult.sendToTarget();

                }

                return rr;

            }

        }

 

        if (rr.mRequest == RIL_REQUEST_SHUTDOWN) {

            // Set RADIO_STATE to RADIO_UNAVAILABLE to continue shutdown process

            // regardless of error code to continue shutdown procedure.

            riljLog("Response to RIL_REQUEST_SHUTDOWN received. Error is " +

                    error + " Setting Radio State to Unavailable regardless of error.");

            setRadioState(RadioState.RADIO_UNAVAILABLE);

        }

 

        // Here and below fake RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, see b/7255789.

        // This is needed otherwise we don't automatically transition to the main lock

        // screen when the pin or puk is entered incorrectly.

        switch (rr.mRequest) {

            case RIL_REQUEST_ENTER_SIM_PUK:

            case RIL_REQUEST_ENTER_SIM_PUK2:

                if (mIccStatusChangedRegistrants != null) {

                    if (RILJ_LOGD) {

                        riljLog("ON enter sim puk fakeSimStatusChanged: reg count="

                                + mIccStatusChangedRegistrants.size());

                    }

                    mIccStatusChangedRegistrants.notifyRegistrants();

                }

                break;

        }

 

        if (error != 0) {

            switch (rr.mRequest) {

                case RIL_REQUEST_ENTER_SIM_PIN:

                case RIL_REQUEST_ENTER_SIM_PIN2:

                case RIL_REQUEST_CHANGE_SIM_PIN:

                case RIL_REQUEST_CHANGE_SIM_PIN2:

                case RIL_REQUEST_SET_FACILITY_LOCK:

                    if (mIccStatusChangedRegistrants != null) {

                        if (RILJ_LOGD) {

                            riljLog("ON some errors fakeSimStatusChanged: reg count="

                                    + mIccStatusChangedRegistrants.size());

                        }

                        mIccStatusChangedRegistrants.notifyRegistrants();

                    }

                    break;

                case RIL_REQUEST_GET_RADIO_CAPABILITY: {

                    // Ideally RIL's would support this or at least give NOT_SUPPORTED

                    // but the hammerhead RIL reports GENERIC :(

                    // TODO - remove GENERIC_FAILURE catching: b/21079604

                    if (REQUEST_NOT_SUPPORTED == error ||

                            GENERIC_FAILURE == error) {

                        // we should construct the RAF bitmask the radio

                        // supports based on preferred network bitmasks

                        ret = makeStaticRadioCapability();

                        error = 0;

                    }

                    break;

                }

                case RIL_REQUEST_GET_ACTIVITY_INFO:

                    ret = new ModemActivityInfo(0, 0, 0,

                            new int [ModemActivityInfo.TX_POWER_LEVELS], 0, 0);

                    error = 0;

                    break;

            }

 

            if (error != 0) rr.onError(error, ret);

        }

        if (error == 0) {

 

            if (RILJ_LOGD) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest)

                    + " " + retToString(rr.mRequest, ret));

 

            if (rr.mResult != null) {

                AsyncResult.forMessage(rr.mResult, ret, null); //异步,因为后面要销毁rr

                rr.mResult.sendToTarget();//发送Handler消息通知,此消息将在//CDMACallTracker中处理

            }

        }

        return rr;

    }

进入CdmaCallTracker的handleMessage()

  public void handleMessage (Message msg) {

        AsyncResult ar;

 

        if (!mPhone.mIsTheCurrentActivePhone) {

            Rlog.w(LOG_TAG, "Ignoring events received on inactive CdmaPhone");

            return;

        }

        switch (msg.what) {

            case EVENT_POLL_CALLS_RESULT:{

                Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");

                ar = (AsyncResult)msg.obj;

 

                if(msg == mLastRelevantPoll) {

                    if(DBG_POLL) log(

                            "handle EVENT_POLL_CALL_RESULT: set needsPoll=F");

                    mNeedsPoll = false;

                    mLastRelevantPoll = null;

                    handlePollCalls((AsyncResult)msg.obj);

                }

            }

            break;

 

            case EVENT_OPERATION_COMPLETE: //完成事件,此消息之前在本类中创建,最后返回给//自己处理

                operationComplete();//完成事件处理

            break;

 

            case EVENT_SWITCH_RESULT:

                 // In GSM call operationComplete() here which gets the

                 // current call list. But in CDMA there is no list so

                 // there is nothing to do.

            break;

 

            case EVENT_GET_LAST_CALL_FAIL_CAUSE:

                int causeCode;

                String vendorCause = null;

                ar = (AsyncResult)msg.obj;

 

                operationComplete();

 

                if (ar.exception != null) {

                    // An exception occurred...just treat the disconnect

                    // cause as "normal"

                    causeCode = CallFailCause.NORMAL_CLEARING;

                    Rlog.i(LOG_TAG,

                            "Exception during getLastCallFailCause, assuming normal disconnect");

                } else {

                    LastCallFailCause failCause = (LastCallFailCause)ar.result;

                    causeCode = failCause.causeCode;

                    vendorCause = failCause.vendorCause;

                }

 

                for (int i = 0, s =  mDroppedDuringPoll.size()

                        ; i < s ; i++

                ) {

                    CdmaConnection conn = mDroppedDuringPoll.get(i);

 

                    conn.onRemoteDisconnect(causeCode, vendorCause);

                }

 

                updatePhoneState();

 

                mPhone.notifyPreciseCallStateChanged();

                mDroppedDuringPoll.clear();

            break;

 

            case EVENT_REPOLL_AFTER_DELAY:

            case EVENT_CALL_STATE_CHANGE:

                pollCallsWhenSafe();

            break;

 

            case EVENT_RADIO_AVAILABLE:

                handleRadioAvailable();

            break;

 

            case EVENT_RADIO_NOT_AVAILABLE:

                handleRadioNotAvailable();

            break;

 

            case EVENT_EXIT_ECM_RESPONSE_CDMA:

                // no matter the result, we still do the same here

                if (mPendingCallInEcm) {

                    mCi.dial(mPendingMO.getAddress(), mPendingCallClirMode, obtainCompleteMessage());

                    mPendingCallInEcm = false;

                }

                mPhone.unsetOnEcbModeExitResponse(this);

            break;

 

            case EVENT_CALL_WAITING_INFO_CDMA:

               ar = (AsyncResult)msg.obj;

               if (ar.exception == null) {

                   handleCallWaitingInfo((CdmaCallWaitingNotification)ar.result);

                   Rlog.d(LOG_TAG, "Event EVENT_CALL_WAITING_INFO_CDMA Received");

               }

            break;

 

            case EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA:

                ar = (AsyncResult)msg.obj;

                if (ar.exception == null) {

                    // Assume 3 way call is connected

                    mPendingMO.onConnectedInOrOut();

                    mPendingMO = null;

                }

            break;

 

            case EVENT_THREE_WAY_DIAL_BLANK_FLASH:

                ar = (AsyncResult) msg.obj;

                if (ar.exception == null) {

                    postDelayed(

                            new Runnable() {

                                public void run() {

                                    if (mPendingMO != null) {

                                        mCi.sendCDMAFeatureCode(mPendingMO.getAddress(),

                                                obtainMessage(EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA));

                                    }

                                }

                            }, m3WayCallFlashDelay);

                } else {

                    mPendingMO = null;

                    Rlog.w(LOG_TAG, "exception happened on Blank Flash for 3-way call");

                }

            break;

 

            default:{

               throw new RuntimeException("unexpected event not handled");

            }

        }

    }

进入operationComplete()

private void operationComplete() {

        mPendingOperations--;

 

        if (DBG_POLL) log("operationComplete: pendingOperations=" +

                mPendingOperations + ", needsPoll=" + mNeedsPoll);

 

        if (mPendingOperations == 0 && mNeedsPoll) {

            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);//创建一个消息

            mCi.getCurrentCalls(mLastRelevantPoll);//将消息传递给mCi,从而再次进入RILJ

        } else if (mPendingOperations < 0) {

            // this should never happen

            Rlog.e(LOG_TAG,"CdmaCallTracker.pendingOperations < 0");

            mPendingOperations = 0;

        }

    }

进入RIL.java的getCurrentCalls()

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给RILC。底层查询Call_list状态列表,RILC处理完后,仍然返回到RILJ,同样在processSolicited()中处理,由此可见processSolicited()基本负责了对RILC层返回消息的处理。同样进入CdmaCallTracker中的handleMessage()的Case  EVENT_POLL_CALLS_RESULT。(请查看之前代码),由handlePollCalls()处理

    protected 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

        Connection newUnknown = null;

        boolean hasNonHangupStateChanged = false;   // Any change besides

                                                    // a dropped connection

        boolean hasAnyCallDisconnected = false;

        boolean needsPollDelay = false;

        boolean unknownConnectionAppeared = false;

 

        for (int i = 0, curDC = 0, dcSize = polledCalls.size()

                ; i < mConnections.length; i++) {

            CdmaConnection conn = mConnections[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 (DBG_POLL) log("poll: conn[i=" + i + "]=" +

                    conn+", dc=" + dc);

            //conn代表旧连接地基本信息,dc代表新连接

            if (conn == null && dc != null) {//拨打第一通电话进入这里

                // Connection appeared in CLCC response that we don't know about

                if (mPendingMO != null && mPendingMO.compareTo(dc)) {

 

                    if (DBG_POLL) log("poll: pendingMO=" + mPendingMO);

 

                    // It's our pending mobile originating call

                    mConnections[i] = mPendingMO;

                    mPendingMO.mIndex = i;

                    mPendingMO.update(dc);

                    mPendingMO = null;

 

                    // Someone has already asked to hangup this call

                    if (mHangupPendingMO) {

                        mHangupPendingMO = false;

                        // Re-start Ecm timer when an uncompleted emergency call ends

                        if (mIsEcmTimerCanceled) {

                            handleEcmTimer(CDMAPhone.RESTART_ECM_TIMER);

                        }

 

                        try {

                            if (Phone.DEBUG_PHONE) log(

                                    "poll: hangupPendingMO, hangup conn " + i);

                            hangup(mConnections[i]);

                        } catch (CallStateException ex) {

                            Rlog.e(LOG_TAG, "unexpected error on hangup");

                        }

 

                        // Do not continue processing this poll

                        // Wait for hangup and repoll

                        return;

                    }

                } else {

                    if (Phone.DEBUG_PHONE) {

                        log("pendingMo=" + mPendingMO + ", dc=" + dc);

                    }

                    mConnections[i] = new CdmaConnection(mPhone.getContext(), dc, this, i);

 

                    Connection hoConnection = getHoConnection(dc);

                    if (hoConnection != null) {

                        // Single Radio Voice Call Continuity (SRVCC) completed

                        mConnections[i].migrateFrom(hoConnection);

                        mHandoverConnections.remove(hoConnection);

                        mPhone.notifyHandoverStateChanged(mConnections[i]);

                    } else {

                        // 检测MT call是不是个新来电或者Unknwon connection

                        newRinging = checkMtFindNewRinging(dc,i);

                        if (newRinging == null) {

                            unknownConnectionAppeared = true;

                            newUnknown = mConnections[i];

                        }

                    }

                    checkAndEnableDataCallAfterEmergencyCallDropped();

                }

                hasNonHangupStateChanged = true;

            } else if (conn != null && dc == null) {

                // This case means the RIL has no more active call anymore and

                // we need to clean up the foregroundCall and ringingCall.

                // Loop through foreground call connections as

                // it contains the known logical connections.

                int count = mForegroundCall.mConnections.size();

                for (int n = 0; n < count; n++) {

                    if (Phone.DEBUG_PHONE) log("adding fgCall cn " + n + " to droppedDuringPoll");

                    CdmaConnection cn = (CdmaConnection)mForegroundCall.mConnections.get(n);

                    mDroppedDuringPoll.add(cn);

                }

                count = mRingingCall.mConnections.size();

                // Loop through ringing call connections as

                // it may contain the known logical connections.

                for (int n = 0; n < count; n++) {

                    if (Phone.DEBUG_PHONE) log("adding rgCall cn " + n + " to droppedDuringPoll");

                    CdmaConnection cn = (CdmaConnection)mRingingCall.mConnections.get(n);

                    mDroppedDuringPoll.add(cn);

                }

                mForegroundCall.setGeneric(false);

                mRingingCall.setGeneric(false);

 

                // Re-start Ecm timer when the connected emergency call ends

                if (mIsEcmTimerCanceled) {

                    handleEcmTimer(CDMAPhone.RESTART_ECM_TIMER);

                }

                // If emergency call is not going through while dialing

                checkAndEnableDataCallAfterEmergencyCallDropped();

 

                // Dropped connections are removed from the CallTracker

                // list but kept in the Call list

                mConnections[i] = null;

            } else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */

                // 来去电冲突处理

                if (conn.isIncoming() != dc.isMT) {

                    if (dc.isMT == true){

                        // 来电优先,此时并不会出现双方都放弃连接的问题,因为MO还没有发至RIL

                        mDroppedDuringPoll.add(conn);

                        // 检测MT call是不是新来电或者unknown connection

                        newRinging = checkMtFindNewRinging(dc,i);

                        if (newRinging == null) {

                            unknownConnectionAppeared = true;

                            newUnknown = conn;

                        }

                        checkAndEnableDataCallAfterEmergencyCallDropped();

                    } else {

              // Call info stored in conn is not consistent with the call info from dc.

              // We should follow the rule of MT calls taking precedence over MO calls

               // when there is conflict, so here we drop the call info from dc and

              // continue to use the call info from conn, and only take a log.

                        Rlog.e(LOG_TAG,"Error in RIL, Phantom call appeared " + dc);

                    }

                } else {

                    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 (mPendingMO != null) {

            Rlog.d(LOG_TAG,"Pending MO dropped before poll fg state:"

                            + mForegroundCall.getState());

 

            mDroppedDuringPoll.add(mPendingMO);

            mPendingMO = null;

            mHangupPendingMO = false;

            if( mPendingCallInEcm) {

                mPendingCallInEcm = false;

            }

            checkAndEnableDataCallAfterEmergencyCallDropped();

        }

 

        if (newRinging != null) {//处理新来电

            mPhone.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 = mDroppedDuringPoll.size() - 1; i >= 0 ; i--) {

            CdmaConnection conn = mDroppedDuringPoll.get(i);

 

            if (conn.isIncoming() && conn.getConnectTime() == 0) {

                // Missed or rejected call

                int cause;

                if (conn.mCause == DisconnectCause.LOCAL) {

                    cause = DisconnectCause.INCOMING_REJECTED;

                } else {

                    cause = DisconnectCause.INCOMING_MISSED;

                }

 

                if (Phone.DEBUG_PHONE) {

                    log("missed/rejected call, conn.cause=" + conn.mCause);

                    log("setting cause to " + cause);

                }

                mDroppedDuringPoll.remove(i);

                hasAnyCallDisconnected |= conn.onDisconnect(cause);

            } else if (conn.mCause == DisconnectCause.LOCAL

                    || conn.mCause == DisconnectCause.INVALID_NUMBER) {

                mDroppedDuringPoll.remove(i);

                hasAnyCallDisconnected |= conn.onDisconnect(conn.mCause);

            }

        }

 

        /* Disconnect any pending Handover connections */

        for (Connection hoConnection : mHandoverConnections) {

            log("handlePollCalls - disconnect hoConn= " + hoConnection.toString());

            ((ImsPhoneConnection)hoConnection).onDisconnect(DisconnectCause.NOT_VALID);

            mHandoverConnections.remove(hoConnection);

        }

 

        // Any non-local disconnects: determine cause

        if (mDroppedDuringPoll.size() > 0) {

            mCi.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 || hasAnyCallDisconnected) {

            internalClearDisconnected();

        }

 

        updatePhoneState();

 

        if (unknownConnectionAppeared) {

            mPhone.notifyUnknownConnection(newUnknown);

        }

 

        if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) {

            mPhone.notifyPreciseCallStateChanged();

        }

 

        //dumpState();

    }

接着是RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED消息的处理,同样的过程,其交

由RIL.processUnsolicited()处理。可以看到此方法与之前的processSolicited很类似。

private void processUnsolicited (Parcel p) {

        int response;

        Object ret;

 

        response = p.readInt();

 

        try {switch(response) {

/*

 cat libs/telephony/ril_unsol_commands.h \

 | egrep "^ *{RIL_" \

 | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: \2(rr, p); break;/'

*/

 

            case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: ret =  responseVoid(p); break;

            case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret =  responseVoid(p); break;

            case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: ret =  responseVoid(p); break;

            case RIL_UNSOL_RESPONSE_NEW_SMS: ret =  responseString(p); break;

            case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: ret =  responseString(p); break;

            case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: ret =  responseInts(p); break;

            case RIL_UNSOL_ON_USSD: ret =  responseStrings(p); break;

            case RIL_UNSOL_NITZ_TIME_RECEIVED: ret =  responseString(p); break;

            case RIL_UNSOL_SIGNAL_STRENGTH: ret = responseSignalStrength(p); break;

            case RIL_UNSOL_DATA_CALL_LIST_CHANGED: ret = responseDataCallList(p);break;

            case RIL_UNSOL_SUPP_SVC_NOTIFICATION: ret = responseSuppServiceNotification(p); break;

            case RIL_UNSOL_STK_SESSION_END: ret = responseVoid(p); break;

            case RIL_UNSOL_STK_PROACTIVE_COMMAND: ret = responseString(p); break;

            case RIL_UNSOL_STK_EVENT_NOTIFY: ret = responseString(p); break;

            case RIL_UNSOL_STK_CALL_SETUP: ret = responseInts(p); break;

            case RIL_UNSOL_SIM_SMS_STORAGE_FULL: ret =  responseVoid(p); break;

            case RIL_UNSOL_SIM_REFRESH: ret =  responseSimRefresh(p); break;

            case RIL_UNSOL_CALL_RING: ret =  responseCallRing(p); break;

            case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break;

            case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:  ret =  responseVoid(p); break;

            case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS:  ret =  responseCdmaSms(p); break;

            case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:  ret =  responseRaw(p); break;

            case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL:  ret =  responseVoid(p); break;

            case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break;

            case RIL_UNSOL_CDMA_CALL_WAITING: ret = responseCdmaCallWaiting(p); break;

            case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: ret = responseInts(p); break;

            case RIL_UNSOL_CDMA_INFO_REC: ret = responseCdmaInformationRecord(p); break;

            case RIL_UNSOL_OEM_HOOK_RAW: ret = responseRaw(p); break;

            case RIL_UNSOL_RINGBACK_TONE: ret = responseInts(p); break;

            case RIL_UNSOL_RESEND_INCALL_MUTE: ret = responseVoid(p); break;

            case RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED: ret = responseInts(p); break;

            case RIL_UNSOl_CDMA_PRL_CHANGED: ret = responseInts(p); break;

            case RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break;

            case RIL_UNSOL_RIL_CONNECTED: ret = responseInts(p); break;

            case RIL_UNSOL_VOICE_RADIO_TECH_CHANGED: ret =  responseInts(p); break;

            case RIL_UNSOL_CELL_INFO_LIST: ret = responseCellInfoList(p); break;

            case RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED: ret =  responseVoid(p); break;

            case RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED: ret =  responseInts(p); break;

            case RIL_UNSOL_SRVCC_STATE_NOTIFY: ret = responseInts(p); break;

            case RIL_UNSOL_HARDWARE_CONFIG_CHANGED: ret = responseHardwareConfig(p); break;

            case RIL_UNSOL_RADIO_CAPABILITY:

                    ret = responseRadioCapability(p); break;

            case RIL_UNSOL_ON_SS: ret =  responseSsData(p); break;

            case RIL_UNSOL_STK_CC_ALPHA_NOTIFY: ret =  responseString(p); break;

            case RIL_UNSOL_LCEDATA_RECV: ret = responseLceData(p); break;

 

            default:

                throw new RuntimeException("Unrecognized unsol response: " + response);

            //break; (implied)

        }} catch (Throwable tr) {

            Rlog.e(RILJ_LOG_TAG, "Exception processing unsol response: " + response +

                "Exception:" + tr.toString());

            return;

        }

 

        switch(response) {

            case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:

                /* has bonus radio state int */

                RadioState newState = getRadioStateFromInt(p.readInt());

                if (RILJ_LOGD) unsljLogMore(response, newState.toString());

 

                switchToRadioState(newState);

            break;

            case RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED:

                if (RILJ_LOGD) unsljLog(response);

 

                mImsNetworkStateChangedRegistrants

                    .notifyRegistrants(new AsyncResult(null, null, null));

            break;

            case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:

                if (RILJ_LOGD) unsljLog(response);

 

                mCallStateRegistrants//发出通知(RegistrantList消息处理机制)

                    .notifyRegistrants(new AsyncResult(null, null, null));

            break;

            case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED:

                if (RILJ_LOGD) unsljLog(response);

 

                mVoiceNetworkStateRegistrants

                    .notifyRegistrants(new AsyncResult(null, null, null));

            break;

            case RIL_UNSOL_RESPONSE_NEW_SMS: {

                if (RILJ_LOGD) unsljLog(response);

 

                // FIXME this should move up a layer

                String a[] = new String[2];

 

                a[1] = (String)ret;

 

                SmsMessage sms;

 

                sms = SmsMessage.newFromCMT(a);

                if (mGsmSmsRegistrant != null) {

                    mGsmSmsRegistrant

                        .notifyRegistrant(new AsyncResult(null, sms, null));

                }

            break;

            }

            case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mSmsStatusRegistrant != null) {

                    mSmsStatusRegistrant.notifyRegistrant(

                            new AsyncResult(null, ret, null));

                }

            break;

            case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                int[] smsIndex = (int[])ret;

 

                if(smsIndex.length == 1) {

                    if (mSmsOnSimRegistrant != null) {

                        mSmsOnSimRegistrant.

                                notifyRegistrant(new AsyncResult(null, smsIndex, null));

                    }

                } else {

                    if (RILJ_LOGD) riljLog(" NEW_SMS_ON_SIM ERROR with wrong length "

                            + smsIndex.length);

                }

            break;

            case RIL_UNSOL_ON_USSD:

                String[] resp = (String[])ret;

 

                if (resp.length < 2) {

                    resp = new String[2];

                    resp[0] = ((String[])ret)[0];

                    resp[1] = null;

                }

                if (RILJ_LOGD) unsljLogMore(response, resp[0]);

                if (mUSSDRegistrant != null) {

                    mUSSDRegistrant.notifyRegistrant(

                        new AsyncResult (null, resp, null));

                }

            break;

            case RIL_UNSOL_NITZ_TIME_RECEIVED:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                // has bonus long containing milliseconds since boot that the NITZ

                // time was received

                long nitzReceiveTime = p.readLong();

 

                Object[] result = new Object[2];

 

                result[0] = ret;

                result[1] = Long.valueOf(nitzReceiveTime);

 

                boolean ignoreNitz = SystemProperties.getBoolean(

                        TelephonyProperties.PROPERTY_IGNORE_NITZ, false);

 

                if (ignoreNitz) {

                    if (RILJ_LOGD) riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED");

                } else {

                    if (mNITZTimeRegistrant != null) {

 

                        mNITZTimeRegistrant

                            .notifyRegistrant(new AsyncResult (null, result, null));

                    }

                    // in case NITZ time registrant isn't registered yet, or a new registrant

                    // registers later

                    mLastNITZTimeInfo = result;

                }

            break;

 

            case RIL_UNSOL_SIGNAL_STRENGTH:

                // Note this is set to "verbose" because it happens

                // frequently

                if (RILJ_LOGV) unsljLogvRet(response, ret);

 

                if (mSignalStrengthRegistrant != null) {

                    mSignalStrengthRegistrant.notifyRegistrant(

                                        new AsyncResult (null, ret, null));

                }

            break;

            case RIL_UNSOL_DATA_CALL_LIST_CHANGED:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                mDataNetworkStateRegistrants.notifyRegistrants(new AsyncResult(null, ret, null));

            break;

 

            case RIL_UNSOL_SUPP_SVC_NOTIFICATION:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mSsnRegistrant != null) {

                    mSsnRegistrant.notifyRegistrant(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_STK_SESSION_END:

                if (RILJ_LOGD) unsljLog(response);

 

                if (mCatSessionEndRegistrant != null) {

                    mCatSessionEndRegistrant.notifyRegistrant(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_STK_PROACTIVE_COMMAND:

                if (RILJ_LOGD) unsljLog(response);

 

                if (mCatProCmdRegistrant != null) {

                    mCatProCmdRegistrant.notifyRegistrant(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_STK_EVENT_NOTIFY:

                if (RILJ_LOGD) unsljLog(response);

 

                if (mCatEventRegistrant != null) {

                    mCatEventRegistrant.notifyRegistrant(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_STK_CALL_SETUP:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mCatCallSetUpRegistrant != null) {

                    mCatCallSetUpRegistrant.notifyRegistrant(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_SIM_SMS_STORAGE_FULL:

                if (RILJ_LOGD) unsljLog(response);

 

                if (mIccSmsFullRegistrant != null) {

                    mIccSmsFullRegistrant.notifyRegistrant();

                }

                break;

 

            case RIL_UNSOL_SIM_REFRESH:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mIccRefreshRegistrants != null) {

                    mIccRefreshRegistrants.notifyRegistrants(

                            new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_CALL_RING:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mRingRegistrant != null) {

                    mRingRegistrant.notifyRegistrant(

                            new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_RESTRICTED_STATE_CHANGED:

                if (RILJ_LOGD) unsljLogvRet(response, ret);

                if (mRestrictedStateRegistrant != null) {

                    mRestrictedStateRegistrant.notifyRegistrant(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:

                if (RILJ_LOGD) unsljLog(response);

 

                if (mIccStatusChangedRegistrants != null) {

                    mIccStatusChangedRegistrants.notifyRegistrants();

                }

                break;

 

            case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS:

                if (RILJ_LOGD) unsljLog(response);

 

                SmsMessage sms = (SmsMessage) ret;

 

                if (mCdmaSmsRegistrant != null) {

                    mCdmaSmsRegistrant

                        .notifyRegistrant(new AsyncResult(null, sms, null));

                }

                break;

 

            case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:

                if (RILJ_LOGD) unsljLogvRet(response, IccUtils.bytesToHexString((byte[])ret));

 

                if (mGsmBroadcastSmsRegistrant != null) {

                    mGsmBroadcastSmsRegistrant

                        .notifyRegistrant(new AsyncResult(null, ret, null));

                }

                break;

 

            case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL:

                if (RILJ_LOGD) unsljLog(response);

 

                if (mIccSmsFullRegistrant != null) {

                    mIccSmsFullRegistrant.notifyRegistrant();

                }

                break;

 

            case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE:

                if (RILJ_LOGD) unsljLog(response);

 

                if (mEmergencyCallbackModeRegistrant != null) {

                    mEmergencyCallbackModeRegistrant.notifyRegistrant();

                }

                break;

 

            case RIL_UNSOL_CDMA_CALL_WAITING:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mCallWaitingInfoRegistrants != null) {

                    mCallWaitingInfoRegistrants.notifyRegistrants(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mOtaProvisionRegistrants != null) {

                    mOtaProvisionRegistrants.notifyRegistrants(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_CDMA_INFO_REC:

                ArrayList listInfoRecs;

 

                try {

                    listInfoRecs = (ArrayList)ret;

                } catch (ClassCastException e) {

                    Rlog.e(RILJ_LOG_TAG, "Unexpected exception casting to listInfoRecs", e);

                    break;

                }

 

                for (CdmaInformationRecords rec : listInfoRecs) {

                    if (RILJ_LOGD) unsljLogRet(response, rec);

                    notifyRegistrantsCdmaInfoRec(rec);

                }

                break;

 

            case RIL_UNSOL_OEM_HOOK_RAW:

                if (RILJ_LOGD) unsljLogvRet(response, IccUtils.bytesToHexString((byte[]) ret));

                if (mUnsolOemHookRawRegistrant != null) {

                    mUnsolOemHookRawRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));

                }

                break;

 

            case RIL_UNSOL_RINGBACK_TONE:

                if (RILJ_LOGD) unsljLogvRet(response, ret);

                if (mRingbackToneRegistrants != null) {

                    boolean playtone = (((int[])ret)[0] == 1);

                    mRingbackToneRegistrants.notifyRegistrants(

                                        new AsyncResult (null, playtone, null));

                }

                break;

 

            case RIL_UNSOL_RESEND_INCALL_MUTE:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mResendIncallMuteRegistrants != null) {

                    mResendIncallMuteRegistrants.notifyRegistrants(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_VOICE_RADIO_TECH_CHANGED:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mVoiceRadioTechChangedRegistrants != null) {

                    mVoiceRadioTechChangedRegistrants.notifyRegistrants(

                            new AsyncResult(null, ret, null));

                }

                break;

 

            case RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mCdmaSubscriptionChangedRegistrants != null) {

                    mCdmaSubscriptionChangedRegistrants.notifyRegistrants(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOl_CDMA_PRL_CHANGED:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mCdmaPrlChangedRegistrants != null) {

                    mCdmaPrlChangedRegistrants.notifyRegistrants(

                                        new AsyncResult (null, ret, null));

                }

                break;

 

            case RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mExitEmergencyCallbackModeRegistrants != null) {

                    mExitEmergencyCallbackModeRegistrants.notifyRegistrants(

                                        new AsyncResult (null, null, null));

                }

                break;

 

            case RIL_UNSOL_RIL_CONNECTED: {

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                // Initial conditions

                setRadioPower(false, null);

                setCdmaSubscriptionSource(mCdmaSubscription, null);

                setCellInfoListRate(Integer.MAX_VALUE, null);

                notifyRegistrantsRilConnectionChanged(((int[])ret)[0]);

                break;

            }

            case RIL_UNSOL_CELL_INFO_LIST: {

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mRilCellInfoListRegistrants != null) {

                    mRilCellInfoListRegistrants.notifyRegistrants(

                                        new AsyncResult (null, ret, null));

                }

                break;

            }

            case RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED: {

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mSubscriptionStatusRegistrants != null) {

                    mSubscriptionStatusRegistrants.notifyRegistrants(

                                        new AsyncResult (null, ret, null));

                }

                break;

            }

            case RIL_UNSOL_SRVCC_STATE_NOTIFY: {

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mSrvccStateRegistrants != null) {

                    mSrvccStateRegistrants

                            .notifyRegistrants(new AsyncResult(null, ret, null));

                }

                break;

            }

            case RIL_UNSOL_HARDWARE_CONFIG_CHANGED:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mHardwareConfigChangeRegistrants != null) {

                    mHardwareConfigChangeRegistrants.notifyRegistrants(

                                             new AsyncResult (null, ret, null));

                }

                break;

            case RIL_UNSOL_RADIO_CAPABILITY:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mPhoneRadioCapabilityChangedRegistrants != null) {

                    mPhoneRadioCapabilityChangedRegistrants.notifyRegistrants(

                            new AsyncResult(null, ret, null));

                 }

                 break;

            case RIL_UNSOL_ON_SS:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mSsRegistrant != null) {

                    mSsRegistrant.notifyRegistrant(

                                        new AsyncResult (null, ret, null));

                }

                break;

            case RIL_UNSOL_STK_CC_ALPHA_NOTIFY:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mCatCcAlphaRegistrant != null) {

                    mCatCcAlphaRegistrant.notifyRegistrant(

                                        new AsyncResult (null, ret, null));

                }

                break;

            case RIL_UNSOL_LCEDATA_RECV:

                if (RILJ_LOGD) unsljLogRet(response, ret);

 

                if (mLceInfoRegistrant != null) {

                    mLceInfoRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));

                }

                break;

        }

    }

经过分析,EVENT_CALL_STATE_CHANGE消息将在CdmaCallTracker.java文件中的handleMessage()方法中被处理,这和之前的消息处理都类似。(请查看之前CdmaCallTracker代码)。发现最终的处理函数为pollCallsWhenSafe()。如下:

protected void pollCallsWhenSafe() {

        mNeedsPoll = true;

 

        if (checkNoOperationsPending()) {

            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);

            mCi.getCurrentCalls(mLastRelevantPoll);//与之前一样的方法调用

        }

    }

可看到之前基本类似的流程。之后的很多消息都是通过类似的过程进行处理的。在此就不予赘述。

1.6   RIL

请看本博客另一篇关于RIL的博文http://blog.csdn.net/a34140974/article/details/50578324

1.7   小结

大概的调用路径如下图所示(中间省略很多):

Android6.0的phone应用源码分析(4)——phone拨号流程分析_第2张图片

有个小错误(左下大框应应该为TeleComFrameWork)

应该注意到的是这些箭头只代表了逻辑的走向,并不一定是程序的真正流向。尤其是对于android系统的中很多系统服务都是以C/S、RPC方式提供的,进程或线程空间的切换分析对于理解整个应用的流程变得尤为重要。以下作图并不严谨,仅供参考。

总结一下就是Dialer→TeleComService→TeleComFramework→TeleponyService→TelephonyFramework→RIL


 

你可能感兴趣的:(Android)