使用aidl文件通信共分为以下几步

1、编写aidl文件,包含ISample.aidl与ICallback.aidl两个
2、使用.md文件编译aidl,生成lib库和相关的.h .cpp文件
3、继承生成的.h .cpp文件,写出自己的服务端.h .cpp文件
4、使用.md文件编译服务端的.h .cpp,生成可执行文件
5、在Android Studio中写出客户端文件,用于测试客户端与服务端是否能进行通信
6、在终端中运行可执行文件,客户端开启。观察log打印情况,判断是否能通

aosp环境配置

将相关环境拷贝到本地,将imx8配置好,这里aosp环境配置略过。

编写与编译aidl文件

aidl文件的编写

  1. 新建aidl文件夹,在aidl-sample子文件夹下编写aidl文件,这里编写两个aidl文件,分别为ISample.aidl与ICallback.aidl。

  2. ISample.aidl文件内容如下:

package sample;
import sample.ICallback;

interface ISample {
    void Foo(int n, out List<String> output);
    void registerCallback(in ICallback cb);
}
  1. ICallback.aidl文件内容如下:
package sample;

interface ICallback {
    void onRecvData(int anInt);
}

aidl文件的编译

  1. Android.mk文件

使用Android.mk文件,对aidl接口进行编译,编译出相关的Bn.h Bp.h等文件
Android.mk文件内容如下:

LOCAL_C_INCLUDES :=             \
            $(TOP)frameworks/native/include \
            $(TOP)system/core/base/include \
			$(TOP)/device/android_aidl/service/aidl/sample
LOCAL_SRC_FILES := $(call all-Iaidl-files-under, sample)
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/sample \
                       $(LOCAL_PATH)/aidl \
                       $(LOCAL_PATH)



LOCAL_SHARED_LIBRARIES := \
            libbinder \
            libcutils \
            liblog \
            libutils

LOCAL_MODULE := libsample-aidl
include $(BUILD_SHARED_LIBRARY)
  1. 编译命令如下
    在aosp环境下,进入docker环境下,使用以下命令编译aidl文件
make libsample-aidl

运行结束后,可以在终端显示的路径下找到对应的lib库与Bn Bp文件
在这里插入图片描述

编写与编译服务端代码

根据生成的BnSample.h 文件,编写出自己的服务端头文件,sample.h

  1. 生成的BnSample.h文件如下
#pragma once

#include <binder/IInterface.h>
#include <sample/ISample.h>

namespace sample {
class BnSample : public ::android::BnInterface<ISample> {
public:
  static constexpr uint32_t TRANSACTION_Foo = ::android::IBinder::FIRST_CALL_TRANSACTION + 0;
  static constexpr uint32_t TRANSACTION_registerCallback = ::android::IBinder::FIRST_CALL_TRANSACTION + 1;
  explicit BnSample();
  ::android::status_t onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) override;
};  // class BnSample

class ISampleDelegator : public BnSample {
public:
  explicit ISampleDelegator(::android::sp<ISample> &impl) : _aidl_delegate(impl) {}

  ::android::binder::Status Foo(int32_t n, ::std::vector<::android::String16>* output) override {
    return _aidl_delegate->Foo(n, output);
  }
  ::android::binder::Status registerCallback(const ::android::sp<::sample::ICallback>& cb) override {
    return _aidl_delegate->registerCallback(cb);
  }
private:
  ::android::sp<ISample> _aidl_delegate;
};  // class ISampleDelegator
}  // namespace sample

  1. 继承BnSample.h,编写自己的SampleService.h文件,如下:
#ifndef SAMPLE_SERVICE_H
#define SAMPLE_SERVICE_H
#include <vector>
#include<BnSample.h>
using namespace android;
class sampleService : public sample::BnSample {
public:
    sampleService();
    ~sampleService();
	
	virtual ::android::binder::Status registerCallback(const ::android::sp<::sample::ICallback>& in_cb); 
    virtual ::android::binder::Status Foo(int32_t n, ::std::vector<::android::String16>* output);
private:
    ::android::sp<::sample::ICallback> mCallback;
}; 


#endif  // SAMPLE_SERVICE_H
  1. 在SampleService.cpp中将相关方法实现,SampleService.cpp文件内容如下:
#include "sampleService.h"
using namespace android;

sampleService::sampleService() {

}
sampleService::~sampleService() {

}
::android::binder::Status sampleService::registerCallback(const ::android::sp<::sample::ICallback>& in_cb)
{
	mCallback = in_cb;
    return ::android::binder::Status::ok(); 
}
::android::binder::Status sampleService::Foo(int32_t n, ::std::vector<::android::String16>* output) {
    for(int i = 0; i < n; i++) {
		 output->push_back(String16("Hello"));
    }
	if (mCallback) {
		mCallback->onRecvData(n);
	}
    return ::android::binder::Status::ok(); 
}

  1. 在sample_main.cpp中调用service中的相关方法,启动服务器
