Application Binder Exploration (Part 1)

This article mainly lists the demo code, including client-side Activity, server-side remote service, aidl and its Java interface files, which are used to describe the client and server-side application binder interaction process.

To briefly describe the function of this sample code, there is a remote service named BookManagerService, which holds a list for saving Book objects, and provides the get and add methods of the list to the outside world. The client Activity binds the service and accesses its interface.

  1. The client Activity binds BookManagerService when onCreate, and the connection is successful to generate an IBookManager object, through which the external interface of BookManagerService can be accessed.
  2.  BookManagerService sets remote, which is a remote service running in another process. It loads two rows of data for the list during onCreate, and then returns the serviceBinder object in the onBind method.

First is the aidl file:

//IBookManager.aidl
interface IBookManager {
     List<Book> getBookList();
     void addBook(in Book book);
}
//Book.aidl
parcelable Book;

Second is the client Activity:

    private IBookManager mRemoteBookManager;
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            IBookManager bookManager = IBookManager.Stub.asInterface(service);
            mRemoteBookManager = bookManager;
            try {
               //mRemoteBookManager.asBinder().linkToDeath(mDeathRecipient, 0);
                List<Book> list = bookManager.getBookList();
                Book newBook = new Book(3, "Android进阶");
                bookManager.addBook(newBook);
            } catch (RemoteException e) {
                e.printStackTrace ();
            }
        }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView(R.layout.activity_book_manager);
        Intent intent = new Intent(this, BookManagerService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

Finally, the server BookManagerService:

    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
    private Binder mBinder = new serviceBinder();
    @Override
    public IBinder onBind(Intent arg0) {
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }
    @Override
    public void onCreate() {
        super.onCreate();
        mBookList.add(new Book(1, "Android"));
        mBookList.add(new Book(2, "Ios"));
    }

    public class serviceBinder extends IBookManager.Stub{
        @Override
        public void addBook(Book book) throws RemoteException {
            mBookList.add(book);
        }@Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }
    }


The program belongs to a service bound to a different process. The general process of the initial operation is as follows:

  1. The client Activity process sends a request to bind the BookManagerService service to AMS (in fact, this is also a binder request, because AMS runs in the system service process);
  2. AMS routine checks, first check whether BookManagerService has been registered, which APP is registered (these information is obtained by parsing the manifest when the app is installed), and then check whether the process that starts BookManagerService exists, because BookManagerService has set remote, so the process at this time is If it does not exist, the Service information will be saved first, the binding request will be postponed, and a new process will be created.
  3. After the new process starts, notify AMS that it is ready, AMS will send the service information just saved to the new process to start the service (such as oncreate), and notify AMS after the service is started.
  4. Then AMS will send the binding request to BookManagerService, BookManagerService calls onbind, and returns a binder object to AMS.
  5. AMS returns the binder object to the client Acitivty (onServiceConnected is called)

        In fact, these processes have been blocked by android. In the application, we only need to pay attention to two objects. The first is the BinderProxy object returned by the onServiceConnected of the client Activity, and the second is the Binder object returned by the onBind of the server BookManagerService. However, what we see in the application are Stub and Proxy. Stub inherits Binder, and Proxy is the wrapper class of BidnerProxy. Regardless of BinderProxy or Bidner, they implement the IBinder interface and can be received by IBinder.

  1. The IBookManager interface defines the getBookList and addBook methods, which also inherit the IInterface interface, with an additional asBinder method, and the next Stub and Proxy implement the IBookManager interface.
  2. The Stub class not only inherits the Bidner class but also the IBookManager interface, and the serviceBinder of the server BookManagerService inherits the Stub class and implements the getBookList and addBook methods (the asBinder interface is implemented by the Stub class), and the serviceBinder object mBinder is returned to AMS.
  3. The onServiceConnected of the client Activity returns BinderProxy, which is wrapped into a Proxy object through the IBookManager.Stub.asInterface method, so that the getBookList and addBook methods implemented by the Proxy can be called, and the Proxy also implements the asBinder interface.

IBookManager interface:

public interface IBookManager extends IInterface {

    static final String DESCRIPTOR = "com.example.testbinder.IBookManager";
    static final int TRANSACTION_getBookList = (IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_addBook = (IBinder.FIRST_CALL_TRANSACTION + 1);

       public List<Book> getBookList()throws RemoteException;
       public void addBook(Book book)throws RemoteException;
}

Stub class:

public static abstract class Stub extends Binder implements IBookManager {
	public Stub() {
		this.attachInterface(this, DESCRIPTOR);
	}
	public static IBookManager asInterface(IBinder obj) {
		if ((obj == null)) {
			return null;
		}
		android.os.IInterface iin = obj.queryLocalInterface (DESCRIPTOR);
		if (((iin != null) && (iin instanceof IBookManager))) {
			return ((IBookManager) iin);
		}
		return new IBookManager.Stub.Proxy(obj);
	}
	@Override
	public android.os.IBinder asBinder() {
		return this;
	}
	@Override
	public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
		switch (code) {
		case INTERFACE_TRANSACTION: {
			reply.writeString(DESCRIPTOR);
			return true;
		}
		case TRANSACTION_getBookList: {
			data.enforceInterface(DESCRIPTOR);
			List<Book> _result = this.getBookList();
			reply.writeNoException();
			reply.writeTypedList(_result);
			return true;
		}
		case TRANSACTION_addBook: {
			data.enforceInterface(DESCRIPTOR);
			Book _arg0;
			if ((0 != data.readInt())) {
				_arg0 = Book.CREATOR.createFromParcel(data);
			} else {
				_arg0 = null;
			}
			this.addBook(_arg0);
			reply.writeNoException();
			return true;
		}
		return super.onTransact(code, data, reply, flags);
	}
       @Override
    public List<Book> getBookList() throws RemoteException {
        // to be implemented by the server        
               return null;
    }

    @Override
    public void addBook(Book book) throws RemoteException {
        // to be implemented by the server    
       }   
 }

Proxy class:

private static class Proxy implements IBookManager {
	private IBinder mRemote;
	Proxy(IBinder remote) {
		mRemote = remote;
	}
	@Override
	public IBinder asBinder() {
		return mRemote;
	}
	public String getInterfaceDescriptor() {
		return DESCRIPTOR;
	}
	@Override
	public List<Book> getBookList()throws RemoteException {
		Parcel _data = Parcel.obtain();
		Parcel _reply = Parcel.obtain();
		List<Book> _result;
		try {
			_data.writeInterfaceToken(DESCRIPTOR);
			mRemote.transact(Stub.TRANSACTION_getBookList, _data,_reply, 0);
			_reply.readException();
			_result = _reply.createTypedArrayList(Book.CREATOR);
		} finally {
			_reply.recycle();
			_data.recycle();
		}
		return _result;
	}
	@Override
	public void addBook(Book book)throws RemoteException {
		Parcel _data = Parcel.obtain();
		Parcel _reply = 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();
		}
	}
}	    

       

        In the next article, describe the binder communication process.








Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324470057&siteId=291194637