Android基础之Binder分析

1,936 阅读16分钟

1.为什么Binder会在面试中经常被问到?Binder到底是什么?

  • 进程间通信机制
  • 也是一个驱动
  • Binder.java继承Ibinder接口,实现跨进程能力

Android中进程和线程的关系?区别?

  1. 线程是CPU调度的最小单元,同时线程是一种有限的系统资源;而进程一般指一个执行单元,在PC和移动设备上指一个程序或者一个应用
  2. 一般来说,一个App程序至少有一个进程,一个进程至少有一个线程(包含与被包含的关系),通俗来讲就是,在App这个工厂里面有一个进程,线程就是里面的生产线,但主线程(即主生产线)只有一条,而子线程(即副生产线)可以有多个。
  3. 进程有自己独立的地址空间,而进程中的线程共享此地址空间,都可以并发执行。

如何开启多进程?应用是否可以开启N个进程?

在AndroidManifest中给四大组件指定属性android:process开启多进程模式,在内存允许的条件下可以开启N个进程。

为何需要IPC?

所有运行在不同进程的四大组件(Activity、Service、Receiver、ContentProvider)共享数据都会失败,这是由于Android为每个应用分配了独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这会导致在不同的虚拟机中访问同一个类的对象会产生多份副本。

多进程的优点

  1. 扩大内存空间:通过开启多进程获取更大内存空间、两个或者多个应用之间共享数据、微信全家桶。
  2. 风险隔离,一般情况下,一个app就一个进程,如果某个模块崩溃了整个应用就挂了,如果实现多进程,只要保证主模块没有崩溃应用依然可以使用(通过双进程守护来拉起另外的进程)。

每一个进程分配的进程是有限的

//查看系统给每一个进程分配的内存大小
adb shell
getprop dalvik.vm.heapsize

使用场景

  • 开发应用:WebView 、视频播放、音乐播放、大图浏览、推送
  • 系统服务中:打电话、闹钟等等

多进程通信可能会出现的问题?

一般来说,使用多进程通信会造成如下几方面的问题:

  1. 静态成员和单例模式完全失效:独立的虚拟机造成。
  2. 线程同步机制完全失效:独立的虚拟机造成。
  3. SharedPreferences的可靠性下降:这是因为Sp不支持两个进程并发进行读写,有一定几率导致数据丢失。
  4. Application会多次创建:Android系统在创建新的进程时会分配独立的虚拟机,所以这个过程其实就是启动一个应用的过程,自然也会创建新的Application。

2.Binder相对其他进程通信有什么优缺点?

Android中IPC方式、各种方式优缺点?

Linux进程间通信机制有哪些?

我们知道Android也是基于Linux内核,Linux现有的进程通信手段有以下几种:

  • 管道:在创建时分配一个page大小的内存,缓存区大小比较有限;
  • 消息队列:信息复制两次,额外的CPU消耗;不合适频繁或信息量大的通信;
  • 共享内存:无须复制,共享缓冲区直接附加到进程虚拟地址空间,速度快;但进程间的同步问题操作系统无法实现,必须各进程利用同步工具解决;
  • 套接字:作为更通用的接口,传输效率低,主要用于不同机器或跨网络的通信;
  • 信号量:常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等;

为什么选择Binder?

既然有现有的IPC方式,为什么重新设计一套Binder机制呢。主要是出于以上三个方面的考量:

  1. 效率:传输效率主要影响因素是内存拷贝的次数,拷贝次数越少,传输速率越高。从Android进程架构角度分析:对于消息队列、Socket和管道来说,数据先从发送方的缓存区拷贝到内核开辟的缓存区中,再从内核缓存区拷贝到接收方的缓存区,一共两次拷贝,如图:

    而对于Binder来说,数据从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到同一块物理地址的,节省了一次数据拷贝的过程,如图:

    共享内存不需要拷贝,Binder的性能仅次于共享内存。

  2. **稳定性:**上面说到共享内存的性能优于Binder,那为什么不采用共享内存呢,因为共享内存需要处理并发同步问题,容易出现死锁和资源竞争,稳定性较差。Socket虽然是基于C/S架构的,但是它主要是用于网络间的通信且传输效率较低。Binder基于C/S架构 ,Server端与Client端相对独立,稳定性较好。

  3. **安全性:**传统Linux IPC的接收方无法获得对方进程可靠的UID/PID,从而无法鉴别对方身份;而Binder机制为每个进程分配了UID/PID,且在Binder通信时会根据UID/PID进行有效性检测。

