Android6.0拨打电话流程

时间:2022-11-10 10:00:45

Telephony框架学习(一)Android6.0MO流程

相关模块

\packages\apps\Dialer
\packages\apps\InCallUI
\packages\services\Telecomm
\packages\services\Telephony
\frameworks\base\telecomm
\frameworks\base\telephony
\frameworks\opt\telephony
\frameworks\opt\net\ims
\vendor\mediatek\proprietary\packages\services\Ims

时序图

Android6.0去电流程,(右键点击在新标签页查看大图)

Android6.0拨打电话流程

概要图

Android6.0拨打电话流程

MO Log

无Update的Log Step 68 69 70 71 72

Android6.0拨打电话流程
Android6.0拨打电话流程

VOLTECall Log

Android6.0拨打电话流程
Android6.0拨打电话流程
(后期会加注释)

Dialer

Step1

    @Override
public void onClick(View view) {
    /** M: Prevent the event if dialpad is not shown. @{ */
    if (getActivity() != null
            && !((DialtactsActivity)getActivity()).isDialpadShown()) {
        Log.d(TAG, "onClick but dialpad is not shown, skip !!!");
        return;
    }
    /** @} */
    switch (view.getId()) {
        case R.id.dialpad_floating_action_button:
            mHaptic.vibrate();
            android.util.Log.d("wds_mo","step1-->Dialer-->DialpadFragment.onClick()");
            handleDialButtonPressed();
            break;
           ....

Step3

    private void handleDialButtonPressed(int type) {
    if (isDigitsEmpty()) { // No number entered.
        handleDialButtonClickWithEmptyDigits();
    } else {
        final String number = mDigits.getText().toString();

        // "persist.radio.otaspdial" is a temporary hack needed for one carrier's automated
        // test equipment.
        // TODO: clean it up.
        if (number != null
                && !TextUtils.isEmpty(mProhibitedPhoneNumberRegexp)
                && number.matches(mProhibitedPhoneNumberRegexp)) {
            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");
            }

            // Clear the digits just in case.
            clearDialpad();
        } 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),
                        (getActivity() instanceof DialtactsActivity ?
                                ((DialtactsActivity) getActivity()).getCallOrigin() : null),
                        type);
            } else {
                intent = IntentUtil.getCallIntent(number,
                        (getActivity() instanceof DialtactsActivity ?
                                ((DialtactsActivity) getActivity()).getCallOrigin() : null));
            }
            /** @} */
            android.util.Log.d("wds_mo","step3-->Dialer-->DialpadFragment.handleDialButtonPressed()");
            DialerUtils.startActivityWithErrorToast(getActivity(), intent);
            hideAndClearDialpad(false);
        }
    }
}

Step5

    public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) {
    try {
        if ((IntentUtil.CALL_ACTION.equals(intent.getAction())
                        && context instanceof Activity)) {
            // 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);
            }
            android.util.Log.d("wds_mo","step5-->Dialer-->DialerUtils.startActivityWithErrorToast()");
            final TelecomManager tm =
                    (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
            tm.placeCall(intent.getData(), intent.getExtras());
            /// M: add log for debugging
            if (DEBUG) {
                Log.d(TAG, "startActivityWithErrorToast placeCall with intent " + intent);
            }
        } else {
            context.startActivity(intent);
        }
    } catch (ActivityNotFoundException e) {
        Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show();
    }
}

framework/telecom

Step6

    public void placeCall(Uri address, Bundle extras) {
    ITelecomService service = getTelecomService();
    if (service != null) {
        if (address == null) {
            Log.w(TAG, "Cannot place call to empty address.");
        }
        try {
            android.util.Log.d("wds_mo","step6-->framework/base/Telecom-->TelecomManager.placeCall()");
            service.placeCall(address, extras == null ? new Bundle() : extras,
                    mContext.getOpPackageName());
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelecomService#placeCall", e);
        }
    }
}

package/services/Telecomm

Step7

      @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");
        }

        // Note: we can still get here for the default/system dialer, even if the Phone
        // permission is turned off. This is because the default/system dialer is always
        // allowed to attempt to place a call (regardless of permission state), in case
        // it turns out to be an emergency call. If the permission is denied and the
        // call is being made to a non-emergency number, the call will be denied later on
        // by {@link UserCallIntentProcessor}.

        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);
                android.util.Log.d("wds_mo","step7-->Telecom-->TelecomServiceImpl.placeCall()");
                new UserCallIntentProcessor(mContext, userHandle).processIntent(intent,
                        callingPackage, hasCallAppOp && hasCallPermission);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }
    }

Step8

    public void processIntent(Intent intent, String callingPackageName,
        boolean canCallNonEmergency) {
    // Ensure call intents are not processed on devices that are not capable of calling.
    if (!isVoiceCapable()) {
        return;
    }

    String action = intent.getAction();

    if (Intent.ACTION_CALL.equals(action) ||
            Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
            Intent.ACTION_CALL_EMERGENCY.equals(action)) {
        android.util.Log.d("wds_mo","step8-->Telecom-->UserCallIntentProcessor.processIntent()");
        processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);
    }
}

Step9

 private void processOutgoingCallIntent(Intent intent, String callingPackageName,
        boolean canCallNonEmergency) {
    Uri handle = intent.getData();
    String scheme = handle.getScheme();
    String uriString = handle.getSchemeSpecificPart();

    /// M: Do noting for CDMA empty flash at present
    if (intent.getBooleanExtra(EXTRA_SEND_EMPTY_FLASH, false)) {
        Log.w(this, "Empty flash obtained from the call intent.");
        return;
    }

    if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
        handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?
                PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);
    }

    final UserManager userManager =
            (UserManager) mContext.getSystemService(Context.USER_SERVICE);
    if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, mUserHandle)
            && !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {
        // Only emergency calls are allowed for users with the DISALLOW_OUTGOING_CALLS
        // restriction.
        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;
    }

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

    intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
            isDefaultOrSystemDialer(callingPackageName));
    android.util.Log.d("wds_mo","step9-->Telecom-->UserCallIntentProcessor.processOutgoingCallIntent()");
    sendBroadcastToReceiver(intent);
}

private boolean isTtyModeEnabled() {
    return (android.provider.Settings.Secure.getInt(
            mContext.getContentResolver(),
            android.provider.Settings.Secure.PREFERRED_TTY_MODE,
            TelecomManager.TTY_MODE_OFF) != TelecomManager.TTY_MODE_OFF);
}

private boolean isDefaultOrSystemDialer(String callingPackageName) {
    if (TextUtils.isEmpty(callingPackageName)) {
        return false;
    }

    final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mContext,
            mUserHandle.getIdentifier());
    if (TextUtils.equals(defaultDialer, callingPackageName)) {
        return true;
    }

    final TelecomManager telecomManager =
            (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
    return TextUtils.equals(telecomManager.getSystemDialerPackage(), callingPackageName);
}

Step10

   private boolean sendBroadcastToReceiver(Intent 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");
    android.util.Log.d("wds_mo","step10-->Telecom-->UserCallIntentProcessor.sendBroadcastToReceiver()");
    mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
    return true;
}

Step11

public class PrimaryCallReceiver extends BroadcastReceiver implements TelecomSystem.Component {

@Override
public void onReceive(Context context, Intent intent) {
    synchronized (getTelecomSystem().getLock()) {
        android.util.Log.d("wds_mo","step11-->Telecom-->PrimaryCallReceiver.onReceive()");
        getTelecomSystem().getCallIntentProcessor().processIntent(intent);
    }
}

Step12

    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 {
        android.util.Log.d("wds_mo","step12-->Telecom-->CallIntentProcessor.processIntent()");
        processOutgoingCallIntent(mContext, mCallsManager, intent);
    }
    Trace.endSection();
}

