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的流程转化成简易流程图进行稳固各个步骤: