天天看点

Android 8.0来电流程分析(二)

Telephony-Service

1.上篇分析到PstnIncommingCallNotifier 中handleMessage处理来电消息,继续跟进分析

switch (msg.what) {
                case EVENT_NEW_RINGING_CONNECTION:
                    handleNewRingingConnection((AsyncResult) msg.obj);
           

2.继续跟进handleNewRingingConnection

/**
     * Verifies the incoming call and triggers sending the incoming-call intent to Telecom.
     *
     * @param asyncResult The result object from the new ringing event.
     */
    private void handleNewRingingConnection(AsyncResult asyncResult) {
        Log.d(this, "handleNewRingingConnection");
        Connection connection = (Connection) asyncResult.result;
        if (connection != null) {
            Call call = connection.getCall();

            // Final verification of the ringing state before sending the intent to Telecom.
            if (call != null && call.getState().isRinging()) {
                if (ExtensionManager.getDigitsUtilExt().isConnectionMatched(connection,
                        mPhoneAccountHandle, mPhone.getContext()) == false) {
                    return;
                }
                sendIncomingCallIntent(connection);
            }
        }
    }
           

3.继续跟进sendIncomingCallIntent

/**
     * Sends the incoming call intent to telecom.
     */
    private void sendIncomingCallIntent(Connection connection) {
        Bundle extras = new Bundle();
        //extras填充一些数据
        ...

        PhoneAccountHandle handle = findCorrectPhoneAccountHandle();
        if (handle == null) {
          //挂断
        } else {
            TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);
        }
    }
    //获取telecomm服务
    public static TelecomManager from(Context context) {
        return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
    }
           

通过aidl接口调用 telecomService 的addNewIncomingCall方法

TelecomService层

4.跟进到TelecomServiceImpl成员变量mBinderImpl的具体实现类

/**
 * Implementation of the ITelecom interface.
 */
public class TelecomServiceImpl
    private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
        /**
         * @see android.telecom.TelecomManager#addNewIncomingCall
         */
        @Override
        public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
                    ...
                            Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
                            intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
                                    phoneAccountHandle);
                            intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true);
                            if (extras != null) {
                                extras.setDefusable(true);
                                intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
                            }
                            mCallIntentProcessorAdapter.processIncomingCallIntent(
                                    mCallsManager, intent);

                    ...
           

5.继续跟进mCallIntentProcessorAdapter.processIncomingCallIntent,

static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
        ...
        Log.d(CallIntentProcessor.class,
                "Processing incoming call from connection service [%s]",
                phoneAccountHandle.getComponentName());
        callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
    }
    ...
           

6.进入到CallsManager中继续跟进

void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
        Log.d(this, "processIncomingCallIntent");
        ...
        Call call = new Call(
                getNextCallId(),
                mContext,
                this,
                mLock,
                mConnectionServiceRepository,
                mContactsAsyncHelper,
                mCallerInfoAsyncQueryFactory,
                mPhoneNumberUtilsAdapter,
                handle,
                null /* gatewayInfo */,
                null /* connectionManagerPhoneAccount */,
                phoneAccountHandle,
                Call.CALL_DIRECTION_INCOMING /* callDirection */,
                false /* forceAttachToExistingConnection */,
                false, /* isConference */
                mClockProxy);

        ...
        call的一些状态设置
        ...
        call.initAnalytics();
        if (getForegroundCall() != null) {
            getForegroundCall().getAnalytics().setCallIsInterrupted(true);
            call.getAnalytics().setCallIsAdditional(true);
        }
        setIntentExtrasAndStartTime(call, extras);
        //添加监听
        // TODO: Move this to be a part of addCall()
        call.addListener(this);

        if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call,
                call.getTargetPhoneAccount()))) {
            notifyCreateConnectionFailed(phoneAccountHandle, call);
        } else {
            //成功上报上去建立连接
            call.startCreateConnection(mPhoneAccountRegistrar);
        }
    }
           

这里和之前MO的流程是一样的,创建了一个Call然后调用startCreateConnection去创建connection,有需要的可以看下去电流程二的后半部分

TelecomFramework

7.跟进到IConnectionService中Binder的实现中去

