(O)Telephony分析之通话流程分析(三)拨打电话流程分析(下)

三.Call的建立和传送

先来看下代码

static void processOutgoingCallIntent(
        Context context,
        CallsManager callsManager,
        Intent intent) {
    ......
    // 拨打电话状态依旧为语音通话
    final int videoState = intent.getIntExtra( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
            VideoProfile.STATE_AUDIO_ONLY);
    clientExtras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);

    // 是否是系统默认电话应用
    final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);

    boolean fixedInitiatingUser = fixInitiatingUserIfNecessary(context, intent);
    ......
    UserHandle initiatingUser = intent.getParcelableExtra(KEY_INITIATING_USER);

    // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
    // 调用CallsManager的startOutgoingCall方法,初始化Call对象
    Call call = callsManager
            .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);

    if (call != null) {
        // Asynchronous calls should not usually be made inside a BroadcastReceiver because once
        // onReceive is complete, the BroadcastReceiver's process runs the risk of getting
        // killed if memory is scarce. However, this is OK here because the entire Telecom
        // process will be running throughout the duration of the phone call and should never
        // be killed.
        NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
                context, callsManager, call, intent, callsManager.getPhoneNumberUtilsAdapter(),
                isPrivilegedDialer);
        final int result = broadcaster.processIntent();
				......
    }
}
此处主要是做了两件事
1)调用CallsManager的startOutgoingCall方法,初始化或者复用Call
2)初始化NewOutgoingCallIntentBroadcaster对象,并调用其processIntent方法

(一)CallsManager的startOutgoingCall方法分析
先查看一下其代码

Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras,
        UserHandle initiatingUser) {
    boolean isReusedCall = true;
    Call call = reuseOutgoingCall(handle);

    // Create a call with original handle. The handle may be changed when the call is attached
    // to a connection service, but in most cases will remain the same.
    if (call == null) {
        call = new Call(getNextCallId(), mContext,
                this,
                mLock,
                mConnectionServiceRepository,
                mContactsAsyncHelper,
                mCallerInfoAsyncQueryFactory,
                mPhoneNumberUtilsAdapter,
                handle,
                null /* gatewayInfo */,
                null /* connectionManagerPhoneAccount */,
                null /* phoneAccountHandle */,
                Call.CALL_DIRECTION_OUTGOING /* callDirection */,
                false /* forceAttachToExistingConnection */,
                false /* isConference */
        );
        call.initAnalytics();

        call.setInitiatingUser(initiatingUser);

        isReusedCall = false;
    }
		......

    List accounts = constructPossiblePhoneAccounts(handle, initiatingUser);
    Log.v(this, "startOutgoingCall found accounts = " + accounts);
		......

    if (phoneAccountHandle == null && accounts.size() > 0) {
        // No preset account, check if default exists that supports the URI scheme for the
        // handle and verify it can be used.
        if(accounts.size() > 1) {
            PhoneAccountHandle defaultPhoneAccountHandle =
                    mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(handle.getScheme(), initiatingUser);
            if (defaultPhoneAccountHandle != null &&
                    accounts.contains(defaultPhoneAccountHandle)) {
                phoneAccountHandle = defaultPhoneAccountHandle;
            }
        } else {
            // Use the only PhoneAccount that is available
            phoneAccountHandle = accounts.get(0);
        }

    }

    call.setTargetPhoneAccount(phoneAccountHandle);
    ......
    // Do not support any more live calls.  Our options are to move a call to hold, disconnect
    // a call, or cancel this call altogether. If a call is being reused, then it has already
    // passed the makeRoomForOutgoingCall check once and will fail the second time due to the
    // call transitioning into the CONNECTING state.
    if (!isPotentialInCallMMICode && (!isReusedCall &&
            !makeRoomForOutgoingCall(call, call.isEmergencyCall()))) {
        // just cancel at this point.
        Log.i(this, "No remaining room for outgoing call: %s", call);
        if (mCalls.contains(call)) {
            // This call can already exist if it is a reused call,
            // See {@link #reuseOutgoingCall}.
            call.disconnect();
        }
        return null;
    }

    boolean needsAccountSelection = phoneAccountHandle == null && accounts.size() > 1 &&
            !call.isEmergencyCall();

    if (needsAccountSelection) {
        // This is the state where the user is expected to select an account
        call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection");
        // Create our own instance to modify (since extras may be Bundle.EMPTY)
        extras = new Bundle(extras);
        extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, accounts);
    } else {
        call.setState(
                CallState.CONNECTING,
                phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
    }

    setIntentExtrasAndStartTime(call, extras);

    // Do not add the call if it is a potential MMI code.
    if ((isPotentialMMICode(handle) || isPotentialInCallMMICode) && !needsAccountSelection) {
        ......
    } else if (!mCalls.contains(call)) {
        ......
        addCall(call);
    }

    return call;
}
从这个方法中,可以看到
1)先调用reuseOutgoingCall方法确认是否有可以直接使用的Call,由于分析的是第一次通话,因此,此处为null,无可用的Call
2)初始化一个Call对象,并且设置一些必要的参数
3)由于传入的参数phoneAccountHandle为null(此前都没有设置过),因此会设置其值为默认的defaultPhoneAccountHandle或者为accounts.get(0)
4)调用addCall方法
从如上的分析中,可以看到,目前有几个问题需要解决
第一,需要由于phoneAccountHandle被设置为默认的defaultPhoneAccountHandle或者accounts.get(0),这个取决于accounts的数量,那么这个值是什么
第二,addCall方法中具体做了什么
下面,就对这两个问题进行分析一下
i)phoneAccountHandle是被设置为什么了?
从上述的代码中看,它是由accounts决定的,如果accounts的数量大于1的话,则为默认的defaultPhoneAccountHandle,如果其数量为1的话,则为accounts中所包含的PhoneAccountHandle
那么,accounts是什么?通过代码查看,了解其是由constructPossiblePhoneAccounts方法得到的
private List constructPossiblePhoneAccounts(Uri handle, UserHandle user) {
    ......
    List allAccounts =
            mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user);
    ......
    return allAccounts;
}
可以看到,是调用PhoneAccountRegistrarD的getCallCapablePhoneAccounts方法返回的
public List getCallCapablePhoneAccounts(
        String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle) {
    return getPhoneAccountHandles(
            PhoneAccount.CAPABILITY_CALL_PROVIDER,
            PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY /*excludedCapabilities*/,
            uriScheme, null, includeDisabledAccounts, userHandle);
}
private List getPhoneAccountHandles(
        int capabilities,
        int excludedCapabilities,
        String uriScheme,
        String packageName,
        boolean includeDisabledAccounts,
        UserHandle userHandle) {
    List handles = new ArrayList<>();

    for (PhoneAccount account : getPhoneAccounts(
            capabilities, excludedCapabilities, uriScheme, packageName,
            includeDisabledAccounts, userHandle)) {
        handles.add(account.getAccountHandle());
    }
    return handles;
}
OK,是通过getPhoneAccounts的getAccountHandle得到的

