使用aidl-cpp生成c++ Binder接口

使用aidl-cpp生成c++ Binder接口

Android小彩虹2021-08-20 18:16:57330A+A-

使用aidl-cpp生成c++ Binder接口

背景

"aidl"表达了几个相关但是不同的概念

  • AIDL接口定义语言
  • .aidl文件(含有AIDL)
  • 将aidl转换为client/server ipc接口

aidl生成器是一个命令行工具,它从一个以.aidl结尾的文件中生成了client和server stub的binder接口。对于java接口,调用的可行性文件为aidl,而对于c++文件来说,则调用的是aidl-cpp。在本文档中,我们将使用AIDL来描述.aidl文件,aidl生成器使用代码生成工具,解析.aidl文件中的AIDL,然后输出代码;

以前aidl生成器只会生成interface/proxy/stub的java代码,c++的binder接口是手工写的,与java对应兼容。Brillo项目增加了aidl生成器对c++的支持,生成的c++实现了跨语言兼容(例如:经过测试,java client可以与native server端进行交互)。

总览

本文档重点描述了c++是如何生成的:

  • 构建接口
  • 跨语言类型映射
  • 实现生成的接口
  • c++打包
  • 跨语言错误报告
  • 跨语言空引用处理
  • 跨语言整数常量

设计细节

建立接口

在以.aidl为后缀的文件中编写AIDL,然后添加到Android.mk的LOCAL_SRC_FILES中,如果构建目标是二进制文件(例如,include $(BUILD_SHARED_LIBRARY)),则生成的代码将是C ++,而不是Java。

AIDL的定义应该与实现位于同一资源库中,任何需要定义的系统都需要实现(包括parcelables和interface)。如果有多种实现(一种c++,一种java),则保持定义与native实现一致,Android系统现在具有无需java即可运行的native组件。

如果在AIDL中使用import语句,即使是在同一个package,也需要在LOCAL_AIDL_INCLUDES中添加所import文件的路径,此路径应该是相对于Android tree一个路径。例如:一个定义com.example.IFoo的IFoo.aidl文件,其路径层级结构为something/something-else/com/example/IFoo.aidl。然后我们就应该写:

LOCAL_AIDL_INCLUDES := something/something-else

最终生成的C++位于对应于接口包的嵌套名称空间中,生成的header也对应于接口包。例如:package com.example.IFoo,对应于namespace ::com::example::IFoo,头文件路径对应在“com/example/IFoo.h”。

类似于Java的工作方式,以.aidl结尾得文件路径必须匹配对应得package。如果IFoo.aidl声明自己在com.example的package中,则目录结构(如添加于LOCAL_SRC_FILES)必须类似于:/some/prefix/com/example/IFoo.aidl

如果需要从其他build target(例如其他二进制文件或者java)中.aidl文件生成代码,只需要添加.aidl的相对路径到LOCAL_SRC_FILES。其他目录中的代码导入AIDL的操作也是一样:添加其root路径(.aidl文件的root路径)到LOCAL_AIDL_INCLUDES

补充(重要)

以上讲述全部基于Android.mk文件,那对应到Android.bp文件如何呢?以举例方式比较如下

Android.bp类似于一种json描述;Android.mk看上去就是一种环境变化的赋值过程;

假设目前/some/prefix/com/example/IFoo.aidl待应用,IFoo在com/example包中,Bn端继承的时候需要public com::example::BnIFoo,bp端就是讲iBinder转为com::example::IIFoo,实际上调用的是bpIFoo,最后通过bpBinder进行IPC,具体使用细节参考binder知识。

上述描述的Android.mk中的LOCAL_SRC_FILES用法:

LOCAL_SRC_FILES := /some/path
LOCAL_SRC_FILES += /some/prefix/com/example/IFoo.aidl

对应于Android.bp中会是:

src: [
    "/some/path",
] + [
    "/some/prefix/com/example/IFoo.aid",
],

上述描述中android.mk中的LOCAL_AIDL_INCLUDES的用法:

