面试 | 再也不怕被问 Binder 机制了

news2024/11/20 9:22:40

Binder 机制

Binder 机制是 Android 特有的一种进程间通信(IPC)方式

1.1 Binder 机制的作用和原理?

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

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

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

1.2 Binder 框架中 Client、Server、ServiceManager、Binder驱动 之间的关系和工作原理?

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

  • Server&Client:服务器&客户端。在 Binder 驱动和 Service Manager 提供的基础设施上,进行 Client-Server 之间的通信。
  • ServiceManager(如同DNS域名服务器)服务的管理者,将 Binder 名字转换为 Client 中对该 Binder 的引用,使得 Client 可以通过 Binder 名字获得 Server 中 Binder 实体的引用。
  • Binder 驱动(如同路由器):负责进程之间 binder 通信的建立,传递,计数管理以及数据的传递交互等底层支持。

完整的过程如下

既然使用内存映射技术可以减少数据拷贝次数,为什么发送方进程不做内存映射?

发送方进程也做内存映射确实可以实现数据 0 拷贝传输,这就属于是以共享内存的方式进行 IPC 了。但是从以下两个角度来看,还是使用 Binder 的方式比较适合 Android

  1. 从性能角度来看: Binder 的数据只要拷贝一次,性能仅次于共享内存,且 RPC 调用的数据通常较小,因此拷贝操作对性能的影响并不大。
  2. 从稳定性和复杂性角度来看:Binder是基于C/S架构的,简单解释下C/S架构,是指客户端(Client)和服务端(Server)组成的架构,Client端有什么需求,直接发送给Server端去完成,架构清晰明朗,Server端与Client端相对独立,稳定性较好;而共享内存实现方式复杂,没有客户与服务端之别, 需要充分考虑到访问临界资源的并发同步问题,否则可能会出现死锁等问题

mmap 内存映射原理?

mmap 是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用 read,write 等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享

mmap 的内存映射原理是不是,进程的用户空间和内核空间有个映射,内核空间和外部存储介质也有一个映射?

mmap 系统调用的内存映射原理是在进程的用户空间和内核空间之间以及内核空间和外部存储介质之间建立映射关系。

以下是 mmap 内存映射的主要过程:

  1. 进程调用 mmap 系统调用,请求将一个文件或其他外部存储介质映射到进程的用户空间内存。
  2. 操作系统在内核空间中为请求的文件或存储介质分配一个内核缓冲区(页缓存),并将文件或存储介质的内容读取到该缓冲区。
  3. 操作系统在进程的用户空间内存中分配一段虚拟地址空间,并将其与内核缓冲区建立映射关系。这样,进程可以通过虚拟地址访问内核缓冲区中的文件或存储介质内容。
  4. 当进程访问映射的虚拟地址时,操作系统会将访问请求转发到内核缓冲区,并根据需要进行读写操作。这些操作可能涉及缓冲区的同步、写时复制(Copy-on-Write, COW)等内存管理策略。

通过 mmap 内存映射,进程可以将文件或其他外部存储介质的内容直接映射到用户空间内存,从而实现高效的数据访问和共享。这种映射机制避免了传统的文件 I/O 操作中的额外数据拷贝和内存分配,提高了 I/O 性能。同时,mmap 内存映射还可以用于进程间通信(IPC)、共享内存等场景,实现进程间的数据共享和同步。

进程间通信时 mmap 的内容映射只需要映射进程用户空间和内核空间吧,还需要映射外部存储介质吗?

在进程间通信(IPC)场景下使用 mmap 时,通常只需要在进程的用户空间和内核空间之间建立映射关系。不一定需要映射到外部存储介质,除非你希望将共享内存的内容持久化到磁盘上。

当使用 mmap 进行进程间通信时,通常会创建一个匿名内存映射(Anonymous Memory Mapping)。匿名内存映射不与任何文件关联,它只是在内核空间分配一段内存(页缓存),并在进程的用户空间与之建立映射关系。这样,多个进程可以共享同一段内核空间内存,实现数据共享和同步。

