Android10_原理机制系列_Binder机制
前言
Binder 从java到c++到kernel,涉及的内容很多,很难在一篇文章中说清楚。这篇主要是自我记录,方便后续查询并拆分总结的。
因为涉及的的确非常多,不能面面俱到,所以可能一些地方感觉比较模糊、没说明白的。这需要自己去阅读了解。文章很长,需要耐心。
关于基础部分,并不是都要了解了才行,而是要完全弄清楚Binder各个层次需要,列出的一些需要多关注的知识点。
另外,该篇文章着重在注册服务和获取服务的过程,有详细的代码流程(这个有点复杂、占篇幅很大部分)辅助理解 注册和获取服务过程的整体思想把握。
基础
不做详细介绍,只是列出。
如前言所说,基础部分并非都要全部了解才可理解Binder。只是列出的需要多关注的地方。
进程空间
这里的进程空间就是进程在内存中的空间。在linux中,有
- 进程分为内核空间和用户空间。 内核空间存放内核的代码和数据,用户空间存放用户程序的代码和数据。
- 每个进程通过系统调用进入内核空间。 进程通过系统调用进入内核运行,这时被称为内核态 。当进程执行程序自己的代码时,称为用户态。
- 所有进程共享同一个内核空间。
- 内核空间为内核保留,一直驻存在内存中。 不允许应用读写该区域或者直接调用内核代码方法。
- 用户空间不能直接访问硬件设备。
Binder跨进程通信,就是借用了这个。
示意图:
进程了解 可以参考下:浅谈进程&线程
IPC基础
需要清楚:进程是独立的,一个进程不能直接访问另一个进程。
进程间如果需要交换数据、进行通信,这个就是IPC(进程间通信/跨进程通信)。可以参考相关文章大致了解下:
随笔分类 - Android_系统_进程线程
内存映射(mmap)
这里简单将,就是将用户空间一段内存地址映射到内核空间,映射关系建立后,任一修改都能反应到另一方。
Parcel
一个容器对象,包含数据和对象引用,支持序列化和跨进程后的反序列化。这里主要用于binder的跨进程通信。
AIDL
Android Interface definition language,接口定义语言,可以了解下。
Binder
IPC在Android中很多:如显然四大组件都需要进行IPC。
Andriod没有使用Linux中的各种IPC机制(进程间通信概述),通过基于OpenBinder的定制修改,实现了自己的一套轻量级的IPC机制---Binder。
在Android中,Binder几乎用于所有核心的跨进程事件中。
相对于Linux中其他IPC机制,那么Binder有什么优点呢?
优点
- Binder只需进行1次数据拷贝。
共享内存不需数据拷贝但控制复杂;其他方式一般需要进行两次数据拷贝;Binder只需1次,通过内存映射机制进行数据传递。 - 稳定性好。
C/S架构,职责分明。 - 安全。
加入了强大的安全机制。
Binder概述
Binder是基于C/S模式。主要有这几个部分:
角色 | 作用 |
---|---|
Server进程 | 服务端,提供服务的进程。 |
Client进程 | 客户端,使用服务的进程。上层应用。 |
ServerManager进程 | 管理服务。Server需要向它注册自己提供的服务。Client向它查询、获取需要的服务。 |
Binder驱动 | 核心部分,Client通过它发送请求到Server,Server通过它返回结果到Client。内核中的驱动设备/dev/binder。 |
下面详述中会具体说到。
Binder---IPC
首先,总体上就如上述进程空间描述。Binder通过内核进行跨进程。
具体点,如下图:
服务通过binder驱动注册到ServiceManager,ServiceManager保存了服务的名称、handle等信息 并加入svclist列表中。客户端通过binder驱动向ServiceManager进程查询获取到对应的服务的handle,然后binder将信息返回给客户端,客户端获取得到相应的服务Binder。
详述Binder的流程
详述Binder的流程 主要是服务注册、获取、ServiceManager相关的代码流程,这段很长,如果不需要看 可以直接跳到最后一块:简单总结。
下面AMS的注册和获取为例说明。Binder过程比较复杂,其中最需注意的是各个层次(java层/c++/kernel) IBinder对象具体是什么。
Binder源码,java层和c++层在 framework/下。驱动层在 kernel/下。
Android AOSP没有kernel源码,得单独下载。这里阅读的源码是AndroidQ的,AOSP部分是android-10.0.0_r40;kernel部分是MTK的,主要两个文件路径在kernel-4.9/drivers/android/binder.c和kernel-4.9/include/uapi/linux/android/binder.h。
另外,下面的过程很多地方 很多方法都需要详细研究的。下面尽量简化了,即使这样(也是水平有限),内容也很长。
主要是一个进程如何与另一个进程通信。围绕这 下面主要介绍了几点:
- Service是如何注册的
- ServerManager的创建,这里涉及到Service的注册和获取。
- Client是如何获取服务的
服务注册
AMS注册过程概述
服务是Context.ACTIVITY_SERVICE。
下面是画的一个注册过程的相对完整的流程(不是类图。文章是MD的,可以直接查看文本看到图片地址,该图片地址。使用wps画的 由于非会员,图形个数有限制带了水印。),再结合代码详细说明下。
这是一个理想的状态流程,比如实际中很多对象从保存好的地方直接获取不需重新创建。
简述:
注册传入了两个主要参数(服务名:activity,Binder:this)。通过一系列调用,最终将服务的名称和Binder等写入到了数据包Parcel(data)中,最终进入了Binder驱动。Binder驱动为AMS创建了binder结点binder_node。最后Binder驱动将相关信息给到ServerManager进程,ServiceManager将其封装加入svclist列表完成注册。
注册详细过程
系统启动后,这个服务即开始注册。这个很简单,注意传入的服务名是Context.ACTIVITY_SERVICE(即activity),以及this(AMS本身,也是继承了IBinder的Binder实体)。
SystemServer.java:
private void startBootstrapServices() {
......
mActivityManagerService.setSystemProcess();
......
}
ActivityManagerService.java:
public void setSystemProcess() {
......
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
......
}
ServiceManager.java:
@UnsupportedAppUsage
public static void addService(String name, IBinder service, boolean allowIsolated,
int dumpPriority) {
......
getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
......
}
getIServiceManager().addService(),这里需要弄清楚的就是getIServiceManager()和addService()两个方法,下面正式开始注册流程。
getIServiceManager()
ServiceManager.java:
@UnsupportedAppUsage
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
关键的一句,这里有几个需要依次弄清楚的。
- BinderInternal.getContextObject()
- Binder.allowBlocking()
- ServiceManagerNative.asInterface()
- getIServiceManager().addService():获取的是IServiceManager,这也是个接口。需要弄清楚getIServiceManager()获取的sServiceManager实际对象是什么在来看addService()方法。
-----回顾点1: getIServiceManager()具体是什么对象;addService()具体是什么
详细来看下这4点:
先看第一点(1/4)
BinderInternal.getContextObject()
BinderInternal.java:
@UnsupportedAppUsage
public static final native IBinder getContextObject();
frameworks/base/core/jni/android_util_Binder.cpp:
{ "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
getContextObject()是native修饰的方法,通过jni,进入了C++。
下面主要来看下ProcessState::self()->getContextObject(NULL)和javaObjectForIBinder(env, b)。
-----回顾点2: getContextObject()具体获取的是什么
先看下ProcessState::self()
ProcessState.java:
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endif
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
#define DEFAULT_MAX_BINDER_THREADS 15
sp<ProcessState> ProcessState::self()
{
......
gProcess = new ProcessState(kDefaultDriver);
return gProcess;
}
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
, mDriverFD(open_driver(driver))
......
{
......
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
......
}
static int open_driver(const char *driver)
{
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
......
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
......
}
从代码能够看到最终通过open_driver()方法打开了/dev/binder或者/dev/vndbinder驱动。通过ioctl进入binder内核并建立联系,在binder内核中创建了binder_proc并设置进程的最大线程数。
注意两个个设置:
- DEFAULT_MAX_BINDER_THREADS:这个fd最大线程数为15
- BINDER_VM_SIZE:ProcessState初始话的内存映射大小:1G-8k(注:这个值也又不同的情况,这里不扩展)
在接着看ProcessState::self()->getContextObject(NULL)
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
......
handle_entry* e = lookupHandleLocked(handle);
if (e != nullptr) {
IBinder* b = e->binder;
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
.......
b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
回到回顾点2,getContextObject()获取了句柄为0的BpBinder。先lookupHandleLocked()尝试获取,没有则创建了一个BpBinder对象。
BpBinder的handle,如果是0 则该BpBinder是servicemanager的binder引用,如果非0 其handle值就是不同Service的hanlde 关联了各个Service。也就是说任何的系统service都可以通过BpBinder(0)就能知道servicemanager的地址。
-----注意点1: 这个handle为0的BpBinder很重要,binder驱动等地方都有关联。
在来看return的方法,javaObjectForIBinder(env, b):
frameworks/base/core/jni/android_util_Binder.cpp:
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
......
if (val->checkSubclass(&gBinderOffsets)) {
// It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
BinderProxyNativeData* nativeData = new BinderProxyNativeData();
nativeData->mOrgue = new DeathRecipientList;
nativeData->mObject = val;
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
......
return object;
}
在注册过程,返回的是BinderProxy。前面知道传入的是BpBinder对象,这是native层的对象在Java层无法使用,转换成BinderProxy。
接着看第二点(2/4)
Binder.allowBlocking()
Binder.java:
public static IBinder allowBlocking(IBinder binder) {
try {
if (binder instanceof BinderProxy) {
((BinderProxy) binder).mWarnOnBlocking = false;
} else if (binder != null && binder.getInterfaceDescriptor() != null
&& binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
Log.w(TAG, "Unable to allow blocking on interface " + binder);
}
} catch (RemoteException ignored) {
}
return binder;
}
这个没什么好说的。
再看第三点(3/4)
ServiceManagerNative.asInterface()
ServiceManagerNative.java:
@UnsupportedAppUsage
static public IServiceManager asInterface(IBinder obj)
{
......
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
.......
return new ServiceManagerProxy(obj);
}
前面传递的参数obj是一个保存着BpBinder的BinderProxy对象,这个BpBinder的handle是0(即关联servicemanager,后续通过transact传入binder驱动 找到目标进程)。
queryLocalInterface获取本地binder,此时in返回是null,所以这里返回了一个ServiceManagerProxy对象,并传入了BinderProxy对象。后续就通过这个BinderProxy代理对象进行通信。
回到回顾点1,从上面一系列可以看出getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
这句话:
getIServiceManager()获取的是ServiceManagerProxy对象,参数obj是BinderProxy。
addService()
接着看最后一点(4/4),addService()
最后来看下ServiceManagerProxy中的相关方法(ServiceManagerProxy是ServiceManagerNative内部类),即getIServiceManager().addService():
ServiceManagerNative.java:
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
data.writeInt(dumpPriority);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
}
注意data.writeStrongBinder(service);
这里写入的IBinder对象是AMS最初传入的this,是Binder的实例,而不是BinderProxy。
这里的mRemote即创建ServiceManagerProxy对象时传入的BinderProxy。
下面就是开始进入binder驱动了,得耐心接着看了。
先看下writeStrongBinder()
这个写入过程稍微注意下。
Parcel:
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
frameworks/base/core/jni/android_os_Parcel.cpp:
{"nativeWriteStrongBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
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));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
frameworks/base/core/jni/android_util_Binder.cpp:
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
// Instance of Binder?
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
return jbh->get(env, obj);
}
// Instance of BinderProxy?
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return getBPNativeData(env, obj)->mObject;
}
ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}
class JavaBBinderHolder
{
public:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);
......
};
class JavaBBinder : public BBinder
{
.....
}
上面已经说过,这里的service就是AMS对象,即Binder实例。所以writeStrongBinder()写入的service通过ibinderForJavaObject(env, object)封装成JavaBBinder(也即BBinder)。即服务Service对象转换成BBinder,传入到binder驱动了。
parcel->writeStrongBinder(ibinderForJavaObject(env, object));
-->
Parcel.cpp:
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
......
if (binder != nullptr) {
BBinder *local = binder->localBinder();
if (!local) {
.......
} else {
obj.hdr.type = BINDER_TYPE_BINDER;
.....
上面看到这里binder是BBinder对象,注意这里的hdr.type = BINDER_TYPE_BINDER ,在binder驱动中有使用。
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0)
接着Java层从此开始向binder驱动传递
BinderProxy:
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
......
try {
return transactNative(code, data, reply, flags);
......
}
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
frameworks/base/core/jni/android_util_Binder.cpp:
{"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{......
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
......
IBinder* target = getBPNativeData(env, obj)->mObject.get();
......
status_t err = target->transact(code, *data, reply, flags);
......
}
parcelForJavaObject将data、reply两个Parcel由Java对象转换成C++。
getBPNativeData()获取的是BpBinder对象。
接下来看BpBinder中的transact()。
frameworks/native/libs/binder/BpBinder.cpp:
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
......
}
frameworks/native/libs/binder/IPCThreadState.cpp:
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
......
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
err = waitForResponse(??);
......
}
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
tr.target.handle = handle;
tr.code = code;
......
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
......
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
......
cmd = (uint32_t)mIn.readInt32();
.......
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
......
do {
......
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
......
} while (err == -EINTR);
......
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
......
}
transact()中关键两步,writeTransactionData()和waitForResponse()。
writeTransactionData()将要传递的数据及命令写入到mOut。这里要发送的命令是BC_TRANSACTION。 在注意的是,handle标识的是目标端,这里是0。即注册中目标是Servicemanager(handle 0 对应 binder_context_mgr_node对象)。
waitForResponse()中while(1)死循环,通过talkWithDriver()中ioctl进入binder,这里传入到binder_ioctl的参数cmd是BINDER_WRITE_READ。
waitForResponse()很重要,在死循环中会对binder返回的应答进行处理,cmd = (uint32_t)mIn.readInt32();
获取应答的命令类型。
另外,注意下传入transact()中的flag为0(即非TF_ONE_WAY)。
进入binder驱动
通过ioctl(),进入了binder内核
{kernel}/drivers/android/binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
.....
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
......
}
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
......
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
......
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
......
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
......
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
......
}
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
......
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
......
if (get_user(cmd, (uint32_t __user *)ptr))
......
switch (cmd) {
......
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr,
cmd == BC_REPLY, 0);
break;
}
......
}
}
通过系统调用,进入binder驱动的binder_ioctl()方法,这里传入的cmd是BINDER_WRITE_READ(),上面 BpBinder中的transact()有说。
上面 BpBinder中的transact()也说过发送命令在mOut中是BC_TRANSACTION,这时通过copy_from_user()从用户空间拷贝数据到了内核空间。最终进入到binder_transaction()事务处理。
注意第四个参数cmd==BC_REPLY为false 。
最重要的binder_transaction()
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply,
binder_size_t extra_buffers_size)
{
.....
if(reply){
......
}else {
if (tr->target.handle) {
......
} else {
......
target_node = context->binder_context_mgr_node;
......
}
}
......
switch (hdr->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct flat_binder_object *fp;
fp = to_flat_binder_object(hdr);
#ifdef BINDER_WATCHDOG
ret = binder_translate_binder(tr, fp, t, thread);
#else
ret = binder_translate_binder(fp, t, thread);
#endif
......
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
t->work.type = BINDER_WORK_TRANSACTION;
......
if (!binder_proc_transaction(t, target_proc,
}
#ifdef BINDER_WATCHDOG
static int binder_translate_binder(struct binder_transaction_data *tr,
......
{
struct binder_node *node;
node = binder_get_node(proc, fp->binder);
if (!node) {
node = binder_new_node(proc, fp);
if (!node)
return -ENOMEM;
#ifdef BINDER_WATCHDOG
parse_service_name(tr, proc, node->name);
#endif
......
ret = binder_inc_ref_for_node(target_proc, node,
fp->hdr.type == BINDER_TYPE_BINDER,
&thread->todo, &rdata);
......
if (fp->hdr.type == BINDER_TYPE_BINDER)
fp->hdr.type = BINDER_TYPE_HANDLE;
fp->binder = 0;
fp->handle = rdata.desc;
}
/* this is an addService() transaction identified by:
* fp->type == BINDER_TYPE_BINDER && tr->target.handle == 0
*/
void parse_service_name(struct binder_transaction_data *tr,
binder_transaction()这个事务处理方法很长,这里主要说下几个注意点。
reply:前面流程传入的为false,cmd是BC_TRANSACTION。说明这是一个Client发给Server的请求事务,在Client端线程上。若为true,即是BC_REPLY说明这是一个Server发给Client的事务处理回复。在server端的线程上。
tr->target.handle:如果是BC_TRANSACTION(这里注册中是这个),接着判断tr->target.handle。如果>0,即目标为普通Service,如果为0,则目标service是ServiceManager。从而获取目标结点target_node,进一步获取目标进程、目标线程及相关信息。
前面有讲到传递的BBinder对象中hdr.type = BINDER_TYPE_BINDER。最终有走到binder_translate_binder,为注册服务创建了binder_node结点,保存了服务的进程及相关信息。
向servicemanager添加BINDER_WORK_TRANSACTION事务,接下来进入ServiceManager进程。
handle值(也待详细了解//TODO):
binder_get_node()->binder_new_node()->binder_inc_ref_for_node()->binder_get_ref_for_node_olocked(),不详述。
new_ref->data.desc,data.desc即handle。
handle值计算方法规律:
每个进程binder_proc所记录的binder_ref的handle值是从1开始递增的;
所有进程binder_proc所记录的handle=0的binder_ref都指向service manager;
同一个服务的binder_node在不同进程的binder_ref的handle值可以不同;
接下来的注册过程进入ServiceManager,从下面ServiceManager的创建过程了解。
ServiceManager的创建
ServiceManager本身也是Binder服务,但它通过自身的binder.c与Binder驱动直接通信。通过循环binder_loop进行读取和处理事务。
主要关注两个文件:frameworks/native/cmds/servicemanager/service_manager.c
和frameworks/native/cmds/servicemanager/binder.c
。
系统启动通过init.rc创建并启动servicemanager。直接看其中main()方法。
frameworks/native/cmds/servicemanager/service_manager.c:
int main(int argc, char** argv)
{
......
//打开binder驱动,申请128k字节大小的内存空间
bs = binder_open(driver, 128*1024);
......
if (binder_become_context_manager(bs)) {
......
binder_loop(bs, svcmgr_handler);
......
}
重点需要关注的是上述3个方法,依次来看:
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
......
bs->fd = open(driver, O_RDWR | O_CLOEXEC);
......
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
......
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
......
}
frameworks/native/cmds/servicemanager/binder.c:
int binder_become_context_manager(struct binder_state *bs)
{
int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj);
// fallback to original method
if (result != 0) {
android_errorWriteLog(0x534e4554, "121035042");
result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
}
void binder_loop(struct binder_state *bs, binder_handler func)
{
......
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
......
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
......
}
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
{
while (ptr < end) {
uint32_t cmd = *(uint32_t *) ptr;
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION: {
......
res = func(bs, &txn, &msg, &reply);
if (txn.transaction_data.flags & TF_ONE_WAY) {
binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer);
} else {
binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res);
}
......
}
void binder_send_reply(struct binder_state *bs,
......
{
......
data.cmd_reply = BC_REPLY;
......
binder_write(bs, &data, sizeof(data));
}
binder_open():这个比较简单,通过系统调用在binder驱动中创建binder_proc对象,调用mmap()内存映射分配了128K的内存空间。
binder_become_context_manager():使servicemanager成为上下文的管理者,创建了全局的binder_node对象binder_context_mgr_node。
binder_loop();这个是最重要的方法,进入死循环,等待Client端的请求。解析binder信息,此处参数ptr指向BC_ENTER_LOOPER,func指向svcmgr_handler。故有请求到来(如BR_TRANSACTION),则调用svcmgr_handler处理,处理完成后会发送BC_REPLY。
看看svcmgr_handler
frameworks/native/cmds/servicemanager/service_manager.c:
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data_secctx *txn_secctx,
struct binder_io *msg,
struct binder_io *reply)
{
......
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid,
(const char*) txn_secctx->secctx);
bio_put_ref(reply, handle);
case SVC_MGR_ADD_SERVICE:
if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
txn->sender_pid, (const char*) txn_secctx->secctx))
......
bio_put_uint32(reply, 0);
......
}
SVC_MGR_ADD_SERVICE就是从addService那拆解来的。SVC_MGR_GET_SERVICE类似。
ServiceManager最核心的两个功能为查询和注册服务:
注册服务:do_add_service(),记录服务名和handle信息,保存到svclist列表;
查询服务:do_find_service(),根据服务名查询相应的的handle信息。
这样,服务就注册到ServiceManager。能够被客户端获取。
客户端获取服务
获取服务概述
同服务注册一样,先看下大致的流程图。
简述:
客户端通过binder驱动从servicemanager进程查询到服务的handle,servicemanager进程同样应答binder驱动,binder驱动通过处理,向客户端返回正确的数据命令,客户端从而获取到服务的Binder对象。完成获取服务的的操作。
获取服务详细过程
直接来看
ActivityManager.getService():
ActivityManager:
@UnsupportedAppUsage
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
@UnsupportedAppUsage
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
ServiceManager.getService(Context.ACTIVITY_SERVICE):
ServiceManager:
@UnsupportedAppUsage
private static Map<String, IBinder> sCache = new ArrayMap<String, IBinder>();
@UnsupportedAppUsage
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
private static IBinder rawGetService(String name) throws RemoteException {
......
final IBinder binder = getIServiceManager().getService(name);
......
}
getIServiceManager()与注册时的流程差不多,返回的是ServiceManagerProxy对象,不在依次赘述了。
直接看下getService()
ServiceManagerNative.java->
class ServiceManagerProxy:
@UnsupportedAppUsage
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
进入binder驱动的也与注册类似。不多赘述。
这里过程大致是,通过transact进入binder驱动,同样找到的目标端是servicemanager,向servicemanager发送请求(BR_TRANSACTION)查询服务(上述ServiceManager创建中),servicemanager查询服务获得服务的handle,通过BC_REPLY返回到binder驱动。binder驱动获得服务的handle,最终同样走到binder_transaction()。binder_thread_read()。
mRemote.transact()
下面是一些信息(do_find_service()查询到服务handle后通过bio_put_ref回应的一些信息,binder中进行处理的重要信息):
void bio_put_ref(struct binder_io *bio, uint32_t handle)
{
......
obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj->hdr.type = BINDER_TYPE_HANDLE;
obj->handle = handle;
obj->cookie = 0;
}
最终进入binder_transaction()
static void binder_transaction(struct binder_proc *proc,
......
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
struct flat_binder_object *fp;
fp = to_flat_binder_object(hdr);
ret = binder_translate_handle(fp, t, thread);
.....
binder_alloc_copy_to_buffer(&target_proc->alloc,
t->buffer, object_offset,
fp, sizeof(*fp));
}
static int binder_translate_handle(struct flat_binder_object *fp,
......
if (node->proc == target_proc) {
......
if (fp->hdr.type == BINDER_TYPE_HANDLE)
fp->hdr.type = BINDER_TYPE_BINDER;
else
fp->hdr.type = BINDER_TYPE_WEAK_BINDER;
fp->binder = node->ptr;
fp->cookie = node->cookie;
......
} else {
......
ret = binder_inc_ref_for_node(target_proc, node,
fp->hdr.type == BINDER_TYPE_HANDLE,
NULL, &dest_rdata);
}
}
通过上述方法依次走下去。在binder_translate_handle()
中,node->proc == target_proc
,当前是在servicemanager进程的,而目标进程是请求服务所在进程,所以等于判断不成立。
这个过程非常重要,分两种情况来说:
当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node;
当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。
通过binder_thread_read进行一些处理。binder向客户端发送BR_REPLY。
reply.readStrongBinder()
sp<IBinder> Parcel::readStrongBinder() const
{
ALOGW("BINDER_DEBUG Parcel->readStrongBinder()");
sp<IBinder> val;
......
readNullableStrongBinder(&val);
return val;
}
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
ALOGW("BINDER_DEBUG Parcel->readNullableStrongBinder() val=%p", val);
return unflatten_binder(ProcessState::self(), *this, val);
}
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
ALOGW("BINDER_DEBUG Parcel->unflatten_binder() sp<IBinder> begin");
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(nullptr, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
由上面分析知道,servicemanager传入的是BINDER_TYPE_HANDLE。请求服务与服务不在同一进程,这个值未变,仍是BINDER_TYPE_HANDLE。getStrongProxyForHandle()注册时有讲过,这里不再单独列出。这里就获取到了对应服务的BpBinder(handle)。handle是从servicemanager查到对应服务的handle。这样服务获取就完成了。
简单总结
简单回顾总结下几个点
服务注册与获取大致过程
开始在 Binder---IPC 中所说的,服务注册与获取的大致过程:
服务通过binder驱动注册到ServiceManager,ServiceManager保存了服务的名称、handle等信息 并加入svclist列表中。客户端通过binder驱动向ServiceManager进程查询获取到对应的服务的handle,然后binder将信息返回给客户端,客户端获取得到相应的服务Binder。
与binder的交互命令
总结下 一个完整的服务注册过程与binder交互命令大致如下图:
服务的注册和获取基本类似,两个过程,服务端都是ServiceManager。
Client端(BC_TRANSACTION)--->binder驱动(BR_TRANSACTION_COMPLETE)--->Client端; binder驱动(BR_TRANSACTION)--->Service端(BC_REPLY)--->binder驱动(BR_TRANSACTION_COMPLETE)--->Service端;binder驱动(BR_REPLY)--->Client端。
关于BpBinder、BBinder
总结下readStrongBinder():
请求服务进程与服务进程不在同一进程(如这个服务获取),返回的是BpBinder对象。如果在同一进程,则不在创建新对象 只是引用加1,返回的是BBinder对象。
我们通过handle去获取远程端的Binder对象,如handle为0 就能获取到servicemanager的BpBinder对象,通过查询到的某个服务的handle获取到对应服务的BpBinder对象(本地则是BBinder对象)。
在注册时data.writeStrongBinder(service);
,通过ibinderForJavaObject()将service实体binder对象转换成BBinder,然后传入binder驱动,完成服务注册到servicemanager。
这里的BBinder和BpBinder都是native层的Binder对象。 BBinder是本地Binder(Native Binder),BpBinder即远程端Binder。
BpBinder提供transact()方法来发送请求;BBinder提供了onTransact()接口来接收请求。
BpBinder时客户端创建用于消息发送的代理;BBinder是服务端用于接收消息的。当通信时,Client端通过BinderProxy 经由Bpbinder的transact()方法最终发送请求到binder驱动。binder驱动接收到经过处理,发送给目标进程JavaBBinder,最终经由服务实体的onTransact()接受处理。
在注册过程,servicemanager中svcmgr_handler()相当于服务端Java层的onTransact()。下面是普通服务接收到请求的过程:
frameworks/native/libs/binder/IPCThreadState.cpp
sp<BBinder> the_context_object;
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
......
default:
err = executeCommand(cmd);
......
}
status_t IPCThreadState::executeCommand(int32_t cmd)
{
......
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
{
......
if (tr.target.ptr) {
......
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
......
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
......
}
frameworks/native/libs/binder/Binder.cpp
status_t BBinder::transact(
......
err = onTransact(code, data, reply, flags);
}
frameworks/base/core/jni/android_util_Binder.cpp
status_t onTransact(
......
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
......
}
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
frameworks/base/core/java/android/os/Binder.java
// Entry point from android_util_Binder.cpp's onTransact
@UnsupportedAppUsage
private boolean execTransact(int code, long dataObj, long replyObj,
......
return execTransactInternal(code, dataObj, replyObj, flags, callingUid);
}
private boolean execTransactInternal(int code, long dataObj, long replyObj, int flags,
......
res = onTransact(code, data, reply, flags);
}
这里onTransact()最终调用到子类实现的onTransact(),即具体服务实现的onTransact()方法。
从上又有一般这样的一个结构层次图(网络中很多,上述理解供参考):
binder驱动中的几个常用量
struct binder_node {
......
struct binder_proc *proc;
struct hlist_head refs;
}
binder_node--->binder结点,即binder的实体。服务注册就会创建一个binder_node。
proc: binder_proc,这里是binder实体对应的进程,相当于某个服务在哪进程。
refs: binder实体的引用对象列表,相当于所有使用某个服务的客户端链表。
struct binder_ref {
struct binder_ref_data data;
struct binder_proc *proc;
struct binder_node *node;
}
struct binder_ref_data {
int debug_id;
uint32_t desc;
int strong;
int weak;
};
binder_ref--->跟踪结点的引用,binder_node的引用的信息
proc:引用对象进程,使用服务的进程
node:引用的binder_node,即引用的目标结点
desc:该引用对象的句柄(handle)
struct binder_proc {
struct hlist_node proc_node;
struct list_head todo;
}
binder_proc--->binder进程的上下文信息,每个使用binder的进程都会创建一个binder_proc对象。在打开/dev/binder时就创建了。
proc_node:将该对象链接到全局binder_procs对象中。
todo:该进程的待处理事务队列。
binder驱动结构体很多,需要多注意,不过都有注释,理解不难。
Android10_原理机制系列_Binder机制的更多相关文章
- Android10_原理机制系列_事件传递机制
前言和概述 Android的输入设备,最常用的就是 触摸屏和按键 了.当然还有其他方式,比如游戏手柄,比如支持OTG设备,则可以链接鼠标.键盘等. 那么这些设备的操作 是如何传递到系统 并 控制界面的 ...
- Java的多线程机制系列:(三)synchronized的同步原理
synchronized关键字是JDK5之实现锁(包括互斥性和可见性)的唯一途径(volatile关键字能保证可见性,但不能保证互斥性,详细参见后文关于vloatile的详述章节),其在字节码上编译为 ...
- springboot系列——重试机制原理和应用,还有比这个讲的更好的吗(附完整源码)
1. 理解重试机制 2. 总结重试机制使用场景 3. spring-retry重试组件 4. 手写一个基于注解的重试组件 5. 重试机制下会出现的问题 6. 模板方法设计模式实现异步重试机制 如果有, ...
- Java的多线程机制系列:不得不提的volatile及指令重排序(happen-before)
一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...
- Java的多线程机制系列:(四)不得不提的volatile及指令重排序(happen-before)
一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...
- 深入理解this机制系列第三篇——箭头函数
× 目录 [1]痛点 [2]解决 [3]基本用法[4]回调函数[5]注意事项 前面的话 this机制与函数调用有关,而作用域则与函数定义有关.有没有什么是可以将this机制和作用域联系起来的呢?本文将 ...
- 《深入理解mybatis原理》 Mybatis初始化机制具体解释
对于不论什么框架而言.在使用前都要进行一系列的初始化,MyBatis也不例外. 本章将通过下面几点具体介绍MyBatis的初始化过程. 1.MyBatis的初始化做了什么 2. MyBatis基于XM ...
- PHP5底层原理之垃圾回收机制
概念 垃圾回收机制 是一种内存动态分配的方案,它会自动释放程序不再使用的已分配的内存块. 垃圾回收机制 可以让程序员不必过分关心程序内存分配,从而将更多的精力投入到业务逻辑. 与之相关的一个概念,内存 ...
- iOS学习系列 - 扩展机制category与associative
iOS学习系列 - 扩展机制category与associative category与associative作为objective-c的扩展机制的两个特性,category即类型,可以通过它来扩展方 ...
随机推荐
- centos 7.8 添加磁盘后查看、分区、格式化、挂载
基础环境 公有云 由于磁盘空间快用完了,现在决定多加一个40G磁盘 第一步 分区 fdisk -l #查看当前磁盘信息 fdisk /dev/vdb #对指定磁盘进行操作 如上图一般磁盘的第一个分区都 ...
- Flink on Yarn三部曲之三:提交Flink任务
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 全网通4G工业路由器模块和串口转网口/4G/有线/WiFi/LTE模块的实现原理
随着现在信息化的高速发展,网络信息的需求量大增,在移动的4G流量的场合比如汽车上实现WiFi网络覆盖,户外wifi网络覆盖需求下,4G流量已经明显不够用,而网线到达的成本比较大,难以管控.在这市场痛点 ...
- ret2libc--ROP(pwn)漏洞入门分析
背景知识 fflush 函数,清理缓冲区. fflush(stdout) 一次性输出以上缓冲区所有数据 read(0,&buf,0xAu) 0代表标准输入,标准输出1,标准错误2,&b ...
- Qlik Sense学习笔记之Mashup开发(一)
date: 2018-12-21 12:33:29 updated: 2018-12-21 12:33:29 Qlik Sense学习笔记之Mashup开发(一) 1.基于Qlik Sense API ...
- 模型评价指标:AUC
参考链接:https://www.iteye.com/blog/lps-683-2387643 问题: AUC是什么 AUC能拿来干什么 AUC如何求解(深入理解AUC) AUC是什么 混淆矩阵(Co ...
- Luogu P5072 [Ynoi2015]盼君勿忘
题意 给定一个长度为 \(n\) 的序列 \(a\) 和 \(m\) 次询问,第 \(i\) 次询问需要求出 \([l_i,r_i]\) 内所有子序列去重之后的和,对 \(p_i\) 取模. \(\t ...
- Git系列:常用命令
一.背景 作为一名程序员,怎么能不懂Git那些常用命令呢?于是花费一点时间来总结Git命令.关于安装的话,就不讲了. 二.常用命令 1.配置全局的用户名称和用户邮箱 git config --glob ...
- vue-cli中使用swiper
1.当前项目配置 cnpm install swiper vue-awesome-swiper --save 或指定版本下载 cnpm install swiper@5.4.5 vue-awesome ...
- 【SpringCloud】02.微服务与SpringCloud
微服务的特点 一系列微小的服务共同组成 跑在自己的进程里 每个服务为独立的业务开发 独立部署 分布式管理 异构--不同的语言.不同类型的数据库 微服务架构的基础框架/组件 服务注册发现 服务网关(Se ...