美文网首页
Binder机制简单理解

Binder机制简单理解

作者: 梧叶已秋声 | 来源:发表于2021-07-04 20:45 被阅读0次

    写在开头:本文为读书笔记。
    本篇大部分文字来自《深入理解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<String16> 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<String16> args;
                for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
                   args.add(data.readString16());
                }
                sp<IShellCallback> shellCallback = IShellCallback::asInterface(
                        data.readStrongBinder());
                sp<IResultReceiver> 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 <code>null</code> 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<Callbacks> 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<StatusBarIconHolder> 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<StatusBarManager>() {
                @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机制简单理解

          本文链接:https://www.haomeiwen.com/subject/lcebyltx.html