Android进程间通信 — Binder学习记录

前言

移动设备的操作系统阵营之一的Android,底层基于Linux内核,中间为Native&Runtime层和Framework层。我们知道Linux本身有着很成熟的IPC(进程间通信)机制,比如管道、消息队列、共享内存、socket、信号和信号量等。然而,Android却使用Binder来作为它的IPC的方案,这是为何呢?接下来,就把我之前学习Binder的心得写下来。

WhatWhyHow

What — Binder是什么

Binder起源于OpenBinder。

官方正式的说,Binder是Android跨进程通信的方式,采用了C/S架构。主要包括4个组件,Client、Server、ServiceManager和Binder驱动。其中Client、Server和ServiceManager运行在用户空间,Binder驱动运行在内核空间。

说完了没说一样是吧。说白了其实Binder对于Android来说就像是电话对于人一样,用于通信的。其中Client、Server、ServiceManager和Binder驱动就是电话内部的几个组成组件。

Client:进程间通信的客户端

Server:进程间通信的服务端

ServiceManager:Binder服务的大管家,它是一个守护进程,Client端和Server端的相互通信都需要借助于它。

下面这张图就是Binder的工作原理:

Android进程间通信 -- Binder学习记录

可以看出无论是服务的注册还是服务的获取,都需要ServiceManager。

Why — 为何使用Binder

刚刚提到说,Android底层基于Linux内核,Linux已经包含了好多成熟的进程间通信的方案,为何要选用Binder呢?

这里从我总结的几点说。

1. 性能:Binder在一次通信中只进行一次内存拷贝。而管道、消息队列、socket等都需要2次内存拷贝,可别小看这一倍带来的差距。对于移动设备来说,性能一直是个大问题。想象一下,如果选用管道作为IPC的方案的话,那么Android绘制屏幕的时候都需要与WindowManager进行IPC通信,如果这里效率不高,势必会造成卡顿甚至于app卡死。

当然了,共享内存的方式压根就不需要内存拷贝,但是共享内存在实际写代码会非常复杂,需要频繁的加锁释放锁,稍有不慎就会造成死锁。

所以从性能的角度来说,Binder的性能仅次于共享内存。

IPC方式

内存拷贝次数

socket/管道/消息队列

2

共享内存

0

Binder

1

2. 安全性:Android作为开源的移动端操作系统,拥有非常多的开发平台,有用于手机设备,有用于智能穿戴设备,也有嵌入式及其机器人平台。同时运行的app来源也很多,很多不正规的第三方app都可以发布、安装到Android上,因此手机安全性显得尤为重要。

通义听悟 通义听悟

阿里云通义听悟是聚焦音视频内容的工作学习AI助手,依托大模型,帮助用户记录、整理和分析音视频内容,体验用大模型做音视频笔记、整理会议记录。

通义听悟 85 查看详情 通义听悟

而Linux传统的IPC的方案,接收方都无法获取对方进程的身份,无法判断对方是否可靠,Linux传统的IPC方案没有任何保护措施。

在Android系统中,Android为每一个安装的app都分配了一个UID标识,这个UID就作为鉴别对方进程身份的重要标志。而Binder采用的C/S架构,系统只暴露了Client端,不会暴露Server端。实际通信中Server端会判断对方进程的UID是否满足权限(在Android 6.0以上的系统,都是通过弹窗询问)。传统的IPC方案只能在用户空间的数据包里填充UID,只能在用户空间定义协议。Binder可以在Binder驱动程序中进行分配和填充记录UID的操作,也就是说,Binder机制对于通信双方的身份是在内核中进行校验支持的,安全性更高。

3. 灵活性:Binder采用的C/S架构,Client端和Server端实则都借助于ServiceManager,在我看来ServiceManager相当于控制和服务中心,有着统一中心化管理的能力,在ServiceManager注册服务后,就可以统一的发布Service供其他进程使用。所以它更加的灵活。

4. 稳定性:相较于Linux传统IPC方案,共享内存虽然性能更好,但是操作起来复杂,需要控制好锁以及各种同步的场景,稍有不慎就会死锁;而B/S架构的模式,像管道/消息队列还得进行包装。而Binder采用C/S架构,稳定性更好。

通过上述的4点,Binder就很适合作为Android系统的IPC方案了。

How — Binder的架构

这里先放出Binder通信架构图:

Android进程间通信 -- Binder学习记录

一次Binder通信过程会涉及到app层、Framework层、Native层和Kernel层,算是把Android的架构从上到下走了个遍。假设已经创建了自己的Client、Service类,并且在Client端持有Service的引用,并且申请调用Service的A函数,那么在Android系统内部的调用过程是这样的:

