美文网首页
Android7.0 拨号流程源码分析

Android7.0 拨号流程源码分析

作者: 小的橘子 | 来源:发表于2019-01-30 21:14 被阅读0次
    拨号流程概览

    1. 应用进程

    从点击拨号按钮流程说起
    packages/apps/Dialer/src/com/android/dialer/dialpad/DialpadFragment.java

    @Override
    public void onClick(View view) {
        int resId = view.getId();
        if (resId == R.id.dialpad_floating_action_button) {
            view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
            // 执行该方法
            handleDialButtonPressed();
        } else if (resId == R.id.deleteButton) {
            keyPressed(KeyEvent.KEYCODE_DEL);
        } ...
    }
    

    handleDialButtonPressed又会调用handleDialButtonPressed(Constants.DIAL_NUMBER_INTENT_NORMAL);
    packages/apps/Dialer/src/com/android/dialer/dialpad/DialpadFragment.java

    private void handleDialButtonPressed(int type) {
        if (isDigitsEmpty()) { // No number entered.
            handleDialButtonClickWithEmptyDigits();
        } else {
            final String number = mDigits.getText().toString();
            // 1. 通过mProhibitedPhoneNumberRegexp正则表达式判断号码是否被禁止
            if (number != null
                    && !TextUtils.isEmpty(mProhibitedPhoneNumberRegexp)
                    && number.matches(mProhibitedPhoneNumberRegexp)) {
                Log.i(TAG, "The phone number is prohibited explicitly by a rule.");
                ...
            } else {
                final Intent intent;
                /** M: [IP Dial] check the type of call @{ */
                if (type != Constants.DIAL_NUMBER_INTENT_NORMAL) {
                    intent = IntentUtil.getCallIntent(IntentUtil.getCallUri(number),
                            LogState.INITIATION_DIALPAD, type);
                } else {
                    // 2. 封装拨号Intent
                    intent = new CallIntentBuilder(number).
                            setCallInitiationType(LogState.INITIATION_DIALPAD)
                            .build();
                }
                /** @} */
                // 3. 启动对应Intent
                DialerUtils.startActivityWithErrorToast(getActivity(), intent);
                hideAndClearDialpad(false);
            }
        }
    }
    

    跟踪步骤2流程可知该Intent由以下几个部分组成

    • Action为:Intent.ACTION_CALL(android.intent.action.CALL)
    • Flag为:FLAG_ACTIVITY_NEW_TASK
    • 号码uri为 tel:10010

    步骤3中startActivityWithErrorToast方法会调用到如下方法
    packages/apps/Dialer/src/com/android/dialer/util/DialerUtils.java

    public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) {
        try {
            if ((IntentUtil.CALL_ACTION.equals(intent.getAction())
                            && context instanceof Activity)) {
                ...
                // 1. 调用TelecomUtil的placeCall继续处理
                final boolean hasCallPermission = TelecomUtil.placeCall((Activity) context, intent);
                if (!hasCallPermission) {
                    Toast.makeText(context, "Cannot place call without Phone permission",
                            Toast.LENGTH_SHORT);
                }
            }
            ...
        } catch (ActivityNotFoundException e) {
            Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show();
        }
    }
    

    packages/apps/Dialer/src/com/android/dialer/util/TelecomUtil.java

    public static boolean placeCall(Activity activity, Intent intent) {
        // 1.
        if (hasCallPhonePermission(activity)) {
            // 2.
            TelecomManagerCompat.placeCall(activity, getTelecomManager(activity), intent);
            return true;
        }
        return false;
    }
    
    

    hasCallPhonePermission方法返回true的条件

    • 当前Dialer为系统默认Dialer
    • 检查Manifest.permission.CALL_PHONE权限是否已经授权

    packages/apps/ContactsCommon/src/com/android/contacts/common/compat/telecom/TelecomManagerCompat.java

    public static void placeCall(@Nullable Activity activity,
                @Nullable TelecomManager telecomManager, @Nullable Intent intent) {
        if (activity == null || telecomManager == null || intent == null) {
            return;
        }
        // 当前平台N > M,返回true
        if (CompatUtils.isMarshmallowCompatible()) {
            telecomManager.placeCall(intent.getData(), intent.getExtras());
            return;
        }
        activity.startActivityForResult(intent, 0);
    }
    

    frameworks/base/telecomm/java/android/telecom/TelecomManager.java

    public void placeCall(Uri address, Bundle extras) {
        // 1. 通过AIDL得到TelecomService的服务端的代理
        ITelecomService service = getTelecomService();
        if (service != null) {
            if (address == null) {
                Log.w(TAG, "Cannot place call to empty address.");
            }
            try {
                // 2. TelecomService进一步处理call
                service.placeCall(address, extras == null ? new Bundle() : extras,
                        mContext.getOpPackageName());
            } catch (RemoteException e) {
                Log.e(TAG, "Error calling ITelecomService#placeCall", e);
            }
        }
    }
    
    1. 首先通过getTelecomService方法内部为ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE)) 得到TelecomService的服务端代理。通过AIDL使用规则搜索new ITelecomService.Stub(),即可看到服务端在TelecomServiceImpl中实现。
    2. 调用placeCall进一步处理,此处address就是tel:10010

    2. Telecom进程处理

    packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java

    private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
        /**
         * @see android.telecom.TelecomManager#placeCall
         */
        @Override
        public void placeCall(Uri handle, Bundle extras, String callingPackage) {
            try {
                ...
                synchronized (mLock) {
                    final UserHandle userHandle = Binder.getCallingUserHandle();
                    long token = Binder.clearCallingIdentity();
                    try {
                        final Intent intent = new Intent(Intent.ACTION_CALL, handle);
                        if (extras != null) {
                            extras.setDefusable(true);
                            intent.putExtras(extras);
                        }
                        // 1. create得到的是UserCallIntentProcessor对象,然后进一步处理拨打电话的Intent
                        mUserCallIntentProcessorFactory.create(mContext, userHandle)
                                .processIntent(
                                        intent, callingPackage, hasCallAppOp && hasCallPermission);
                    } 
                    ...
    }
    

    通过UserCallIntentProcessor的processIntent方法进一步处理拨打电话的Intent

    packages/services/Telecomm/src/com/android/server/telecom/components/UserCallIntentProcessor.java

    /**
     * Processes intents sent to the activity.
     *
     * @param intent The intent.
     */
    public void processIntent(Intent intent, String callingPackageName,
            boolean canCallNonEmergency) {
        // 1. 判断是否支持语音通话,通过读取config_voice_capable值
        if (!isVoiceCapable()) {
            return;
        }
        String action = intent.getAction();
    
        // 2. 判断ACTION是否为打电话
        if (Intent.ACTION_CALL.equals(action) ||
                Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
                Intent.ACTION_CALL_EMERGENCY.equals(action)) {
            processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);
        }
    }
    private void processOutgoingCallIntent(Intent intent, String callingPackageName,
                boolean canCallNonEmergency) {
        ...
        // 3. 将是否为默认Dialer或是系统的Dialer的boolean值放入Intent的Extra中
        intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
                isDefaultOrSystemDialer(callingPackageName));
    
        intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);
        sendBroadcastToReceiver(intent);
    }
    private boolean sendBroadcastToReceiver(Intent intent) {
        // 4. 进一步完善Intent
        intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        intent.setClass(mContext, PrimaryCallReceiver.class);
        Log.d(this, "Sending broadcast as user to CallReceiver");
        // 5. 发送广播,只有系统用户可以接收
        mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
        return true;
    }
    
    1. 判断config_voice_capable判断语音通话是否支持,该值在frameworks/base/core/res/res/values/strings.xml中配置
    2. 判断Action是否为ACTION_CALL,Intent.ACTION_CALL_PRIVILEGED,Intent.ACTION_CALL_EMERGENCY之一,是才继续处理
    3. MO 的Intent添加是否为默认Dialer或者系统Dialer的信息
      • 默认Dialer通过获取数据库判断
      Settings.Secure.getStringForUser(context.getContentResolver(),
                  Settings.Secure.DIALER_DEFAULT_APPLICATION, user);
      
      • 系统Dialer通过packages/services/Telecomm/res/values/config.xml中如下属性获取
      <string name="ui_default_package" translatable="false">com.android.dialer</string>
      
    4. MO 的Intent添加如下信息
      • 是否来电 由于是去电,故为false
      • 指定接收广播的类为PrimaryCallReceiver
    5. 发送广播,指定只有System用户可以接收该广播

    packages/services/Telecomm/src/com/android/server/telecom/components/PrimaryCallReceiver.java

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.startSession("PCR.oR");
        synchronized (getTelecomSystem().getLock()) {
            if (!ExtensionManager.getCallMgrExt()
                    .shouldPreventVideoCallIfLowBattery(context, intent)) {
                getTelecomSystem().getCallIntentProcessor().processIntent(intent);
            }
        }
        Log.endSession();
    }
    

    getTelecomSystem().getCallIntentProcessor()返回的类型为CallIntentProcessor,通过processIntent方法将接收到的Intent进一步处理

    packages/services/Telecomm/src/com/android/server/telecom/CallIntentProcessor.java

    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 {
            processOutgoingCallIntent(mContext, mCallsManager, intent);
        }
        Trace.endSection();
    }
    

    前面并没有设置KEY_IS_UNKNOWN_CALL属性,故为false,走processOutgoingCallIntent

    packages/services/Telecomm/src/com/android/server/telecom/CallIntentProcessor.java

    /**
     * Processes CALL, CALL_PRIVILEGED, and CALL_EMERGENCY intents.
     *
     * @param intent Call intent containing data about the handle to call.
     */
    static void processOutgoingCallIntent(
            Context context,
            CallsManager callsManager,
            Intent intent) {
        ...
        // 1. 创建Call对象
        Call call = callsManager
                .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);
        if (call != null) {
            NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
                    context, callsManager, call, intent, new PhoneNumberUtilsAdapterImpl(),
                    isPrivilegedDialer);
            // 2. 
            final int result = broadcaster.processIntent();
            final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
    
            if (!success && call != null) {
                disconnectCallAndShowErrorDialog(context, call, result);
            }
        }
    }
    
    1. 先看下call对象是如何创建并拉起IncallUI界面
      packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
    Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras,
            UserHandle initiatingUser) {
        boolean isReusedCall = true;
        Call call = reuseOutgoingCall(handle);
        // 1. 创建Call对象    
        if (call == null) {
            call = new Call(getNextCallId(), mContext,
                    this,
                    mLock,
                    mConnectionServiceRepository,
                    mContactsAsyncHelper,
                    mCallerInfoAsyncQueryFactory,
                    handle,
                    null /* gatewayInfo */,
                    null /* connectionManagerPhoneAccount */,
                    null /* phoneAccountHandle */,
                    Call.CALL_DIRECTION_OUTGOING /* callDirection */,
                    false /* forceAttachToExistingConnection */,
                    false /* isConference */
            );
            call.setInitiatingUser(initiatingUser);
            call.initAnalytics();
            isReusedCall = false;
        }
        ...
        // 获取当前激活的卡列表
        List<PhoneAccountHandle> accounts = constructPossiblePhoneAccounts(handle, initiatingUser);
        Log.v(this, "startOutgoingCall found accounts = " + accounts);
        if (phoneAccountHandle == null && accounts.size() > 0 && !call.isEmergencyCall()) {
            if(accounts.size() > 1) {
                // 双激活卡下取通话主卡账户,没有通话主卡则为空
                PhoneAccountHandle defaultPhoneAccountHandle =
                        mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(handle.getScheme(),
                                initiatingUser);
                if (defaultPhoneAccountHandle != null &&
                        accounts.contains(defaultPhoneAccountHandle)) {
                    phoneAccountHandle = defaultPhoneAccountHandle;
                }
            } else {
                // 单激活卡直接取该卡账户
                phoneAccountHandle = accounts.get(0);
            }
        }
        ...
    
        call.setTargetPhoneAccount(phoneAccountHandle);
    
        boolean isPotentialInCallMMICode = isPotentialInCallMMICode(handle);
    
        if (!isReusedCall && !makeRoomForOutgoingCall(call, call.isEmergencyCall())) {
            // just cancel at this point.
            Log.d(this, "No remaining room for outgoing call: %s", call);
            showToastInfomation(mContext.getResources()
                    .getString(R.string.outgoing_call_failed));
            if (mCalls.contains(call)) {
                // This call can already exist if it is a reused call,
                // See {@link #reuseOutgoingCall}.
                call.disconnect();
            }
            return null;
        }
    
        boolean needsAccountSelection = phoneAccountHandle == null && accounts.size() > 1 &&
                !call.isEmergencyCall();
    
        Log.i(this, "MO - dump: needSelect = %s; phoneAccountHandle = %s; accounts.size() = %s.",
                needsAccountSelection, phoneAccountHandle, accounts.size());
    
        
        // 是否需要弹出双卡选择框(双卡下没有指定账户呼出非紧急号码且当前无通话主卡)
        if (needsAccountSelection) {
            // 设置当前call为等待用户选择SIM卡状态CallState.SELECT_PHONE_ACCOUNT
            call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection");
            extras = new Bundle(extras);
            extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, accounts);
        } else {
            // 设置当前call为连接状态CallState.CONNECTING
            call.setState(
                    CallState.CONNECTING,
                    phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
        }
    
        setIntentExtrasAndStartTime(call, extras);
    
        // 如果是MMI Code 不添加call到mCalls列表中
        if ((isPotentialMMICode(handle) || isPotentialInCallMMICode)
                && TelecomUtils.isSupportMMICode(call.getTargetPhoneAccount())
                && !needsAccountSelection) {
            call.addListener(this);
        } else if (!mCalls.contains(call)) {
            // We check if mCalls already contains the call because we could potentially be reusing
            // a call which was previously added (See {@link #reuseOutgoingCall}).
            // 添加当前call到mCalls列表中
            addCall(call);
        }
        return call;
    }
    

    看下addCall方法

    private void addCall(Call call) {
        ...
        call.addListener(this);
        // 1. 将call添加到mCall列表中
        mCalls.add(call);
        ...
        // 2. 遍历所有mListeners调用onCallAdded方法
        for (CallsManagerListener listener : mListeners) {
            listener.onCallAdded(call);
        }
        Trace.endSection();
    }
    
    

    mListeners主要来源于CallManager的构造方法中添加的Listener

    mListeners.add(mInCallWakeLockController);
    mListeners.add(statusBarNotifier);
    mListeners.add(mCallLogManager);
    mListeners.add(mPhoneStateBroadcaster);
    mListeners.add(mInCallController);
    mListeners.add(mCallAudioManager);
    mListeners.add(missedCallNotifier);
    mListeners.add(mHeadsetMediaButton);
    mListeners.add(mProximitySensorManager);
    ///M: add listener for phone recording
    mListeners.add(PhoneRecorderHandler.getInstance());
    

    这里说下mInCallController,其实InCallController对象,内部封装了与incallui服务的相关操作,实际上就是一个远程服务代理类,当callsmanager添加一路call时, 回调InCallController的onCallAdded方法

    @Override
    public void onCallAdded(Call call) {
        if (!isBoundToServices()) {
            bindToServices(call);
        } else {
            adjustServiceBindingsForEmergency();
            addCall(call);
    
            for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
                ComponentName componentName = entry.getKey();
                IInCallService inCallService = entry.getValue();
                ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
                        true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar());
                try {
                    // 1.
                    inCallService.addCall(parcelableCall);
                } catch (RemoteException ignored) {
                }
            }
        }
    }
    

    调用inCallService的addCall方法告诉incallui当前添加了一路通话,incallui收到后会拉起界面,具体过程在此就不详述了。

    1. 接着刚才得到call对象后的下一步分析,通过NewOutgoingCallIntentBroadcaster对象的的processIntent()进一步做处理

    packages/services/Telecomm/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java

    public int processIntent() {
        Intent intent = mIntent;
        ...
        boolean isVoicemailNumber = PhoneAccount.SCHEME_VOICEMAIL.equals(handle.getScheme());
        // 1. 如果语音信箱的号码调用CallsManager的placeOutgoingCall方法直接拨号
        if (isVoicemailNumber) {
            if (Intent.ACTION_CALL.equals(action)
                    || Intent.ACTION_CALL_PRIVILEGED.equals(action)) {
                // 标识call已准备就绪
                mCall.setNewOutgoingCallIntentBroadcastIsDone();
                ...
                mCallsManager.placeOutgoingCall(mCall, handle, null, speakerphoneOn,
                        VideoProfile.STATE_AUDIO_ONLY);
    
                return DisconnectCause.NOT_DISCONNECTED;
            } else {
                Log.d(this, "Unhandled intent %s. Ignoring and not placing call.", intent);
                return DisconnectCause.OUTGOING_CANCELED;
            }
        }
    
        ...
        // 判断是否为潜在的紧急拨号
        final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);
        Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);
        // 2. 根据是否是紧急拨号重新修正Action
        rewriteCallIntentAction(intent, isPotentialEmergencyNumber);
        action = intent.getAction();
        boolean callImmediately = false;
    
        if (Intent.ACTION_CALL.equals(action)) {
            if (isPotentialEmergencyNumber) {
                // 如果是系统Dialer或者默认dialer拨紧急号码则callImmediately会置为true,否则会启动系统dialer由用户进一步决定如何操作
                if (!mIsDefaultOrSystemPhoneApp) {
                    launchSystemDialer(intent.getData());
                    return DisconnectCause.OUTGOING_CANCELED;
                } else {
                    callImmediately = true;
                }
            }
        } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
            if (!isPotentialEmergencyNumber) {
                return DisconnectCause.OUTGOING_CANCELED;
            }
            callImmediately = true;
        } else {
            return DisconnectCause.INVALID_NUMBER;
        }
        // 3. 如果是紧急拨号,callImmediately会赋值为true,直接调用 mCallsManager.placeOutgoingCall进行拨号
        if (callImmediately) {
            ...
            mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,
                    speakerphoneOn, videoState);
        }
    
        UserHandle targetUser = mCall.getInitiatingUser();
        // 4. 调用该方法发送广播
        broadcastIntent(intent, number, !callImmediately, targetUser);
        return DisconnectCause.NOT_DISCONNECTED;
    }
    
    1. VoiceMail直接调用mCallsManager.placeOutgoingCall,并return
    2. rewriteCallIntentAction内部会判断如果Action是Intent.ACTION_CALL_PRIVILEGED,然后还是紧急拨号,则转化Action为Intent.ACTION_CALL_EMERGENCY,不是紧急拨号则使用Intent.ACTION_CALL
    3. 紧急拨号,callImmediately置为true,直接调用 mCallsManager.placeOutgoingCall方法拨打电话

    packages/services/Telecomm/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java

    private void broadcastIntent(
            Intent originalCallIntent,
            String number,
            boolean receiverRequired,
            UserHandle targetUser) {
        Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
        if (number != null) {
            broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
        }
        broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        checkAndCopyProviderExtras(originalCallIntent, broadcastIntent);
        mContext.sendOrderedBroadcastAsUser(
                broadcastIntent,
                targetUser,
                android.Manifest.permission.PROCESS_OUTGOING_CALLS,
                AppOpsManager.OP_PROCESS_OUTGOING_CALLS,
                receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,
                null,  // scheduler
                Activity.RESULT_OK,  // initialCode
                number,  // initialData: initial value for the result data (number to be modified)
                null);  // initialExtras
    }
    
    

    发送了一个Action为Intent.ACTION_NEW_OUTGOING_CALL的有序广播,如果是非紧急拨号,则指定最终广播接收者(也就是最后一个接收该广播)为NewOutgoingCallBroadcastIntentReceiver,紧急拨号则为空。

    NewOutgoingCallIntentBroadcaster$NewOutgoingCallBroadcastIntentReceiver.java

    **
     * Processes the result of the outgoing call broadcast intent, and performs callbacks to
     * the OutgoingCallIntentBroadcasterListener as necessary.
     */
    public class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                // 1. 得到最终拨号的号码
                String resultNumber = getResultData();
                ...
    
                Uri resultHandleUri = Uri.fromParts(
                        mPhoneNumberUtilsAdapter.isUriNumber(resultNumber) ?
                                PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL,
                        resultNumber, null);
    
                Uri originalUri = mIntent.getData();
                // 2. 打印号码是否被被其它广播接收者更改过的log
                if (originalUri.getSchemeSpecificPart().equals(resultNumber)) {
                } else {
                }
    
                GatewayInfo gatewayInfo = getGateWayInfoFromIntent(intent, resultHandleUri);
                // 标识call准备就绪
                mCall.setNewOutgoingCallIntentBroadcastIsDone();
                // 3. 调用该方法
                mCallsManager.placeOutgoingCall(mCall, resultHandleUri, gatewayInfo,
                        mIntent.getBooleanExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE,
                                false),
                        mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
                                VideoProfile.STATE_AUDIO_ONLY));
    
        ...
    }
    
    1. 得到最终的号码
    2. 判断号码是否被中间的广播接收者更改过
    3. 调用最重要的mCallsManager.placeOutgoingCall方法进行拨号,无论voicemail,emergencyNumber,正常拨号都会调用该方法进行最终的拨号。

    packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java

    public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
            boolean speakerphoneOn, int videoState) {
    
        ...
        // 1. 指定了激活的SIM卡或者是紧急拨号,就调用call.startCreateConnection方法
        if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {
            call.startCreateConnection(mPhoneAccountRegistrar);
        }
        ...
    }
    

    packages/services/Telecomm/src/com/android/server/telecom/Call.java

    void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
        mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
                phoneAccountRegistrar, mContext);
        mCreateConnectionProcessor.process();
    }
    

    创建CreateConnectionProcessor,并调用process方法

    packages/services/Telecomm/src/com/android/server/telecom/CreateConnectionProcessor.java

    public void process() {
        clearTimeout();
        mAttemptRecords = new ArrayList<>();
        if (mCall.getTargetPhoneAccount() != null) {
            mAttemptRecords.add(new CallAttemptRecord(
                    mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
        }
        adjustAttemptsForConnectionManager();
        adjustAttemptsForEmergency();
        mAttemptRecordIterator = mAttemptRecords.iterator();
        // 执行该方法
        attemptNextPhoneAccount();
    }
    
    private void attemptNextPhoneAccount() {
        ...
        PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
        // 1. 得到ConnectionServiceWrapper对象
        mService = mRepository.getService(phoneAccount.getComponentName(),
                phoneAccount.getUserHandle());
        mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
        mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
        mCall.setConnectionService(mService);
        setTimeoutIfNeeded(mService, attempt);
        // 2. 建立连接
        mService.createConnection(mCall, this);
        ...
    }
    

    packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java

    public void createConnection(final Call call, final CreateConnectionResponse response) {
        BindCallback callback = new BindCallback() {
            @Override
            public void onSuccess() {
                ...
                // 2.
                mServiceInterface.createConnection(
                        call.getConnectionManagerPhoneAccount(),
                        callId,
                        new ConnectionRequest(
                                call.getTargetPhoneAccount(),
                                call.getHandle(),
                                extras,
                                call.getVideoState(),
                                callId),
                        call.shouldAttachToExistingConnection(),
                        call.isUnknown());
                ...
            }
            ...
        };
        // 1. 内部会跨进程绑定远程Service ConnectionService
        mBinder.bind(callback, call);
    }
    
    1. 绑定远程Service ConnectionService,当绑定成功后,会调用onServiceConnected方法,该方法中会回调callback的onSuccess方法并将返回的binder对象通过IConnectionService.Stub.asInterface(binder);得到远程Service的代理,赋值给mServiceInterface
    2. IPC调用远程Service ConnectionService的createConnection方法,对应类为TelephonyConnectionService。

    3. Telephony进程

    TelephonyConnectionService的createConnection方法在父类中实现
    frameworks/base/telecomm/java/android/telecom/ConnectionService.java

    @Override
    public void createConnection(
            PhoneAccountHandle connectionManagerPhoneAccount,
            String id,
            ConnectionRequest request,
            boolean isIncoming,
            boolean isUnknown) {
        SomeArgs args = SomeArgs.obtain();
        args.arg1 = connectionManagerPhoneAccount;
        args.arg2 = id;
        args.arg3 = request;
        args.argi1 = isIncoming ? 1 : 0;
        args.argi2 = isUnknown ? 1 : 0;
        // 解析参数,并发送MSG_CREATE_CONNECTION消息交由Handler处理
        mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
    }
    
    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                ...
                case MSG_CREATE_CONNECTION: {
                    SomeArgs args = (SomeArgs) msg.obj;
                    try {
                        final PhoneAccountHandle connectionManagerPhoneAccount =
                                (PhoneAccountHandle) args.arg1;
                        final String id = (String) args.arg2;
                        final ConnectionRequest request = (ConnectionRequest) args.arg3;
                        final boolean isIncoming = args.argi1 == 1;
                        final boolean isUnknown = args.argi2 == 1;
                        ...
                        // 走该方法
                        createConnection(
                                connectionManagerPhoneAccount,
                                id,
                                request,
                                isIncoming,
                                isUnknown);
                ...
    }   
    private void createConnection(
            final PhoneAccountHandle callManagerAccount,
            final String callId,
            final ConnectionRequest request,
            boolean isIncoming,
            boolean isUnknown) {
        ...
        // 1. 来电走onCreateIncomingConnection,去电走onCreateOutgoingConnection
        Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
                : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
                : onCreateOutgoingConnection(callManagerAccount, request);
        ...
        connection.setTelecomCallId(callId);
        if (connection.getState() != Connection.STATE_DISCONNECTED) {
            addConnection(callId, connection);
        }
        ...    
    

    去电通过onCreateOutgoingConnection创建通话连接,实现在实体类TelephonyConnectionService实现。

    packages/services/Telephony/src/com/android/services/telephony/TelephonyConnectionService.java

    @Override
    public Connection onCreateOutgoingConnection(
            PhoneAccountHandle connectionManagerPhoneAccount,
            final ConnectionRequest request) {
        if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
            ...
            number = phone.getVoiceMailNumber();
            // 1. Voicemail拨号,但Voicemail号码为空错误
            if (TextUtils.isEmpty(number)) {
                return Connection.createFailedConnection(
                        DisconnectCauseUtil.toTelecomDisconnectCause(
                                android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING,
                                "Voicemail scheme provided but no voicemail number set."));
            }
            // Convert voicemail: to tel:
        }
        // 飞行模式拨号错误
        // 还有其他一些出错情况的判断,出错就会界面给出对应提示
        ...
        // 3. 继续拨号这段逻辑
        placeOutgoingConnection(connection, phone, request);
    

    packages/services/Telephony/src/com/android/services/telephony/TelephonyConnectionService.java

    private void placeOutgoingConnection(
                TelephonyConnection connection, Phone phone, ConnectionRequest request) {
        String number = connection.getAddress().getSchemeSpecificPart();
        ...
        com.android.internal.telephony.Connection originalConnection;
        try {
            originalConnection =
                    phone.dial(number, null, request.getVideoState(), request.getExtras());
        }
        ...
    }
    

    调用phone对象的dial()方法实现真正拨号.在Android N上,cdma和gsm都由GsmCdmaPhone对象统一处理。

    frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java

    @Override
    public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
            throws CallStateException {
        ...
        // VOLTE开启或者VOWIFI开启都会为true
        boolean imsUseEnabled = isImsUseEnabled()
                 && imsPhone != null
                 && (imsPhone.isVolteEnabled() || imsPhone.isWifiCallingEnabled() ||
                 (imsPhone.isVideoEnabled() && VideoProfile.isVideo(videoState)))
                 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
    
        ...
        if ((imsUseEnabled && (!isUt || useImsForUt)) || useImsForEmergency) {
            try {
                if (videoState == VideoProfile.STATE_AUDIO_ONLY) {
                    // 调用imsPhone拨打电话
                    return imsPhone.dial(dialString, uusInfo, videoState, intentExtras);
                } else {
                    if (SystemProperties.get("persist.mtk_vilte_support").equals("1")) {
                        if (DBG) {
                            Rlog.d(LOG_TAG, "Trying IMS PS video call");
                        }
                        return imsPhone.dial(dialString, uusInfo, videoState, intentExtras);
                    }...
                }
            } ...
        }
        ...
        // 正常拨号走此处
        return dialInternal(dialString, null, videoState, intentExtras);
    }
    

    frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java

    @Override
    protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
                                      Bundle intentExtras)
            throws CallStateException {
        if (isPhoneTypeGsm()) {
            if (handleInCallMmiCommands(newDialString)) {
                return null;
            }
            
            String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
            GsmMmiCode mmi =
                    GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
            if (mmi == null) {
                // 1. Gsm拨号
                return mCT.dial(newDialString, uusInfo, intentExtras);
            } else if (mmi.isTemporaryModeCLIR()) {
                return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
            } else {
                mPendingMMIs.add(mmi);
                mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
                try {
                    mmi.processCode();
                } catch (CallStateException e) {
                    //do nothing
                }
                return null;
            }
        } else {
            // 2. 非Gsm拨号
            return mCT.dial(newDialString);
        }
    }
    

    实际都是通过mCT的dial进行呼出,mCT实际为GsmCdmaCallTracker对象,这里以CDMA进行分析,也就是走注释2处。

    frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java

    private Connection dial(String dialString, int clirMode) throws CallStateException {
        // 1. 将Call设置为IDLE状态,并通知状态发生改变
        clearDisconnected();
        ...
        mPendingMO = new GsmCdmaConnection(mPhone, checkForTestEmergencyNumber(dialString),
                    this, mForegroundCall);
        if(!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) {
            /// M: Proprietary ECC handling @{
            //mCi.dial(mPendingMO.getAddress(), clirMode, obtainCompleteMessage());
            if (isEmergencyCall) {
                mCi.emergencyDial(mPendingMO.getAddress(), clirMode, null,
                        obtainCompleteMessage());
            } else {
                // 2. 通过RILJ拨打电话
                mCi.dial(mPendingMO.getAddress(), clirMode, obtainCompleteMessage());
            }
            /// @}
        }
        ...
        // 3. 在此更新Phone状态集精确的Call状态
        updatePhoneState();
        mPhone.notifyPreciseCallStateChanged();
        return mPendingMO;
    }
    
    1. 设置IDLE方法如下
    public GsmCdmaCall mRingingCall = new GsmCdmaCall(this);
    public GsmCdmaCall mForegroundCall = new GsmCdmaCall(this);
    public GsmCdmaCall mBackgroundCall = new GsmCdmaCall(this);
    public void clearDisconnected() {
        // 1. clearDisconnected内部会将Call状态设置为IDLE
        mRingingCall.clearDisconnected();
        mForegroundCall.clearDisconnected();
        mBackgroundCall.clearDisconnected();
        // 2. 内部会调用mPhone的notifyPhoneStateChanged更新Phone的状态
        updatePhoneState();
        // 3. 更新精确Phone状态
        mPhone.notifyPreciseCallStateChanged();
    }
    

    Call的所有状态为枚举类型

    public enum State {
        IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING;
    }
    
    1. mCi是CommandsInterface类型,跟踪赋值可以看到其实通过Phone对象获取的,而Phone对象是由PhoneFactory创建的,代码如下

    frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java

    public static void makeDefaultPhone(Context context) {
        ...
        int numPhones = TelephonyManager.getDefault().getPhoneCount();
        int[] networkModes = new int[numPhones];
        sPhones = new Phone[numPhones];
        sCommandsInterfaces = new RIL[numPhones];
        sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
    
        for (int i = 0; i < numPhones; i++) {
            networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;
            // 1. 创建RIL
            sCommandsInterfaces[i] = new RIL(context, networkModes[i],
                    cdmaSubscription, i);
        }
        SubscriptionController.init(context, sCommandsInterfaces);
        RadioManager.init(context, numPhones, sCommandsInterfaces);
    
        sUiccController = UiccController.make(context, sCommandsInterfaces);
    
        for (int i = 0; i < numPhones; i++) {
            Phone phone = null;
            // 2. 创建Phone对象,实际对应GsmCdmaPhone,并传入对应的RIL对象,sCommandsInterfaces[i]就对应Phone中的mCi变量
            int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
            if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
                phone = new GsmCdmaPhone(context,
                        sCommandsInterfaces[i], sPhoneNotifier, i,
                        PhoneConstants.PHONE_TYPE_GSM,
                        TelephonyComponentFactory.getInstance());
            } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                phone = new GsmCdmaPhone(context,
                        sCommandsInterfaces[i], sPhoneNotifier, i,
                        PhoneConstants.PHONE_TYPE_CDMA_LTE,
                        TelephonyComponentFactory.getInstance());
            }
            sPhones[i] = phone;
        }
    
        sPhone = sPhones[0];
        sCommandsInterface = sCommandsInterfaces[0];
    }
    

    知道了mCi是RIL,由于是java文件也称作RILJ。我们继续分析mCi.dial拨打电话的方法。

    4. RILJ与RILC的交互

    frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java

    @Override
    public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
        if (!PhoneNumberUtils.isUriNumber(address)) {
            // 1. 封装为RILRequest
           RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
            
            rr.mParcel.writeString(address);
            rr.mParcel.writeInt(clirMode);
            ...
            // 2. 调用send
            send(rr);
        } else {
            RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL_WITH_SIP_URI, result);
            
            rr.mParcel.writeString(address);
            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
            
            mEventLog.writeRilDial(rr.mSerial, clirMode, uusInfo);
            send(rr);
        }
    }
    private void send(RILRequest rr) {
        Message msg;
    
        if (mSocket == null) {
            rr.onError(RADIO_NOT_AVAILABLE, null);
            rr.release();
            return;
        }
        msg = mSender.obtainMessage(EVENT_SEND, rr);
        acquireWakeLock(rr, FOR_WAKELOCK);
        // 3. 交由mSender子线程的Handler处理
        msg.sendToTarget();
    }
    

    将拨号信息及拨号请求RIL_REQUEST_DIAL封装在RILRequest中,在注释3处交由与RILC的服务端进行通信的子线程mSender中

    class RILSender extends Handler implements Runnable {
        public RILSender(Looper looper) {
            super(looper);
        }
        byte[] dataLength = new byte[4];
    
        @Override public void
        handleMessage(Message msg) {
            RILRequest rr = (RILRequest)(msg.obj);
            RILRequest req = null;
    
            switch (msg.what) {
                case EVENT_SEND:
                case EVENT_SEND_ACK:
                    try {
                        LocalSocket s;
                        // 1. 得到客户端LocalSocket对象
                        s = mSocket;
                        ...
                        byte[] data;
                        data = rr.mParcel.marshall();
                        ...
    
                        // parcel length in big endian
                        dataLength[0] = dataLength[1] = 0;
                        dataLength[2] = (byte)((data.length >> 8) & 0xff);
                        dataLength[3] = (byte)((data.length) & 0xff);
    
                        // 2. 向服务端发送数据长度
                        s.getOutputStream().write(dataLength);
                        // 3. 向服务端发送数据
                        s.getOutputStream().write(data);
                        if (msg.what == EVENT_SEND_ACK) {
                            rr.release();
                            return;
                        }
                    } catch (IOException ex) {
                      ...
    

    当服务端给出回应后后会在RILReceiver中接收到,代码如下

    frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java

    class RILReceiver implements Runnable {
        byte[] buffer;
    
        RILReceiver() {
            buffer = new byte[RIL_MAX_COMMAND_BYTES];
        }
    
        @Override
        public void
        run() {
            int retryCount = 0;
            String rilSocket = "rild";
    
            try {for (;;) {
                LocalSocket s = null;
                LocalSocketAddress l;
                ...
                try {
                    s = new LocalSocket();
                    
                    l = new LocalSocketAddress(rilSocket,
                            LocalSocketAddress.Namespace.RESERVED);
                    // 1. 连接name为rild的服务端Socket,也就是RILC部分
                    s.connect(l);
                } catch (IOException ex){
                    ...
                }
                mSocket = s;
                int length = 0;
                try {
                    InputStream is = mSocket.getInputStream();
                    for (;;) {
                        Parcel p;
                        // 2. 阻塞读取服务端发来的消息,一有消息就会继续执行接下来的代码,如果length为-1,就会推出循环             
                        length = readRilMessage(is, buffer);
    
                        if (length < 0) {
                            break;
                        }
    
                        p = Parcel.obtain();
                        p.unmarshall(buffer, 0, length);
                        p.setDataPosition(0);
    
                        // 3. 接收到上报的消息后就会通过该方法处理
                        processResponse(p);
                        p.recycle();
                    }
                } catch (java.io.IOException ex) {
                    ...
                }
    
                //4. 退出循环,也就切断了和Modem的联系,需要设置Radio状态为RADIO_UNAVAILABLE
                setRadioState (RadioState.RADIO_UNAVAILABLE);
    
                try {
                    mSocket.close();
                } catch (IOException ex) {
                }
    
                mSocket = null;
                ...
        }
    }
    

    主要看下上报消息的处理

    private void processResponse (Parcel p) {
        int type;
    
        type = p.readInt();
    
        if (type == RESPONSE_UNSOLICITED || type == RESPONSE_UNSOLICITED_ACK_EXP) {
            // 处理URC消息,也就是modem主动上报消息的处理
            processUnsolicited (p, type);
        } else if (type == RESPONSE_SOLICITED || type == RESPONSE_SOLICITED_ACK_EXP) {
            // 处理非URC消息,modem回复上层下发的请求,例如拨号
            RILRequest rr = processSolicited (p, type);
            if (rr != null) {
                if (type == RESPONSE_SOLICITED) {
                    decrementWakeLock(rr);
                }
                rr.release();
                return;
            }
        } else if (type == RESPONSE_SOLICITED_ACK) {
            ...
        }
    }
    

    发起拨号请求,modem回应的消息应在processSolicited中处理,继续看该方法。

    private RILRequest processSolicited (Parcel p, int type) {
        int serial, error;
        boolean found = false;
    
        serial = p.readInt();
        error = p.readInt();
    
        RILRequest rr;
        // 1. 根据serial找到对应的RILRequest
        rr = findAndRemoveRequestFromList(serial);
        ...
         try {switch (rr.mRequest) {
            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;
            // 2. 拨号时建立的RILRequest的mRequest为RIL_REQUEST_DIAL,responseVoid返回的null,表示只关心Modem是否回应,无需其他内容
            case RIL_REQUEST_DIAL: ret =  responseVoid(p); break;
            ...
         }
         ...
         if (error == 0) {
            if (rr.mResult != null) {
                AsyncResult.forMessage(rr.mResult, ret, null);
                // 3. 发送到对应的Handler处理
                rr.mResult.sendToTarget();
            }
        }
        return rr;
    }
    

    注释3处,拨号后接收到Modem的回应,封装消息后又交由对应Handler处理。mResults是什么?mResult是调用RIL的dial方法传入的Message类型的result,该方法调用是在
    GsmCdmaCallTracker中,具体如下
    frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java

    public class GsmCdmaCallTracker extends CallTracker {
        private Connection dial(String dialString, int clirMode) throws CallStateException {
            ...
            // 1. 调用obtainCompleteMessage返回一个Message
            mCi.dial(mPendingMO.getAddress(), clirMode, obtainCompleteMessage());
            ...
        }
        public Message obtainCompleteMessage() {
            return obtainCompleteMessage(EVENT_OPERATION_COMPLETE);
        }
        public Message obtainCompleteMessage(int what) {
            mPendingOperations++;
            mLastRelevantPoll = null;
            mNeedsPoll = true;
            // 2. 返回一个what为EVENT_OPERATION_COMPLETE的Message
            return obtainMessage(what);
        }
        @Override
        public void handleMessage(Message msg) {
            AsyncResult ar;
    
            switch (msg.what) {
                // 3. 处理what为EVENT_OPERATION_COMPLETE消息
                case EVENT_OPERATION_COMPLETE:
                    operationComplete();
                break;
        ...
        
    }
    

    GsmCdmaCallTracker间接继承Handler,注释1处调用RIL的dial时传入了一个what为EVENT_OPERATION_COMPLETE的Message。当在RIL中调用rr.mResult.sendToTarget()时,就会在注释3处接收到,然后调用operationComplete()方法

    private void operationComplete() {
        mPendingOperations--;
        if (mPendingOperations == 0 && mNeedsPoll) {
            // 封装了EVENT_POLL_CALLS_RESULT消息,调用RIL的getCurrentCalls获取Call状态
            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
            mCi.getCurrentCalls(mLastRelevantPoll);
        } else if (mPendingOperations < 0) {
            // this should never happen
            Rlog.e(LOG_TAG,"GsmCdmaCallTracker.pendingOperations < 0");
            mPendingOperations = 0;
        }
    }
    

    接下来的流程又进入与RIL层的socket通信,过程与前面一样,最后GsmCdmaCallTracker收到EVENT_POLL_CALLS_RESULT消息进行处理,调用了handlePollCalls((AsyncResult)msg.obj)方法

    @Override
    protected synchronized void handlePollCalls(AsyncResult ar) {
        ...
        // 1. 更新Phone状态
        updatePhoneState();
        if (unknownConnectionAppeared) {
            if (isPhoneTypeGsm()) {
                for (Connection c : newUnknownConnectionsGsm) {
                    mPhone.notifyUnknownConnection(c);
                }
            } else {
                mPhone.notifyUnknownConnection(newUnknownConnectionCdma);
            }
        }
    
        if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) {
            // 2. 更新Call精确的状态
            mPhone.notifyPreciseCallStateChanged();
        }
    }
    

    注册了该phone电话状态监听的对象将会收到通知

    Call的所有状态定义在Call中

    public enum State {
        IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING;
        public boolean isAlive() {
            return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING);
        }
        public boolean isRinging() {
            return this == INCOMING || this == WAITING;
        }
        public boolean isDialing() {
            return this == DIALING || this == ALERTING;
        }
    }
    

    Call状态与PreciseCallState封装的精确Call状态对应关系如下

    public static int convertPreciseCallState(Call.State state) {
        switch (state) {
            case ACTIVE:
                return PreciseCallState.PRECISE_CALL_STATE_ACTIVE;
            case HOLDING:
                return PreciseCallState.PRECISE_CALL_STATE_HOLDING;
            case DIALING:
                return PreciseCallState.PRECISE_CALL_STATE_DIALING;
            case ALERTING:
                return PreciseCallState.PRECISE_CALL_STATE_ALERTING;
            case INCOMING:
                return PreciseCallState.PRECISE_CALL_STATE_INCOMING;
            case WAITING:
                return PreciseCallState.PRECISE_CALL_STATE_WAITING;
            case DISCONNECTED:
                return PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED;
            case DISCONNECTING:
                return PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING;
            default:
                return PreciseCallState.PRECISE_CALL_STATE_IDLE;
        }
    }
    

    具体notifyPreciseCallStateChanged发送过程自行阅读源码。

    后续modem会主动上报一些电话状态的变化:RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,对于URC消息在processUnsolicited 中处理

    private void processUnsolicited (Parcel p, int type) {
        int response;
        Object ret;
    
        response = p.readInt();
        ...
        switch(response) {
            ...
            case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
                // 1. 利用Resistrant机制通知对应的所有注册者
                mCallStateRegistrants
                    .notifyRegistrants(new AsyncResult(null, null, null));
            break;
            ...
    }
    

    先说下RegistrantList机制,如果需要接收Modem上报的消息,就需要注册到对应的RegistrantList中,待Modem有对应消息时,就会通知对应的RegistrantList列表。看下RIL中的不同类型的RegistrantList列表

    // Radio状态列表
    protected RegistrantList mRadioStateChangedRegistrants = new RegistrantList();
    protected RegistrantList mOnRegistrants = new RegistrantList();
    protected RegistrantList mAvailRegistrants = new RegistrantList();
    protected RegistrantList mOffOrNotAvailRegistrants = new RegistrantList();
    protected RegistrantList mNotAvailRegistrants = new RegistrantList();
    // Call状态注册着列表
    protected RegistrantList mCallStateRegistrants = new RegistrantList();
    // Network状态注册者列表
    protected RegistrantList mNetworkStateRegistrants = new RegistrantList();
    
    // 注册接口方法
    @Override
    public void registerForCallStateChanged(Handler h, int what, Object obj) {
        Registrant r = new Registrant (h, what, obj);
    
        mCallStateRegistrants.add(r);
    }
    ...
    

    而监听Modem上传Call状态的是在GsmCdmaCallTracker构造方法中注册的

    mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
    

    当Modem上报Call状态时通过mCallStateRegistrants .notifyRegistrants(new AsyncResult(null, null, null))方法,内部会调用注册传入的Handler(也就是GsmCdmaCallTracker)的sendMessage发送消息,消息类型是EVENT_CALL_STATE_CHANGE就调用pollCallsWhenSafe()方法。

    protected void pollCallsWhenSafe() {
        mNeedsPoll = true;
        if (checkNoOperationsPending()) {
            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
            mCi.getCurrentCalls(mLastRelevantPoll);
        }
    }
    

    与RIL Socket通信得到Call状态,和前面获取Call状态过程相同。

    至此,拨号流程就完了,通过实际问题打印log会有更深刻的认识。下面对总结下大体流程。

    参考

    http://blog.csdn.net/michael_yt/article/details/53748915

    https://www.cnblogs.com/lance2016/p/6002371.html

    相关文章

      网友评论

          本文标题:Android7.0 拨号流程源码分析

          本文链接:https://www.haomeiwen.com/subject/aveajqtx.html