Binder机制简单理解

-----2023.2.22----
回过头来看这篇文,太过细节.看源码还是要自顶向下,当初走了点弯路.要把握设计思想.
binder机制中有2个难以理解的点:句柄和句柄到对象的联系是如何建立.
这需要对c++的思想和android系统有一定的了解.

handle,句柄

C++沉思录

通过代理类(为每个对象创建一个代理),创建代理将会复制锁代理的对象,就像复制代理一样.如果想避免复制,通常使用句柄.它允许在保持代理的多态行为的同时,避免进行不必要的复制.
handle只通过控制引用计数就能高效地复制该类的对象.

句柄到对象的联系是如何建立的?
用户空间不直接请求句柄,内核空间按需分配句柄给进程.

现代操作系统

现代操作系统
现代操作系统

现代操作系统

-----2023.2.22----

写在开头:本文为读书笔记。
本篇大部分文字来自《深入理解Android内核设计思想》,小部分图文是阅读《深入理解Android内核设计思想》过程中的思考的问题(因为带着问题点去看才能印象深刻),参考部分博客,我有给出链接,小部分是自己结合源码的理解。部分源码未详细开展,本文目的是梳理大致流程。另外,代码最好放到Android studio里面去看,网页上看代码一多的话跳转很麻烦。

Binder可以分为4部分。
• Binder 驱动
• Service Manager
• Binder Client
• Binder Server
如果统观Binder 中的各个组成元素,就会惊奇地发现它和TCP/IP 网络有很多相似之处。
• Binder 驱动一路由器
• Service Manager一DNS
• Binder Client一客户端
• Binder Server一服务器


深入理解Android内核设计思想

接下来我会带着问题去分析binder的大致工作原理,这里主要分析binder驱动和Service Manager。

1.binder驱动

Binder Driver 会将自己注册成一个misc device, 并向上层提供一个/dev/binder 节点——值得一提的是, Binder 节点并不对应真实的硬件设备。Binder 驱动运行于内核态,可以提供open(), ioctl(), mmap()等常用的文件操作。

首先,问题一:为什么Binder 驱动只用了一次复制,
就实现了进程间的数据共享

首先要理解Android进程空间。
首先,对于一个32位的处理器, 在Linux系统中,其虚拟地址为32位,因此其虚拟地址空间的范围为

一个可执行文件运行起来的话它就变成了进程,系统会给每个进程分配一个4G大小的虚拟地址空间。如果一个Android设备是8g内存,给每个进程分配4g实际内存是不可能的。
Linux系统将虚拟地址空间按3:1比例划分,其中用户空间(user space)占3GB,内核空间(kernel space)占1GB。其中前3G内存是用户空间,最后1G是内核空间。所有的进程有各自的用户空间,但所有的进程都共享一个内核空间。
对应关系大致如下(对应关系是乱画的),实际是通过页表,找到实际的物理内存地址。

1.png

操作系统_存储模型

假设有两个进程A 和B, 其中进程B 通过open()和mmap()后与Binder 驱动建立了联系。

什么是mmap:内存映射文件。
进程通过一个系统调用(mmap)将一个文件(或部分)映射到其虚拟地址空间的一部分,访问这个文件就象访问内存中的一个大数组,而不是对文件进行读写。

操作系统_存储模型

深入理解Android内核设计思想

对于进程B而言, 它通过mmap()返回值得到一个内存地址(当然这是虚拟地址),这个地址通过虚拟内存转换(分段、分页)后最终将指向物理内存的某个位置。对千Binder 驱动而言,它也有一个指针( binder_proc->buffer )指向某个虚拟内存地址。而经过虚拟内存转换后,它和应用程序中指向的物理内存处千同一个位置。
这时Binder 和应用程序就拥有了若干共用的物理内存块。换句话说, 它们对各自内存地址的操作,实际上是在同一块内存中执行的。

右半部分Binder 驱动通过copy_from_ user() , 把进程A 中的某段数据复制到其binder_proc->buffer
所指向的内存空间中。这时候我们惊喜地发现, 因为binder_proc->buffer 在物理内存中的位置和进程B 是共享的, 因而进程B 可以直接访问到这段数据。也就是说, Binder 驱动只用了一次复制,就实现了进程A 和B 间的数据共享。