Android进程间通信 -- Binder学习记录

从调用过程上看可以发现,当Client端发起请求后,Client端的当前线程会挂起。这里需要注意,如果Server端进程需要执行长时间的操作的话,最好不要在UI线程里做以免发生ANR。

接下来说说Binder的C/S架构。我们知道Android系统在开机启动过程中Zygote创建后会fork出system_server进程,然后由system_server进程会孵化出大量的系统服务,分为引导服务、核心服务和其他服务(这里后续会出一篇文章具体介绍)。那么在Android系统中是怎么管理这些服务的,并且让用户可以跨进程调用这些服务呢?

调用系统服务的过程:Android在开机过程初始化所有的Service后,会将这些Service向ServiceManager注册,Client端想要申请具体的Service将直接向ServiceManager要就行了。具体做法是Client端首先向ServiceManager查询,得到具体的Service的引用,然后通过这个引用向具体的Server端发送请求,Server端执行完成后就返回。

而这里有个问题,Client端持有Service的引用,然后调用具体Server端的某个函数,一次Binder请求就完成了。可是Client端和Server端的这两个进程之间是怎么共享资源的呢?聪明的读者一定都猜到了,没错,就是通过Binder驱动。

当Client向Server发请求时,Client会先从自己的进程空间把请求数据拷贝到内核空间,然后因为Server和内核共享数据,所以这里不需要再进行拷贝,直接通过内存地址偏移量获得请求数据地址,并通知Server端执行onTransact()函数,这个函数属于Binder类,当Server端进程执行完毕后将结果写入自己的共享内存中,Binder驱动再将结果拷贝到Client端的进程空间,并唤醒Client端的线程。

Android进程间通信 -- Binder学习记录

接下来说说Binder驱动。用户态程序通过系统调用陷入内核态,比如打开Binder驱动方法的调用链为:open() –> __open() –> binder_open()。open()为用户态方法,__open()为系统调用,通过系统调用表查找到对应内核Binder驱动的binder_open()方法。

Android进程间通信 -- Binder学习记录

Binder驱动有几个核心的方法:

binder_init:主要工作是注册misc设备。binder_open:打开Binder驱动设备。期间会创建binder_proc对象(管理着IPC所需的各种信息)。binder_mmap:在内核虚拟地址空间申请一块与用户虚拟内存相同大小的内存;然后再申请1个page大小的物理内存,再将同一块物理内存分别映射到内核虚拟地址空间和用户虚拟内存空间,从而实现了用户空间的Buffer和内核空间的Buffer同步操作的功能。刚刚讲C/S架构时提到Server端不需要拷贝,Server和内核空间共享一块空间主要就是通过binder_mmap()来实现的。binder_ioctl:负责在两个进程间收发IPC数据和IPC reply数据。

具体的源码分析这里就不展开了。

Binder机制运用。首先看一下下面2行代码:

代码语言:javascript代码运行次数:0运行复制

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);  String deviceId = telephonyManager.getDeviceId();

getSystemService(Context.TELEPHONY_SERVICE)在Android系统内部会向ServiceManager查询标识为TELEPHONY_SERVICE的Server端对象的引用。即TelephonyManager对象的引用,这个引用的真正实现是TelephonyManager的某个代理。得到这个引用后,调用getDeviceId时,真正的实现是在代理里面,代理把参数、数据等打包到Parcel对象中,然后调用transact函数(该函数继承于Binder),之后就会触发Binder驱动做一些列操作,Client端把数据拷贝到内核空间,然后Server端接收,执行完相应的操作(这里是getDeviceId)后把结果映射到内核空间,然后内核再拷贝到Client端的进程空间中从而完成这次Binder IPC调用。

Android进程间通信 -- Binder学习记录

总结

这篇文章记录了个人学习Android Binder的见解,算是一个概要性的学习记录和总结。因为毕竟写的比较简单,也还没有从Android源码来分析,因为Binder贯穿着整个Android系统。如果想全部写明白要写好几篇文章。后续应该会出专门的几篇文章从源码入手,详细的阐述Android Binder。

作者的话

个人喜欢计算机技术,主要涉及的领域包括:Android系统,Linux内核,嵌入式软/硬件,机器人和智能硬件。同时也对其他的各个技术栈都感兴趣。

同时也很喜欢生活,喜欢享受生活,喜欢用拍照和视频的方式来记录生活。

如果你也是个爱学习爱技术的人,欢迎一起探讨,没准,咱们能成为好朋友。如果觉得本文有哪些不对的地方,欢迎指出,大家一起学习进步。