Step13

分两部分执行
static void processOutgoingCallIntent(
Context context,
CallsManager callsManager,
Intent intent) {

    /// M: for log parser @{
    LogUtils.logIntent(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);

    /// M: For dial via specified slot. @{
    if (intent.hasExtra(TelecomUtils.EXTRA_SLOT)) {
        int slotId = intent.getIntExtra(TelecomUtils.EXTRA_SLOT, -1);
        phoneAccountHandle = TelecomUtils
                .getPhoneAccountHandleWithSlotId(context, slotId, phoneAccountHandle);
    }
    /// @}

    /// M: for VoLTE @{
    // Here we handle all error case for VoLTE.
    boolean isImsCallRequest = TelecomVolteUtils.isImsCallOnlyRequest(intent);
    boolean isConferenceDialRequest = TelecomVolteUtils.isConferenceDialRequest(intent);
    if (isImsCallRequest || isConferenceDialRequest) {
        Log.d(TAG, "MO - VoLTE case: Ims Call / Conference Dial = %s / %s",
                isImsCallRequest, isConferenceDialRequest);
        if (!TelecomVolteUtils.isImsEnabled(context)) {
            Log.d(TAG, "MO - VoLTE case: Ims is disabled => Abandon");
            TelecomVolteUtils.showImsDisableDialog(context);
            return;
        }
        List<PhoneAccountHandle> accounts = TelecomUtils.getVoltePhoneAccountHandles();
        if (accounts == null || accounts.isEmpty()) {
            Log.d(TAG, "MO - VoLTE case: No VoLTE account => Abandon");
            TelecomVolteUtils.showNoImsAccountDialog(context);
            return;
        }
        if (isImsCallRequest) {
            clientExtras.putBoolean(TelecomVolteUtils.EXTRA_VOLTE_IMS_CALL, true);
        }
        if (isConferenceDialRequest) {
            handle = TelecomVolteUtils.checkHandleForConferenceDial(context, handle);
        }
    }
    /// @}

    /// M: For Ip dial & suggested account & VoLTE-Ims Call &
    //         VoLTE-Conference Dial & ViLTE-Block certain ViLTE. @{
    copyExtraToBundle(intent, clientExtras);
    /// @}

    // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
    android.util.Log.d("wds_mo","step13-->Telecom-->CallIntentProcessor.processOutgoingCallIntent()-- to InCallUI");
    Call call = callsManager.startOutgoingCall(handle, phoneAccountHandle, clientExtras);

    if (call != null) {
        /// M: ip dial. ip prefix already add, here need to change intent @{
        if (call.isIpCall()) {
            intent.setData(call.getHandle());
        }
        /// @}

        /// M: For VoLTE - Conference Dial @{
        // For Con dial, skip NewOutgoingCallIntentBroadcaster. createConnection() directly.
        if (call.isConferenceDial()) {
            call.startCreateConnection(TelecomSystem.getInstance().getPhoneAccountRegistrar());
            return;
        }
        /// @}

        // Asynchronous calls should not usually be made inside a BroadcastReceiver
        // because once
        // onReceive is complete, the BroadcastReceiver's process runs the risk of getting
        // killed if memory is scarce. However, this is OK here because the entire Telecom
        // process will be running throughout the duration of the phone call and should never
        // be killed.
        NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
                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);
        }
    }
}

Step14

 Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras) {

           ...


     // Do not add the call if it is a potential MMI code.
    if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) {
        call.addListener(this);
        /// M: If no account for MMI Code, show a dialog with "No SIM or SIM error" message. @{
        if (phoneAccountHandle == null) {
            Log.d(this, "MO - MMI with no sim: show error dialog and return");
            TelecomUtils.showErrorDialog(mContext, R.string.callFailed_simError);
            disconnectCall(call);
            return null;
        }
        /// @}
    } 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 #getNewOutgoingCall}).
        android.util.Log.d("wds_mo","step14-->Telecom-->CallsManager.startOutgoingCall()");
        addCall(call);
    }

    return call;
}

Step15

    private void addCall(Call call) {
    Trace.beginSection("addCall");
    Log.v(this, "addCall(%s)", call);
    call.addListener(this);
    mCalls.add(call);

    // TODO: Update mForegroundCall prior to invoking
    // onCallAdded for calls which immediately take the foreground (like the first call).
    android.util.Log.d("wds_mo","step15-->Telecom-->CallsManager.addCall()");
    for (CallsManagerListener listener : mListeners) {
        if (Log.SYSTRACE_DEBUG) {
            Trace.beginSection(listener.getClass().toString() + " addCall");
        }

        listener.onCallAdded(call);
        if (Log.SYSTRACE_DEBUG) {
            Trace.endSection();
        }
    }
    updateCallsManagerState();
    Trace.endSection();
}

Step16

    @Override
public void onCallAdded(Call call) {
    if (!isBoundToServices()) {
        android.util.Log.d("wds_mo","step16-->Telecom-->InCallController.onCallAdded()");
        bindToServices(call);
    } else {
        adjustServiceBindingsForEmergency();

        Log.i(this, "onCallAdded: %s", call);
        // Track the call if we don't already know about it.
        addCall(call);

        for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
            ComponentName componentName = entry.getKey();
            IInCallService inCallService = entry.getValue();
            ParcelableCall parcelableCall = toParcelableCall(call,
                    true /* includeVideoProvider */);
            try {
                inCallService.addCall(parcelableCall);
            } catch (RemoteException ignored) {
            }
        }
    }
}

Step17

    private void bindToServices(Call call) {
    PackageManager packageManager = mContext.getPackageManager();
    Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE);

    List<ComponentName> inCallControlServices = new ArrayList<>();
    ComponentName inCallUIService = null;

             .... ....
          if (inCallUIService != null) {
        // skip default dialer if we have an emergency call or if it failed binding.
        android.util.Log.d("wds_mo","step17-->Telecom-->InCallController.bindToServices()");
        if (mCallsManager.hasEmergencyCall()) {
            Log.i(this, "Skipping default-dialer because of emergency call");
            inCallUIService = null;
        } else if (!bindToInCallService(inCallUIService, call, "def-dialer")) {
            Log.event(call, Log.Events.ERROR_LOG,
                    "InCallService UI failed binding: " + inCallUIService);
            inCallUIService = null;
        }
    }
    ......
 }

Step18

    private boolean bindToInCallService(ComponentName componentName, Call call, String tag) {
    if (mInCallServices.containsKey(componentName)) {
        Log.i(this, "An InCallService already exists: %s", componentName);
        return true;
    }

    if (mServiceConnections.containsKey(componentName)) {
        Log.w(this, "The service is already bound for this component %s", componentName);
        return true;
    }

    Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
    intent.setComponent(componentName);
    if (call != null && !call.isIncoming()){
        intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS,
                call.getIntentExtras());
        intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
                call.getTargetPhoneAccount());
    }

    Log.i(this, "Attempting to bind to [%s] InCall %s, with %s", tag, componentName, intent);
    InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
    android.util.Log.d("wds_mo","step18-->Telecom-->InCallController.bindToInCallService()");
    if (mContext.bindServiceAsUser(intent, inCallServiceConnection,
                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                UserHandle.CURRENT)) {
        mServiceConnections.put(componentName, inCallServiceConnection);
        /// M: Register voice recording listener @{
        PhoneRecorderHandler.getInstance().setListener(mRecorderListener);
        /// @}
        return true;
    }
    return false;
}

package/apps/InCallUI

Step19

    @Override
