技术标签: java binder binder架构解析 service manager native binder
相关源码路径
/framework/base/core/java/Android/os/IInterface.java
/framework/base/core/java/Android/os/IServiceManager.java
/framework/base/core/java/Android/os/ServiceManager.java
/framework/base/core/java/Android/os/ServiceManagerNative.java(包含内部类ServiceManagerProxy)
/framework/base/core/java/Android/os/IBinder.java
/framework/base/core/java/Android/os/Binder.java(包含内部类BinderProxy)
/framework/base/core/java/Android/os/Parcel.java
/framework/base/core/java/com/Android/internal/os/BinderInternal.java
/framework/base/core/jni/Android_os_Parcel.cpp
/framework/base/core/jni/AndroidRuntime.cpp
/framework/base/core/jni/Android_util_Binder.cpp
Android系统中,多进程间的通信都是依赖于底层Binder IPC机制,Binder机制是一种RPC方案。例如:当进程A中的Activity与进程B中的Service通信时,就使用了binder机制。为了完成进程间的通信,binder使用AIDL来描述进程间的接口。此外,整个Android系统架构中,采用了大量的binder机制。
Android中的Binder通信采用C/S架构,从组件视角来说,包含Client、Server、Service Manager以及binder驱动,其中Service Manager用于管理系统中的各种服务。Binder整体通信架构如下图所示:
(1)注册服务(addService):Server进程要先注册Service到Service Manager。该过程:Server是客户端,Service Manager是服务端;
(2)获取服务(getService):Client进程使用某个Service前,须先向Service Manager中获取相应的Service。该过程:Client是客户端,Service Manager是服务端;
(3)使用服务:Client根据得到的Service信息建立与Service所在的Server进程通信的通路,然后就可以直接与Service交互。该过程:client是客户端,server是服务端。
binder相对来说还是比较复杂的,有framework层与native层的binder。framework层的binder采用JNI技术来调用native(C/C++ framework)层的binder架构,从而为上层应用程序提供服务。需要注意的是:
(1) framework层的Binder是建立在Native层架构基础之上的,核心逻辑都是交予Native层方法来处理
(2)framework层的Service Manager类与Native层的功能并不完全对应,java层的Service Manager类的实现最终是通过BinderProxy传递给Native层来完成的。
图中红色代表整个framework层binder架构相关组件;Binder类代表Server端,BinderProxy类代表Client端;图中蓝色代表Native层Binder架构相关组件。
Android源码中,binder的核心库是在native层实现,但在java层和native层都有接口供应用程序使用。如果单从binder角度出发,Binder架构图如下:
(1) binder驱动层
Android因此添加了binder驱动,其设备节点为/dev/binder,主设备号为10,binder驱动程序在内核中的头文件和代码路径如下:
kernel/drivers/staging/binder.h
kernel/drivers/staging/binder.c
binder驱动层的主要作用是完成实际的binder数据传输。
(2) binder adapter层
主要是IPCThreadState.cpp和ProcessState.cpp,源码位于frameworks/native/libs/binder目录下,这两个类都采用了单例模式,主要负责和驱动直接交互。
a、ProcessState,进程相关的类,负责打开binder设备,进行一些初始化设置并做内存映射;
void ProcessState::startThreadPool()该方法启动的新线程,并通过joinThreadPool读取binder设备,查看是否有请求。
b、IPCThreadState,线程相关的类,负责直接和binder设备通信,使用ioctl读写binder驱动数据。
status_t IPCThreadState::talkWithDriver(bool doReceive) 该方法调用的是ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)从/dev/binder读取。
status_t IPCThreadState::executeCommand(int32_t cmd)该方法是对talkWithDriver返回的数据进行处理。
void IPCThreadState::joinThreadPool(bool isMain)该方法创建线程并进行talkWithDriver以及executeCommand。
(3) Binder核心层
Binder核心层主要是IBinder及它的两个子类,即BBinder和BpBinder,分别代表了最基本的服务端及客户端。源码位于frameworks/native/libs/binder目录下。
binder service服务端实体类会继承BnInterface,而BnInterface会继承自BBinder,服务端可将BBinder对象注册到servicemananger进程。
客户端程序和驱动交互时只能得到远程对象的句柄handle,它可以调用调用ProcessState的getStrongProxyForHandle函数,利用句柄handle建立BpBinder对象,然后将它转为IBinder指针返回给调用者。这样客户端每次调用IBinder指针的transact方法,其实是执行BpBinder的transact方法。
(4) Binder框架层
a、Native Binder框架层包含以下类(frameworks/native/libs/binder):IInterface,BnInterface,BpInterface,等。
b、Java框架层包含以下类(frameworks/base/core/java/android/os):
IBinder,Binder,IInterface,ServiceManagerNative,ServiceManager,BinderInternal,IServiceManager,ServiceManagerProxy
Java框架层的类的部分方法的实现在本地代码里(frameworks/base/core/jni)。
整个Binder从kernel至,native,JNI,Framework层所涉及的类如下:
int register_Android_os_Binder(JNIEnv* env)
{
// 注册Binder类的jni方法
if (int_register_Android_os_Binder(env) < 0)
return -1;
// 注册BinderInternal类的jni方法
if (int_register_Android_os_BinderInternal(env) < 0)
return -1;
// 注册BinderProxy类的jni方法
if (int_register_Android_os_BinderProxy(env) < 0)
return -1;
...
return 0;
}
public interface IBinder
{
. . . . . .
public String getInterfaceDescriptor() throws RemoteException;
public boolean pingBinder();
public boolean isBinderAlive();
public IInterface queryLocalInterface(String descriptor); //返回IInterface类型
public void dump(FileDescriptor fd, String[] args) throws RemoteException;
public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException;
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException; //通信函数
public interface DeathRecipient
{
public void binderDied();
}
public void linkToDeath(DeathRecipient recipient, int flags)throws RemoteException;
public boolean unlinkToDeath(DeathRecipient recipient, int flags);
}
public class Binder implements IBinder {
...
public Binder() {
init();
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Binder> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
}
public void attachInterface(IInterface owner, String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
public String getInterfaceDescriptor() {
return mDescriptor;
}
public IInterface queryLocalInterface(String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (code == INTERFACE_TRANSACTION) {
reply.writeString(getInterfaceDescriptor());
return true;
} else if (code == DUMP_TRANSACTION) {
ParcelFileDescriptor fd = data.readFileDescriptor();
String[] args = data.readStringArray();
if (fd != null) {
try {
dump(fd.getFileDescriptor(), args);
} finally {
try {
fd.close();
} catch (IOException e) {
// swallowed, not propagated back to the caller
}
}
}
// Write the StrictMode header.
if (reply != null) {
reply.writeNoException();
} else {
StrictMode.clearGatheredViolations();
}
return true;
}
return false;
}
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);//调用onTransact()函数
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
public void linkToDeath(DeathRecipient recipient, int flags) {
}
public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
return true;
}
protected void finalize() throws Throwable {
try {
destroy();
} finally {
super.finalize();
}
}
private native final void init();
private native final void destroy();
// Entry point from android_util_Binder.cpp's onTransact
private boolean execTransact(int code, long dataObj, long replyObj, int flags) {
...
try {
res = onTransact(code, data, reply, flags);//调用onTransact()函数
} catch (RemoteException e) {
if ((flags & FLAG_ONEWAY) != 0) {
Log.w(TAG, "Binder call failed.", e);
} else {
reply.setDataPosition(0);
reply.writeException(e);
}
res = true;
}
...
return res;
}
}
final class BinderProxy implements IBinder {
...
public IInterface queryLocalInterface(String descriptor) {
return null;
}
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
return transactNative(code, data, reply, flags);
}
public native String getInterfaceDescriptor() throws RemoteException;
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
public native void linkToDeath(DeathRecipient recipient, int flags)
throws RemoteException;
public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
BinderProxy() {
mSelf = new WeakReference(this);
}
...
}
最后,在来看IInterface接口,很简单,就一个方法,返回值是IBinder。
public interface IInterface
{
public IBinder asBinder();
}
四者的UML类图如下所示:
interface ICompute {
int add(int a,int b);
}
此时,会生成一个相应的java文件,如下:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\Code\\Github\\Android\\Demo\\src\\com\\tfygg\\demo\\service\\ICompute.aidl
*/
package com.tfygg.demo.service;
public interface ICompute extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.tfygg.demo.service.ICompute {
private static final java.lang.String DESCRIPTOR = "com.tfygg.demo.service.ICompute";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.tfygg.demo.service.ICompute
* interface, generating a proxy if needed.
*/
public static com.tfygg.demo.service.ICompute asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.tfygg.demo.service.ICompute))) {
return ((com.tfygg.demo.service.ICompute) iin);
}
return new com.tfygg.demo.service.ICompute.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_add: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.tfygg.demo.service.ICompute {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int add(int a, int b) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public int add(int a, int b) throws android.os.RemoteException;
}
对照着生成出来的ICompute.java文件,绘制如下Binder模型图:
class IBinder : public virtual RefBase
{
public:
. . . . . .
IBinder();
virtual sp<IInterface> queryLocalInterface(const String16& descriptor);
virtual const String16& getInterfaceDescriptor() const = 0;
virtual bool isBinderAlive() const = 0;
virtual status_t pingBinder() = 0;
virtual status_t dump(int fd, const Vector<String16>& args) = 0;
virtual status_t transact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0) = 0;
class DeathRecipient : public virtual RefBase
{
public:
virtual void binderDied(const wp<IBinder>& who) = 0;
};
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = NULL, uint32_t flags = 0) = 0;
virtual status_t unlinkToDeath(const wp<DeathRecipient>& recipient,
void* cookie = NULL, uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = NULL) = 0;
virtual bool checkSubclass(const void* subclassID) const;
typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
virtual void attachObject(const void* objectID, void* object,
void* cleanupCookie, object_cleanup_func func) = 0;
virtual void* findObject(const void* objectID) const = 0;
virtual void detachObject(const void* objectID) = 0;
virtual BBinder* localBinder();
virtual BpBinder* remoteBinder();
protected:
virtual ~IBinder();
private:
};
template
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp queryLocalInterface(const String16& _descriptor);
virtual String16 getInterfaceDescriptor() const;
protected:
virtual IBinder* onAsBinder();
};
BnInterface模版的定义如下所示:
template
class BpInterface : public INTERFACE, public BpRefBase
{
public:
BpInterface(const sp& remote);
protected:
virtual IBinder* onAsBinder();
};
这两个模版在使用的时候,起到得作用实际上都是双继承:使用者定义一个接口INTERFACE,然后使用BnInterface和BpInterface两个模版结合自己的接口,构建自己的BnXXX和BpXXX两个类。
#define DECLARE_META_INTERFACE(INTERFACE) /
static const String16 descriptor; /
static sp asInterface(const sp& obj); /
virtual String16 getInterfaceDescriptor() const; /
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) /
const String16 I##INTERFACE::descriptor(NAME); /
String16 I##INTERFACE::getInterfaceDescriptor() const { /
return I##INTERFACE::descriptor; /
} /
sp I##INTERFACE::asInterface(const sp& obj) /
{ /
sp intr; /
if (obj != NULL) { /
intr = static_cast( /
obj->queryLocalInterface( /
I##INTERFACE::descriptor).get()); /
if (intr == NULL) { /
intr = new Bp##INTERFACE(obj); /
} /
} /
return intr; /
}
在定义自己的类的时候,只需要使用DECLARE_META_INTERFACE和IMPLEMENT_META_INTERFACE两个接口,并结合类的名称,就可以实现BpInterface中asInterface()和getInterfaceDescriptor()两个函数。
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
由此可知,使用interface_cast的作用就是将IBinder实例转化成IXXXService实例。
文章浏览阅读4k次。今天在用exp工具导出数据时出现如下提示:连接到: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit ProductionWith the Partitioning, Automatic Storage Management, OLAP, Data Miningand Real Application T_dummyflag
文章浏览阅读127次。SCC(超级计算集群)简介 SCC概述 超级计算集群(Super Computing Cluster,SCC)使用高速RDMA网络互联的CPU以及GPU等异构加速设备,面向高性能计算、人工智能/机器学习、科学/工程计算、数据分析、音视频处理等应用,提供极致计算性能和并行效率的计算集群服务。SCC实例类型 类型 CPU Memory 网络 存储 适用场景 ecs.scch5.16xlarge 64核..._跨rdma网卡bond
文章浏览阅读1.2k次,点赞3次,收藏2次。音频采集量化概念1.采样大小(位深):一个采样用多少bit存放,常用的是16bit。2.采样率:采样频率,8K, 16K, 32K, 44.1K, 48K3.声道数:单声道,双声道,多声道码率计算PCM数据音频流码率=采样率x采样大小x声道数WAVWAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持。WAVE文_linux pcm short数组
文章浏览阅读648次。import java.util.concurrent.Exchanger;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ExchangerTest{ public static void main(String[] args) _exchanger类交换变量时值交换吗
文章浏览阅读1.2w次。mac安装双系统的坑安装环境:2017 macbook air 128g(是的,空间很小)macos 10.14.4准备:1。win10镜像。安装步骤为:1。打开boot camp2。分区3。安装出现错误:windows支持软件未能存储到所选驱动器,磁盘上没有足够的可用空间。删了很多东西,把win的分区加大都无法解决问题。折腾了很久终于找到了原因。原因:boot camp只认fat32,fat32..._bootcamp磁盘上没有足够的可用空间
文章浏览阅读509次。写在前面GDOI赛前集训Part2,今天结束了,当然作为一个弱菜,还是垫了一波底。_四会集训总结
文章浏览阅读495次,点赞23次,收藏8次。我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。这是一套 100% 原创的学习路线,它坚持实用主义,追求前沿技术,不但为初学者规划好了具体的学习步骤,还指明了常见的陷阱和困难。
文章浏览阅读99次。建立远程仓库进入需要的建仓库的文件夹,初始化本地仓库将所有变化提交到暂存区4. 提交代码到本地仓库5. 关联远程仓库6. 拉取远程仓库7.强制将本地分支推送到远程分支8.推送成功...
文章浏览阅读1.7w次,点赞5次,收藏3次。当使用docker login -u xxx -p xx时,报WARNING! Using --password via the CLI is insecure. Use --password-stdin.提示解决:1. 将密码写入到一个文件中,例如/etc/docker_passwd文件2.使用以下命令执行登录:cat /etc/docker_passwd | docker login --username 用户名--password-stdin..._warning! using --password via the cli is insecure. use --password-stdin.
文章浏览阅读73次。由于新浪博客书写保存问题,以后博客所在目录为CSDNMa_Hong_Kaihttps://blog.csdn.net/Ma_Hong_Kai/article/details/82734720(至于剩下的未写完的会在CSDN上更新) ...
文章浏览阅读117次。引言古人云:“活到老,学到老。”互联网算是最辛苦的行业之一,“加班”对工程师来说已是“家常便饭”,同时互联网技术又日新月异,很多工程师都疲于应付,叫苦不堪。以至于长期以来流传一个很广的误解:35岁是程序员工作的终点。如何在繁忙的工作中做好技术积累,构建个人核心竞争力,相信是很多工程师同行都在思考的问题。同样的工作、同样的做需求,为什么有的人只能在现有岗位上缓慢前行,而有的人却能进阿里,本文..._15096683069
文章浏览阅读1.3k次。前言:_audio架构