android12的拨号流程

在这里插入图片描述
可以看到,在aosp的packages\services包下,有两个service,分别为Telecomm和Telephony,Telecomm在android5.0引入,是Android的一个系统服务,运行在system系统进程,位于Dialer,和TeleService之间,起到桥梁作用。Telephony,TeleService服务,运行于自身的com.android.phone进程。

路径统称进程
packages/app/DialerDialercom.android.dialer
packages/service/telecommtelecomsystem_service
packages/service/telephonyTeleServiceTeleService

Telecom服务

Telecom是一个更一般性的通讯框架,运行在system进程中。

1.点击拨号
在这里插入图片描述
/android/packages/apps/Dialer/java/com/android/dialer/dialpadview/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();
    }

在handleDialButtonPressed中做一些基本的判断,判断号码是否为空

  private void handleDialButtonPressed() {
    if (isDigitsEmpty()) { // No number entered. 判断号码是否为空
      // No real call made, so treat it as a click
      PerformanceReport.recordClick(UiAction.Type.PRESS_CALL_BUTTON_WITHOUT_CALLING);
      handleDialButtonClickWithEmptyDigits();
    } else {
      final String number = digits.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(prohibitedPhoneNumberRegexp)
          && number.matches(prohibitedPhoneNumberRegexp)) {
        PerformanceReport.recordClick(UiAction.Type.PRESS_CALL_BUTTON_WITHOUT_CALLING);
        LogUtil.i(
            "DialpadFragment.handleDialButtonPressed",
            "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 {
        PreCall.start(getContext(), new CallIntentBuilder(number, CallInitiationType.Type.DIALPAD));
        hideAndClearDialpad();
      }
    }
  }

/android/packages/apps/Dialer/java/com/android/dialer/precall/PreCall.java

 static void start(Context context, CallIntentBuilder builder) {
    //调用DialerUtils.startActivityWithErrorToast方法
    DialerUtils.startActivityWithErrorToast(context, getIntent(context, builder));
  }

/android/packages/apps/Dialer/java/com/android/dialer/util/DialerUtils.java

//开启一个activity,或者显示错误弹窗
  public static void startActivityWithErrorToast(
      final Context context, final Intent intent, int msgId) {
    try {
      //如果activity是拨打电话
      if ((Intent.ACTION_CALL.equals(intent.getAction()))) {
		...
        if (shouldWarnForOutgoingWps(context, intent.getData().getSchemeSpecificPart())) {
        ...
        } else {
          //拨打电话,或者显示错误弹窗
          placeCallOrMakeToast(context, intent);
        }
      } else { //不是直接开启activity
        context.startActivity(intent);
      }
    } catch (ActivityNotFoundException e) {
    //如果开启activity异常则,显示错误弹窗
      Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show();
    }
  }

/packages/apps/Dialer/java/com/android/dialer/telecom/TelecomUtil.java

  //尝试使用TelecomManager去拨打一个电话
  //拨打一个电话成功,返回true
  //如果由于权限检查,拨打电话失败返回false
  public static boolean placeCall(Context context, Intent intent) {
    if (hasCallPhonePermission(context)) {
      getTelecomManager(context).placeCall(intent.getData(), intent.getExtras());
      return true;
    }
    return false;
  }

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

//使用telecom service和其他的附加服务,向提供的地址拨打电话
    @RequiresPermission(anyOf = {android.Manifest.permission.CALL_PHONE,
            android.Manifest.permission.MANAGE_OWN_CALLS})
    public void placeCall(Uri address, Bundle extras) {
    	//获取TelecomService
        ITelecomService service = getTelecomService();
        if (service != null) {
            if (address == null) {
                Log.w(TAG, "Cannot place call to empty address.");
            }
            try {
                service.placeCall(address, extras == null ? new Bundle() : extras,
                        mContext.getOpPackageName(), mContext.getAttributionTag());
            } catch (RemoteException e) {
                Log.e(TAG, "Error calling ITelecomService#placeCall", e);
            }
        }
    }