以上就是Android进程间通信 — Binder学习记录的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/300202.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月5日 00:31:07
下一篇 2025年11月5日 00:46:40

相关推荐

  • 配置低的电脑可以安装 Linux 系统吗?

    配置低的电脑是否能安装 Linux 系统? 想要学习 Linux,但经济紧张只能购买旧电脑,对配置要求存在疑问。本文将针对这个问题展开解答,为您提供详细的指导。 Linux 系统对配置的要求 Linux 系统对硬件配置的要求相对较低,这一点与 Windows 等系统不同。一般来说,具有以下配置的电脑…

    2025年12月9日
    000
  • 低配电脑能流畅运行Linux系统吗?

    低配电脑能否安装 Linux 系统 对于想学习 Linux 系统但经济紧张的朋友,购买一台旧电脑是不错的选择。不过,在这之前,我们先来探讨一下低配电脑是否适合安装 Linux。 Linux 系统是一种轻量级的操作系统,相对于 Windows 系统来说,对硬件要求较低。一台低配电脑,例如配备了第一代主…

    2025年12月9日
    000
  • PHP命令行模式下如何使用Redis?

    php命令行模式下无法使用redis 解决方案 在php命令行模式下运行php脚本时,出现”class redis not found”错误,表明php尚未加载redis扩展。虽然通过url可以访问到redis服务,但这并不意味着php命令行模式下也能使用redis。 为了解…

    2025年12月9日
    000
  • 为什么我的电脑访问网站出现 DNS_PROBE_FINISHED_NXDOMAIN 错误,而其他电脑却可以正常访问?

    在不同电脑上访问同一个网站时出现 DNS_PROBE_FINISHED_NXDOMAIN 错误的排查步骤 你提到的问题是一个常见的网络问题,当一台电脑试图访问一个网站时,却收到“DNS_PROBE_FINISHED_NXDOMAIN”错误。同时,另一台电脑却可以正常访问该网站。究其原因,通常与 DN…

    2025年12月9日
    000
  • 如何更新作曲家

    要更新系统上的 composer,请按照以下步骤操作: 全局更新 composer 要更新系统上的 composer,请按照以下步骤操作: 全局更新 composer: 如果您已经全局安装了 composer(可在终端中作为 composer 命令使用),则可以使用以下命令来更新它: compose…

    2025年12月9日
    000
  • ## 使用 pcntl_async_signals 和 pcntl_wait 时,为什么 SIGTERM 信号回调函数没有被调用?

    pcntl_async_signals 与 pcntl_wait 的配合使用 在处理 linux 系统中的信号时,pcntl_async_signals 和 pcntl_wait 两个函数经常被同时使用。但是,在某些情况下,这两个函数同时使用时可能会出现问题。 问题描述 如下所示的代码中,serve…

    2025年12月9日
    000
  • Webshell 中红框中的箭头表示什么?

    Webshell方式登录Linux后,红框中箭头的含义解析 以Webshell方式登录Linux后,您可能会注意到命令输出中出现类似于图中红框中的箭头。这些箭头具有特定的含义,有助于理解文件系统结构。 红框中的箭头表示: 软链接(符号链接) 什么是软链接? 软链接是一种特殊类型的文件,指向另一个文件…

    2025年12月9日
    000
  • Pheanstalk 消息队列如何设置后台消费者执行消息处理?

    beanstalkd 消费者后台执行 pheanstalk 消息队列允许您设置后台消费者来处理消息。要使消费者代码在后台安静地运行,而不必直接调用消费者方法,您可以使用以下方法: 后台进程 最简单的方法是使用后台进程来启动消费者。您可以使用以下命令行命令以后台方式启动 php 脚本: nohup p…

    2025年12月9日
    000
  • 【Laravel vx Docker】利用 Laravel Sail 高效搭建 Laravel 应用开发环境

    关于 laravel sail laravel sail 是 laravel 框架的官方开发环境。 sail 提供了一个轻量级的命令行界面 (cli),可以使用 docker 轻松设置和管理 laravel 应用程序开发环境。下面,我们讲解一下 laravel sail 的主要特性和使用方法。 使用…

    2025年12月9日
    000
  • Webshell 登录 Linux 后红框箭头指向的含义是什么?

    webshell登录Linux时红框箭头指向的含义 在通过webshell方式登录Linux服务器后,可能会在终端界面中看到类似于下图红框所示的箭头指向: [图片:显示红框箭头的终端界面截屏] 这些箭头指向的含义是: 软链接(soft link / symbolic link) 软链接是一种文件系统…

    2025年12月9日
    000
  • Webshell 下红框箭头的含义是什么?

    通过 Webshell 登陆 Linux 系统时,红框中箭头的含义 在以 Webshell 方式登陆 Linux 系统后,你可能会看到类似下方的界面: [插入红框界面截图] 其中的红框部分是一个软链接(soft link / symbolic link)。 什么是软链接? 软链接是一种文件,它指向另…

    2025年12月9日
    000
  • 使用swoole作为基于ESP6的脚本可编程控制器的云端物联网网关框架

    脚本可编程控制器的本地功能已经基本完成,开始实现远程相关功能。 远程系统整体架构如下:使用ESP8266的SDK实现tcp服务器和tcp客户端。在tcp服务器的基础上编写http协议解析代码,设计简单的http服务器,处理与浏览器的数据交互,包括内置网页的下载,并使用ajax技术获取状态并保存数据。…

    2025年12月9日
    000
  • php函数对象编程指南在跨平台开发中的兼容性是什么?

    php 函数对象编程指南简介允许将函数作为一等对象处理,与面向对象编程完全兼容,提供可重用性、可扩展性和代码简洁性等优势,并可与高阶函数结合使用。 PHP 函数对象编程指南 简介 函数对象编程 (FOP) 是 PHP 中一种基于函数的编程范例,它允许将函数作为一等对象处理。FOP 提供了强大的灵活性…

    2025年12月9日
    000
  • 为什么 Docker 近年来正在失去优势

    近年来,docker一度成为开发领域的明星工具,以其突破性的技术彻底改变了软件开发。最初,docker 通过其轻量级容器化技术显着简化了开发和部署流程。然而,到了 2024 年,这项技术的缺点越来越明显。 早期的辉煌 不久前,Docker 成功解决了“它在我的机器上可以运行,但在你的机器上不行”的老…

    2025年12月9日 好文分享
    000
  • Apache 虚拟主机:增加安全性

    为了在使用 apache 设置反向代理时确保安全性,您可以实施多种最佳实践,例如使用 ssl/tls 启用 https、调整安全标头,配置防火墙,以及保护对后端的访问。下面是一个详细的实现,以确保您有一个更安全的环境。 启用带有 ssl/tls 的 https 使用 https 对于保护客户端和服务…

    2025年12月9日
    000
  • php 函数缓存技术详解:如何使用函数缓存技术优化大型项目?

    函数缓存技术通过将函数调用结果存储在内存中,提高函数执行效率。php 中可使用 opcache 或 apc 实现函数缓存。具体实战步骤包括:安装 opcache/apc、配置缓存设置,启用文件更改监控等。使用时无需额外操作,缓存机制自动生效。需要注意函数签名更改、对象缓存和性能测试等事项。 PHP …

    2025年12月9日
    000
  • php网络编程指南:高性能网络编程技巧

    高性能 php 网络编程指南:同步 vs. 异步 i/o:异步 i/o 允许程序在等待 i/o 操作完成的同时继续执行,从而提高性能。非阻塞 i/o:基于异步 i/o,使用操作系统函数检查 i/o 状态,即使 i/o 操作不可用也能继续执行。流式 api:允许面向对象式网络编程,简化通信并提供灵活性…

    2025年12月9日
    000
  • PHP 函数中有哪些可用的日志记录工具?

    php 中内置了强大的日志记录函数,包括:error_log():记录错误或警告消息。trigger_error():触发自定义错误或警告。log():记录日志消息,指定设施和优先级。syslog():将消息记录到系统日志。 PHP 函数中的日志记录工具 简介 日志记录对于跟踪和检测应用程序中的错误…

    2025年12月9日
    000
  • PHP 函数事件处理技术是否支持异步处理?

    php 函数事件处理支持异步执行,允许函数在触发事件时立即返回,继续执行后续代码。回调函数在事件触发时被异步调用,用于响应特定事件。 PHP 函数事件处理的异步执行 PHP 函数事件处理允许通过注册回调函数来响应异步事件。与传统同步执行不同,异步执行允许函数在触发事件时立即返回,而不必等待事件完成。…

    2025年12月9日
    000
  • 现代 PHP 中的 PHP Fiber 并发性

    PHP Fibers 在 PHP 8.1 中引入,带来了一种令人兴奋的新方法来处理 PHP 中的并发和异步编程。 Fibers 允许您在执行过程中暂停和恢复函数,使开发人员能够更好地控制非阻塞操作,例如处理 I/O、数据库查询或 HTTP 请求,而无需停止整个脚本。 在本博客中,我们将探讨 PHP …

    2025年12月9日
    000

发表回复

登录后才能评论
关注微信