【binder】【android12】【2.servicemanager启动——全源码分析】

系列文章目录

 可跳转到下面链接查看下表所有内容https://blog.youkuaiyun.com/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.youkuaiyun.com/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501


目录

系列文章目录

1.简介

1.1 流程介绍

1.2 时序图

2.源码分析

2.1 servicemanager的启动

 2.2 servicemanager.rc

 2.3 main.cpp

 2.4 ProcessState::initWithDriver

 2.5 ProcessState::init

 2.6 ProcessState::ProcessState

 2.7 open_driver

 2.8 binder_open

 2.9 获取版本号binder_ioctl

 2.10 设置binder最大线程数binder_ioctl

2.11 binder_mmap

 2.12 binder_update_page_range

 2.13 setThreadPoolMaxThreadCount

 2.14 ServiceManager构造函数

 2.15 ServiceManager::addService

 2.16 getCallingContext

 2.17 IPCThreadState::self

 2.18 IPCThreadState::IPCThreadState

 2.19 Access::canAdd

 2.20 IPCThreadState::setTheContextObject

 2.21 ProcessState::becomeContextManager

2.22  binder_ioctl

 2.23 binder_new_node

 2.24 Looper::prepare

 2.25 Looper::getForThread

 2.26 Looper::initTLSKey

 2.27 Looper::Looper

 2.28 Looper::rebuildEpollLocked

2.29 Looper::setForThread

 2.30 sp setupTo

 2.31 IPCThreadState::setupPolling

 2.32 Parcel::writeInt32

 2.33 IPCThreadState::flushCommands

2.34 IPCThreadState::talkWithDriver

 2.35 binder_ioctl

 2.36 binder_thread_write

 2.37 Looper::addFd

 2.38 ClientCallbackCallback::setupTo

2.39 pollAll

 2.40 pollOnce

 2.41 pollInner


1.简介

经过上一篇,我们已经知道servermanager的框架,那么本篇便从源码的角度分析servermangaer服务的启动流程。

1.1 流程介绍

第一步:首先init进程启动后会读取各个进程的rc启动文件,然后会去启动servermanager服务。

第二步:在servermanager服务的main函数中,首先会打开/dev/binder驱动,并申请一块内存,通过mmap的进行内存映射,将servermanager服务的用户空间映射到驱动中,从而会减少数据的拷贝。

第三步:在servermanager服务的main函数中,创建servicemanager服务的对象,并将ServiceManager对象注册到自身的Map表保存起来。

第四步:becomeContextManager通知驱动成为binder的管理者。

第五步:servermanager服务的主线程进入死循环,调用epoll_wait() 监听/dev/binder是否有数据可读,如有则调用回调执行指令,根据client传入的code,从而调用get()\add()\ 等接口,来查询、注册binder服务。

1.2 时序图

 (为了保证流程的完整性,较为模糊,可放大观看)


2.源码分析

2.1 servicemanager的启动

1.在init.rc中,当init进程启动后,会去启动servicemanager、hwservicemanager、vndservicemanager 三个binder的守护进程。

[/system/core/rootdir/init.rc]
on init
    ...
    start servicemanager //启动sericemanager服务
    start hwservicemanager
    start vndservicemanager

 2.2 servicemanager.rc

1.init进程启动后,会从指定路径加载进程的rc文件,然后启动servicemanager服务。

service servicemanager /system/bin/servicemanager
    class core animation //服务的类为core和animation
    user system //在启动服务前将用户切换为system
    group system readproc //在启动前将用户组切换为system和readproc
    critical //表明这个服务是至关重要的服务,如果它在四分钟内退出超过四次,则设备将重启进入恢复模式
    onrestart restart apexd //当此服务重启后,重启apexd服务
    onrestart restart audioserver //当此服务重启后,重启audioserver服务
    onrestart restart gatekeeperd //当此服务重启后,重启gatekeeperd服务
    onrestart class_restart main //当此服务重启后,重启所有class为main的服务
    onrestart class_restart hal //当此服务重启后,重启所有class为 hal的服务
    onrestart class_restart early_hal //当此服务重启后,重启所有class为early_hal的服务
    writepid /dev/cpuset/system-background/tasks //写入当前servicemanager进程的pid到/dev/cpuset/system-background/tasks文件中
    shutdown critical //设置Service进程的关闭行为。在关机期间,当前服务在shutdown超时之前不会被关闭。

 2.3 main.cpp