进程和binder通讯大致如下所示。

https://blog.csdn.net/codefly/article/details/17058607?spm=1001.2014.3001.5501

以下是简单的进程间通讯图。


https://juejin.cn/post/6857132425781182477

native层这里涉及到几个类。BpBinderBBbinder

binder机制中,C++层次的继承关系图如下:


image.png
https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android10-c2f2-release/libs/binder/BpBinder.cpp

// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }
    return DEAD_OBJECT;
}

BpBinder* BpBinder::create(int32_t handle) {
    int32_t trackedUid = -1;
    if (sCountByUidEnabled) {
        trackedUid = IPCThreadState::self()->getCallingUid();
        AutoMutex _l(sTrackingLock);
        uint32_t trackedValue = sTrackingMap[trackedUid];
        if (CC_UNLIKELY(trackedValue & LIMIT_REACHED_MASK)) {
            if (sBinderProxyThrottleCreate) {
                return nullptr;
            }
        } else {
            if ((trackedValue & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) {
                ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)",
                      getuid(), trackedUid, trackedValue);
                sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK;
                if (sLimitCallback) sLimitCallback(trackedUid);
                if (sBinderProxyThrottleCreate) {
                    ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy"
                          " count drops below %d",
                          trackedUid, getuid(), sBinderProxyCountLowWatermark);
                    return nullptr;
                }
            }
        }
        sTrackingMap[trackedUid]++;
    }
    return new BpBinder(handle, trackedUid);
}

BBbinder定义在Binder.cpp中。

https://android.googlesource.com/platform/frameworks/native/+/refs/heads/android10-c2f2-release/libs/binder/Binder.cpp

// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);
    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            reply->writeInt32(pingBinder());
            break;
        default:
            err = onTransact(code, data, reply, flags);
            break;
    }
    if (reply != nullptr) {
        reply->setDataPosition(0);
    }
    return err;
}

// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
{
    switch (code) {
        case INTERFACE_TRANSACTION:
            reply->writeString16(getInterfaceDescriptor());
            return NO_ERROR;
        case DUMP_TRANSACTION: {
            int fd = data.readFileDescriptor();
            int argc = data.readInt32();
            Vector args;
            for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
               args.add(data.readString16());
            }
            return dump(fd, args);
        }
        case SHELL_COMMAND_TRANSACTION: {
            int in = data.readFileDescriptor();
            int out = data.readFileDescriptor();
            int err = data.readFileDescriptor();
            int argc = data.readInt32();
            Vector args;
            for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
               args.add(data.readString16());
            }
            sp shellCallback = IShellCallback::asInterface(
                    data.readStrongBinder());
            sp resultReceiver = IResultReceiver::asInterface(
                    data.readStrongBinder());
            // XXX can't add virtuals until binaries are updated.
            //return shellCommand(in, out, err, args, resultReceiver);
            (void)in;
            (void)out;
            (void)err;
            if (resultReceiver != nullptr) {
                resultReceiver->send(INVALID_OPERATION);
            }
            return NO_ERROR;
        }
        case SYSPROPS_TRANSACTION: {
            report_sysprop_change();
            return NO_ERROR;
        }
        default:
            return UNKNOWN_TRANSACTION;
    }
}

BBinder用于server端,BpBinder用于client端。
例如BpMediaPlayer和BnMediaPlayerService,就类似是Bpxxx和Bnxxx。
具体分析可参考这篇。

Android之MediaPlayer 基本类_CAESAR的专栏-CSDN博客

BpBinder的实例的transact会调用BBbinder实例的transact,最终调用BBbinder中的onTransact。

其实这是一个Proxy-Stub模式。Proxy Stub即代理和存根。
打个比方,你到自动取款机上去取款;你就是客户,取款机就是你的代理;你不会在乎钱具体放在那里,你只想看到足够或更多的钱从出口出来(这就是com的透明性)。你同银行之间的操作完全是取款机代理实现。 你的取款请求通过取款机,传到另一头,银行的服务器,他也没有必要知道你在哪儿取钱,他所关心的是你的身份,和你取款多少。当他确认你的权限,就进行相应的操作,返回操作结果给取款机,取款机根据服务器返回结果,从保险柜里取出相应数量的钱给你。你取出卡后,操作完成。 取款机不是直接同服务器连接的,他们之间还有一个“存根”,取款机与存根通信,服务器与存根通信。从某种意义上说存根就是服务器的代理。