private List getPhoneAccounts(
        int capabilities,
        int excludedCapabilities,
        String uriScheme,
        String packageName,
        boolean includeDisabledAccounts,
        UserHandle userHandle) {
    List accounts = new ArrayList<>(mState.accounts.size());
    for (PhoneAccount m : mState.accounts) {
        ......
        accounts.add(m);
    }
    return accounts;
}
mState是什么?查看整个PhoneAccountRegistrar的代码,发现,这个mState是在PhoneAccountRegistrar的初始化的时候写入的,来看它的代码
public PhoneAccountRegistrar(Context context, String fileName,
            DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy) {
    mAtomicFile = new AtomicFile(new File(context.getFilesDir(), fileName));

    mState = new State();
    mContext = context;
    mUserManager = UserManager.get(context);
    mDefaultDialerCache = defaultDialerCache;
    mSubscriptionManager = SubscriptionManager.from(mContext);
    mAppLabelProxy = appLabelProxy;
    mCurrentUserHandle = Process.myUserHandle();
    read();
}
read方法
private void read() {
    final InputStream is;
    try {
        is = mAtomicFile.openRead();
    } catch (FileNotFoundException ex) {
        return;
    }

    boolean versionChanged = false;

    XmlPullParser parser;
    try {
        parser = Xml.newPullParser();
        parser.setInput(new BufferedInputStream(is), null);
        parser.nextTag();
        mState = readFromXml(parser, mContext);
        versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;

    } catch (IOException | XmlPullParserException e) {
        Log.e(this, e, "Reading state from XML file");
        mState = new State();
    } finally {
        try {
            is.close();
        } catch (IOException e) {
            Log.e(this, e, "Closing InputStream");
        }
    }

    // Verify all of the UserHandles.
    List badAccounts = new ArrayList<>();
    for (PhoneAccount phoneAccount : mState.accounts) {
        UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle();
        if (userHandle == null) {
            Log.w(this, "Missing UserHandle for %s", phoneAccount);
            badAccounts.add(phoneAccount);
        } else if (mUserManager.getSerialNumberForUser(userHandle) == -1) {
            Log.w(this, "User does not exist for %s", phoneAccount);
            badAccounts.add(phoneAccount);
        }
    }
    mState.accounts.removeAll(badAccounts);

    // If an upgrade occurred, write out the changed data.
    if (versionChanged || !badAccounts.isEmpty()) {
        write();
    }
}
原来,它是读取xml文件得到的数据,那么xml文件里面有哪些数据呢?下面是我从高通的某平台的O版本的项目中导出的phone-account-registrar-state.xml


	
		
			0
			
			
				
					com.android.phone/com.android.services.telephony.TelephonyConnectionService
					89860081101750717452
					0
				
			
		
	
	
		
			
				
					com.android.phone/com.android.services.telephony.TelephonyConnectionService
					E
					0
				
			
			tel:
			tel:
			182
			AAAAAQGJUE5HDQoaCgAAAA1JSERSAAAAJgAAADAIBgAAAH2yCCgAAAAEc0JJVAgICAh8CGSIAAAB
