Android7.0去电流程源码分析(二)
来源:互联网 发布:淘宝卖家论坛首页 编辑:程序博客网 时间:2024/05/22 13:23
上篇博客分析到调用broadcastIntent,这里接着分析
1.接着查看NewOutgoingCallIntentBroadcaster.java文件中的broadcastIntent方法:
private void broadcastIntent( Intent originalCallIntent, String number, boolean receiverRequired, UserHandle targetUser) { //要发送的广播 Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL); if (number != null) { broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number); } // Force receivers of this broadcast intent to run at foreground priority because we // want to finish processing the broadcast intent as soon as possible. broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); Log.v(this, "Broadcasting intent: %s.", broadcastIntent); Log.p(TAG, "broadcastIntent(): EXTRA_PHONE_NUMBER " + number); checkAndCopyProviderExtras(originalCallIntent, broadcastIntent); mContext.sendOrderedBroadcastAsUser( broadcastIntent, targetUser, android.Manifest.permission.PROCESS_OUTGOING_CALLS, AppOpsManager.OP_PROCESS_OUTGOING_CALLS, receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null, null, // scheduler Activity.RESULT_OK, // initialCode number, // initialData: initial value for the result data (number to be modified) null); // initialExtras }
2.这里看到发送一个Intent.ACTION_NEW_OUTGOING_CALL广播,对于非紧急拨号,才会生成一个
NewOutgoingCallBroadcastIntentReceive 实例来接收该广播,我们跟进onReceive方法
public class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { try { ... GatewayInfo gatewayInfo = getGateWayInfoFromIntent(intent, resultHandleUri); mCall.setNewOutgoingCallIntentBroadcastIsDone(); 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)); } } } }
3.NewOutgoingCallBroadcastIntentReceiver内部做了一些处理后最后还是调用到CallsManager的placeOutgoingCall方法,所以该方法是去电的关键方法继续看callManager.placeOutgoingCall方法
public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo, boolean speakerphoneOn, int videoState) { ... call.setHandle(uriHandle); call.setGatewayInfo(gatewayInfo); final boolean useSpeakerWhenDocked = mContext.getResources().getBoolean( R.bool.use_speaker_when_docked); final boolean useSpeakerForDock = isSpeakerphoneEnabledForDock(); final boolean useSpeakerForVideoCall = isSpeakerphoneAutoEnabledForVideoCalls(videoState); // Auto-enable speakerphone if the originating intent specified to do so, if the call // is a video call, of if using speaker when docked call.setStartWithSpeakerphoneOn(speakerphoneOn || useSpeakerForVideoCall || (useSpeakerWhenDocked && useSpeakerForDock)); call.setVideoState(videoState); if (call.isEmergencyCall()) { new AsyncEmergencyContactNotifier(mContext).execute(); } final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean( com.android.internal.R.bool.config_requireCallCapableAccountForHandle); if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) { if (!call.isEmergencyCall()) { updateLchStatus(call.getTargetPhoneAccount().getId()); } //Block to initiate Emregency call now as the current active call //is not yet disconnected. if (mPendingMOEmerCall == null) { // 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. // +++ Delay 1500 ms to speed up launch inCallUI int time = android.os.SystemProperties.getInt("persist.asus.tellril", 0); Log.d(TAG, "placeOutgoingCall(): persist.asus.tellril time = " + time); if (time == 0 ||call.isEmergencyCall()) { Log.d(TAG, "placeOutgoingCall(): no delay to startCreateConnection"); //创建连接 call.startCreateConnection(mPhoneAccountRegistrar); } else { new android.os.CountDownTimer(time, time) { @Override public void onTick(long millisUntilFinished) { } @Override public void onFinish() { Log.d(TAG, "placeOutgoingCall(): delay time to startCreateConnection"); call.startCreateConnection(mPhoneAccountRegistrar); } }.start(); } } // --- Delay 1500 ms to speed up launch inCallUI } else if (mPhoneAccountRegistrar.getCallCapablePhoneAccounts( requireCallCapableAccountByHandle ? call.getHandle().getScheme() : null, false, call.getInitiatingUser()).isEmpty()) { // If there are no call capable accounts, disconnect the call. markCallAsDisconnected(call, new DisconnectCause(DisconnectCause.CANCELED, "No registered PhoneAccounts")); markCallAsRemoved(call); } }
4.如果是Video Call或者是紧急呼叫的话会做一些额外操作,如果条件满足的话会调用到startCreateConnection建立连接
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) { Log.d(TAG, "startCreateConnection(): phoneAccountRegistrar " + phoneAccountRegistrar); if (mCreateConnectionProcessor != null) { Log.w(this, "mCreateConnectionProcessor in startCreateConnection is not null. This is" + " due to a race between NewOutgoingCallIntentBroadcaster and " + "phoneAccountSelected, but is harmlessly resolved by ignoring the second " + "invocation."); return; } mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this, phoneAccountRegistrar, mContext); mCreateConnectionProcessor.process(); }
5.新建了一个CreateConnectionProcessor对象,处理连接请求
@VisibleForTesting public void process() { Log.v(this, "process"); clearTimeout(); mAttemptRecords = new ArrayList<>(); if (mCall.getTargetPhoneAccount() != null) { Log.d(this, "process mCall.getTargetPhoneAccount() = " + mCall.getTargetPhoneAccount()); mAttemptRecords.add(new CallAttemptRecord( mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount())); } else { Log.d(this, "process mCall.getTargetPhoneAccount() is null"); } adjustAttemptsForConnectionManager(); adjustAttemptsForEmergency(mCall.getTargetPhoneAccount()); mAttemptRecordIterator = mAttemptRecords.iterator(); attemptNextPhoneAccount(); }
6.进入attemptNextPhoneAccount方法
private void attemptNextPhoneAccount() { Log.v(this, "attemptNextPhoneAccount"); CallAttemptRecord attempt = null; if (mAttemptRecordIterator.hasNext()) { attempt = mAttemptRecordIterator.next(); if (!mPhoneAccountRegistrar.phoneAccountRequiresBindPermission( attempt.connectionManagerPhoneAccount)) { Log.w(this, "Connection mgr does not have BIND_TELECOM_CONNECTION_SERVICE for " + "attempt: %s", attempt); attemptNextPhoneAccount(); return; } // If the target PhoneAccount differs from the ConnectionManager phone acount, ensure it // also requires the BIND_TELECOM_CONNECTION_SERVICE permission. if (!attempt.connectionManagerPhoneAccount.equals(attempt.targetPhoneAccount) && !mPhoneAccountRegistrar.phoneAccountRequiresBindPermission( attempt.targetPhoneAccount)) { Log.w(this, "Target PhoneAccount does not have BIND_TELECOM_CONNECTION_SERVICE for " + "attempt: %s", attempt); attemptNextPhoneAccount(); return; } } if (mCallResponse != null && attempt != null) { Log.i(this, "Trying attempt %s", attempt); PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount; // 获取ConnectionServiceWrapper对象 mService = mRepository.getService(phoneAccount.getComponentName(), phoneAccount.getUserHandle()); if (mService == null) { Log.i(this, "Found no connection service for attempt %s", attempt); attemptNextPhoneAccount(); } else { mConnectionAttempt++; mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount); mCall.setTargetPhoneAccount(attempt.targetPhoneAccount); mCall.setConnectionService(mService); setTimeoutIfNeeded(mService, attempt); // 已成功获取ConnectionServiceWrapper对象,创建连接 mService.createConnection(mCall, this); } } else { Log.v(this, "attemptNextPhoneAccount, no more accounts, failing"); DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ? mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR); notifyCallConnectionFailure(disconnectCause); } }
这里主要的两步操作是获取ConnectionServiceWrapper对象,并调用createConnection方法创建连接。那么我们继续跟进 ConnectionServiceWrapper。
/** * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps * track of when the object can safely be unbound. Other classes should not use * {@link IConnectionService} directly and instead should use this class to invoke methods of * {@link IConnectionService}. */@VisibleForTestingpublic class ConnectionServiceWrapper extends ServiceBinder {实际上就是一个包装了绑定远程服务的代理类,看看它的构造方法 ConnectionServiceWrapper( ComponentName componentName, ConnectionServiceRepository connectionServiceRepository, PhoneAccountRegistrar phoneAccountRegistrar, CallsManager callsManager, Context context, TelecomSystem.SyncRoot lock, UserHandle userHandle) { super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle); mConnectionServiceRepository = connectionServiceRepository; phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() { // TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections // To do this, we must proxy remote ConnectionService objects }); mPhoneAccountRegistrar = phoneAccountRegistrar; mCallsManager = callsManager; mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); }
这里的ConnectionService.SERVICE_INTERFACE就是”android.telecom.ConnectionService”也就是它所绑定的远程服务的action,获取该对象后调用createConnection方法
7.继续跟进createConnection方法
/** * Creates a new connection for a new outgoing call or to attach to an existing incoming call. */ @VisibleForTesting public void createConnection(final Call call, final CreateConnectionResponse response) { Log.d(this, "createConnection(%s) via %s.", call, getComponentName()); BindCallback callback = new BindCallback() { @Override public void onSuccess() {//最终创建成功后会回到这里的回调方法 String callId = mCallIdMapper.getCallId(call); 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 { mServiceInterface.createConnection( call.getConnectionManagerPhoneAccount(), callId, new ConnectionRequest( call.getTargetPhoneAccount(), call.getHandle(), extras, call.getVideoState(), callId), call.shouldAttachToExistingConnection(), call.isUnknown()); } catch (RemoteException e) { Log.e(this, e, "Failure to createConnection -- %s", getComponentName()); mPendingResponses.remove(callId).handleCreateConnectionFailure( new DisconnectCause(DisconnectCause.ERROR, e.toString())); } } @Override public void onFailure() { Log.e(this, new Exception(), "Failure to call %s", getComponentName()); response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR)); } }; //将callback和call传入 mBinder.bind(callback, call); }
8.我们看到其创建了BindCallback ,然后使用mBinder调用bind方法。这里的mBinder对象是ConnectionServiceWrapper的父类ServiceBinder里的一个内部类,继续查看其bind调用。
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服务 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) { 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(); } }
9.这里我们看到主要是创建一个服务,然后调用mContext.bindService进行绑定服务,
10.跟进ServiceBinderConnection继续分析onServiceConnected。
private final class ServiceBinderConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName componentName, IBinder binder) { try { Log.startSession("SBC.oSC"); 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; // setBinder(binder); handleSuccessfulConnection(); } } finally { Log.endSession(); } }
11.看到设置了binder,设置成功后调用handleSucessfulCOnnection方法,继续根据setBinder看看。
private void setBinder(IBinder binder) { if (mBinder != binder) { if (binder == null) { removeServiceInterface(); mBinder = null; for (Listener l : mListeners) { l.onUnbind(this); } } else { mBinder = binder; setServiceInterface(binder); } } }
12.这里我们看到setServiceInterface只是个接口,回到其子类ConnectionServiceWrapper.java中查看具体实现
/** {@inheritDoc} */ @Override protected void setServiceInterface(IBinder binder) { Log.d(TAG, "setServiceInterface(): binder " + binder); mServiceInterface = IConnectionService.Stub.asInterface(binder); Log.v(this, "Adding Connection Service Adapter."); addConnectionServiceAdapter(mAdapter); }
13.看到其获取远程IConnectionService服务的aidl接口,然后我们继续回到10跟踪handleSuccessfulConnection方法
private void handleSuccessfulConnection() { for (BindCallback callback : mCallbacks) { callback.onSuccess(); } mCallbacks.clear(); }
14.我们看到其调用了callback.onSuccess(),而这个callback其实是我们之前传参带入后进行初始化的,就回到7的onSucess方法中继续调用。
总结7-14的分析, mBinder.bind(callback, call)该方法调用时会创建一个连接,封装了绑定远程服务的一些操作,若当前还未绑定服务,则直接调用bindService获取远程服务的aidl接口,成功获取到aidl接口后将其赋值给mServiceInterface,当绑定完成后会调用handleSuccessFulConnection方法,其回调了CallBack的onSuccess方法。至此就完成了服务的创建及连接
接下来的流程就到了远程服务的createConnection实现了。
根据以上源码分析的流程整理的时序图如下,如果不清楚可以另存为到本地查看。
结合上一章的分析的第五步进入telecomManager到这章的末尾分析来看
其实在telecomManager中获取(ITelecomService.aidl)TelecomService后一路调用,期间有进行一些过滤等操作,最终其实主要做的就是是通过AIDL的调用去获取底层的服务以创建一个连接通道。
- Android7.0去电流程源码分析(二)
- Android7.0去电流程源码分析(一)
- 去电流程分析---之二
- android -- phone (二) 去电流程
- android -- phone (二) 去电流程
- android -- phone (二) 去电流程
- 去电流程分析---之一
- Android7.0关机流程分析
- Android7.0 startService流程分析
- Android7.0关机流程分析
- android7.0拨号流程分析
- Android6.0去电流程
- Android7.0 编译系统流程分析
- [Android7.0]开启NFC的流程分析
- Android7.0 编译系统流程分析
- Android7.0 编译系统流程分析
- [Android7.0]NFC初始化的流程分析
- Android7.0 init.rc流程分析
- 学Python(6)—日期计算案例
- latex 页眉插入图片logo
- 项目经理面试中可能遇到的问题(持续更新)
- 本地代码上传到Github
- 数据结构--静态单链表
- Android7.0去电流程源码分析(二)
- 面试前需考虑的25个问题
- 配置静态元素的过期时间
- 深入理解 Java 反射:Method (成员方法)
- Java注解之Retention、Documented、Target介绍
- Retrofit框架流程图
- AAA关于MySQL的事务处理及隔离级别
- 全字母句哪里错了
- Android RecyclerView的简便写法