皮皮网

【生态商城源码】【Photo sphere 源码】【forkjoinpool源码分析】binder源码

时间:2024-11-23 07:59:13 分类:热点 来源:7447的源码

1.AndroidFramework 之启动 ServiceManager
2.Android Binder Hook的实现
3.一文分析Binder机制和AIDL的源码理解
4.深度分析Binder线程池的启动流程
5.Framework层的Binder(源码分析篇)
6.log4j2(一) 获取 ILoggerFactory

binder源码

AndroidFramework 之启动 ServiceManager

        本文源码基于 Android ,涉及相关源码如下。

        ServiceManagaer 是 Binder 的守护进程,在 Binder 机制中起着重要的作用。本文将从源码的角度对其进行分析,整体流程如下:

        时序图如下。

        先来看看 ServiceManager 是如何启动的:

        在 Zygote 一文中说过, init 进程启动的第二阶段会解析 init.rc 文件。

        在这之后会触发 trigger init 。

        结合 init.rc 看看 action init 做了什么。

        当触发 trigger init 后,会启动 servicemanager 服务,其声明如下。

        对应的执行文件为 /system/bin/servicemanager ,在编译前位于 frameworks/native/cmds/servicemanager 下,来看看 Android.bp 。

        其对应的源码为 service_manager.c 和 binder.c ,入口函数 main() 位于 servicemanager.c 。

        启动完 ServiceManager 后会打开 Binder 驱动。

        在 main() 中首先调用 binder_open() 。

        binder_open() 主要做了如下事情:

        给结构体 binder_state 分配内存。

        系统调用 open() 打开 /dev/binder ,如果打开驱动失败,则执行 fail_open 释放内存。

        简单的解释一下什么是系统调用?

        由于需要限制不同的程序之间的访问能力,防止程序获取别的程序的内存数据, CPU 划分出两个权限等级,用户态和 内核态。

        所有的用户程序都是运行在用户态,但有时需要做一些内核态的事情,而唯一可以做这些事情的就是操作系统,所以程序需要向操作系统发起请求,以程序的名字来执行这些操作。这时就需要一个从用户态切换到内核态但不能控制内核态中执行的机制,这种机制就是 系统调用。

        系统调用 ioctl() 传入 BINDER_VERSION 命令获取 Binder 驱动版本,对比版本是否一致,不一致则执行 fail_open 释放内存。

        系统调用 mmap() 映射 kb 的内存空间,即把 Binder 驱动文件的 kb 映射到内存空间供 ServiceManager 使用,内存映射失败则执行 fail_map ,关闭 fd 并释放内存。

        ServiceManager 进程 mmap 的内存大小可以通过 adb shell 命令查看。

        可以看到内存映射地址为 0xff ~ 0xf ,差为 0x 即十进制的 kb 。

        打开 Binder 驱动后会将 ServiceManager 设置为上下文管理者。

        调用 binder_become_context_manager() 。

        android 新增 BINDER_SET_CONTEXT_MGR_EXT 命令来设置安全的上下文管理者,如果设置失败,则使用原有的 BINDER_SET_CONTEXT_MGR 命令来设置上下文管理者,两者区别在于是否携带参数。

        最后会进入循环,从 Binder 驱动读取和解析数据。

        调用 binder_loop() 进入循环,不断地通过系统调用 ioctl() 从 Binder 驱动读取数据,并通过 binder_parse() 进行数据解析。

        注意这里调用 binder_loop() 传入的 svcmgr_handler() ,后面会使用到。

        binder_write() 会封装 struct binder_write_read ,并通过系统调用 ioctl() 将对应的命令传递给 Binder 驱动。

        binder_parse() 用来解析从 Binder 驱动读取到的数据,然后根据不同的命令执行对应的操作。

        因为 cmd 命令可能有多个,所以通过 while 循环每次处理一个 cmd 命令,多 cmd 的结构大致如下图所示。

        这里重点看下 BR_TRANSACTION 命令。

        BR_TRANSACTION 是 Binder 驱动向 Server 端发送请求数据。

        binder_transaction_data 的结构如下,其表明了 transcation 传输的具体语义,语义码记录在 code 中,不同语义码携带的数据是不同的,这些数据由 data 指定。

        在解析完 binder_transaction_data 的具体语义后,会调用前面传给 binder_loop() 的 svcmgr_handler() ,其实就是 switch case 语义码做不同的事情。

        ServiceManager 的功能其实很简单:

        至此 ServiceManager 就分析完了。

