FrameWork-进程间通信之Binder机制,mmap原理

Android 进阶——Framework核心 之Binder Java成员类详解(三) Framework核心 之Binder Java成员类详解 阅读详情

进程间通信之Binder机制

  • Binder是什么?
  • 为什么要使用Binder?
  • Binder原理
  • Binder使用实战

1、Binder是什么

Binder 是一种进程间通信机制,基于开源的 OpenBinder 实现;OpenBinder 起初由 Be Inc. 开发,后由 Plam Inc. 接手。从字面上来解释 Binder 有胶水、粘合剂的意思,顾名思义就是粘和不同的进程,使之实现通信


2、为什么要使用Binder

各种进程间通信方式对比

传统Linux进程间通信方式:管道、信号量、socket、共享内存,而Binder是android系统独有的。

  • Binder:只需要拷贝一次,基于c/s架构,易用性高,系统为每个APP分配UID同时支持实名和匿名更安全
  • 共享内存:无需拷贝,控制复杂,易用性差,依赖上层协议,访问接入点是开放的不安全
  • Socket:需要拷贝两次,基于c/s架构,作为一款通用接口,其传输效率低,开销大,以来上层协议,访问接入点是开放的,不安全

Android系统需要一种高效率,安全性高的方式,也就是Binder,binder只需要拷贝一次,仅次于共享内存,而且采用传统的c/s结构


3.Binder实现机制

3.1 Linux系统关于内存的几个概念

首先需要明确Linux系统关于内存的几个概念:虚拟内存,用户空间,内核空间、MMap

  • 虚拟内存

虚拟内存简单来说,是一种内存管理技术,是虚拟的、逻辑上存在的存储空间;将物理上(不连续的物理)的内存(碎片)形成一个逻辑上连续完整的地址空间。虚拟内存初始化的过程,就叫做内存映射。实际原理请自行百度吧,当时学计算机原理的时候头秃了很久。

我们的用户程序操作的内存实际上都是通过虚拟内存操作真正的物理内存。详细可见我的另一篇帖子什么是虚拟内存?虚拟内存的原理

  • 用户空间、内核空间

虚拟内存被操作系统划分成两块:用户空间和内核空间,用户空间是用户程序代码运行的地方,内核空间是内核代码运行的地方。为了安全,他们是隔离的,即使用户的程序崩溃了,内核也不受影响。

32位系统,即2^32,即总共可以访问地址为4G.内核空间为1G,用户空间为3G;64位操作系统,低位2-47位是有效的可变地址,高位48-63位全补0对应用户空间,全补1是内核空间

  • MMap(Memory Mapping)内存映射

Linux通过将虚拟内存区域与磁盘上的空间关联起来,以初始化这个虚拟内存区域的内容,这个过程成为内存映射。具体一点来说,把一个文件或者其他对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间的映射关系。实现这种映射关系之后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写到对应的磁盘文件。

示意图如下:

在这里插入图片描述

用户空间(虚拟内存)和磁盘文件(物理内存)存在映射关系,这样在虚拟内存中操作文件,就会自动回写到磁盘文件中。

3.2 Binder驱动启动流程

Binder驱动启动流程主要有3个步骤:

  • binder_init()驱动启动

主要做3件事:

  • 为binder设备分配内存;
  • 然后初始化binder设备;
  • 最后把binder设备添加到设备链表里
  • binder_open()驱动打开
  • 创建binder_proc对象;
  • 当前进程信息保存到proc,这样proc就保存了当前进程信息
  • 把proc把proc添加到binder_proc链表中
  • binder_mmap()
  • 通过用户空间的虚拟内存大小分配一块内核的虚拟内存,这两个大小是一样的;
  • 分配一块物理内存–1页4kb;现在还没有通信,先分配这么多,用到的时候再分配;这块儿物理内存同样和虚拟内存的大小一样
  • 把这块物理内存分别映射到用户空间虚拟内存和内核空间虚拟内存;

如图所示:

在这里插入图片描述

注:intent传递数据大小是1MB-8kb,异步方式是一半。因为intent传递数据依靠binder,这个大小是binder驱动初始化的时候分配的

整个安卓Binder进程通信的内存映射机制就如下图所示:

