背景

最近打算学习一下如何在framework层添加一个自定义service。 了解到自定义service需要使用aidl,为了加强对aidl的了解和使用过程,特意又温习了一下aidl的使用,并用博客的形式记录下来。 aidl官方参考:https://developer.android.google.cn/develop/background-work/services/aidl?hl=en

AIDL是什么

官方解释:Android 接口定义语言 (AIDL) 类似于其他 IDL:它允许您定义客户端和服务使用进程间通信 (IPC) 进行相互通信时都认可的编程接口。

定义 AIDL 接口

这里我使用的ide是Android Studio Iguana版本。 首先创建一个project,里面创建两个app一个叫client,另一个叫server。 在server app的src/main目录创建一个aidl文件IMyAidlInterface.aidl,内容如下

// IMyAidlInterface.aidl

package com.hai.server;

// Declare any non-default types here with import statements

//aidl说明参考:https://developer.android.google.cn/develop/background-work/services/aidl?hl=en

interface IMyAidlInterface {

/**

* 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);

int getPid();

oneway void getThreadId();

}

IMyAidlInterface.aidl中定义了三个接口供客户端调用。

然后编译一下project,就会在server的build目录下自动生成IMyAidlInterface.java接口文件,内容如下

/*

* This file is auto-generated. DO NOT MODIFY.

*/

package com.hai.server;

// Declare any non-default types here with import statements

//aidl说明参考:https://developer.android.google.cn/develop/background-work/services/aidl?hl=en

public interface IMyAidlInterface extends android.os.IInterface

{

/** Default implementation for IMyAidlInterface. */

public static class Default implements com.hai.server.IMyAidlInterface

{

/**

* 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 int getPid() throws android.os.RemoteException

{

return 0;

}

@Override public void getThreadId() 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.hai.server.IMyAidlInterface

{

/** Construct the stub at attach it to the interface. */

public Stub()

{

this.attachInterface(this, DESCRIPTOR);

}

/**

* Cast an IBinder object into an com.hai.server.IMyAidlInterface interface,

* generating a proxy if needed.

*/

public static com.hai.server.IMyAidlInterface asInterface(android.os.IBinder obj)

{

if ((obj==null)) {

return null;

}

android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

if (((iin!=null)&&(iin instanceof com.hai.server.IMyAidlInterface))) {

return ((com.hai.server.IMyAidlInterface)iin);

}

return new com.hai.server.IMyAidlInterface.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;

if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {

data.enforceInterface(descriptor);

}

switch (code)

{

case INTERFACE_TRANSACTION:

{

reply.writeString(descriptor);

return true;

}

}

switch (code)

{

case TRANSACTION_basicTypes:

{

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();

break;

}

case TRANSACTION_getPid:

{

int _result = this.getPid();

reply.writeNoException();

reply.writeInt(_result);

break;

}

case TRANSACTION_getThreadId:

{

this.getThreadId();

break;

}

default:

{

return super.onTransact(code, data, reply, flags);

}

}

return true;

}

private static class Proxy implements com.hai.server.IMyAidlInterface

{

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;

}

/**

* 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);

_reply.readException();

}

finally {

_reply.recycle();

_data.recycle();

}

}

@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);

_reply.readException();

_result = _reply.readInt();

}

finally {

_reply.recycle();

_data.recycle();

}

return _result;

}

@Override public void getThreadId() throws android.os.RemoteException

{

android.os.Parcel _data = android.os.Parcel.obtain();

try {

_data.writeInterfaceToken(DESCRIPTOR);

boolean _status = mRemote.transact(Stub.TRANSACTION_getThreadId, _data, null, android.os.IBinder.FLAG_ONEWAY);

}

finally {

_data.recycle();

}

}

}

static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);

static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

static final int TRANSACTION_getThreadId = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);

}

public static final java.lang.String DESCRIPTOR = "com.hai.server.IMyAidlInterface";

/**

* 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;

public int getPid() throws android.os.RemoteException;

public void getThreadId() throws android.os.RemoteException;

}

IMyAidlInterface.java结构图

可以看到IMyAidlInterface.java也定义了和aidl相同的三个接口,并且定义了Default和Stub两个静态内部类去实现IMyAidlInterface接口。

Default类默认空实现且没有继承Binder,实际无意义。Stub是一个继承Binder抽象类,实际是要在server端写一个Stub的实现类去实现实际的接口功能Stub.Proxy一般用于client端。

Server端实现服务

接下来就是在server端的service中实现aidl接口服务,这里我写了一个ServerService类,内容如下

package com.hai.server;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.os.RemoteException;

import android.os.SystemClock;

import android.system.Os;

import android.util.Log;

public class ServerService extends Service {

private static final String TAG = "ServiceService";

IMyAidlInterface.Stub binder = new IMyAidlInterface.Stub() {

@Override

public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

Log.d(TAG, "basicTypes() called with: anInt = [" + anInt + "], aLong = [" + aLong + "], aBoolean = [" + aBoolean + "], aFloat = [" + aFloat + "], aDouble = [" + aDouble + "], aString = [" + aString + "]");

}

@Override

public int getPid() throws RemoteException {

SystemClock.sleep(2000);

return Os.getpid();

}

@Override

public void getThreadId() throws RemoteException {

SystemClock.sleep(2000);

}

};

@Override

public IBinder onBind(Intent intent) {

Log.d(TAG, "onBind() called with: intent = [" + intent + "]");

return binder;

}

@Override

public boolean onUnbind(Intent intent) {

Log.d(TAG, "onUnbind() called with: intent = [" + intent + "]");

return super.onUnbind(intent);

}

}

为了client端可以通过隐式服务绑定服务,还需要在AndroidManifest.xml做一下配置

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:roundIcon="@mipmap/ic_launcher_round"

android:supportsRtl="true"

android:theme="@style/Theme.AidlDemo">

android:name=".ServerService"

android:enabled="true"

android:exported="true">

当client端通过bindservice绑定成功后,服务端就会返回server端的binder对象给到client端。

Client端使用服务

首先需要把server端的aidl整个文件夹拷贝到client端的src目录,以便client端能够获得aidl的访问权限。client端的代码结构如图 编译一下project,就会在client的build目录下自动生成IMyAidlInterface.java接口文件。 接下来就是bindservice,bindservice服务成功后就可以获得binder的代理对象,进而调用aidl接口服务。如下是在activity中通过bindservice的方式调用aidl接口服务。

package com.hai.aidldemo;

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 androidx.activity.EdgeToEdge;

import androidx.appcompat.app.AppCompatActivity;

import com.hai.server.IMyAidlInterface;

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";

IMyAidlInterface myAidlInterface;

ServiceConnection serviceConnection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

Log.d(TAG, "onServiceConnected() called with: name = [" + name + "], service = [" + service + "]");

myAidlInterface = IMyAidlInterface.Stub.asInterface(service);

}

@Override

public void onServiceDisconnected(ComponentName name) {

Log.d(TAG, "onServiceDisconnected() called with: name = [" + name + "]");

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

EdgeToEdge.enable(this);

setContentView(R.layout.activity_main);

}

public void clk(View view) {

switch (view.getId()) {

case R.id.btn_bind:

if (myAidlInterface == null) {

boolean b = bindService(new Intent("com.hai.server.ServerService").setPackage("com.hai.server"), serviceConnection, Context.BIND_AUTO_CREATE);

Log.d(TAG, "bindService: " + b);

}

break;

case R.id.btn_unbind:

if (myAidlInterface != null) {

unbindService(serviceConnection);

}

break;

case R.id.btn_basicType:

try {

myAidlInterface.basicTypes(1, 2, true, 4, 5, "6");

} catch (RemoteException e) {

throw new RuntimeException(e);

}

break;

case R.id.btn_getPid:

try {

long start = System.currentTimeMillis();

int pid = myAidlInterface.getPid();

Log.d(TAG, "getPid: " + pid + ", cost:" + (System.currentTimeMillis() - start));

} catch (RemoteException e) {

throw new RuntimeException(e);

}

break;

case R.id.btn_getThreadId:

try {

long start = System.currentTimeMillis();

myAidlInterface.getThreadId();

Log.d(TAG, "getThreadId: cost:" + (System.currentTimeMillis() - start));

} catch (RemoteException e) {

throw new RuntimeException(e);

}

break;

}

}

}

项目源码:

https://gitee.com/menty/aidl-demo/blob/master/client/src/main/java/com/hai/aidldemo/MainActivity.java

参考文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。