目录
AIDL文件
IRemoteService.aidl
// IRemoteService.aidl
package com.example.aidldemo;
import com.example.aidldemo.MyData;
// Declare any non-default types here with import statements
interface IRemoteService {
int getPid();
MyData getMyData();
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
MyData.aidl 定义远程通信的自定义数据
// MyData.aidl
package com.example.aidldemo;
parcelable MyData;
Parcel数据
MyData.java
public class MyData implements Parcelable {
private int data1;
private int data2;
public MyData(){
}
protected MyData(Parcel in) {
readFromParcel(in);
}
public static final Creator<MyData> CREATOR = new Creator<MyData>() {
@Override
public MyData createFromParcel(Parcel in) {
return new MyData(in);
}
@Override
public MyData[] newArray(int size) {
return new MyData[size];
}
};
@Override
public int describeContents() {
return 0;
}
/** 将数据写入到Parcel **/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(data1);
dest.writeInt(data2);
}
/** 从Parcel中读取数据 **/
public void readFromParcel(Parcel in){
data1 = in.readInt();
data2 = in.readInt();
}
public int getData2() {
return data2;
}
public void setData2(int data2) {
this.data2 = data2;
}
public int getData1() {
return data1;
}
public void setData1(int data1) {
this.data1 = data1;
}
@Override
public String toString() {
return "data1 = "+ data1 + ", data2="+ data2;
}
}
Server端
RemoteService.java
本例是为了演示进程间的通信机制,故需要将Service与Activity处于不同的进程,需要在AndroidManifest.xml中,把service配置成android:process=":remote"
,进程也可以命名成其他的。
package com.example.aidldemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
public class RemoteService extends Service {
private static final String TAG = "BinderSimple";
MyData mMyData;
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "[RemoteService] onCreate");
initMyData();
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG,"[RemoteService] onBind");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "[RemoteService] onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.i(TAG, "[RemoteService] onDestroy");
super.onDestroy();
}
/**
* 实现IRemoteService.aidl中定义的方法
*/
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public int getPid() throws RemoteException {
Log.i(TAG,"[RemoteService] getPid()="+android.os.Process.myPid());
return android.os.Process.myPid();
}
@Override
public MyData getMyData() throws RemoteException {
Log.i(TAG,"[RemoteService] getMyData() "+ mMyData.toString());
return mMyData;
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
/**此处可用于权限拦截**/
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
return super.onTransact(code, data, reply, flags);
}
};
/**
* 初始化MyData数据
**/
private void initMyData() {
mMyData = new MyData();
mMyData.setData1(10);
mMyData.setData2(20);
}
}
Client端
ClientActivity.java
package com.example.aidldemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "BinderSimple";
private IRemoteService mRemoteService;
private boolean mIsBound;
private TextView mCallBackTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "[ClientActivity] onCreate");
setContentView(R.layout.activity_main);
mCallBackTv = (TextView) findViewById(R.id.tv_callback);
mCallBackTv.setText(R.string.remote_service_unattached);
}
/**
* 用语监控远程服务连接的状态
*/
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mRemoteService = IRemoteService.Stub.asInterface(service);
String pidInfo = null;
try {
MyData myData = mRemoteService.getMyData();
pidInfo = "pid="+ mRemoteService.getPid() +
", data1 = "+ myData.getData1() +
", data2="+ myData.getData2();
} catch (RemoteException e) {
e.printStackTrace();
}
Log.i(TAG, "[ClientActivity] onServiceConnected "+pidInfo);
mCallBackTv.setText(pidInfo);
Toast.makeText(MainActivity.this, R.string.remote_service_connected, Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "[ClientActivity] onServiceDisconnected");
mCallBackTv.setText(R.string.remote_service_disconnected);
mRemoteService = null;
Toast.makeText(MainActivity.this, R.string.remote_service_disconnected, Toast.LENGTH_SHORT).show();
}
};
public void clickHandler(View view){
switch (view.getId()){
case R.id.btn_bind:
bindRemoteService();
break;
case R.id.btn_unbind:
unbindRemoteService();
break;
case R.id.btn_kill:
killRemoteService();
break;
}
}
/**
* 绑定远程服务
*/
private void bindRemoteService(){
Log.i(TAG, "[ClientActivity] bindRemoteService");
Intent intent = new Intent(MainActivity.this, RemoteService.class);
intent.setAction(IRemoteService.class.getName());
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
mCallBackTv.setText(R.string.binding);
}
/**
* 解除绑定远程服务
*/
private void unbindRemoteService(){
if(!mIsBound){
return;
}
Log.i(TAG, "[ClientActivity] unbindRemoteService ==>");
unbindService(mConnection);
mIsBound = false;
mCallBackTv.setText(R.string.unbinding);
}
/**
* 杀死远程服务
*/
private void killRemoteService(){
Log.i(TAG, "[ClientActivity] killRemoteService");
try {
android.os.Process.killProcess(mRemoteService.getPid());
mCallBackTv.setText(R.string.kill_success);
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, R.string.kill_failure, Toast.LENGTH_SHORT).show();
}
}
}
运行
该工程会生成一个apk,安装到手机,打开apk,界面如下:
界面上有三个按钮,分别是功能分别是bindService(绑定Service), unbindService(解除绑定Service), killProcess(杀死Service进程)。
从左往右,依次点击界面,可得:
原理分析
调用图:
源码
采用AIDL技术,原理还是利用framework binder的架构。本文的实例AIDL会自动生成一个与之相对应的IRemoteService.java文件,如下:
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.example.aidldemo;
// Declare any non-default types here with import statements
public interface IRemoteService extends android.os.IInterface
{
/** Default implementation for IRemoteService. */
public static class Default implements com.example.aidldemo.IRemoteService
{
@Override public int getPid() throws android.os.RemoteException
{
return 0;
}
@Override public com.example.aidldemo.MyData getMyData() throws android.os.RemoteException
{
return null;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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.example.aidldemo.IRemoteService
{
private static final java.lang.String DESCRIPTOR = "com.example.aidldemo.IRemoteService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.aidldemo.IRemoteService interface,
* generating a proxy if needed.
*/
public static com.example.aidldemo.IRemoteService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.aidldemo.IRemoteService))) {
return ((com.example.aidldemo.IRemoteService)iin);
}
return new com.example.aidldemo.IRemoteService.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_getPid:
{
data.enforceInterface(descriptor);
int _result = this.getPid();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_getMyData:
{
data.enforceInterface(descriptor);
com.example.aidldemo.MyData _result = this.getMyData();
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_basicTypes:
{
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0!=data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.example.aidldemo.IRemoteService
{
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 int getPid() 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_getPid, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getPid();
}
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public com.example.aidldemo.MyData getMyData() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
com.example.aidldemo.MyData _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getMyData, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getMyData();
}
_reply.readException();
if ((0!=_reply.readInt())) {
_result = com.example.aidldemo.MyData.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean)?(1):(0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public static com.example.aidldemo.IRemoteService sDefaultImpl;
}
static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getMyData = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
public static boolean setDefaultImpl(com.example.aidldemo.IRemoteService 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.example.aidldemo.IRemoteService getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public int getPid() throws android.os.RemoteException;
public com.example.aidldemo.MyData getMyData() throws android.os.RemoteException;
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}
简单分析
ClientActivity 拿到 mRemoteService (类型IRemoteService extends android.os.IInterface),
然后可以远程调用 mRemoteService的成员方法
public int getPid() throws android.os.RemoteException;
public com.example.aidldemo.MyData getMyData() throws android.os.RemoteException;
IRemoteService 由 onServiceConnected(ComponentName name, IBinder service) 中参数service(android.os.IBinder)而来
即 IRemoteService.Stub.asInterface(service)
android.os.IBinder obj 如何得到 IRemoteService (android.os.IInterface)?
/**
* Cast an IBinder object into an com.example.aidldemo.IRemoteService interface,
* generating a proxy if needed.
*/
public static com.example.aidldemo.IRemoteService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
// 通过描述符查询
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.aidldemo.IRemoteService))) {
// 类型转换
return ((com.example.aidldemo.IRemoteService)iin);
}
return new com.example.aidldemo.IRemoteService.Stub.Proxy(obj);
}