01. Android Binder图解 小米系统专家 解析Service 的addService注册过程 (安卓12)

很多BAT也不一定能懂的binder机制!
我同事从小米跳槽过来,干安卓framework层10年,是小米的专家级别
然后他把binder驱动层全部和我讲解了一遍,然后我这边做个笔记分享给大家。
因为搞懂binder需要会c,linux内核知识。看java根本就看不懂!

分4篇文字讲解:

01. Android Binder图解 小米系统专家 解析Service 的addService注册过程 (安卓12)

02. Android Binder图解 小米系统专家 解析 ServiceManager和binder通信 (安卓12)

03. Android Binder图解 小米系统专家 解析binder驱动层解析binder通信过程 (安卓12)

04. Android Binder图解 小米系统专家 从binder java层解析binder整个流程(安卓12)

binder包含4部分:我将Binder机制分为了Java Binder、Native Binder、Kernel Binder,

20200824193035435.png

一句话总结:把service服务通过binder驱动添加到serverManager的过程

系统源码位置:

<pre style="font-size: 0.817rem; font-family: "JetBrains Mono", monospace; overflow-wrap: break-word; margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198);">/frameworks/av/media/mediaserver/main_mediaserver.cpp
/frameworks/native/libs/binder/ProcessState.cpp
/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
/frameworks/native/libs/binder/IServiceManager.cpp
/frameworks/native/include/binder/IInterface.h
/frameworks/native/libs/binder/IServiceManager.cpp
/frameworks/native/libs/binder/Binder.cpp
/frameworks/native/libs/binder/IPCThreadState.cpp</pre>

一. MediaPlayerService是怎么创建的

media进程是init进程解析init.rc开启的

Media 进程是由

init 进程通过解析 init.rc 文件而创建的。

service media /system/bin/mediaserver

class main

user media

group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm     

ioprio rt 4

二:我们先来看MediaServer的入口函数,代码如下所示。
/frameworks/av/media/mediaserver/main_mediaserver.cpp

**<pre style="font-size: 0.817rem; font-family: "JetBrains Mono", monospace; overflow-wrap: break-word; margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198);">int main(int argc __unused, char argv __unused)
{
signal(SIGPIPE, SIG_IGN);
//获取ProcessState实例
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
ALOGI("ServiceManager: %p", sm.get());
InitializeIcuOrDie();
//注册MediaPlayerService
MediaPlayerService::instantiate();//1
ResourceManagerService::instantiate();
registerExtensions();
//启动Binder线程池
ProcessState::self()->startThreadPool();
//当前线程加入到线程池
IPCThreadState::self()->joinThreadPool(); }
</pre>

ProcesState源码的关键:

打开binder驱动

static int open_driver()
{
   int fd = open("/dev/binder", O_RDWR);
   if (fd >= 0) {              
       //设置驱动层的最大线程数;调用的时binder_ioctl()方法;
       size_t maxThreads = 15;
       result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
   } else {
       ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
   }
   return fd;
}

三. 添加defaultServiceManager()

frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

<pre style="font-size: 0.817rem; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; overflow-wrap: break-word; margin: 8px 0px; background-color: rgb(43, 43, 43); color: rgb(169, 183, 198);">void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService,());
}
</pre>

四:传递数据

frameworks/native/libs/binder/IServiceManager.cpp

 virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                bool allowIsolated, int dumpsysPriority) {
        Parcel data, reply;//数据包
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name); //name值为"media.player"
        data.writeStrongBinder(service); //service值为MediaPlayerService
        data.writeInt32(allowIsolated ? 1 : 0);
        data.writeInt32(dumpsysPriority);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);//1
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }

然后传给BpBinder的transact函数,代码如下所示。
frameworks/native/libs/binder/BpBinder.cpp

status_t BpBinder::transact(
   uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
   if (mAlive) {
       status_t status = IPCThreadState::self()->transact(
           mHandle, code, data, reply, flags);
       if (status == DEAD_OBJECT) mAlive = 0;
       return status;
   }

   return DEAD_OBJECT;
}

