Android Binder通信原理(二):servicemanager启动

news2024/9/28 23:27:09

源码基于:Android R

0. 前言

下图是android 8.0 之前binder 的软件框架,依赖的驱动设备是/dev/binder,binder机制的四要素分别是client、server、servicemanager和binder驱动。

对于android 8.0后的binder 和vndbinder依然同这个框架,只不过驱动的设备多加/dev/vndbinder

这篇主要分析servicemanger的流程,hwservicemanger后续补充。

2. servicemanager 生成

先来看下该bin 文件产生:

frameworks/native/cmds/servicemanager/Android.bp

cc_binary {
    name: "servicemanager",
    defaults: ["servicemanager_defaults"],
    init_rc: ["servicemanager.rc"],
    srcs: ["main.cpp"],
}

cc_binary {
    name: "vndservicemanager",
    defaults: ["servicemanager_defaults"],
    init_rc: ["vndservicemanager.rc"],
    vendor: true,
    cflags: [
        "-DVENDORSERVICEMANAGER=1",
    ],
    srcs: ["main.cpp"],
}

该目录下通过同样的main.cpp 编译出两个bin 文件:servicemanager 和 vndservicemanager,两个bin 文件对应不同的 *.rc 文件。

frameworks/native/cmds/servicemanager/servicemanager.rc

service servicemanager /system/bin/servicemanager
    class core animation
    user system
    group system readproc
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart audioserver
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart inputflinger
    onrestart restart drm
    onrestart restart cameraserver
    onrestart restart keystore
    onrestart restart gatekeeperd
    onrestart restart thermalservice
    writepid /dev/cpuset/system-background/tasks
    shutdown critical
frameworks/native/cmds/servicemanager/vndservicemanager.rc

service vndservicemanager /vendor/bin/vndservicemanager /dev/vndbinder
    class core
    user system
    group system readproc
    writepid /dev/cpuset/system-background/tasks
    shutdown critical

3. servicemanager 的main()

frameworks/native/cmds/servicemanager/main.cpp

int main(int argc, char** argv) {
    if (argc > 2) {
        LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
    }

    //根据参数确认代码的设备是binder还是vndbinder
    const char* driver = argc == 2 ? argv[1] : "/dev/binder";

    //驱动设备的初始化工作,后面第 3.1 节详细说明
    sp<ProcessState> ps = ProcessState::initWithDriver(driver);

    //告知驱动最大线程数,并设定servicemanger的线程最大数
    ps->setThreadPoolMaxThreadCount(0);
    //调用处理,以error方式还是fatal
    ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);

    //核心的接口都在这里
    sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>());

    //将servicemanager作为一个特殊service添加进来
    if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
        LOG(ERROR) << "Could not self register servicemanager";
    }

    //保存进程的context obj
    IPCThreadState::self()->setTheContextObject(manager);
    //通知驱动context mgr是该context
    ps->becomeContextManager(nullptr, nullptr);

    //servicemanager 中新建一个looper,用以处理binder消息
    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);

    //通知驱动进入looper,并开始监听驱动消息,并设立callback进行处理
    BinderCallback::setupTo(looper);
    ClientCallbackCallback::setupTo(looper, manager);

    //启动looper,进入每次的poll处理,进程如果没有出现异常情况导致abort是不会退出的
    while(true) {
        looper->pollAll(-1);
    }

    // should not be reached
    return EXIT_FAILURE;
}

2.1 initWithDriver()

frameworks/native/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::initWithDriver(const char* driver)
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != nullptr) {
        // Allow for initWithDriver to be called repeatedly with the same
        // driver.
        if (!strcmp(gProcess->getDriverName().c_str(), driver)) {
            return gProcess;
        }
        LOG_ALWAYS_FATAL("ProcessState was already initialized.");
    }

    if (access(driver, R_OK) == -1) {
        ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
        driver = "/dev/binder";
    }

    gProcess = new ProcessState(driver);
    return gProcess;
}

函数的参数为driver 的设备名称,是 /dev/binder 还是 /dev/vndbinder。

另外的逻辑比较简单,ProcesState 是管理 “进程状态”,Binder 中每个进程都会有且只有一个mProcess 对象,如果该实例不为空,则确认该实例打开的driver 是否为当前需要init 的driver 名称;如果该实例不存在,则通过 new 创建一个。

详细的PorcessState 可以查看第 4 节。

2.2 new ServiceManager()

核心的接口都是位于Servicemanager 中,这里构造时新建一个Access 对象,如下:

frameworks/native/cmds/servicemanager/ServiceManager.cpp

ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {
    ...
}

4. ProcessState 类

