Zygote通信为什么用Socket,而不是Binder?

我觉得,chatgpt的答案好像更适合答题。
为什么zygote使用socket而不是binder

Zygote是Android中的一个重要进程,它是启动应用程序进程的父进程。Zygote使用Socket来与应用程序进程进行通信,而不是使用Android中的IPC机制Binder,这是因为Socket和Binder有不同的优缺点,而在Zygote进程中使用Socket可以更好地满足Zygote进程的需求。

首先,Socket具有良好的跨平台性,能够在不同的操作系统和语言之间进行通信。这对于Zygote进程来说非常重要,因为它需要在不同的设备和架构上运行,并且需要与不同的应用程序进程进行通信。使用Socket可以让Zygote进程更加灵活和可扩展,因为它不需要考虑Binder所带来的特定限制和要求。

其次,Socket具有简单的API和易于使用的特点。Zygote进程需要快速启动并与应用程序进程建立通信,Socket提供了快速、可靠的通信方式,并且使用Socket API也很容易实现。相比之下,Binder需要更多的配置和维护工作,这对于Zygote进程来说可能会增加不必要的复杂性和开销。

最后,Socket在数据传输时具有更低的延迟和更高的吞吐量,这对于Zygote进程来说非常重要。Zygote进程需要在较短的时间内启动应用程序进程,并且需要传输大量的数据和代码,Socket的高性能和低延迟使其成为更好的选择。

总之,Zygote进程使用Socket而不是Binder是基于其优点和需求而做出的选择。虽然Binder在Android中扮演着重要的角色,但在某些情况下,使用Socket可以提供更好的性能和更大的灵活性。
——分割线——
看完《安卓传奇:Android缔造团队回忆录》后,我觉得这个问题的答案书中给出了.这段历史是这样的...
先来看看书中关于Zygote的灵感来源,Emacs.

是Dalvik小组为Android 1.0 开发的另一个东西。Zygote就像你做三明治时用的面包片。当然,你也可以在每次做三明治时从头开始烤面包,但如果是这样的话,每次你想吃三明治都要花大量的时间和精力。很明显,如果有现成的面包,你只需要把它切成片,并更快更容易地做出三明治。Zygote就像做三明治用的面包。
Dan的这个想法来自Emacs(UNIX系统上的一个非常流行的文本编辑器)的一个特性,我们可以随时转储编辑器的状态,稍后可以从这个保存点启动Emacs(这个过程被巧妙地称为反转储(undump))。这意味着Emacs可以更快地启动,因为它只需要从磁盘上恢复状态,
不需要在启动时重新执行一大堆代码逻辑。“我的想法是我们实现一个具有反转储功能的系统,就像Emacs最‘著名’(至少对我来说)的那个特性。Mike Fleming说:‘我们跳过转储和重新加载这些步骤,怎么样?’说完他就开干了。”
Mike 让系统跑了起来,从根本上改变了应用程序的启动方式。原先的每个应用程序在启动时都需要加载必要的代码,并进行初始化。Zygote 创建了一个包含大部分核心平台代码的进程,并几乎预加载和初始化了所有这些代码。每当有应用程序启动时,都会通过分叉
(将其复制到一个新进程中)Zygote 进程,让应用程序立即进入即将就绪的状态。

而binder的来源.