#include <sys/types.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/log.h>
#include "sampleService.h"

using namespace android;
int main(int argc, char** argv) {
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    ALOGI("EOLServiceManager: %p", sm.get());
    sm->addService(String16("sampleService"), new sampleService());
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    return 0;
} 

编译服务端代码生成可执行文件

将上述sampleService.h sampleService.cpp sample_main.cpp三个文件通过Android.mk编译成可执行文件sample
其中,Android.mk文件内容如下:
(上半部分为编写库的代码,下半部分依赖这个库编出可执行文件sample)

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES :=             \
            $(TOP)frameworks/native/include \
            $(TOP)system/core/base/include \
			$(TOP)/device/android_aidl/service/aidl/sample
LOCAL_SRC_FILES := $(call all-Iaidl-files-under, sample)
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/sample \
                       $(LOCAL_PATH)/aidl \
                       $(LOCAL_PATH)
LOCAL_SHARED_LIBRARIES := \
            libbinder \
            libcutils \
            liblog \
            libutils
LOCAL_MODULE := libsample-aidl
include $(BUILD_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_SRC_FILES:=\
		sampleService.cpp \
		sample_main.cpp
LOCAL_MODULE_TAGS := optional

LOCAL_C_INCLUDES :=  \
	$(TOP)/frameworks/native/include \
	$(TOP)/system/core/base/include \
	$(TOP)/device/aidltest_callback/service/aidl \
	$(TARGET_OUT_INTERMEDIATES)/SHARED_LIBRARIES/libsample-aidl_intermediates/aidl-generated/include/sample
LOCAL_SHARED_LIBRARIES := \
			libbinder \
			libcutils \
			liblog \
			libutils \
			libsample-aidl \

LOCAL_MODULE:= sampleService

include $(BUILD_EXECUTABLE)

将编译出的lib库与sample可执行文件推入虚拟机中

adb push … /data

编写客户端代码

新建一个工程,用于编写客户端

1、编译客户端的aidl文件

  1. 将aidl文件拷贝到客户端的aidl文件夹下
    一定要在aidl文件夹下,AS编译时才能正确识别

  2. 在AS的build.gradle脚本中,添加有关于aidl编译的脚本

 buildFeatures{
        aidl = true
    }
  1. 先将aid文件编译出来,会生成如下所示的相关aidl文件
    在这里插入图片描述

编写客户端代码

1 相关的界面布局

在activity.html界面中,添加一段按钮相关的代码

<Button
        android:id="@+id/bt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        tools:ignore="MissingConstraints"/>

在Android.xml中设置相关代码,

android:theme="@style/Theme.MyAIDLEOL"
2 客户端代码

这里客户端需要做的:
(1)将相关的aidl文件导入

import sample.ICallback;
import sample.IEOL;

(2)重写callback的相关方法(模拟app端)

public ICallback.Stub cb = new ICallback.Stub() {
        @Override
        public void RadioTest(boolean active) {
            Log.d("hugo", "hugo, RadioTest called");
        }
 }

(3)添加一个按钮点击事件,点击按钮后
获取服务器
当bindService之后,客户端会得到一个Binder引用
通过asInterface得到一个IEOL的实例
后续调用IEOL实例中的相关方法和回调函数

客户端相关代码如下:

package com.example.service;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import sample.ISample;
import sample.ICallback;
import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.Method;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;

import com.example.myapplication.R;

public class MainActivity extends AppCompatActivity{
    List<String> list = new ArrayList<String>();
    public ICallback.Stub cb = new ICallback.Stub() {
        @Override
        public void onRecvData(int anInt) {
            Log.d("hugo", "hugo, OnRecvData called");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button bt = (Button)findViewById(R.id.bt);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    Method getServiceMethod = Class.forName("android.os.ServiceManager")
                            .getDeclaredMethod("getService", new Class[]{String.class});
                    Object serviceManager = getServiceMethod.invoke(null, new Object[]{"sampleService"});
                    ISample sample = ISample.Stub.asInterface((IBinder) serviceManager);
                    Log.d("hugo", "service: " + sample);
                    sample.registerCallback(cb);
                    Log.d("hugo", "registered");
                    sample.Foo(5,list);
                    Log.d("hugo", "list" + list);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                Log.d("hugo", "size = " + list.size());
            }
        });
    }
}

运行服务端 观察客户端log打印情况

  1. 在AS终端中进入到虚拟机后,运行sample可执行文件
adb shell
cd data
chmod 777 sampleService
export LD_LIBRARY_PATH=.
./sampleService
  1. 在logcat中,过滤出与hugo有关的日志,观察服务端方法的执行情况
    以下为示例log
    在这里插入图片描述
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