主要作用为:

1.打开/dev/binder驱动,并完成mmap的内存映射,然后向设置最大线程数。

2.创建servicemanager服务的对象。

3.将ServiceManager对象注册到自身的Map表中。

4.becomeContextManager通知驱动成为binder的管理者。

5.进入死循环,调用epoll_wait() 监听/dev/binder是否有数据可读,如有则调用回调执行指令,根据client传入的code,从而调用get()\add()\ 等接口,来查询、注册binder服务。

int main(int argc, char** argv) {//servicemanager入口,与/dev/binder交互,vndservicemanager也是走这个口,只是init时,会传入/dev/vndbinder值
    if (argc > 2) {
        LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
    }

    const char* driver = argc == 2 ? argv[1] : "/dev/binder";//因为没传入值所以driver值是/dev/binder

    sp<ProcessState> ps = ProcessState::initWithDriver(driver);//传入的值是/dev/binder,创建了ProcessState对象,里面主要是通过mmap内存映射一块地址空间
    ps->setThreadPoolMaxThreadCount(0);//设置最大线程数为0
    ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);

    sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());//创建了一个ServiceManager对象
    if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {//将自身注册到ServiceManager当中
        LOG(ERROR) << "Could not self register servicemanager";
    }

    IPCThreadState::self()->setTheContextObject(manager);
    ps->becomeContextManager();//成为管理者

    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);

    BinderCallback::setupTo(looper);
    ClientCallbackCallback::setupTo(looper, manager);

    while(true) {//死循环,
        looper->pollAll(-1);//阻塞在此处,等待监听的fd有消息的到来
    }

    // should not be reached
    return EXIT_FAILURE;
}

 2.4 ProcessState::initWithDriver

sp<ProcessState> ProcessState::initWithDriver(const char* driver)
{
    return init(driver, true /*requireDefault*/);
}

 2.5 ProcessState::init

1.创建了ProcessState对象。此对象用于打开binder驱动,并完成内存的映射,将用户空间的一块内存映射到内核空间,映射关系建立后,用户对这块内存区域的修改可直接反映到内核空间,反之内核空间对其修改也能反映到用户空间。

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;//call_once的flag
    std::call_once(gProcessOnce, [&](){//call_once表示这个函数只执行一次
        if (access(driver, R_OK) == -1) {//access判断/dev/binder文件是否存在
            ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
            driver = "/dev/binder";
        }

        std::lock_guard<std::mutex> l(gProcessMutex);
        gProcess = sp<ProcessState>::make(driver);//此处使用的是安卓智能指针的构造,内部会调用new ProcessState
    });

    if (requireDefault) {//传入的是true,打印log
        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;
}

 2.6 ProcessState::ProcessState

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))//driver是/dev/binder
    , mDriverFD(open_driver(driver))//打开binder驱动返回的fd文件描述符
    , mVMStart(MAP_FAILED)//
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)//保护线程数量的锁,pthread_mutex_t mThreadCountLock;
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)//条件变量。pthread_cond_t mThreadCountDecrement;
    , mExecutingThreadsCount(0)
    , mWaitingForThreads(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)//最大线程数15
    , mStarvationStartTimeMs(0)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
    , mCallRestriction(CallRestriction::NONE)
{
    if (mDriverFD >= 0) {
        // mmap binder,内存映射。128k的内存地址,申请128k的内存地址用来接收事务,对应binder驱动的binder_mmap函数。
        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();
        }
		*/
    }
}

 2.7 open_driver

