通过上一篇的介绍,大家应该对 Binder 通信流程有了整体的了解,但其中很多知识点并没有讲到,例如:
1、怎样实现 Binder 双工通信?
2、进程间 Binder 对象是以什么方式传递?
3、Binder 通信中 Parcel 的作用?
4、Java 和 JNI 层在整个 Binder 通信中扮演的角色和作用?
5、同一个进程会使用到 Binder 通信吗?
在这一篇中都会给大家一一讲解。
一、Binder 双工通信
1.1 什么是 Binder 双工通信
== 双 ==工通信表示两个进程之间可以互相调用和传递数据,Android 中最典型的场景就是应用进程和 AmS 之间的通信,我们都知道系统应用进程通过如下方法获取 AmS 客户端的代理:
IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
IActivityManager am = IActivityManager.Stub.asInterface(b);
或者第三方应用可以通过标准 SDK 接口:
ActivityManager am = (ActivityManager) mContex.getSystemService(Context.ACTIVITY_SERVICE);
这样,我们就能通过 am 对象
跨进程调用 system_server
进程中 AmS
的相关方法或者向它传递数据,但是 AmS
却不能发过来调用应用进程的方法或者向其传递数据,这种情况该怎么处理呢?
其实方法很简单,Binder 机制已经给我们提供一种便捷的方法,我们只需要在应用进程中创建一个 Binder 服务端对象,再通过刚刚获得 am 对象
传递给 AmS ,这样就能实现双工通信了。
1.2 Binder 双工通信代码实现
我们知道应用的生命周期方法都是 AmS 来驱动的,其中关键就在 ActivityThread.java 这个类,这个类就是应用的主线程,非常非常重要,我们这里只关注它和 AmS 是如何实现实现双工通信的。
先来看一个关键的内部类:
private class ApplicationThread extends ApplicationThreadNative {
......
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
int seq = getLifecycleSeq();
if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this
+ " operation received seq: " + seq);
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
configChanges,
seq);
}
public final void scheduleStopActivity(IBinder token, boolean showWindow,
int configChanges) {
int seq = getLifecycleSeq();
if (DEBUG_ORDER) Slog.d(TAG, "stopActivity " + ActivityThread.this
+ " operation received seq: " + seq);
sendMessage(
showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,
token, 0, configChanges, seq);
}
public final void scheduleWindowVisibility(IBinder token, boolean showWindow) {
sendMessage(
showWindow ? H.SHOW_WINDOW : H.HIDE_WINDOW,
token);
}
public final void scheduleResumeActivity(IBinder token, int processState,
boolean isForward, Bundle resumeArgs) {
int seq = getLifecycleSeq();
if (DEBUG_ORDER) Slog.d(TAG, "resumeActivity " + ActivityThread.this
+ " operation received seq: " + seq);
updateProcessState(processState, false);
sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0, 0, seq);
}
// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
.....
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
......
}
可以看到 ApplicationThread 继承 ApplicationThreadNative,ApplicationThreadNative 又是什么呢?
public abstract class ApplicationThreadNative extends Binder
implements IApplicationThread {
}
看到它是继承了 Binder 并实现 IApplicationThread 接口的抽象类,这就表示它是 Binder 服务端,我们可以看看 ActivityManagerService.java 的继承关系:
public class ActivityManagerService extends ActivityManagerNative {
...
}
而 ActivityManagerNative 也是继承 Binder,所以说 ApplicationThreadNative 本质上和 AmS 都是 Binder 服务端,如果发布到 ServiceManager,其他进程是可以访问到的。
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
...
}
知道了 ApplicationThread 是什么,接下来看应用进程是如何把它传递给 AmS 的?
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
......
//获取AmS的代理对象
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
//通过这个代理对象把mAppThread传递给AmS
//mAppThread就是new一个ApplicationThread()对象;
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
.....
try {
mInstrumentation = new Instrumentation();
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
获取到 AmS 的代理对象,通过 attachApplication() 方法把 mAppThread 当作参数传过去即可。是不是很简单,仅仅两行代码就搞定了,我们再来看看 attachApplication() 的实现。
public void attachApplication(IApplicationThread app) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app.asBinder());
mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
经典的 Binder 调用方式,这部分上一篇文章已经介绍过,这样会最终调用到 AmS 那边的 attachApplication() 方法:
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
......
case ATTACH_APPLICATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IApplicationThread app = ApplicationThreadNative.asInterface(
data.readStrongBinder());
if (app != null) {
attachApplication(app);
}
reply.writeNoException();
return true;
}
......
}
}
@Override
public void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
AmS 收到 thread
对象后保存下来,之后就可以直接调用应用进程中的相应方法。讲到这里,引言中第一问题已经有了答案,但真正的原理还是没有说明白,比如,为什么把 Binder 对象传递过去,对端就能使用它调用自己的方法,这和在 ServiceManager 注册的服务有什么区别?下面我重点介绍其中的原理。
二、Binder 对象在进程中传递过程
2.1 匿名 Binder 的概念
Binder 服务分为两种:实名服务
和匿名服务
区别:
实名服务
:能够通过 ServiceManager 查询到,比如 Android 中的实名服务都是系统提供的如AmS、WmS、PmS;
匿名服务
:普通应用开发的 Binder 服务,只能是匿名服务,比如我们刚刚介绍的 ApplicationThread。
这就回答了上一章最后说的那个问题,其实它们没有本质的区别,只不过实名服务
在 ServiceManager 中注册过,别的进程可以查询使用,而匿名服务
只有创建的人知道,除非你暴露给别的进程,否则它们无法访问。最终对 Binder 驱动而言,它们都是同一种东西。
2.2 Binder 对象的传递过程
上一章介绍应用进程和 AmS 之间的双工通信就是通过attachApplication() 方法把 ApplicationThread 传递给 AmS 进程:
public void attachApplication(IApplicationThread app) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app.asBinder());
mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
而这个IApplicationThread app
对象本质是一个 Binder 对象,为什么一个简单的 Binder 对象传递过去,对方就能直接调用自己的方法呢?这其中的原理是什么?
这一块是本文的重点,我们就从这个 Binder 对象传递过程讲起。
IApplicationThread app
对象是通过 Parcel.java 中的 writeStrongBinder() 方法打包到 Parcel 中的,我们来看这个方法的实现:
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
Java 层的代码很简单,直接调用了 native 层的方法,继续往下看:
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
native 层的 writeStrongBinder() 也很简单,调用了 flatten_binder() 方法,继续往下跟:
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj;
...
if (binder != NULL) {
IBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = 0;
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
}
return finish_flatten_binder(binder, obj, out);
}
先来看看 local 是什么,其实,它就是用来判断当前 binder 对象是本地BBinder 对象还是代理 BpBinder 对象。
来看具体定义:
class IBinder : public virtual RefBase
{
...
virtual BBinder* localBinder();
virtual BpBinder* remoteBinder();
...
}
localBinder() 和 remoteBinder() 是 IBinder 中的两个虚方法,而BBinder 和 BpBinder 都继承 IBinder:
- frameworks/native/libs/binder/Binder.cpp
BBinder* IBinder::localBinder()
{
return NULL;
}
BpBinder* IBinder::remoteBinder()
{
return NULL;
}
默认两个方法都返回 NULL
,但 BBinder 重写了其中 localBinder() 方法,返回 BBinder 对象:
BBinder* BBinder::localBinder()
{
return this;
}
BpBinder 重写了其中 remoteBinder() 方法,返回 BpBinder 对象:
- frameworks/native/libs/binder/BpBinder.cpp
BpBinder* BpBinder::remoteBinder()
{
return this;
}
所以 flatten_binder() 方法中通过 IBinder *local = binder->localBinder()
获得 local 对象,再根据它是否为空判断当前传递的 binder 对象是本地 BBinder 还是代理 BpBinder,因为只有 BBinder 对象 localBinder() 方法的返回值不为 NULL
。
回过头再开看 flatten_binder() 方法:
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj;
...
if (binder != NULL) {
IBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = 0;
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
...
}
return finish_flatten_binder(binder, obj, out);
}
根据 local
是否为空分了两种情况:
- BINDER_TYPE_HANDLE
- BINDER_TYPE_BINDER
我们传下来的 ApplicationThread 是 Binder 本地对象(为什么说ApplicationThread 是 Binder 本地对象我们在后面再讲),故 local 不为 NULL, 所以走下面的分支:
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
只有 type 为BINDER_TYPE_BINDER
时才会把 binder 对象打包到 flat_binder_object
中,传递给 Binder 驱动,当 type 为 BINDER_TYPE_HANDLE
时,只是传递的一个整型句柄 handle
, 真正的 binder 对象并没有传递下去,这从代码中可以看出:obj.binder = 0
。
所以,“打扁”的意思就是把 binder 对象整理成 flat_binder_object
变量,如果打扁的是 binder 实体,那么 flat_binder_object
用 cookie 域记录 binder 实体的指针,即 BBinder 指针;而如果打扁的是 binder 代理,那么 flat_binder_object
用 handle 域记录的 binder 代理的句柄值。
接下来就调用 finish_flatten_binder() 方法把flat_binder_object
写入 parcel 后发给 Binder 驱动, 发送的过程在上一篇文章已经介绍,这里再说下 IPCThreadState::writeTransactionData() 方法,它会先把 Parcel 数据整理成一个 binder_transaction_data
数据:
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
binder_transaction_data tr;
......
// 这部分是待传递数据
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
// 这部分是扁平化的binder对象在数据中的具体位置
tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
tr.data.ptr.offsets = data.ipcObjects();
......
mOut.write(&tr, sizeof(tr));
......
}
所以,当binder_transaction_data
传递到 Binder 驱动层后,驱动层可以准确地分析出数据中到底有多少binder对象,并分别进行处理产生出合适的红黑树节点。此时,如果产生的红黑树节点是 binder_node 的话, binder_node 的 cookie 域会被赋值成flat_binder_object
所携带的 cookie 值,也就是用户态的 BBinder 地址值。
这个新生成的 binder_node 节点被插入红黑树后,会一直严阵以待,以后当它成为另外某次传输动作的目标节点时,它的 cookie 域就派上用场了
(这里的成为另外某次传输动作的目标节点可以理解为:AmS 拿到 ApplicationThread 的代理对象后,想要反过来调用应用进程的方法,此时刚刚传入的 BBinder 对象就成为目标节点),此时 cookie 值会被反映到用户态,于是用户态就拿到了 BBinder 对象。
总结:
- 1、应用进程获取 AmS 的代理对象,把 ApplicationThread 传递过去,这个 ApplicationThread 继承 Binder,可以理解为 binder 实体对象;
- 2、通过 Parcel 的 writeStrongBinder() 方法,把传入的 ApplicationThread 对象,并判断
local
是否为空,如果是 binder 代理对象,flat_binder_object
用 handle 域记录的 binder 代理的句柄值,并把 type 设为 BINDER_TYPE_HANDLE;如果是 binder 实体对象,flat_binder_object
用 cookie 域记录 binder 实体的指针,即BBinder指针; - 3、经过 Binder 驱动时,驱动会根据传入的数据生成
binder node
,以后当它成为另外某次传输动作的目标节点时,用户态就能根据生成的binder node
拿到 BBinder 对象,这就解释了开始我们的疑问:为什么把 Binder 对象传递给 AmS,AmS 就能使用它调用自己的方法?是因为传递 BBinder 对象过程中,Binder 驱动会生成一一对应的节点,对端进程根据节点自然可以找到自己。
三、JNI 层 Binder 内容介绍
3.1 Java 和 Native 层 Binder 对象转化
Android 上层都是用 Java 写的,但是 Binder 驱动是 C 实现,它们之间互相传递对象必然要经过 JNI 层,之前说到应用进程传给 AmS 的 ApplicationThread 是 Binder 本地对象,并没有说其中的原因,其实在 JNI 层有一个转化过程。
先来看Java 层 Binder.java 的构造方法:
public Binder() {
init();
......
}
private native final void init();
init() 是 native 方法,我们继续往下看:
- frameworks/base/core/jni/android_util_Binder.cpp
static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
JavaBBinderHolder* jbh = new JavaBBinderHolder();
if (jbh == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return;
}
ALOGV("Java Binder %p: acquiring first ref on holder %p", obj, jbh);
jbh->incStrong((void*)android_os_Binder_init);
//这里很关键,请注意是 gBinderOffsets
env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh);
}
这个方法里面创建一个 JavaBBinderHolder 对象,它其实会持有一个 JavaBBinder 对象,而
JavaBBinder 继承 BBinder :
class JavaBBinderHolder : public RefBase
{
public:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);
mBinder = b;
ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
}
return b;
}
sp<JavaBBinder> getExisting()
{
AutoMutex _l(mLock);
return mBinder.promote();
}
private:
Mutex mLock;
wp<JavaBBinder> mBinder;
};
class JavaBBinder : public BBinder
{
public:
JavaBBinder(JNIEnv* env, jobject object)
: mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
{
ALOGV("Creating JavaBBinder %p\n", this);
android_atomic_inc(&gNumLocalRefs);
incRefsCreated(env);
}
......
}
我们回过头来看 Java 层向下传输 ApplicationThread 的方法:
public void attachApplication(IApplicationThread app) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app.asBinder());
mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
ApplicationThread 对象是通过writeStrongBinder() 写入 Parcel 的,再看它是native 方法,直接看它的 JNI 实现:
- frameworks/base/core/jni/android_os_Parcel.cpp
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
......
}
}
在调用真正的 Parcel.cpp 的 writeStrongBinder() 方法之前,通过 ibinderForJavaObject() 把 Java 层的对象转化为 native 层的 IBinder 对象,
-
ibinderForJavaObject()
: 将 Java 层对象转换为Native 层的 JavaBBinder 对象 -
javaObjectForIbinder()
: 将 Native 层对象转换为Java 层对象
来看 ibinderForJavaObject() 的实现:
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
......
// 刚刚 init() 方法中,设置的值为 gBinderOffsets,所以走的是这个分支,通过上面介绍,这边会返回一个 JavaBBinder 对象
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL;
}
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
}
......
return NULL;
}
刚刚 Binder.java 调用的native init() 方法中,设置的值为 gBinderOffsets,所以走的是上面的 if 分支,通过上面介绍,这里会返回一个 JavaBBinder 对象。
同理,javaObjectForIBinder()
方法就是 Java 层从 Parcel 中读取 Binder 对象时调用的,如下:
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
到此,引言中提到的第四个问题 “Java 和 JNI 层在整个 Binder 通信中扮演的角色和作用?”已经阐述,其实 JNI 中还有很多内容,我们这里就不一一介绍了。
四、相同进程中 Binder 通信过程
4.1 asBinder() 方法的作用
public abstract class ActivityManagerNative extends Binder implements IActivityManager {
/**
* Cast a Binder object into an activity manager interface, generating
* a proxy if needed.
*/
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
Log.v(TAG, " queryLocalInterface return not null in = " + in);
return in;
}
Log.v(TAG, "Activitymanager new ActivityManagerProxy() ");
return new ActivityManagerProxy(obj);
}
public IBinder asBinder() {
return this;
}
......
}
class ActivityManagerProxy implements IActivityManager {
public ActivityManagerProxy(IBinder remote) {
mRemote = remote;
}
public IBinder asBinder() {
return mRemote;
}
......
}
本地做了一个验证,WindwoManagerService.java 和 Settings 应用分别去通过 Binder 去获得 AmS 对象,代码如下:
IBinder b = ServiceManager.getService("activity");
IActivityManager am = ActivityManagerNative.asInterface(b);
Log.d(TAG, " WindowManagerService binder = " + b + " service = " + am + " old service = " + mActivityManager);
WmS 中打印的 log 如下:
01-07 06:59:23.283 1424 1520 V binder: queryLocalInterface return not null in = com.android.server.am.ActivityManagerService@e7c84de
01-07 06:59:23.283 1424 1520 D binder: WindowManagerService binder = com.android.server.am.ActivityManagerService@e7c84de service = com.android.server.am.ActivityManagerService@e7c84de
Settings 打印 log 如下:
01-08 08:10:31.059 3179 3179 V binder: Activitymanager new ActivityManagerProxy()
01-08 08:10:31.059 3179 3179 D binder: Settings binder = android.os.BinderProxy@ceb71a0 service = android.app.ActivityManagerProxy@e04a9aa
结论:可以看出,因为 WmS 和 AmS 都属于 system_server 进程,所以返回的直接是 ActivityManagerService
本身对象,而 Settings 属于应用进程,返回的是 ActivityManagerProxy
代理对象。
为什么会有这种现象呢,可以看出 Java 层代码两者并无不同,区别就是 JNI 和 Binder 驱动对两者 type 类型的处理不一样,JNI 刚刚已经介绍过,Binder 驱动会判断传来的 IBinder 类型为BINDER_TYPE_HANDLE
时,会判断该 IBinder 的实体被定义的进程(也就是该 IBinder 代表的 server 被定义的进程)与目标进程(也即 IBinder被传递的目标进程)是否相同,如果相同,则将该IBinder type 转化BINDER_TYPE_BINDER
,同时使其变为 IBinder 本地对象的引用
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
struct binder_transaction *t;
for (; offp < off_end; offp++) {
.....
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
........
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->binder = 0;
fp->handle = ref->desc;
fp->cookie = 0;
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo);
} break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
......
if (ref->node->proc == target_proc) {
if (fp->type == BINDER_TYPE_HANDLE)
fp->type = BINDER_TYPE_BINDER;
else
fp->type = BINDER_TYPE_WEAK_BINDER;
fp->binder = ref->node->ptr;
fp->cookie = ref->node->cookie;
binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
......
} else {
struct binder_ref *new_ref;
new_ref = binder_get_ref_for_node(target_proc, ref->node);
if (new_ref == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
fp->binder = 0;
fp->handle = new_ref->desc;
fp->cookie = 0;
binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
......
} break;
}
参考:
IBinder对象在进程间传递的形式(一)
红茶一杯话Binder(ServiceManager篇)
Android Binder跨进程与非跨进程的传输异同源码分析
深入分析Android Binder 驱动
网友评论