Binder 的概念可以追溯到 Be 公司。George Hoffman 是 Be 公司图形和框架团队的负责人,他需要一种机制让 Be 的互联网设备的 JavaScript UI 层与底层系统服务发生交互,于是就有了 Binder。随着 Be 公司的工程师后来加入 PalmSource 开发 Palm OS,再到后来加入 Android,Binder 也都一直在演化。George 最终没有参与开发 Android,但他与 Be 和 PalmSource 的未来 Android 工程师一起设计了许多概念,这些概念最终都出现在 Android 上,比如 Activity 和 Intent。
Android 设备上始终运行着许多进程,负责处理系统的各种任务。系统进程负责进程的管理、应用的启动、窗口的管理和其他底层的操作系统功能。电话进程负责保持通话正常连接。运行中的前台应用进程为用户提供交互功能。系统 UI 进程负责处理导航按钮、状态栏和通知。还有很多其他进程,它们都需要在某个时刻与其他流程通信。
通常来说,IPC 机制是一种简单而底层的东西,而这也正是 Danger 前工程师们想要的。
黄威说:“Danger 做事喜欢速战速决,但主要还是要简单。”但来自 Be 公司的工程师,包括 Jeff、Joe 和 Dianne,更喜欢他们在 PalmSource 实现的功能更全面(也更复杂)的 Binder。
况且,Binder 是开源的,可以直接用在这个新平台上。
这一分歧造成了团队之间的摩擦。Mike Fleming 站在 Danger 一边:“我对 Binder 持怀疑态度。我认为它没有经过深思熟虑。这确实是他们在 Palm 做的,但并没有被用在真正的产品中。”
“我感觉特别糟糕的是对Binder的阻塞调用会导致另一边也阻塞。我觉得这导致了很多不必要的线程开销,而且没有为我们带来任何价值。另外,初始的Binder Linux内核驱动程序也不是很健壮。为了让它更健壮,我们也是费了很大一番功夫的。”
对Binder持怀疑态度的人并没有赢得这场战斗,Jeff和他的小组奋勇向前,实现了Binder,成为Android框架的一个基础部分。与此同时,Mike在他的电话功能中跳过Binder:“我在Java进程和本地接口进程之间开了一个UNIX域套接字。”

binder当初并不成熟,团队成员对于进程间通讯更倾向于用socket.后面为了做了很多优化,才使得binder通讯变得成熟稳定.
关于Android操作系统,书中推荐阅读《现代操作系统》,并深入阅读介绍 Android 的章节(10.8)。那一章是 Dianne Hackborn 写的,为 Binder和 Linux 扩展等内容提供了详尽的细节。另关于handle设计思想的理解,我推荐阅读《C++沉思录》.

----------分割线---------

要想了解这个问题,首先需要对Linux进程间通讯机制有一定的了解。

1.Linux进程间通讯机制

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

Binder机制基于开源的OpenBinder。http://www.angryredplanet.com/~hackbod/openbinder/docs/html/BinderIPCMechanism.html

2. socket 与 binder 对比

先来看看 socket与binder 两种进程间通讯机制 对比。


https://www.jianshu.com/p/066d99da7cbd
http://gityuan.com/2015/11/21/binder-framework/

接下来回顾下 Zygote启动和Android启动。
Zygote启动过程的函数调用类大致流程:


http://gityuan.com/2016/02/13/android-zygote/#jnistartreg

http://gityuan.com/2016/02/13/android-zygote/#jnistartreg
Zygote启动过程:
1.解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法;
2.调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数;
3.通过JNI方式调用ZygoteInit.main(),第一次进入Java世界;
4.registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
5.preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高app启动效率;
6.zygote完毕大部分工作,接下来再通过startSystemServer(),fork得力帮手system_server进程,也是上层framework的运行载体。
7.zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

下面来看一张图,标示了调用startService之后的通讯流程。

http://gityuan.com/2016/03/06/start-service/

图中涉及3种IPC通信方式:BinderSocket以及Handler,在图中分别用3种不同的颜色来代表这3种通信方式。一般来说,同一进程内的线程间通信采用的是 Handler消息队列机制,不同进程间的通信采用的是binder机制,另外与Zygote进程通信采用的Socket

Android系统启动流程如下:


https://www.jianshu.com/p/3e033aeb44f8

现在回到问题,为什么Zygote通信为什么用Socket,而不是Binder?

具体可看这篇:
android中AMS通知Zygote去fork进程为什么使用socket而不使用binder?

可从以下五个方面分析:
1.先后时序问题:
binder驱动是早于init进程加载的。而init进程是安卓系统启动的第一个进程。
安卓中一般使用的binder引用,都是保存在ServiceManager进程中的,而如果想从ServiceManager中获取到对应的binder引用,前提是需要注册。虽然Init进程是先创建ServiceManager,后创建Zygote进程的。虽然Zygote更晚创建,但是也不能保证Zygote进程去注册binder的时候,ServiceManager已经初始化好了。注册时间点无法保证,AMS无法获取到Zygote的binder引用,这是原因之一。