无标题.png

第二个问题来了。
问题二:binder驱动是如何从代理对象找到其对应的binder实体呢?
binder代理对象是指BpBinder实例,也就是BpXXX。
它是在用户空间创建,并且运行在Client进程中。
binder实体是指BBinder实例,也就是BnXXX,运行在Service进程中。

回到问题,这里主要是靠binder_proc(定义在kernel中)中的4棵红黑树

//https://github.com/Iscle/OrangePi_4G-IOT_Android_8.1_BSP/blob/58548740b6e9afe99a55b77582588c37609d2bca/kernel-4.4/drivers/android/binder.c
struct binder_proc
{
    . . . . . .
    struct rb_root threads;
    struct rb_root nodes;
    struct rb_root refs_by_desc;
    struct rb_root refs_by_node;
    . . . . . .
    . . . . . .
};

有四颗红黑树。nodes树用于记录binder实体,refs_by_desc树和refs_by_node树则用于记录binder代理。之所以会有两个代理树,是为了便于快速查找,threads树用于记录执行传输动作的线程信息。

https://blog.csdn.net/codefly/article/details/17058673?spm=1001.2014.3001.5501

BpBinder到底是如何和BBinder联系上可以参考下图:
https://blog.csdn.net/codefly/article/details/17058673?spm=1001.2014.3001.5501

BpBinder通过binder的句柄,即handle,其实就是
BpBinder调用create的时候传入的一个int型的参数,BpBinder* BpBinder::create(int32_t handle)
BpBinder创建后,会持有一个句柄。
BpBinder通过handle查询BBinder地址流程如下:
1.binder驱动查找binder_proc结构和句柄值相符的binder_ref节点
2.通过binder_ref节点的node域找到对应的binder_node节点,这个目标binder_node当然是从属于进程2的binder_proc啦,因为binder_refbinder_node都处于binder驱动的地址空间中,所以是可以用指针直接指向的。
3.binder_node节点的cookie域,记录的其实是BBinder的地址,binder驱动只需把这个binder实体对象地址值返回即可。

所以问题二的总结版答案是:首先通过代理对象BpBinderhandle找到binder_procbinder_ref存储的node域,然后把node域中的cookie域(cookie域记录了BBinder实体对象的地址),通过binder驱动把传cookie域所记录的Binder实体对象地址值给client进程。

其实这里还有一个问题点,如何通过handle找?这里涉及到ServiceManager部分,放到后面去。

2.ServiceManager

ServiceManager 在Android 系统启动之后就运行起来了,并通过BINDER_SET_CONTEXT_MGR 把自己注册成Binder “ 大管家”。它在做完一系列初始化后,在最后一次ioctl 的read 操作中会进入睡眠等待,直到有Binder Client 发起服务请求而被Binder 驱动唤醒。

这一部分我只看java层。

https://android.googlesource.com/platform/frameworks/base/+/refs/heads/android10-c2f2-release/core/java/android/os/ServiceManager.java

public final class ServiceManager {
    private static final String TAG = "ServiceManager";
    private static final Object sLock = new Object();
    @UnsupportedAppUsage
    private static IServiceManager sServiceManager;
 
   
    @UnsupportedAppUsage
    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }
        // Find the service manager
        sServiceManager = ServiceManagerNative
                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
        return sServiceManager;
    }
    /**
     * Returns a reference to a service with the given name.
     *
     * @param name the name of the service to get
     * @return a reference to the service, or null if the service doesn't exist
     */
    @UnsupportedAppUsage
    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return Binder.allowBlocking(rawGetService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
 
    /**
     * Place a new @a service called @a name into the service
     * manager.
     *
     * @param name the name of the new service
     * @param service the service object
     * @param allowIsolated set to true to allow isolated sandboxed processes
     * to access this service
     */
    @UnsupportedAppUsage
    public static void addService(String name, IBinder service, boolean allowIsolated) {
        addService(name, service, allowIsolated, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
    }
    /**
     * Place a new @a service called @a name into the service
     * manager.
     *
     * @param name the name of the new service
     * @param service the service object
     * @param allowIsolated set to true to allow isolated sandboxed processes
     * @param dumpPriority supported dump priority levels as a bitmask
     * to access this service
     */
    @UnsupportedAppUsage
    public static void addService(String name, IBinder service, boolean allowIsolated,
            int dumpPriority) {
        try {
            getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
        } catch (RemoteException e) {
            Log.e(TAG, "error in addService", e);
        }
    }
}

ServiceManager中主要是调用add和get方法。
下面以StatusBarManagerService为例,来看看ServiceManager的使用。
如果只看java层的话,主要涉及到StatusBarManagerServiceStatusBarManagerStatusBarCommandQueue这4个类。

SystemServer中的startOtherServices,将StatusBarManagerService添加到ServiceManager中。
StatusBarManagerService是继承自IStatusBarService.Stub

//https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
  StatusBarManagerService statusBar = null;
......................
 if (!isWatch) {
           t.traceBegin("StartStatusBarManagerService");
                try {
                    statusBar = new StatusBarManagerService(context);
                    ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
                } catch (Throwable e) {
                    reportWtf("starting StatusBarManagerService", e);
                }
                t.traceEnd();
            }
...................
}