public IBinder onBind(Intent intent) {
    Log.d(this, "onBind");
    final Context context = getApplicationContext();
    /// M: [plugin]ensure a context is valid.
    ExtensionManager.registerApplicationContext(context);
    final ContactInfoCache contactInfoCache = ContactInfoCache.getInstance(context);
    android.util.Log.d("wds_mo","step19-->InCallUI-->InCallServiceImpl.onBind()");
    InCallPresenter.getInstance().setUp(
            getApplicationContext(),
            CallList.getInstance(),
            AudioModeProvider.getInstance(),
            new StatusBarNotifier(context, contactInfoCache),
            contactInfoCache,
            new ProximitySensor(context, AudioModeProvider.getInstance())
            );
    InCallPresenter.getInstance().onServiceBind();
    InCallPresenter.getInstance().maybeStartRevealAnimation(intent);
    TelecomAdapter.getInstance().setInCallService(this);

    return super.onBind(intent);
}

Step20

public void setUp(Context context,
        CallList callList,
        AudioModeProvider audioModeProvider,
        StatusBarNotifier statusBarNotifier,
        ContactInfoCache contactInfoCache,
        ProximitySensor proximitySensor) {
    android.util.Log.d("wds_mo","step20-->InCallUI-->InCallPresenter.setUp()");
    if (mServiceConnected) {
        Log.i(this, "New service connection replacing existing one.");
        // retain the current resources, no need to create new ones.
        Preconditions.checkState(context == mContext);
        Preconditions.checkState(callList == mCallList);
        Preconditions.checkState(audioModeProvider == mAudioModeProvider);
        return;
    }

    Preconditions.checkNotNull(context);
    mContext = context;

    mContactInfoCache = contactInfoCache;

    /// M: for ALPS01328763 @{
    // remove the original one before add new listener
    if (mStatusBarNotifier != null) {
        removeListener(mStatusBarNotifier);
        removeIncomingCallListener(mStatusBarNotifier);
        mStatusBarNotifier.tearDown();
    }
    /// @}
    mStatusBarNotifier = statusBarNotifier;
    addListener(mStatusBarNotifier);
    /// M: ALPS01843428 @{
    // Passing incoming event to StatusBarNotifier for updating the notification.
    addIncomingCallListener(mStatusBarNotifier);
    /// @}

    mAudioModeProvider = audioModeProvider;

    /// M: for ALPS01328763 @{
    // remove the original one before add new listener
    if (mProximitySensor != null) {
        removeListener(mProximitySensor);
        //M: fix ALPS02535607
        removeDetailsListener(mProximitySensor);
    }
    /// @}
    mProximitySensor = proximitySensor;
    addListener(mProximitySensor);
    //M: fix ALPS02535607,add onDetail change listener for ProximitySensor
    addDetailsListener(mProximitySensor);

    addIncomingCallListener(mAnswerPresenter);
    addInCallUiListener(mAnswerPresenter);

    mCallList = callList;

    /// M: add for phone recording.
    mRecordingState = PhoneRecorderUtils.RecorderState.IDLE_STATE;
    // This only gets called by the service so this is okay.
    mServiceConnected = true;
    ///M: WFC @{
    if (ImsManager.isWfcEnabledByPlatform(mContext)) {
         mRoveOutReceiver = new InCallUiWfcUtils.RoveOutReceiver(mContext);
         mRoveOutReceiver.register(mContext);
    }
    /// @}
    // The final thing we do in this set up is add ourselves as a listener to CallList.  This
    // will kick off an update and the whole process can start.
    mCallList.addListener(this);

    VideoPauseController.getInstance().setUp(this);
    VideoSessionController.getInstance().setUp(this);

    /// M: [AutoAnswer]for Engineer Mode @{
    mAutoAnswer = new AutoAnswerHelper(mContext);
    addIncomingCallListener(mAutoAnswer);
    /// @}

    Log.d(this, "Finished InCallPresenter.setUp");
}

Step21

   public void maybeStartRevealAnimation(Intent intent) {
    if (intent == null || mInCallActivity != null) {
        return;
    }
    final Bundle extras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);
    if (extras == null) {
        // Incoming call, just show the in-call UI directly.
        return;
    }

    if (extras.containsKey(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS)) {
        // Account selection dialog will show up so don't show the animation.
        return;
    }

    final PhoneAccountHandle accountHandle =
            intent.getParcelableExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
    final Point touchPoint = extras.getParcelable(TouchPointManager.TOUCH_POINT);

    InCallPresenter.getInstance().setBoundAndWaitingForOutgoingCall(true, accountHandle);

    final Intent incallIntent = getInCallIntent(false, true);
    incallIntent.putExtra(TouchPointManager.TOUCH_POINT, touchPoint);
    android.util.Log.d("wds_mo","step21-->InCallUI-->InCallPresenter.maybeStartRevealAnimation()");
    mContext.startActivity(incallIntent);
}

Step22

    @Override
protected void onCreate(Bundle icicle) {
    Log.d(this, "onCreate()...  this = " + this);
    android.util.Log.d("wds_mo","step22-->InCallUI-->startActivity-->InCallActivity.onCreate() ");
    super.onCreate(icicle);
    ......
}

package/services/Telecomm

Step23

public final class InCallController extends CallsManagerListenerBase {
/**
 * Used to bind to the in-call app and triggers the start of communication between
 * this class and in-call app.
 */
private class InCallServiceConnection implements ServiceConnection {
    /** {@inheritDoc} */
    @Override public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d(this, "onServiceConnected: %s", name);
        android.util.Log.d("wds_mo","step23-->Telecom-->InCallController.InCallServiceConnection.onServiceConnected()");
        onConnected(name, service);
    }
      /** {@inheritDoc} */
    @Override public void onServiceDisconnected(ComponentName name) {
        Log.d(this, "onDisconnected: %s", name);
        onDisconnected(name);
    }
}

Step24

这里分两部分,先初始化InCallAdapter,后执行addCall

 private void onConnected(ComponentName componentName, IBinder service) {
    Trace.beginSection("onConnected: " + componentName);
    Log.i(this, "onConnected to %s", componentName);

    IInCallService inCallService = IInCallService.Stub.asInterface(service);
    mInCallServices.put(componentName, inCallService);

    try {
        android.util.Log.d("wds_mo","step24-->Telecom-->InCallController.onConnected()");
        inCallService.setInCallAdapter(
                new InCallAdapter(
                        mCallsManager,
                        mCallIdMapper,
                        mLock));
    } catch (RemoteException e) {
        Log.e(this, e, "Failed to set the in-call adapter.");
        Trace.endSection();
        onInCallServiceFailure(componentName, "setInCallAdapter");
        return;
    }

    // Upon successful connection, send the state of the world to the service.
    Collection<Call> calls = mCallsManager.getCalls();
    if (!calls.isEmpty()) {
        Log.i(this, "Adding %s calls to InCallService after onConnected: %s", calls.size(),
                componentName);

        for (Call call : calls) {
            try {
                // Track the call if we don't already know about it.

                addCall(call);
                inCallService.addCall(toParcelableCall(call, true /* includeVideoProvider */));
            } catch (RemoteException ignored) {
            }
        }
        onCallAudioStateChanged(
                null,
                mCallsManager.getAudioState());
        onCanAddCallChanged(mCallsManager.canAddCall());
    } else {
        unbindFromServices();
    }
    Trace.endSection();
}

Step25&27

framewrok/base/telecomm

先后执行初始化,后使用

  /** Manages the binder calls so that the implementor does not need to deal with it. */
private final class InCallServiceBinder extends IInCallService.Stub {
    @Override
    public void setInCallAdapter(IInCallAdapter inCallAdapter) {
        android.util.Log.d("wds_mo","step25-->framework/base/Telecom-->InCallService.InCallServiceBinder.setInCallAdapter()");
        mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
    }

