frameworks 之BInder启动

frameworks 之BInder启动

  • 调用 AppRuntime
  • 打开驱动 内存映射 ProcessState
  • PoolThread 开启 Binder 消息

进程在fork 的时候会初始化并启动对应的 Binder。
涉及到的类如下

  • frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
  • frameworks/base/core/jni/include/android_runtime/AndroidRuntime.h
  • frameworks/base/core/jni/AndroidRuntime.cpp
  • frameworks/base/cmds/app_process/app_main.cpp
  • frameworks/native/libs/binder/ProcessState.cpp
  • frameworks/native/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
  • frameworks/native/libs/binder/IPCThreadState.cpp

调用 AppRuntime

创建进程时候会执行 zygoteInit 方法,该方法会调用对应的 nativeZygoteInit

public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,String[] argv, ClassLoader classLoader) {if (RuntimeInit.DEBUG) {Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");}Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");RuntimeInit.redirectLogStreams();RuntimeInit.commonInit();// 这里启动BinderZygoteInit.nativeZygoteInit();return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,classLoader);}// c++ 方法private static native void nativeZygoteInit();

查看 nativeZygoteInit 实现(位于 AndroidRuntime.cpp ),通过变量调用 onZygoteInit。该方法和gCurRuntime 变量为 静态方法和静态变量, 其中 变量初始化为
AppRuntimemain 方法初始化,AppRuntime 继承 AndroidRuntime, 初始化时候会将 this 赋值给 gCurRuntime。

// frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{gCurRuntime->onZygoteInit();
}
// 初始化变量 gCurRuntime
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :mExitWithoutCleanup(false),mArgBlockStart(argBlockStart),mArgBlockLength(argBlockLength)
{init_android_graphics();// Pre-allocate enough space to hold a fair number of options.mOptions.setCapacity(20);assert(gCurRuntime == NULL);        // one per processgCurRuntime = this;
}
// frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{if (!LOG_NDEBUG) {String8 argv_String;for (int i = 0; i < argc; ++i) {argv_String.append("\"");argv_String.append(argv[i]);argv_String.append("\" ");}ALOGV("app_process main with argv: %s", argv_String.string());}// 初始化 AppRuntime ,该方法会初始化 gCurRuntimeAppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// Process command line arguments// ignore argv[0]argc--;argv++;
}

打开驱动 内存映射 ProcessState

因为变量其实是子类 AppRuntime, 所以 onZygoteInit 方法实际就是由 AppRuntime 实现,查看对应的代码。 该代码调用对应的 ProcessState::self 静态方法

// frameworks/base/cmds/app_process/app_main.cppvirtual void onZygoteInit(){sp<ProcessState> proc = ProcessState::self();ALOGV("App process: starting thread pool.\n");proc->startThreadPool();}

查看 self 方法, 该方法调用 Init 方法, 而 init 方法主要通过 make 方法初始化 ProcessState 变量。第一参数为 BInder 驱动