先不看client端的调用,只看service这一端的流程。
下面是省略版IStatusBarService.aidl和IStatusBar.aidl文件。
注意:为减少文件,我有删除部分函数的参数。

import xxx.xxx.xxx.IStatusBar;

interface IStatusBarService {
   void removeIcon(String slot);
   void registerStatusBar(IStatusBar callbacks);
}
oneway interface IStatusBar {
        void removeIcon(String slot);
}

statusbar中一个图标对应一个slot。
可以新建这2个aidl文件到Android studio中,然后build一下工程,看看生成的java文件。

StatusBarManagerService继承自IStatusBarService.Stub, 是BBinder。CommandQueue 继承自IStatusBar.Stub,

public class StatusBarManagerService extends IStatusBarService.Stub {
    private volatile IStatusBar mBar;

    @Override
    public void removeIcon(String slot) {
        enforceStatusBar();

        synchronized (mIcons) {
            mIcons.remove(slot);

            if (mBar != null) {
                try {
                    mBar.removeIcon(slot);
                } catch (RemoteException ex) {
                }
            }
        }
    }

    @Override
    public void registerStatusBar(IStatusBar bar) {
        mBar = bar;
    }
    
}
public class CommandQueue extends IStatusBar.Stub{
    private ArrayList mCallbacks = new ArrayList<>();

    public interface Callbacks {
        default void removeIcon(String slot) { }
    }

    public void addCallback(Callbacks callbacks) {
        mCallbacks.add(callbacks);
    }

    public void removeIcon(String slot) {
        synchronized (mLock) {
            // don't coalesce these
            mHandler.obtainMessage(MSG_ICON, OP_REMOVE_ICON, 0, slot).sendToTarget();
        }
    }


    private final class H extends Handler {
        private H(Looper l) {
            super(l);
        }

        public void handleMessage(Message msg) {
            final int what = msg.what & MSG_MASK;
            switch (what) {
                case MSG_ICON: {
                    switch (msg.arg1) {
                        case OP_REMOVE_ICON:
                            for (int i = 0; i < mCallbacks.size(); i++) {
                                mCallbacks.get(i).removeIcon((String) msg.obj);
                            }
                            break;
                    }
                    break;
                }

            }
        }
    }
}

再来看StatusBar 。

public class StatusBar implements CommandQueue.Callbacks{
    protected CommandQueue mCommandQueue;

    protected IStatusBarService mBarService;

    public StatusBar(CommandQueue commandQueue){
        mCommandQueue = commandQueue;
    }

    @Override
    public void start() {
        mBarService = IStatusBarService.Stub.asInterface(
                ServiceManager.getService(Context.STATUS_BAR_SERVICE));

        mCommandQueue.addCallbacks(this);

        try {
            mBarService.registerStatusBar(mCommandQueue);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

这里终于看到了ServiceManager。前面SystemServer.java中调用了 ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);StatusBar.java中,调用了getService。

mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));

也就是这里是 IStatusBarService.Stub.asInterface(StatusBarManagerService)。