    @Override
    public void addCall(ParcelableCall call) {
        android.util.Log.d("wds_mo","step27-->framework/base/Telecom-->InCallService.InCallServiceBinder.addCall()");
        mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
    }

    @Override
    public void updateCall(ParcelableCall call) {
        android.util.Log.d("wds_mo","step70-->framework/base/Telecom-->InCallService.InCallServiceBinder.updateCall()");
        mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget();
    }

    @Override
    public void setPostDial(String callId, String remaining) {
        // TODO: Unused
    }
    .............

Step26&28 需要先初始化Phone才能执行addCall

   @Override
    public void handleMessage(Message msg) {
        /// M: [log optimize]for performance debugging.
        mMessageAnalyzer.onStartHandleMessage(msg);
        if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) {
            /// M: [log optimize]for performance debugging.
            mMessageAnalyzer.onMessageHandled(msg);
            return;
        }

        SomeArgs args;
        switch (msg.what) {
            case MSG_SET_IN_CALL_ADAPTER:
                android.util.Log.d("wds_mo","step26-->framework/base/Telecom-->InCallService.handleMessage_MSG_SET_IN_CALL_ADAPTER");
                mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
                mPhone.addListener(mPhoneListener);
                onPhoneCreated(mPhone);
                break;
            case MSG_ADD_CALL:
                android.util.Log.d("wds_mo","step28-->framework/base/Telecom-->InCallService.handleMessage_MSG_ADD_CALL");
                mPhone.internalAddCall((ParcelableCall) msg.obj);
                break;

Step29

   final void internalAddCall(ParcelableCall parcelableCall) {

    Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
            parcelableCall.getState());
    mCallByTelecomCallId.put(parcelableCall.getId(), call);
    mCalls.add(call);
    checkCallTree(parcelableCall);
    call.internalUpdate(parcelableCall, mCallByTelecomCallId);
    android.util.Log.d("wds_mo","step29-->framework/base/Telecom-->InCallService.internalAddCall()");
    fireCallAdded(call);
 }

Step30

    private void fireCallAdded(Call call) {
    android.util.Log.d("wds_mo","step30-->framework/base/Telecom-->Phone.fireCallAdded()");
    for (Listener listener : mListeners) {
        listener.onCallAdded(this, call);
    }
}

Step32

package/apps/InCallUI

   public void onCallAdded(android.telecom.Call telecommCall) {
    Trace.beginSection("onCallAdded");
    Call call = new Call(telecommCall);
    Log.d(this, "onCallAdded: callState=" + call.getState());
    if (call.getState() == Call.State.INCOMING ||
            call.getState() == Call.State.CALL_WAITING) {

        onIncoming(call, call.getCannedSmsResponses());
    } else {
        android.util.Log.d("wds_mo","step32-->InCallUI-->CallList.onCallAdded() ");
        onUpdate(call);
    }

    /// M: [log optimize] @{
    if (call.isConferenceCall()) {
        Log.notify(call, Log.CcNotifyAction.CONFERENCED, "ConfCreated");
    }
    /// @}

    Trace.endSection();
}

Step33

  public void onUpdate(Call call) {
    Trace.beginSection("onUpdate");
    onUpdateCall(call);
    android.util.Log.d("wds_mo","step33-->InCallUI-->CallList.onUpdate()");
    notifyGenericListeners();
    Trace.endSection();
}

Step34

    private void notifyGenericListeners() {
    android.util.Log.d("wds_mo","step34-->InCallUI-->CallList.notifyGenericListeners()");
    for (Listener listener : mListeners) {
        listener.onCallListChange(this);
    }
}

Step35

  @Override
public void onCallListChange(CallList callList) {
     android.util.Log.d("wds_mo","step35-->InCallUI-->InCallPresenter.onCallListChange()");
          if (mInCallActivity != null && mInCallActivity.getCallCardFragment() != null &&
            mInCallActivity.getCallCardFragment().isAnimating()) {
        /// M: add for monitor call card animation process
        Log.d(this, "[onCallListChange] Call Card view is animating!");
        mAwaitingCallListUpdate = true;

        return;
    }
    if (callList == null) {

        return;
    }
    ..................

}

Step13

package/services/Telecomm

Step13继续执行

static void processOutgoingCallIntent(

           ......

        NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
                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);
        }
    }
}

Step36

 private class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

           ...........

        Uri originalUri = mIntent.getData();

        if (originalUri.getSchemeSpecificPart().equals(resultNumber)) {
            Log.v(this, "Call number unmodified after new outgoing call intent broadcast.");
        } else {
            Log.v(this, "Retrieved modified handle after outgoing call intent broadcast: "
                    + "Original: %s, Modified: %s",
                    Log.pii(originalUri),
                    Log.pii(resultHandleUri));
        }

        GatewayInfo gatewayInfo = getGateWayInfoFromIntent(intent, resultHandleUri);
        android.util.Log.d("wds_mo","step36-->Telecom-->NewOutgoingCallIntentBroadcaster.onReceive()");
        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));
        Trace.endSection();
    }
}
}

Step37

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


       ...........

/// M: ALPS02035599 Since NewOutgoingCallIntentBroadcaster and the SELECT_PHONE_ACCOUNT @{
    // sequence run in parallel, this call may be already disconnected in the  select phone
    // account sequence.
    if (call.getState() == CallState.DISCONNECTED) {
        return;
    }
    /// @}

    if (call.getTargetPhoneAccount() != null || isEmergencyCall) {
        // If the account has been set, proceed to place the outgoing call.
        // Otherwise the connection will be initiated when the account is set by the user.
        android.util.Log.d("wds_mo","step37-->Telecom-->CallsManager.placeOutgoingCall()");
        call.startCreateConnection(mPhoneAccountRegistrar);
    }

Step38

    void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
    /// M: Workaround for ALPS01845919. @{
    // Maybe broadcast will be delayed, the phoneAccount selected earlier than received broadcast,
    // and the call will be place twice, need cancel the duplicate one.
    if (mCreateConnectionProcessor != null) {
        Log.v(this, "Canceling this duplicate call.");
        return;
    }
    /// @}

    Preconditions.checkState(mCreateConnectionProcessor == null);
    mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
            phoneAccountRegistrar, mContext);
    android.util.Log.d("wds_mo","step38-->Telecom-->Call.startCreateConnection()");
    mCreateConnectionProcessor.process();
}

Step39

  void process() {
    Log.v(this, "process");
    clearTimeout();
    mAttemptRecords = new ArrayList<>();
    if (mCall.getTargetPhoneAccount() != null) {
        mAttemptRecords.add(new CallAttemptRecord(
                mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
    }
    adjustAttemptsForConnectionManager();
    adjustAttemptsForEmergency();
    mAttemptRecordIterator = mAttemptRecords.iterator();
    android.util.Log.d("wds_mo","step39-->Telecom-->CreateConnectionProcessor.process()");
    attemptNextPhoneAccount();
}

Step40

  private void attemptNextPhoneAccount() {

             ..........

    if (mResponse != null && attempt != null) {
        Log.i(this, "Trying attempt %s", attempt);
        PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
        ConnectionServiceWrapper service =
                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);
            /// M: Valid phone account for ECC may have been set.@{
            if (mCall.getTargetPhoneAccount() == null) {
                mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
            }
            /// @}
            mCall.setConnectionService(service);
            setTimeoutIfNeeded(service, attempt);
            android.util.Log.d("wds_mo","step40-->Telecom-->CreateConnectionProcessor.attemptNextPhoneAccount()");
            service.createConnection(mCall, new Response(service));
        }
    } else {
        Log.v(this, "attemptNextPhoneAccount, no more accounts, failing");
        if (mResponse != null) {
            clearTimeout();
            mResponse.handleCreateConnectionFailure(mLastErrorDisconnectCause != null ?
                    mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR));
            mResponse = null;
            mCall.clearConnectionService();
        }
    }
}