在这里插入图片描述


4.Binder使用实战

4.1 在server端创建Service
class UserManagerService : Service() {
    private val mBinder =UserManagerBinder()
    override fun onCreate() {
        super.onCreate()
        Log.i(Companion.TAG, "onCreate: ")
    }

    override fun onBind(intent: Intent): IBinder {
        return mBinder
    }

    companion object {
        private const val TAG = "UserManagerService"
    }
}

然后把这个service注册到manifest

   <service
            android:name=".service.UserManagerService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.wilson.binder_server.action" />
            </intent-filter>
        </service>

注意exported要为true,否则不能由其他进程启动

4.2 在服务端java同级目录创建AIDL文件夹并编辑AIDL接口以及相关数据结构

在这里插入图片描述
注意图中框住的bean一定要同目录。

package com.wilson.binder_server.beans;

// Declare any non-default types here with import statements

parcelable UserInfo;

package com.wilson.binder_server;

// Declare any non-default types here with import statements
import com.wilson.binder_server.beans.UserInfo;

interface IUserManager {

    void addUser(inout UserInfo user);
    boolean removeUser(inout UserInfo user);
    UserInfo getUser(in String name);
}

注意形参前面有inout和in

  • 定向 tag in 表示数据只能由客户端流向服务端,服务端将会收到客户端对象的完整数据,但是客户端对象不会因为服务端对传参的修改而发生变动。
  • out 表示数据只能由服务端流向客户端。服务端将会收到客户端对象,该对象不为空,但是它里面的字段为空,但是在服务端对该对象作任何修改之后客户端的传参对象都会同步改动。
  • inout 则表示数据可以在服务端与客户端之间双向流通。其中的数据流向是针对在客户端中的那个传入方法的对象而言的。服务端将会接收到客户端传来对象的完整信息,并且客户端将会同步服务端对该对象的任何变动。

Javabean

public class UserInfo implements Parcelable {
    public String name;
    public int age;
    public int gender;