BpBinder类通过IPCThreadState类来与Binder驱动交互

BpBinder将逻辑处理交给IPCThreadState

IPCThreadState* IPCThreadState::self()
{   
   //首次进来gHaveTLS的值为false
   if (gHaveTLS) {
restart:
       const pthread_key_t k = gTLS;//1
       IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);//2
       if (st) return st;
       return new IPCThreadState;//3
   }
   ...
   pthread_mutex_unlock(&gTLSMutex);
   goto restart;
}

IPCThreadState的transact函数。

在内存中创建一个Binder节点,将自己置为0号节点,这里的handle 值为 0 代表是 ServiceManager 进程

  • Binder驱动在内核空间中为传输的Binder实体对象创建对应的Binder节点

frameworks/native/libs/binder/IPCThreadState.cpp

*```
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel
reply, uint32_t flags)
{
status_t err;

flags |= TF_ACCEPT_FDS;
...
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);//1

if (err != NO_ERROR) {
    if (reply) reply->setError(err);
    return (mLastError = err);
}

if ((flags & TF_ONE_WAY) == 0) {
   ...
    if (reply) {
        err = waitForResponse(reply);//2
    } else {
        Parcel fakeReply;
        err = waitForResponse(&fakeReply);
    }
   ...
} else {
   //不需要等待reply的分支
    err = waitForResponse(NULL, NULL);
}

return err;

}

**总结:

1.addService函数将数据打包发送给BpBinder来进行处理。

2.BpBinder新建一个IPCThreadState对象,并将通信的任务交给IPCThreadState。

3.IPCThreadState的writeTransactionData函数用于将命令协议和数据写入到mOut中。

4.IPCThreadState的waitForResponse函数主要做了两件事,一件事是通过ioctl函数操作mOut和mIn来与Binder驱动进行数据交互,另一件事是处理各种命令协议。**

**open 是打开驱动、mmap 是映射驱动、ioctl 是操作驱动、close 是关闭驱动,

分别对应驱动层的 binder_open、binder_mmap、binder_ioctl 和 binder_colse 方法

最终通过ioctl函数和Binder驱动进行通信,最后是交给了binder 驱动的 ioctl 方法,这一部分涉及到Kernel Binder的内容**

面试常问的问题:

问题:请问****MediaPlayerService****所在的进程,如何和binder驱动通信的?(重点)

MediaPlayerService是如何注册的。通过了解MediaPlayerService是如何注册的,可以得知系统服务的注册过程

我的理解:

1).打开binder驱动

2). 把对应的参数,封装成bpbinder序列化的对象,交给binder驱动

打开/dev/binder设备,这样的话就相当于和内核binder机制有了交互的通道

l 映射fd到内存,设备的fd传进去后,估计这块内存是和binder设备共享的

binder_ioctl()

问题:MediaPlayerService和servermanager是不同进程,如何通信的?

通过binder驱动。内核,内存映射关系。

————————————————

问题:bpbinder有什么作用?

Bn 是Binder Native的含义,是和Bp相对的,Bp的p是proxy代理的意思,那么另一端一定有一个和代理打交道的东西,这个就是Bn。

讲到这里会有点乱喔。先分析下,到目前为止都构造出来了什么。

l BpServiceManager

l BnMediaPlayerService

数据流向:

具体的数据有 interfaceToken(远程服务的名称)、handle(远程服务的句柄)、cookie(本地服务的地址),

有两个结构体 flat_binder_object 和 binder_write_read。

问题:Media 服务是如何添加到servermanager中的?

1).Media 进程是由 init 进程通过解析 init.rc 文件而创建的。

2). 最后是交给了binder 驱动的 ioctl 方法

问题:binder进程是在哪里启动的?

我们知道Zygote进程会调用AndroidRuntime::startReg函数注册一系列的JNI函数,而这其中就包括我们的Android Framework层的Binder框架层相关的JNI,此时就标志着Framework层BInder框架的启动,而不是到了system_server进程才开始启动的

!
1641780705473-ti3.png
binder.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容