// frameworks/native/libs/binder/ProcessState.cpp
// 驱动名称
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endifsp<ProcessState> ProcessState::self()
{return init(kDefaultDriver, false /*requireDefault*/);
}sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{[[clang::no_destroy]] static sp<ProcessState> gProcess;[[clang::no_destroy]] static std::mutex gProcessMutex;if (driver == nullptr) {std::lock_guard<std::mutex> l(gProcessMutex);return gProcess;}[[clang::no_destroy]] static std::once_flag gProcessOnce;std::call_once(gProcessOnce, [&](){if (access(driver, R_OK) == -1) {ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);driver = "/dev/binder";}std::lock_guard<std::mutex> l(gProcessMutex);// 生成 processState,传入驱动 该方法来自 gProcess = sp<ProcessState>::make(driver);});if (requireDefault) {// Detect if we are trying to initialize with a different driver, and// consider that an error. ProcessState will only be initialized once above.LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != driver,"ProcessState was already initialized with %s,"" can't initialize with %s.",gProcess->getDriverName().c_str(), driver);}return gProcess;
}

make 为 binder_interface_utils.h 的泛型 方法。

// frameworks/native/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
static std::shared_ptr<T> make(Args&&... args) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"// 创建变量T* t = new T(std::forward<Args>(args)...);
#pragma clang diagnostic pop// warning: Potential leak of memory pointed to by 't' [clang-analyzer-unix.Malloc]return t->template ref<T>();  // NOLINT(clang-analyzer-unix.Malloc)}

查看对应的ProcessState 构造方法,在构造方法内 打开 Binder 驱动,在通过 mmap 映射内存。通过上面的传进来的驱动参数 通过 open_driver 打开驱动,里面调用 open方法打开驱动, 并返回文件描述符, 里面还会设置最大线程数,后续通过 ioctl 跟驱动交互。
BINDER_VM_SIZE 定义了内存大小,_SC_PAGE_SIZE 为内存片大小一般为1024 这就是 1M - 4k 的由来mmap 传入大小参数 进行映射对应的内存。

// frameworks/native/libs/binder/ProcessState.cpp
// 内存大小
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
// 最大线程数
#define DEFAULT_MAX_BINDER_THREADS 15
// 打开驱动
static int open_driver(const char *driver)
{// 打开驱动int fd = open(driver, O_RDWR | O_CLOEXEC);if (fd >= 0) {int vers = 0;// 告诉binder驱动版本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));}uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);if (result == -1) {ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));}} else {ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));}// 返回文件描述符return fd;
}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), mWaitingForThreads(0), mMaxThreads(DEFAULT_MAX_BINDER_THREADS), mStarvationStartTimeMs(0), mThreadPoolStarted(false), mThreadPoolSeq(1), mCallRestriction(CallRestriction::NONE)
{if (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
}

创建完 ProcessState 后,调用 startThreadPool 方法,里面又继续调用 spawnPooledThread 方法。

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

spawnPooledThread 方法又生成了 PoolThread 对象

void ProcessState::spawnPooledThread(bool isMain)
{if (mThreadPoolStarted) {// 生成 binder线程名称。String8 name = makeBinderThreadName();ALOGV("Spawning new pooled thread, name=%s\n", name.string());// 将 isMain 构造参数传入地址,为truesp<Thread> t = sp<PoolThread>::make(isMain);t->run(name.string());}
}

PoolThread 开启 Binder 消息

PoolThread 继承于 Thread 。不了解 Thread 可以查看该文章 ,从上面知道 make 生成对应的 PoolThread 对象。所以调用 run 方法 则会执行 threadLoop 方法。

class PoolThread : public Thread
{
public:explicit PoolThread(bool isMain): mIsMain(isMain){}protected:// 调用 run 会执行virtual bool threadLoop(){IPCThreadState::self()->joinThreadPool(mIsMain);return false;}const bool mIsMain;
};

首先则会执行 self 静态方法, 该方法会从一个 pthread_getspecific 类似 key value 的结构获取,如果获取到 则立即返回。 否则构造一个新的变量。第一次为 false 不会进入先进入下面 在通过 goto restart 重新获取 pthread_key_create 创建对应的key。可以看出每个binder线程只有一个 IPCThreadState

IPCThreadState* IPCThreadState::self()
{// 第一次为 false 不会进入先进入下面 在通过 goto restart 重新获取if (gHaveTLS.load(std::memory_order_acquire)) {
restart:const pthread_key_t k = gTLS;// 获取缓存是否存在,存在则返回,不存在则构建一个新的IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);if (st) return st;return new IPCThreadState;}// Racey, heuristic test for simultaneous shutdown.if (gShutdown.load(std::memory_order_relaxed)) {ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n");return nullptr;}pthread_mutex_lock(&gTLSMutex);if (!gHaveTLS.load(std::memory_order_relaxed)) {// threadDestructor 方法生成对应的对象。// 创建一个 Keyint key_create_value = pthread_key_create(&gTLS, threadDestructor);if (key_create_value != 0) {pthread_mutex_unlock(&gTLSMutex);ALOGW("IPCThreadState::self() unable to create TLS key, expect a crash: %s\n",strerror(key_create_value));return nullptr;}gHaveTLS.store(true, std::memory_order_release);}pthread_mutex_unlock(&gTLSMutex);goto restart;
}

查看 IPCThreadState 的构造方法,可以看到初始化一些变量,并放进去对应的缓存中 pthread_setspecific

IPCThreadState::IPCThreadState(): mProcess(ProcessState::self()),mServingStackPointer(nullptr),mWorkSource(kUnsetWorkSource),mPropagateWorkSource(false),mIsLooper(false),mIsFlushing(false),mStrictModePolicy(0),mLastTransactionBinderFlags(0),mCallRestriction(mProcess->mCallRestriction) {// 放进对应的 缓存中pthread_setspecific(gTLS, this);clearCaller();mIn.setDataCapacity(256);mOut.setDataCapacity(256);
}

通过 self 创建完 IPCThreadState 后则调用 joinThreadPool 方法。该方法开启了while 循环,让线程进入到循环中,等待命令,解析命令,给出响应。

void IPCThreadState::joinThreadPool(bool isMain)
{LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());// // isMain为true 所以会给驱动发送一个BC_ENTER_LOOPER 进入循环命令mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);mIsLooper = true;status_t result;do {processPendingDerefs();// now get the next command to be processed, waiting if necessaryresult = getAndExecuteCommand();if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",mProcess->mDriverFD, result);}// Let this thread exit the thread pool if it is no longer// needed and it is not the main process thread.if(result == TIMED_OUT && !isMain) {break;}} while (result != -ECONNREFUSED && result != -EBADF);LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",(void*)pthread_self(), getpid(), result);mOut.writeInt32(BC_EXIT_LOOPER);mIsLooper = false;talkWithDriver(false);
}

这样就完成了 Binder 启动。

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

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

相关文章

UDP程序设计

UDP协议概述 UDP&#xff0c;User Datagram Protocol&#xff0c;用户数据报协议&#xff0c;是一个简单的面向数据报(package-oriented)的传输层协议&#xff0c;规范为&#xff1a;RFC 768。 UDP提供数据的不可靠传递&#xff0c;它一旦把应用程序发给网络层的数据发送出去…

Java | Leetcode Java题解之第300题最长递增子序列

题目&#xff1a; 题解&#xff1a; class Solution {public int lengthOfLIS(int[] nums) {int len 1, n nums.length;if (n 0) {return 0;}int[] d new int[n 1];d[len] nums[0];for (int i 1; i < n; i) {if (nums[i] > d[len]) {d[len] nums[i];} else {int…

做一个能和你互动玩耍的智能机器人之四--固件

在openbot的firmware目录下我们能够找到arduino的固件源码和相关的文档。 openbot的controller目录下&#xff0c;是控制器的代码目录&#xff0c;用来控制机器人做一些动作。未来的目标是加入大模型&#xff0c;使其能够理解人的语言和动作来控制。 固件代码&#xff0c;支持…

利用小爱同学与点灯科技+esp8266+舵机,制作智能关灯神器:小白也可制作,米家同步设备可实现多部手机进行控制。(亲测有用)

利用小爱同学与点灯科技&#xff0c;制作智能关灯神器&#xff1a;小白也可制作&#xff0c;米家同步设备可实现多部手机进行控制。 文章目录 利用小爱同学与点灯科技&#xff0c;制作智能关灯神器&#xff1a;小白也可制作&#xff0c;米家同步设备可实现多部手机进行控制。1.…

19. Revit API: Parameter(参数)

一、前言 我们在前面或多或少提到也用到参数了&#xff0c;这篇便细讲一下。 首先&#xff0c;我们知道好多信息都藏在参数里&#xff0c;或者说可以从参数中获取。我们还能够通过调整参数的值&#xff0c;改变模型的形态&#xff0c;即族的参变。 其次&#xff0c;有时族上…

对接支付接口、分账系统、银行云账户如何与我们合作

以下是对接流程的优化版本&#xff0c;以提供更清晰的步骤和描述&#xff1a; 一、签约与打款&#xff1a; 客户完成合同签约。 同时进行首次打款&#xff0c;合同细节可以在后续补充。 二、对接服务专群&#xff1a; 客户与服务专群&#xff08;技术、客服等团队&#xff09;取…

一文讲透如何使用CSS美化HTML界面

上一篇文章(初识HTML文件&#xff0c;创建自己的第一个网页&#xff01;)介绍了HTML文件&#xff0c;并实战练习了如何编写一个结构简单的HTML网页&#xff0c;但最后也提到了单纯使用HTML语言创建的网页并不美观&#xff0c;有没有一个东西像PS能够美化图片一样让我们能够对我…

python 面向对象基础

1.self # 1. 定义类 class Washer (): def wash ( self ): print ( hellow world ) # <__main__.Washer object at 0x0000024BA2B34240> print ( self ) # 2. 创建对象 haier1 Washer () # <__main__.Washer object at 0x0000018B7B224240> print (…

RockyLinux 9.3 安装docker-ce

先安装yum工具 dnf install yum-utils -y

【前端 16】使用Ajax发送异步请求

Ajax 基础入门&#xff1a;实现异步请求 Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一种在无需重新加载整个网页的情况下&#xff0c;能够更新部分网页的技术。通过使用 Ajax&#xff0c;可以在后台与服务器交换数据&#xff0c;这意味着可以在不影响用户…

【代码】Python3|Scrapy框架初探(汽车之家大连市二手车车辆数据爬取、清洗与可视化)

本篇主要是整个项目的介绍&#xff0c;没提到太多琐碎的技术细节&#xff0c;以后有空的话会整理一下 Scrapy 和原生爬虫的差异&#xff0c;还有它坑人的一些地方&#xff0c;单发出来。 开源地址&#xff1a;https://github.com/shandianchengzi/car_home_spider 使用说明&a…

Github 2024-07-28 php开源项目日报Top10

根据Github Trendings的统计,今日(2024-07-28统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量PHP项目10Blade项目2TypeScript项目2Java项目1ASP项目1Laravel:表达力和优雅的 Web 应用程序框架 创建周期:4631 天开发语言:PHP, BladeStar…

openssl 加密

使用tar命令在Linux中加密文件可以通过两种方式实现&#xff1a;使用gzip压缩的同时加密&#xff0c;或者使用加密选项。 1. 使用gzip压缩的同时加密&#xff1a; “ tar cz file1 file2 | openssl enc -e -aes256 -out archive.tar.gz.enc “ – cz&#xff1a;创建tar压缩文…

基于粒子群优化算法(PSO)永磁同步电机电流环多参数辨识MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 仿真模型简介 在同步旋转dq 轴坐标系下建立PMSM 数学模型&#xff0c;将定子dq 轴电压设为辨识模型和实际测量值的输入&#xff0c;设计了PSO 辨识PMSM 参数的适应度函数。该辨识方法不需推导复杂的电机数学…

R语言统计分析——整合和重构

参考资料&#xff1a;R语言实战【第2版】 R中提供了许多用来整合&#xff08;aggregate&#xff09;和重塑&#xff08;reshape&#xff09;数据的强大方法。在整合数据时&#xff0c;往往将多组观测替换为根据这些观测计算的描述性统计量。在重塑数据时&#xff0c;则会通过修…

STM32——GPIO(点亮LEDLED闪烁)

一、什么是GPIO&#xff1f; GPIO&#xff08;通用输入输出接口&#xff09;&#xff1a; 1.GPIO 功能概述 GPIO 是通用输入/输出&#xff08;General Purpose I/O&#xff09;的简称&#xff0c;既能当输入口使用&#xff0c;又能当输出口使用。端口&#xff0c;就是元器件…

数据结构(5.3_5)——二叉树的线索化

第一种寻找中序前驱方法 中序线索化 本质上就是一次中序遍历&#xff0c;只不过需要在一边遍历一边处理结点线索化 代码&#xff1a; //全局变量pre 指向当前访问结点的前驱 ThreadNode* pre NULL;struct ElemType {int value; };//线索二叉树结点 typedef struct ThreadNode…

linux练习2

一、搭建nfs服务器&#xff0c;客户端可从服务端/share目录上传与下载文件 **服务端** 1、下载相关安装包 [rootserver ~]# yum install rpcbind -y [rootserver ~]# yum install nfs-utils -y 2、 创建共享文件夹/share并授予权限 [rootserver ~]# mkdir /share [rootserv…

Vue3 响应式高阶用法之 `triggerRef()`

Vue3 响应式高阶用法之 triggerRef() 在 Vue3 的响应式系统中&#xff0c;shallowRef 提供了一种轻量级的响应式状态管理方式。然而&#xff0c;当我们需要对 shallowRef 的内层属性进行操作时&#xff0c;就会遇到一些限制。幸运的是&#xff0c;Vue3 提供了 triggerRef() 方…

Yum源配置问题

一、配置yum源 1.备份当前yum源 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2.下载新的CentOS-Base.repo 到/etc/yum.repos.d/ wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 或者 curl …