主要作用为:

1.open打开binder驱动,通过系统调用_open,最后会调用到binder_open,陷入内核态。获取fd。

2.通过ioctl,获取binder驱动版本号,用vers保存。然后对比版本号是否一致。

3.通过ioctl设置binder驱动最大线程数。

static int open_driver(const char *driver)
{
    int fd = open(driver, O_RDWR | O_CLOEXEC);//driver值是/dev/binder,打开binder驱动,陷入内核,此
	//open对应_open,然后对应binder驱动层的binder_open,binder_open中主要是为/dev/binder这个驱动设备节点,创建
	//对应的proc对象,然后通过fd返回。这样就可以和驱动进行通信。
    if (fd >= 0) {//大于0代表打开成功
        int vers = 0;
        status_t result = ioctl(fd, BINDER_VERSION, &vers);//获取binder驱动的版本信息,用vers保存
		/**正常不执行
        if (result == -1) {//如果获取信息失败,则关闭binder驱动
            ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
            close(fd);
            fd = -1;
        }
		*/
		
		/**
        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {//如果获取的版本信息不匹配,则关闭binder驱动
          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;//设置最大线程数15
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);//设置binder驱动最大线程数
		
		/**
        if (result == -1) {
            ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
        }
		*/
        uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;//DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION值是1,表示默认启用更新垃圾检测
        result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);//设置到binder驱动中
		/**
        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;
}

 2.8 binder_open

1.为当前sm服务进程分配保存binder_proc的对象。binder_proc结构体保存的是sm服务的进程的信息。

2.对sm服务的binder_proc的对象进行初始化,如初始化todo队列,设置进程优先级等。

3.将sm服务的binder_proc添加到binder_procs队列中,驱动有一个全局的binder_procss的列表,用于存储所有进程的binder_proc对象。

//主要作用:binder驱动为用户进程创建了用户进程自己的binder——proc实体
static int binder_open(struct inode *nodp, struct file *filp)
{
	struct binder_proc *proc;//proc表示驱动中binder进程


	proc = kzalloc(sizeof(*proc), GFP_KERNEL);//为binder_proc结构体在分配kernel内存空间
	if (proc == NULL)
		return -ENOMEM;
	//下面是对binder_proc进行初始化,binder_proc用于管理数据的记录体
	get_task_struct(current);
	proc->tsk = current;//current代表当前线程。当前线程此时是servicemanager的主线程,当前线程的task保存在binder进程的tsk
	INIT_LIST_HEAD(&proc->todo);//初始化to列表
	init_waitqueue_head(&proc->wait);//初始化wait列表
	proc->default_priority = task_nice(current);//当前进程的nice值转化为进程优先级

	binder_lock(__func__);

	binder_stats_created(BINDER_STAT_PROC);//BINDER_PROC对象创建+1
	hlist_add_head(&proc->proc_node, &binder_procs);//将proc_node节点添加到binder_procs为表头的队列
	proc->pid = current->group_leader->pid;
	INIT_LIST_HEAD(&proc->delivered_death);
	filp->private_data = proc;//将 proc 保存到filp中,这样下次可以通过filp找到此proc

	binder_unlock(__func__);

	if (binder_debugfs_dir_entry_proc) {
		char strbuf[11];
		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
		proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
			binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
	}

	return 0;
}
//进程相关的参数
struct binder_proc {
	struct hlist_node proc_node;//hlist_node表示哈希表中的一个节点。哈希表中的一个节点,用于标记该进程
	struct rb_root threads;// rb_root表示红黑树。Binder线程池每一个Binder进程都有一个线程池,
	//由Binder驱动来维护,Binder线程池中所有线程由一个红黑树来组织,RB树以线程ID为关键字  */
        //上述红黑树的根节点
	struct rb_root nodes;// 一系列Binder实体对象(binder_node)和Binder引用对象(binder_ref) */
    //在用户空间:运行在Server端称为Binder本地对象,运行在Client端称为Binder代理对象*/
    //在内核空间:Binder实体对象用来描述Binder本地对象,Binder引用对象来描述Binder代理对象 */
    //Binder实体对象列表(RB树),关键字 ptr
	struct rb_root refs_by_desc;//记录binder引用, 便于快速查找,binder_ref红黑树的根节点(以handle为key),它是Client在Binder驱动中的体现。
	//Binder引用对象,关键字  desc
	struct rb_root refs_by_node;//记录binder引用, 便于快速查找,binder_ref红黑树的根节点(以ptr为key),它是Client在Binder驱动中的体现,
	//Binder引用对象,关键字  node
	struct list_head waiting_threads; 
	int pid;//进程组pid
	struct task_struct *tsk;//任务控制模块
	const struct cred *cred;
	struct hlist_node deferred_work_node;
	int deferred_work;
	bool is_dead;

	struct list_head todo;//待处理队列,进程每接收到一个通信请求,Binder将其封装成一个工作项,保存在待处理队列to_do中  */

	struct binder_stats stats;
	struct list_head delivered_death;
	int max_threads;// Binder驱动程序最多可以请求进程注册线程的最大数量,
	//进程可以调用ioctl注册线程到Binder驱动程序中,当线程池中没有足够空闲线程来处理事务时,Binder驱动可以主动要求进程注册更多的线程到Binder线程池中 */
    // Binder驱动程序最多可以请求进程注册线程的最大数量
	int requested_threads;
	int requested_threads_started;
	int tmp_ref;
	long default_priority;
	struct dentry *debugfs_entry;
	struct binder_alloc alloc;
	struct binder_context *context;//存储binder_node和binder_context_mgr_uid以及name
	spinlock_t inner_lock;
	spinlock_t outer_lock;
	struct dentry *binderfs_entry;
};

 2.9 获取版本号binder_ioctl

