Ahao's Technical Blog Ahao's Technical Blog
首页
  • 001.基础篇
  • 002.玩转AOSP篇
  • 003.学穿Binder篇
  • 004.基础组件篇
  • 005.系统启动过程分析
  • 006.Hal开发入门与实践
  • 007.显示系统
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

阿豪讲Framework

不积跬步无以至千里
首页
  • 001.基础篇
  • 002.玩转AOSP篇
  • 003.学穿Binder篇
  • 004.基础组件篇
  • 005.系统启动过程分析
  • 006.Hal开发入门与实践
  • 007.显示系统
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 基础篇

  • 玩转AOSP篇

  • 学穿Binder篇

    • 000.Binder 专题导学 —— 如何深入掌握 Binder
    • 001.学习 Binder 的预备知识
    • 002.Binder 基本原理
    • 003.Binder 程序示例之 C 语言篇
    • 004.Binder 服务注册过程情景分析之 C 语言篇
    • 005.Binder 服务获取与使用过程情景分析之C语言篇
    • 006.Android Binder 驱动框架设计与分析
    • 007.Binder 驱动情景分析之 ServiceManager 启动过程
    • 008.Binder 驱动情景分析之服务注册过程
    • 009.Binder 驱动情景分析之服务获取与使用过程
    • 010.Binder 程序示例之 C++ 篇
    • 011.Binder C++ 程序分析之主要类解析
    • 012.Binder 服务注册过程情景分析之 C++ 篇
    • 013.Binder 服务获取与使用过程情景分析之C++篇
    • 014.Binder 程序示例之 aidl-cpp 篇
    • 015.添加 Android Native 系统服务
    • 016.添加 Native 系统服务回调
    • 017.Binder 程序示例之 Java 篇
    • 018.Binder Java 层初始化
    • 019.Binder Java 层服务注册过程分析
    • 020.Binder Java 层服务获取与使用过程分析
    • 021.添加 Java 系统服务
    • 022.Android Java 系统服务框架与第三方 App 使用自定义 Java 系统服务
    • 023.添加 Java 系统服务回调
    • 024.AIDL 数据类型详解之 Java 篇
    • 025.AIDL 数据类型详解之 C++ 篇
      • AIDL 中的数据结构
      • Native 示例程序
      • 参考资料
    • 026.Java 调用 Native 服务
    • 027.Native 调用 Java Binder 服务
    • 028.AIDL 关键字 in out inout oneway 解析
    • 029.Binder 驱动 Debug 入门指南
    • 030.Binder 匿名服务源码分析
    • 031.Binder 中的 Parcel 数据结构分析(C++)
    • 032.Binder 中的 Parcel 数据结构分析(Java)
    • 033.Binder 多线程情景分析
    • 034.Binder 线程池溢出问题
    • 035.Binder 代理对象泄露问题分析
    • 036.Binder 死亡通知情景分析
    • 037.Binder 异常处理机制
    • 038.Binder 系统源码演进
    • 039.Binder 面试题汇总
    • 补充——LocalService
  • 基础组件篇

  • 系统启动过程分析

  • Hal开发入门与实践

  • 显示系统

  • Framework
  • 学穿Binder篇
阿豪
2023-08-06
目录

025.AIDL 数据类型详解之 C++ 篇

# AIDL 中的数据结构

在上文我们说到 AIDL 中支持的数据类型,这里我们再回顾一下:

在 Java 层,AIDL 支持以下多种数据类型:

  • Java 编程语言中的所有的基本类型(如 int、long、char、boolean 等)
  • String 与 CharSequence
  • List:List 中的所有元素必须是 AIDL 支持的数据类型,生成的方法旨在使用 List 接口,但另一方实际接收的具体类始终是 ArrayList
  • Map:Map 中的所有元素必须是 AIDL 支持的数据类型,不支持泛型 Map(如 Map<String,Integer> 形式的 Map),生成的方法旨在使用 Map 接口,但另一方实际接收的具体类始终是 HashMap
  • 生成的方法旨在使用 Map 接口,但另一方实际接收的具体类始终是 HashMap。
  • Parcelable 类型

Native 层支持类似的数据类型,这些类型与 Java 层的对应关系如下:

kua

# Native 示例程序

接下来我们就来写一个演示 AIDL 数据类型的 Native层 示例程序:

首先我们在 device/jelly/rice14/ 目录下创建如下的文件与文件夹