https://www.jianshu.com/p/3f3f8a5bbc6b

2.多线程问题
Linux中,fork进程是不推荐fork一个多线程的进程的,因为如果存在锁的情况下,会导致锁异常。
而如果自身作为binder机制的接收者,就会创建一个额外的线程来进行处理(发送者进程是无影响的)。
所以,如果使用binder机制,就会导致去fork一个多线程的进程,这是原因之二。

3.效率问题
AMS和Zygote之间使用的LocalSocket,相对于网络Socket,减少了数据验证等环节,所以其实效率相对于正常的网络Socket会大幅的提升。虽然还是要经过两次拷贝,但是由于数据量并不大,所以其实影响并不明显。
所以,LocalSocket效率其实也不低,这是原因之三。

4.安全问题
LocalSocket其实也有权限校验,并不意味着可以被所有进程随意调用,这是原因之四。

5.Binder拷贝问题
如果使用binder通讯机制的话,从Zygote中fork出子进程会拷贝Zygote中binder对象。所以就凭白多占用了一块无用的内存区域。而Binder对象不能释放。Binder的特殊性在于其是成对存在的,其分为Client端对象和Server端对象。假设我们使用binder,如果要释放掉APP的Server端binder引用对象,就必须释放掉AMS中的Client端binder对象,那这样就会导致AMS失去binder从而无法正常向Zygote发送消息。
而使用socket通讯机制的话,fork出APP进程之后,APP进程会去主动的关闭掉这个socket,从而释放这块区域。相关代码在ZygoteConnection的processCommand方法中:

try {
            if (pid == 0) {
            // in child
            zygoteServer.setForkChild();
 
            zygoteServer.closeServerSocket();
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
 
            return handleChildProc(parsedArgs, childPipeFd,
                                    parsedArgs.mStartChildZygote);
            } else {
               // In the parent. A pid < 0 indicates a failure and will be handled in
               // handleParentProc.
               IoUtils.closeQuietly(childPipeFd);
               childPipeFd = null;
               handleParentProc(pid, serverPipeFd);
               return null;
            }
    } 

所以,使用binder会造成额外的内存占用,这是原因之五。

另外,binder调用一般是同步阻塞的。如果使用oneway,是非阻塞(像一些系统服务调用应用进程的时候就会使用 oneway,比如 AMS 调用应用进程启动 Activity,这样就算应用进程中做了耗时的任务,也不会阻塞系统服务的运行。)。但是,binder驱动对于oneway的调用是类似于handler sendmessage那样的,挨个处理,所以如果服务端的oneway接口处理太慢而客户端调用太多的话,来不及处理的调用会占满binder驱动的缓存,导致其他调用抛出上面的transaction failed。
oneway 方法的隐患具体参考这篇。
AIDL oneway 方法的隐患

socket也不是单独使用的,I/O模型中的epoll是一种高效的管理socket的模型,epoll机制相对成熟,是同步非阻塞。

socket(套接字)是对 TCP/IP 或者UDP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API)。
而Binder很负复杂。

简单的设计,减少出问题的几率,会让系统更加稳定。

Zygote通信为什么用Socket,而不是Binder?
说了这么多,其实是通过对比加深对Android进程间通讯Socket和Binder两种机制的理解。

3.Zygote 处理 socket消息代码分析

具体代码流程分析可看这篇:
app_process: zygote处理socket消息请求(5)

参考链接:
为什么 Android 要采用 Binder 作为 IPC 机制?
为什么Android的Zygote与SystemServer通信采用Socket,而不是Binder?
[026]Zygote中Socket通信能否替换成Binder通信?
Android系统启动-zygote篇
Android10.0系统启动之Zygote进程-[Android取经之路]
app_process: zygote处理socket消息请求(5)
Android Framework层学习——为什么SystemServer进程与Zygote进程通讯采用Socket而不是Binder
android中AMS通知Zygote去fork进程为什么使用socket而不使用binder

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

推荐阅读更多精彩内容