Step41

  void createConnection(final Call call, final CreateConnectionResponse response) {
    logOutgoing("createConnection(%s) via %s.", call, getComponentName());
    BindCallback callback = new BindCallback() {
        @Override
        public void onSuccess() {

          .....

    android.util.Log.d("wds_mo","step41-->Telecom-->ConnectionServiceWrapper.createConnection()");
    mBinder.bind(callback, call);
}

Step42

        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) {
            Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
            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) {
                android.util.Log.d("wds_mo","step42-->Telecom-->Binder2.bind(()");
                isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,
                        mUserHandle);
            } else {

                isBound = mContext.bindService(serviceIntent, connection, bindingFlags);
            }
            if (!isBound) {
                handleFailedConnection();
                return;
            }
        } else {
            Log.d(ServiceBinder.this, "Service is already bound.");
            Preconditions.checkNotNull(mBinder);
            handleSuccessfulConnection();
        }
    }
}

Step43

private final class ServiceBinderConnection implements ServiceConnection {

          ........

        @Override
    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 request was queued so unbind immediately.
            if (mIsBindingAborted) {
                clearAbort();
                logServiceDisconnected("onServiceConnected");
                mContext.unbindService(this);
                handleFailedConnection();
                return;
            }

            mServiceConnection = this;
            android.util.Log.d("wds_mo","step43-->Telecom-->Binder2.onServiceConnected()");
            setBinder(binder);

            handleSuccessfulConnection();
        }
    }

   ..........

Step44

    private void setBinder(IBinder binder) {
    if (mBinder != binder) {
        mBinder = binder;
        android.util.Log.d("wds_mo","step44-->Telecom-->Binder2.setBinder()");
        setServiceInterface(binder);

        if (binder == null) {
            for (Listener l : mListeners) {
                l.onUnbind(this);
            }
        }
    }
}

Step45

    @Override
protected void setServiceInterface(IBinder binder) {
    if (binder == null) {
        // We have lost our service connection. Notify the world that this service is done.
        // We must notify the adapter before CallsManager. The adapter will force any pending
        // outgoing calls to try the next service. This needs to happen before CallsManager
        // tries to clean up any calls still associated with this service.
        handleConnectionServiceDeath();
        mCallsManager.handleConnectionServiceDeath(this);
        mServiceInterface = null;
    } else {
        android.util.Log.d("wds_mo","step45-->Telecom-->ConnectionServiceWrapper.setServiceInterface()");
        mServiceInterface = IConnectionService.Stub.asInterface(binder);
        addConnectionServiceAdapter(mAdapter);
    }
}

Step46

    private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
    if (isServiceValid("addConnectionServiceAdapter")) {
        try {
            logOutgoing("addConnectionServiceAdapter %s", adapter);
            android.util.Log.d("wds_mo","step46-->Telecom-->ConnectionServiceWrapper.addConnectionServiceAdapter()");
            mServiceInterface.addConnectionServiceAdapter(adapter);
        } catch (RemoteException e) {
        }
    }
}

Step47

返回到43步继续执行,因为4647是并发执行,这里按照Log的顺序来,46执行到48 ,47执行到50,

    private void handleSuccessfulConnection() {
    android.util.Log.d("wds_mo","step47-->Telecom-->ServiceBinder.handleSuccessfulConnection()");
    for (BindCallback callback : mCallbacks) {
        callback.onSuccess();
    }
    mCallbacks.clear();
}

Step50

返回到41,如果47步callback.onSuccess() 继续执行

    void createConnection(final Call call, final CreateConnectionResponse response) {
    logOutgoing("createConnection(%s) via %s.", call, getComponentName());
    BindCallback callback = new BindCallback() {
        @Override
        public void onSuccess() {
            String callId = mCallIdMapper.getCallId(call);
            /// M: In some complex scenario, before binding success, the call has been
            // disconnected. So here pass a null callId to telephony will cause JE.
            if (callId == null) {
                Log.w(this, "createConnection stop, callId is null");
                return;
            }
            mPendingResponses.put(callId, response);

            GatewayInfo gatewayInfo = call.getGatewayInfo();
            Bundle extras = call.getIntentExtras();
            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 {
                /// M: For VoLTE @{
                boolean isConferenceDial = call.isConferenceDial();
                if (isConferenceDial) {
                    logOutgoing("createConference(%s) via %s.", call, getComponentName());
                    mServiceInterface.createConference(
                            call.getConnectionManagerPhoneAccount(),
                            callId,
                            new ConnectionRequest(
                                    call.getTargetPhoneAccount(),
                                    call.getHandle(),
                                    extras,
                                    call.getVideoState()),
                            call.getConferenceParticipants(),
                            call.isIncoming());
                } else {
                    android.util.Log.d("wds_mo","step50-->Telecom-->ConnectionServiceWrapper.createConnection().onSuccess");
                    mServiceInterface.createConnection(
                            call.getConnectionManagerPhoneAccount(),
                            callId,
                            new ConnectionRequest(
                                    call.getTargetPhoneAccount(),
                                    call.getHandle(),
                                    extras,
                                    call.getVideoState()),
                            call.isIncoming(),
                            call.isUnknown());
                }
                /// @}
            .......

Step48&52

46和50 都是IConnectionService.aidl 客服端发送请求到服务端 mServiceInterface

   private final IBinder mBinder = new IConnectionService.Stub() {
    @Override
    public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
        android.util.Log.d("wds_mo","step48-->framework/base/Telecom-->ConnectionService.IBinder.addConnectionServiceAdapter()");
        mHandler.obtainMessage(MSG_ADD_CONNECTION_SERVICE_ADAPTER, adapter).sendToTarget();
    }

    public void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
        mHandler.obtainMessage(MSG_REMOVE_CONNECTION_SERVICE_ADAPTER, adapter).sendToTarget();
    }

    @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;
        android.util.Log.d("wds_mo","step52-->framework/base/Telecom-->ConnectionService.IBinder.createConnection()");
        mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
    }

     .....................

Step49&53

    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_ADD_CONNECTION_SERVICE_ADAPTER:
                android.util.Log.d("wds_mo","step49-->framework/base/Telecom-->handleMessage.MSG_ADD_CONNECTION_SERVICE_ADAPTER");
                mAdapter.addAdapter((IConnectionServiceAdapter) msg.obj);
                onAdapterAttached();
                break;
            case MSG_REMOVE_CONNECTION_SERVICE_ADAPTER:
                mAdapter.removeAdapter((IConnectionServiceAdapter) msg.obj);
                break;
            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;
                    if (!mAreAccountsInitialized) {
                        Log.d(this, "Enqueueing pre-init request %s", id);
                        mPreInitializationConnectionRequests.add(new Runnable() {
                            @Override
                            public void run() {
                                android.util.Log.d("wds_mo","step53-->framework/base/Telecom-->handleMessage.MSG_CREATE_CONNECTION");
                                createConnection(
                                        connectionManagerPhoneAccount,
                                        id,
                                        request,
                                        isIncoming,
                                        isUnknown);
                            }
                        });
                    } else {

                        createConnection(
                                connectionManagerPhoneAccount,
                                id,
                                request,
                                isIncoming,
                                isUnknown);
                    }
                } finally {
                    args.recycle();
                }
                break;
            }

        .............

Step52

