Linux进程间能力传递原理和应用分析

2021-10-26 11:56杨明赵
山西电子技术 2021年5期
关键词:描述符服务端安卓

杨 倩,杨明赵

(1.重庆理工大学,重庆 400054;2.云从科技集团股份有限公司,重庆 401120)

0 引言

Linux遵循传统UNIX系统“一切皆文件”的理念,进程已打开的文件,称为“文件描述符(File Descriptor,简称:FD)”,将文件描述符从一个进程传递到另外一个进程,对应的使用文件描述符所关联资源的能力也就被传递到了新的进程。在软件设计中,这种方式可以实现在一组进程中的不同进程对同一资源不同阶段共享访问,可以利用进程的相互隔离,带来安全性、 稳定性和健壮性等方面的好处, 文件描述符的进程间传递是Linux操作系统的一种重要的进程间能力传递手段,本文将对其底层原理和典型应用场景进行分析。

1 文件描述符进程间传递原理

现代操作系统的进程一般工作在虚拟内存地址空间通过MMU地址转换映射到物理内存,进程无法访问其他进程的虚拟内存,这样就达到了相互隔离的安全目的。 进程之间的交互操作只能通过比如将不同进程的某一部分虚拟地址区间映射到相同的物理内存块,达到共享内存的目的;也可以通过进程处于内核特权模式上下文中,将数据从一个进程的内存拷贝到另外一个进程的内存,达到内存间消息交互的目的。文件描述符通常通过整数表示,该整数代表在文件描述符表(File Descriptor Table)中的索引,进程每次打开文件,会从该表空闲项中分配一项。 文件描述符是进程操作该进程描述符所关联资源的句柄,有了进程描述符也就具备了操作这些资源的能力(Capability)。如果能在进程之间传递文件描述符,也就能够实现能力的传递而不是直接传输数据,这样可以减少数据的拷贝,提高数据使用效率。但是,文件描述符表为各个进程私有,互相之间无法访问。要实现进程之间文件描述符的传递,实际上是要实现该文件描述符所关联资源在不同进程的内存空间的重新映射。文件描述符的映射关系如图1所示[1]。

图1 文件描述符和进程的关系

文件描述符的传递目前在不同的Linux衍生系统上有不同的实现,原生的Linux系统使用基于UNIX域套接字的sendmsg()和recvmsg()系统调用可以实现上述能力,从Linux内核5.6版本开始, 引入了一种新的系统调用叫做pidfd_getfd(),使得进程间传递文件描述符更加安全可靠,并且使得开发相关应用更加简洁方便;而安卓系统,为了使其应用框架更加简洁,让不同的进程可以通过RPC的方式进行交互,在内核层面添加了Binder IPC机制,Binder也支持文件描述符的传递。后面的章节将对这种系统能力的实际应用场景进行一些分析。

2 应用场景

2.1 图形系统数据零拷贝

多数操作系统图形子系统采用客户端/服务端模型,负责操作显存的进程作为服务端,称为“显示服务器”,其他具有图像界面的应用进程作为客户端。 所有客户端将绘制完成自身图像数据(比如GUI)传输到服务端,由服务端对图像进行转换、裁剪、混合等操作后,将最终图像送到显存进行显示[2]。

图2 图形系统客户端/服务端模型

图像数据具有数据量大的特点,采用共享内存池实现数据零拷贝必不可少,然而,这里的服务端和众多客户端进程通常并没有进程上的父子关系,进程之间的内存共享只能通过文件描述符传递来实现。

以安卓及桌面Linux系统所采用的Wayland架构为例,客户端在启动阶段会和服务端建立会话,会话通道不同的操作系统有所不同,比如安卓采用其特有的Binder IPC、 Wayland采用UNIX域套接字,所采用的这些通道底层都提供了文件描述符的传递能力,通过会话一端将内存句柄以文件描述符的形式传递给对端,这样就完成了共享内存池的建立。 后续客户端完成一帧操作后,通过会话通道唤醒服务端。服务端进行后续处理。可以看到,过程是在共享的内存中进行的,IPC机制只是起到处理双方同步访问机制的作用,保证一方开始读的时候另外一方已经写入完成[3]。

2.2 隔离外部设备访问权限

一般操作系统需要对权限进行管理,系统资源需要特殊的权限才能进行访问,如果这些特权进程发生错误或者用户不受信任代码运行于特权进程,将给不法攻击者带来可乘之机。安卓操作系统对这些应用使用系统资源进行了限制,采用了授权访问机制,如果应用需要访问这些设备,需要向系统申请对应的权限,系统通过对话框提示用户同意后,才能进行进一步操作[4]。

这类需求一般实现方式是,通过系统服务作为代理,介于用户进程和设备之间做访问限制,带来效率和实时性上的问题。所以,安卓在架构设计上使用了文件描述符传递机制,首先限制设备文件节点只能由特定系统服务访问,确保了安全性。经过用户允许的程序,可以由系统服务将所涉及到的设备节点打开,然后将文件描述符通过Binder机制发送到用户程序,从而用户程序得到了访问该设备的“能力”。在这种场景下,通过文件描述符的传递,用户进程与设备之间的交互完全没有第三方的参与,在不破坏设备访问协议、不增加额外的数据拷贝开销以及不增加数据延迟的情况下,很简洁地实现了访问权限限制和授权访问[5]。

2.3 互联网服务零停机运维

互联网基础设施需要保证互联网请求都能及时得到响应。其中负载均衡器需要管理来自用户的大量TCP连接和数据分发,如果过程中需要升级程序或者更新配置,则需要重新启动该服务,这种情况下,已经建立的TCP连接需要被强制RESET,以及重启过程中客户端发起的SYN请求也会被拒绝。这样短暂的中断在一些关键的互联网基础设施是不被允许的,所以提出了“零停机运维”的概念。

“零停机运维”要求服务即使在不得不重启的情况下,仍然保持连接活跃,不让客户端请求无响应或者响应错误。这种条件下,文件描述符进程间传递发挥了作用。知名开源负载均衡器Haproxy配置热加载以及互联网公司FaceBook提出的“Socket Takeover”均使用了这种技术。其核心原理是,服务新的实例先启动,完成初始化,与即将关闭的旧实例建立连接,旧实例将所有活跃的TCP套接字文件描述符发送到新的实例,新的服务接管这些活跃的连接,然后旧服务实例退出,完成了整个重启过程。过程中,活跃的连接状态不会受到影响,客户端的连接不会被中断,从客户端感觉不到服务端的重启活动,即实现了“零停机”[6,7]。

3 结束语

本文章对文件描述符的跨进程传递原理进行了原理分析,并对已有的一些应用场景进行了描述。相信未来在其他的一些场景下,文件描述符的传递也会有更加广泛的应用场景。

猜你喜欢
描述符服务端安卓
iPhone不卡的秘密曝光:安卓也能享受
基于AKAZE的BOLD掩码描述符的匹配算法的研究
文物表情包
欧洲共同语言参考标准在中国高校学术英语写作教学适用性的研究:可理解性,可行性和有用性
安卓系统或成智能汽车标配
基于深度学习的局部描述符
新时期《移动Web服务端开发》课程教学改革的研究
一种基于PCIE总线的改进分散集聚DMA的设计
安卓机器人
摸清黑客套路防范木马侵入