ProcesState 是管理 “进程状态”,Binder 中每个进程都会有且只有一个mProcess 对象。该对象用以:

  • 初始化驱动设备;
  • 记录驱动的名称、FD;
  • 记录进程线程数量的上限;
  • 记录binder 的 context obj;
  • 启动 binder线程;

4.1 ProcessState 构造

frameworks/native/libs/binder/ProcessState.cpp

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.");
#endif

    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
}

该函数主要做了如下:

在初始化列表中,通过调用 open_driver() 代码设备驱动;

如果驱动open 成功,mDriverFD 被赋值后,通过mmap() 创建大小 BINDER_VM_SIZE 的buffer,用以接收 transactions 数据。

通过命令行可以确认这个大小,假设 servicemanager 的PID 为510,则通过:

cat /proc/510/maps 可以看到:

748c323000-748c421000 r--p 00000000 00:1f 4                              /dev/binderfs/binder

不用奇怪为什么不是/dev/binder,软连接而已:

lrwxrwxrwx  1 root      root                  20 1970-01-01 05:43 binder -> /dev/binderfs/binder
lrwxrwxrwx  1 root      root                  22 1970-01-01 05:43 hwbinder -> /dev/binderfs/hwbinder
lrwxrwxrwx  1 root      root                  22 1970-01-01 05:43 vndbinder -> /dev/binderfs/vndbinder

 

4.2 ProcessState 单例

ProcessState 使用self() 函数获取对象,因为有 vndbinder 和binder共用一份代码,所以如果需要使用 vndbinder,需要在调用 self() 函数前调用 initWithDriver() 来指定驱动设备名称。当然如果强制使用self() 函数,那么获取的单例针对的驱动设备为 kDefaultDriver

frameworks/native/libs/binder/ProcessState.cpp

#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endif

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

 

4.3 open_driver()

对于 binder 和 vndbinder 设备,在 ProcessState 构造的时候会在初始化列表中调用 open_driver() 来对设备进行open 和初始化。

frameworks/native/libs/binder/ProcessState.cpp

static int open_driver(const char *driver)
{
    //通过系统调用open 设备
    int fd = open(driver, O_RDWR | O_CLOEXEC);
    if (fd >= 0) {
        int vers = 0;

        //如果open 成功,会查询binder version是否匹配
        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;
        }

        //如果不是当前的version,为什么还是不return?
        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;
        //如果binder version 是当前的,会通知驱动设置最大的线程数
        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;
}

这里需要注意,每个进程创建的 binder 的最大线程数为:DEFAULT_MAX_BINDER_THREADS

frameworks/native/libs/binder/ProcessState.cpp

#define DEFAULT_MAX_BINDER_THREADS 15

对于servicemanager,main 函数中设定为0,也就是servicemanager 直接使用主线程,普通service 限制最大的binder thread为 15,详细在后面进行驱动分析。

4.4 makeBinderThreadName()

frameworks/native/libs/binder/ProcessState.cpp

String8 ProcessState::makeBinderThreadName() {
    int32_t s = android_atomic_add(1, &mThreadPoolSeq);
    pid_t pid = getpid();
    String8 name;
    name.appendFormat("Binder:%d_%X", pid, s);
    return name;
}

这是产生binder 线程名称的函数,通过变量 mThreadPoolSeq 控制顺序和个数,最终的binder 线程名称类似 Binder:1234_F

线程的最大数量是规定的,如上一些中说到的 DEFAULT_MAX_BINDER_THREADS (默认为15)。

当然,也可以通过 setThreadPoolMaxThreadCount() 函数来设定最大线程数,在servicemanager 中就是通过该函数指定 max threads为0,详细见第 3 节。

4.4.1 setThreadPoolMaxThreadCount()

frameworks/native/libs/binder/ProcessState.cpp

status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
    status_t result = NO_ERROR;
    if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) {
        mMaxThreads = maxThreads;
    } else {
        result = -errno;
        ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result));
    }
    return result;
}

4.5 spawnPooledThread()

frameworks/native/libs/binder/ProcessState.cpp

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 thread,PoolThread 继承自Thread,run 的时候会将 binder name 带入,所以,在打印线程堆栈时能知道第几个Binder 的线程。而每一个binder thread都会通过IPCThreadState 管理:

frameworks/native/libs/binder/ProcessState.cpp

class PoolThread : public Thread
{
public:
    explicit PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }

protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};

5. IPCThreadState 类

同 ProcessState 类,每个进程有很多的线程用来记录 “线程状态”,在每次binder 的BINDER_WRITE_READ 调用后,驱动都会根据情况确定是否需要spawn 线程,而创建一个PoolThread(详见ProcessState) 都会伴随一个IPCThreadState进行管理,而binder 线程中所有的操作都是通过 IPCThreadState 进行的。

 