继续刚才49步的执行

   void addAdapter(IConnectionServiceAdapter adapter) {
    android.util.Log.d("wds_mo","step51-->framework/base/Telecom-->ConnectionServiceAdapter.addAdapter()");
    for (IConnectionServiceAdapter it : mAdapters) {
        if (it.asBinder() == adapter.asBinder()) {
            Log.w(this, "Ignoring duplicate adapter addition.");
            return;
        }
    }
    if (mAdapters.add(adapter)) {
        try {
            adapter.asBinder().linkToDeath(this, 0);
        } catch (RemoteException e) {
            mAdapters.remove(adapter);
        }
    }
}

Step54

继续执行53步
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);

    /// M: ALPS02136977. Prints debug messages for MO. @{
    if (!isIncoming) {
        String callNumber = null;
        if (request != null && request.getAddress() != null) {
            callNumber = request.getAddress().getSchemeSpecificPart();
        }
        FormattedLog formattedLog = new FormattedLog.Builder()
                .setCategory("CC")
                .setServiceName(getConnectionServiceName())
                .setOpType(FormattedLog.OpType.OPERATION)
                .setActionName("Dial")
                .setCallNumber(callNumber)
                .setCallId("")
                .buildDebugMsg();
        if (formattedLog != null) {
            Log.d(this, formattedLog.toString());
        }
    }
    /// @}
    android.util.Log.d("wds_mo","step54-->framework/base/Telecom-->Connection.createConnection()");
    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.createFailedConnection(
                new DisconnectCause(DisconnectCause.ERROR));
    }

    if (connection.getState() != Connection.STATE_DISCONNECTED) {
        addConnection(callId, connection);
    }

     ........

pacakge/services/Telephony

Step55

    @Override
public Connection onCreateOutgoingConnection(
        PhoneAccountHandle connectionManagerPhoneAccount,
        final ConnectionRequest request) {



         ...........




    } else {
        android.util.Log.d("wds_mo","step55-->Telephony-->TelephonyConnectionService.onCreateOutgoingConnection()");
        placeOutgoingConnection(connection, phone, request);
    }

    return connection;
}

Step56

  private void placeOutgoingConnection(
        TelephonyConnection connection, Phone phone, ConnectionRequest request) {
    String number = connection.getAddress().getSchemeSpecificPart();
    boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(this, number);
    /// M: CC036: [ALPS01794357] Set PhoneAccountHandle for ECC @{
    if (isEmergencyNumber) {
        final PhoneAccountHandle phoneAccountHandle;
        String phoneIccId = phone.getIccSerialNumber();
        int slotId = SubscriptionController.getInstance().getSlotId(phone.getSubId());
        if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
            phoneIccId = !TextUtils.isEmpty(phoneIccId) ?
                    phoneIccId : TelephonyManagerEx.getDefault().getSimSerialNumber(slotId);
        }
        if (TextUtils.isEmpty(phoneIccId)) {
            // If No SIM is inserted, the corresponding IccId will be null,
            // take phoneId as PhoneAccountHandle::mId which is IccId originally
            phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(
                    Integer.toString(phone.getPhoneId()));
        } else {
            phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(phoneIccId);
        }
        Log.d(this, "placeOutgoingConnection, set back account mId: %s, iccId: %s",
                phoneAccountHandle.getId(), phoneIccId);
        connection.setAccountHandle(phoneAccountHandle);
    }
    /// @}
    com.android.internal.telephony.Connection originalConnection;
    try {
        android.util.Log.d("wds_mo","step56-->Telephony-->TelephonyConnectionService.placeOutgoingConnection()");
        originalConnection =
                phone.dial(number, null, request.getVideoState(), request.getExtras());
   } catch (CallStateException e) {

    .......
}

framework/opt/telephony

Step57

    @Override
public Connection
dial (String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
        throws CallStateException {
    boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(dialString);
    ImsPhone imsPhone = mImsPhone;

        .......



    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 (LOCAL_DEBUG) Rlog.d(LOG_TAG, "Trying (non-IMS) CS call");
    /// M: For 3G VT only @{
    //return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);
    Rlog.d("wds_mo","step57-->framework/opt/telephony-->GSMPhone.dial()B");
    return dialInternal(dialString, null, videoState, intentExtras);
    /// @}
}

Step58

    @Override
protected Connection
dialInternal (String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
        throws CallStateException {

    /// M: Ignore stripping for VoLTE SIP uri. @{
    String newDialString = dialString;
    if (!PhoneNumberUtils.isUriNumber(dialString)) {
        // Need to make sure dialString gets parsed properly
        newDialString = PhoneNumberUtils.stripSeparators(dialString);
    }
    /// @}

    // handle in-call MMI first if applicable
    if (handleInCallMmiCommands(newDialString)) {
        return null;
    }

    // Only look at the Network portion for mmi
    String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
    /* M: SS part */
    Rlog.d(LOG_TAG, "network portion:" + networkPortion);
    /* M: SS part end */
    GsmMmiCode mmi =
            GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
    if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
                           "dialing w/ mmi '" + mmi + "'...");

    if (mmi == null) {
        /// M: For 3G VT only @{
        //return mCT.dial(newDialString, uusInfo, intentExtras);
        if (videoState == VideoProfile.STATE_AUDIO_ONLY) {
            Rlog.d("wds_mo","step58-->framework/opt/telephony-->GSMPhone.dialInternal()A");
            return mCT.dial(newDialString, uusInfo, intentExtras);
        } else {
            if (!is3GVTEnabled()) {
                throw new CallStateException("cannot vtDial for non-3GVT-capable device");
            }
            return mCT.vtDial(newDialString, uusInfo, intentExtras);
        }
        /// @}
    } else if (mmi.isTemporaryModeCLIR()) {
        /// M: For 3G VT only @{
        //return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
        if (videoState == VideoProfile.STATE_AUDIO_ONLY) {

            return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
        } else {
            if (!is3GVTEnabled()) {
                throw new CallStateException("cannot vtDial for non-3GVT-capable device");
            }
            return mCT.vtDial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
        }
        /// @}
    } else {
        /* M: SS part */
        Rlog.d(LOG_TAG, "[dial]mPendingMMIs.add(mmi) + " + mmi);
        /* M: SS part end */
        mPendingMMIs.add(mmi);
        mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
        mmi.processCode();

        // FIXME should this return null or something else?
        return null;
    }
}

Step59

    synchronized Connection
dial (String dialString, int clirMode, UUSInfo uusInfo, Bundle intentExtras)
        throws CallStateException {
    // note that this triggers call state changed notif

    clearDisconnected();

    if (!canDial()) {
        throw new CallStateException("cannot dial in current state");
    }

    String origNumber = dialString;
    dialString = convertNumberIfNecessary(mPhone, dialString);

    // 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() == GsmCall.State.ACTIVE) {
        // this will probably be done by the radio anyway
        // but the dial might fail before this happens
        // and we need to make sure the foreground call is clear
        // for the newly dialed connection

        /// M: CC015: CRSS special handling @{
        mWaitingForHoldRequest.set();
        /// @}

        switchWaitingOrHoldingAndActive();
        // This is a hack to delay DIAL so that it is sent out to RIL only after
        // EVENT_SWITCH_RESULT is received. We've seen failures when adding a new call to
        // multi-way conference calls due to DIAL being sent out before SWITCH is processed
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            // do nothing
        }

        // Fake local state so that
        // a) foregroundCall is empty for the newly dialed connection
        // b) hasNonHangupStateChanged remains false in the
        // next poll, so that we don't clear a failed dialing call
        fakeHoldForegroundBeforeDial();
    }

    if (mForegroundCall.getState() != GsmCall.State.IDLE) {
        //we should have failed in !canDial() above before we get here
        throw new CallStateException("cannot dial in current state");
    }

    mPendingMO = new GsmConnection(mPhone.getContext(), checkForTestEmergencyNumber(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;

        /// M: CC015: CRSS special handling @{
        mWaitingForHoldRequest.reset();
        /// @}

        // handlePollCalls() will notice this call not present
        // and will mark it as dropped.
        pollCallsWhenSafe();
    } else {
        // Always unmute when initiating a new call
        setMute(false);

        /// M: CC015: CRSS special handling @{
        if (!mWaitingForHoldRequest.isWaiting()) {
            /// M: CC010: Add RIL interface @{
            /// M: ECC Retry @{
            if (PhoneNumberUtils.isEmergencyNumber(mPhone.getSubId(), dialString)
            /// @}
                    && !PhoneNumberUtils.isSpecialEmergencyNumber(dialString)) {
                int serviceCategory = PhoneNumberUtils.getServiceCategoryFromEccBySubId(
                        dialString, mPhone.getSubId());
                mCi.setEccServiceCategory(serviceCategory);
                mCi.emergencyDial(mPendingMO.getAddress(), clirMode, uusInfo,
                        obtainCompleteMessage(EVENT_DIAL_CALL_RESULT));
            /// @}
            } else {
                Rlog.d("wds_mo","step59-->framework/opt/telephony-->GsmCallTracker.dial()");
                mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo,
                        obtainCompleteMessage(EVENT_DIAL_CALL_RESULT));
            }
        } else {
            mWaitingForHoldRequest.set(mPendingMO.getAddress(), clirMode, uusInfo);
        }
        /// @}
    }

    if (mNumberConverted) {
        mPendingMO.setConverted(origNumber);
        mNumberConverted = false;
    }

    updatePhoneState();
    mPhone.notifyPreciseCallStateChanged();

    return mPendingMO;
}

