bindService() 调用流程

API 28

一、bindService() 调用流程时序图

bindService() 调用流程

二、bindService() 调用流程文字描述

多次编写,欢迎交流,如有错误,感谢指正

ContextImpl#bindService(Intent service, ServiceConnection conn, int flags) ->
	ContextImpl#bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) ->
		// mPackageInfo 类型为 LoadedApk
		// getServiceDispatcher() 方法调用了 LoadedApk#ServiceDispatcher#getServiceDispatcher(),最终返回 LoadedApk#ServiceDispatcher#InnerConnection
		// sd:LoadedApk#ServiceDispatcher#InnerConnection,InnerConnection 是 ServiceDispatcher.Stub 的子类(Binder 类型对象),因此 sd 对象可以跨进程传递
			// InnerConnection extends IServiceConnection.Stub
		IServiceConnection sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
		// ########################### 从客户端进程转到 AMS 所在进程 ###########################
		// 需要注意的是,当前在客户端进程,sd(ServiceDispatcher.Stub 的子类)这个 Binder 对象跨进程传递到 AMS 所在进程后,AMS 收到的是 BinderProxy 对象
		ActivityManager.getService().bindService(..., sd, flags, ...) ->
			// 参数 connection 就是上面的 sd
				// sd:LoadedApk#ServiceDispatcher#InnerConnection,InnerConnection 是 ServiceDispatcher.Stub 的子类(Binder 类型对象)
			ActiveServices#bindServiceLocked(..., final IServiceConnection connection, int flags, ...) ->
				ServiceLookupResult res = retrieveServiceLocked(...) ->
					// 有个 ServiceMap 内部类,用于绑定用户和其对应的 Service
					ServiceMap smap = getServiceMapLocked(userId);
					// comp 默认不为空
					final ComponentName comp = service.getComponent();
					从 smap 中获取 ServiceRecord 对象:
						a 若存在,则取出
						b 若不存在,则创建 ServiceRecord 对象
					作为参数构造 ServiceLookupResult 对象实例后返回
				ServiceRecord s = res.record;
				// 往 ServiceRecord#bindings 添加键值对(ServiceRecord#bindings 默认为空,具体添加的什么不用关心,重要的是下面 requestServiceBindingsLocked() 方法中会用到)
				AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
				// 当前在 AMS 所在进程
				// 把 connection 赋给 ConnectionRecord#conn(下面 publishServiceLocked() 方法中会用到)
					// connection 是 LoadedApk#ServiceDispatcher#InnerConnection
					// InnerConnection 是 ServiceDispatcher.Stub 的子类(Binder 类型对象)
				ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent);
				IBinder binder = connection.asBinder();
	            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
	            if (clist == null) {
	                clist = new ArrayList<ConnectionRecord>();
	                // 给 ServiceRecord#connections 添加键值对(具体添加的什么不用关心,重要的是下面 publishServiceLocked() 方法中会用到)
	                	// s 类型为 ServiceRecord
	                s.connections.put(binder, clist);
	            }
	            // 如果 ContextImpl#bindService() 第三个参数 flags 带有 BIND_AUTO_CREATE,则调用 bringUpServiceLocked()
				bringUpServiceLocked() ->
					// 如果没有调用 realStartServiceLocked(),则跳过当前 if
						// r.app:默认为 null,在下面 realStartServiceLocked() 方法中被赋值
					// 如果调用了 realStartServiceLocked()
						// Service 所在进程启动完成,且应用进程也向 AMS 报告过了(AMS 持有 IApplicationThread 应用端 Binder 句柄)
					if (r.app != null && r.app.thread != null) {
						// bindService() 不用关注这个方法,该方法内部是 startService() 相关的逻辑(内部调用 Service#onStartCommand() 方法)
						sendServiceArgsLocked(r, execInFg, false);
						return null;
					}
					// 如果 Service 所在进程不存在,则跳过当前 if
					// 如果 Service 所在进程存在
						// Service 所在进程启动完成,且应用进程也向 AMS 报告过了(AMS 持有 IApplicationThread 应用端 Binder 句柄),接下来反射创建 Service
					if (app != null && app.thread != null) {
						realStartServiceLocked() ->
							ActivityThread#ApplicationThread#scheduleCreateService()
								// 从 AMS 所在进程转到客户端进程
								ActivityThread#handleCreateService() ->
									// 获取 LoadedApk 实例
									LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
									// instantiateService() 方法反射创建 Service 实例
									service = packageInfo.getAppFactory().instantiateService(cl, data.info.name, data.intent); // 创建 Service
									// 创建 ContextImpl 实例
									ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
									// 将创建的 Service 设置为 ContextImpl 的 mOuterContext
									context.setOuterContext(service);
									// 创建 Application(有就不创建,没有就创建)
									packageInfo.makeApplication(false, mInstrumentation);
									// 给 Service 设置上下文
									service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService());
									// 调用 Service#onCreate()
									service.onCreate();
							// 当前在 AMS 所在进程
							// 内部 for 循环遍历 ServiceRecord#bindings,调用 requestServiceBindingLocked()
							requestServiceBindingsLocked() ->
								requestServiceBindingLocked() ->
									// 准备发布 Service
									// ########################### 从 AMS 所在进程转到客户端进程 ###########################
									ActivityThread#ApplicationThread#scheduleBindService()
										ActivityThread#handleBindService()
											// 调用 Service#onBind(),一般返回的是 AIDL 的 Stub 的实现类
											IBinder binder = s.onBind(data.intent);
											// ########################### 从客户端进程转到 AMS 所在进程 ###########################
											// 客户端调用 AMS#publishService() 方法发布服务(这是一个跨进程调用)
												// 应用端发布的服务是 AIDL 的 Stub 的实现类,类型为 Binder
												// AMS 端收到的是服务对应的 BinderProxy 对象
											// 同时会传递 binder(类型为 BinderProxy)作为最终 onServiceConnected(name, service) 方法的第二个参数
											ActivityManager.getService().publishService(..., binder)
												ActivityManagerService#publishService(IBinder token, Intent intent, IBinder service)
													ActiveServices#publishServiceLocked(ServiceRecord r, Intent intent, IBinder service)
														IntentBindRecord b = r.bindings.get(filter);
														b.binder = service;
														b.requested = true;
														b.received = true;
														// for 循环遍历 r.connections(ServiceRecord#connections)
														// ########################### 从 AMS 所在进程转到客户端进程 ###########################
															// conn:ConnectionRecord 类的成员变量 IServiceConnection(conn 对应上面 new ConnectionRecord() 时传入的第三个参数)
															// 一直往上找,该参数是在一开始的 ContextImpl#bindServiceCommon() 中被赋值为 sd,实际类型为 LoadedApk#ServiceDispatcher#InnerConnection,InnerConnection 是 ServiceDispatcher.Stub 的子类(Binder 类型对象)
															// 需要注意的是,当前是 AMS 所在进程,AMS 持有的是 sd(ServiceDispatcher.Stub 的子类)对应的 BinderProxy 对象
															// 所以 AMS 调用 conn.connected(),实际上跨进程调用的是客户端进程 sd(ServiceDispatcher.Stub 的子类)的 connected() 方法,即 LoadedApk#ServiceDispatcher#InnerConnection#connected()
														c.conn.connected(r.name, service, false);
															LoadedApk.ServiceDispatcher sd = mDispatcher.get();
															sd.connected(name, service, dead);
																// mActivityThread 是在 ContextImpl#bindService() 中被赋值,类型为 Handler,不为空
																if (mActivityThread != null) {
																	// 当前在客户端进程
																	// 通过 Handler 把线程从 Binder 线程池切换到应用主进程
																	// RunConnection implements Runnable,查看其 run() 方法
																	mActivityThread.post(new RunConnection(name, service, 0, dead));
																		RunConnection#run()doConnected(mName, mService, mDead);
																				// 这里的 service 是从 ActivityThread#handleBindService() 方法中传下来的
																				//	IBinder binder = s.onBind(data.intent);
																				//	ActivityManager.getService().publishService(data.token, data.intent, binder);
																				// publishService() 方法的第三个参数 binder 是 onServiceConnected() 方法的第二个参数 service
																				// 而 binder 是 Service#onBind() 的返回值,这也是我们平时在写 Service#onBind() 方法时,方法要返回一个远程 Binder 接口的实现类
																				// 且 mConnection 是我们在代码中创建的 ServiceConnection 实例,通过 ContextImpl#bindService() 传下来
																				// 因此这也是在 Connection#onServiceConnected() 方法中就能获取到远程 Binder 本地代理的原因
																				mConnection.onServiceConnected(name, service);
																} else {
																	doConnected(name, service, dead);
																}
							// bindService() 不用关注这个方法,该方法内部是 startService() 相关的逻辑(内部调用 Service#onStartCommand() 方法)
							sendServiceArgsLocked(r, execInFg, true);
						return null;
					}
					// Service 所在进程不存在(略),走这里
						// 启动 Service 所在进程
						// 反射创建 Service,调用 Service#onCreate()(不涉及 bindService() 逻辑)
				return 0;
				// 不带 BIND_AUTO_CREATE
				// 应用进程启动了(s.app:Service 对应的 ProcessRecord 不为空),且 Service 的 Binder 对象已经发布给 AMS 了(是否发布,就看 received 是否为 true)
    				// b.intent.received:当前为默认 false,在上面调用 publishService() 方法时 IntentBindRecord#received 被置为 true
    					// b:AppBindRecord
    					// b.intent:IntentBindRecord
				if (s.app != null && b.intent.received)
					// 当前在 AMS 所在进程
					// Service 已经启动,现在开始连接
					// b.intent.binder:在上面调用 publishService() 方法时 IntentBindRecord#binder 赋值为 Service#onBind() 这个服务对应的 BinderProxy 对象
						// b:AppBindRecord
    					// b.intent:IntentBindRecord
					c.conn.connected(s.name, b.intent.binder, false);
    			// 不带 BIND_AUTO_CREATE
			    // Service 的 Binder 对象当然还未发布给 AMS(是否发布,就看 received 是否为 true)
			        // 情况一:应用进程没启动,requestServiceBindingLocked() 直接返回,bindService() 流程结束(也就是说,在要绑定的 Service 所在的进程不存在情况下调用 bindService(),且 bindService() 第三个参数不带 BIND_AUTO_CREATE,那么 bindService() 不会帮忙创建要绑定的 Service 所在的进程)
			            // 调用 bindService() 方法时,会在 bringUpServiceLocked() 方法中创建要绑定的 Service 所在的进程
			        // 情况二:应用进程启动了
			    // b.intent.requested:当前为默认 false,在 bindService 过程中调用 publishService() 时被置为 true
				else if (!b.intent.requested)
					requestServiceBindingLocked()

三、onServiceConnected() 第二个参数类型是 BinderProxy?

代码中 onBind() 的返回值是 Stub,为什么 onServiceConnected() 第二个参数接收到的类型是 BinderProxy

// publishService() 方法的第三个参数 binder 是 onServiceConnected() 方法的第二个参数 service,参数类型为 BinderProxy
mConnection.onServiceConnected(name, service);

Java 层:Parcel#readStrongBinder() 方法返回的是 BinderProxy
在这里插入图片描述
AMS 通过 publishService() 方法通知客户端 Service 已创建完毕(这是一个跨进程调用,应用端 ActivityManagerService 向 ServiceManager 注册服务,应用端 ActivityManagerService 收到的 binder 返回值,类型为 BinderProxy)

代码实测:bindService() 第二个参数 ServiceConnection 的 onServiceConnected 回调的第二个参数 service 实际类型是 BinderProxy
bindService() 第二个参数 ServiceConnection 的 onServiceConnected 回调的第二个参数 service 实际类型是 BinderProxy

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值