• Android-Binder 简析


    前言

    对于Android来说,Binder的重要性怎么说都不为过。不管是我们的四大组件Activity、Service、BroadcastReceiver、ContentProvider,还是经常在应用中使用到的各种ServiceManager,其背后都是Binder在支撑。然而Binder机制又不是三言两语能够描述得清楚的,因此本文通过对一个简单的AIDL Demo进行分析,让读者对Binder有个初步的认识,要想深入了解Binder背后的原理,可以参考最后的延伸阅读。

    Demo

    首先我们通过AIDL新建一个跨进程通信的Demo,然后在代码中简单分析Binder的运行过程。

    Server Module

    我们先新建一个提供接口的AIDL服务端module,服务端主要提供AddBook和getBookList两个功能,其目录如下:

    p2.png

    p2.png

    • IBookManager.AIDL

    // IAIDLServer.aidl
    package com.nancyyihao.aidlserver;
    import  com.nancyyihao.aidlserver.Book;
    
    // Declare any non-default types here with import statements
    
    interface IBookManager {
        List<Book> getBookList();
        void addBook(in Book book);
    }
    
    • Book.java

    package com.nancyyihao.aidlserver;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    /**
     * Created by jumper on 2016/9/7.
     */
    public class Book implements Parcelable {
        private String bookName;
        private int bookId;
    
        public Book(){}
    
        public Book(int bookId, String bookName){
            this.bookId = bookId ;
            this.bookName = bookName ;
        }
    
        public Book(Parcel parcel){
            bookName = parcel.readString();
            bookId = parcel.readInt();
        }
    
        public String getBookName() {
            return bookName;
        }
    
        public void setBookName(String bookName) {
            this.bookName = bookName;
        }
    
        public int getBookId() {
            return bookId;
        }
    
        public void setBookId(int bookId) {
            this.bookId = bookId;
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(bookName);
            dest.writeInt(bookId);
        }
    
        public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){
    
            @Override
            public Book createFromParcel(Parcel source) {
                return new Book(source);
            }
    
            @Override
            public Book[] newArray(int size) {
                return new Book[size];
            }
    
        };
    }
    
    • Book.AIDL

    package com.nancyyihao.aidlserver;
    parcelable Book;
    
    • BookManagerService

    package com.nancyyihao.aidlserver;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    import android.os.RemoteException;
    
    import java.util.List;
    import java.util.concurrent.CopyOnWriteArrayList;
    
    /**
     * Created by jumper on 2016/9/7.
     */
    public class BookManagerService extends Service {
    
        private static final String TAG = "BMS";
        private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            // to distinguish with client module, we set the book id different from client module
            mBookList.add(new Book(3,"Android"));
            mBookList.add(new Book(4,"iOS"));
        }
    
        private Binder mBinder = new IBookManager.Stub() {
    
            @Override
            public List<Book> getBookList() throws RemoteException {
                return mBookList;
            }
    
            @Override
            public void addBook(Book book) throws RemoteException {
                mBookList.add(book);
            }
        } ;
    }
    

    Client Module

    把Server module的代码拷贝一份(AIDL包名不能变),然后新建一个MainActivity即可

    • MainActivity

    package com.nancyyihao.aidlserver;
    
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    
    import com.nancyyihao.R;
    
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity";
        private ServiceConnection mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                IBookManager bookManager = IBookManager.Stub.asInterface(service);
                Log.e("trace", "onServiceConnected");
                try {
                    List<Book> bookList = bookManager.getBookList();
                    Log.e(TAG, "query book list, list type:" + bookList.getClass().getCanonicalName());
                    Log.e(TAG, "query book list:" + bookList.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            final Intent intent = new Intent();
            intent.setAction("com.nancyyihao.startservice");
            intent.setPackage("com.nancyyihao.aidlserver"); // server's package name
            Log.e("trace", "bindService");
            bindService(intent, mConnection, BIND_AUTO_CREATE);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unbindService(mConnection);
        }
    }
    

    分析

    把代码写好后,build一下,就能看到自动生成了一个IBookManager.Java文件

    • IBookManager.Java

    p3.png

    p3.png

    package com.nancyyihao.aidlserver;
    // Declare any non-default types here with import statements
    
    public interface IBookManager extends android.os.IInterface {
        /**
         * Local-side IPC implementation stub class.
         */
        public static abstract class Stub extends android.os.Binder implements com.nancyyihao.aidlserver.IBookManager {
            private static final java.lang.String DESCRIPTOR = "com.nancyyihao.aidlserver.IBookManager"; // Binder Indentifier
    
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            /**
             * Cast an IBinder object into an com.nancyyihao.aidlserver.IBookManager interface,
             * generating a proxy if needed.
             */
            public static com.nancyyihao.aidlserver.IBookManager asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.nancyyihao.aidlserver.IBookManager))) {
                    return ((com.nancyyihao.aidlserver.IBookManager) iin);  // local Binder
                }
                return new com.nancyyihao.aidlserver.IBookManager.Stub.Proxy(obj);  // remote Binder
            }
    
            @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_getBookList: {
                        data.enforceInterface(DESCRIPTOR);
                        java.util.List<com.nancyyihao.aidlserver.Book> _result = this.getBookList();
                        reply.writeNoException();
                        reply.writeTypedList(_result);
                        return true;
                    }
                    case TRANSACTION_addBook: {
                        data.enforceInterface(DESCRIPTOR);
                        com.nancyyihao.aidlserver.Book _arg0;
                        if ((0 != data.readInt())) {
                            _arg0 = com.nancyyihao.aidlserver.Book.CREATOR.createFromParcel(data);
                        } else {
                            _arg0 = null;
                        }
                        this.addBook(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    
            private static class Proxy implements com.nancyyihao.aidlserver.IBookManager {
                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 java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    java.util.List<com.nancyyihao.aidlserver.Book> _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.createTypedArrayList(com.nancyyihao.aidlserver.Book.CREATOR);
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    
                @Override
                public void addBook(com.nancyyihao.aidlserver.Book book) 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 ((book != null)) {
                            _data.writeInt(1);
                            book.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                        mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
            }
    
            static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
    
        public java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException;
    
        public void addBook(com.nancyyihao.aidlserver.Book book) throws android.os.RemoteException;
    }
    
    

    Client先调用bindService启动服务,会调用BookManagerService的onCreate方法,接着调用onBind方法,该方法会返回远程的Binder---mBinder,该Binder包含getBookList和AddBook两个方法的具体实现。

        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
         private Binder mBinder = new IBookManager.Stub() {
    
            @Override
            public List<Book> getBookList() throws RemoteException {
                return mBookList;
            }
    
            @Override
            public void addBook(Book book) throws RemoteException {
                mBookList.add(book);
            }
        } ;
    

    当Client和server成功建立连接时,就会调用Client的onServiceConnected(name, service)方法把远程的mBinder回调给Client,此时的service就是远程的mBinder对象

    private ServiceConnection mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                IBookManager bookManager = IBookManager.Stub.asInterface(service);
                Log.e("trace", "onServiceConnected");
                try {
                    List<Book> bookList = bookManager.getBookList();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    

    Client端通过asInterface方法把mBinder转成AIDL接口,如果是本进程内的Binder就直接返回,否则返回内部代理类proxy

     public static com.nancyyihao.aidlserver.IBookManager asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.nancyyihao.aidlserver.IBookManager))) {
                    return ((com.nancyyihao.aidlserver.IBookManager) iin);  // local Binder
                }
                return new com.nancyyihao.aidlserver.IBookManager.Stub.Proxy(obj);  // remote Binder
            }
    

    接着执行

     try {
                    List<Book> bookList = bookManager.getBookList();
                } catch (Exception e) {
                    e.printStackTrace();
                }
    

    此时的bookManager通过asInterface方法转换后,返回的实际上是本地的proxy类

    private static class Proxy implements com.nancyyihao.aidlserver.IBookManager {
                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 java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    java.util.List<com.nancyyihao.aidlserver.Book> _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.createTypedArrayList(com.nancyyihao.aidlserver.Book.CREATOR);
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    
                @Override
                public void addBook(com.nancyyihao.aidlserver.Book book) 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 ((book != null)) {
                            _data.writeInt(1);
                            book.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                        mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
            }
            static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
    

    通过代码我们可以看到proxy类其实也是一个IBookManager接口,调用bookManager.getBookList()其实是调用Proxy.getBookList

     @Override
                public java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    java.util.List<com.nancyyihao.aidlserver.Book> _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.createTypedArrayList(com.nancyyihao.aidlserver.Book.CREATOR);
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    

    Proxy.getBookList方法中调用了mRemote.trasact()

        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);
            if (reply != null) {
                reply.setDataPosition(0);
            }
            return r;
        }
    

    Client就是在这里和Server进行远程通信的!把需要的参数放data中,服务端执行完后把接口写到result里。从代码中可以看到transact方法中调用了onTransact方法。我们再看看onTransact方法有啥东西。

      @Override
            public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
               ......
                    case TRANSACTION_getBookList: {
                        data.enforceInterface(DESCRIPTOR);
                        java.util.List<com.nancyyihao.aidlserver.Book> _result = this.getBookList();
                        reply.writeNoException();
                        reply.writeTypedList(_result);
                        return true;
                    }
                  ......
            }
    

    直接调用了this.getBookList方法返回结果,这个this到底是哪个对象?前面提到mRemote其实是远程中的Binder对象,其代码如下

     private Binder mBinder = new IBookManager.Stub() {
    
            @Override
            public List<Book> getBookList() throws RemoteException {
                return mBookList;
            }
    
            @Override
            public void addBook(Book book) throws RemoteException {
                mBookList.add(book);
            }
        } ;
    

    this.getBookList其实就是mRemote.getBookList,就是上面代码中的mBinder.getBookList!然后把返回结果放到result中即可。至此,整个通信过程分析完毕。

    总结

    • Client是通过本地的Proxy类像Server发起通信

    • Client通过ServerConnection接口回调收到Server远程Binder对象

    • IPC过程发生在transact方法中,该方法会挂起直到服务端返回结果,因此不能在主线程调用远程服务。

    Binder工作机制

    p1.jpg

    图片和文中Demo来自《Android开发技术探索》

    源码下载

    延伸阅读

  • 相关阅读:
    Docker配置mysql
    Docker中部署Redis
    Linux上docker的安装
    tomcat启动报错:To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
    导出excel表格不能用ajax
    linux安装jdk
    第三次实验报告:使用Packet Tracer分析TCP连接建立过程
    第二次实验报告:使用Packet Tracer分析应用层协议
    第一次实验报告:使用Packet Tracer分析HTTP数据包
    PYTHON——多线程:队列Queue数据结构
  • 原文地址:https://www.cnblogs.com/jasonkent27/p/5860680.html
Copyright © 2020-2023  润新知