以下是一个使用匿名内存映射进行进程间通信的简单示例:

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main() {
    // 创建匿名内存映射
    void *addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (addr == MAP_FAILED) {
        perror("mmap");
        return 1;
    }

    // fork 子进程
    pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        return 1;
    } else if (pid == 0) {
        // 子进程:读取共享内存的内容
        printf("Child: Read from shared memory: %s\\\\n", (char *)addr);
    } else {
        // 父进程:写入共享内存
        strcpy((char *)addr, "Hello, mmap!");
        printf("Parent: Write to shared memory: %s\\\\n", (char *)addr);
    }

    // 释放内存映射
    munmap(addr, 4096);
    return 0;
}

在这个示例中,我们创建了一个匿名内存映射,并在父进程和子进程之间共享。父进程向共享内存写入数据,子进程从共享内存读取数据。这里的内存映射并没有映射到外部存储介质,只是在进程的用户空间和内核空间之间建立了映射关系。

当然,如果你希望将共享内存的内容持久化到磁盘上,可以使用文件映射(File-backed Mapping)来实现。在这种情况下,mmap 会在进程的用户空间、内核空间和外部存储介质之间建立映射关系。

oneway 机制?

  • 非 oneway 的 aidl 接口,调用方线程会被阻塞,直到被调用方进程返回为止
  • oneway 的 aidl 接口,不会阻塞调用方线程,而是立即返回。在Android Framework 中 AMS 启动 Activity 时就是使用的 oneway 的方式,不会因为应用进程而阻塞了AMS进程的线程
  • oneway 的还有一个特点,它是串行化的,binder 驱动内部有一个队列,会将它一个一个发送给接收进程

那么问题来了,oneway 的接口立即返回,怎么拿到被调用方进程的处理结果呢?

首先,如果我们不需要关注返回结果的,建议使用 oneway,如果需要返回结果,也可以用 oneway,有两种方式:

  1. 注册监听,将 callback 也定义成 aidl 接口,然后通过注册方式向接收方进程传递,接收方进程拿到 callback,通过 binder 机制可以向发送方回调数据
  2. 直接在定义方法的时候,传入 aidl 定义的 callback 接口,同上机制

但是要注意,通过单独注册监听的方式,如果需要反注册的话,接受方进程维护的监听列表,要使用 RemoteCallbackList 来存储。因为发送方的 callback 和接收方拿到的 callback 不是同一个对象,而 RemoteCallbackList 内部通过以 callback 对应的 binder 作为 key (虽然不是同一个对象,但是 binder 是同一个),所以可以保证注册和反注册正常,同时 RemoteCallbackList 内部做了线程安全保障(注册和反注册都是synchronized 方法),不需要自己额外处理多线程问题

Binder 通信的数据大小限制?

Binder 调用中同步调用优先级大于 oneway(异步)的调用,为了充分满足同步调用的内存需要,所以将 oneway 调用的内存限制到申请内存上限的一半

Android系统 中大部分IPC场景是使用 Binder 作为通信方式,在进程创建的时候会为 Binder 创建一个1M 左右的缓冲区用于跨进程通信时的数据传输,如果超过这个上限就就会抛出这个异常,而且这个缓存区时当前进程内的所有线程共享的,线程最大数量为16个,如同时间内总传输大小超过了1M,也会抛异常。另外在Activity启动的场景比较特殊,因为Binder 的通信方式为两种,一种是异步通信,一种是同步通信,异步通信时数据缓冲区大小被设置为了原本的1半

关于 Binder 线程池的问题?

Binder 线程池是由 Android 系统自动创建和管理的。当一个进程需要使用 Binder IPC 通信时,系统会为该进程创建一个 Binder 线程池。线程池的创建和管理是在 Android 系统底层的 native 代码中实现的,主要涉及到 libbinder 库中的 C++ 代码。

在 Android 源码中,Binder 线程池的创建和管理主要位于以下路径的文件中:

frameworks/native/libs/binder/ProcessState.cpp

在这个文件中,ProcessState 类负责管理 Binder 线程池。当一个进程第一次使用 Binder IPC 通信时,ProcessState 会创建一个线程池并启动一定数量的 Binder 线程。线程池的大小可以通过 ProcessState::setThreadPoolMaxThreadCount() 方法进行设置,默认值是 16。

需要注意的是,这部分代码是 Android 系统底层的实现,通常情况下,开发者不需要直接修改这部分代码。在应用层,开发者只需关注如何使用 Binder IPC 进行通信即可。

