Service源码浅析一
Service源码浅析二
Service源码浅析三
Service源码浅析四
咱们带着这几个问题继续分析Service的代码:
- binderDied和onServiceDisconnected是否会同时触发?有先后顺序吗?
- Service AIDL进程间通信服务端和客户端分别运行在哪个线程?
Stop Service
public abstract boolean stopService(Intent service);
ContextImpl
@Override
public boolean stopService(Intent service) {
warnIfCallingFromSystemProcess();
return stopServiceCommon(service, mUser);
}
private boolean stopServiceCommon(Intent service, UserHandle user) {
// // Keep this in sync with ActivityManagerLocal.stopSdkSandboxService
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
int res = ActivityManager.getService().stopService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to stop service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
接下来就到了ActivityManagerService,它会调用ActiveServices中的方法stopServiceLocked,然后是bringDownServiceLocked,剩下的流程就和unbind Service中一样了,执行ActivityThread中的一些列操作。
linkToDeath
public void linkToDeath(@NonNull DeathRecipient recipient, int flags)
throws RemoteException;
linkToDeath是IBinder方法,它接受一个DeathRecipient作为参数。
public interface DeathRecipient {
public void binderDied();
/**
* The function called when the process hosting an IBinder
* has gone away.
*
* This callback will be called from any binder thread like any other binder
* transaction. If the process receiving this notification is multithreaded
* then synchronization may be required because other threads may be executing
* at the same time.
*
* No locks are held in libbinder when {@link binderDied} is called.
*
* There is no need to call {@link unlinkToDeath} in the binderDied callback.
* The binder is already dead so {@link unlinkToDeath} is a no-op.
* It will be unlinked when the last local reference of that binder proxy is
* dropped.
*
* @param who The IBinder that has become invalid
*/
default void binderDied(@NonNull IBinder who) {
binderDied();
}
}
IBinder的实现类是Binder
/**
* Local implementation is a no-op.
*/
public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
}
Binder的linkToDeath方法实现也是空的,那它是在哪实现的呢?
其实它的实现类是BinderProxy,它是IBinder native类的Java层代理
public void linkToDeath(DeathRecipient recipient, int flags)
throws RemoteException {
linkToDeathNative(recipient, flags);
mDeathRecipients.add(recipient);
}
private native void linkToDeathNative(DeathRecipient recipient, int flags)
throws RemoteException;
linkToDeathNative是native方法,它的实现在哪呢?
native实现在
frameworks/platform_frameworks_base/core/jni/android_util_Binder.cpp
static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj,
jobject recipient, jint flags) // throws RemoteException
{
if (recipient == NULL) {
jniThrowNullPointerException(env, NULL);
return;
}
BinderProxyNativeData *nd = getBPNativeData(env, obj);
IBinder* target = nd->mObject.get();
LOG_DEATH_FREEZE("linkToDeath: binder=%p recipient=%p\n", target, recipient);
if (!target->localBinder()) {
sp<DeathRecipientList> list = nd->mOrgue;
sp<JavaDeathRecipient> jdr = sp<JavaDeathRecipient>::make(env, recipient, list);
status_t err = target->linkToDeath(jdr, NULL, flags);
if (err != NO_ERROR) {
// Failure adding the death recipient, so clear its reference
// now.
jdr->clearReference();
signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/);
}
}
}
target->linkToDeath最后追到
frameworks/native/libs/binder/BpBinder.cpp
status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
if (isRpcBinder()) {
if (rpcSession()->getMaxIncomingThreads() < 1) {
ALOGE("Cannot register a DeathRecipient without any incoming threads. Need to set max "
"incoming threads to a value greater than 0 before calling linkToDeath.");
return INVALID_OPERATION;
}
} else if constexpr (!kEnableKernelIpc) {
LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
return INVALID_OPERATION;
} else {
if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() == 0) {
ALOGW("Linking to death on %s but there are no threads (yet?) listening to incoming "
"transactions. See ProcessState::startThreadPool and "
"ProcessState::setThreadPoolMaxThreadCount. Generally you should setup the "
"binder "
"threadpool before other initialization steps.",
String8(getInterfaceDescriptor()).c_str());
}
}
Obituary ob;
ob.recipient = recipient;
ob.cookie = cookie;
ob.flags = flags;
LOG_ALWAYS_FATAL_IF(recipient == nullptr,
"linkToDeath(): recipient must be non-NULL");
{
RpcMutexUniqueLock _l(mLock);
if (!mObitsSent) {
if (!mObituaries) {
mObituaries = new Vector<Obituary>;
if (!mObituaries) {
return NO_MEMORY;
}
ALOGV("Requesting death notification: %p handle %d\n", this, binderHandle());
if (!isRpcBinder()) {
if constexpr (kEnableKernelIpc) {
getWeakRefs()->incWeak(this);
IPCThreadState* self = IPCThreadState::self();
self->requestDeathNotification(binderHandle(), this);
self->flushCommands();
}
}
}
ssize_t res = mObituaries->add(ob);
return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
}
}
return DEAD_OBJECT;
}
追到这里还是一脸懵,服务进程挂了是怎么通知客户端的?
其实它是通过binder驱动直接通知客户端的
+----------------+ +---------------+ +----------------+
| 服务端进程死亡 | ----> | Binder驱动 | ----> | 客户端进程 |
+----------------+ +---------------+ +----------------+
|
v
+-----------------+
| 死亡通知工作项 |
| (BINDER_WORK_ |
| DEAD_BINDER) |
+-----------------+
Binder驱动可以感知服务端进程死亡,然后回调客户端注册的Java层方法。
咱们在看bindService时应该注意到,传入的ServiceConnection经过LoadedApk包装之后变成了ServiceDispatcher,服务绑定之后会通过doConnected触发ServiceConnection#onServiceConnected
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.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;
}
} else {
// The named service is being disconnected... clean up.
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
// If there was an old service, it is now disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
} else {
// If there is a new viable service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);
} else {
// The binding machinery worked, but the remote returned null from onBind().
mConnection.onNullBinding(name);
}
}
}
这个方法中还藏了一步,它悄悄的给服务端注册了另一个死亡监听DeathMonitor
private final class DeathMonitor implements IBinder.DeathRecipient
{
DeathMonitor(ComponentName name, IBinder service) {
mName = name;
mService = service;
}
public void binderDied() {
death(mName, mService);
}
final ComponentName mName;
final IBinder mService;
}
最后会通过主线程回调onServiceDisconnected,感觉太鸡贼了。
public void doDeath(ComponentName name, IBinder service) {
synchronized (this) {
ConnectionInfo old = mActiveConnections.get(name);
if (old == null || old.binder != service) {
// Death for someone different than who we last
// reported... just ignore it.
return;
}
mActiveConnections.remove(name);
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
mConnection.onServiceDisconnected(name);
}
也就是说服务端进程死亡之后,客户自己注册的死亡监听可以收到回调,这里注册的监听也可以收到回调,所以咱们开头的第一个问题就有答案了
- binderDied和onServiceDisconnected是否会同时触发?有先后顺序吗?
不会同时触发,应该是先在Binder线程触发binderDied,再在主线程触发onServiceDisconnected
- binderDied和onServiceDisconnected是否会同时触发?有先后顺序吗?
目前咱们就剩下第2个问题了
- Service AIDL进程间通信服务端和客户端分别运行在哪个线程?
先说答案,以客户端调用服务端为例,客户端侧的逻辑运行在客户端侧的调用进程,服务端的逻辑运行在Binder线程池的线程中,服务端调用客户端同理。
- Service AIDL进程间通信服务端和客户端分别运行在哪个线程?
这里涉及Binder通信的原理,可以参考[Binder 一]Binder浅析
咱们先来回顾一下AIDL进程通信的步骤:
- 创建 .aidl 文件
咱们创建一个简单的AIDL文件
interface IRemoteService {
int getPid();
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
- 实现接口
private val binder = object : IRemoteService.Stub() {
override fun getPid(): Int {
return Process.myPid()
}
override fun basicTypes(
anInt: Int,
aLong: Long,
aBoolean: Boolean,
aFloat: Float,
aDouble: Double,
aString: String?
) {
}
}
- 向客户端公开该接口
override fun onBind(intent: Intent?): IBinder {
return binder
}
客户端绑定服务端成功之后会回调onServiceConnected,这个咱们在上一篇已经跟过流程了。
private val mConnection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
// This is called when the connection with the service is
// established, giving us the service object we can use to
// interact with the service. We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
mService = IRemoteService.Stub.asInterface(service)
}
override fun onServiceDisconnected(className: ComponentName) {
// This is called when the connection with the service is
// unexpectedly disconnected—that is, its process crashed.
mService = null
}
}
首先,咱们在 build/generated/aidl_source_output_dir下找到编译器为我们自动生成的IRemoteService.java类文件。

