首先了解Phone 與 system是什麼 ,我在網上找了一張圖片先了解一下
設計圖:
- Dialer (dialer進程 )撥打電話的入口,來電不會經過Dialer。但是撥打電話的出口不光是Dialer,在聯繫人和短信裏也有撥打電話的出口。
- InCallUI (dialer進程) 負責顯示通話界面的信息,來電信息。
- Telecomm(system_process和telecomm:ui進程) 處理Intent,發送廣播,設置call的狀態,audio狀態。
- Telephony ( phone進程) 向下層傳遞撥號,註冊了很多廣播,申請很多權限,service data sms wap network等。
- telecomm(phone_process) 提供placeCall的接口,創建outgoingCall的connection,通知上層成功建立connection
- telephony (phone_process) 撥號也就是dial命令的下發,但是如果是Ims網絡就會有下面一步
- Vendor/ims(phone_process) 創建ImsConnection,ImsCall,撥號.
連接入口在system_process進程中的ConnectionServiceWrapper.java
system進程與phone進程之間連接流程圖
流程圖:
第一步
ConnectionServiceWrapper.java
system進入ConnectionServiceWrapper.java中的createConnection方法
步驟一
public void createConnection(final Call call, final CreateConnectionResponse response) {//創建鏈接就是一個綁定服務的過程
Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
BindCallback callback = new BindCallback() {// 鏈接創建成功後 onSuccess 會被調用
@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());
}
if (call.isIncoming() && mCallsManager.getEmergencyCallHelper()
.getLastEmergencyCallTimeMillis() > 0) {
// Add the last emergency call time to the connection request for incoming calls
if (extras == call.getIntentExtras()) {
extras = (Bundle) extras.clone();
}
extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS,
mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis());
}
// Call is incoming and added because we're handing over from another; tell CS
// that its expected to handover.
if (call.isIncoming() && call.getHandoverSourceCall() != null) {
extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true);
extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT,
call.getHandoverSourceCall().getTargetPhoneAccount());
}
Log.addEvent(call, LogUtils.Events.START_CONNECTION,
Log.piiHandle(call.getHandle()));
ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
.setAccountHandle(call.getTargetPhoneAccount())
.setAddress(call.getHandle())
.setExtras(extras)
.setVideoState(call.getVideoState())
.setTelecomCallId(callId)
// For self-managed incoming calls, if there is another ongoing call Telecom
// is responsible for showing a UI to ask the user if they'd like to answer
// this new incoming call.
.setShouldShowIncomingCallUi(
!mCallsManager.shouldShowSystemIncomingCallUi(call))
.setRttPipeFromInCall(call.getInCallToCsRttPipeForCs())
.setRttPipeToInCall(call.getCsToInCallRttPipeForCs())
.build();
try {
mServiceInterface.createConnection( // 通過遠程接口創建鏈接 利用遠程接口創建一個通話鏈接
call.getConnectionManagerPhoneAccount(),
callId,
connectionRequest,
call.shouldAttachToExistingConnection(),
call.isUnknown(),
Log.getExternalSession());
} 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));
}
};
//綁定
mBinder.bind(callback, call);
ServiceBinder.java
進入mBinder.bind中 ConnectionServiceWrapper是ServiceBinder的子類,而mBinder.bind方法是ServiceBinder裏面的內部類Binder2 中
步驟二
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;
}
//在類裏面綁定成功後mBinder.bind(callback, call);在父類ServiceBinder類裏面mCallbacks.add(callback);吧回調用集合給裝載起來,然後進行便利數據
//成功獲取到aidl接口後將其賦值mServiceInterface,
mCallbacks.add(callback);
if (mServiceConnection == null) {
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
ServiceConnection connection = new ServiceBinderConnection(call);
Log.addEvent(call, LogUtils.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, //如果綁定成功調用connection方法 這裏綁定是綁定了framework/base/telepony
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();
}
}
}
步驟三
mContext.bindServiceAsUser()傳入了一個connection對象代表,如果連接成功回調到connection對象中,connection繼承ServiceConnection,我們來看一下connection對象吧,
回調onServiceConnected()方法,返回一個bind
步驟四
private final class ServiceBinderConnection implements ServiceConnection {
/**
* 綁定服務的初始調用。
*/
private Call mCall;
ServiceBinderConnection(Call call) {
mCall = call;
}
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
try {
Log.startSession("SBC.oSC");
synchronized (mLock) {
Log.i(this, "Service bound %s", componentName);
Log.addEvent(mCall, LogUtils.Events.CS_BOUND, componentName);
mCall = null;
//取消綁定請求被排隊,因此立即取消綁定。
if (mIsBindingAborted) {
clearAbort();
logServiceDisconnected("onServiceConnected");
mContext.unbindService(this);
handleFailedConnection();
return;
}
if (binder != null) {
mServiceDeathRecipient = new ServiceDeathRecipient(componentName);
try {
binder.linkToDeath(mServiceDeathRecipient, 0);
mServiceConnection = this;
// 設置 mServiceInterface
// 會觸發 ConnectionServiceWrapper.setServiceInterface ==> ConnectionServiceWrapper.addConnectionServiceAdapter
// 通過mServiceInterface,給綁定的服務,提供一個訪問自己的接口
setBinder(binder);// 觸發bind(BindCallback callback, Call call) 中 callback 的 onSuccess
handleSuccessfulConnection(); //回調進入子類
//整個綁定過程,只做2件事,一是給遠程服務提供訪問自己的接口,二是利用遠程接口創建一個通話鏈接。
// 這2件事都是跨進程進行的。遠程服務訪問自己的接口是
} catch (RemoteException e) {
Log.w(this, "onServiceConnected: %s died.");
if (mServiceDeathRecipient != null) {
mServiceDeathRecipient.binderDied();
}
}
}
}
} finally {
Log.endSession();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
失敗處理...
}
}
入口步驟五
setBinder() 回調到ServiceConnectionWrapper.java中setServiceInterface() 遠程服務提供訪問自己的接口
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);
}
}
}
步驟六
setServiceInterace() 調用的是子類實現方法 ,他的子類是ConnectionServiceWrapper.java
ConnectionServiceWrapper.java
@Override
protected void setServiceInterface(IBinder binder) {
mServiceInterface = IConnectionService.Stub.asInterface(binder);
Log.v(this, "Adding Connection Service Adapter.");
addConnectionServiceAdapter(mAdapter);//這個mAdapter 給遠程服務提供訪問自己的接口
}
步驟七
/** See {@link IConnectionService#addConnectionServiceAdapter}. */
private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
if (isServiceValid("addConnectionServiceAdapter")) {
try {
//在類裏面綁定成功後mBinder.bind(callback, call);在父類ServiceBinder類裏面mCallbacks.add(callback);吧回調用集合給裝載起來,然後進行便利數據
//成功獲取到aidl接口後將其賦值mServiceInterface,
logOutgoing("addConnectionServiceAdapter %s", adapter);
mServiceInterface.addConnectionServiceAdapter(adapter, Log.getExternalSession());
} catch (RemoteException e) {
}
}
}
完成遠程服務提供訪問自己的接口
步驟八
回到ServiceBinder中子類對象中的connection對象裏面的onServiceConnected()方法
然後調用 handleSuccessfulConnection()
private void handleSuccessfulConnection() {
for (BindCallback callback : mCallbacks) {
callback.onSuccess();
}
mCallbacks.clear();
}
步驟九
回調到ConnectionServiceWrapper中Bindcallback中的onSuccess()方法中
@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());
}
if (call.isIncoming() && mCallsManager.getEmergencyCallHelper()
.getLastEmergencyCallTimeMillis() > 0) {
// Add the last emergency call time to the connection request for incoming calls
if (extras == call.getIntentExtras()) {
extras = (Bundle) extras.clone();
}
extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS,
mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis());
}
// Call is incoming and added because we're handing over from another; tell CS
// that its expected to handover.
if (call.isIncoming() && call.getHandoverSourceCall() != null) {
extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true);
extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT,
call.getHandoverSourceCall().getTargetPhoneAccount());
}
Log.addEvent(call, LogUtils.Events.START_CONNECTION,
Log.piiHandle(call.getHandle()));
ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
.setAccountHandle(call.getTargetPhoneAccount())
.setAddress(call.getHandle())
.setExtras(extras)
.setVideoState(call.getVideoState())
.setTelecomCallId(callId)
// For self-managed incoming calls, if there is another ongoing call Telecom
// is responsible for showing a UI to ask the user if they'd like to answer
// this new incoming call.
.setShouldShowIncomingCallUi(
!mCallsManager.shouldShowSystemIncomingCallUi(call))
.setRttPipeFromInCall(call.getInCallToCsRttPipeForCs())
.setRttPipeToInCall(call.getCsToInCallRttPipeForCs())
.build();
try {
mServiceInterface.createConnection( // 通過遠程接口創建鏈接 利用遠程接口創建一個通話鏈接
call.getConnectionManagerPhoneAccount(),
callId,
connectionRequest,
call.shouldAttachToExistingConnection(),
call.isUnknown(),
Log.getExternalSession());
} catch (RemoteException e) {
Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
mPendingResponses.remove(callId).handleCreateConnectionFailure(
new DisconnectCause(DisconnectCause.ERROR, e.toString()));
}
}
這個方法內部
步驟十
phone進程
ConnectionService.java
@Override
public void createConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
String id,
ConnectionRequest request,
boolean isIncoming,
boolean isUnknown,
Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_CREATE_CONN);
try {
SomeArgs args = SomeArgs.obtain();
args.arg1 = connectionManagerPhoneAccount;
args.arg2 = id;
args.arg3 = request;
args.arg4 = Log.createSubsession();
args.argi1 = isIncoming ? 1 : 0;
args.argi2 = isUnknown ? 1 : 0;
mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
} finally {
Log.endSession();
}
}
步驟十一
創建連接MSG_CREATE_CONNECTION
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ADD_CONNECTION_SERVICE_ADAPTER: {
SomeArgs args = (SomeArgs) msg.obj;
try { // 添加 來自於 system 進程的接口
IConnectionServiceAdapter adapter = (IConnectionServiceAdapter) args.arg1;
Log.continueSession((Session) args.arg2,
SESSION_HANDLER + SESSION_ADD_CS_ADAPTER);
mAdapter.addAdapter(adapter);
onAdapterAttached();
} finally {
args.recycle();
Log.endSession();
}
break;
}
case MSG_REMOVE_CONNECTION_SERVICE_ADAPTER: {
SomeArgs args = (SomeArgs) msg.obj;
try {
Log.continueSession((Session) args.arg2,
SESSION_HANDLER + SESSION_REMOVE_CS_ADAPTER);
mAdapter.removeAdapter((IConnectionServiceAdapter) args.arg1); // 移除
} finally {
args.recycle();
Log.endSession();
}
break;
}
case MSG_CREATE_CONNECTION: { // 創建鏈接
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg4, SESSION_HANDLER + SESSION_CREATE_CONN);
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 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);
}
} finally {
args.recycle();
Log.endSession();
}
break;
}
}
}
}
步驟十二
通過遠程接口創建鏈接 ,利用遠程接口創建一個通話鏈接,等待12步驟完成,完成後會返回一連接對象connection對象傳入handlerCreateConnectionComplete()方法
/**
* 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) {
boolean isLegacyHandover = request.getExtras() != null &&
request.getExtras().getBoolean(TelecomManager.EXTRA_IS_HANDOVER, false);
boolean isHandover = request.getExtras() != null && request.getExtras().getBoolean(
TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, false);
Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +
"isIncoming: %b, isUnknown: %b, isLegacyHandover: %b, isHandover: %b",
callManagerAccount, callId, request, isIncoming, isUnknown, isLegacyHandover,
isHandover);
Connection connection = null;
if (isHandover) {
PhoneAccountHandle fromPhoneAccountHandle = request.getExtras() != null
? (PhoneAccountHandle) request.getExtras().getParcelable(
TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT) : null;
if (!isIncoming) {
connection = onCreateOutgoingHandoverConnection(fromPhoneAccountHandle, request);
} else {
connection = onCreateIncomingHandoverConnection(fromPhoneAccountHandle, request);
}
} else {
connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
: isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
: onCreateOutgoingConnection(callManagerAccount, request);
}
Log.d(this, "createConnection, connection: %s", connection);
if (connection == null) {
Log.i(this, "createConnection, implementation returned null connection.");
connection = Connection.createFailedConnection(
new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONNECTION"));
}
connection.setTelecomCallId(callId);
if (connection.getState() != Connection.STATE_DISCONNECTED) {
// 監聽 Connection 的狀態變化,通知 system 進程(CallsManager)更新
// 通過 system 進程提供的 adapter 實現
addConnection(request.getAccountHandle(), callId, connection);
}
Uri address = connection.getAddress();
String number = address == null ? "null" : address.getSchemeSpecificPart();
Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s, properties: %s",
Connection.toLogSafePhoneNumber(number),
Connection.stateToString(connection.getState()),
Connection.capabilitiesToString(connection.getConnectionCapabilities()),
Connection.propertiesToString(connection.getConnectionProperties()));
Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId);
//mAdapter.handleCreateConnectionComplete 調用回到 ConnectionServiceWrapper 的 handleCreateConnectionComplete,
// 然後回到 Call 的 handleCreateConnectionSuccess
mAdapter.handleCreateConnectionComplete(// 通知 system 進程(即CallsManager) 電話鏈接已經創建完成
callId,
request,
new ParcelableConnection(
request.getAccountHandle(),
connection.getState(),
connection.getConnectionCapabilities(),
connection.getConnectionProperties(),
connection.getSupportedAudioRoutes(),
connection.getAddress(),
connection.getAddressPresentation(),
connection.getCallerDisplayName(),
connection.getCallerDisplayNamePresentation(),
connection.getVideoProvider() == null ?
null : connection.getVideoProvider().getInterface(),
connection.getVideoState(),
connection.isRingbackRequested(),
connection.getAudioModeIsVoip(),
connection.getConnectTimeMillis(),
connection.getConnectElapsedTimeMillis(),
connection.getStatusHints(),
connection.getDisconnectCause(),
createIdList(connection.getConferenceables()),
connection.getExtras()));
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();
}
}
通過Adapter.handleCreateConnectionComplete()回調進入ConnectionServiceWrapper.java裏面的Adapter內部類中
@Override
public void handleCreateConnectionComplete(String callId, ConnectionRequest request, //連接建立完成
ParcelableConnection connection, Session.Info sessionInfo) {
Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE);
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
logIncoming("handleCreateConnectionComplete %s", callId);
ConnectionServiceWrapper.this
.handleCreateConnectionComplete(callId, request, connection); //framework/base/telecom回調後調用 更新UI
if (mServiceInterface != null) {
logOutgoing("createConnectionComplete %s", callId);
try {
mServiceInterface.createConnectionComplete(callId,
Log.getExternalSession());//調用到
} catch (RemoteException e) {
}
}
}
} catch (Throwable t) {
Log.e(ConnectionServiceWrapper.this, t, "");
throw t;
} finally {
Binder.restoreCallingIdentity(token);
Log.endSession();
}
}
private void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
// TODO: Note we are not using parameter "request", which is a side effect of our tacit
// assumption that we have at most one outgoing connection attempt per ConnectionService.
// This may not continue to be the case. 判斷是否連接成功連接只需要進行一次
if (connection.getState() == Connection.STATE_DISCONNECTED) {
// A connection that begins in the DISCONNECTED state is an indication of
// failure to connect; we handle all failures uniformly
removeCall(callId, connection.getDisconnectCause());
} else {
// Successful connection 連接成功
if (mPendingResponses.containsKey(callId)) {
mPendingResponses.remove(callId)
.handleCreateConnectionSuccess(mCallIdMapper, connection);
}
}
連接建立完畢