AIDLCppTypeDemo
├── Android.bp
├── com
│   └── yuandaima
│       ├── IHello.aidl
│       ├── Student.aidl
│       ├── Student.cpp
│       └── Student.h
├── HelloClient.cpp
└── HelloServer.cpp
1
2
3
4
5
6
7
8
9
10

其中的 Student.aidl Student.h Student.cpp 是我们自定义的数据类型,在 AIDL 中自定义数据类型需要继承 Parcelable:

//Student.h
#ifndef _COM_YUANDAIMA_STUDENT_H
#define _COM_YUANDAIMA_STUDENT_H

#include <android-base/unique_fd.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <binder/Status.h>
#include <utils/RefBase.h>
#include <vector>

using namespace std;
using namespace android;

namespace com {
namespace yuandaima {

    class Student : public Parcelable {
        public:
            Student();
            virtual ~Student();
            
            virtual status_t writeToParcel(Parcel* out) const;
            virtual status_t readFromParcel(const Parcel* in); 

            void setAge(int32_t age);
            int32_t getAge();
            void setName(String16 name);
            String16 getName();
        private:
            String16 mName;
            int32_t mAge;
    };

}
}
#endif

// Student.cpp
#include "Student.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

using namespace std;
using namespace android;

namespace com {
namespace yuandaima {

    Student::Student() {
        this->setAge(20);
        this->setName(String16("jack"));
    }

    Student::~Student() {
    }

    status_t Student::writeToParcel(Parcel* out) const {
        status_t err;
        err = out->writeString16(mName);
        if (err != NO_ERROR) {
            return err;
        }
        err = out->writeInt32(mAge);
        if (err != NO_ERROR) {
            return err;
        }
        return NO_ERROR;
    }

    status_t Student::readFromParcel(const Parcel* in) {
        status_t err;
        err = in->readString16(&mName);
        if (err != NO_ERROR) {
            return err;
        }
        err = in->readInt32(&mAge);
        if (err != NO_ERROR) {
            return err;
        }

        return NO_ERROR;
    }

    int32_t Student::getAge() const {
        return mAge;
    }

    String16 Student::getName() const {
        return mName;
    }

    void Student::setAge(int32_t age) {
        mAge = age;
    }
    void Student::setName(String16 name) {
        mName = name;
    }

}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

在 aidl 中我们只需要简单声明即可:

//Student.aidl
package com.yuandaima;

parcelable Student cpp_header "com/yuandaima/Student.h";
1
2
3
4

与 Java 不同的是,我们需要指定对应的头文件。

IHelloService.aidl 中声明了我们 binder 服务的对外接口:

package com.yuandaima;

import com.yuandaima.Student;

interface IHello
{
    void hello();
    int sum(int x, int y);
    int printList(in List<String> strs);
	int printMap(in Map maps);
    int printStudent(in Student student);
}
1
2
3
4
5
6
7
8
9
10
11
12

接着我们编译 aidl 文件:

# 源码目录下
source build/envsetup.sh
# 选择合适的 product
lunch

# 进入项目目录下
# -I 用于指定我们的在哪里查找 import
aidl-cpp -I . com/yuandaima/IHello.aidl ./ ./IHello.cpp
1
2
3
4
5
6
7
8

编译后,生成了对应的 h 和 cpp 文件,整个项目结构如下:

AIDLCppTypeDemo
├── Android.bp
├── com
│   └── yuandaima
│       ├── BnHello.h
│       ├── BpHello.h
│       ├── IHello.aidl
│       ├── IHello.h
│       ├── Student.aidl
│       ├── Student.cpp
│       └── Student.h
├── HelloClient.cpp
├── HelloServer.cpp
└── IHello.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14

接着服务端类和服务端主程序 HelloServer.cpp:

#define LOG_TAG "aidl_cpp"

#include <stdlib.h>
#include <utils/RefBase.h>
#include <utils/Log.h>
#include <binder/TextOutput.h>
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>

#include "com/yuandaima/IHello.h"
#include "com/yuandaima/BnHello.h"

using namespace android;

class IHelloServer : public com::yuandaima::BnHello
{
public:
    binder::Status hello() override
    {
        ALOGI("hello");
        return binder::Status();
    }

    binder::Status sum(int32_t v1, int32_t v2, int32_t *_aidl_return) override
    {
        ALOGI("server: sum: %d + %d", v1, v2);
        *_aidl_return = v1 + v2;
        return binder::Status();
    }