/** @hide */
    protected IBinder mBinder = new IConnectionService.Stub() {
        @Override
        public void createConnection(
                ...
                mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
            ...
           

8.找到handler事件处理的地方

case MSG_CREATE_CONNECTION: {
                        ...
                        if (!mAreAccountsInitialized) {
                            Log.d(this, "Enqueueing pre-init request %s", id);
                            mPreInitializationConnectionRequests.add(
                                    new android.telecom.Logging.Runnable(
                                            SESSION_HANDLER + SESSION_CREATE_CONN + ".pICR",
                                            null /*lock*/) {
                                @Override
                                public void loggedRun() {
                                    createConnection(
                                            connectionManagerPhoneAccount,
                                            id,
                                            request,
                                            isIncoming,
                                            isUnknown);
                                }
                            }.prepare());
                        } else {
                            createConnection(
                                    connectionManagerPhoneAccount,
                                    id,
                                    request,
                                    isIncoming,
                                    isUnknown);
                        }
                    } 
                    ...
           

9.可以看到无论如何都会调用createConnection,点击跟进到ConnectionService中的此方法

/**
     * 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.
     */
    /** {@hide} */
    protected 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);

        //判断是来电还是去电创造不同的connection
        Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
                : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
                : onCreateOutgoingConnection(callManagerAccount, request);
        ...

        Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId);
        //创建成功后调用
        mAdapter.handleCreateConnectionComplete(
                callId,
                request,
                new ParcelableConnection(
                ...

        if (isIncoming && request.shouldShowIncomingCallUi() &&
                (connection.getConnectionProperties() & Connection.PROPERTY_SELF_MANAGED) ==
                        Connection.PROPERTY_SELF_MANAGED) {
            // Tell ConnectionService to show its incoming call UX.
            connection.onShowIncomingCallUi();
        }
        if (isUnknown) {
            triggerConferenceRecalculate();
        }
    }
           

9.1当判断是来电时会通过 onCreateIncomingConnection 创建连接,直接跟进去发现是空实现,那么该方法的实现应该在该类的子类中,跟进到其子类TelephonyConnectionService中

/**
 * Service for making GSM and CDMA connections.
 */
public class TelephonyConnectionService extends ConnectionService 

    @Override
    public Connection onCreateIncomingConnection(
            PhoneAccountHandle connectionManagerPhoneAccount,
            ConnectionRequest request) {
        ...
        Phone phone = getPhoneForAccount(accountHandle, isEmergency);
        ...
        Call call = phone.getRingingCall();

        com.android.internal.telephony.Connection originalConnection =
                call.getState() == Call.State.WAITING ?
                    call.getLatestConnection() : call.getEarliestConnection();
        ...
        Connection connection =
                createConnectionFor(phone, originalConnection, false /* isOutgoing */,
                        request.getAccountHandle(), request.getTelecomCallId(),
                        request.getAddress(), videoState);

        ...
    }
           

9.2 可以看到其是通过createConnectionFor创建

//返回需要的connection
    protected 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();
        boolean allowsMute = allowsMute(phone);
        returnConnection = new MtkGsmCdmaConnection(phoneType, originalConnection, telecomCallId,
                mEmergencyTonePlayer, allowsMute, isOutgoing);

        if (returnConnection != null) {
            // Listen to Telephony specific callbacks from the connection
            returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
            returnConnection.setVideoPauseSupported(
                    TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
                            phoneAccountHandle));
        }
        return returnConnection;
    }
           

10.继续回到之前的 handleCreateConnectionComplet中跟进

public void handleCreateConnectionComplete(
            String id,
            ConnectionRequest request,
            ParcelableConnection connection) {
        for (IConnectionServiceAdapter adapter : mAdapters) {
            try {
                adapter.handleCreateConnectionComplete(id, request, connection,
                        Log.getExternalSession());
            } catch (RemoteException e) {
            }
        }
    }
           

11.这里通过AIDL进行通信,搜索 IConnectionServiceAdapter.Stub,

跟进到 ConnectionServiceWrapper

@Override
        public void handleCreateConnectionComplete(String callId, ConnectionRequest request,
                ParcelableConnection connection, Session.Info sessionInfo) {
                ...
                    logIncoming("handleCreateConnectionComplete %s", callId);
                    ConnectionServiceWrapper.this
                            .handleCreateConnectionComplete(callId, request, connection);
                ...
        }
    之前在拨号创建完connection并呼叫之后也会走到这个地方
           

12.继续跟进handleCreateConnectionComplete

private void handleCreateConnectionComplete(
            String callId,
            ConnectionRequest request,
            ParcelableConnection connection) {
        ...
        if (connection.getState() == Connection.STATE_DISCONNECTED) {
            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 {
                    mPendingResponses.remove(callId)
                            .handleCreateConnectionSuccess(mCallIdMapper, connection);
                }
            }
        }
    }
           

mPendingResponses是hashMap容器,每次在 createConnection 的时候会将对象加入该容器,如果此时connection还未断开的,会移除此connection,调用hanleCreateConnectionSuccess方法。

往上追溯createConnection跟踪到mService.createConnection(mCall, this);

CreateConnectionProcessor.java会把自身传入,发现该类也实现了 CreateConnectionResponse ,所以这里的 handleCreateConnectionSuccess

调用的是这个类里面的方法

13.继续跟进 CreateConnectionProcessor 中的此方法

@Override
    public void handleCreateConnectionSuccess(
            CallIdMapper idMapper,
            ParcelableConnection connection) {
        if (mCallResponse == null) {
            mService.abort(mCall);
        } else {

            mCallResponse.handleCreateConnectionSuccess(idMapper, connection);

            String number = connection == null || connection.getHandle() == null ?
                    null : connection.getHandle().getSchemeSpecificPart();
            if (!PhoneNumberUtils.isEmergencyNumber(number)) {
                mCallResponse = null;
            }
        }
    }   
           

14.发现这里的 mCallResponse (mCallResponse为何是 telecomm Call 对象?),继续跟进telecomm Call中的

@Override
    public void handleCreateConnectionSuccess(
            CallIdMapper idMapper,
            ParcelableConnection connection) {
        ...
        switch (mCallDirection) {
            case CALL_DIRECTION_INCOMING:
                // Listeners (just CallsManager for now) will be responsible for checking whether
                // the call should be blocked.
                for (Listener l : mListeners) {
                    //触发回调
                    l.onSuccessfulIncomingCall(this);
                }
                break;
            case CALL_DIRECTION_OUTGOING:
                for (Listener l : mListeners) {
                    l.onSuccessfulOutgoingCall(this,
                            getStateFromConnectionState(connection.getState()));
                }
                break;
            case CALL_DIRECTION_UNKNOWN:
                for (Listener l : mListeners) {
                    l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection
                            .getState()));
                }
                break;
        }
    }
           

这里根据来电类型,触发回调,监听者会收到通知,之前在CallManager中执行 processIncomingCallIntent 方法创建Call的时候就添加了监听,所以最后会回调到

CallsManager中

继续阅读