当前位置: 代码迷 >> 综合 >> 探究android-aidl---bindService的绑定及其内部原理
  详细解决方案

探究android-aidl---bindService的绑定及其内部原理

热度:62   发布时间:2023-12-02 12:35:08.0

bindService的用法

    private IMyAidlInterface iMyAidlInterface;private void bindService() {Intent intent = new Intent();intent.setComponent(new ComponentName("com.example.aidlserver", "MyService"));bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);}private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);try {iMyAidlInterface.hi("");} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {}};

bindService的大致流程

bindService涉及哪些参与者
1.客户端进程(请求端) 2.系统进程   3.serviceManager进程  4. 服务端进程
通讯过程是怎样的?

1. bindService时传递的ServiceConnection参数
在绑定服务时调用bindService(Intent service, ServiceConnection conn, int flags),在绑定成功后的ServiceConnection对象里onServiceConnected()将会收到服务端传来的代理对象。所以先从bindService时传入的ServiceConnection对象开始探究,这个ServiceConnection对象如何被保存?如何通过ServiceConnection对象回调服务代理对象?
根据bindService()源码看下:
frameworks\base\core\java\android\app\ContextImpl.java

@Overridepublic boolean bindService(Intent service, ServiceConnection conn,int flags) {warnIfCallingFromSystemProcess();return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), getUser());}