3.Binder机制的作用和原理?

传统的IPC传输数据

Linux系统将一个进程分为用户空间和内核空间。对于进程之间来说,用户空间的数据不可共享,内核空间的数据可共享,为了保证安全性和独立性,一个进程不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的 ,这就需要跨进程之间的数据通信方式。普通的跨进程通信方式一般需要2次内存拷贝,如下图所示:

Binder传输数据

一次完整的 Binder IPC 通信过程通常是这样:

  1. 首先 Binder 驱动在内核空间创建一个数据接收缓存区。
  2. 接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系。
  3. 发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。

MMAP的原理

Linux通过将一个虚拟内存区域与一个磁盘上的对象关联起来,以初始化这个虚拟内存区域的内容,这个过程称为内存映射(memory mapping)

对文件进行mmap,会在进程的虚拟内存分配地址空间,创建映射关系。

实现这样的映射关系后,就可以采用指针的方式读写操作这一段内存,而系统会自动回写到对应的文件磁盘上。

所有的系统资源管理都是在内核空间中完成的。比如读写磁盘文件,分配回收内存,从网络接口读写数据等等。用户空间通过系统调用让内核空间完成这些功能。

写文件流程:

1、调用write,告诉内核需要写入数据的开始地址与长度。 2、内核将数据拷贝到内核缓存。 3、由操作系统调用,将数据拷贝到磁盘,完成写入。

Binder框架中ServiceManager的作用?

Binder框架 是基于 C/S 架构的。由一系列的组件组成,包括 Client、Server、ServiceManager、Binder驱动,其中 Client、Server、Service Manager 运行在用户空间,Binder 驱动运行在内核空间。如下图所示:

4.Binder驱动

Binder架构

Binder的jni方法注册讲解

1.zygote启动

1-1.启动zygote进程

zygote是由init进程通过解析 init.zygote.rc 文件而创建的,zygote所对应的可执行程序 app_process,所对应的源文件是 app_main.cpp ,进程名为zygote。

// system/core/rootdir/init.zygote32.rc

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --startsystem-server    
    class main    
    socket zygote stream 660 root system    
    onrestart write /sys/android_power/request_state wake    
    onrestart write /sys/power/state on    
    onrestart restart media    
    onrestart restart netd    
    writepid /dev/cpuset/foreground/tasks
1-2.执行app_main.cpp中的main方法

启动zygote的入口函数是 app_main.cpp 中的main方法。

//frameworks/base/cmds/app_process/app_main.cpp

// 186 
int main(int argc, char* const argv[])

// 248 将zygote标志位置为true。 
if (strcmp(arg, "--zygote") == 0) {    
    zygote = true; 
}

// 306 运行AndroidRuntime.cpp的start方法 
if (zygote) {    
    runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 
}

1-3.AndroidRuntime::start

调用startReg方法来完成jni方法的注册。

frameworks/base/core/jni/AndroidRuntime.cpp

//frameworks/base/core/jni/AndroidRuntime.cpp

// 1007 
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)