6UlEQVRYhe2YO47TUBRAz72JRMEvMkJQ0iGlBQmQEIqABigonOcsgWWQhi0wQ5WgNGgspoCCNhuY
BWS2gESbgsSXwjZxJgPkoWT8Cp/Gha2ro/OebdmCB865VpqmyyRJEjP7CFwqTonPnHPIgFMz+yAi
79M0/bn1wF6v155Op4t+v/9aRCbAlR1JrSEio06n86a1zcXD4VDH4/HSOfdKRI6Ay3uQMmAJ3JvP
59//ObgslSTJSzP7BFwlT687lCrJiuPsr8Odc61i+V6YWVpI2Z6kKOYqcPePxSqlnpvZZ+Aa+yt1
ruEGlVLPKlL7LLXBRrGylHPuKXAMXCfflFvdKLtirUBZyjn3GEgLqeyipaBSrLKnnpjZMXCDGkqV
KKyVelSRqqVUiZSlBoPBwyzLvgA3qbHUbzGAOI7vq+pX4Db53bfT18z/oHEcP6hILQlACkBV9Yhc
qtY9dRYFbnGBT/RtUWBBYFKQCwWxp84SXKmSRsyXRswXZfUJFhRKQE/7KkEvZZA0Yr40Yr40Yr40
Yr40Yr40Yr40Yr40Yr4oq3/rIZEpMCOXC0Gw9JipmR2wKmc1SlnhoGZ2oFEUHYrICGhT7w8WAdoi
Moqi6LB1cnJi3W73m5n9EJE7QFSDYAbMzOwd8HYymSx+ASOfrdnny/IjAAAAAElFTkSuQmCC

			0
			
			Emergency calling only
			
				tel
				voicemail
			
			
				-1
				false
			
			true
			15
		
	
分析其读取的过程,可以知道,mState的defaultOutgoingAccountHandles/accounts/versionNumber均在其中有所规定,那么接下来就按照这份xml文件中的内容分析其流程
从上面可以看到,accounts只有一个PhoneAccountHandle,因此
phoneAccountHandle被设置为上述accounts的唯一值了,即三个参数分别为
mComponentName为com.android.phone/com.android.services.telephony.TelephonyConnectionService
mId为E
mUserHandle为UserManager.get(context).getUserForSerialNumber(0)
ii)addCall方法做了什么
直接看其代码

private void addCall(Call call) {
    ......
    call.addListener(this);
    mCalls.add(call);
    .....
    for (CallsManagerListener listener : mListeners) {
        ......
        listener.onCallAdded(call);
        ......
    }
    ......
}
可以看到,主要是将刚刚初始化的Call对象加入到mCalls中进行管理,并且调用mListers中所有的Listener对象的onCallAdded方法,那么mListeners是什么?
查找代码,发现在CallsManager的初始化的时候已经对其值进行处理过
mListeners.add(mInCallWakeLockController);
mListeners.add(statusBarNotifier);
mListeners.add(mCallLogManager);
mListeners.add(mPhoneStateBroadcaster);
mListeners.add(mInCallController);
mListeners.add(mCallAudioManager);
mListeners.add(missedCallNotifier);
mListeners.add(mHeadsetMediaButton);
mListeners.add(mProximitySensorManager);
因此,会分别调用添加到mListeners中的所有对象的onCallAdded方法
这个部分,具体的不再分析,只需要知道,分别会启动相关的应用程序
如InCallController启动InCallUi应用,用于展示通话界面,CallLogManager对象启动添加通话历史记录等,不再赘述
接下来,分析下Call的建立和传递的第二个部分
(二)初始化NewOutgoingCallIntentBroadcaster对象,并调用其processIntent方法
一样,先看其代码
public NewOutgoingCallIntentBroadcaster(Context context, CallsManager callsManager, Call call,
        Intent intent, PhoneNumberUtilsAdapter phoneNumberUtilsAdapter,
        boolean isDefaultPhoneApp) {
    mContext = context;
    mCallsManager = callsManager;
    mCall = call;
    mIntent = intent;
    mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
    mIsDefaultOrSystemPhoneApp = isDefaultPhoneApp;
    mLock = mCallsManager.getLock();
}
初始化,没啥说的
public int processIntent() {
    Intent intent = mIntent;
    String action = intent.getAction();
    final Uri handle = intent.getData();
    ......
    String number = mPhoneNumberUtilsAdapter.getNumberFromIntent(intent, mContext);
    ......
    UserHandle targetUser = mCall.getInitiatingUser();
    Log.i(this, "Sending NewOutgoingCallBroadcast for %s to %s", mCall, targetUser);
    broadcastIntent(intent, number, !callImmediately, targetUser);
    return DisconnectCause.NOT_DISCONNECTED;
}
调用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);

    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
}
发送广播,在NewOutgoingCallBroadcastIntentReceiver中进行处理
public class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            ......
                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));
            }
        }
        .....
    }
}
回到CallsManager中,调用placeOutgoingCall方法