客户端进程使用方法参数带 callback 的方式调用服务端进程提供的方法,那么这个方法的调用线程和 callback 的回调线程是同一个线程吗?

在 Android 的 Binder 通信中,客户端进程使用带有回调接口(Callback)的方法参数调用服务端进程提供的方法时,方法的调用线程和回调线程是否是同一个线程,取决于服务端的实现方式。

以下是一些可能的情况:

  1. 如果服务端在收到客户端请求时,立即在当前线程中处理请求并调用回调接口,那么方法的调用线程和回调线程是同一个线程。这种情况下,客户端的调用可能会被阻塞,直到服务端处理完请求并调用回调接口。
  2. 如果服务端在收到客户端请求时,将请求放入一个队列或线程池中异步处理,并在处理完成后调用回调接口,那么方法的调用线程和回调线程可能不是同一个线程。这种情况下,客户端的调用不会被阻塞,服务端可以并发处理多个请求。

一般来说,为了提高响应性能和避免客户端调用被阻塞,服务端通常会采用异步处理方式,将请求放入队列或线程池中处理,并在处理完成后调用回调接口。这样,方法的调用线程和回调线程可能不是同一个线程。

在实际应用中,需要根据具体需求和场景选择合适的线程模型,并确保回调接口的实现是线程安全的。

如果是 oneway 的接口,即使服务端立即在当前线程中处理请求并调用回调接口,客户端也不会阻塞吧?

是的,如果在 AIDL 接口中使用 oneway 关键字,那么即使服务端立即在当前线程中处理请求并调用回调接口,客户端的调用也不会被阻塞。

oneway 关键字表示这是一个单向异步调用。在这种情况下,客户端在调用服务端的方法时,不会等待服务端的响应,而是立即返回。这意味着客户端的调用线程不会被阻塞,可以继续执行其他任务。

在实际应用中,oneway 关键字通常用于那些不需要返回结果或者可以通过回调接口返回结果的场景,例如通知、事件回调等。这样可以避免客户端调用被阻塞,提高程序的响应性能。然而,需要注意的是,由于 oneway 调用是异步的,客户端在调用完成后无法直接获取返回结果,需要通过其他方式(如回调接口或事件总线)来获取异步调用的结果。

有两个运行在同一个进程的 Activity A 和 B,A 启动 B,使用 intent 传递参数,这个时候 intent 的数据携带大小会受 Binder 同信的大小限制吗?

是的,因为这里涉及应用进程和 AMS 所在的 system_server 进程的 Binder IPC 通信息,所以 Intent 传递数据会受到 Binder 事务的大小限制。Binder 事务的缓冲区大小通常限制在 1MB 左右(具体大小可能因 Android 版本和设备而异),这意味着 Intent 携带的数据不能超过这个限制。如果超过这个限制,会抛出 TransactionTooLargeException 异常。

为了避免这个问题,可以考虑以下方法来传递较大数据:

  1. 使用文件:将数据写入文件,然后通过 Intent 传递文件的 URI。在接收 Activity 中,使用该 URI 读取文件内容。
  2. 使用全局变量或单例模式:将数据存储在全局变量或单例对象中,这样在不同的 Activity 之间可以直接访问。
  3. 使用数据库或 SharedPreferences:将数据存储在数据库或 SharedPreferences 中,然后在需要的 Activity 中读取。
  4. 对于较大的 Bitmap 图片,可以使用 LruCache 缓存机制来在不同的 Activity 之间共享。

如果你还没有掌握Framework,现在想要在最短的时间里吃透它,可以参考一下《Android Framework核心知识点》,里面内容包含了:Init、Zygote、SystemServer、Binder、Handler、AMS、PMS、Launcher……等知识点记录。

《Framework 核心知识点汇总手册》:https://qr18.cn/AQpN4J

Handler 机制实现原理部分:
1.宏观理论分析与Message源码分析
2.MessageQueue的源码分析
3.Looper的源码分析
4.handler的源码分析
5.总结

Binder 原理:
1.学习Binder前必须要了解的知识点
2.ServiceManager中的Binder机制
3.系统服务的注册过程
4.ServiceManager的启动过程
5.系统服务的获取过程
6.Java Binder的初始化
7.Java Binder中系统服务的注册过程

Zygote :

  1. Android系统的启动过程及Zygote的启动过程
  2. 应用进程的启动过程