    public UserInfo(String name, int age, int gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public UserInfo() {
    }

    protected UserInfo(Parcel in) {
        name = in.readString();
        age = in.readInt();
        gender = in.readInt();
    }

    public static final Creator<UserInfo> CREATOR = new Creator<UserInfo>() {
        @Override
        public UserInfo createFromParcel(Parcel in) {
            return new UserInfo(in);
        }

        @Override
        public UserInfo[] newArray(int size) {
            return new UserInfo[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    public void readFromParcel(Parcel in) {
        name = in.readString();
        age = in.readInt();
        gender = in.readInt();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
        dest.writeInt(gender);
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                '}';
    }
}

这个bean就是AIDL中的bean所指向的类;
bean需要实现Parcelable接口,由于我一开始的bean使用的Kotlin 的data class,没有手动实现接口,而是使用@Parcelize注解,结果发现编译之后,找不到Parcelable的方法,懒得去解决只好老老实实实现接口了

4.3 把服务端aidl整个文件以及java/kotlin的bean同目录拷贝到client

在这里插入图片描述

4.5 编译并实现自定义Binder

编译后在client和service端同时生成一个类文件:

package com.wilson.binder_server;
public interface IUserManager extends android.os.IInterface
{
  /** Default implementation for IUserManager. */
  public static class Default implements com.wilson.binder_server.IUserManager
  {
    @Override public void addUser(com.wilson.binder_server.beans.UserInfo user) throws android.os.RemoteException
    {
    }
    @Override public boolean removeUser(com.wilson.binder_server.beans.UserInfo user) throws android.os.RemoteException
    {
      return false;
    }
    @Override public com.wilson.binder_server.beans.UserInfo getUser(java.lang.String name) throws android.os.RemoteException
    {
      return null;
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }

  /** Local-side IPC implementation stub class. 本地Binder需要实现/继承的接口*/
  public static abstract class Stub extends android.os.Binder implements com.wilson.binder_server.IUserManager
  {
    private static final java.lang.String DESCRIPTOR = "com.wilson.binder_server.IUserManager";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.wilson.binder_server.IUserManager interface,
     * generating a proxy if needed.
     */
    public static com.wilson.binder_server.IUserManager asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.wilson.binder_server.IUserManager))) {
        return ((com.wilson.binder_server.IUserManager)iin);
      }
      return new com.wilson.binder_server.IUserManager.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
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_addUser:
        {
          data.enforceInterface(descriptor);
          com.wilson.binder_server.beans.UserInfo _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.wilson.binder_server.beans.UserInfo.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.addUser(_arg0);
          reply.writeNoException();
          if ((_arg0!=null)) {
            reply.writeInt(1);
            _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
          }
          else {
            reply.writeInt(0);
          }
          return true;
        }
        case TRANSACTION_removeUser:
        {
          data.enforceInterface(descriptor);
          com.wilson.binder_server.beans.UserInfo _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.wilson.binder_server.beans.UserInfo.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          boolean _result = this.removeUser(_arg0);
          reply.writeNoException();
          reply.writeInt(((_result)?(1):(0)));
          if ((_arg0!=null)) {
            reply.writeInt(1);
            _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
          }
          else {
            reply.writeInt(0);
          }
          return true;
        }
        case TRANSACTION_getUser:
        {
          data.enforceInterface(descriptor);
          java.lang.String _arg0;
          _arg0 = data.readString();
          com.wilson.binder_server.beans.UserInfo _result = this.getUser(_arg0);
          reply.writeNoException();
          if ((_result!=null)) {
            reply.writeInt(1);
            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
          }
          else {
            reply.writeInt(0);
          }
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }


	//-----Binder代理类
    private static class Proxy implements com.wilson.binder_server.IUserManager
    {
      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 void addUser(com.wilson.binder_server.beans.UserInfo user) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((user!=null)) {
            _data.writeInt(1);
            user.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          boolean _status = mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addUser(user);
            return;
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            user.readFromParcel(_reply);
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public boolean removeUser(com.wilson.binder_server.beans.UserInfo user) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        boolean _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((user!=null)) {
            _data.writeInt(1);
            user.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          boolean _status = mRemote.transact(Stub.TRANSACTION_removeUser, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().removeUser(user);
          }
          _reply.readException();
          _result = (0!=_reply.readInt());
          if ((0!=_reply.readInt())) {
            user.readFromParcel(_reply);
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public com.wilson.binder_server.beans.UserInfo getUser(java.lang.String name) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        com.wilson.binder_server.beans.UserInfo _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeString(name);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getUser, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getUser(name);
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            _result = com.wilson.binder_server.beans.UserInfo.CREATOR.createFromParcel(_reply);
          }
          else {
            _result = null;
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      public static com.wilson.binder_server.IUserManager sDefaultImpl;
    }
    static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_removeUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_getUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    public static boolean setDefaultImpl(com.wilson.binder_server.IUserManager impl) {
      // Only one user of this interface can use this function
      // at a time. This is a heuristic to detect if two different
      // users in the same process use this function.
      if (Stub.Proxy.sDefaultImpl != null) {
        throw new IllegalStateException("setDefaultImpl() called twice");
      }
      if (impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.wilson.binder_server.IUserManager getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  public void addUser(com.wilson.binder_server.beans.UserInfo user) throws android.os.RemoteException;
  public boolean removeUser(com.wilson.binder_server.beans.UserInfo user) throws android.os.RemoteException;
  public com.wilson.binder_server.beans.UserInfo getUser(java.lang.String name) throws android.os.RemoteException;
}

这个类的原理下面说。

  • 然后在service端实现我们自己的Binder
class UserManagerBinder : IUserManager.Stub() {
    private val mUserManager by lazy { UserManager.getInstance() }

    init {
        Log.i(TAG, ": UserManagerBinder init ")
    }

    companion object {
        private const val GET_USER = Binder.FIRST_CALL_TRANSACTION + 1
        const val ADD_USER = GET_USER + 1
        private const val TAG = "UserManagerBinder"
    }

    override fun addUser(user: UserInfo?) {
        user?.let {
            mUserManager.addUser(user)
        }
    }

    override fun removeUser(user: UserInfo?): Boolean {
        user?.let { return mUserManager.removeUser(user) }
        return false
    }

    override fun getUser(name: String?): UserInfo {
        return mUserManager.getUser(name) ?: UserInfo()
    }

}

这个类需要继承我们IUserMnager的内部类Stub

然后在服务端的自定义Service里使用该Binder:

	private val mBinder =UserManagerBinder()
	override fun onBind(intent: Intent): IBinder {
        return mBinder
    }

4.6 编写Client端
class MainActivity : AppCompatActivity() {

    private var mUserManagerBinder: IUserManager? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //绑定服务
        findViewById<TextView>(R.id.tv_main).setOnClickListener {
            val serviceIntent = Intent().apply {
                setPackage("com.wilson.binder_server")
                action = "com.wilson.binder_server.action"
            }
            val success = bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE)
            Log.i(TAG, "bindService success=$success")
        }
		//向服务端发送数据
        findViewById<View>(R.id.btn_add_user).setOnClickListener {
            mUserManagerBinder?.addUser(UserInfo("wilson", 18, 1))
        }
        //从服务端获取数据
        findViewById<View>(R.id.btn_get_user).setOnClickListener {

            mUserManagerBinder?.getUser("wilson")?.let {
                Log.i(TAG, "get_user: user = [$it] ")
            }
        }

    }

	//链接回调
    private val mServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            service?.let {
                mUserManagerBinder = IUserManager.Stub.asInterface(service)
            }
            Log.i(Companion.TAG, "onServiceConnected: ")
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            mUserManagerBinder = null
            Log.i(Companion.TAG, "onServiceDisconnected: ")
        }

    }

    companion object {
        private const val TAG = "MainActivity"
    }
}

绑定服务有显式和隐式两种,参考我的另一篇帖子服务的启动方式。

需要注意,bindService返回结果并非绑定成功与否,它表示服务端是否存在,真正的绑定成功是ServiceConnection回调 onServiceConnected

代码一切完成,在client调用绑定方法,addUser和getUser方法:
在这里插入图片描述
所有代码已上传Github

4.7 AIDL编译生成的类解析

IUserManager 主要分为3部分

  • IUserManager接口定义
    这个就是我们实际需要调用的方法;
  • IUserManager.Stub内部类
    这个类继承了Binder同时实现了我们的IUserManager接口。这个类是client和service真正数据传递的的实现。

我们在client中,servieConnected方法中调用Stub.asInterface开始看:

  public static com.wilson.binder_server.IUserManager asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.wilson.binder_server.IUserManager))) {
        return ((com.wilson.binder_server.IUserManager)iin);
      }
      return new com.wilson.binder_server.IUserManager.Stub.Proxy(obj);
    }

