1.基本使用
服务端创建
AIDL文件
interface IDemoInterface {
void demo();
int getDemo();
void setDemo(int i);
}
public class DemoServer extends IDemoInterface.Stub{
private int value=0;
@Override
public void demo() throws RemoteException {
Log.e("DemoServer","demo");
}
@Override
public int getDemo() throws RemoteException {
return value;
}
@Override
public void setDemo(int i) throws RemoteException {
value=i;
Log.e("DemoServer","setDemo"+i);
}
}
public class DemoService extends Service {
private DemoServer demoServer;
public DemoService() {
}
@Override
public void onCreate() {
super.onCreate();
demoServer=new DemoServer();
}
@Override
public IBinder onBind(Intent intent) {
return demoServer;
}
}
以上是服务端代码,基本功能就是写入值、取出值。
客户端代码
public class MainActivity extends AppCompatActivity {
private TextView startService,demo,setDemo,getDemo;
IDemoInterface idemo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService=findViewById(R.id.startService);
demo=findViewById(R.id.demo);
setDemo=findViewById(R.id.setDemo);
getDemo=findViewById(R.id.getDemo);
startService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.roxmotor.aidlservice.DemoService");
intent.setPackage("com.roxmotor.aidlservice");
boolean result = getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Log.d("MainActivity",result+"");
}
});
demo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
idemo.demo();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
setDemo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Log.d("MainActivity","设置了200");
idemo.setDemo(200);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
getDemo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
int value=idemo.getDemo();
Log.e("MainActivity","获取值:"+value);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//成功连接
Log.d("MainActivity","pushManager ***************成功连接***************");
idemo=IDemoInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
//断开连接调用
Log.d("MainActivity","pushManager ***************连接已经断开***************");
}
};
}
执行结果
上面基本使用方式就不详细说了,这里就不详细说adil如何使用了,我们直接来看aidl是如何帮助我们跨进程处理数据的。
public interface IDemoInterface extends android.os.IInterface
{
/** Default implementation for IDemoInterface. */
public static class Default implements com.roxmotor.aidlservice.IDemoInterface
{
@Override public void demo() throws android.os.RemoteException
{
}
@Override public int getDemo() throws android.os.RemoteException
{
return 0;
}
@Override public void setDemo(int i) throws android.os.RemoteException
{
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.roxmotor.aidlservice.IDemoInterface
{
private static final java.lang.String DESCRIPTOR = "com.roxmotor.aidlservice.IDemoInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.roxmotor.aidlservice.IDemoInterface interface,
* generating a proxy if needed.
*/
public static com.roxmotor.aidlservice.IDemoInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.roxmotor.aidlservice.IDemoInterface))) {
return ((com.roxmotor.aidlservice.IDemoInterface)iin);
}
return new com.roxmotor.aidlservice.IDemoInterface.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_demo:
{
data.enforceInterface(descriptor);
this.demo();
reply.writeNoException();
return true;
}
case TRANSACTION_getDemo:
{
data.enforceInterface(descriptor);
int _result = this.getDemo();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_setDemo:
{
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
this.setDemo(_arg0);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.roxmotor.aidlservice.IDemoInterface
{
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 demo() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_demo, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().demo();
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public int getDemo() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getDemo, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getDemo();
}
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void setDemo(int i) 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.writeInt(i);
boolean _status = mRemote.transact(Stub.TRANSACTION_setDemo, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().setDemo(i);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public static com.roxmotor.aidlservice.IDemoInterface sDefaultImpl;
}
static final int TRANSACTION_demo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getDemo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_setDemo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
public static boolean setDefaultImpl(com.roxmotor.aidlservice.IDemoInterface 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.roxmotor.aidlservice.IDemoInterface getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public void demo() throws android.os.RemoteException;
public int getDemo() throws android.os.RemoteException;
public void setDemo(int i) throws android.os.RemoteException;
}
结构如下
代码初看比较长,我们一个个来看。
我们先看下Default这个类,他只是实现了com.roxmotor.aidlservice.IDemoInterface这个接口,而且都是空实现,同时并没有继承Binder,asBinder返回是null,我个人一般不用Default。
Stub构造函数,当我们bindService时,在onBind返回一个IBind类型接口,因为所有的IBinder aidl 远程调用都要继承自IDemoInterface.Stub,所以必然会调用到
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
Stub 的空构造函数。而Stub 本身又是Binder 的子类。调用了Binder 的attachInterface 方法。
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
分别保存了当前类的实例对象(This,也就是当前的binder)和当前类接口描述符(DESCRIPTOR),后面会通过DESCRIPTOR查找对应的binder
private static final java.lang.String DESCRIPTOR = "com.roxmotor.aidlservice.IDemoInterface";
public static com.roxmotor.aidlservice.IDemoInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.roxmotor.aidlservice.IDemoInterface))) {
return ((com.roxmotor.aidlservice.IDemoInterface)iin);
}
return new com.roxmotor.aidlservice.IDemoInterface.Stub.Proxy(obj);
}
我们知道这里的obj是bindService拿到的远程Binder,即BinderProxy(这里为什么是BinderProxy,后面文章会说到。)
那我们看下BinderProxy的queryLocalInterface(DESCRIPTOR)
public IInterface queryLocalInterface(String descriptor) {
return null;
}
这里返回null,asInterface方法直接返回com.roxmotor.aidlservice.IDemoInterface.Stub.Proxy(obj)。如果obj不是远程的BinderProxy,那就是本进程Binder,其方法如下
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
if (mDescriptor != null && mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
这里的mOwner,就是本地的一个Stub
这里的asInterface,就是判断是拿本地binder还是拿远程binder即BinderProxy
private static class Proxy implements com.roxmotor.aidlservice.IDemoInterface
{
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 demo() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_demo, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().demo();
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public int getDemo() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getDemo, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getDemo();
}
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void setDemo(int i) 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.writeInt(i);
boolean _status = mRemote.transact(Stub.TRANSACTION_setDemo, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().setDemo(i);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public static com.roxmotor.aidlservice.IDemoInterface sDefaultImpl;
}
调用远程binder会走Proxy这里。
我们可以大概看看出,Proxy实现了IDemoInterface的方法,内部实现是通过mRemote去调用的。这个mRemote就是bindService拿到的IBinder service,也就是BinderProxy.
我们拿getDemo方法来看看
_data是传参,_reply是返回值,他们是Parcel类型(进程间通信由于资源不共享,因此无法直接传递对象,只能通过序列化在不同的空间拷贝两份相同的资源)
我们可以看出,不管哪个方法,_data都要存储DESCRIPTOR,也就是描述符。现在我们知道为什么客户端adil为什么要和服务端一样了。他们一样的话,DESCRIPTOR也就一样,服务端可以通过这个DESCRIPTOR可以在onTransact里面找到对应的方法。
getDemo没有参数,所以_data里面没有存储给服务端参数。setDemo里面存储了一个参数,调用了_data.writeInt(i)。
接下来执行
mRemote.transact(Stub.TRANSACTION_getDemo, _data, _reply, 0);
这里的mRemote,我们现在知道,他是BinderProxy.调用了transact方法,最终还是执行了Stub中的onTransact
@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_demo:
{
data.enforceInterface(descriptor);
this.demo();
reply.writeNoException();
return true;
}
case TRANSACTION_getDemo:
{
data.enforceInterface(descriptor);
int _result = this.getDemo();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_setDemo:
{
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
this.setDemo(_arg0);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
我们看下TRANSACTION_getDemo,这里我们把this.getDemo方法的结果存储到reply中。这里this.getDemo是那里实现呢?
这里的Stub实现了IDemoInterface接口,但是并没有真正的实现,那在那里实现了?我们回看代码,发现了一个叫DemoServer的类,继承了IDemoInterface.Stub,实现了所有方法。
@Override
public int getDemo() throws RemoteException {
return value;
}
this.getDemo就是返回value。
我们继续往下看。
执行mRemote.transact方法后,_result = _reply.readInt();会取出_reply值,然后return _result。最终拿到返回值。
整个过程完成。
Proxy调用getDemo,实际上是通过调用mRemote.transact()来触发远端Stub的onTransact()
一般流程:
1.binderService,获得一个远程binder,即BinderProxy
2.在Proxy,拿到BinderProxy,同时通过Parcel将参数传给BinderProxy,最终触发BinderProxy的transact方法。
3.Binder的transact方法最终会触发到Server上Stub的onTransact方法。
4.Server上Stub的onTransact方法中,会先从Parcel中解析中参数,然后将参数带入真正的方法中执行,然后将结果写入Parcel后传回。
5.Client的Ipc方法中,执行Binder的transact时,是阻塞等待的。一直到Server逻辑执行结束后才会继续执行。
6.当Server返回结果后,Client从Parcel中取出返回值,于是实现了一次IPC调用。
大概流程如下:
1.ServiceConnection是如何获取到Binder的而且是BinderProxy?
2.transact方法最终是如何触发Stub中的onTransact的?
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。