AMS源码分析 :

  1. Activity生命周期管理
  2. onActivityResult执行过程
  3. AMS中Activity栈管理详解

深入PMS源码:

1.PMS的启动过程和执行流程
2.APK的安装和卸载源码分析
3.PMS中intent-filter的匹配架构

WMS:
1.WMS的诞生
2.WMS的重要成员和Window的添加过程
3.Window的删除过程

《Android Framework学习手册》:https://qr18.cn/AQpN4J

  1. 开机Init 进程
  2. 开机启动 Zygote 进程
  3. 开机启动 SystemServer 进程
  4. Binder 驱动
  5. AMS 的启动过程
  6. PMS 的启动过程
  7. Launcher 的启动过程
  8. Android 四大组件
  9. Android 系统服务 - Input 事件的分发过程
  10. Android 底层渲染 - 屏幕刷新机制源码分析
  11. Android 源码分析实战

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1204094.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Django下的Race Condition漏洞

目录 环境搭建 无锁无事务的竞争攻击复现 无锁有事务的竞争攻击复现 悲观锁进行防御 乐观锁进行防御 环境搭建 首先我们安装源码包&#xff1a;GitHub - phith0n/race-condition-playground: Playground for Race Condition attack 然后将源码包上传到Ubuntu 为了方便使…

python双端队列_中间是头两边是尾_两边是头中间是尾

双端队列的顺序表存储结构以及两种特殊的双端队列 双端队列 是一种允许我们同时从前端和后端添加和删除元素的特殊队列&#xff0c;它是队列和栈的结合体。 双端队列&#xff08;deque&#xff09;与队列&#xff08;queue&#xff09;就差了两个字&#xff0c;队列里元素只能…

uniapp——项目day04

购物车页面——商品列表区域 渲染购物车商品列表的标题区域 1. 定义如下的 UI 结构&#xff1a; 2.美化样式 渲染商品列表区域的基本结构 1. 通过 mapState 辅助函数&#xff0c;将 Store 中的 cart 数组映射到当前页面中使用&#xff1a; import badgeMix from /mixins/tab…

2023年【建筑电工(建筑特殊工种)】找解析及建筑电工(建筑特殊工种)复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 建筑电工(建筑特殊工种)找解析是安全生产模拟考试一点通生成的&#xff0c;建筑电工(建筑特殊工种)证模拟考试题库是根据建筑电工(建筑特殊工种)最新版教材汇编出建筑电工(建筑特殊工种)仿真模拟考试。2023年【建筑电…

1 Supervised Machine Learning Regression and Classification

文章目录 Week1OverViewSupervised LearningUnsupervised LearningLinear Regression ModelCost functionGradient Descent Week2Muliple FeatureVectorizationGradient Descent for Multiple RegressionFeature ScalingGradient DescentFeature EngineeringPolynomial Regress…

数据结构线性表——栈

前言&#xff1a;哈喽小伙伴们&#xff0c;今天我们将一起进入数据结构线性表的第四篇章——栈的讲解&#xff0c;栈还是比较简单的哦&#xff0c;跟紧博主的思路&#xff0c;不要掉队哦。 目录 一.什么是栈 二.如何实现栈 三.栈的实现 栈的初始化 四.栈的操作 1.数据入栈…

CTFhub-RCE-读取源代码

源代码&#xff1a; <?php error_reporting(E_ALL); if (isset($_GET[file])) { if ( substr($_GET["file"], 0, 6) "php://" ) { include($_GET["file"]); } else { echo "Hacker!!!"; } } else {…

重磅!2024QS亚洲大学排名出炉!北大蝉联榜首,港大反超新国立、清华!

2023年11月8日&#xff0c;全球高等教育分析机构QS Quacquarelli Symonds发布了2024年QS世界大学排名&#xff1a;亚洲大学排名。 本次排名全方位评估了来自亚洲25个国家和地区的856所大学在全球认可度、研究实力、教学资源和国际化等方面的表现&#xff0c;有148所院校首次跻…

绝望了,软件测试的行业基本盘,崩了......

不得不承认&#xff0c;现在工作不好找 去年很多人都觉得今年的就业环境会好很多&#xff0c;但是到了现在都发现之前想错了&#xff0c;实际上是一塌糊涂… 于是有了很多年轻人焦虑日常的灵魂一问&#xff1a;“快半年了&#xff0c;找不到工作&#xff0c;我好焦虑&#xf…