这里的代码很简单,初次最终到最后一行,返回一个Proxy实例,并注入服务端Binder

Proxy是Stub的内部类,他们实现了相同的IUserManager接口,可以看到内部声明了一个变量mRemote就是通过构造器注入的服务端的Binder,它就是服务端Binder的代理。它的主要作用是向服务端传递数据和接收服务端传递过来的数据。

以addUser为例:

@Override public void addUser(com.wilson.binder_server.beans.UserInfo user) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((user!=null)) {
            _data.writeInt(1);
            user.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          //调用服务端Binder
          boolean _status = mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addUser(user);
            return;
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            user.readFromParcel(_reply);
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }

这里把我们的业务数据序列化之后,调用mRemote.transact传递我们的数据达到代理的目的。为什么要代理呢,因为数据序列化反序列化模板类代码实现麻烦,聪明的设计师帮我们实现。

以上是针对于client端的原理,下面是service端。

上述说的服务端的Binder就是在server端我们自定义service中的onBind中我们返回了自定义的Binder实例。而我们的自定义Binder继承了Stub,我们聚焦与Stub。

Stub同样实现了IUserManager,在onTransact实现根据不同的方法标识,执行对应的数据处理,反序列化接口或者序列化返回数据。


这篇文章讲的有点乱,条理不够清晰,各位大佬将就着看吧,如果有问题,麻烦指正哈。
我要出门做核酸去了,哈哈哈哈哈

所有代码已上传Github

Android 进程通讯机制之Binder(信使)架构以及内存映射详解 由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!由于整个文档比较全面,内容比较多,篇幅不允许,下面以截图方式展示。本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长! 阅读详情

