Binder进程间通信示例 (一)

本文深入探讨了Android的跨进程通信(IPC)机制,重点介绍了Binder机制的优势与工作原理,包括其在C/S架构中的应用,以及如何通过AIDL实现跨进程的数据交换和事件监听。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IPC(Inter-Process Communication) 跨进程通信

本节主要是熟悉Android IPC中的AIDL实现方式

导读: IPC -> Binder -> 示例 未包含对aidl创建规则的讲解,可以查看

一、任何一个操作系统都有对应的IPC机制

  1. windows : 通过剪切版、管道、油槽(windows中最简单的一种进程间通信)等进行通信

  2. Linux : 通过命名管道、共享内存、信号量(本质可以理解为数据操作锁) 等进行通信

  3. Android : 并不是完全继承自Linux,通信方式一般优选Binder、Socket等等

二、Android Binder机制

  1. Android的进程架构(每个Android进程都是独立的,由用户空间和内核空间组成)

    模型

    设计优点:

    • 稳定性、安全性高:每一个Android进程都拥有自己独立的虚拟地址空间,一方面可以限制其它进程访问自己的虚拟地址空间,另一方面,当一个进程崩溃时不至于牵连其它的进程

    • 便于复用与管理:内核共享有助于系统维护和并发操作、节省空间

  2. Binder机制优点

    • 传输效率高、可操作性强

      • 对于消息队列、Socket和管道而言,数据先从发送方的缓存区拷贝到内核开辟的缓存区中,再从内核缓存区拷贝到接收方的缓存区,一共拷贝两次

      • 对于Binder来说,数据从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到一块物理地址的

    • 实现C/S架构方便

      • Client和Server端相对独立、很稳定

    • 安全性高

      • Binder机制为每个进程分配了UID/PID,且在Binder通信时会根据UID/PID进行检测

  3. Binder定义了四个角色:Server、Client、ServiceManager和Binder驱动

    • 其中Server、Client、ServiceManager运行于用户空间,Binder驱动运行于内核空间

    • ServiceManager工作流程 : Service在ServiceManager注册,然后Client通过Binder名字获取Binder实体引用或代理类

    • Binder驱动

      • 与硬件设备没有关系,工作于内核态

      • 提供open()、mmap()、poll()、ioctl()等标准文件操作

      • 负责进程之间binder通信的建立、传递、计数管理以及数据的传递交互等底层支持

      • 驱动和应用程序之间定义了一套接口协议,主要功能由ioctl()接口实现

      • 代码位于linux目录的drivers/misc/binder.c中

  4. Binder工作原理

    • transact方法和onTransact方法,可以通过自己编写aidl文件,然后ReBuild一下,然后去查看具体aidl生成的java源码,如接下来的IBookManagerService中的IBookManager类文件

三、 实现Binder进程通信,以书为例子,实现C端查看S端书籍,S端书籍增加时通知C端

通过AS新建AIDL文件会自动生成aidl文件夹,这里需要注意包名,尽量将所有aidl相关放在同一个包内

这里需要需要注意对象的跨进程传输实际是反序列化操作,具体代码内会标准,所以如果想要实现监听事件,通知Client,需要使用到Android自带的RemoteCallbackList类,毕竟跨进程传输底层的Binder对象是同一个