Git的GUI图形化工具ssh协议IDEA集成Git

一、GIT的GUI图形化工具 1、介绍 Git自带的GUI工具&#xff0c;主界面中各个按钮的意思基本与界面文字一致&#xff0c;与git的命令差别不大。在了解自己所做的操作情况下&#xff0c;各个功能点开看下就知道是怎么操作的。即使不了解&#xff0c;只要不做push操作&#xff0c…

LeetCode-剑指 Offer 22. 链表中倒数第k个节点(C语言 )

目录捏 一、题目描述二、示例与提示三、思路四、代码 一、题目描述 给定一个头节点为 head 的链表用于记录一系列核心肌群训练项目编号&#xff0c;请查找并返回倒数第 cnt 个训练项目编号。 二、示例与提示 示例 1&#xff1a; 输入&#xff1a; head [2,4,7,8], cnt 1 输…

Linux 源码包安装

SRPM 包&#xff0c;比 RPM 包多了一个“S”&#xff0c;是“Source”的首字母&#xff0c;所以 SRPM 可直译为“源代码形式的 RPM 包”。也就是说&#xff0c;SRPM 包中不再是经过编译的二进制文件&#xff0c;都是源代码文件。可以这样理解&#xff0c;SRPM 包是软件以源码形…

新生儿母乳过敏:原因、科普和注意事项

引言&#xff1a; 母乳过敏是一种较为罕见但可能令家长担忧的现象。母亲通常认为母乳是新生儿最安全、最适合的食物&#xff0c;然而有时候宝宝可能对母乳中的某些成分产生过敏反应。本文将科普新生儿母乳过敏的原因&#xff0c;提供相关信息&#xff0c;并为父母和监护人提供…

轻量封装WebGPU渲染系统示例<27>- 浮点RTT纹理(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/FloatRTT.ts 当前示例运行效果: 此示例基于此渲染系统实现&#xff0c;当前示例TypeScript源码如下: const floatRTT { diffuse: { uuid: "rtt0", rttTe…

SPC on-line 应用探讨

中国是制造业大国&#xff0c;大部分工厂主要重点是将原料经由加工制造过程&#xff08;或流程&#xff09;转变为最终可销售的产品或服务。”产品”是经过被定义的规格下&#xff08;定义规格者包含客户、制造商本身、供应商…等&#xff09;&#xff0c;在经过”受控制”的人…

Linux C 进程编程

进程编程 进程介绍进程的定义进程和线程以及程序的区别进程块PCB进程的状态相关指令 进程调度算法先来先服务调度算法 FCFS短作业(进程)优先调度算法 SJF优先权调度算法 FPF优先权调度算法的类型非抢占式优先权算法抢占式优先权算法 优先权类型静态优先权动态优先权 高响应比优…

RT-DETR算法优化改进:Backbone改进 | HGBlock完美结合PPHGNetV2 GhostConv

💡💡💡本文独家改进: GhostConv助力RT-DETR ,HGBlock与PPHGNetV2 GhostConv完美结合 推荐指数:五星 HGBlock_GhostConv | 亲测在多个数据集能够实现涨点 RT-DETR魔术师专栏介绍: https://blog.csdn.net/m0_63774211/category_12497375.html ✨✨✨魔改创新RT-…

202311.13 windows通过vscode ssh远程连接到Ubuntu 连接失败 waiting for server log

关闭VScode时没有关闭终端的Ubuntu进程&#xff1f; 导致重启后不能正常连接到Ubuntu了 Windows 系统自带的cmd终端通过ssh 可以连接 应该是vscode里对Ubuntu 的服务器端配置出了问题 参考&#xff1a;记录 VSCode ssh 连接远程服务器时出错及解决方法 在Windows 的vscode里面执…

jumpserver任意密码重置漏洞-CVE-2023-42820

目录 jumpserver 环境搭建 这里用的是vulhub靶场 进入 jumpserver 的目录 修改配置文件 config.env 里面的 DOMAINS 参数为kali的地址 运行环境&#xff0c;第一次运行的话会拉取文件&#xff0c;要耐心等待。 命令&#xff1a; 查看docker容器 命令&#xff1a; 用浏…