当前位置:   article > 正文

安卓10拨号流程详细总结_com.phone.thephone.call.dialer

com.phone.thephone.call.dialer

电话应用框架

Android电话模块是一个典型的分层结构设计,如下:

电话框架分为4个层次,分别为:应用层、框架层(framework层,简称fw)、RIL(Radio Interface Layer)、modem。

应用层:app应用,包括Dialer.apk、TeleService.apk、Telecom.apk、InCallUI.apk。

其中Dialer.apk跑在com.android.dialer进程中,TeleService.apk跑在常驻进程com.android.phone进程中,Telecom.apk跑在system进程中、InCallUI.apk跑在com.android.incallui进程中。

框架层:包括telephony fw、telecom fw。Code分别位于frameworks/opt/telephony、frameworks/base/telecomm。

RIL:位于User Libraries层中的HAL层,提供AP(Application Processor,应用处理器)和BP(Baseband Processor,基带处理器)之间的通信功能。RIL通常分为RILJ、RILC,RILJ即为java的RIL.java,code位于框架层,RILC才是真正的RIL层。Android的RIL驱动模块,在hardware/ril目录下,一共分rild,libril.so以及librefrence_ril.so三个部分。

Modem:位于BP,负责实际的无线通信能力处理

 实现各进程交互的aidl:

 拨号流程框架流程

 

  • packages/apps/Dialer/java/com/android/dialer/dialpadview/DialpadFragment.java

用户点击拨号盘的拨号按钮,此时开始呼叫长征第一步,dialpadfragment的onclick方法会响应点击事件。 

  1. @Override
  2. public void onClick(View view) {
  3. int resId = view.getId();
  4. if (resId == R.id.dialpad_floating_action_button) {
  5. view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
  6. handleDialButtonPressed();
  7. }

找到拨号界面对应的l ayout 界面布局文件dialer/dialpadview/res/layout/dialpad_fragment.xml ,其中就包含了打开拨号盘的浮动按钮,其定义如下 

 在该类中 运行:handleDialButtonPressed(); 方法,判断是否号码是否为空,是否非法等情况

 

10 之前没有这一步,直接调用 DialerUtils.startActivityWithErrorToast() 方法

携带Intent.ACTION_CALL的Intent Action会走到TelecomUtil placeCall流程,否则直接context.startActivity(intent);

  1. public static void startActivityWithErrorToast(
  2. final Context context, final Intent intent, int msgId) {
  3. try {
  4. if ((Intent.ACTION_CALL.equals(intent.getAction()))) {
  5. placeCallOrMakeToast(context, intent);
  6. } else {
  7. context.startActivity(intent);

startActivityWithErrorToast() 方法 调用下列方法

hasCallPhonePermission()会检查是否有呼叫权限,是否有Manifest.permission.CALL_PHONE)权限:

  1. private static void placeCallOrMakeToast(Context context, Intent intent) {
  2. final boolean hasCallPermission = TelecomUtil.placeCall(context, intent);
  3. if (!hasCallPermission) {
  4. Toast.makeText(context, "Cannot place call without Phone permission", Toast.LENGTH_SHORT)
  5. .show();
  6. }
  7. }
  1. public static boolean placeCall(Context context, Intent intent) {
  2. if (hasCallPhonePermission(context)) {
  3. getTelecomManager(context).placeCall(intent.getData(), intent.getExtras());
  4. return true;
  5. }
  6. return false;
  7. }

TelecomManager.placeCall主要获取TelecomService的Binder接口,跨进程进入到TelecomService(system进程)内部,至此 com.android.dialer 进程的工作暂时完成

  1. private static TelecomManager getTelecomManager(Context context) {
  2. return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
  3. }

Telecom Manager 获取ITelecomService 服务并调用其placeCall 方法继续传递intent 发出通话呼叫请求,将涉及第一次跨进程的服务调用。

  1. public void placeCall(Uri address, Bundle extras) {
  2. ITelecomService service = getTelecomService();
  3. if (service != null) {
  4. if (address == null) {
  5. Log.w(TAG, "Cannot place call to empty address.");
  6. }
  7. try {
  8. service.placeCall(address, extras == null ? new Bundle() : extras,
  9. mContext.getOpPackageName());
  10. } catch (RemoteException e) {
  11. Log.e(TAG, "Error calling ITelecomService#placeCall", e);
  12. }
  13. }
  14. }

其中,getTelecomService() 方法

  1. private ITelecomService getTelecomService() {
  2. if (mTelecomServiceOverride != null) {
  3. return mTelecomServiceOverride;
  4. }
  5. return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
  6. }

调用ITelecomService的placeCall方法,此处是aidl调用,对应的我们需要找到接收的地方,按照命名规则应该是TelecomServiceImpl:

创建UserCallIntentProcessorFactory,调用processIntent方法处理呼叫:

  1. private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
  2. @Override
  3. public void placeCall(Uri handle, Bundle extras, String callingPackage) {
  4. try {
  5. synchronized (mLock) {
  6. final UserHandle userHandle = Binder.getCallingUserHandle();
  7. long token = Binder.clearCallingIdentity();
  8. try {
  9. final Intent intent = new Intent(Intent.ACTION_CALL, handle);
  10. mUserCallIntentProcessorFactory.create(mContext, userHandle)
  11. .processIntent(
  12. intent, callingPackage, hasCallAppOp && hasCallPermission);
  13. }
  14. }
  15. }
  16. }
  17. }

processIntent判断是否是呼叫请求: 

  1. public void processIntent(Intent intent, String callingPackageName,
  2. boolean canCallNonEmergency, boolean isLocalInvocation) {
  3. // Ensure call intents are not processed on devices that are not capable of calling.
  4. if (!isVoiceCapable()) {
  5. return;
  6. }
  7. String action = intent.getAction();
  8. if (Intent.ACTION_CALL.equals(action) ||
  9. Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
  10. Intent.ACTION_CALL_EMERGENCY.equals(action)) {
  11. processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency,
  12. isLocalInvocation);
  13. }
  14. }
  • Intent.ACTION_CALL: 可以拨打普通呼叫
public static final String ACTION_CALL = "android.intent.action.CALL";
  • Intent.ACTION_CALL_PRIVILEGED:可以拨打任意类型号码
public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
  • Intent.ACTION_CALL_EMERGENCY:可以拨打紧急呼叫
public static final String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY";

processOutgoingCallIntent方法:

  1. private void processOutgoingCallIntent(Intent intent, String callingPackageName,
  2. boolean canCallNonEmergency, boolean isLocalInvocation) {
  3. ------
  4. ------
  5. int videoState = intent.getIntExtra(
  6. TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
  7. VideoProfile.STATE_AUDIO_ONLY);
  8. Log.d(this, "processOutgoingCallIntent videoState = " + videoState);
  9. intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
  10. isDefaultOrSystemDialer(callingPackageName));
  11. // Save the user handle of current user before forwarding the intent to primary user.
  12. intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);
  13. sendIntentToDestination(intent, isLocalInvocation, callingPackageName);
  14. }