相关推荐

进程间通信机制 Binder原理讲解笔记

在拆解分析Binder之前先上一张Binder架构图,总体对Binder有一个整体了解:Binder跨进程通信机制:基于C/S架构,由Client、Server、Server Manager和Binder驱动组成。下面的介绍我们主要也是从这几个方面进行分析。一直在说Binder,那么Binder到底是什么东西呢?概括来说Binder:跨Android进程通信的机制Binder是一个驱动Binder.java实现了IBinder接口从而具备了跨进程的能力。

DonnyCoy 692

Android mmap+Binder机制

1.Binder ①Binder是什么? 机制:Binder是一种进程间通信的机制 驱动:Binder是一个虚拟物理设备驱动 应用层:Binder是一个能发起进程间通信的JAVA类 Binder就是Android中的血管,在Android中使用Activity、Service等组件时都需要和AMS(system_server)进行通信,这种跨进程的通信都是通过Binder完成。 Activity、Service等组件和AMS不是同一个进程,其实也是多进程通信。 ②为什么要用多进程? 虚拟机给

zenmela2011的专栏 3306

Android Framework学习六:Binder原理

Binder是Android系统中的一种进程间通信(IPC)机制,涵盖机制、应用和驱动三个层面。在机制层面,Binder提供标准化的通信方式,支持不同进程间的数据交换和方法调用。在应用层面,开发者可通过继承Binder类实现自定义的跨进程通信逻辑。在驱动层面,Binder作为虚拟物理设备驱动,负责管理内存映射、线程管理等底层操作。Binder通信过程中,数据通过Binder驱动在内核态和用户态之间传递,客户端通过copy_from_user将数据拷贝到内核空间,服务端通过mmap直接访问内核空间。每个APP

zmlovelx(帅得不敢出门 程序员群31843264) 1647

【Android】Binder(二)内存划分和Binder实现一次拷贝

内存划分和Binder实现一次拷贝

每天不是在写bug就是在写bug的路上 1802

图解Android中的binder机制

一个进程是不能直接直接操作另一个进程的,比如说读取另一个进程的数据,或者往另一个进程的内存空间写数据,进程之间的通信要通过内核进程才可以,因此这里就要使用到进程通信工具Binder了如下图:Binder driver通过/dev/binder /dev/binder 提供了 open, release release, poll poll, mmap mmap, flush flush, and ioctl等操作的接口api。这样进程A和进程B就可以通过内核进程进行通信了。

2401_84123005的博客 1098

征服面试官系列: Binder 核心机制和进程间通信,你都理解了吗?

说起Android的进程间通信,想必大家都会不约而同的想起Android中的Binder机制。而提起Binder,想必也有不少同学会想起初学Android时被Binder和AIDL支配的恐惧感。但是作为一个Android开发者,Binder是我们必须掌握的知识。因为它是构架整个Android大厦的钢筋和混凝土,连接了Android各个系统服务和上层应用。 只有了解了Binder机制才能更加深入的理解Android开发和Android Framework。这也是为什么无论是《Android开发艺术探索》还

A_pyf的博客 505

图解Android中的Binder机制

前言 Binder做为Android中核心机制,对于理解Android系统是必不可少的,关于binder的文章也有很多,但是每次看总感觉看的不是很懂,到底什么才是binder机制?为什么要使用binder机制?binder机制又是怎样运行的呢?这些问题只是了解binder机制是不够的,需要从Android的整体系统出发来分析,在我找了很多资料后,真正的弄懂了binder机制,相信看完这篇文章大家也...

有图有真相 2万+

Android Framework -- Binder

Binder通信篇Binder的通信部分其实很简单,但源码中的业务封装太过复杂使得Binder看起来很复杂。抛开业务封装看下Binder通讯原理。ServiceManager就抛开了Binder的业务封装,直接使用它的通信功能。首先我们知道,逻辑地址空间有4G,其中3G为用户空间,1G为内核空间;我们的应用进程都在用户空间中且相互隔绝无法直接互相访问。于是乎有了进程间通信的需求。Android基于L

瑜艾 570

【Android Framework系列】第2章 Binder机制大全

