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

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() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            try {
                iMyAidlInterface.hi("");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public 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

@Override
    public 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, Handler
            handler, 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中,进行bindService
         	int 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里没有该sd
            if (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对象里的IServiceConnection
            return 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) {
				//在进程的主线程中执行RunConnection
                mActivityThread.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进程各个客户端的IServiceConnection
     ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);
        ...
      //检查服务端是否已启动,如果没启动调起服务端进程,则启动服务进程
      //>>>>>1
     if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
             return 0;
       }
 ...
 //服务端进程已经启动完成 && 服务端的binder对象已经发布给ams
            if (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 {  
            	//检查是否有待启动的service
                didSomething |= 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.app
        r.app = app;
       ...
			//通过app.thread得到目的进程(ActivityThread),调度service的onCreate()方法
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
    	...
		//请求服务端进程将binder对象句柄发布到ams
        requestServiceBindingsLocked(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 {
		...
				//跨进程调用服务端进程的scheduleBindService
                r.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发布到ams
                        ActivityManager.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的流程转化成简易流程图进行稳固各个步骤:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值