android AIDL使用demo

背景

最近打算学习一下如何在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 接口

project结构图
这里我使用的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结构图

可以看到IMyAidlInterface.java也定义了和aidl相同的三个接口,并且定义了DefaultStub两个静态内部类去实现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做一下配置

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        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">
        <service
            android:name=".ServerService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.hai.server.ServerService" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>
    </application>
</manifest>

当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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/766748.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

不同系统间数据交换要通过 api 不能直接数据库访问

很多大数据开发提供数据给外部系统直接给表结构&#xff0c;这是不好的方式。在不同系统间进行数据交换时&#xff0c;通过API&#xff08;应用程序编程接口&#xff09;而非直接访问数据库是现代系统集成的一种最佳实践。 目录 为什么要通过API进行数据交换如何通过API进行数据…

论文辅导 | 基于多尺度分解的LSTM⁃ARIMA锂电池寿命预测

辅导文章 模型描述 锂电池剩余使用寿命&#xff08;Remaining useful life&#xff0c;RUL&#xff09;预测是锂电池研究的一个重要方向&#xff0c;通过对RUL的准确预测&#xff0c;可以更好地管理和维护电池&#xff0c;延长电池使用寿命。为了能够准确预测锂电池的RUL&…

STM32 看门狗 HAL

由时钟图可以看出看门狗采用的是内部低速时钟&#xff0c;频率为40KHz 打开看门狗&#xff0c;采用32分频&#xff0c;计数1250。 结合设置的分频系数和重载计数值&#xff0c;我们可以计算出看门狗的定时时间&#xff1a; 32*1250/40kHz 1s 主函数中喂狗就行 HAL_IWDG_Ref…

STM32 HAL库读取ID

在stm32f1xx_hal.c文件中由读取ID号的子函数&#xff0c;不同单片机的UID_BASE不同&#xff0c;本单片机用的是STM32F103CBT6,跳转之后可以看到地址为&#xff1a;0x1FFFF7E8 在程序中只需定义一个数组调用读取ID的函数即可 uint32_t UID[3]; while(1) { UID[0] HAL_GetUIDw0…

catia数控加工仿真铣平面粗加工

1&#xff0c;零件建模&#xff0c;毛坯建模 2 在毛坯上建立坐标系 3 添加资料刀具 4&#xff0c;双击对相关加工信息做设置 5 Roughing 加工设置 高亮红色区域是必选的&#xff0c;其他可以默认 6 完成加工仿真 7 加工余量

EasyExcel4导入导出数据(基于MyBatisPlus)

一、POM依赖 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><m…

Camera Raw:编辑 - 细节

Camera Raw “编辑”模块中的细节 Detail面板用于增强照片的锐度和减少噪点。通过对锐化和降噪进行精细调整&#xff0c;可以提高图像的清晰度&#xff0c;减少噪点&#xff0c;提高图像质量。 ◆ ◆ ◆ 使用方法与技巧 1、增强照片锐度 较小的“半径”&#xff0c;较大的“细…

如何解决大文件传输存在的痛点,实现高效流转?

在当代的数字化时代&#xff0c;数据资产在各行各业中扮演着举足轻重的角色&#xff0c;而数据的流通与交换则是其价值得以实现的关键。企业在进行大文件传输时&#xff0c;都面临着诸多挑战&#xff0c;比如网络延迟、大小受限、安全风险等。因此&#xff0c;如何高效安全的进…

springboot个人证书管理系统16679

springboot个人证书管理系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了个人证书管理系统的开发全过程。通过分析个人证书管理系统管理的不足&#xff0c;创建了一个计算机管理个人证书管理系统的方案。文…

3、FTL基本工作过程

上文描述了FTL的四大功能&#xff0c;这里简述一下每个功能的含义。 地址转换简述 FTL要维护一个地址转换表&#xff0c;这个转换表是主机读/写硬盘的逻辑地址到硬盘实际物理地址的转换关系。 假如SSD的容量是128G&#xff0c;SSD逻辑块的大小是4KB&#xff0c;那SSD的逻辑块…

Linux系统的服务——以Centos7为例

一、Linux系统的服务简介 服务是向外部提供对应功能的进程&#xff0c;其运行在系统后台&#xff0c;能够7*24小时持续不断的提供外界随时发来的服务请求&#xff0c;且服务进程常驻在内存中&#xff0c;具有固定的端口号&#xff0c;通过端口号就能找到服务内容。 提供服务的一…

Linux源码阅读笔记10-进程NICE案例分析2

set_user_nice set_user_nice函数功能&#xff1a;设置某一进程的NICE值&#xff0c;其NICE值的计算是根据进程的静态优先级&#xff08;task_struct->static_prio&#xff09;&#xff0c;直接通过set_user_nice函数更改进程的静态优先级。 内核源码 void set_user_nice…

Unity3d C#实现基于UGUI ScrollRect的轮播图效果功能(含源码)

前言 轮播功能是一种常见的页面组件&#xff0c;用于在页面中显示多张图片/素材并自动或手动进行切换&#xff0c;以提高页面的美观度和用户体验。主要的功能是&#xff1a;自动/手动切换;平滑的切换效果;导航指示器等。可惜Unity的UGUI系统里没有现成的实现该功能&#xff0c…

BiTCN-Attention一键实现回归预测+8张图+特征可视化图!注意力全家桶再更新!

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原理简介 数据介绍 结果展示 全家桶代码目…

pom.xml文件加载后没有变成maven图标

原因&#xff1a; 开启了IDEA的节电模式 现象为&#xff1a; xml会变橙色&#xff0c;yml变粉色&#xff0c;自动提示关闭等 把这个节能模式的勾选给取消掉就可以正常显示了

flask的基本使用

1 sqlalchemy 快速使用 # 1 sqlalchemy 企业级orm框架# 2 python界的orm框架-1 django-orm #只能django框架用-2 peewee # 小型orm框架&#xff1a;https://docs.peewee-orm.com/en/latest/peewee/quickstart.html-----同步orm框架------3 sqlalchemy # 企业级…

虚拟机交叉编译基于ARM平台的opencv(ffmpeg/x264)

背景&#xff1a; 由于手上有一块rk3568的开发板&#xff0c;需要运行yolov5跑深度学习模型&#xff0c;但是原有的opencv不能对x264格式的视频进行解码&#xff0c;这里就需要将ffmpegx264编译进opencv。 但是开发板算力有限&#xff0c;所以这里采用在windows下&#xff0c;安…

React Native V0.74 — 稳定版已发布

嗨,React Native开发者们, React Native 世界中令人兴奋的消息是,V0.74刚刚在几天前发布,有超过 1600 次提交。亮点如下: Yoga 3.0New Architecture: Bridgeless by DefaultNew Architecture: Batched onLayout UpdatesYarn 3 for New Projects让我们深入了解每一个新亮点…

k8s 中间件

1. zookeeper 是的&#xff0c;Zookeeper 和 Kafka 经常一起使用&#xff0c;Zookeeper 在 Kafka 中扮演了关键角色。以下是 Zookeeper 和 Kafka 在实际项目中的结合使用及其作用的详细说明。 项目背景 假设我们有一个分布式数据处理系统&#xff0c;该系统需要高吞吐量的实…

300关卡成语释义典故题库ACCESS\EXCEL数据库

成语典故指关于成语产生、形成、流传的故事传说。成语有很大一部分是从古代相承沿用下来的&#xff0c;它既代表了一个故事典故&#xff0c;又是一种现成的话&#xff0c;很多又有比喻引申意义而被广泛引用。 今天又获得了一个成语游戏的数据&#xff0c;即根据成语典故或者释…