Binder是Android中主要的跨进程通信方式,整个Android系统架构中,大量采用了Binder机制作为IPC(进程间通信)方案。只需要拷贝一次,基于C/S架构,易用性高,系统为每个APP分配UID同时支持实名和匿名更安全

Yvan 5204

【KO】Android Framework

这些解答覆盖了 Android Framework 核心机制(Binder、Handler、AMS 等 ),实际面试中需结合代码示例、原理细节灵活阐述,突出对 Android 底层的理解。

abbiz的博客 767

高项49个过程,输入、工具技术、输出的思维导图

为了制定项目章程的管理方法主要是采用了数据收集技术,例如通过头脑风暴,通过召集主题专家和团队成员收集信息、解决方案,并在短时间内获得大量创意,并对大量创意进行分析和排序,选出最优化最适合本项目方案,并对项目成员的不同差异观点,进行了引导和对冲突的管理,最终有助于项目干系人的目标、成功标准的内容达成一致意见,形成完善的项目章程。在本过程中得到项目章程,在制定项目章程中需要包括信息有:项目名称、项目目标、项目总里程碑进度表、项目经理、主要干系人及财务预算信息。本过程在仅开展一次,或仅在项目的预定义点开展。

Legend_Jiang的博客 6182

Android FrameWork ---- Binder驱动源码分析

Binder机制以及Binder驱动源码分析

qq_33235287的博客 2513

kettle信息发送钉钉

由于其他的作业比较多,想要在job中加入一个转化发送消息到钉钉,其他的配置说明直接获取系统的信息。这样也避免直接修改其他的转换和大量的工作量。 步骤: 1、新建一个转换 拉取获取系统信息、获取变量、JavaScript代码、获取access_token组件。 2、获取系统信息设置 拿到需要的信息,比如作业的读写更新删除行数,job的日志内容 这个日志内容同在作业执行页面下输出的日志,所以可以在执行作业时选择是详细日志、基本日志还是错误日志。 3、获取变量 获取变量主要是想要去拿到job的名称,文件名。按

Deng_7788的博客 1448

硬货:图解Android中的binder机制

前言 Binder做为Android中核心机制,对于理解Android系统是必不可少的,关于binder的文章也有很多,但是每次看总感觉看的不是很懂,到底什么才是binde...

Android技术之家 379

水电站数字孪生:水力发电在可视化领域的应用

为智慧水坝领域提供了 B/S 架构的基于 WebGL 的图形引擎,与 GIS、粒子仿真、虚拟现实、边缘计算等技术相结合,融合多元业务系统数据,形成数字孪生界面,助力水利水电工程进一步提升数字化水平,乃至为整个工业领域添砖加瓦。

二三维数据可视化/数字孪生 2255

2026从0到1!C#工控机开发实战指南:新手一周就能跑通的完整项目

这篇文章摘要如下: 工业自动化领域工控机开发入门指南,针对零基础开发者提供从环境搭建到项目实战的全流程指导。文章首先解答工控机开发的3个核心问题,比较工控机与普通PC的区别,推荐使用C#作为开发语言。随后详细讲解开发环境配置、四大核心技术栈(通信协议、数据库、UI框架、多线程),并重点演示Modbus TCP通信的实现。最后通过一个完整的温度监控系统项目实战,展示如何用WPF构建实时数据采集界面,包括Modbus通信类编写、数据采集服务实现等关键代码片段。全文采用图解+代码的方式,帮助开发者快速掌握工控系统

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 704

Android Framework通信:Binder

对Binder跨进程通信的原理,予以记录!Binder 原理剖析与使用——西门吹雪Binder 是一种进程间通信机制,基于开源的 OpenBinder 实现;OpenBinder 起初由 Be Inc. 开发,后由 Plam Inc. 接手。从进程间通信的角度看,Binder 是一种进程间通信的机制;从 Server 进程的角度看,Binder 指的是 Server 中的 Binder 实体对象;

qq_43357394的博客 635

手把手教你学PCIE(2.1.8)--pcie基本概念流量控制(Flow Control, FC)