sendIntentToDestination 方法:

  1. private boolean sendIntentToDestination(Intent intent, boolean isLocalInvocation,
  2. String callingPackage) {
  3. intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
  4. intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
  5. if (isLocalInvocation) {
  6. // We are invoking this from TelecomServiceImpl, so TelecomSystem is available. Don't
  7. // bother trampolining the intent, just sent it directly to the call intent processor.
  8. // TODO: We should not be using an intent here; this whole flows needs cleanup.
  9. Log.i(this, "sendIntentToDestination: send intent to Telecom directly.");
  10. synchronized (TelecomSystem.getInstance().getLock()) {
  11. TelecomSystem.getInstance().getCallIntentProcessor().processIntent(intent,
  12. callingPackage);
  13. }
  14. } else {
  15. // We're calling from the UserCallActivity, so the TelecomSystem is not in the same
  16. // process; we need to trampoline to TelecomSystem in the system server process.
  17. Log.i(this, "sendIntentToDestination: trampoline to Telecom.");
  18. TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
  19. tm.handleCallIntent(intent);
  20. }
  21. return true;
  22. }

安卓10 这里去除了以前的广播机制

调用getTelecomSystem方法返回TelecomSystem对象,调用getCallIntentProcessor()返回CallIntentProcessor对象,然后调用processIntent方法

  1. public void processIntent(Intent intent, String callingPackage) {
  2. final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);
  3. Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall);
  4. Trace.beginSection("processNewCallCallIntent");
  5. if (isUnknownCall) {
  6. processUnknownCallIntent(mCallsManager, intent);
  7. } else {
  8. processOutgoingCallIntent(mContext, mCallsManager, intent, callingPackage);
  9. }
  10. Trace.endSection();
  11. }

processOutgoingCallIntent方法,调用CallsManager的startOutgoingCall()方法创建Call,后new NewOutgoingCallIntentBroadcaster,调用processIntent()方法:

CallsManager 创建Call, 链接,监听Call状态

下面先分析  startOutgoingCall()方法, 