Step60

   @Override
public void
dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
    Rlog.d("wds_mo","step60-->framework/opt/telephony-->RIL.dial() ");
    if (!PhoneNumberUtils.isUriNumber(address)) {
       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));

       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));
       send(rr);
    }
}

framework/base/telecomm

Step60

继续执行第54步,未执行完的

    void handleCreateConnectionComplete(
        String id,
        ConnectionRequest request,
        ParcelableConnection connection) {
    android.util.Log.d("wds_mo","step60-->Telephony-->ConnectionServiceAdapter.handleCreateConnectionComplete()");
    for (IConnectionServiceAdapter adapter : mAdapters) {
        try {
            adapter.handleCreateConnectionComplete(id, request, connection);
        } catch (RemoteException e) {
        }
    }
}

package/service/Telecomm

Step61

private final class Adapter extends IConnectionServiceAdapter.Stub {

    @Override
    public void handleCreateConnectionComplete(
            String callId,
            ConnectionRequest request,
            ParcelableConnection connection) {
        long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                /// M: for log parser @{
                String number = "";
                String action = "";
                Uri uri = connection.getHandle();
                if (uri != null) {
                    number = uri.getSchemeSpecificPart();
                }
                Call call = mCallIdMapper.getCall(callId);
                if (call != null) {
                    if (call.isIncoming()) {
                        action = LogUtils.NOTIFY_ACTION_CREATE_MT_SUCCESS;
                    } else if (!call.isUnknown()) {
                        action = LogUtils.NOTIFY_ACTION_CREATE_MO_SUCCESS;
                    }
                }
                LogUtils.logCcNotify(number, action, callId, connection.toString());
                /// @}
                logIncoming("handleCreateConnectionComplete %s", callId);
                if (mCallIdMapper.isValidCallId(callId)) {
                    android.util.Log.d("wds_mo","step61-->Telecom-->ConnectionServiceWrapper.Adapter.handleCreateConnectionComplete()");
                    ConnectionServiceWrapper.this
                            .handleCreateConnectionComplete(callId, request, connection);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }
    ...........

Step62

    private void handleCreateConnectionComplete(
        String callId,
        ConnectionRequest request,
        ParcelableConnection connection) {
    // TODO: Note we are not using parameter "request", which is a side effect of our tacit
    // assumption that we have at most one outgoing connection attempt per ConnectionService.
    // This may not continue to be the case.
    if (connection.getState() == Connection.STATE_DISCONNECTED) {
        // A connection that begins in the DISCONNECTED state is an indication of
        // failure to connect; we handle all failures uniformly
        removeCall(callId, connection.getDisconnectCause());
    } else {
        // Successful connection
        if (mPendingResponses.containsKey(callId)) {
            String num = connection.getHandle().getSchemeSpecificPart();
            /// M: add for CMCC L + C ecc retry
            if (PhoneNumberUtils.isEmergencyNumber(num)) {

                mPendingResponses.get(callId).
                         handleCreateConnectionSuccess(mCallIdMapper, connection);
            } else {
                android.util.Log.d("wds_mo","step62-->Telecom-->ConnectionServiceWrapper.handleCreateConnectionComplete");
                mPendingResponses.remove(callId)
                        .handleCreateConnectionSuccess(mCallIdMapper, connection);
            }
        }
    }
}

Step63

 @Override
public void handleCreateConnectionSuccess(
        CallIdMapper idMapper,
        ParcelableConnection connection) {
    Log.v(this, "handleCreateConnectionSuccessful %s", connection);
    setTargetPhoneAccount(connection.getPhoneAccount());
    setHandle(connection.getHandle(), connection.getHandlePresentation());
    setCallerDisplayName(
            connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());
    setConnectionCapabilities(connection.getConnectionCapabilities());
    setVideoProvider(connection.getVideoProvider());
    setVideoState(connection.getVideoState());
    setRingbackRequested(connection.isRingbackRequested());
    setIsVoipAudioMode(connection.getIsVoipAudioMode());
    setStatusHints(connection.getStatusHints());
    setExtras(connection.getExtras());

    mConferenceableCalls.clear();
    for (String id : connection.getConferenceableConnectionIds()) {
        mConferenceableCalls.add(idMapper.getCall(id));
    }

    if (mIsUnknown) {
        for (Listener l : mListeners) {
            l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection.getState()));
        }
    } else if (mIsIncoming) {
        // We do not handle incoming calls immediately when they are verified by the connection
        // service. We allow the caller-info-query code to execute first so that we can read the
        // direct-to-voicemail property before deciding if we want to show the incoming call to
        // the user or if we want to reject the call.
        mDirectToVoicemailQueryPending = true;

        // Timeout the direct-to-voicemail lookup execution so that we dont wait too long before
        // showing the user the incoming call screen.
        mHandler.postDelayed(mDirectToVoicemailRunnable, Timeouts.getDirectToVoicemailMillis(
                mContext.getContentResolver()));
    } else {
        /// M: ALPS02568075 @{
        // when perform ECC retry from dialing state
        // force to set as CONNECTING this time
        // in order to reset audio mode as normal in CallAudioManager.onCallStateChanged
        // then Ecc is changed to dialing again, can set audio mode once time.
        android.util.Log.d("wds_mo","step63-->Telecom-->Call.handleCreateConnectionSuccess()");
        if (isEmergencyCall() && getState() == CallState.DIALING) {
            Log.v(this, "Change ecc state as connecting");
            for (Listener l : mListeners) {
                l.onSuccessfulOutgoingCall(this, CallState.CONNECTING);
            }
        }
        /// @}
        for (Listener l : mListeners) {
            l.onSuccessfulOutgoingCall(this,
                    getStateFromConnectionState(connection.getState()));
        }
    }
}

Step64

 @Override