// 1051 
if (startReg(env) < 0) {
    
    

//1440 
int AndroidRuntime::startReg(JNIEnv* env)

// 1459 注册jni方法 
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {

    


// 1283 
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env) {    
    // 循环注册jni方法    
    for (size_t i = 0; i < count; i++) {        
        if (array[i].mProc(env) < 0) {            
            return -1;        
        }    
    }    
    return 0; 
}

     
    
// 1296 
static const RegJNIRec gRegJNI[] = {
    
    // 1312     
    REG_JNI(register_android_os_Binder), 
    
}

2.register_android_os_Binder

//frameworks/base/core/jni/android_util_Binder.cpp
    
// 1282 
int register_android_os_Binder(JNIEnv* env) {    
    if (int_register_android_os_Binder(env) < 0)        
        return -1;    
    if (int_register_android_os_BinderInternal(env) < 0)        
        return -1;    
    if (int_register_android_os_BinderProxy(env) < 0)        
        return -1;
}
2-1.int_register_android_os_Binder
//frameworks/base/core/jni/android_util_Binder.cpp

// 843 
static const JNINativeMethod gBinderMethods[] = {     
    /* name, signature, funcPtr */    
    { "getCallingPid", "()I", (void*)android_os_Binder_getCallingPid },    
    { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },    
    { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },    
    { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity},
    { "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },    
    { "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy },    
    { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },   
    { "init", "()V", (void*)android_os_Binder_init },    
    { "destroy", "()V", (void*)android_os_Binder_destroy },    
    { "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable } 
};

// 857 
const char* const kBinderPathName = "android/os/Binder";

// 859 
static int int_register_android_os_Binder(JNIEnv* env) {    
    // 查找文件 kBinderPathName = "android/os/Binder",返回对应Class对象    
    jclass clazz = FindClassOrDie(env, kBinderPathName);
    // 通过gBinderOffsets结构体,保存Java层Binder类的信息,为JNI层访问Java层提供通道    
    gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);    
    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");     
    gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
    // 通过RegisterMethodsOrDie,将为gBinderMethods数组完成映射关系,从而为Java层访问 JNI层提供通道    
    return RegisterMethodsOrDie(        
        env, kBinderPathName,        
        gBinderMethods, 
        NELEM(gBinderMethods));
}

2-2.int_register_android_os_BinderInternal
//frameworks/base/core/jni/android_util_Binder.cpp
    
// 925 
static const JNINativeMethod gBinderInternalMethods[] = {     
    /* name, signature, funcPtr */    
    { "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },    
    { "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },    
    { "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },    
    { "handleGc", "()V", (void*)android_os_BinderInternal_handleGc } };

// 933 
const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";

// 935 
static int int_register_android_os_BinderInternal(JNIEnv* env){    
    // 查找文件kBinderInternalPathName = "com/android/internal/os/BinderInternal",返回Class对象    
    jclass clazz = FindClassOrDie(env, kBinderInternalPathName);
    // 通过gBinderInternalOffsets,保存Java层BinderInternal类的信息,为JNI层访问java 层提供通道    
    gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
    
    // 通过RegisterMethodsOrDie(),将为gBinderInternalMethods数组完成映射关系,从而为 Java层访问JNI层提供通道    
    return RegisterMethodsOrDie(        
        env, kBinderInternalPathName,        
        gBinderInternalMethods, 
        NELEM(gBinderInternalMethods));
}

2-3.int_register_android_os_BinderProxy
//frameworks/base/core/jni/android_util_Binder.cpp

// 1241 
static const JNINativeMethod gBinderProxyMethods[] = {     
    /* name, signature, funcPtr */    
    {"pingBinder",          "()Z", (void*)android_os_BinderProxy_pingBinder},    
    {"isBinderAlive",       "()Z", (void*)android_os_BinderProxy_isBinderAlive},    
    {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
    {"transactNative",      "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact}, 
    {"linkToDeath",         "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath}, 
    {"unlinkToDeath",       "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},    
    {"destroy",             "()V", (void*)android_os_BinderProxy_destroy}, };

// 1252 
const char* const kBinderProxyPathName = "android/os/BinderProxy";

// 1254 
static int int_register_android_os_BinderProxy(JNIEnv* env) {    
    // 查找文件 kBinderProxyPathName = "android/os/BinderProxy",返回对应Class对象    
    jclass clazz = FindClassOrDie(env, "java/lang/Error");    
    gErrorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);

    // 通过gBinderProxyOffsets,保存Java层BinderProxy类的信息,为JNI层访问Java提供通道    
    clazz = FindClassOrDie(env, kBinderProxyPathName);    
    gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);    
    gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", " ()V");    
    gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice", "(Landroid/os/IBinder$DeathRecipient;)V");
    
    gBinderProxyOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");    
    gBinderProxyOffsets.mSelf = GetFieldIDOrDie(env, clazz, "mSelf","Ljava/lang/ref/WeakReference;");  
    
    gBinderProxyOffsets.mOrgue = GetFieldIDOrDie(env, clazz, "mOrgue", "J");
    
    clazz = FindClassOrDie(env, "java/lang/Class");    
    gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", " ()Ljava/lang/String;");
    
    // 通过RegisterMethodsOrDie(),将为gBinderProxyMethods数组完成映射关系,从而为Java 层访问JNI层提供通道    
    return RegisterMethodsOrDie(        
        env, kBinderProxyPathName,        
        gBinderProxyMethods, NELEM(gBinderProxyMethods)); 
}

Binder驱动注册讲解

image-20210414092603045

1.binder_init

主要工作:

  1. 分配内存
  2. 初始化设备
  3. 放入链表 binder_devices

kernel/drivers/staging/android/binder.c

// 4290 设备驱动入口函数 
device_initcall(binder_init);

// 4213 
static int __init binder_init(void)
    
// 4220 创建名为binder的单线程的工作队列 
binder_deferred_workqueue = create_singlethread_workqueue("binder");

// 4269 
ret = init_binder_device(device_name);

kernel/drivers/staging/android/binder.c

// 4186 
static int __init init_binder_device(const char *name)
{    
    int ret;    
    struct binder_device *binder_device;
    
    // 4191 1.为binder设备分配内存    
    binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
    
    // 4195 2.初始化设备    
    binder_device->miscdev.fops = &binder_fops; // 设备的文件操作结构,这是 file_operations结构
    
    binder_device->miscdev.minor = MISC_DYNAMIC_MINOR; //  次设备号 动态分配    
    binder_device->miscdev.name = name; // 设备名,"binder"
    
    binder_device->context.binder_context_mgr_uid = INVALID_UID;    
    binder_device->context.name = name;
    
    // 4202 misc驱动注册    
    ret = misc_register(&binder_device->miscdev);
    
    // 4208 3.将hlist节点添加到binder_devices为表头的设备链表    
    hlist_add_head(&binder_device->hlist, &binder_devices);
    return ret; 
}

misc设备:是没有硬件的一段内存,优点是注册简单

2.binder_open

主要工作:

  1. 创建binder_proc对象
  2. 当前进程信息proc
  3. filp->private_data = proc
  4. 添加到binder_procs链表中

kernel/drivers/staging/android/binder.c

// 3454 
static int binder_open(struct inode *nodp, struct file *filp)

// 3462 为binder_proc结构体在kernel分配内存空间 
proc = kzalloc(sizeof(*proc), GFP_KERNEL);

// 3465 将当前线程的task保存到binder进程的tsk 
get_task_struct(current); proc->tsk = current; 
INIT_LIST_HEAD(&proc->todo); // 初始化todo列表 
init_waitqueue_head(&proc->wait); // 初始化wait队列 
proc->default_priority = task_nice(current); // 将当前进程的nice值转换为进程优先级

// 3474 同步锁,因为binder支持多线程访问 
binder_lock(__func__);
binder_stats_created(BINDER_STAT_PROC); // binder_proc对象创建数加1 
hlist_add_head(&proc->proc_node, &binder_procs); // 将proc_node节点添加到 binder_procs的队列头部 
proc->pid = current->group_leader->pid; // 进程pid 
INIT_LIST_HEAD(&proc->delivered_death); // 初始化已分发的死亡通知列表 
filp->private_data = proc; // 将这个binder_proc与filp关联起来,这样下次通过filp就能找 到这个proc了
binder_unlock(__func__); // 释放同步锁

3.binder_mmap

主要工作:

  1. 通过用户空间的虚拟内存大小,分配一块内核的虚拟内存
  2. 分配一块物理内存(4KB)
  3. 把这块物理内存分别映射到用户空间的虚拟内存和内核的虚拟内存。

kernel/drivers/staging/android/binder.c

// 3355  vma:进程的虚拟内存
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
// 3366 保证映射内存大小不超过4M 
if ((vma->vm_end - vma->vm_start) > SZ_4M)    
    vma->vm_end = vma->vm_start + SZ_4M;

// 3382 同步锁,保证一次只有一个进程分配内存,保证多进程间的并发访问 
mutex_lock(&binder_mmap_lock); 
// 是否已经做过映射,执行过则进入if,goto跳转,释放同步锁后结束binder_mmap方法 
if (proc->buffer) {   
    goto err_already_mapped;
} 
// 采用 VM_IOREMAP方式,分配一个连续的内核虚拟内存,与进程虚拟内存大小一致 
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); 
// 内存分配不成功直接报错 
if (area == NULL) {    
    ret = -ENOMEM;    
    failure_string = "get_vm_area";    
    goto err_get_vm_area_failed; 
} 
// 将proc中的buffer指针指向这块内核的虚拟内存 
proc->buffer = area->addr; 
// 计算出用户空间和内核空间的地址偏移量。地址偏移量 = 用户虚拟内存地址 - 内核虚拟内存地址 
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; 
mutex_unlock(&binder_mmap_lock); // 释放锁

// 3407 分配物理页的指针数组,数组大小为vma的等效page个数 ,4kb的物理内存
proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);

// 3418 分配物理页面,同时映射到内核空间和进程空间,先分配1个物理页。 
if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) 

kernel/drivers/staging/android/binder.c

// 576 
static int binder_update_page_range(struct binder_proc *proc, int allocate,
                                    void *start, void *end,                    
                                    struct vm_area_struct *vma)

// 609 allocate为1,代表分配内存过程。如果为0则代表释放内存过程 
if (allocate == 0)        
      goto free_range;

// 624 分配一个page的物理内存 
*page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);

// 630 物理空间映射到虚拟内核空间
ret = map_kernel_range_noflush((unsigned long)page_addr,                   
                               PAGE_SIZE, PAGE_KERNEL, page);

// 641 物理空间映射到虚拟进程空间 
ret = vm_insert_page(vma, user_page_addr, page[0]);

kernel/drivers/staging/android/binder.c

// 3355 
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)

// 3425 
list_add(&buffer->entry, &proc->buffers);// 将buffer连入buffers链表中 
buffer->free = 1; // 此内存可用 
binder_insert_free_buffer(proc, buffer);// 将buffer插入proc->free_buffers链表中
proc->free_async_space = proc->buffer_size / 2; // 异步的可用空闲空间大小 
barrier(); 
proc->files = get_files_struct(current); 
proc->vma = vma; 
proc->vma_vm_mm = vma->vm_mm;
3-1.binder_insert_free_buffer

kernel/drivers/staging/android/binder.c

// 494 
static void binder_insert_free_buffer(struct binder_proc *proc,struct binder_buffer *new_buffer)
    
// 511 
while (*p) {    
    parent = *p;    
    buffer = rb_entry(parent, struct binder_buffer, rb_node);
    
    // 计算得出空闲内存的大小    
    buffer_size = binder_buffer_size(proc, buffer);
    if (new_buffer_size < buffer_size)        
        p = &parent->rb_left;   
    else        
        p = &parent->rb_right; 
} 
rb_link_node(&new_buffer->rb_node, parent, p); // 将 buffer插入 proc->free_buffers 链表中
rb_insert_color(&new_buffer->rb_node, &proc->free_buffers)

4.binder_ioctl

只要做读写操作

kernel/drivers/staging/android/binder.c

// 3241 
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 
    
// 3254 进入休眠状态,直到中断唤醒 
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);

// 3259 根据当前进程的pid,从binder_proc中查找binder_thread, 
//      如果当前线程已经加入到proc的线程队列则直接返回, 
//      如果不存在则创建binder_thread,并将当前线程添加到当前的proc 
thread = binder_get_thread(proc);

// 3265 进行binder的读写操作
switch (cmd) {    
    case BINDER_WRITE_READ:        
        ret = binder_ioctl_write_read(filp, cmd, arg, thread);        
        if (ret)
4-1.binder_ioctl_write_read

kernel/drivers/staging/android/binder.c

// 3136
static int binder_ioctl_write_read(struct file *filp,                
                                   unsigned int cmd, unsigned long arg,                
                                   struct binder_thread *thread)
    
// 3150 把用户空间数据ubuf拷贝到bwr ,copy的数据头,不是有效数据
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
    
// 3160 
if (bwr.write_size > 0) { // 当写缓存中有数据,则执行binder写操作   
        ret = binder_thread_write(proc, thread,                  
                                  bwr.write_buffer,                  
                                  bwr.write_size,                  
                                  &bwr.write_consumed); 
} 
if (bwr.read_size > 0) { // 当读缓存中有数据,则执行binder读操作    
    ret = binder_thread_read(proc, thread, bwr.read_buffer,                 
                             bwr.read_size,                
                             &bwr.read_consumed,                 
                             filp->f_flags & O_NONBLOCK);    
    // 进程todo队列不为空,则唤醒该队列中的线程    
    if (!list_empty(&proc->todo))        
        wake_up_interruptible(&proc->wait); 
}
    
// 3192 把内核空间数据bwr拷贝到ubuf 
if (copy_to_user(ubuf, &bwr, sizeof(bwr))){

数据结构

file_operations
static const struct file_operations binder_fops = {    
    .owner = THIS_MODULE,    
    .poll = binder_poll,    
    .unlocked_ioctl = binder_ioctl,    
    .compat_ioctl = binder_ioctl,    
    .mmap = binder_mmap,    
    .open = binder_open,    
    .flush = binder_flush,    
    .release = binder_release, 
};
binder_proc

每个进程调用open()打开binder驱动都会创建该结构体,用于管理IPC所需的各种信息。

struct binder_proc {    
    struct hlist_node proc_node; // 进程节点    
    struct rb_root threads; // binder_thread红黑树的根节点    
    struct rb_root nodes; // binder_node红黑树的根节点    
    struct rb_root refs_by_desc; // binder_ref红黑树的根节点(以 handle为 key)    
    struct rb_root refs_by_node; // binder_ref红黑树的根节点(以 ptr为 key)    
    int pid; // 相应进程 id    
    struct vm_area_struct *vma; // 指向进程虚拟地址空间的指针    
    struct mm_struct *vma_vm_mm; // 相应进程的内存结构体    
    struct task_struct *tsk; //     相应进程的 task结构体    
    struct files_struct *files; // 相应进程的文件结构体    
    struct hlist_node deferred_work_node;    
    int deferred_work;    
    void *buffer; // 内核空间的起始地址    
    ptrdiff_t user_buffer_offset; // 内核空间与用户空间的地址偏移量
    struct list_head buffers; // 所有的 buffer    
    struct rb_root free_buffers; // 空闲的 buffer    
    struct rb_root allocated_buffers; // 已分配的 buffer    
    size_t free_async_space; // 异步的可用空闲空间大小
    struct page **pages; // 指向物理内存页指针的指针    
    size_t buffer_size; // 映射的内核空间大小    
    uint32_t buffer_free; // 可用内存总大小    
    struct list_head todo; // 进程将要做的事    
    wait_queue_head_t wait; // 等待队列    
    struct binder_stats stats; // binder统计信息    
    struct list_head delivered_death; // 已分发的死亡通知    
    int max_threads; // 最大线程数    
    int requested_threads; // 请求的线程数    
    int requested_threads_started; // 已启动的请求线程数    
    int ready_threads; // 准备就绪的线程个数    
    long default_priority; // 默认优先级    
    struct dentry *debugfs_entry;    
    struct binder_context *context; 
};
binder_node
struct binder_node {    
    int debug_id; // 节点创建时分配,具有全局唯一性,用于调试使用    
    struct binder_work work;    
    union {        
        struct rb_node rb_node; // binder节点正常使用,union        
        struct hlist_node dead_node; // binder节点已销毁,union    
    };    
    struct binder_proc *proc; // binder所在的进程,见后面小节    
    struct hlist_head refs; // 所有指向该节点的 binder引用队列    
    int internal_strong_refs;    
    int local_weak_refs;    
    int local_strong_refs;    
    binder_uintptr_t ptr; // 指向用户空间 binder_node的指针,对应于 flat_binder_object.binder 
    binder_uintptr_t cookie; // 指向用户空间 binder_node的指针,附件数据,对应于 flat_binder_object.cookie
    unsigned has_strong_ref:1; // 占位 1bit    
    unsigned pending_strong_ref:1; // 占位 1bit    
    unsigned has_weak_ref:1; // 占位 1bit    
    unsigned pending_weak_ref:1; // 占位 1bit    
    unsigned has_async_transaction:1; // 占位 1bit    
    unsigned accept_fds:1; // 占位 1bit    
    unsigned min_priority:8; // 占位 8bit,最小优先级    
    struct list_head async_todo; // 异步todo队列 
};

binder_buffer
struct binder_buffer {    
    struct list_head entry; // buffer实体的地址    
    struct rb_node rb_node; // buffer实体的地址               
            /* by address */    
    unsigned free:1; // 标记是否是空闲buffer,占位1bit    
    unsigned allow_user_free:1; // 是否允许用户释放,占位1bit    
    unsigned async_transaction:1; // 占位1bit    
    unsigned debug_id:29; // 占位29bit
    struct binder_transaction *transaction; // 该缓存区的需要处理的事务
    struct binder_node *target_node; // 该缓存区所需处理的Binder实体    
    size_t data_size; // 数据大小    
    size_t offsets_size; // 数据偏移量    
    size_t extra_buffers_size;    
    uint8_t data[0]; // 数据地址 
};

5.如何启动service_manager服务

1.启动servicemanager进程

ServiceManager是由init进程通过解析init.rc文件而创建的,其所对应的可执行程序servicemanager, 所对应的源文件是service_manager.c,进程名为servicemanager。

system/core/rootdir/init.rc
// 602 
service servicemanager /system/bin/servicemanager    
    class core    
    user system    
    group system    
    critical    
    onrestart restart healthd    
    onrestart restart zygote    
    onrestart restart media    
    onrestart restart surfaceflinger    
    onrestart restart drm

2.main

启动ServiceManager的入口函数是 service_manager.c 中的main()方法。

frameworks/native/cmds/servicemanager/service_manager.c
// 354 
int main(int argc, char **argv)

// 358 打开 binder驱动,申请 128k字节大小的内存空间---见后面小节 
bs = binder_open(128*1024);

// 364 设为守护进程,成为 binder大管理者---见后面小节 
if (binder_become_context_manager(bs)) {

// 391 进入无限循环,处理client端发来的请求---见后面小节 
binder_loop(bs, svcmgr_handler);

2-1.binder_open

2-2.binder_become_context_manager

2-2-1.binder_ioctl
2-2-2.binder_ioctl_set_ctx_mgr
2-2-2-1.binder_new_node

2-3.binder_loop

2-3-1.binder_write
2-3-2.binder_thread_write
2-3-3.binder_thread_read

6.如何获取service_manager服务

image-20210414073146204

image-20210414073246912

7.AIDL

aidl主要负责两个进行之间进行通信,在使用上,分为两个角色:服务端(负责被调用)、客户端(负责调用)。两个进程都可以为服务端和客户端来实现互相调用。

  1. 两端建立相同的AIDL,包名文件名一致,如果有数据类,数据类也要一模一样。
  2. 服务端实现一个服务,以及其中的stub方法;
  3. 客户端绑定服务,并调用方法,其中实现由proxy完成

使用参考:blog.csdn.net/weixin_3381…

AIDL生成的类:参考

手动实现一个AILD

调用的接口

public interface IPersonManager extends IInterface {

    void addPerson(Person person) throws RemoteException;

    List<Person> getPersonList() throws RemoteException;
}

Person

public class Person implements Parcelable {

    private String name;
    private int grade;

    public Person(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }

    protected Person(Parcel in) {
        this.name = in.readString();
        this.grade = in.readInt();
    }

    public static final Creator<Person> CREATOR = new Creator<Person>() {
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(grade);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", grade=" + grade +
                '}';
    }
}

服务端

Stub

public abstract class Stub extends Binder implements IPersonManager {

    private static final String DESCRIPTOR = "com.enjoy.binder.common.IPersonManager";

    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }

    public static IPersonManager asInterface(IBinder binder) {
        if ((binder == null)) {
            return null;
        }
        IInterface iin = binder.queryLocalInterface(DESCRIPTOR);
        if ((iin != null) && (iin instanceof IPersonManager)) {
            return (IPersonManager) iin;
        }
        return new Proxy(binder);
    }

    @Override
    public IBinder asBinder() {
        return this;
    }

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            case INTERFACE_TRANSACTION:
                reply.writeString(DESCRIPTOR);
                return true;

            case TRANSACTION_addPerson:
                Log.e("leo", "Stub,TRANSACTION_addPerson: " + Thread.currentThread());
                data.enforceInterface(DESCRIPTOR);
                Person arg0 = null;
                if ((0 != data.readInt())) {
                    arg0 = Person.CREATOR.createFromParcel(data);
                }
                this.addPerson(arg0);
                reply.writeNoException();
                return true;

            case TRANSACTION_getPersonList:
                data.enforceInterface(DESCRIPTOR);
                List<Person> result = this.getPersonList();
                reply.writeNoException();
                reply.writeTypedList(result);
                return true;
        }
        return super.onTransact(code, data, reply, flags);
    }

    static final int TRANSACTION_addPerson = IBinder.FIRST_CALL_TRANSACTION;
    static final int TRANSACTION_getPersonList = IBinder.FIRST_CALL_TRANSACTION + 1;
}

RemoteService

public class RemoteService extends Service {

    private ArrayList<Person> persons;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        persons = new ArrayList<>();
        Log.e("LeoAidlService", "success onBind");
        return iBinder;
    }

    private IBinder iBinder = new Stub() {
        @Override
        public void addPerson(Person person) throws RemoteException {
            persons.add(person);
        }

        @Override
        public List<Person> getPersonList() throws RemoteException {
            return persons;
        }
    };
}

AndroidManifest.xml

 <service
      android:name=".server.RemoteService"
      android:exported="true"
      android:process=":remote">
      <intent-filter>
            <action android:name="com.xxx.binder" />
            <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
</service>

客户端

Proxy

public class Proxy implements IPersonManager {

    private static final String DESCRIPTOR = "com.enjoy.binder.common.IPersonManager";

    private IBinder mRemote;

    public Proxy(IBinder remote) {
        mRemote = remote;
    }

    @Override
    public void addPerson(Person person) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            if ((person != null)) {
                data.writeInt(1);
                person.writeToParcel(data, 0);
            } else {
                data.writeInt(0);
            }
            Log.e("leo", "Proxy,addPerson: " + Thread.currentThread());
            //同步的情况,transcat调用后会挂起,一般都是同步
            mRemote.transact(Stub.TRANSACTION_addPerson, data, reply, 0);
            reply.readException();
        } finally {
            reply.recycle();
            data.recycle();
        }
    }

    @Override
    public List<Person> getPersonList() throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        List<Person> result;
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            mRemote.transact(Stub.TRANSACTION_getPersonList, data, reply, 0);
            reply.readException();
            result = reply.createTypedArrayList(Person.CREATOR);
        } finally {
            reply.recycle();
            data.recycle();
        }
        return result;
    }

    @Override
    public IBinder asBinder() {
        return mRemote;
    }
}

ClientActivity

public class ClientActivity extends AppCompatActivity {

    private IPersonManager iPersonManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //绑定服务
        initAndBindService();
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.e("leo", "------------onClick:" + Thread.currentThread());
                    iPersonManager.addPerson(new Person("leo", 3));
                    List<Person> persons = iPersonManager.getPersonList();
                    Log.e("leo", persons.toString() + "," + Thread.currentThread());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void initAndBindService(){
        Intent intent = new Intent(this, RemoteService.class);
        intent.setAction("com.enjoy.binder");
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("leo", "onServiceConnected: success");
            iPersonManager = Stub.asInterface(service);// proxy
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e("leo", "onServiceDisconnected: success");
            iPersonManager = null;
        }
    };
}