public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
        boolean speakerphoneOn, int videoState) {
    ......
    call.startCreateConnection(mPhoneAccountRegistrar);
    ......
}
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
    ......
    mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
            phoneAccountRegistrar, mContext);
    mCreateConnectionProcessor.process();
}
public void process() {
    ......
    attemptNextPhoneAccount();
}
private void attemptNextPhoneAccount() {
    ......
    PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
    mService = mRepository.getService(phoneAccount.getComponentName(), phoneAccount.getUserHandle());
    ......
    mService.createConnection(mCall, this);
    ......
}
从上面的分析,知道,这边的PhoneAccountHandle对象是在phone-account-registrar-state.xml文件中读取出来的,那么分析一下ConnectionServiceRepository的getService方法,我们知道
mService就是PhoneAccountHandle的Component对应的类的对象,即TelephonyConnectionService对象
看其createConnection方法,父类ConnectionService

private void createConnection(
        final PhoneAccountHandle callManagerAccount,
        final String callId,
        final ConnectionRequest request,
        boolean isIncoming,
        boolean isUnknown) {
    ......

    Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
            : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
            : onCreateOutgoingConnection(callManagerAccount, request);
    ......
}
调用onCreateOutgoingConnection方法

public Connection onCreateOutgoingConnection(
        PhoneAccountHandle connectionManagerPhoneAccount,
        final ConnectionRequest request) {
				......
        placeOutgoingConnection((TelephonyConnection) resultConnection, phone, request);
        ......
}
调用placeOutgoingConnection方法

private void placeOutgoingConnection(
        TelephonyConnection connection, Phone phone, ConnectionRequest request) {
    placeOutgoingConnection(connection, phone, request.getVideoState(), request.getExtras());
}
private void placeOutgoingConnection(
        TelephonyConnection connection, Phone phone, int videoState, Bundle extras) {
    .....
    originalConnection = phone.dial(number, null, videoState, extras);
		......
}
调用Phone对象的dial方法

public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
        throws CallStateException {
    ......
    if (isPhoneTypeGsm()) {
        return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);
    } else {
        return dialInternal(dialString, null, videoState, intentExtras);
    }
}
调用dialInternal方法

protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
                                  Bundle intentExtras)
        throws CallStateException {
    return dialInternal(dialString, uusInfo, videoState, intentExtras, null);
}
protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
                                  Bundle intentExtras, ResultReceiver wrappedCallback)
        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);
        GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this,
                                                      mUiccApplication.get(), wrappedCallback);
        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);
    }
}
可以看到,会调用GsmCdmaCallTracker的dial方法

public Connection dial(String dialString) throws CallStateException {
    if (isPhoneTypeGsm()) {
        return dial(dialString, CommandsInterface.CLIR_DEFAULT, null);
    } else {
        return dial(dialString, CommandsInterface.CLIR_DEFAULT);
    }
}
以Gsm Phone来看

public Connection dial(String dialString, UUSInfo uusInfo, Bundle intentExtras)
        throws CallStateException {
    return dial(dialString, CommandsInterface.CLIR_DEFAULT, uusInfo, intentExtras);
}
public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo,
                                    Bundle intentExtras)
        throws CallStateException {
    ......
    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(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage());
    }

    if (mNumberConverted) {
        mPendingMO.setConverted(origNumber);
        mNumberConverted = false;
    }

    updatePhoneState();
    mPhone.notifyPreciseCallStateChanged();

    return mPendingMO;
}
这边调用RIL的dial方法,最终会传入RIL层,进行处理


















你可能感兴趣的:(Telephony分析)