文章目录
回顾
Service启动系列总结:
《Service启动流程总结-start和stop service》
概述
在开发中我们使用Context#bindService和Context#unbindService来绑定和解绑Service,通过绑定来启动Service,可以方便的调用Service提供的API。Service的bind、unbind过程和start、stop过程类似,比较大的区别是多了Binder的传递过程。
基本使用
- 定义AIDL文件
// ISpeaker.aidl
package com.cdh.study;
// Declare any non-default types here with import statements
interface ISpeaker {
String sayHello();
}
- 定义Server端
public class SpeakerService extends Service {
// 创建由aidl文件自动生成的Stub实例
private final ISpeaker.Stub mSpeakerBinder = new ISpeaker.Stub() {
@Override
public String sayHello() throws RemoteException {
return "hello!";
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
// 返回Stub实例
return mSpeakerBinder;
}
}
在Service的onBind回调中返回创建的ISpeaker.Stub实例,Stub继承Binder和ISpeaker。Client端在成功连接后便可通过其调用Server端的sayHello方法。
- 定义Client端
// Server端API接口,若Client和Server处于同一进程则返回的即是Server端binder实例,否则是Server端binder代理
private ISpeaker mISpeaker;
// 创建ServiceConnection实例,用作回调接口
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 连接回调,service即Server端onBind返回的IBinder
mISpeaker = ISpeaker.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 断连回调
mISpeaker = null;
}
};
public void bind() {
// 绑定Server
mContext.bindService(new Intent(mContext, SpeakerService.class), mConnection, Context.BIND_AUTO_CREATE);
}
public void unbind() {
// 解绑Server,需要传入绑定时的ServiceConnection接口(内部以ServiceConnection作为key)
mContext.unbindService(mConnection);
}
- 调用Server端提供的API
public void requestHello() {
if (mISpeaker != null) {
try {
// 调用Service方法,会返回"hello!"
mISpeaker.sayHello();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
Client端首先进行绑定Service,成功绑定后会回调ServiceConnection的onServiceConnected方法,在这里获取Server端binder实例或binder代理,之后便可通过binder来调用Server端API。
以上是一个bind service的简单例子,接下来跟踪源码调用看看bind service的整体流程。
源码探究
文中源码基于 Android 10.0
bind过程
Caller发起bind
Caller指调用方,发起bind service,将会调用ContextImpl的bindService方法:
[ContextImpl#bindService]
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
// 传入意图、ServiceConnection实例、BIND_AUTO_CREATE(表示目标Service未启动时自动创建)和主线程Handler和当前用户具柄
return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
getUser());
}
[ContextImpl#bindServiceCommon]
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
// binder通信接口,用于AMS向Caller进程通信
IServiceConnection sd;
// ···
if (mPackageInfo != null) {
if (executor != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
} else {
// 此时executor是null,执行这个case获取IServiceConnection
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
}
} else {
throw new RuntimeException("Not supported in system context");
}
// 省略显示意图校验 ···
try {
IBinder token = getActivityToken();
// ···
// 请求AMS进行bind流程
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
该方法中先获取IServiceConnection,然后调用AMS的bindIsolatedService方法。
IServiceConnection说明
在前面的基本使用例子中,Client端通过ServiceConnection接口回调获取Server端binder。但ServiceConnection只是一个普通接口,不支持跨进程通信。因此这里利用IServiceConnection进行AMS向Caller进程调用时的binder通信接口。
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
上文通过这个方法获取IServiceConnection,mPackageInfo是LoadedApk,进入方法看看。
[LoadedApk#getServiceDispatcher]
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
return getServiceDispatcherCommon(c, context, handler, null, flags);
}
[LoadedApk#getServiceDispatcherCommon]
private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
Context context, Handler handler, Executor executor, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
// ···
if (sd == null) {
if (executor != null) {
sd = new ServiceDispatcher(c, context, executor, flags);
} else {
// 创建ServiceDispatcher
sd = new ServiceDispatcher(c, context, handler, flags);
}
// ···
} else {
// ···
}
// 返回其中的mIServiceConnection成员
return sd.getIServiceConnection();
}
}
这里省略了判断缓存的部分,若没有缓存,则新建ServiceDispatcher包装传入的参数。
接着看ServiceDispatcher构造方法:
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int flags) {
mIServiceConnection = new InnerConnection(this);
mConnection = conn;
mContext = context;
mActivityThread = activityThread;
mActivityExecutor = null;
mLocation = new ServiceConnectionLeaked(null);
mLocation.fillInStackTrace();
mFlags = flags;
}
ServiceDispatcher会持有InnerConnection和ServiceConnection。
InnerConnection继承IServiceConnection.Stub,它实现了IServiceConnection的connected方法:
private static class InnerConnection extends IServiceConnection.Stub {
@UnsupportedAppUsage
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
// 利用弱引用持有ServiceDispatcher
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}

本文详细介绍了Android中Service的绑定(bind)和解绑(unbind)过程,包括 Caller 发起bind请求,AMS处理bind,Service处理bind请求,AMS发布Service,以及 Caller 处理连接回调等步骤。同时,文章还分析了解绑过程,包括从Caller发起unbind请求,AMS解绑Service,以及Service执行onUnbind回调等。整个流程涉及AMS、Service、Binder通信等多个关键环节。
1万+

被折叠的 条评论
为什么被折叠?