//IStatusBarService.java
    public static com.example.myapplication.IStatusBarService asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.example.myapplication.IStatusBarService))) {
        return ((com.example.myapplication.IStatusBarService)iin);
      }
      return new com.example.myapplication.IStatusBarService.Stub.Proxy(obj);
    }

Stub.asInterface这里会根据调用进程与当前进程是否一致判断返回Bbinder(Binder实体)还是BpBinder(本地Binder的代理对象,即IStatusBarService.Stub.Proxy)。
如果忽略掉binder驱动层,可以看成这里是返回一个StatusBar可以调用的StatusBarManagerService实例。

mBarService.registerStatusBar(mCommandQueue);

StatusBar中调用了mBarService.registerStatusBar(mCommandQueue);因此StatusBarManagerService持有CommandQueue

所以,当调用StatusBarManagerService 的removeIcon(String slot)的时候,会走到CommandQueuemCallbacks.get(i).removeIcon((String) msg.obj);中。

这里使用了回调。
removeIcon实际的具体的实现是在StatusBarIconControllerImpl中。

public class StatusBarIconControllerImpl implements  CommandQueue.Callbacks,StatusBarIconController {

    @Inject
    public StatusBarIconControllerImpl(Context context, CommandQueue commandQueue) {
        mContext = context;
        commandQueue.addCallback(this);
    }

    public void removeIcon(String slot) {
        removeAllIconsForSlot(slot);
    }

    @Override
    public void removeAllIconsForSlot(String slotName) {
        Slot slot = getSlot(slotName);
        if (!slot.hasIconsInSlot()) {
            return;
        }

        int slotIndex = getSlotIndex(slotName);
        List iconsToRemove = slot.getHolderListInViewOrder();
        for (StatusBarIconHolder holder : iconsToRemove) {
            int viewIndex = getViewIndex(slotIndex, holder.getTag());
            slot.removeForTag(holder.getTag());
            mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex));
        }
    }

}

如果需要aidl中新增一个其他控制函数,也可以把具体实现写到StatusBar,看具体需求。
至于StatusBarStatusBarIconControllerImpl的创建,涉及到依赖注入与控制反转,这里不做深入,可参考这一篇文章去具体分析。Dagger2和它在SystemUI上的应用
Android源码中其实很多模块用到了依赖注入与控制反转。

service端的分析就到这里了,下面来看看client端。
这里主要就是StatusBarManager

@SystemService(Context.STATUS_BAR_SERVICE)
public class StatusBarManager {
    private IStatusBarService mService;

    private synchronized IStatusBarService getService() {
        if (mService == null) {
            mService = IStatusBarService.Stub.asInterface(ServiceManager.getService(STATUS_BAR_SERVICE));
        }
        return mService;
    }


    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public void removeIcon(String slot) {
        try {
            final IStatusBarService svc = getService();
            if (svc != null) {
                svc.removeIcon(slot);
            }
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
}
frameworks/base/core/java/android/app/SystemServiceRegistry.java


        registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
                new CachedServiceFetcher() {
            @Override
            public StatusBarManager createService(ContextImpl ctx) {
                return new StatusBarManager(ctx.getOuterContext());
            }});

StatusBarManagerSystemServiceRegistry中初始化。