public void onSuccessfulOutgoingCall(Call call, int callState) {
    Log.v(this, "onSuccessfulOutgoingCall, %s", call);

    setCallState(call, callState, "successful outgoing call");
    if (!mCalls.contains(call)) {
        // Call was not added previously in startOutgoingCall due to it being a potential MMI
        // code, so add it now.
        /// M: If already exist other calls, should handle properly. @{
        // original google code:
        //addCall(call);
        handleShouldAddOutgoingCall(call);
        /// @}
    } else {
        // M: Temp solution for ALPS02548133.
        handleCallsWhenOutgoingSuccess(call);
    }

    // The call's ConnectionService has been updated.
    for (CallsManagerListener listener : mListeners) {
        listener.onConnectionServiceChanged(call, null, call.getConnectionService());
    }

    //ALPS01781841, do not mark Ecc call as dialing state this time point
    //Ecc call is marked as dialing state only when FWK call state event(MSG_SET_DIALING) post to ConnectionServiceWrapper.Adapter
    android.util.Log.d("wds_mo","step64-->Telecom-->CallsManager.onSuccessfulOutgoingCall()");
    if (!call.isEmergencyCall()) {
        markCallAsDialing(call);
    }
}

Step66

private void setCallState(Call call, int newState, String tag) {
    if (call == null) {
        return;
    }
    int oldState = call.getState();
    Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState),
            CallState.toString(newState), call);
    if (newState != oldState) {
        // Unfortunately, in the telephony world the radio is king. So if the call notifies
        // us that the call is in a particular state, we allow it even if it doesn't make
        // sense (e.g., STATE_ACTIVE -> STATE_RINGING).
        // TODO: Consider putting a stop to the above and turning CallState
        // into a well-defined state machine.
        // TODO: Define expected state transitions here, and log when an
        // unexpected transition occurs.
        call.setState(newState, tag);

        /// M: Set the voice recording capability
        int capabilities = call.getConnectionCapabilities();
        boolean hasRecordCap = (capabilities & Connection.CAPABILITY_VOICE_RECORD) == 0
                ? false : true;
        boolean okToRecord = okToRecordVoice(call);
        if (okToRecord && !hasRecordCap) {
            call.setConnectionCapabilities(capabilities
                    | Connection.CAPABILITY_VOICE_RECORD);
        }
        if (!okToRecord && hasRecordCap) {
            PhoneRecorderHandler.getInstance().stopVoiceRecordIfNecessary(call);
            call.setConnectionCapabilities(capabilities
                  & ~Connection.CAPABILITY_VOICE_RECORD);
        }

        Trace.beginSection("onCallStateChanged");
        // Only broadcast state change for calls that are being tracked.
        android.util.Log.d("wds_mo","step66-->Telecom-->CallsManager.setCallState()");
        if (mCalls.contains(call)) {
            for (CallsManagerListener listener : mListeners) {
                if (Log.SYSTRACE_DEBUG) {
                    Trace.beginSection(listener.getClass().toString() + " onCallStateChanged");
                }
                listener.onCallStateChanged(call, oldState, newState);
                if (Log.SYSTRACE_DEBUG) {
                    Trace.endSection();
                }
            }
            updateCallsManagerState();
        }
        /// M: MSMA call control, first call action finished. @{
        handleActionProcessComplete(call);
        /// @}
        Trace.endSection();
    }
}

Step67

    @Override
public void onCallStateChanged(Call call, int oldState, int newState) {
    android.util.Log.d("wds_mo","step67-->Telecom-->InCallController.onCallStateChanged()");
    updateCall(call);
}

Step69

   private void updateCall(Call call, boolean videoProviderChanged) {
    if (!mInCallServices.isEmpty()) {
        ParcelableCall parcelableCall = toParcelableCall(call,
                videoProviderChanged /* includeVideoProvider */);
        Log.i(this, "Sending updateCall %s ==> %s", call, parcelableCall);
        List<ComponentName> componentsUpdated = new ArrayList<>();
        android.util.Log.d("wds_mo","step69-->Telecom-->InCallController.updateCall()");
        for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
            ComponentName componentName = entry.getKey();
            IInCallService inCallService = entry.getValue();
            componentsUpdated.add(componentName);
            try {
                inCallService.updateCall(parcelableCall);
            } catch (RemoteException ignored) {
            }
        }
        Log.i(this, "Components updated: %s", componentsUpdated);
    }
}

framework/base/Telecomm

Step70

  private final class InCallServiceBinder extends IInCallService.Stub {

      .......

    @Override
    public void updateCall(ParcelableCall call) {
        android.util.Log.d("wds_mo","step70-->framework/base/Telecom-->InCallService.InCallServiceBinder.updateCall()");
        mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget();
    }

    .....

Step71

      @Override
    public void handleMessage(Message msg) {
        /// M: [log optimize]for performance debugging.
        mMessageAnalyzer.onStartHandleMessage(msg);
        if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) {
            /// M: [log optimize]for performance debugging.
            mMessageAnalyzer.onMessageHandled(msg);
            return;
        }

        SomeArgs args;
        switch (msg.what) {
             ....

            case MSG_UPDATE_CALL:
                android.util.Log.d("wds_mo","step71-->framework/base/Telecom-->InCallService.handleMessage_MSG_UPDATE_CALL");
                TelecomTrace.begin("InCallService_update");
                mPhone.internalUpdateCall((ParcelableCall) msg.obj);
                TelecomTrace.end("InCallService_update");
                break;
            ...

Step72

    final void internalUpdateCall(ParcelableCall parcelableCall) {

     Call call = mCallByTelecomCallId.get(parcelableCall.getId());
     if (call != null) {
         checkCallTree(parcelableCall);
         android.util.Log.d("wds_mo","step72-->framework/base/Telecom-->Phone.internalUpdateCall");
         call.internalUpdate(parcelableCall, mCallByTelecomCallId);
     }
 }

Step73

   /** {@hide} */
final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
    // First, we update the internal state as far as possible before firing any updates.


    .........

    if (stateChanged) {
        android.util.Log.d("wds_mo","step73-->framework/base/Telecom-->Call.internalUpdate()");
        fireStateChanged(mState);
    }

    .............

}

Step74

    private void fireStateChanged(final int newState) {
    android.util.Log.d("wds_mo","step74-->framework/base/Telecom-->Call.fireStateChanged()");
    for (CallbackRecord<Callback> record : mCallbackRecords) {
        final Call call = this;
        final Callback callback = record.getCallback();
        record.getHandler().post(new Runnable() {
            @Override
            public void run() {
                callback.onStateChanged(call, newState);
            }
        });
    }
}

package/apps/InCallUI

Step75

private android.telecom.Call.Callback mTelecomCallCallback =
        new android.telecom.Call.Callback() {
            @Override
            public void onStateChanged(android.telecom.Call call, int newState) {
                Log.d(this, "TelecommCallCallback onStateChanged call=" + call + " newState="
                        + newState);
                android.util.Log.d("wds_mo","step75-->InCallUI-->Call.mTelecomCallCallback.onStateChanged()");
                InCallTrace.begin("telecomStateChanged");
                update();
                InCallTrace.end("telecomStateChanged");
            }
     .....

Step76

    private void update() {
    Trace.beginSection("Update");
    int oldState = getState();
    updateFromTelecommCall();
    if (oldState != getState() && getState() == Call.State.DISCONNECTED) {
        /// M: [log optimize]
        Log.notify(this, Log.CcNotifyAction.DISCONNECTED,
                mDisconnectCause == null ?
                        "DisconnectCause: null" : mDisconnectCause.toString());
        CallList.getInstance().onDisconnect(this);
    } else {
        android.util.Log.d("wds_mo","step76-->InCallUI-->Call.update()");
        CallList.getInstance().onUpdate(this);
    }
    Trace.endSection();
}

之后与33步重合