    binder::Status printList(const ::std::vector<::android::String16>& strs, int32_t* _aidl_return) override
    {
        for (const auto & str : strs)
        {
            ALOGI("%s", String8(str).c_str());
        }

        *_aidl_return = 1;
        return binder::Status();
    }

    binder::Status printMap(const ::android::binder::Map& maps, int32_t* _aidl_return) override
    {
        for(auto it : maps){
            std::string val;
            it.second.getString(&val);
            ALOGI("key is %s, value is %s", it.first.c_str(), val.c_str());
        }
        *_aidl_return = 1;
        return binder::Status();
    }

    binder::Status printStudent(const ::com::yuandaima::Student& student, int32_t* _aidl_return) override
    {

        ALOGI("name is %s, age is %d", String8(student.getName()).c_str(), student.getAge());
        *_aidl_return = 1;
        return binder::Status();
    }

};

int main(int argc, char const *argv[])
{
    defaultServiceManager()->addService(String16("IHello"), new IHelloServer());
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

接着完成客户端程序 HelloClient.cpp :

#define LOG_TAG "aidl_cpp"

#include <stdlib.h>
#include <utils/RefBase.h>
#include <utils/Log.h>
#include <binder/TextOutput.h>
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>

#include "com/yuandaima/IHello.h"
#include "com/yuandaima/BpHello.h"
#include "com/yuandaima/Student.h"

using namespace android;

int main(int argc, char const *argv[]) {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("IHello"));
    sp<com::yuandaima::IHello> hello = interface_cast<com::yuandaima::IHello>(binder);

    hello->hello();
    int ret = 0;
    hello->sum(1, 2, &ret);

    ::std::vector<::android::String16> strs;
    int32_t result1;
    strs.emplace_back("Hello Binder");

    hello->printList(strs, &result1);

    ::android::binder::Map maps;
    maps.insert(::android::binder::Map::value_type("test", ::android::binder::Value("Test")));
    int32_t result2;
    hello->printMap(maps, &result2);

    com::yuandaima::Student student;
    int32_t result3;
    hello->printStudent(student, &result3);


    return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

最后编译测试:

# 项目目录下执行单编
mm
# 回到系统源码目录
adb push out/target/product/rice14/system/bin/IHelloTypeServer /data/local/tmp

adb push out/target/product/rice14/system/bin/IHelloTypeClient /data/local/tmp

# 进入模拟器 shell 环境
adb shell
cd /data/local/tmp

# 执行服务端
./IHelloTypeServer & 
# 执行客户端
./IHelloTypeClient 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

接着查看log:

logcat | grep aidl_cpp

08-07 10:57:44.372  2824  2825 I aidl_cpp: hello
08-07 10:57:44.372  2824  2825 I aidl_cpp: server: sum: 1 + 2
08-07 10:57:44.373  2824  2825 I aidl_cpp: Hello Binder
08-07 10:57:44.373  2824  2825 I aidl_cpp: key is test, value is 
08-07 12:04:57.181 10985 10986 I aidl_cpp: hello
08-07 12:04:57.182 10985 10986 I aidl_cpp: server: sum: 1 + 2
08-07 12:04:57.182 10985 10986 I aidl_cpp: Hello Binder
08-07 12:04:57.182 10985 10986 I aidl_cpp: key is test, value is 
08-07 12:07:48.053 11334 11335 I aidl_cpp: hello
08-07 12:07:48.053 11334 11335 I aidl_cpp: server: sum: 1 + 2
08-07 12:07:48.054 11334 11335 I aidl_cpp: Hello Binder
08-07 12:07:48.054 11334 11335 I aidl_cpp: key is test, value is 
08-07 12:07:48.054 11334 11335 I aidl_cpp: name is jack, age is 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

从 log 可以看出我们的程序指针成功了。

# 参考资料

  • Android 接口定义语言 (AIDL) (opens new window)
  • Generating C++ Binder Interfaces with aidl-cpp (opens new window)
  • AIDL interface between Java and C++ (opens new window)
024.AIDL 数据类型详解之 Java 篇
026.Java 调用 Native 服务

← 024.AIDL 数据类型详解之 Java 篇 026.Java 调用 Native 服务→

最近更新
01
如何调试 SurfaceFlinger
10-05
02
SurfaceFlinger 概述
10-05
03
HWC 接口分析
10-05
更多文章>
Theme by Vdoing | Copyright © 2020-2025 AHao Framework | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式