接着看下bindServiceCommon():
frameworks\base\core\java\android\app\ContextImpl.java

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handlerhandler, UserHandle user) {// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.IServiceConnection sd;...if (mPackageInfo != null) {//根据请求时传入的ServiceConnection获取IServiceConnection对象sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);} ...// IServiceConnection对象传入到ams中,进行bindServiceint res = ActivityManager.getService().bindService(mMainThread.getApplicationThread(), getActivityToken(), service,service.resolveTypeIfNeeded(getContentResolver()),  sd, flags, getOpPackageName(), user.getIdentifier());...}

接下来再看下 mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
这里怎么根据请求时传入的ServiceConnection获取IServiceConnection对象,这个IServiceConnection对象有什么用处?
frameworks\base\core\java\android\app\LoadedApk.java

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,Context context, Handler handler, int flags) {synchronized (mServices) {LoadedApk.ServiceDispatcher sd = null;// ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices// mServices中存着当前进程所有请求绑定服务的context和对应的接收服务的派遣对象ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);//如果当前上下文从未绑定过服务则map为空if (map != null) {if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);// 根据ServiceConnection获取ServiceDispatcher对象;// ServiceDispatcher用于系统进程返回服务代理给客户端时的派遣sd = map.get(c);}//如果当前ServiceConnection首次传入绑定服务时,map里没有该sdif (sd == null) {//新建ServiceDispatcher对象sd = new ServiceDispatcher(c, context, handler, flags);if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);if (map == null) {map = new ArrayMap<>();mServices.put(context, map);}//把新建ServiceDispatcher对象存储在mServices和map里map.put(c, sd);} else {sd.validate(context, handler);}//返回ServiceDispatcher对象里的IServiceConnectionreturn sd.getIServiceConnection();}}

接下来看看ServiceDispatcher的构造方法
frameworks\base\core\java\android\app\LoadedApk.java

 ServiceDispatcher(ServiceConnection conn,Context context, Handler activityThread, int flags) {// getIServiceConnection() 里返回的就是 mIServiceConnection 对象mIServiceConnection = new InnerConnection(this);mConnection = conn;mContext = context;mActivityThread = activityThread;mLocation = new ServiceConnectionLeaked(null);mLocation.fillInStackTrace();mFlags = flags;}

接下来看看InnerConnection的构造方法:
frameworks\base\core\java\android\app\LoadedApk.java

	private static class InnerConnection extends IServiceConnection.Stub {final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;InnerConnection(LoadedApk.ServiceDispatcher sd) {//弱引用持有传入的ServiceDispatcher对象mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);}//InnerConnection里只有一个实现方法connected()public void connected(ComponentName name, IBinder service, boolean dead)throws RemoteException {LoadedApk.ServiceDispatcher sd = mDispatcher.get();if (sd != null) {//当有跨进程调用 InnerConnection.connected()时,调用 ServiceDispatcher.connect()sd.connected(name, service, dead);}}}

frameworks\base\core\java\android\app\LoadedApk.java

public void connected(ComponentName name, IBinder service, boolean dead) {if (mActivityThread != null) {//在进程的主线程中执行RunConnectionmActivityThread.post(new RunConnection(name, service, 0, dead));} else {doConnected(name, service, dead);}}

接下来看下RunConnection的run()方法:
frameworks\base\core\java\android\app\LoadedApk.java

private final class RunConnection implements Runnable {...public void run() {if (mCommand == 0) {//调用doConnected()方法doConnected(mName, mService, mDead);} else if (mCommand == 1) {doDeath(mName, mService);}}...}

再继续看下doConnected():
frameworks\base\core\java\android\app\LoadedApk.java

 public void doConnected(ComponentName name, IBinder service, boolean dead) {ServiceDispatcher.ConnectionInfo old;ServiceDispatcher.ConnectionInfo info;synchronized (this) {if (mForgotten) {// We unbound before receiving the connection; ignore// any connection received.return;}//检查已绑定的服务中是否有包含该服务old = mActiveConnections.get(name);//如果已绑定的服务中有包含该服务,则返回if (old != null && old.binder == service) {// Huh, already have this one.  Oh well!return;}if (service != null) {// A new service is being connected... set it all up.info = new ConnectionInfo();info.binder = service;info.deathMonitor = new DeathMonitor(name, service);try {//监听服务的生命周期service.linkToDeath(info.deathMonitor, 0);//在mActiveConnections中加入已绑定这个服务的记录mActiveConnections.put(name, info);} catch (RemoteException e) {// This service was dead before we got it...  just// don't do anything with it.mActiveConnections.remove(name);return;}} ...if (old != null) {// 该ServiceConnection之前用于绑定别的服务,但一个ServiceConnection对象只能对应一个服务的绑定操作,// 所以要把ServiceConnection所绑定旧的服务给解绑mConnection.onServiceDisconnected(name);}...if (service != null) {//在客户端传入的ServiceConnection对象mConnection中回调onServiceConnected()方法,把服务端代理对象返回传给客户端mConnection.onServiceConnected(name, service);} ...}

在这里插入图片描述
在这小节中可得:客户端在绑定服务时,传入的ServiceConnection,会被封装成IServiceConnection对象,用于服务端回调代理类时的跨进程通讯到客户端中。

2. bindService在ams中的调度流程
接下来再来看下ams中bindService():
frameworks\base\core\java\android\app\ActivityManagerService.java

public int bindService(IApplicationThread caller, IBinder token, Intent service,String resolvedType, IServiceConnection connection, int flags, String callingPackage,int userId) throws TransactionTooLargeException {...synchronized(this) {//mServices为ActiveServices对象,ActiveServices用于系统内的所有服务的调度操作return mServices.bindServiceLocked(caller, token, service,resolvedType, connection, flags, callingPackage, userId);}}

\frameworks\base\services\core\java\com\android\server\am\ActiveServices.java

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,String resolvedType, final IServiceConnection connection, int flags,String callingPackage, final int userId) throws TransactionTooLargeException {...// 根据请求的Intent去查找ServiceLookupResult,// 每个进程的每个Service都在ActiveServices中的mServiceMap对象里保存着ServiceRecord对象// 如果mServiceMap对象里没有找到ServiceRecord对象,则到pms处目的Service基本资料(包名类名信息等),// 再保存至ActiveServices中的mServiceMap对象。ServiceLookupResult res =retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),Binder.getCallingUid(), userId, true, callerFg, isBindExternal, allowInstant);if (res == null) {return 0;}if (res.record == null) {return -1;}ServiceRecord s = res.record;...//AppBindRecord 记录了Service与应用程序进程之间的关联,//例如 被绑定的service 与 绑定Service进程 的IntentBindRecord等等//AppBindRecord对象b 中记录请求绑定客户端AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);//ConnectionRecord 记录了服务端Service进程各个客户端的IServiceConnectionConnectionRecord c = new ConnectionRecord(b, activity,connection, flags, clientLabel, clientIntent);...//检查服务端是否已启动,如果没启动调起服务端进程,则启动服务进程//>>>>>1if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,permissionsReviewRequired) != null) {return 0;}...//服务端进程已经启动完成 && 服务端的binder对象已经发布给amsif (s.app != null && b.intent.received) {// Service is already running, so we can immediately// publish the connection.try {//调用c.con.connected//c.con是IServiceConnection类型,这里保存的是客户端的IServiceConnection对象,可跨进程通讯//IServiceConnection中保存了bindService时传入的ServiceConnection。c.conn.connected(s.name, b.intent.binder, false);}...}    //ams未向服务端进程请求过binder对象else if (!b.intent.requested) {//请求服务端进程进行发布binder			 requestServiceBindingLocked(s, b.intent, callerFg, false);}
}

在前面的ServiceLookupResult 、ServiceRecord 、AppBindRecord 、ConnectionRecord 之间的关系如下图所示:
在这里插入图片描述

>>>>1 处代码解析

\frameworks\base\services\core\java\com\android\server\am\ActiveServices.java

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,boolean whileRestarting, boolean permissionsReviewRequired)throws TransactionTooLargeException {//目的service的应用存在且整在系统中运行,且ServiceRecord r 对象的app 已经被赋值if (r.app != null && r.app.thread != null) {//调度目的service的onStartCommand()方法,并退出当前方法。如果待onStartCommand的队列为空则直接退出该方法//由于此次是调用bindService(),所以待onStartCommand的队列为空。sendServiceArgsLocked(r, execInFg, false);return null;}...	//根据目的service的包名,向ams获取目的service进程的ProcessRecord实例app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);if (app != null && app.thread != null) {try {app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);//在realStartServiceLocked()里://赋值 ServiceRecord变量 r 的app参数 、调用服务端的Service.onCreate、判断服务端binder是否在ams上发布过realStartServiceLocked(r, app, execInFg);return null;} ...}//如果在ams中没获取到目的service的程序信息,则说明目的service的进程未启动if ((app == null || (app != null && app.pid == 0)) && !permissionsReviewRequired) {...//启动目的进程if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,hostingType, r.name, false, isolated, false)) == null)...}//排队待启动service的列表中未包含该service记录,则加入排队队列if (!mPendingServices.contains(r)) {mPendingServices.add(r);}...}

在服务端app被启动后。服务端app调用ams.attachApplication()进行通知app进程创建成功。
ams在attachApplicationLocked()中:

frameworks\base\core\java\android\app\ActivityManagerService.java

 @GuardedBy("this")private final boolean attachApplicationLocked(IApplicationThread thread,int pid, int callingUid, long startSeq) {
...// Find any services that should be running in this process...if (!badApp) {try {  //检查是否有待启动的servicedidSomething |= mServices.attachApplicationLocked(app, processName);checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");} catch (Exception e) {Slog.wtf(TAG, "Exception thrown starting services in " + app, e);badApp = true;}}
...}

\frameworks\base\services\core\java\com\android\server\am\ActiveServices.java

  boolean attachApplicationLocked(ProcessRecord proc, String processName)throws RemoteException {...// Collect any services that are waiting for this process to come up.//查看是否有service在排队队列待初始化if (mPendingServices.size() > 0) {ServiceRecord sr = null;try {for (int i=0; i<mPendingServices.size(); i++) {...//realStartServiceLocked中将ServiceRecord实例sr的app对象赋值且执行service的onCreate()realStartServiceLocked(sr, proc, sr.createdFromFg);didSomething = true;...}

\frameworks\base\services\core\java\com\android\server\am\ActiveServices.java

private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app, boolean execInFg) throws RemoteException {if (app.thread == null) {throw new RemoteException();}if (DEBUG_MU)Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid+ ", ProcessRecord.uid = " + app.uid);//赋值r.appr.app = app;...//通过app.thread得到目的进程(ActivityThread),调度service的onCreate()方法app.thread.scheduleCreateService(r, r.serviceInfo,mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),app.repProcState);...//请求服务端进程将binder对象句柄发布到amsrequestServiceBindingsLocked(r, execInFg);...}

\frameworks\base\services\core\java\com\android\server\am\ActiveServices.java

private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)throws TransactionTooLargeException {for (int i=r.bindings.size()-1; i>=0; i--) {// 遍历要绑定服务端的IntentBindRecord对象// IntentBindRecord 记录了绑定serviced的请求intent和binder对象的相关状态//r.bindings对象是在bindServiceLocked()时调用ServiceRecord.retrieveAppBindingLocked()时候加入IntentBindRecord ibr = r.bindings.valueAt(i);if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {break;}}}

\frameworks\base\services\core\java\com\android\server\am\ActiveServices.java

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,boolean execInFg, boolean rebind) throws TransactionTooLargeException {...//跨进程调用服务端进程的scheduleBindServicer.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,r.app.repProcState);...
}

服务端进程scheduleBindService(),调度到handleBindService()进行:
\frameworks\base\core\java\android\app\ActivityThread.java

    private void handleBindService(BindServiceData data) {...//判断该服务是否被绑定过if (!data.rebind) {IBinder binder = s.onBind(data.intent);//没被绑定过的服务,把服务binder发布到amsActivityManager.getService().publishService(data.token, data.intent, binder);}...}

frameworks\base\core\java\android\app\ActivityManagerService.java

  public void publishService(IBinder token, Intent intent, IBinder service) {...mServices.publishServiceLocked((ServiceRecord)token, intent, service);...}

ActiveServices.java

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {...IntentBindRecord b = r.bindings.get(filter);if (b != null && !b.received) {b.binder = service;b.requested = true;b.received = true;//遍历请求绑定的ConnectionRecord 内含用于跨进程通讯的 客户端给IServiceConnection对象for (int conni=r.connections.size()-1; conni>=0; conni--) {ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);...try {//调用IServiceConnection对象的connected(),即可回调IBinder对象到客户端c.conn.connected(r.name, service, false);} ...}

代码走到IServiceConnection.connected(),算是成功把binder对象放回到客户端。
(关于IServiceConnection.connected()的执行调度到ServiceConnection.onServiceConnected()流程在上一小节进行分析)

小结

将bindService的流程转化成简易流程图进行稳固各个步骤:
在这里插入图片描述

  相关解决方案