注意耗时操作,Server端操作的方法都是在服务端Binder线程池中,非UI线程,而onServiceConnected和onServiceDisconnected都是在UI线程中

  • Book.java

    package aidldemo;
    public class Book implements Parcelable {
        public int bookId;
        public String bookName;
    ​
        public Book(int bookId,String bookName){
            this.bookId = bookId;
            this.bookName = bookName;
        }
        protected Book(Parcel in) {
            bookId = in.readInt();
            bookName = in.readString();
        }
    ​
        public static final Creator<Book> CREATOR = new Creator<Book>() {
            @Override
            public Book createFromParcel(Parcel in) {
                return new Book(in);
            }
    ​
            @Override
            public Book[] newArray(int size) {
                return new Book[size];
            }
        };
    ​
        @Override
        public int describeContents() {
            return 0;
        }
    ​
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(bookId);
            dest.writeString(bookName);
        }
    ​
        @Override
        public String toString() {
            return "Book{" +
                    "bookId=" + bookId +
                    ", bookName='" + bookName + '\'' +
                    '}';
        }
    }
  • Book.aidl

    package aidldemo;
    parcelable Book;
  • IBookManager.aidl

    package aidldemo;
    ​
    // Declare any non-default types here with import statements
    import aidldemo.Book;
    import aidldemo.IOnNewArrivedListener;
    interface IBookManager {
        List<Book> getBookList();
        void addBook(in Book book);
        //注册监听,主要是通知Client,更新书籍了
        void registerListener(IOnNewArrivedListener listener);
        void unRegisterListener(IOnNewArrivedListener listener);
    }
  • IOnNewArrivedListener.aidl

    import aidldemo.Book;
    //监听
    interface IOnNewArrivedListener{
    void onNewBookArrived(in Book newBook);
    }
  • BookManagerService.java Server端

    public class BookManagerService extends Service {
        private static final String TAG = "XXXXXXXX";
        private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
        private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);
        //private CopyOnWriteArrayList<IOnNewArrivedListener> mListener = new CopyOnWriteArrayList<>();
        private RemoteCallbackList<IOnNewArrivedListener> mListener = new RemoteCallbackList<>();
        private Binder mBind = new IBookManager.Stub() {
            @Override
            public List<Book> getBookList() throws RemoteException {
                return mBookList;
            }
    ​
            @Override
            public void addBook(Book book) throws RemoteException {
                mBookList.add(book);
            }
    ​
            @Override
            public void registerListener(IOnNewArrivedListener listener) throws RemoteException {
                mListener.register(listener);
                Log.d(TAG," BMS registerListener");
            }
    ​
            @Override
            public void unRegisterListener(IOnNewArrivedListener listener) throws RemoteException {
                mListener.unregister(listener);
                Log.d(TAG,"BMS unRegisterListener");
            }
        };
    ​
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return mBind;
        }
    ​
        @Override
        public void onCreate() {
            super.onCreate();
            mBookList.add(new Book(1, "Android"));
            mBookList.add(new Book(2, "IOS"));
            new Thread(new ServiceWork()).start();
        }
    ​
        @Override
        public void onDestroy() {
            mIsServiceDestoryed.set(true);
            super.onDestroy();
        }
    ​
        private void onNewBookArrived(Book book) throws RemoteException {
            mBookList.add(book);
            final int N = mListener.beginBroadcast();//和finishBroadcast成对出现,否则出错
            for (int i = 0; i < N; ++i) {
                Log.d(TAG, "BMS OnNewBookArrived,notify listeners : "+i);
                IOnNewArrivedListener l = mListener.getBroadcastItem(i);
                if (l != null) {
                    l.onNewBookArrived(book);
                }
            }
            mListener.finishBroadcast();
        }
    ​
        private class ServiceWork implements Runnable {
            @Override
            public void run() {
                while (!mIsServiceDestoryed.get()) {
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    int bookId = mBookList.size() + 1;
                    Book newBook = new Book(bookId, "new Book#" + bookId);
                    try {
                        onNewBookArrived(newBook);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
  • MainActivity.java Client端

    public class MainActivity extends AppCompatActivity {
    ​
        private static final String TAG = "XXXXXXXX";
        private static final int MESSAGE_NEW_BOOK_ARRIVED = 1;
        private IBookManager mRemoteBookManager;
        @SuppressLint("HandlerLeak")
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MESSAGE_NEW_BOOK_ARRIVED:
                        Log.d(TAG, "Client receive new book : " + msg.obj.toString());
                        break;
                    default:
                        super.handleMessage(msg);
                }
            }
        };
    ​
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Intent intent = new Intent(this, BookManagerService.class);
            bindService(intent, conn, Context.BIND_AUTO_CREATE);
        }
        //这个listener是运行在客户端的Binder线程池里,操作UI需要注意
        private IOnNewArrivedListener mBookArrivedListener = new IOnNewArrivedListener.Stub() {
            @Override
            public void onNewBookArrived(Book newBook) throws RemoteException {
                mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, newBook).sendToTarget();
            }
        };
        private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //UI线程
                IBookManager bookManager = IBookManager.Stub.asInterface(service);
                try {
                    mRemoteBookManager = bookManager;
                    List<Book> list = bookManager.getBookList();
                    Log.d(TAG, "Client  query book list ,list type : " + list.getClass().getCanonicalName());
                    Log.d(TAG, list.toString());
                    bookManager.registerListener(mBookArrivedListener);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    ​
            @Override
            public void onServiceDisconnected(ComponentName name) {
    ​
            }
        };
    ​
        @Override
        protected void onDestroy() {
            if(mRemoteBookManager != null && mRemoteBookManager.asBinder().isBinderAlive()){
                try {
                    mRemoteBookManager.unRegisterListener(mBookArrivedListener);
                    Log.d(TAG,"Client unRegisterListener");
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            unbindService(conn);
            super.onDestroy();
        }
    }

四、注意在注册Service时,清单文件里process属性,要不然不是进程间通信。最后运行完事。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值