5.1 IPCThreadState 构造

frameworks/native/libs/binder/IPCThreadState.cpp

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      mServingStackPointer(nullptr),
      mWorkSource(kUnsetWorkSource),
      mPropagateWorkSource(false),
      mStrictModePolicy(0),
      mLastTransactionBinderFlags(0),
      mCallRestriction(mProcess->mCallRestriction)
{
    pthread_setspecific(gTLS, this);
    clearCaller();
    mIn.setDataCapacity(256);
    mOut.setDataCapacity(256);
}

5.2 self()

frameworks/native/libs/binder/IPCThreadState.cpp

IPCThreadState* IPCThreadState::self()
{
    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)) {
        int 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;
}

每个线程创建后,都会通过pthread_getspecific() 确认TLS中是否有已经创建了IPCThreadState,如果有就直接返回,如果没有则新建一个。

 

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

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

相关文章

【Python版】手把手带你如何进行Mock测试

什么是mock&#xff1f; mock测试是以可控的方式模拟真实的对象行为。程序员通常创造模拟对象来测试对象本身该具备的行为&#xff0c;很类似汽车设计者使用碰撞测试假人来模拟车辆碰撞中人的动态行为 为什么要使用Mock&#xff1f; 之所以使用mock测试&#xff0c;是因为真…

js+html+css 封装一个弹窗组件

HTML中通过一个按钮触发显示弹窗的函数showPopup()&#xff0c;弹窗的内容包含在一个div元素中&#xff0c;初始设置为隐藏状态。 CSS中定义了弹窗的样式&#xff0c;包括背景、位置、边框等。 JavaScript中定义了两个函数showPopup()和hidePopup()&#xff0c;分别用于显示和隐…

CORS原理及解决办法

浏览器的同源策略阻止读取来自不同来源的资源。这种机制阻止恶意站点读取另一个站点的数据&#xff0c;但它也阻止合法使用。 一般情况下&#xff0c;我们可以通过两种方式解决浏览器的同源策略&#xff0c;JSONP和CORS,CORS解决方案更为通用&#xff08;推荐&#xff09;。 …

算法程序设计 之 胖男孩问题(7/8)

一、题目分析 问题描述 麦克结婚后&#xff0c;在上个月他胖了70磅。因为手指上的脂肪过多&#xff0c;使他连给他最亲密的朋友斯拉夫克写一个电子邮件都很困难。 每晚麦克都详细地描述那一天他所吃的所有东西&#xff0c;但有时当他只想按一次某键时往往会按了不止一次&…

java 读取图片中的文字

Maven依赖导入Tess4j <!-- https://mvnrepository.com/artifact/net.sourceforge.tess4j/tess4j --><dependency><groupId>net.sourceforge.tess4j</groupId><artifactId>tess4j</artifactId><version>4.5.4</version></de…

基于SpringBoot的二手书交易系统的设计与实现(源码、数据库、文档)

作为新兴事物&#xff0c;校园电子商务是&#xff0c;首先是指在校园范围内&#xff0c;其技术手段是校园网&#xff0c;而服务对象是全部师生。主要经营形式为学生自主经营&#xff0c;能够满足多群体生活学习需求&#xff0c;同时具备范围小&#xff0c;安全性高&#xff0c;…

《Web应用技术》期末复习(END)

说明&#xff1a;不知道是哪位兄台在群里说了一句&#xff0c;整的我压力山大。这是我个人的期末复习梳理&#xff0c;自己使用并且提供给几位有需要的朋友使用&#xff0c;并不确定期末考试考不考这些。请大家视情况查看和使用&#xff0c;如果有错误&#xff0c;也欢迎大家找…

opencv如何使用GPU的三种方法

我在工作实验涉及到图像和视频处理时&#xff0c;通常使用opencv提供的库来做处理&#xff0c;虽然OpenCV是一个广泛使用的库&#xff0c;它提供了丰富的功能和工具。然而&#xff0c;有时候在处理大量图片或视频时&#xff0c;我们可能会面临速度受限的问题。 opencv执行图像…

SpringMvc拦截器入门

文章目录 前言五、拦截器入门1.拦截器简介2.拦截器入门案例3.拦截器参数4. 拦截器链配置 总结 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&#xff0c;方便日后回顾。当然&#xff0c;如果能帮到一些萌新进行新技术的学习那也是极好的。作者…

管理Linux目录、用户、组以及文档的权限和归属

