AIDL相关的重要类和接口
1.IInterface
2.IBinder
3.Binder
4.BinderProxy
IInterface
public interface IInterface
{
/**
* Retrieve the Binder object associated with this interface.
* You must use this instead of a plain cast, so that proxy objects
* can return the correct result.
*/
public IBinder asBinder();
}
IBinder
/**
* Get the canonical name of the interface supported by this binder.
*/
public @Nullable String getInterfaceDescriptor() throws RemoteException;
/**
* Check to see if the object still exists.
*
* @return Returns false if the
* hosting process is gone, otherwise the result (always by default
* true) returned by the pingBinder() implementation on the other
* side.
*/
public boolean pingBinder();
/**
* Check to see if the process that the binder is in is still alive.
*
* @return false if the process is not alive. Note that if it returns
* true, the process may have died while the call is returning.
*/
public boolean isBinderAlive();
/**
* Attempt to retrieve a local implementation of an interface
* for this Binder object. If null is returned, you will need
* to instantiate a proxy class to marshall calls through
* the transact() method.
*/
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor);
/**
* Print the object's state into the given stream.
*
* @param fd The raw file descriptor that the dump is being sent to.
* @param args additional arguments to the dump request.
*/
public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) throws RemoteException;
/**
* Like {@link #dump(FileDescriptor, String[])} but always executes
* asynchronously. If the object is local, a new thread is created
* to perform the dump.
*
* @param fd The raw file descriptor that the dump is being sent to.
* @param args additional arguments to the dump request.
*/
public void dumpAsync(@NonNull FileDescriptor fd, @Nullable String[] args)
throws RemoteException;
/**
* Execute a shell command on this object. This may be performed asynchrously from the caller;
* the implementation must always call resultReceiver when finished.
*
* @param in The raw file descriptor that an input data stream can be read from.
* @param out The raw file descriptor that normal command messages should be written to.
* @param err The raw file descriptor that command error messages should be written to.
* @param args Command-line arguments.
* @param shellCallback Optional callback to the caller's shell to perform operations in it.
* @param resultReceiver Called when the command has finished executing, with the result code.
* @hide
*/
public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err,
@NonNull String[] args, @Nullable ShellCallback shellCallback,
@NonNull ResultReceiver resultReceiver) throws RemoteException;
/**
* Perform a generic operation with the object.
*
* @param code The action to perform. This should
* be a number between {@link #FIRST_CALL_TRANSACTION} and
* {@link #LAST_CALL_TRANSACTION}.
* @param data Marshalled data to send to the target. Must not be null.
* If you are not sending any data, you must create an empty Parcel
* that is given here.
* @param reply Marshalled data to be received from the target. May be
* null if you are not interested in the return value.
* @param flags Additional operation flags. Either 0 for a normal
* RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
*
* @return Returns the result from {@link Binder#onTransact}. A successful call
* generally returns true; false generally means the transaction code was not
* understood.
*/
public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
throws RemoteException;
/**
* Interface for receiving a callback when the process hosting an IBinder
* has gone away.
*
* @see #linkToDeath
*/
public interface DeathRecipient {
public void binderDied();
}
/**
* Register the recipient for a notification if this binder
* goes away. If this binder object unexpectedly goes away
* (typically because its hosting process has been killed),
* then the given {@link DeathRecipient}'s
* {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method
* will be called.
*
* You will only receive death notifications for remote binders,
* as local binders by definition can't die without you dying as well.
*
* @throws RemoteException if the target IBinder's
* process has already died.
*
* @see #unlinkToDeath
*/
public void linkToDeath(@NonNull DeathRecipient recipient, int flags)
throws RemoteException;
/**
* Remove a previously registered death notification.
* The recipient will no longer be called if this object
* dies.
*
* @return {@code true} if the recipient is successfully
* unlinked, assuring you that its
* {@link DeathRecipient#binderDied DeathRecipient.binderDied()} method
* will not be called; {@code false} if the target IBinder has already
* died, meaning the method has been (or soon will be) called.
*
* @throws java.util.NoSuchElementException if the given
* recipient has not been registered with the IBinder, and
* the IBinder is still alive. Note that if the recipient
* was never registered, but the IBinder has already died, then this
* exception will not be thrown, and you will receive a false
* return value instead.
*/
public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags);
Binder
public class Binder implements IBinder {
...
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
...
}
IMusicService.aidl 的定义
interface IMusicService {
void updateMusicList(in List musicFileList);
void getPlayList(out List musicFileList);
boolean play(int position);
boolean pause();
boolean stop();
}
void updateMusicList(in List
musicFileList);
void getPlayList(out ListmusicFileList);中的in和out表示数据走向的方向标记。in表示走向Remote服务,out表示走向客户端。它们之间的细节差别表现:
IMusicService 的类结构
IMusicService 有一个抽象的子类Stub, Stub继承自Binder,实现了IMusicService接口。Stub里面定义了一个Proxy类,Stub.Proxy直接实现了IMusicService接口。
public interface IMusicService extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.chiang.chnplayer.aidl.IMusicService {
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
private static class Proxy implements com.chiang.chnplayer.aidl.IMusicService {
}
public static com.chiang.chnplayer.aidl.IMusicService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.chiang.chnplayer.aidl.IMusicService))) {
return ((com.chiang.chnplayer.aidl.IMusicService) iin);
}
return new com.chiang.chnplayer.aidl.IMusicService.Stub.Proxy(obj);
}
}
public void updateMusicList(java.util.List musicFileList) throws android.os.RemoteException;
public void getPlayList(java.util.List musicFileList) throws android.os.RemoteException;
public boolean play(int position) throws android.os.RemoteException;
public boolean pause() throws android.os.RemoteException;
public boolean stop() throws android.os.RemoteException;
}
IMusicService 的具体实现
public interface IMusicService extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.chiang.chnplayer.aidl.IMusicService {
private static final java.lang.String DESCRIPTOR = "com.chiang.chnplayer.aidl.IMusicService";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.chiang.chnplayer.aidl.IMusicService interface,
* generating a proxy if needed.
*/
public static com.chiang.chnplayer.aidl.IMusicService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.chiang.chnplayer.aidl.IMusicService))) {
return ((com.chiang.chnplayer.aidl.IMusicService) iin);
}
return new com.chiang.chnplayer.aidl.IMusicService.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 {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_updateMusicList: {
//验证Binder标识
data.enforceInterface(DESCRIPTOR);
java.util.List _arg0;
_arg0 = data.createTypedArrayList(com.chiang.chnplayer.aidl.SongInfo.CREATOR);
this.updateMusicList(_arg0);//这调用的是继承IMusicService.Stub后实现的方法
reply.writeNoException();
return true;
}
case TRANSACTION_getPlayList: {
data.enforceInterface(DESCRIPTOR);
java.util.List _arg0;
_arg0 = new java.util.ArrayList();
this.getPlayList(_arg0);
reply.writeNoException();
reply.writeTypedList(_arg0);
return true;
}
case TRANSACTION_play: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
boolean _result = this.play(_arg0);
reply.writeNoException();
reply.writeInt(((_result) ? (1) : (0)));
return true;
}
case TRANSACTION_pause: {
data.enforceInterface(DESCRIPTOR);
boolean _result = this.pause();
reply.writeNoException();
reply.writeInt(((_result) ? (1) : (0)));
return true;
}
case TRANSACTION_stop: {
data.enforceInterface(DESCRIPTOR);
boolean _result = this.stop();
reply.writeNoException();
reply.writeInt(((_result) ? (1) : (0)));
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.chiang.chnplayer.aidl.IMusicService {
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 updateMusicList(java.util.List musicFileList) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeTypedList(musicFileList);
mRemote.transact(Stub.TRANSACTION_updateMusicList, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void getPlayList(java.util.List musicFileList) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getPlayList, _data, _reply, 0);
_reply.readException();
_reply.readTypedList(musicFileList, com.chiang.chnplayer.aidl.SongInfo.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public boolean play(int position) 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);
_data.writeInt(position);
mRemote.transact(Stub.TRANSACTION_play, _data, _reply, 0);
_reply.readException();
_result = (0 != _reply.readInt());
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public boolean pause() 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);
mRemote.transact(Stub.TRANSACTION_pause, _data, _reply, 0);
_reply.readException();
_result = (0 != _reply.readInt());
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public boolean stop() 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);
mRemote.transact(Stub.TRANSACTION_stop, _data, _reply, 0);
_reply.readException();
_result = (0 != _reply.readInt());
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_updateMusicList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getPlayList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_play = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
}
public void updateMusicList(java.util.List musicFileList) throws android.os.RemoteException;
public void getPlayList(java.util.List musicFileList) throws android.os.RemoteException;
public boolean play(int position) throws android.os.RemoteException;
public boolean pause() throws android.os.RemoteException;
public boolean stop() throws android.os.RemoteException;
}
data.enforceInterface(DESCRIPTOR);//验证Binder标识
IMusicService.Stub的实现类(这里是匿名实现类)
private IMusicService.Stub mBinder=new IMusicService.Stub() {
@Override
public boolean stop() throws RemoteException {
return mMusicPlayer.stop();
}
@Override
public void updateMusicList(List musicFileList)
throws RemoteException {
mMusicPlayer.updateMusicList(musicFileList);
}
@Override
public boolean play(int position) throws RemoteException {
return mMusicPlayer.play(position);
}
@Override
public boolean pause() throws RemoteException {
return mMusicPlayer.pause();
}
@Override
public void getPlayList(List musicFileList)
throws RemoteException {
List tmp = mMusicPlayer.getFileList();
int count = tmp.size();
for(int i = 0; i < count; i++)
{
musicFileList.add(tmp.get(i));
}
}
};
ServiceConnection中onServiceConnected参数 IBinder service的来源?
class MServiceConnetion implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service){
mIMusicService=IMusicService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
关于在同一进程绑定Service和跨进程绑定Service后,ServiceConnection返回的IBinder对象和X.Stub.asInterface返回的对象。
private IPayService mIPayService;
class PayServiceConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIPayService = IPayService.Stub.asInterface(service);
mIPayService.toString();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
public static com.fmtech.aidl_payservice.IPayService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.fmtech.aidl_payservice.IPayService))) {
return ((com.fmtech.aidl_payservice.IPayService) iin);
}
return new com.fmtech.aidl_payservice.IPayService.Stub.Proxy(obj);
}
public class PayService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new PayServiceStub();
}
private void pay(){
...
}
class PayServiceStub extends IPayService.Stub{
@Override
public void callMethodInService() throws RemoteException {
pay();
}
}
}
1.同一进程绑定Service
ServiceConnection#onServiceConnected返回的对象是PayService在onBind中直接返回的PayServiceStub实例;IPayService.Stub.asInterface方法返回的也是PayServiceStub实例。所以,当MainActivity中mIPayService调用callMethodInService时,直接调用的是Payservice中的callMethodInService方法。不需要走其他流程。
2.跨进程绑定Service
ServiceConnection#onServiceConnected返回的对象是BinderProxy实例;IPayService.Stub.asInterface方法返回的是IPayService.Stub.Proxy实例。所以,当MainActivity中mIPayService调用callMethodInService时流程如下:
-->IPayService.Stub.Proxy#callMethodInService()-->BinderProxy#transact()
BinderProxy#queryLocalInterface()
public IInterface queryLocalInterface(String descriptor) {
return null;
}
当onServiceConnected返回的对象是BinderProxy时,asInterface()方法中queryLocalInterface()返回的是null,所以asInterface()方法会返回*.Stub.Proxy
public static com.chiang.chnplayer.aidl.IMusicService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.chiang.chnplayer.aidl.IMusicService))) {
return ((com.chiang.chnplayer.aidl.IMusicService) iin);
}
return new com.chiang.chnplayer.aidl.IMusicService.Stub.Proxy(obj);
}
@Override
public void callMethodInService() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(IPayService.Stub.TRANSACTION_callMethodInService, _data, _reply, 0);//mRemote即是BinderProxy实例
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
...
return transactNative(code, data, reply, flags);
}
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
BinderProxy.transact后会调用native方法,由native层进行处理;最后,再由native层回调IPayService.Stub.onTransact()方法,进而调用callMethodInService()方法。
为什么跨进程绑定Service时,ServiceConnection#onServiceConnected返回的对象是BinderProxy实例?
........
【相关源码】MusicService