主要作用为:

1.此时用于获取版本号,存在一次拷贝行为。

//获取binder版本号分析
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int ret;
	struct binder_proc *proc = filp->private_data;
	struct binder_thread *thread;//binder线程
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;

	trace_binder_ioctl(cmd, arg);

	ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//binder_stop_on_user_error值是0,
	//binder_stop_on_user_error < 2为假时,休眠,故此处不休眠
	if (ret)
		goto err_unlocked;

	binder_lock(__func__);
	thread = binder_get_thread(proc);//获取当前sm的proc实体对象的binder_thread
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {
	case BINDER_VERSION://获取版本号
		if (size != sizeof(struct binder_version)) {
			ret = -EINVAL;
			goto err;
		}
		if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) {
			//将驱动程序的BINDER_CURRENT_PROTOCOL_VERSION变量地址,拷贝sizeof(*ptr)的ubuf用户空间地址。
			//分析,此处是有一次拷贝的。
			ret = -EINVAL;
			goto err;
		}
		break;
	default:
		ret = -EINVAL;
		goto err;
	}
	ret = 0;
err:
	if (thread)
		thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
	binder_unlock(__func__);
	wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
	if (ret && ret != -ERESTARTSYS)
		printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
	trace_binder_ioctl_done(ret);
	return ret;
}

 2.10 设置binder最大线程数binder_ioctl

//设置binder最大线程数分析
//ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);maxThreads值为15
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int ret;
	struct binder_proc *proc = filp->private_data;
	struct binder_thread *thread;//binder线程
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;//ubuf是15的地址

	trace_binder_ioctl(cmd, arg);

	ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
	if (ret)
		goto err_unlocked;

	binder_lock(__func__);
	thread = binder_get_thread(proc);//获取当前sm的proc实体的binder_thread
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {
	case BINDER_SET_MAX_THREADS://设置binder最大线程数量
		if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {//拷贝用户空间的地址到内核空间
			ret = -EINVAL;
			goto err;
		}
		break;
	ret = 0;
err:
	if (thread)
		thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
	binder_unlock(__func__);
	wait_ev
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值