通过ITelecomService 远程调用Telecom系统服务,接下来就进入到system_process进程

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

 		 /**
         * @see android.telecom.TelecomManager#placeCall
         */
        @Override
        public void placeCall(Uri handle, Bundle extras, String callingPackage,
                String callingFeatureId) {
            try {
                Log.startSession("TSI.pC");
                enforceCallingPackage(callingPackage);

                PhoneAccountHandle phoneAccountHandle = null;
                if (extras != null) {
                    phoneAccountHandle = extras.getParcelable(
                            TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
                    if (extras.containsKey(TelecomManager.EXTRA_IS_HANDOVER)) {
                        // This extra is for Telecom use only so should never be passed in.
                        extras.remove(TelecomManager.EXTRA_IS_HANDOVER);
                    }
                }
                boolean isSelfManaged = phoneAccountHandle != null &&
                        isSelfManagedConnectionService(phoneAccountHandle);
                if (isSelfManaged) {
                    mContext.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_OWN_CALLS,
                            "Self-managed ConnectionServices require MANAGE_OWN_CALLS permission.");

                    if (!callingPackage.equals(
                            phoneAccountHandle.getComponentName().getPackageName())
                            && !canCallPhone(callingPackage, callingFeatureId,
                            "CALL_PHONE permission required to place calls.")) {
                        // The caller is not allowed to place calls, so we want to ensure that it
                        // can only place calls through itself.
                        throw new SecurityException("Self-managed ConnectionServices can only "
                                + "place calls through their own ConnectionService.");
                    }
                } else if (!canCallPhone(callingPackage, callingFeatureId, "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, callingFeatureId, null)
                        == AppOpsManager.MODE_ALLOWED;

                final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==
                        PackageManager.PERMISSION_GRANTED;
                // The Emergency Dialer has call privileged permission and uses this to place
                // emergency calls.  We ensure permission checks in
                // NewOutgoingCallIntentBroadcaster#process pass by sending this to
                // Telecom as an ACTION_CALL_PRIVILEGED intent (which makes sense since the
                // com.android.phone process has that permission).
                final boolean hasCallPrivilegedPermission = mContext.checkCallingPermission(
                        CALL_PRIVILEGED) == PackageManager.PERMISSION_GRANTED;

                synchronized (mLock) {
                    final UserHandle userHandle = Binder.getCallingUserHandle();
                    long token = Binder.clearCallingIdentity();
                    try {
                        final Intent intent = new Intent(hasCallPrivilegedPermission ?
                                Intent.ACTION_CALL_PRIVILEGED : Intent.ACTION_CALL, handle);
                        if (extras != null) {
                            extras.setDefusable(true);
                            intent.putExtras(extras);
                        }
                        mUserCallIntentProcessorFactory.create(mContext, userHandle)
                                .processIntent(
                                        intent, callingPackage, isSelfManaged ||
                                                (hasCallAppOp && hasCallPermission),
                                        true /* isLocalInvocation */);
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    }
                }
            } finally {
                Log.endSession();
            }
        }

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

 //处理发送到活动的意图
    public void processIntent(Intent intent, String callingPackageName,
            boolean canCallNonEmergency, boolean isLocalInvocation) {
        // 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)) {
            processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency,
                    isLocalInvocation);
        }
    }
//处理向外呼叫的intent
        private void processOutgoingCallIntent(Intent intent, String callingPackageName,
            boolean canCallNonEmergency, boolean isLocalInvocation) {
        ...
        sendIntentToDestination(intent, isLocalInvocation, callingPackageName);
    }
private boolean sendIntentToDestination(Intent intent, boolean isLocalInvocation,
            String callingPackage) {
        intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        if (isLocalInvocation) {
            // We are invoking this from TelecomServiceImpl, so TelecomSystem is available.  Don't
            // bother trampolining the intent, just sent it directly to the call intent processor.
            // TODO: We should not be using an intent here; this whole flows needs cleanup.
            Log.i(this, "sendIntentToDestination: send intent to Telecom directly.");
            synchronized (TelecomSystem.getInstance().getLock()) {
                TelecomSystem.getInstance().getCallIntentProcessor().processIntent(intent,
                        callingPackage);
            }
        } else {
            // We're calling from the UserCallActivity, so the TelecomSystem is not in the same
            // process; we need to trampoline to TelecomSystem in the system server process.
            Log.i(this, "sendIntentToDestination: trampoline to Telecom.");
            TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
            tm.handleCallIntent(intent, callingPackage);
        }
        return true;
    }

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