            mService = IStatusBarService.Stub.asInterface(ServiceManager.getService(STATUS_BAR_SERVICE));

这里也是通过ServiceManagerIStatusBarService获取一个Binder,不过由于是不同进程所以这里获取的是Binder代理对象。

StatusBarManager 类定义的时候用@SystemService(Context.STATUS_BAR_SERVICE)修饰,因此
获取StatusBarManager 可以通过getSystemService

StatusBarManager mStatusBarManager = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
或
StatusBarManager mStatusBarManager = (StatusBarManager) getSystemService(StatusBarManager.class);

然后会在StatusBarNotifier调用 mStatusBarManager.setIcon

//https://cs.android.com/android/platform/superproject/+/master:packages/services/Telecomm/src/com/android/server/telecom/StatusBarNotifier.java
        if (isMuted) {
            mStatusBarManager.setIcon(
                    SLOT_MUTE,
                    android.R.drawable.stat_notify_call_mute,
                    0,  /* iconLevel */
                    mContext.getString(R.string.accessibility_call_muted));
        } else {
            mStatusBarManager.removeIcon(SLOT_MUTE);
        }

StatusBarNotifier会由一个client去调用,应该是某个telecom相关进程。

简单来说,removeIcon的调用过程如下。

这张图是只是java代码部分,忽略了c++部分代码,实际java到驱动中间是通过jni去调用c++代码,c++代码访问binder驱动

大致流程就是这样的。

http://gityuan.com/2015/11/21/binder-framework/

StatusBarManagerService就是一个BinderProxy,

如何设计到native层的话,这里还有一个问题:Client如何通过ServiceManager创建BpBinder?
问题3可以参考这篇。
深入理解任何Binder Client都可以直接通过ServiceManager的0这个Binder句柄创建一个BpBinde
这个问题我暂时没有捋清楚,代码还没有过一遍。

总结:
如果要访问SM(Binder Server)的服务,流程应该是怎么样的呢?
无非就是以下几步:
· 打开Binder 设备;
· 执行mrnap;
· 通过Binder 驱动向SM 发送请求( SM 的handle 为0) ;
· 获得结果。

如果应用程序代码中每次使用SM 服务( 或者其他Binder Server 服务),都需要打开一次Binder 驱动、执行mmap , 其后果就是消耗的系统资源会越来越多, 直到崩溃。一个有效的解决办法是每个进程只允许打开一次Binder 设备, 且只做一次内存映射一一所有需要使用Binder 驱动的线程共享这一资源。
ProcessState 和IPCThreadState
Android 系统特别为程序进程使用Binder 机制封装了两个实现类,即ProcessState 和IPCThreadState。从名称上可以看出,前者是进程相关的,而后者是线程相关的。ProcessState 负责打开B inder 驱动设备,进行mmap等准备工作; 而如何与Binder 驱动进行具体的命令通信则由IPCThreadState 来完成。
ProcessState 的构造函数中初始化了很多变量—最重要的是,它调用open_driver()打开了/dev/binder 节点。我们再复习一下使用Binder 驱动所需要做的准备工作: 首先是打开binder 节点,然后执行mmap()一具体而言,映射的内存块大小为BINDER_VM_SIZE 。
真正与Binder 驱动打交道的地方是talkWithDriver 中的ioctl(),整个流程中多次调用了这个函数。

Binder 的执行过程多数是阻塞型的( 或者说是同步操作)。换句话说,通过Binder去调用服务进程提供的接口函数,那么此函数执行结束时结果就已经产生,不涉及回调机制。比如用户使用getService 向ServiceManager 发起查询请求一函数的返回值就是查询的结果,意味若用户不需要提供额外的回调函数来接收结果。
Binder 是如何做到这一点的呢?可以想到的方法有很多, 其中常见的一种就是让调用者进程暂时挂起,直到目标进程返回结果后, Binder 再唤醒等待的进程。

因为一个transcation 通常涉及两个进程A 和B , 当A 向B 发送了请求后, B 需要一段时间来执行:此时对A 来说就是一个“未完成的操作“一直到B 返回结果
后, Binder 驱动才会再次启动A 来继续执行。

关于Binder的传输,我觉得结合AIDL去说明比较好,所以留到下一篇。有空的话在写。

参考链接:

《深入理解Android内核设计思想》

Dagger2和它在SystemUI上的应用
图解Android - Binder 和 Service - 漫天尘沙 - 博客园

红茶一杯话Binder(初始篇)
Android之MediaPlayer 基本类_CAESAR的专栏-CSDN博客
Android深入浅出之Binder机制 - innost - 博客园

深入理解任何Binder Client都可以直接通过ServiceManager的0这个Binder句柄创建一个BpBinde

掌握 binder 机制?先搞懂这几个关键类!

不懂砍我之看完这篇还不明白Binder你砍我(二)

Binder中的代理模式

Binder系列7—framework层分析

Android源码代理模式---Binder

Android Bander设计与实现 - 设计篇

Android跨进程通信IPC之8——Binder驱动

Binder本地对象,实体对象,引用对象,代理对象的引用计数_jltxgcy的专栏-CSDN博客

为什么 Android 要采用 Binder 作为 IPC 机制?

Binder系列—开篇

Binder之ProcessState和IPCThreadState类分析_jiejingguo的博客-CSDN博客

ActivityManagerService简析 -

Proxy Stub

你可能感兴趣的:(Binder机制简单理解)