emergencycall

更新时间:2023-01-04 03:45:52 阅读: 评论:0


2023年1月4日发(作者:danai gurira)

androidN拨打电话流程

本⽂主要分析从拨号盘拨号发出Intent开始,最终到中执⾏拨号操作的过程。

(1)⾸先拨号盘应⽤发送了action为的Intent,被UrCallActivity接收处理,UrCallActivity调⽤

UrCallIntentProcessor来处理:

@Override

protectedvoidonCreate(Bundlebundle){

te(bundle);

ession("");

try{

Intentintent=getIntent();

verifyCallAction(intent);

finalUrManagerurManager=(UrManager)getSystemService(_SERVICE);

finalUrHandleurHandle=newUrHandle(rHandle());

newUrCallIntentProcessor(this,urHandle).processIntent(getIntent(),

getCallingPackage(),true/*hasCallAppOp*/);

}finally{

sion();

}

finish();

(2)UrCallIntentProcessor通过processOutgoingCallIntent(),ndBroadcastToReceiver()调⽤PrimaryCallReceiver来处理:

privatebooleanndBroadcastToReceiver(Intentintent){

ra(_IS_INCOMING_CALL,fal);

gs(_RECEIVER_FOREGROUND);

ss(mContext,);

Log.d(this,"SendingbroadcastasurtoCallReceiver");

oadcastAsUr(intent,);

returntrue;

}

(3)(3)PrimaryCallReceiver中处理:PrimaryCallReceiver中处理:

publicvoidonReceive(Contextcontext,Intentintent){

ession("");

synchronized(getTelecomSystem().getLock()){

getTelecomSystem().getCallIntentProcessor().processIntent(intent);

}

sion();

}

(3)(3)CallIntentProcessor中处理:CallIntentProcessor中处理:

publicvoidprocessIntent(Intentintent){

finalbooleanisUnknownCall=leanExtra(KEY_IS_UNKNOWN_CALL,fal);

Log.i(this,"onReceive-isUnknownCall:%s",isUnknownCall);

ection("processNewCallCallIntent");

if(isUnknownCall){

processUnknownCallIntent(mCallsManager,intent);

}el{

processOutgoingCallIntent(mContext,mCallsManager,intent);

}

tion();

}

在processOutgoingCallIntent中主要的跳转逻辑

Callcall=callsManager

.startOutgoingCall(handle,phoneAccountHandle,clientExtras,initiatingUr);

if(call!=null){

NewOutgoingCallIntentBroadcasterbroadcaster=newNewOutgoingCallIntentBroadcaster(

context,callsManager,call,intent,neNumberUtilsAdapter(),

isPrivilegedDialer);

finalintresult=sIntent();

finalbooleansuccess=result==_DISCONNECTED;

if(!success&&call!=null){

endingMOEmergencyCall();

disconnectCallAndShowErrorDialog(context,call,result);

}

}

其中重点通过CallManager的startOutgoingCall⽅法构造了⼀个Call对象,其中重点会为该Call设置PhoneAccountHandle

CallstartOutgoingCall(Urihandle,PhoneAccountHandlephoneAccountHandle,Bundleextras,

UrHandleinitiatingUr){

booleanisReudCall=true;

Callcall=reuOutgoingCall(handle);

//dlemaybechangedwhenthecallisattached

//toaconnectionrvice,butinmostcaswillremainthesame.

if(call==null){

call=newCall(getNextCallId(),mContext,

this,

mLock,

mConnectionServiceRepository,

mContactsAsyncHelper,

mCallerInfoAsyncQueryFactory,

mPhoneNumberUtilsAdapter,

handle,

null/*gatewayInfo*/,

null/*connectionManagerPhoneAccount*/,

null/*phoneAccountHandle*/,

_DIRECTION_OUTGOING/*callDirection*/,

fal/*forceAttachToExistingConnection*/,

fal/*isConference*/

);

if((extras!=null)&&

lean(_DIAL_CONFERENCE_URI,fal)){

//RetPostDialDigitswithemptystringforConfURIcall.

tDialDigits("");

}

alytics();

tiatingUr(initiatingUr);

isReudCall=fal;

}

...

Listaccounts=

constructPossiblePhoneAccounts(handle,initiatingUr,scheme);

if(phoneAccountHandle!=null){

if(!ns(phoneAccountHandle)){

if(!ns(phoneAccountHandle)){

phoneAccountHandle=null;

}

}

if(phoneAccountHandle==null&&()>0){

if(()>1){

PhoneAccountHandledefaultPhoneAccountHandle=

goingPhoneAccountForScheme(scheme,

initiatingUr);

if(defaultPhoneAccountHandle!=null&&

ns(defaultPhoneAccountHandle)){

phoneAccountHandle=defaultPhoneAccountHandle;

}

}el{

phoneAccountHandle=(0);

}

}

getPhoneAccount(phoneAccountHandle);

...

booleanneedsAccountSelection=phoneAccountHandle==null&&()>1&&

!gencyCall();

if(needsAccountSelection){

te(_PHONE_ACCOUNT,"needsaccountlection");

//Createourowninstancetomodify()

extras=newBundle(extras);

celableList(BLE_PHONE_ACCOUNTS,accounts);

}el{

te(

TING,

phoneAccountHandle==null?"no-handle":ng());

}

...

returncall;

}

(3)(3)NewOutgoingCallIntentBroadcaster中主要逻辑:NewOutgoingCallIntentBroadcaster中主要逻辑:

if(callImmediately){

Stringscheme=isUriNumber?_SIP:_TEL;

booleanspeakerphoneOn=leanExtra(

_START_CALL_WITH_SPEAKERPHONE,fal);

intvideoState=Extra(

_START_CALL_WITH_VIDEO_STATE,

_AUDIO_ONLY);

OutgoingCallIntentBroadcastIsDone();

utgoingCall(mCall,rts(scheme,number,null),null,

speakerphoneOn,videoState);

}

重点调⽤CallsManager的placeOutgoingCal()⽅法

在placeOutgoingCal中核⼼调⽤了reateConnection(mPhoneAccountRegistrar);

if(getPhoneAccount()!=null||gencyCall()){

if(!gencyCall()){

updateLchStatus(getPhoneAccount().getId());

}

if(mPendingMOEmerCall==null){

reateConnection(mPhoneAccountRegistrar);

}

}elif(lCapablePhoneAccounts(

requireCallCapableAccountByHandle?dle().getScheme():null,fal,

tiatingUr()).isEmpty()){

markCallAsDisconnected(call,newDisconnectCau(ED,

"NoregisteredPhoneAccounts"));

markCallAsRemoved(call);

}

(4)(4)startCreateConnection中处理:startCreateConnection中处理:

voidstartCreateConnection(PhoneAccountRegistrarphoneAccountRegistrar){

if(mCreateConnectionProcessor!=null){

Log.w(this,""+

"duetoaracebetweenNewOutgoingCallIntentBroadcasterand"+

"phoneAccountSelected,butisharmlesslyresolvedbyignoringthecond"+

"invocation.");

return;

}

mCreateConnectionProcessor=newCreateConnectionProcessor(this,mRepository,this,

phoneAccountRegistrar,mContext);

s();

}

(5)(5)CreateConnectionProcessor中处理:CreateConnectionProcessor中处理:

publicvoidprocess(){

Log.v(this,"process");

clearTimeout();

mAttemptRecords=newArrayList<>();

if(getPhoneAccount()!=null){

(newCallAttemptRecord(

getPhoneAccount(),getPhoneAccount()));

}

adjustAttemptsForConnectionManager();

adjustAttemptsForEmergency(getPhoneAccount());

mAttemptRecordIterator=or();

attemptNextPhoneAccount();

}

其中重点逻辑在attemptNextPhoneAccount();

privatevoidattemptNextPhoneAccount(){

CallAttemptRecordattempt=null;

if(t()){

attempt=();

if(!ccountRequiresBindPermission(

tionManagerPhoneAccount)){

attemptNextPhoneAccount();

return;

}

if(!(PhoneAccount)&&

!ccountRequiresBindPermission(

PhoneAccount)){

attemptNextPhoneAccount();

return;

}

}

if(mCallRespon!=null&&attempt!=null){

PhoneAccountHandlephoneAccount=tionManagerPhoneAccount;

mService=vice(ponentName(),

rHandle());

if(mService==null){

Log.i(this,"Foundnoconnectionrviceforattempt%s",attempt);

attemptNextPhoneAccount();

}el{

mConnectionAttempt++;

nectionManagerPhoneAccount(tionManagerPhoneAccount);

getPhoneAccount(PhoneAccount);

nectionService(mService);

tTimeoutIfNeeded(mService,attempt);

Connection(mCall,this);

}

}el{

DisconnectCaudisconnectCau=mLastErrorDisconnectCau!=null?

mLastErrorDisconnectCau:newDisconnectCau();

notifyCallConnectionFailure(disconnectCau);

}

其中主要逻辑是找到⼀个正确的PhoneAccount然后通过调⽤Connection(mCall,this),其中mService为

ConnectionServiceWrapper类型的对象。

(6)(6)ConnectionServiceWrapper中处理:ConnectionServiceWrapper中处理:

publicvoidcreateConnection(finalCallcall,finalCreateConnectionResponrespon){

BindCallbackcallback=newBindCallback(){

@Override

publicvoidonSuccess(){

StringcallId=lId(call);

(callId,respon);

GatewayInfogatewayInfo=ewayInfo();

Bundleextras=entExtras();

if(gatewayInfo!=null&&ewayProviderPackageName()!=null&&

ginalAddress()!=null){

extras=(Bundle)();

ing(

Y_PROVIDER_PACKAGE,

ewayProviderPackageName());

celable(

Y_ORIGINAL_ADDRESS,

ginalAddress());

}

try{

Connection(

nectionManagerPhoneAccount(),

callId,

newConnectionRequest(

getPhoneAccount(),

dle(),

extras,

eoState(),

callId),

AttachToExistingConnection(),

own());

}catch(RemoteExceptione){

Log.e(this,e,"FailuretocreateConnection--%s",getComponentName());

(callId).handleCreateConnectionFailure(

newDisconnectCau(,ng()));

}

}

};

(callback,call);

}

其中最主要的⼀步还是下⾯的代码

Connection(

nectionManagerPhoneAccount(),

callId,

newConnectionRequest(

getPhoneAccount(),

dle(),

extras,

eoState(),

callId),

AttachToExistingConnection(),

own());

那么问题来了mServiceInterface到底是什么东西,上⾯所有的分析都是在Telecomm中发⽣的,众所周知,android中的phone是运⾏

在⾃⼰单独的进程中的,到此为⽌,以后的流程都是发⽣在phone进程中的,马上分析⼀下mServiceInterface是⼀个什么东西。

可以看出上⾯的代码是在调⽤(callback,call)后回调函数中调⽤的(mBinder是ConnectionServiceWrapper的⽗类

ServiceBinder中的⼀个内部类),所以才可应该是bind操作后对mServiceInterface进⾏了赋值。

voidbind(BindCallbackcallback,Callcall){

Log.d(,"bind()");

//Retanyabortrequestifwe'reaskedtobindagain.

clearAbort();

if(!y()){

//Bindingalreadyinprogress,appendtothelistofcallbacksandbailout.

(callback);

return;

}

(callback);

if(mServiceConnection==null){

IntentrviceIntent=newIntent(mServiceAction).tComponent(mComponentName);

ServiceConnectionconnection=newServiceBinderConnection(call);

(call,_CS,mComponentName);

finalintbindingFlags=_AUTO_CREATE|_FOREGROUND_SERVICE;

finalbooleanisBound;

if(mUrHandle!=null){

isBound=rviceAsUr(rviceIntent,connection,bindingFlags,

mUrHandle);

}el{

isBound=rvice(rviceIntent,connection,bindingFlags);

}

if(!isBound){

handleFailedConnection();

return;

}

}el{

Log.d(,"Serviceisalreadybound.");

otNull(mBinder);

handleSuccessfulConnection();

}

}

可以看出果然去bind了rvice,然后绑定成功后,应该会回调ServiceBinderConnection的onServiceConnected:

publicvoidonServiceConnected(ComponentNamecomponentName,IBinderbinder){

try{

synchronized(mLock){

mCall=null;

if(mIsBindingAborted){

clearAbort();

logServiceDisconnected("onServiceConnected");

Service(this);

handleFailedConnection();

return;

}

mServiceConnection=this;

tBinder(binder);

handleSuccessfulConnection();

}

}finally{

sion();

}

}

可以看出在绑定成功后回调⽤tBinder(binder)来保存获取到的远程Binder对象,看看tBinder的实现:

privatevoidtBinder(IBinderbinder){

if(mBinder!=binder){

if(binder==null){

removeServiceInterface();

mBinder=null;

for(Listenerl:mListeners){

nd(this);

}

}el{

mBinder=binder;

tServiceInterface(binder);

}

}

}

可以看出如果绑定成功的话会调⽤tServiceInterface⽅法,该⽅法是ServiceBinder的⼀个抽象函数,看看ServiceBinder的⼦类

ConnectionServiceWrapper的实现:

@Override

protectedvoidtServiceInterface(IBinderbinder){

mServiceInterface=rface(binder);

Log.v(this,"AddingConnectionServiceAdapter.");

addConnectionServiceAdapter(mAdapter);

}

真相⼤⽩,原来mServiceInterface就是(callback,call)中绑定服务返回的远程Binder对象,下⾯分析到底bind了那个服

务,在bind函数中明确指定了Intent的ComponentName。

IntentrviceIntent=newIntent(mServiceAction).tComponent(mComponentName);

ServiceConnectionconnection=newServiceBinderConnection(call);

mComponentName是从哪⾥来的?

publicclassConnectionServiceWrapperextendsServiceBinder{

ConnectionServiceWrapper(

ComponentNamecomponentName,

ConnectionServiceRepositoryconnectionServiceRepository,

PhoneAccountRegistrarphoneAccountRegistrar,

CallsManagercallsManager,

Contextcontext,

otlock,

UrHandleurHandle){

super(E_INTERFACE,componentName,context,lock,urHandle);

mConnectionServiceRepository=connectionServiceRepository;

tener(er(){

});

mPhoneAccountRegistrar=phoneAccountRegistrar;

mCallsManager=callsManager;

mAppOpsManager=(AppOpsManager)temService(_OPS_SERVICE);

}

}

protectedServiceBinder(StringrviceAction,ComponentNamecomponentName,Contextcontext,

otlock,UrHandleurHandle){

tate(!y(rviceAction));

otNull(componentName);

mContext=context;

mLock=lock;

mServiceAction=rviceAction;

mComponentName=componentName;

mUrHandle=urHandle;

}

可以看出mComponentName是在构造ConnectionServiceWrapper对象时候传⼊的。回到attemptNextPhoneAccount⽅法中:

privateConnectionServiceWrappermService;

mService=vice(ponentName(),

rHandle());

publicConnectionServiceWrappergetService(ComponentNamecomponentName,UrHandleurHandle){

PaircacheKey=(componentName,urHandle);

ConnectionServiceWrapperrvice=(cacheKey);

if(rvice==null){

rvice=newConnectionServiceWrapper(

componentName,

this,

mPhoneAccountRegistrar,

mCallsManager,

mContext,

mLock,

urHandle);

tener(mUnbindListener);

(cacheKey,rvice);

}

returnrvice;

}

可以看出mComponentName来源于ponentName()(PhoneAccount为PhoneAccountHandle类型变

量,PhoneAccount类中有个成员变量PhoneAccountHandle,android有时候起得变量名容易让⼈混淆,PhoneAccountHandle主要

是保存了创建链接的服务的包名类名信息,PhoneAccount中包含了PhoneAccountHandle,还有最关键的该Account的Capabilities,

⽀持不⽀持语⾳通话等),现在问题⼜来了phoneAccount是怎么来的。对于PhoneAccount我理解就是可以安卓为了打电话功能可以扩

展新加的东西,现在我们⼿机⼤部分情况通过SIM卡打电话,⾛的是运营商⽹络,但是还有其他电话类型⽐如VOIP,具体我也不了解,所

以系统可能也可以有很多的PhoneAccount。当然现在我们还是⾛的标准的打电话流程,我们去看看SIM卡的PhoneAccount是在哪⾥创

建的。

在TelecomAccountRegistry中注册了PhoneAccount

privatePhoneAccountregisterPstnPhoneAccount(booleanisEmergency,booleanisDummyAccount){

StringdummyPrefix=isDummyAccount?"Dummy":"";

PhoneAccountHandlephoneAccountHandle=

tnPhoneAccountHandleWithPrefix(

mPhone,dummyPrefix,isEmergency);

PhoneAccountaccount=r(phoneAccountHandle,label)

.tAddress(rts(_TEL,line1Number,null))

.tSubscriptionAddress(

rts(_TEL,subNumber,null))

.tCapabilities(capabilities)

.tIcon(icon)

.tHighlightColor(color)

.tShortDescription(description)

.tSupportedUriSchemes((

_TEL,_VOICEMAIL))

.tExtras(instantLetteringExtras)

.tGroupId(groupId)

.build();

erPhoneAccount(account);

returnaccount;

}

此时我们关⼼的mComponentName就是在下⾯代码中创建的:

PhoneAccountHandlephoneAccountHandle=

tnPhoneAccountHandleWithPrefix(

mPhone,dummyPrefix,isEmergency);

在PhoneUtils中:

privatestaticfinalComponentNamePSTN_CONNECTION_SERVICE_COMPONENT=

newComponentName("",

"onyConnectionService");

可以看出是在phone进程中的⼀个服务,所以回到最上⾯的代码Connection(),其实调⽤的是

TelephonyConnectionService的createConnection⽅法,好,继续往下⾛(注意,此时后已经进⼊phone进程了,上⾯的所有操作都不

是在phone进程中的),发现TelephonyConnectionService没有实现该⽅法,⽤的⽗类ConnectionService的⽅法。该类代码路径为

frameworks/ba/telecomm/java/android/telecom/.给我们⼀个启⽰,我们想扩展电话功能需要继承实现该

类,并注册我们⾃⼰的PhoneAccount。

privatevoidcreateConnection(

finalPhoneAccountHandlecallManagerAccount,

finalStringcallId,

finalConnectionRequestrequest,

booleanisIncoming,

booleanisUnknown){

Connectionconnection=isUnknown?onCreateUnknownConnection(callManagerAccount,request)

:isIncoming?onCreateIncomingConnection(callManagerAccount,request)

:onCreateOutgoingConnection(callManagerAccount,request);

}

我们现在是呼出,所以调⽤的是onCreateOutgoingConnection,该⽅法在ConnectionService中是空的实现,所以⼜回到了

TelephonyConnectionService中,在onCreateOutgoingConnection中,代码很长我就不贴了,主要是创建了⼀个链接:

ConnectionresultConnection=getTelephonyConnection(request,numberToDial,

isEmergencyNumber,handle,phone);

然后处理该链接

placeOutgoingConnection((TelephonyConnection)resultConnection,phone,request);

重点就在该⽅法

privatevoidplaceOutgoingConnection(

TelephonyConnectionconnection,Phonephone,intvideoState,Bundleextras,

ConnectionRequestrequest){

tionoriginalConnection=null;

try{

if(phone!=null){

if(isAddParticipant){

ticipant(number);

return;

}el{

originalConnection=(number,null,eoState(),bundle);

}

}

}

}

终于,我们看见了我们想看见的,以下的情节就是俗套了,⼜调⽤CT(CallTracker)的dail⽅法,CT⼜调⽤

CI(CommandsInterface也就是RIL),最终java层拨号流程就已经分析完了,下篇⽂章想分析⼀下,打电话过程中和UI(InCallUI)的交

互。

本文发布于:2023-01-04 03:45:52,感谢您对本站的认可!

本文链接:http://www.wtabcd.cn/fanwen/fan/90/88403.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

下一篇:abandon
标签:emergencycall
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图