LOCAL_AIDL_INCLUDES += /some/prefix

对应于android.bp中会是:

aidl: {
    include_dirs: ["/some/prefix"]
}

通过以上示例,细品,不多赘述了!

类型映射

下表总结了c++类型对应的Java类型,在AIDL文件中可能会用于in/out/inout参数。

Java type c++ type inout Notes
boolean bool in "前8种类型被认为是基本类型"
byte int8_t in
char char16_t in
int int32_t in
long int64_t in
float float in
double double in
String String16 in 支持空引用
android.os.Parcelable android::Parcelable inout
T extends IBinder sp in
Arrays( T[ ] ) vector inout
List vector inout
PersistableBundle PersistableBundle inout binder/PersistableBundle.h
List vector<sp> inout
FileDescriptor ScopedFd inout nativehelper/ScopedFd.h

请注意,java.util.Map和java.utils.List并不是跨语言通信的良好选择,因为它们在Java端可能包含任意类型。例如,将Map强制转换为Map <String,Object>,然后动态检查对象值并将其序列化为类型/值对。支持发送任意Java可序列化文件,Android捆绑软件等。

实现生成的接口

给定一个接口声明,例如:

package foo;

import bar.IAnotherInterface;

interface IFoo {
  IAnotherInterface DoSomething(int count, out List<String> output);
}

aidl-cpp 将会生成c++接口:

namespace foo {

// Some headers have been omitted for clarity.
#include <android/String16.h>
#include <cstdint>
#include <vector>
#include <bar/IAnotherInterface.h>

// Some class members have been omitted for clarity.
class IFoo : public android::IInterface {
 public:
  virtual android::binder::Status DoSomething(
      int32_t count,
      std::vector<android::String16>* output,
      android::sp<bar::IAnotherInterface>* returned_value) = 0;
};

请注意,这aidl-cpp将导入.aidl文件中使用的导入的包类型。对于导入的类型(例如:包裹和接口),它将导入与导入的包/类名称相对应的标头。例如,import bar.IAnotherInterface。aidl-cpp生成#include <bar/IAnotherInterface.h>

当编写service端的是实现时:

#include "foo/BnFoo.h"

namespace unrelated_namespace {

class MyFoo : public foo::BnFoo {
 public:
  android::binder::Status DoSomething(
      int32_t count,
      std::vector<android::String16>* output,
      android::sp<bar::IAnotherInterface>* returned_value) override {
    for (int32_t i = 0; i < count; ++i) {
      output->push_back(String16("..."));
    }
    *returned_value = new InstanceOfAnotherInterface;
    return Status::ok();
  }
};  // class MyFoo

}  // namespace unrelated_namespace

注意输出值output和returned_value通过指针传递,并且始终有效。

C++ Parcelables

parcelables可理解为:binder传输中的可打包对象。

在Java中,一个parcelables应该扩展android.os.Parcelable,并提供static final CREATOR的实现,另外如果需要做out参数的话,还需要提供一个readFormPacel方法。

在C++中,parcelables必须实现android::Parcelable,该原文件位于libbinder中的binder/Parcelable.h。Parcelables必须定义一个无参构造器,为了在数组中使用,一个parcelable必须实现一个拷贝构造器或者移动构造(在vector中隐式调用)。

C++ AIDL生成器需要知道parcelables定义在那个头文件中,他会从如下的cpp_header指令而得知。生成器会能拿到此字串bar/foo.h,并将其用include包含。

// ExampleParcelable.aidl
package com.example.android;

// Native types must be aliased at their declaration in the appropriate .aidl
// file.  This allows multiple interfaces to use a parcelable and its C++
// equivalent without duplicating the mapping between the C++ and Java types.
// Generator will assume bar/foo.h declares class
// com::example::android::ExampleParcelable
parcelable ExampleParcelable cpp_header "bar/foo.h";

空引用处理

异常报告

整数常量

(后面三项暂时先不看了,用到再说)

android.googlesource.com/platform/sy…

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1
本网站由 提供CDN/云存储服务

联系我们