public void handleCallIntent(Intent intent, String callingPackageProxy) {
        ITelecomService service = getTelecomService();
        if (service != null) {
            try {
            	//使用通信服务
                service.handleCallIntent(intent, callingPackageProxy);
            } catch (RemoteException e) {
                Log.e(TAG, "RemoteException handleCallIntent: " + e);
            }
        }
    }

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

 public void handleCallIntent(Intent intent, String callingPackage) {
            try {
                Log.startSession("TSI.hCI");
                synchronized (mLock) {
                    mContext.enforceCallingOrSelfPermission(PERMISSION_HANDLE_CALL_INTENT,
                            "handleCallIntent is for internal use only.");

                    long token = Binder.clearCallingIdentity();
                    try {
                        Log.i(this, "handleCallIntent: handling call intent");
                        mCallIntentProcessorAdapter.processOutgoingCallIntent(mContext,
                                mCallsManager, intent, callingPackage);
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    }
                }
            } finally {
                Log.endSession();
            }
        }

可以看到,调用了 mCallIntentProcessorAdapter.processOutgoingCallIntent,而mCallIntentProcessorAdapter是在TelecomServiceImpl的构造函数中初始化的,mCallIntentProcessorAdapter = callIntentProcessorAdapter;而,TelecomServiceImpl是在TelecomSystem的构造函数中创建的,至于TelecomSystem的创建和TelecomService服务的启动可以看博客https://blog.csdn.net/jason_wzn/article/details/58164251的分析

mTelecomServiceImpl = new TelecomServiceImpl(
                    mContext, mCallsManager, mPhoneAccountRegistrar,
                    new CallIntentProcessor.AdapterImpl(defaultDialerCache),
                    new UserCallIntentProcessorFactory() {
                        @Override
                        public UserCallIntentProcessor create(Context context,
                                UserHandle userHandle) {
                            return new UserCallIntentProcessor(context, userHandle);
                        }
                    },
                    defaultDialerCache,
                    new TelecomServiceImpl.SubscriptionManagerAdapterImpl(),
                    new TelecomServiceImpl.SettingsSecureAdapterImpl(),
                    mLock);

最终调用/packages/services/Telecomm/src/com/android/server/telecom/CallIntentProcessor#AdapterImpl.processOutgoingCallIntent方法

public void processOutgoingCallIntent(Context context, CallsManager callsManager,
                Intent intent, String callingPackage) {
            CallIntentProcessor.processOutgoingCallIntent(context, callsManager, intent,
                    callingPackage, mDefaultDialerCache);
        }

调用CallIntentProcessor.processOutgoingCallIntent

static void processOutgoingCallIntent(
            Context context,
            CallsManager callsManager,
            Intent intent,
            String callingPackage,
            DefaultDialerCache defaultDialerCache) {

     	...
        // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
        //创建call对象
        CompletableFuture<Call> callFuture = callsManager
                .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,
                        intent, callingPackage);
          ...
    }

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

CompletableFuture<Call> startOutgoingCall(Uri handle,
            PhoneAccountHandle requestedAccountHandle,
            Bundle extras, UserHandle initiatingUser, Intent originalIntent,
            String callingPackage) {
        final List<Uri> callee = new ArrayList<>();
        callee.add(handle);
        return startOutgoingCall(callee, requestedAccountHandle, extras, initiatingUser,
                originalIntent, callingPackage, false);
    }