文章目录 一、管理Linux目录和文件1、查看及切换目录pwd&#xff1a;查看当前工作目录cd&#xff1a;切换工作目录ls&#xff1a;列出文档及属性alias&#xff1a;别名cat查看文件内容less分页显示长文件 2.新建目录/文件mkdir 创建目录touch创建文件 3.删除/移动/复制rm删除mv…

ai描述生成器绘画有哪些?ai绘画生成器描述介绍

从前&#xff0c;有一个名叫小华的画家&#xff0c;他是一位非常出色的艺术家&#xff0c;但是他总是感到自己还没有达到他理想中作品的水平。他一直在寻找一种方法来创造出高质量的艺术品。有一天&#xff0c;他听说了一种神奇的技术&#xff0c;可以让计算机通过人工智能生成…

MySQL全备+binlog恢复方法之伪装master

利用mysql全备 binlog server恢复方法之伪装master 单实例试验 一、试验环境 10.72.7.40 实例 mysql3306为要恢复的对象&#xff0c;mysql3306的全备binlog server&#xff08;目录/data/mysql/mysql3306/backup&#xff09; 实例mysql3307为伪装master 实例mysql3308为伪…

黑马程序员前端 Vue3 小兔鲜电商项目——(四)Home 页面布局

文章目录 Home 页面组件结构组件结构拆分Home 模块中引入组件 分类实现模板代码渲染数据 banner 轮播图实现模板代码封装接口渲染数据 面板组件封装创建公共组件复用抽取主题和副主题 新鲜好物实现模版代码封装接口渲染数据 人气推荐实现模板代码封装接口渲染数据 懒加载指令实…

Java实现加密(五)Base64编码

目录 一、Base64是怎么诞生的二、Base64定义三、Base64原理1.ASCII码转Base64&#xff08;字节数 % 3 0&#xff09;2.ASCII码转Base64&#xff08;字节数 % 3 2&#xff09;3.ASCII码转Base64&#xff08;字节数 % 3 1&#xff09;4.UTF-8转Base64 四、Java实现Base64编解码…

Android Binder通信原理(一):简介

源码基于&#xff1a;Android R 0. 前言 在Linux 系统中现有的进程间通信&#xff08;IPC&#xff09;方式&#xff1a; 管道(PIPE)&#xff1a;在创建时分配一个page大小的内存&#xff0c;缓存区大小比较有限&#xff1b;命名管道(FIFO)&#xff1a;考虑 PIPE_BUF 和原子操…

华为流程体系:IPD流程之敏捷开发(限制版)

目录 前言 敏捷 逐步采用敏捷原则 专栏列表 CSDN学院课程地址 前言 今天继续来谈谈 IPD 体系中敏捷开发所涉及的一些相关内容。 无论是硬件产品的开发过程&#xff0c;还是在应用或者是学习 IPD 的过程中。 瀑布式流程几乎都是标配。 这其实跟硬件产品或者是传统 IPD …

ROS:配置VScode

目录 前言一、下载二、vscode 安装三、vscode 集成 ROS 插件四、vscode 使用4.1 创建 ROS 工作空间4.2启动 vscode4.3vscode 中编译 ros4.4创建 ROS 功能包4.5C 实现4.6python 实现4.7配置 CMakeLists.txt4.8编译4.9执行 前言 VSCode 全称 Visual Studio Code&#xff0c;是微…

关于华为云服务器安装宝塔面板后,点击终端无响应解决方案

问题再现: 下面是我沟通宝塔客服后&#xff0c;给的解决方案。 我在百般无奈的情况下、卸载了宝塔后&#xff0c;最终躺平&#xff0c;选择了问宝塔官方客服 1、从华为提供的远程登录方式选一种 二、输入服务器密码通过ssh远程登录 服务器 二、执行宝塔官方提供的 命令执…

电影《闪电侠》观后感

上周看了电影《闪电侠》&#xff0c;主要是闪电侠这个人成长过程&#xff0c;与以往英雄题材类还是有些不太一样的&#xff0c;像之前蜘蛛侠和钢铁侠&#xff0c;都是讲主人公怎么成为那个英雄的&#xff0c;而本部电影是一个类似倒叙&#xff0c;他自己本身就已经是闪电侠了&a…

zookeeper安装使用及工作原理分析

1. Zookeeper概念简介 Zookeeper是一个分布式协调服务&#xff1b;就是为用户的分布式应用程序提供协调服务&#xff0c;它是集群的管理者&#xff0c;监视着集群中各个节点的状态&#xff0c;根据节点提交的反馈进行下一步合理操作。 具体介绍&#xff1a; A、zookeeper是为…