PCIe 的流量控制(Flow Control, FC)是确保数据传输可靠性和高效性的关键技术。通过信用值管理,发送方和接收方可以动态调整数据传输速率,避免数据丢失和溢出。理解流量控制的工作原理和实现机制对于开发和调试 PCIe 系统非常重要。希望这个介绍能帮助你更好地理解和使用 PCIe 流量控制。

MHD0815的博客 1808

助攻面试:图解Android Binder机制

码个蛋(codeegg) 第 936次推文作者:Hanking链接:https://juejin.im/post/5e89f717f265da47e6491496前言Binder做为A...

陈宇明 190

YOLO系列算法改进 | C3k2改进篇 | 融合DEConv细节增强卷积模块 | 细节增强+多分支差分卷积融合,标准卷积的完美涨点替代! | TIP 2024

YOLO系列算法改进 | C3k2改进篇 | 融合DEConv细节增强卷积模块 | 细节增强+多分支差分卷积融合,标准卷积的完美涨点替代! | TIP 2024 (以YOLO26最新目标检测模型为基础,融合C3k2_DEConv创新模块进行改进)

2502_91881744的博客 310

“华为杯”研究生数学建模竞赛2019年-【华为杯】D题:汽车行驶工况构建(附获奖论文和MATLAB代码实现)

映了汽车道路行驶的运动学特征。准差、加速度标准差这九个特征参数用于后续的数据分析,建立了合理的汽车运动特征评。特征参数与所属类特征参数的特征值的相关性大小替代误差进行排序的,计算得到汽车行。对于问题一,我们首先对原始数据进行了时间变量转换,将原本的年月日时分秒的计。紧接着进行了运动学片段的划分,引入九个特征参数,通过主成分分析、本文研究的是汽车行驶工况构建,汽车行驶工况是描述汽车行驶的速度。的合理性评价标准,对两种方法都进行了合理性评价,得到的。进行了合理性评价,得到了最优的汽车行驶工况曲线。

getusushu的博客 1003

5 分钟跑通本地 SWF 播放:Ruffle 桌面版 Flash 播放器上手指南

Flash Player 退役多年,你手里的 .swf 老游戏和课件点开只剩白屏。Ruffle 桌面版用 Rust 重写了整套 Flash 播放内核,SWF 里的动画、声音与 ActionScript 1/2 脚本都能直接执行,本地路径和网络地址都支持。装好拖入文件,5 分钟内画面就能跑起来。 ## 三类人群对号入座:谁该用 Ruffle 打开 SWF 如果你正处在以下情况之一,这个工具就是为

gitblog_01122的博客 363

【Clickhouse】Clickhouse写入报错keeper server rejected the connection during the handshake

我的clickhouse集群时不时的报这个错误All connection tries failed while connecting to ZooKeeper. nodes: xxx 到时写入数据失败 用的ck自带的keeper。你需要仔细检查ZooKeeper集群的配置和状态,确保所有节点都正常运行,并且能够正确地选举领导者。检查ZooKeeper的ACL以及ClickHouse连接所使用的凭据,确保它们被正确配置和授权。版本不兼容:有时,不同版本的软件之间可能存在不兼容性,导致连接问题。

九师兄 373

探索Android Framework底层:Handler和Binder

以前学习Android的时候,有时候想研究源码,研究Android底层原理,只能去翻书,或者向其他公司的大牛请教,一个疑问可能会卡好几天。那时候只要了解四大组件、视图、网络请求,你就能拿...

郭霖 682

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

【Android Framework】 Android Binder 机制解析

http://blog.youkuaiyun.com/dkbdkbdkb/article/details/47447159

Jon.Lo 的专栏 664

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Android-Framework:Binder全解析,实现原理分析

共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存 套接字 套接字是更为基础的进程间通信机制,与其他方式不同的是,套接字可用于不同机器之间的进程间通信。 Linux上IPC原理 首先我们需要理解**User space(用户空间)**和 Kernel space(内核空间)。 为了保护用户进程不能直接操作内核,保证内核的安全,操作系统从逻辑上将虚拟空间划分为用..

m0_61418377的博客 382

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

上一篇: Android性能优化(二)--CPU和内存优化工具及方法
下一篇: StartActivity原理(一)——Android9.0 Activity启动原理, pauseActivity原理
cry kid
博客等级 码龄10年 144粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值