private CompletableFuture<Call> startOutgoingCall(List<Uri> participants,
            PhoneAccountHandle requestedAccountHandle,
            Bundle extras, UserHandle initiatingUser, Intent originalIntent,
            String callingPackage, boolean isConference) {
            ...
		if (call == null) {
            call = new Call(getNextCallId(), mContext,
                    this,
                    mLock,
                    mConnectionServiceRepository,
                    mPhoneNumberUtilsAdapter,
                    handle,
                    isConference ? participants : null,
                    null /* gatewayInfo */,
                    null /* connectionManagerPhoneAccount */,
                    null /* requestedAccountHandle */,
                    Call.CALL_DIRECTION_OUTGOING /* callDirection */,
                    false /* forceAttachToExistingConnection */,
                    isConference, /* isConference */
                    mClockProxy,
                    mToastFactory);
		
		addCall(callToPlace);
		...
}
    //将指定的通话添加到实时通话列表中
    public void addCall(Call call) {
        ...
        call.addListener(this);
        mCalls.add(call);

       ...
        for (CallsManagerListener listener : mListeners) {
            ...
            listener.onCallAdded(call);
            ...
        }
        ...
    }

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

public void onCallAdded(Call call) {
        if (!isBoundAndConnectedToServices()) {
            // We are not bound, or we're not connected.
            bindToServices(call);
        } else {
            ...
            addCall(call);

            ...

            List<ComponentName> componentsUpdated = new ArrayList<>();
            for (Map.Entry<InCallServiceInfo, IInCallService> entry : mInCallServices.entrySet()) {
                ...
                    inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
                ...
        }
    }

这里调用inCallService.addCall远程调用Dialer进程的InCallService服务,并将Call对象传回。
/frameworks/base/telecomm/java/android/telecom/InCallService.InCallServiceBinder

 public void addCall(ParcelableCall call) {
            mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
        }

InCallServiceBinder.mHandler

			case MSG_ADD_CALL:
                    mPhone.internalAddCall((ParcelableCall) msg.obj);
                    break;

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

final void internalUpdateCall(ParcelableCall parcelableCall) {
       ...
            call.internalUpdate(parcelableCall, mCallByTelecomCallId);
       ...
    }

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

final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {

       ...
       // Now we fire updates, ensuring that any client who listens to any of these notifications
       // gets the most up-to-date state.

       if (stateChanged) {
           fireStateChanged(mState);
       }
       if (detailsChanged) {
           fireDetailsChanged(mDetails);
       }
      ...
   }
private void fireStateChanged(final int newState) {
        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);
                }
            });
        }
    }

/packages/apps/Dialer/java/com/android/incallui/call/DialerCall#telecomCallCallback

 public void onStateChanged(Call call, int newState) {
          LogUtil.v("TelecomCallCallback.onStateChanged", "call=" + call + " newState=" + newState);
          update();
        }
private void update() {
   ...
      for (DialerCallListener listener : listeners) {
        listener.onDialerCallUpdate();
      }
   ...
  }

/packages/apps/Dialer/java/com/android/incallui/call/CallList.java#DialerCallListenerImpl

@Override
    public void onDialerCallUpdate() {
      Trace.beginSection("CallList.onDialerCallUpdate");
      onUpdateCall(call);
      notifyGenericListeners();
      Trace.endSection();
    }

CallList.java

private void notifyGenericListeners() {
    ...
    for (Listener listener : listeners) {
      listener.onCallListChange(this);
    }
    ...
  }

CallList的listeners在incallui/InCallPresenter.java的setUp,中赋值this.callList = callList;
/packages/apps/Dialer/java/com/android/incallui/InCallPresenter.java

public void onCallListChange(CallList callList) {
    
    ...
    newState = startOrFinishUi(newState);
    ...
  }
private InCallState startOrFinishUi(InCallState newState) {
    ...
    if ((showCallUi || showAccountPicker) && !shouldStartInBubbleMode()) {
      LogUtil.i("InCallPresenter.startOrFinishUi", "Start in call UI");
      //开始显示UI
      showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */);
    } else if (newState == InCallState.NO_CALLS) {
      // The new state is the no calls state.  Tear everything down.
      inCallState = newState;
      attemptFinishActivity();
      attemptCleanup();
    }
    ...
    return newState;
  }

开启InCallActivity

public void showInCall(boolean showDialpad, boolean newOutgoingCall) {
    LogUtil.i("InCallPresenter.showInCall", "Showing InCallActivity");
    context.startActivity(
        InCallActivity.getIntent(context, showDialpad, newOutgoingCall, false /* forFullScreen */));	
  }

参考:Android Dialer源码分析之去电流程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值