bindservice
一 前言
通过startservice来启动一个service,通常该service是无法返回结果的(这也是与bindservice的区别之一),服务开启, 这个服务和开启他的调用者之间就没有任何的关系了,调用者的生命周期和它的生命周期也没有关系(所以,service在任务完成的时调用stopSelf或stopsService来结束该服务)。
通过bindservice来和service绑定,绑定后可以和service交互,发送请求,得到结果甚至执行IPC通信。由于调用者和绑定者绑在一起,调用者一旦退出该服务也就终止了。
可以先看Android组件管理框架—后台服务Service之startService方式启动流程(android p)。
二 图示调用流程
图示调用流程展示的是主要调用流程。
三 代码具体流程
调用者调用bindService后将会调用下面的方法。
1 frameworks/base/core/java/android/content/contextWrAPPer.java
@Override
public boolean bindService(intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
这里mBase变量是ContextImpl类型,是在创建activity的时候,new 一个ContextImpl对象,赋值给activity的。
2 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里的mMainThread.getHandler,其中mMainTharead是activitythread的实例,可以先看下 mMainThread.getHandler的方法。
3 frameworks/base/core/java/android/app/ActivityThread.java
final H mH = new H();
final Handler getHandler() {
return mH;
}
这个是ActivityThread的内部类H的实例,H类继承Hander。
接着看上面的bindServiceCommon方法。
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
if (conn == null) {
throw new illegalargumentException("connection is null");
}
if (mPackageInfo != null) {
//位置1
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new runtimeexception("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_priority;
}
service.prepareToLeaveProcess(this);
//位置2
int res = activitymanager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfneeded(getContentResolver()),
sd, flags, 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();
}
}
先看位置1的mPackageInfo.getServiceDispatcher 。
4 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<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
sd = map.get(c);
}
if (sd == null) {
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);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
在getServiceDispatcher函数中,传进来的参数context是一个调用bindService的activity实例,先以它为Key值在mServices中查看是否已经存在相应的ServiceDispatcher实例,如果有则不用创建直接取出。在该情景中,需要创建一个新的ServiceDispatcher。在创建新的ServiceDispatcher实例过程中,将上面传下来ServiceConnection参数c和Hanlder参数保存在ServiceDispatcher实例的内部,并创建一个InnerConnection对象,它是一个Binder对象,会传递给ActivityManagerService,ActivityManagerServic后续则要通过该Binder对象和ServiceConnection通信。函数getServiceDispatcher最后就是返回了一个InnerConnection对象给ContextImpl.bindService函数。回到ContextImpl.bindService函数中,它接着就要调用ActivityManagerService的远程接口来进一步处理。
看一下ServiceDispatcher,是LoadedApk的内部类。
static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
private final ServiceConnection mConnection;
private final Context mContext;
private final Handler mActivityThread;
private final ServiceConnectionLeaked mLocation;
private final int mFlags;
private RuntimeException mUnbindLocation;
private boolean mForgotten;
private static class ConnectionInfo {
IBinder binder;
IBinder.DeathRecipient deathmonitor;
}
private static class InnerConnection extends IServiceConnection.Stub {
final weakreference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(componentname name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
}
...
}
LoadedApk、ServiceDispatcher、ServiceDispatcher.InnerConnection、ServiceConnection之间的具体关系暂不讨论。
再看位置2的ActivityManager.getService().bindService,返回的ActivityManagerService实例和startActivity的流程是一样的,所以直接看ActivityManagerService的bindService方法。
5 frameworks/base/core/java/android/app/ActivityManager.java
6 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
调用到系统进程来了。
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws transactionTooLargeException {
enforceNotIsolatedCaller("bindService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
synchronized(this) {
//位置1
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
位置1的mServices是ActiveServices的实例,看它的调用方法bindServiceLocked。
7 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 {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
+ " flags=0x" + integer.toHexString(flags));
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when binding service " + service);
}
ActivityRecord activity = null;
if (token != null) {
activity = ActivityRecord.isInStackLocked(token);
if (activity == null) {
Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;
}
}
int clientLabel = 0;
PendingIntent clientIntent = null;
final boolean isCallerSystem = callerApp.info.uid == Process.SYSTEM_UID;
//retrieveServiceLocked解析service这个Intent,也是解析Androidmanifest.xml定义的
//Service标签的intent-filter相关内容,将解析结果放在res.record中。
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true);
...
try {
...
mAm.startassociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
s.appInfo.uid, s.name, s.processName);
// Once the apps have become associated, if one of them is caller is ephemeral
// the target app should now be able to see the calling app
mAm.grantEphemeralAccessLocked(callerApp.userId, service,
s.appInfo.uid, UserHandle.getAppId(callerApp.uid));
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
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>();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c);
...
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//位置1
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsreviewrequired) != null) {
return 0;
}
}
...
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
函数首先根据传进来的参数token是启动service的activity在ActivityManagerService里面的一个令牌,通过这个令牌就可以将这个activity对应的的ActivityRecord取回来。
看位置1的bringUpServiceLocked。
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
//Slog.i(TAG, "bring up service:");
//r.dump(" ");
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
...
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
String hostingType = "service";
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
//位置1
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
...
}
...
return null;
}
看位置1的realStartServiceLocked。
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
mAm.updateOomAdjLocked();
boolean created = false;
try {
...
//位置1
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postnotification();
created = true;
...
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
//位置2
requestServiceBindingsLocked(r, execInFg);
...
//位置3
sendServiceArgsLocked(r, execInFg, true);
...
}
位置1的scheduleCreateService与startService的流程是一样的,可以回看之前的Android组件管理框架—后台服务Service之startService方式启动流程(Android P)。位置1的scheduleCreateService方法最终会调到Service的onCreate方法;位置3的scheduleCreateService方法最终会调到Service的onStartCommond方法。我们看位置2的requestServiceBindingsLocked方法。
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
//位置1
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
看位置1的requestServiceBindingLocked。
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can't yet bind.
return false;
}
if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
+ " rebind=" + rebind);
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//位置1
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
...
}
...
return true;
}
看位置1的app.thread.scheduleBindService,r.app.thread是ApplicationThread的实例,ApplicationThread是ActivityThread的内部类。
8 frameworks/base/core/java/android/app/ActivityThread.java
调用到调用者对应的进程。
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false);
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
s.rebind = rebind;
if (DEBUG_SERVICE)
Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
sendmessage(H.BIND_SERVICE, s);
}
发送消息H.BIND_SERVICE。H也是ActivityThread的内部类,并继承Handler。
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
接收到这个消息后进行处理,调用handleBindService方法。
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (DEBUG_SERVICE)
Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
//位置1
IBinder binder = s.onBind(data.intent);
//位置2
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
位置1的onBind方法。
9 frameworks/base/core/java/android/app/Service.java
/**
* Return the communication channel to the service. May return null if
* clients can not bind to the service. The returned
* {@link android.os.IBinder} is usually for a complex interface
* that has been <a href="{@docRoot}guide/components/aidl.html">described using
* aidl</a>.
*
* <p><em>Note that unlike other application components, calls on to the
* IBinder interface returned here may not happen on the main thread
* of the process</em>. More information about the main thread can be found in
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
* Threads</a>.</p>
*
* @param intent The Intent that was used to bind to this service,
* as given to {@link android.content.Context#bindService
* Context.bindService}. Note that any extras that were included with
* the Intent at that point will <em>not</em> be seen here.
*
* @return Return an IBinder through which clients can call on to the
* service.
*/
@Nullable
public abstract IBinder onBind(Intent intent);
位置2的ActivityManager.getService().publishService。
10 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void publishService(IBinder token, Intent intent, IBinder service) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
mServices.publishServiceLocked。
11 frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Not publishing to: " + c);
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Published intent: " + intent);
continue;
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
//位置1
c.conn.connected(r.name, service, false);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e);
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
位置1的 c.conn.connected。conn,它的类型是IServiceConnection,是一个Binder对象的远程接口,也是前面创建的LoadedApk.ServiceDispatcher.InnerConnection对象。
12 frameworks/base/core/java/android/app/LoadedApk.java
InnerConnection是LoadedApk的内部类。
static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
...
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
}
...
}
sd.connected。
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
mActivityThread.post。
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
mDead = dead;
}
public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
...
}
doConnected。
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
...
// If there is a new service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
mConnection.onServiceConnected(name, service),把service这个Binder对象传到activity中。
service 已经onCreate()和onBind(),同时,绑定服务时,服务返回的Binder对象也接收到了。
三 总结
ServiceDispatcher 类似于一个Dispatcher的作用,这个类的作用就是当client bind某个service成功之后,负责向client分配service IBinder的;以及当client unbind service时,负责通知client unbind service的状态。
InnerConnection 它是一个Binder对象,会传递给ActivityManagerService,ActivityManagerServic后续则要通过该Binder对象和ServiceConnection通信。
相关阅读
Android获取应用签名(开发版SHA1和发布版SHA1)
当我们需要接入百度地图等一系列需要开发版SHA1和发布版SHA1才能创建完成应用的时候,如果找不到开发版SHA1和发布版SHA1是不是很苦
是当控件被按下的时候控件的表示,可以实现按下按钮时,按钮变成领一个模样,松开之后又恢复原样。类似的还有:android:state_focused是
Android模块添加依赖后无法找到的原因(implementation
Android模块添加依赖后无法找到的原因(implementation和api的区别) 场景: Android3.0以上,例如在BaseLibrary中添加了 dependencies {
Web service服务(接口)一.定义Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用
文章目录引言OSI 七层网络模型物理层数据链路层网络层传输层会话层表达层应用层TCP/IP 四层模型IP 协议TCP 协议TCP 的三次握手与