Android Binder Hook的实现

        Binder Hook可以Hook掉当前App用到的系统Service服务。

        以LocationManager为例,在获取一个LocationManager时分为两步。第一,获取IBinder对象;第二:IBinder对象通过asInterface()转化为LocationMangerService对象。最后初始化LocationManager,application层用到的都是LocationManager。

        Hook的大致原理是:ServiceManager在获取某个Binder时,如果本地有缓存的Binder,就不再跨进程请求Binder了。我们可以在缓存中加入自己的Binder,使得ServiceManager查询本地缓存时得到一个自定义的CustomBinder对象,不再跨进程向系统请求。并且ILocationManager.Stub.asInterface(CustomBinder)方法返回我们自定义的Service对象。

        这里面有两个地方需要用到自定义的对象。由于我们只Hook其中一部分的功能,其他功能还需要保留,所以用动态代理的方式创建自定义的Binder和自定义的Service。

        在理解后面的内容前你需要了解这些知识点:

        Activity等类在获取系统Service时,都是调用getSystemService(serviceName)方法获取的。

        Context 的 getSystemService() 方法调用了 SystemServiceRegistry 的 getSystemService() 方法。

        SystemServiceRegistry 中有一个常量 SYSTEM_SERVICE_FETCHERS,这是一个Map。保存了ServiceName和对应的ServiceFetcher。ServicFetcher是用于创建具体Service的类。ServiceFetcher 的关键方法是 createService() 方法。

        在 ServiceFetcher 的 createService() 方法中,调用了 ServiceManager.getService(name) 方法。以 LocationManager 对应的 ServiceFetcher 为例,它的createService()方法源码如下:

        假如我们要修改 LocationManager 的 getLastKnownLocation() 方法(下文都是)。我们要做的就是让ServiceManager.getService("location")返回我们自定义的Binder。先看一下这个方法简化后的源码:

        sCache是一个Map,缓存了已经向系统请求过的Binder。如果我们需要让这个方法返回我们我们自己的binder,只需要事先往sCache中put一个自定义的Binder就行了。

        在put之前,需要先创建出一个自定义的Binder。这个Binder在被 ILocationManager.Stub.asInterface 处理后,可以返回一个自定义的 LocationManagerService。

        先看一下Binder的 asInterface() 的实现:

        如果把 queryLocalInterface()方法返回一个自定义的Service,使得走if语句内部,不走else,那就算是Hook成功了。

        假设我们想让系统的LocationManager返回的位置信息全是在天安门(., .)。那我们需要使得 LocatitionManagerService 的 getLastLocation() 方法 返回的全是 (., .)。

        由于我们不能直接拿到系统的这个Service对象,可以先用反射的方式拿到系统的LocationManagerService。然后拦截getLastLocation()方法。

        原生的Binder对象在调用 queryLocalInterface() 方法时会返回原生的Service对象。我们希望返回3.1中的自定义Service。所以这里拦截 queryLocalInterface() 方法。

        有了自定义的Binder后,将它注入到ServiceManger的sCache变量中就完成Hook了~

        当onClick被调用的时候,Toast和Log都会显示天安门的坐标(., .)。证明Hook成功!

        你甚至可以用Binder Hook的方式Hook掉 ActivityManager。

一文分析Binder机制和AIDL的理解

       理解Android进程间通信的关键在于Binder机制,这是源码Android系统用于不同进程间交互的基础。不理解此机制,源码阅读源码时会面临诸多困难,源码难以把握系统深层次的源码逻辑与实现。尤其在遇到复杂问题时,源码生态商城源码深入理解进程间通信原理至关重要。源码

       Binder机制的源码引入主要是为了弥补Linux进程中其他通信方式在性能与安全性方面的不足。尽管Binder并非Android的源码原创技术,其源自更早的源码OpenBinder项目,但它已经成为Android进程间通信的源码核心手段。Binder机制通过代理对象实现进程间的源码数据交换,确保跨进程操作的源码高效与安全。

       在Android中,源码Binder代理是源码进程间通信的桥梁。当两个应用或进程需要交互时,Photo sphere 源码它们之间不能直接通信,而必须通过Binder实现。同样,应用调用系统服务时,也需通过Binder进行跨进程通信。常见的系统服务如ActivityManagerService(AMS)、WIFI、定位、媒体服务等,都需要通过Binder机制与应用进程交换信息。

       Binder本身是一个实现IBinder接口的Java类,它并非底层驱动,而是Android系统各层通信代码的集合。要理解Binder机制,需要从底层驱动到应用层逐步剖析,forkjoinpool源码分析耐心分析其代码结构。

       理解AIDL的关键在于其如何简化进程间通信的复杂性。尽管AIDL与实现进程间通信无关,它通过生成的代码模板减少了开发者的负担,降低了出错概率。通过对比使用AIDL与不使用AIDL实现的进程间通信代码,可以更清晰地理解AIDL生成的类是如何构建客户端与服务端之间的桥梁。

       实现进程间通信的示例代码展示了一个简单的客户端和服务端应用。在不使用AIDL的情况下,客户端通过直接调用IBinder对象的transact方法实现通信,这直接展示了Binder通信的核心逻辑。而在使用AIDL的情况下,客户端与服务端通过生成的类实现通信,AIDL生成的Stub类与Proxy类简化了这一过程,使得客户端更容易地与服务端交互,openswan源码卸载而服务端通过实现Stub类中的方法处理通信请求。

       总结来说,理解AIDL是为了更高效、更简洁地实现进程间通信,而Binder机制则是Android系统实现这一目标的核心技术。通过深入理解这两个组件,开发者可以更有效地与系统交互,提升应用的性能与稳定性。

