当前位置: 首页 > news >正文

一个Binder的前生今世 (二):Binder进程和线程的创建

文章目录

  • 一个Binder的前生今世 (二):Binder进程和线程的创建
    • binder在进程中的启动
    • 小结
    • 注释

一个Binder的前生今世 (二):Binder进程和线程的创建

前篇文章一个Binder的前生今世 (一):Service的创建 讲了一个Service是如何创建以及如何与客户端建立联系的。讲解中涉及到了两个类 ProcessStateIPCThreadState ,当时没有详细介绍这两个类是怎么来的,只是介绍了它们在Binder客户端和服务端传递的作用。这篇文章我们就来深入了解下这两个类以及和binder的关系。可以说这两个类整个串联起了Binder驱动和Binder应用的联系,在Binder的架构实现中属于中流砥柱的作用。

binder在进程中的启动

首先要明确一个概念: 一个进程中对应一个Binder进程(也就是后文说的ProcessState)用来管理与Binder驱动的通讯和Binder对应的应用线程(后文说的IPCThreadState)。

要说明Binder在进程中如何启动,我们就需要先了解一个android的应用是如何创建起来的。当然我们这篇文章不介绍Android应用是如何创建的,不了解的可以网上查看其他的资料,很多,我也会另写文章记录。

Android的应用都会通过app_main.cpp来创建,惯例,我们先来明确用到的类的路径:

app_main.cpp : Android/frameworks/base/cmds/app_process/app_main.cpp
IPCThreadState : Android/frameworks/native/libs/binder/IPCThreadState.cpp
ProcessState : Android/frameworks/native/libs/binder/ProcessState.cpp

好,我们了解到,Android应用的启动都会走到app_main.cpp中的AppRuntime类的onZygoteInit函数:

virtual void onZygoteInit(){sp<ProcessState> proc = ProcessState::self();ALOGV("App process: starting thread pool.\n");proc->startThreadPool();}

好,这里我们今天的第一个主角类登场了:ProcessState。先来了解下这个类。
这个类和IPCthreadState在Android的Binder架构体系中启动连接应用层和驱动层的作用,应用和驱动层打交道的所有接口调用都是在这两个类中的。
所以,每当一个应用初始化的时候,都会调用到这里,那我们就接着往下看这个ProcessState是如何初始化的:

sp<ProcessState> ProcessState::self()
{Mutex::Autolock _l(gProcessMutex);if (gProcess != nullptr) {return gProcess;}gProcess = new ProcessState(kDefaultDriver);return gProcess;
}

这个self函数就是一个单例模式,创建ProcessState

ProcessState::ProcessState(const char *driver): mDriverName(String8(driver)), mDriverFD(open_driver(driver)), mVMStart(MAP_FAILED), mThreadCountLock(PTHREAD_MUTEX_INITIALIZER), mThreadCountDecrement(PTHREAD_COND_INITIALIZER), mExecutingThreadsCount(0), mMaxThreads(DEFAULT_MAX_BINDER_THREADS), mStarvationStartTimeMs(0), mBinderContextCheckFunc(nullptr), mBinderContextUserData(nullptr), mThreadPoolStarted(false), mThreadPoolSeq(1), mCallRestriction(CallRestriction::NONE)
{// TODO(b/139016109): enforce in build system
#if defined(__ANDROID_APEX__)LOG_ALWAYS_FATAL("Cannot use libbinder in APEX (only system.img libbinder) since it is not stable.");
#endifif (mDriverFD >= 0) {// mmap the binder, providing a chunk of virtual address space to receive transactions.mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);if (mVMStart == MAP_FAILED) {// *sigh*ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());close(mDriverFD);mDriverFD = -1;mDriverName.clear();}}#ifdef __ANDROID__LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened.  Terminating.", driver);
#endif
}

这里可以大概看出这个类是管理一个线程池的作用,另外还有管理binder驱动,我们可以看到第3行open_driver ,这里就是打开了Bidner驱动:

static int open_driver(const char *driver)
{int fd = open(driver, O_RDWR | O_CLOEXEC);if (fd >= 0) {int vers = 0;status_t result = ioctl(fd, BINDER_VERSION, &vers);if (result == -1) {ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));close(fd);fd = -1;}if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",vers, BINDER_CURRENT_PROTOCOL_VERSION, result);close(fd);fd = -1;}size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);if (result == -1) {ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));}} else {ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));}return fd;
}

这里除了open驱动外,还设置了最大线程数,这里DEFAULT_MAX_BINDER_THREADS为15:

#define DEFAULT_MAX_BINDER_THREADS 15

