Android7.0去电流程源码分析(三)

2019-04-13 12:57发布

上篇博客分析到调用ServiceConnection,这里接着分析
1.ServiceConnection.java类中实现了该远程服务
private final IBinder mBinder = new IConnectionService.Stub() 并重写了其接口,这里我们主要关注 @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; //2.发送消息 mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget(); } 3.这里我们主要追踪其createConnection方法其发送了CREATE_CONNECTION消息,追踪消息处理的地方 private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { ... case MSG_CREATE_CONNECTION: { SomeArgs args = (SomeArgs) msg.obj; try { final PhoneAccountHandle connectionManagerPhoneAccount = (PhoneAccountHandle) args.arg1; final String id = (String) args.arg2; final ConnectionRequest request = (ConnectionRequest) args.arg3; final boolean isIncoming = args.argi1 == 1; final boolean isUnknown = args.argi2 == 1; if (!mAreAccountsInitialized) { Log.d(this, "Enqueueing pre-init request %s", id); mPreInitializationConnectionRequests.add(new Runnable() { @Override public void run() { createConnection( connectionManagerPhoneAccount, id, request, isIncoming, isUnknown); } }); } else { createConnection( connectionManagerPhoneAccount, id, request, isIncoming, isUnknown); } } finally { args.recycle(); } break; } 4.使用异步的方式创建了连接,继续分析createConnection /** * This can be used by telecom to either create a new outgoing call or attach to an existing * incoming call. In either case, telecom will cycle through a set of services and call * createConnection util a connection service cancels the process or completes it successfully. */ 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); //根据具体类型进行创建-》onCreateIncomingConnection 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)); } connection.setTelecomCallId(callId); if (connection.getState() != Connection.STATE_DISCONNECTED) { addConnection(callId, connection);//创建成功添加到队列中 } Uri address = connection.getAddress(); String number = address == null ? "null" : address.getSchemeSpecificPart(); mAdapter.handleCreateConnectionComplete( callId, request, new ParcelableConnection( request.getAccountHandle(), connection.getState(), connection.getConnectionCapabilities(), connection.getConnectionProperties(), connection.getAddress(), connection.getAddressPresentation(), connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation(), connection.getVideoProvider() == null ? null : connection.getVideoProvider().getInterface(), connection.getVideoState(), connection.isRingbackRequested(), connection.getAudioModeIsVoip(), connection.getConnectTimeMillis(), connection.getStatusHints(), connection.getDisconnectCause(), createIdList(connection.getConferenceables()), connection.getExtras())); if (isUnknown) { triggerConferenceRecalculate(); } } 5.可以看到其根据connection类型创建对于的coneection,去电走的是onCreateOutgoingConneciton创建,跟进该方法,发现其返回的值为空,应该是其子类进行重载了该方法,跟踪TelephonyConnectionService方法 @Override public Connection onCreateOutgoingConnection( PhoneAccountHandle connectionManagerPhoneAccount, final ConnectionRequest request) { Log.i(this, "onCreateOutgoingConnection, request: " + request); ... //判断网络状态,手机号码是否正确,是否是紧急呼叫等,获取phone对象 ... // Get the right phone object from the account data passed in. final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber); Connection resultConnection = getTelephonyConnection(request, numberToDial, isEmergencyNumber, handle, phone); // If there was a failure, the resulting connection will not be a TelephonyConnection, // so don't place the call! if(resultConnection instanceof TelephonyConnection) { placeOutgoingConnection((TelephonyConnection) resultConnection, phone, request); } return resultConnection; } } 这里主要跟进getTelephonyConnection和placeOutgoingConnection
7.那先来看下getTelephonyConnection private Connection getTelephonyConnection(final ConnectionRequest request, final String number, boolean isEmergencyNumber, final Uri handle, Phone phone) { ... //创建失败的一些情况,如phone为空,check 当前网络的状态sim卡设置pin等,紧急状态下拨打非紧急号码等, ... final TelephonyConnection connection = createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle(), request.getTelecomCallId(), request.getAddress(), request.getVideoState()); if (connection == null) { Log.d(this, "onCreateOutgoingConnection connection == null"); return Connection.createFailedConnection( DisconnectCauseUtil.toTelecomDisconnectCause( android.telephony.DisconnectCause.OUTGOING_FAILURE, "Invalid phone type")); } connection.setAddress(handle, PhoneConstants.PRESENTATION_ALLOWED); connection.setInitializing(); connection.setVideoState(request.getVideoState()); Log.d(this, "onCreateOutgoingConnection final"); return connection; } 可以看到这里其实是通过createConnectionFor来创建,继续进一步进行跟进 private TelephonyConnection createConnectionFor( Phone phone, com.android.internal.telephony.Connection originalConnection, boolean isOutgoing, PhoneAccountHandle phoneAccountHandle, String telecomCallId, Uri address, int videoState) { TelephonyConnection returnConnection = null; int phoneType = phone.getPhoneType(); //根据对于的pnone类型进行创建连接,并添加监听 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { returnConnection = new GsmConnection(originalConnection, telecomCallId); } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { boolean allowsMute = allowsMute(phone); returnConnection = new CdmaConnection(originalConnection, mEmergencyTonePlayer, allowsMute, isOutgoing, telecomCallId); } if (returnConnection != null) { // Listen to Telephony specific callbacks from the connection returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener); returnConnection.setVideoPauseSupported( TelecomAccountRegistry.getInstance(this).isVideoPauseSupported( phoneAccountHandle)); } return returnConnection; } 8.通过getTelephonyConnection方法根据对于的pnone类型进行创建连接,并添加监听,获取到connection对象。继续分析onCreateOutgoingConnection中的placeOutgoingConnection方法。 private void placeOutgoingConnection( TelephonyConnection connection, Phone phone, int videoState, Bundle extras, ConnectionRequest request) { ... com.android.internal.telephony.Connection originalConnection = null; try { if (phone != null) { if (isAddParticipant) { ... } else { ... //调用phone.dial进行呼叫 originalConnection = phone.dial(number, null, request.getVideoState(), bundle); Log.d(this, "placeOutgoingConnection phone.dial -- originalConnection = " + originalConnection); 9.可以看到其实是通过调用phone.dail进行呼叫,而phone是具有ril通信能力的,其会调用RIL的dial方法进行处理。具体的可以另外见phone讲解。
这里我们继续分析,android N中cdma和gsm统一由GsmCdmaPhone对象进行处理,我们跟进到此类中的dial方法。 @Override public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras) throws CallStateException { ... //IMS通话 if ((imsUseEnabled && (!isUt || useImsForUt)) || useImsForEmergency || useImsPrefer) { try { if (DBG) logd("Trying IMS PS call"); return imsPhone.dial(dialString, uusInfo, videoState, intentExtras); } catch (CallStateException e) { if (DBG) logd("IMS PS call exception " + e + "imsUseEnabled =" + imsUseEnabled + ", imsPhone =" + imsPhone); if (!Phone.CS_FALLBACK.equals(e.getMessage())) { CallStateException ce = new CallStateException(e.getMessage()); ce.setStackTrace(e.getStackTrace()); throw ce; } } } 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 (DBG) logd("Trying (non-IMS) CS call"); //CS通话 if (isPhoneTypeGsm()) { return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras); } else { return dialInternal(dialString, null, videoState, intentExtras); } } 10.这里我们以GSM为例可以看到CS通话最终根据phone的类型调用不同的dialInternal方法进行呼叫. protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras) throws CallStateException { // Need to make sure dialString gets parsed properly String newDialString = PhoneNumberUtils.stripSeparators(dialString); if (isPhoneTypeGsm()) { // 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); //mmi的作用? GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get()); if (DBG) logd("dialing w/ mmi '" + mmi + "'..."); if (mmi == null) { return mCT.dial(newDialString, uusInfo, intentExtras); } else if (mmi.isTemporaryModeCLIR()) { return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras); } else { mPendingMMIs.add(mmi); mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); try { mmi.processCode(); } catch (CallStateException e) { //do nothing } // FIXME should this return null or something else? return null; } } else { return mCT.dial(newDialString); } } 11.可以看到其主要通过mCT.dial方法调用进行呼叫,那么这里的mmi和mCT又是什么呢?mmi对号码进行格式化去掉无用数据,在此没有继续深入,有兴趣的朋友可以自行深入。 public GsmCdmaCallTracker mCT; 可以看到其实是通过GsmCdmaCallTracker进行呼叫,这里我们以GSM为例进行进一步分析 //GSM /** * clirMode is one of the CLIR_ constants */ public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo, Bundle intentExtras) throws CallStateException { // note that this triggers call state changed notif clearDisconnected(); 更新一些call的状态 ... if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0 || mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) { // Phone number is invalid mPendingMO.mCause = DisconnectCause.INVALID_NUMBER; // handlePollCalls() will notice this call not present // and will mark it as dropped. pollCallsWhenSafe(); } else { // Always unmute when initiating a new call setMute(false); //关键地方,其实是调用mCi.dial的方法进行呼叫,携带了EVENT_OPERATION_COMPLETE mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage()); } if (mNumberConverted) { mPendingMO.setConverted(origNumber); mNumberConverted = false; } //更新PHONE的状态 updatePhoneState(); mPhone.notifyPreciseCallStateChanged();//发起phone状态更改通知 return mPendingMO;//返回通话连接 } 可以看到其实是调用mCi的方法进行通信且调用了obtainCompleteMessage方法
先看下obtain方法的调用,用来唤醒getCurrentCalls() private Message obtainCompleteMessage() { // return obtainCompleteMessage(EVENT_OPERATION_COMPLETE); } /** * Obtain a message to use for signalling "invoke getCurrentCalls() when * this operation and all other pending operations are complete */ private Message obtainCompleteMessage(int what) { mPendingOperations++; mLastRelevantPoll = null; mNeedsPoll = true; if (DBG_POLL) log("obtainCompleteMessage: pendingOperations=" + mPendingOperations + ", needsPoll=" + mNeedsPoll); return obtainMessage(what); } //消息EVENT_OPERATION_COMPLETE处理时调用operationComplete private void operationComplete() { mPendingOperations--; if (DBG_POLL) log("operationComplete: pendingOperations=" + mPendingOperations + ", needsPoll=" + mNeedsPoll); if (mPendingOperations == 0 && mNeedsPoll) { mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); //查询当前call情况 mCi.getCurrentCalls(mLastRelevantPoll); } else if (mPendingOperations < 0) { // this should never happen Rlog.e(LOG_TAG,"GsmCdmaCallTracker.pendingOperations < 0"); mPendingOperations = 0; } } 继续分析mCi.dail public CommandsInterface mCi; 看下其初始化情况 public GsmCdmaCallTracker (GsmCdmaPhone phone) { this.mPhone = phone; mCi = phone.mCi; ... } 继续追踪GsmCdmaPhone的初始化–>需要查看phone的初始化,可以看到在PhoneFactory中makeDefaultPhone的初始化 public static void makeDefaultPhone(Context context) { ... //RIL sCommandsInterfaces = new RIL[numPhones]; sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones]; for (int i = 0; i < numPhones; i++) { // reads the system properties and makes commandsinterface // Get preferred network type. networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE; Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i])); sCommandsInterfaces[i] = new RIL(context, networkModes[i], cdmaSubscription, i); } Rlog.i(LOG_TAG, "Creating SubscriptionController"); telephonyComponentFactory.initSubscriptionController( context, sCommandsInterfaces); // Instantiate UiccController so that all other classes can just // call getInstance() sUiccController = UiccController.make(context, sCommandsInterfaces); for (int i = 0; i < numPhones; i++) { Phone phone = null; int phoneType = TelephonyManager.getPhoneType(networkModes[i]); //根据具体的PHONE类型初始化,其中mCi就是RIL if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { phone = telephonyComponentFactory.makePhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_GSM, telephonyComponentFactory); } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { phone = telephonyComponentFactory.makePhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_CDMA_LTE, telephonyComponentFactory); } Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i); sPhones[i] = phone; } ... 12.可以看到PHONE的创建是根据具体的PHONE类型初始化,其中mCi就是RIL,那么继续看看RIL的dail方法 @Override public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) { //注意此封装的消息类型 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)); mMetrics.writeRilDial(mInstanceId, rr.mSerial, clirMode, uusInfo); //发送消息给底层了,具体可以参见RILJ消息处理机制 send(rr); } private void send(RILRequest rr) { Message msg; if (mSocket == null) { rr.onError(RADIO_NOT_AVAILABLE, null); rr.release(); return; } //继续追踪 handleMessage msg = mSender.obtainMessage(EVENT_SEND, rr); acquireWakeLock(rr, FOR_WAKELOCK); msg.sendToTarget(); } class RILSender extends Handler implements Runnable { handleMessage(Message msg) { RILRequest rr = (RILRequest)(msg.obj); RILRequest req = null; switch (msg.what) { case EVENT_SEND: case EVENT_SEND_ACK: LocalSocket s; s = mSocket; ... s.getOutputStream().write(dataLength); s.getOutputStream().write(data); ... break; ... } ... ... } 到这里就通过Socket通信下发到底层去了,不过目前在android8.0上已经重写RILJ架构改用一个service进行通信。
以上源码分析流程的时序图如下
这里写图片描述