再分析 new NewOutgoingCallIntentBroadcaster,的processIntent()方法

  1. static void processOutgoingCallIntent(
  2. Context context,
  3. CallsManager callsManager,
  4. Intent intent,
  5. String callingPackage) {
  6. --------
  7. // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
  8. // 先执行此处代码,更新 ui 界面
  9. CompletableFuture<Call> callFuture = callsManager
  10. .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,
  11. intent, callingPackage);
  12. final Session logSubsession = Log.createSubsession();
  13. callFuture.thenAccept((call) -> {
  14. if (call != null) {
  15. Log.continueSession(logSubsession, "CIP.sNOCI");
  16. try {
  17. // 实际的,将上层信息下发到telephony, ril
  18. sendNewOutgoingCallIntent(context, call, callsManager, intent);
  19. } finally {
  20. Log.endSession();
  21. }
  22. }
  23. });
  24. }

其中的 sendNewOutgoingCallIntent 方法如下定义:‘

  1. static void sendNewOutgoingCallIntent(Context context, Call call, CallsManager callsManager,
  2. Intent intent) {
  3. // Asynchronous calls should not usually be made inside a BroadcastReceiver because once
  4. // onReceive is complete, the BroadcastReceiver's process runs the risk of getting
  5. // killed if memory is scarce. However, this is OK here because the entire Telecom
  6. // process will be running throughout the duration of the phone call and should never
  7. // be killed.
  8. final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);
  9. NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
  10. context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
  11. isPrivilegedDialer);
  12. // If the broadcaster comes back with an immediate error, disconnect and show a dialog.
  13. NewOutgoingCallIntentBroadcaster.CallDisposition disposition = broadcaster.evaluateCall();
  14. if (disposition.disconnectCause != DisconnectCause.NOT_DISCONNECTED) {
  15. disconnectCallAndShowErrorDialog(context, call, disposition.disconnectCause);
  16. return;
  17. }
  18. broadcaster.processCall(disposition);
  19. }
  1. public void processCall(CallDisposition disposition) {
  2. if (disposition.callImmediately) {
  3. boolean speakerphoneOn = mIntent.getBooleanExtra(
  4. TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
  5. int videoState = mIntent.getIntExtra(
  6. TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
  7. VideoProfile.STATE_AUDIO_ONLY);
  8. placeOutgoingCallImmediately(mCall, disposition.callingAddress, null,
  9. speakerphoneOn, videoState);
  10. // Don't return but instead continue and send the ACTION_NEW_OUTGOING_CALL broadcast
  11. // so that third parties can still inspect (but not intercept) the outgoing call. When
  12. // the broadcast finally reaches the OutgoingCallBroadcastReceiver, we'll know not to
  13. // initiate the call again because of the presence of the EXTRA_ALREADY_CALLED extra.
  14. }

其中 placeOutgoingCallImmediately 代码:

  1. private void placeOutgoingCallImmediately(Call call, Uri handle, GatewayInfo gatewayInfo,
  2. boolean speakerphoneOn, int videoState) {
  3. Log.i(this,
  4. "Placing call immediately instead of waiting for OutgoingCallBroadcastReceiver");
  5. // Since we are not going to go through "Outgoing call broadcast", make sure
  6. // we mark it as ready.
  7. mCall.setNewOutgoingCallIntentBroadcastIsDone();
  8. mCallsManager.placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, videoState);
  9. }

 

先执行了 startOutgoingCall 方法 ,然后再 执行 broadcaster. processCall () 方法 

备注:

这里先设置一个分支,先分析 callsManager.startOutgoingCall 方法

CallsManager 的拨号处理流程

CallsManager.statOutgoingCall 的主要逻辑是创建、更新和保存Call 对象

startOutgoingCall 新建一个(或者重用) call, 将CallsManager绑定监听该 call, 然后通知 callsManager 的监听者, 添加了一个 call

  1. Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras) {
  2. Call call = getNewOutgoingCall(handle);
  3. // 如果是MMI 号码
  4. if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) {
  5. // 让CallsManager监听call的行为
  6. call.addListener(this);
  7. } else if (!mCalls.contains(call)) {
  8. // 确保Call不会重复添加(getNewOutgoingCall有重用机制)
  9. // 添加call, 然后callsManager通知监听者,添加了一个call
  10. addCall(call);
  11. }
  12. return call;
  13. }

addCall 方法:addCall 添加call, 然后callsManager通知监听者,添加了一个call

CallsManager对象将保存多个Call 对象到mCalls 集合中, Call 对象则设置Listener 对象为
CallsManager , 对象之间相互引用。而CallsManager 对象通过 mlisteners  发出onCallAdded 消息
回调。那么mlisteners 究竟是什么呢?摘录出Calls

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/988298?site
推荐阅读
相关标签
  

闽ICP备14008679号