然后,我们在回过头继续看ProcessState构造函数,接着初始化了一个锁mThreadCountLock 1和 一个条件变量 mThreadCountDecrement 2,最后初始花了内存映射:

mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

这里可以看到一个进程的mVMStart 内存映射大小为:

#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)

好了,到这里ProcessState的初始化就完成了,它是一个线程池,管理进程中所有的Binder线程,它还负责进程的Binder驱动打开和初始化操作,然后就是开启了与Binder驱动的内存映射。

我们接着来看proc->startThreadPool()

void ProcessState::startThreadPool()
{AutoMutex _l(mLock);if (!mThreadPoolStarted) {mThreadPoolStarted = true;spawnPooledThread(true);}
}

从名字可以看出这个方法的作用就是启动线程池了。我们继续往下跟踪:

void ProcessState::spawnPooledThread(bool isMain)
{if (mThreadPoolStarted) {String8 name = makeBinderThreadName();ALOGV("Spawning new pooled thread, name=%s\n", name.string());sp<Thread> t = new PoolThread(isMain);t->run(name.string());}
}

这里的作用就是启动一个Binder线程了,接着我们就来到了查看PoolThread是个什么东东:

class PoolThread : public Thread
{
public:explicit PoolThread(bool isMain): mIsMain(isMain){}protected:virtual bool threadLoop(){IPCThreadState::self(

相关文章:

一个Binder的前生今世 (二):Binder进程和线程的创建

文章目录 一个Binder的前生今世 (二):Binder进程和线程的创建binder在进程中的启动小结注释一个Binder的前生今世 (二):Binder进程和线程的创建 前篇文章一个Binder的前生今世 (一):Service的创建 讲了一个Service是如何创建以及如何与客户端建立联系的。讲解中涉及到…...

RocketMq源码分析(八)--消息消费流程

文章目录 一、消息消费实现二、消息消费过程1、消息拉取2、消息消费1&#xff09;提交消费请求2&#xff09;消费消息 一、消息消费实现 消息消费有2种实现&#xff0c;分别为&#xff1a;并发消费实现&#xff08;ConsumeMessageConcurrentlyService&#xff09;和顺序消费实现…...

sql--索引使用

最左前缀法则&#xff08;联合索引&#xff09; 联合索引 位置不影响&#xff0c;但是所有索引必须连续使用&#xff0c;才会走索引 中间跳过则会造成后面索引则会失效 索引失效 规避方法---尽量使用> 或 < Explain需要重点关注的字段 Type key_leng possibl…...

alibaba.fastjson的使用(三)-- Map、List ==》JSON字符串

目录 1.使用到的方法为: 2. Map转JSON字符串 3. List转JSON字符串 1.使用到的方法为: static String toJSONString(Object object) 2. Map转JSON字符串 /**...

pycharm 2023.2.3设置conda虚拟环境

分两步&#xff1a; &#xff08;1&#xff09;设置Virtualenv Environment &#xff08;2&#xff09;设值Conda Executable 加载conda环境&#xff0c;然后选择conda环境...

安卓Frida 脱壳

总结下现在脱壳的方法,比如寒冰大佬的Fart,买Nexus 手机,然后刷入肉丝老师的镜像就可以。是比较快速的方式。我今天推荐的方式是,使用Frida 来脱壳,基本上满足日常需求。也不用特别准备手机,脱壳镜像等。 Frida 环境电脑端安装比较简单,主要注意和手机版本相同即可。手机…...

【C】为什么7.0会被存储为6.99999

在《C Primer Plus》第 6 版 3.3.3 节 浮点数的介绍中&#xff0c;作者说浮点数通常只是实际值的近似值&#xff0c;例如&#xff0c;7.0可能被储存为浮点值6.99999。 如果采用32位的IEEE 754浮点表示形式来存储7.0&#xff0c;那么它的二进制表示将如下&#xff1a; 符号位&…...

Framework -- 系统架构

一、前言 framework的学习&#xff0c;需要掌握到什么程度&#xff1f; App 的启动流程&#xff1a;整体的过程&#xff0c;具体到某些类在整个流程中所起的作用&#xff1b;组件的设计模式&#xff0c;核心设计思想&#xff1b;需要知晓目前已知的问题&#xff0c;以及解决方…...

1.1 计算机安全概念

思维导图&#xff1a; 前言&#xff1a; 第1章: 计算机与网络安全概念笔记 1. 学习目标 了解保密性、完整性和可用性的关键安全需求。了解OSI的X.800安全架构。识别和举例说明不同的安全威胁和攻击。掌握安全设计的基本准则。熟悉攻击面和攻击树的使用。了解与密码标准相关的…...

react中的函数柯里化

函数柯里化是一种将接受多个参数的函数转化为一系列接受单一参数的函数的技术。在React开发中&#xff0c;函数柯里化可以帮助我们更好地组织组件的代码&#xff0c;使其具有更好的可读性和可复用性。 一个简单的函数柯里化示例&#xff1a; function add(a) {return functio…...

Unity点乘的实战案例1

向量的点乘,也叫向量的内积、数量积&#xff0c;对两个向量执行点乘运算&#xff0c;就是对这两个向量对应位一一相乘之后求和的操作&#xff0c;点乘的结果是一个标量。点乘&#xff0c;也叫数量积。结果是一个向量在另一个向量方向上投影的长度&#xff0c;是一个标量。 • …...

Hive数据查询详解

本专栏案例数据集链接: https://download.csdn.net/download/shangjg03/88478038 1.数据准备 为了演示查询操作,这里需要预先创建三张表,并加载测试数据。 1.1 员工表 -- 建表语句CREATE TABLE emp(empno INT, -- 员工表编号ename STRING, -- 员工姓名...

人工智能基础_机器学习008_使用正规方程_损失函数进行计算_一元一次和二元一次方程演示_sklearn线性回归演示---人工智能工作笔记0048

自然界很多都是正态分布的,身高,年龄,体重...但是财富不是. 然后我们来看一下这个y = wx+b 线性回归方程. 然后我们用上面的代码演示. 可以看到首先import numpy as np 导入numby 数据计算库 import matplotlib.pyplot as plt 然后导入图形画的库 然后: X = np.linspace(0,…...

【详细】Java网络通信 TCP、UDP、InetAddress

一、网络程序设计基础 1.局域网与因特网 为了实现两台计算机的通信&#xff0c;必须用一个网络线路连接两台计算机&#xff08;服务器<-->网络<-->客户机&#xff09;。 服务器是指提供信息的计算机或程序&#xff0c;客户机是指请求信息的计算机或程序。网络用…...

Linux(Centos7)操作记录

1、nginx -t #Nginx配置文件检查 上述截图代表检查没问题 上述截图检查配置文件配置错误&#xff0c;并提示错误文件位置 2、systemctl restart nginx #重启Nginx 重启Nginx失败 3、systemctl status nginx.service #查看Nginx服务状态 80端口被占导致服务启动失败 4、n…...

Vue全局事件总线实现任意组件间通信

一、安装全局事件总线 全局事件总线就像是一个工具&#xff0c;专门用于挂载自定义事件和。 想要所有的组件都能使用这个全局事件总线&#xff0c;就只有在Vue的原型身上添加一个能够绑定自定义事件的属性。 所以我们在创建Vue实例对象的时候就可以添加如下代码&#xff1a;…...

linux-tools-$(uname -r) linux-headers-$(uname -r)工具安装:

linux-tools-$(uname -r) linux-headers-$(uname -r)工具安装: ebpfebpf-virtual-machine:~$ sudo apt-get install linux-tools-$(uname -r) [sudo] ebpf 的密码&#xff1a; 正在读取软件包列表... 完成 正在分析软件包的依赖关系树... 完成 正在读取状态信息... 完成 linux…...

hive sql,年月日 时分秒格式的数据,以15分钟为时间段,找出每一条数据所在时间段的上下界限时间值(15分钟分区)

获取当前的年月日 时分秒 select date_format(current_timestamp(), yyyy-MM-dd HH:mm:ss)date_format(时间字段, ‘yyyy-MM-dd HH:mm:ss’) 将时间字段转为 2023-10-18 18:14:16 这种格式 在指定时间上增加15分钟 select from_unixtime(unix_timestamp(current_timestamp(…...

C#学习系列之继承

C#学习系列之继承 啰嗦继承使用特殊基类隐藏方法实际使用总结 啰嗦 基础学习。 继承 一个类派生于另一个基类型&#xff0c;它拥有该基础类型的所有成员字段和函数。A派生于B&#xff0c;继承A的所有东西&#xff0c;同时可以增加自己的东西。 使用 public class parent {p…...

PyTorch入门学习(六):神经网络的基本骨架使用

目录 一、引言 二、创建神经网络骨架 三、执行前向传播 一、引言 神经网络是深度学习的基础。在PyTorch中&#xff0c;可以使用nn.Module类创建自定义神经网络模型。本文将演示如何创建一个简单的神经网络骨架并执行前向传播操作。 二、创建神经网络骨架 首先&#xff0c…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...