深度分析Binder线程池的启动流程

       理论基础Binder

       Binder它是Android中的一种进程间通信机制,它主要采用的是CS架构模式。Binder框架中主要涉及到4个角色Client、Server、ServiceManager及Binder驱动,其中Client、Server、asp 弹窗源码ServiceManager运行在用户空间,Binder驱动运行在内核空间。

线程池

       线程池它是一种用于多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。

       简单的说:线程池就是创建一些线程,它们的集合称为线程池。

Binder线程池启动流程

       我们知道一个新的app应用程序进程在创建完成之后,它会通过调用RunTimeInit类的静态成员函数zygoteInitNative来进行启动Binder线程池。

       Binder线程池启动过程中,主要调用几个关键函数:ZygoteInitNative--->onZygoteInit--->startThreadPool。

       下面的源码分析主要是以android5.0版本为例。

ZygoteInitNative源码分析

       由于ZygoteInitNative函数是java实现的代码,实践上最终调用的是由C++实现的JNI方法。以下代码来源于系统的/frameworks/base/core/jni/androidRuntime.cpp文件中

staticvoidcom_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv*env,jobjectclazz){ //gCurRuntime是个全局的变量,后面跟上的是另外实现的方法。gCurRuntime->onZygoteInit();}onZygoteInit源码分析

       onZygoteInit函数在需要源码的位置:/frameworks/base/cmds/app_process/app_main.cpp文件中。

该函数是个虚函数,并且是一个无返回值和无参数的函数virtualvoidonZygoteInit(){ //Re-enabletracingnowthatwe'renolongerinZygote.atrace_set_tracing_enabled(true);//获取进程的状态信息sp<ProcessState>proc=ProcessState::self();//打印日志信息ALOGV("Appprocess:startingthreadpool.\n");//启动线程池proc->startThreadPool();}startThreadPool源码分析

       startThreadPool系统实现在\frameworks\native\libs\binder\ProcessState.cpp文件中。

       每一个支持Binder进程间通信机制的进程内都有一个唯一的ProcessState对象,当这个ProcessState对象的成员函数StartThreadPool函数被第一次调用的时候,它就会在当前进程中启动一个线程池,并将mThreadPoolStarted这个成员变量设置为true。

//该函数是个无参数,无返回值的函数voidProcessState::startThreadPool(){ AutoMutex_l(mLock);//判断线程池是否启动状态,启动的话就将标志信息设置为true属性。if(!mThreadPoolStarted){ mThreadPoolStarted=true;spawnPooledThread(true);}}总结

       Binder在android底层中是一个非常重要的机制,我们在实际的项目调用过程中,我们在app应用程序中只要实现自己的Binder本地对象的时候,跟其他服务一样,只需要将它进行启动起来,并且进行注册到ServerMananger就可以了。至于内部的实现一般是不需要去关心的。

Framework层的Binder(源码分析篇)

       本文以android-.0.0_r的AOSP分支为基础,解析framework层的Binder工作原理。

       从ServiceManager的getService方法入手,其核心代码是通过getIServiceManager().getService(name)获取服务。首先,ServiceManager的实现与进程中的ProcessState密切相关,ProcessState是单例,负责打开和映射Binder驱动。构造函数中,它会初始化驱动、验证版本并设置线程数,接着进行binder映射。

       在ProcessState的getContextObject方法中,调用native函数android_util_Binder.cpp中的getContextObject()。这个函数通过handle 0(ServiceManager的handle)获取BpBinder对象,然后通过javaObjectForIBinder函数将其转换为Java中的类型。

       进一步分析,BpBinder与java层的Binder之间存在对应关系,通过BinderProxy NativeData创建单例的BinderProxy。然后,每个服务的BinderProxy实例化和计数处理都在这个过程中完成。ServiceManagerNative.asInterface方法简化了getIServiceManager的调用,通过调用asInterface实例化ServiceManagerProxy。

       IServiceManager接口通过AIDL生成,其代理类ServiceManagerProxy实际上是不必要的。aidl文件在编译时生成对应java代码,用于binder通信。通过aidl文件,我们可以看到如queryLocalInterface等方法的实现细节。

       在Parcel的协助下,客户端与服务端进行数据传递,通过序列化和反序列化进行交互。在transact函数中,对Parcel大小进行检查,避免数据传输过大导致的问题。最后,客户端与binder驱动的通信过程涉及了Transaction数据的写入、等待响应、数据处理和内存回收等步骤。

       总的来说,framework层的Binder工作涉及服务管理、数据转换、通信协议和内存管理等环节,理解这些有助于深入掌握Binder的工作机制。

log4j2(一) 获取 ILoggerFactory

       å…³äºŽlog4j2的初始化流程,现在项目基本都是springboot项目,就需要结合 springboot 源码来解析,这块可以参考 Springboot - Log4J2LoggingSystem源码解析

        因为spring-boot-starter依赖中日志使用的是spring-boot-starter-logging,这里面是用的是logback,所以需要先剔除此依赖

        再添加log4j2依赖

        如果我们想使用 yml 后缀的配置文件还需要再加一个依赖

        然后相关依赖版本如下

        以下源码基于 log4j 2.7。

        先看一张log4j官方提供的类图

        先简单了解一下这些类

        过滤器的种类也很多,比如根据日志级别。Filter会返回一个枚举值Filter.Result,有三种:

        详细参见 log4j - Filters

        log4j的初始化流程实在有点饶,这里简要讲讲。

        LoggerFactory#getLogger(String)

        在只有一个log4j2的依赖时,加载流程大致如下:

        在 getILoggerFactory() 方法中做了这么几件事

        再看下 log4j2 的 StaticLoggerBinder 源码

        下一篇看看后续Logger的获取。

        添加 logback 依赖(直接放开 spring-boot-starter-logging 也行),这样我们项目就有两个 org/slf4j/impl/StaticLoggerBinder.class 了

        然后启动,提示

        我的疑问就是为啥不用log4j2而用logback,就打开这个网址查了下,里面最后有一段

        告诉我们

        好吧,随机的我也是醉了。。

        参考

       http://logging.apache.org/log4j/2.x/log4j-users-guide.pdf

       http://www.slf4j.org/codes.html#multiple_bindings

        回家,风雨兼程。

android和Linux的区别?

       æœ‰ä»¥ä¸‹ä¸‰ç‚¹åŒºåˆ«ï¼š

       1、Android没有本地窗口系统,而Linux是有X窗口系统。

       2、Android没有glibc支持,而Linux是有glibc支持的。

       3、Android是有自己专有的驱动程序。

       è™½ç„¶Android基于Linux内核,但是它与Linux之间还是有很大的差别。

扩展资料

       Android专有的驱动程序

       1、Android Binder 基于OpenBinder框架的一个驱动,用于提供 Android平台的进程间通信(InterProcess Communication,IPC)功能。源代码位于drivers/staging/android/binder.c。

       2、Android电源管理(PM) 一个基于标准Linux电源管理系统的轻量级Android电源管理驱动,针对嵌入式设备做了很多优化。源代码位于:

       kernel/power/earlysuspend.c

       kernel/power/consoleearlysuspend.c

       kernel/power/fbearlysuspend.c

       kernel/power/wakelock.c

       kernel/power/userwakelock.c

       3、低内存管理器(Low Memory Killer) 比Linux的标准的OOM(Out Of Memory)机制更加灵活,它可以根据需要杀死进程以释放需要的内存。源代码位于 drivers/staging/ android/lowmemorykiller.c。

       4、匿名共享内存(Ashmem) 为进程间提供大块共享内存,同时为内核提供回收和管理这个内存的机制。源代码位于mm/ashmem.c。

       5、Android PMEM(Physical) PMEM用于向用户空间提供连续的物理内存区域,DSP和某些设备只能工作在连续的物理内存上。源代码位于drivers/misc/pmem.c。

       6、Android Logger 一个轻量级的日志设备,用于抓取Android系统的各种日志。源代码位于drivers/staging/android/logger.c。

       7、Android Alarm 提供了一个定时器,用于把设备从睡眠状态唤醒,同时它还提供了一个即使在设备睡眠时也会运行的时钟基准。源代码位于drivers/rtc/alarm.c。

       8、USB Gadget驱动 一个基于标准 Linux USB gadget驱动框架的设备驱动,Android的USB驱动是基于gaeget框架的。源代码位于drivers/usb/gadget/。

       9、Android Ram Console 为了提供调试功能,Android允许将调试日志信息写入一个被称为RAM Console的设备里,它是一个基于RAM的Buffer。源代码位于drivers/staging/android / ram_console.c。

       ã€Android timed device 提供了对设备进行定时控制的功能,目前支持vibrator和LED设备。源代码位于drivers/staging/android /timed_output.c(timed_gpio.c)。

参考资料:百度百科——Android

       ç™¾åº¦ç™¾ç§‘——linux

copyright © 2016 powered by 皮皮网   sitemap