在aosp环境下使用aidl进行通信
本文介绍了如何在aosp环境下,使用aidl进行跨进程通信,通过一个小的sample来实现。
在aosp环境下使用含有callback的aidl进行通信
使用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文件的编写
-
新建aidl文件夹,在aidl-sample子文件夹下编写aidl文件,这里编写两个aidl文件,分别为ISample.aidl与ICallback.aidl。
-
ISample.aidl文件内容如下:
package sample;
import sample.ICallback;
interface ISample {
void Foo(int n, out List<String> output);
void registerCallback(in ICallback cb);
}
- ICallback.aidl文件内容如下:
package sample;
interface ICallback {
void onRecvData(int anInt);
}
aidl文件的编译
- 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)
- 编译命令如下
在aosp环境下,进入docker环境下,使用以下命令编译aidl文件
make libsample-aidl
运行结束后,可以在终端显示的路径下找到对应的lib库与Bn Bp文件
编写与编译服务端代码
根据生成的BnSample.h 文件,编写出自己的服务端头文件,sample.h
- 生成的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
- 继承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
- 在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();
}
- 在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文件
-
将aidl文件拷贝到客户端的aidl文件夹下
一定要在aidl文件夹下,AS编译时才能正确识别 -
在AS的build.gradle脚本中,添加有关于aidl编译的脚本
buildFeatures{
aidl = true
}
- 先将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打印情况
- 在AS终端中进入到虚拟机后,运行sample可执行文件
adb shell
cd data
chmod 777 sampleService
export LD_LIBRARY_PATH=.
./sampleService
- 在logcat中,过滤出与hugo有关的日志,观察服务端方法的执行情况
以下为示例log
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)