从上图中可以看到asInterface是Stub的方法
/**
* Cast an IBinder object into an com.example.serverdemo.IRemoteService interface,
* generating a proxy if needed.
*/
public static com.example.serverdemo.IRemoteService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.serverdemo.IRemoteService))) {
return ((com.example.serverdemo.IRemoteService)iin);
}
return new com.example.serverdemo.IRemoteService.Stub.Proxy(obj);
}
该方法会返回服务端的接口对象,如果客户端和服务端在同一个进程,则返回Stub对象本身,如果不在同一进程,则返回Proxy对象。
/**
* Use information supplied to {@link #attachInterface attachInterface()}
* to return the associated {@link IInterface} if it matches the requested
* descriptor.
*/
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
if (mDescriptor != null && mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
可以看到queryLocalInterface返回的是attachInterface中的接口,attachInterface是在Stub构造方法中调用的。
public static abstract class Stub extends android.os.Binder implements com.example.serverdemo.IRemoteService
{
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
}
跨进程情况下返回的是Proxy对象,
private static class Proxy implements com.example.serverdemo.IRemoteService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
}
Proxy实现了IRemoteService,并持有服务端传过来的IBinder对象,并通过这个对象调用对应的方法
@Override public int getPid() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
以调用getPid方法为例,会触发mRemote.transact,这里发生了进程通信,从客户端进程进入服务端进程,方法transact的实现在Binder类中,接下来都是在服务端进程发生的。
/**
* Default implementation rewinds the parcels and calls onTransact. On
* the remote side, transact calls into the binder to do the IPC.
*/
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
会调用到服务端Stub对象的onTransact方法。
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {
data.enforceInterface(descriptor);
}
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
}
switch (code)
{
case TRANSACTION_getPid:
{
int _result = this.getPid();
reply.writeNoException();
reply.writeInt(_result);
break;
}
case TRANSACTION_basicTypes:
{
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0!=data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
break;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
return true;
}
然后会触发自定义Binder对象的getPid方法,并返回结果,这个大体流程就走下来了,但是mRemote.transact是怎么调到服务端进程的,这块还得深究,本篇文章到此结束。
参考: