1. 下载 AOSP源码,配置编译环境

2. 目录结构

device下新建一个sample目录保存我们即将写的native服务,我的目录结构如下,这个service将在sample目录中实现。

    device
        |
        | -xx
            |-service
                |-sample
                    |-aidl
                    |-include
                    |-process
                    |-service
                    |-test
                    Android.mk

3. 编写AIDL文件

新建AIDL文件ISample.aidl,声明接口,接口名称要与文件名一致。 in/out来表示是输入/输出参数,默认是in,out参数在最终生成的从C++源文件会以指针实现。这里定义了一个DoSomething接口,有两个参数:n和一个内含string的vector,功能是返回n个"Hello"在ouput数组中。

1
2
3
4
5
package sample;

interface ISample {
void DoSomething(int n, out List<String> output);
}

新建一个Android.mk文件,编译生成对应的lib库以及头文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:=\
            sample/ISample.aidl \

LOCAL_MODULE_TAGS := optional

LOCAL_C_INCLUDES :=             \
            $(TOP)/frameworks/native/include \
            $(TOP)/system/core/base/include \

LOCAL_SHARED_LIBRARIES := \
            libbinder \
            libcutils \
            liblog \
            libutils \

LOCAL_MODULE:=libsample-aidl


include $(BUILD_SHARED_LIBRARY)

编译会生成BnSample.h,BpSample.h和ISample.h三个头文件,在out/target/product/generic_x86_64/obj/SHARED_LIBRARIES/libsample-aidl_intermediates/aidl-generated 目录下。同级的src目录下还有对应的cpp源文件ISample.cpp,AIDL帮我们实现好了这些格式化的文件,自己手写实现也是可以的。

4. 实现 sampleService

sampleService.h, sampleService继承自BnSample。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#ifndef SAMPLE_SERVICE_H
#define SAMPLE_SERVICE_H

#include<BnSample.h>
#include <vector>

namespace android {

class sampleService : public sample::BnSample {
public:

    sampleService();
    ~sampleService();
    virtual ::android::binder::Status DoSomething(int32_t n, ::std::vector<::android::String16>* output);
}; 

}

#endif  // SAMPLE_SERVICE_H

sampleService.cpp,在此实现DoSomething的逻辑,这里就简单的把n个"Hello"塞到vector中返回。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include"sampleService.h"

using namespace android;

sampleService::sampleService() {

}

sampleService::~sampleService() {
    
}

::android::binder::Status sampleService::DoSomething(int32_t n, ::std::vector<::android::String16>* output) {

    for(int i = 0; i < n; i++) {
        output->push_back(String16("Hello"));
    }

    return ::android::binder::Status::ok(); 
}

service的Android.mk 如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:=\
            sampleService.cpp \

LOCAL_MODULE_TAGS := optional

LOCAL_C_INCLUDES :=             \
            $(TOP)/frameworks/native/include \
            $(TOP)/system/core/base/include \
            $(TOP)/device/x/eva0/framerworks/service/sample/include \
            $(TARGET_OUT_INTERMEDIATES)/SHARED_LIBRARIES/libsample-aidl_intermediates/aidl-generated/include/sample

LOCAL_SHARED_LIBRARIES := \
            libbinder \
            libcutils \
            liblog \
            libutils \
            libsample-aidl \

LOCAL_MODULE:=libsampleservice

include $(BUILD_SHARED_LIBRARY)

然后我们需要一个进程来承载我们的service,在process目录下新建sample_main.cpp文件,在main函数中调用serviceManager的addService方法将我们的service注册进去,以便客户端可以找到。

 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
#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("ServiceManager: %p", sm.get());

    sm->addService(String16("sampleService"), new sampleService());

    ProcessState::self()->startThreadPool();

    IPCThreadState::self()->joinThreadPool();

    return 0;

}

对应的的mk如下,编译生成的sampleService就是我们service的可执行文件。

 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
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
 
LOCAL_SRC_FILES:=\
			sample_main.cpp \
 
LOCAL_MODULE_TAGS := optional
 
LOCAL_C_INCLUDES :=             \
			$(TOP)/frameworks/native/include \
			$(TOP)/system/core/base/include \
			$(TOP)/device/x/eva0/framerworks/service/sample/include \
			$(TARGET_OUT_INTERMEDIATES)/SHARED_LIBRARIES/libsample-aidl_intermediates/aidl-generated/include/sample

LOCAL_SHARED_LIBRARIES := \
			libbinder \
			libcutils \
			liblog \
			libutils \
			libsample-aidl \
			libsampleservice \

LOCAL_MODULE:= sampleService
 
include $(BUILD_EXECUTABLE)	
	

6. 实现客户端

客户端就是通过serviceManager取得sampleService的指针后,简单的调用下DoSomething接口, n值传入3,并把返回的vector打印出来。

 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
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <utils/Errors.h>
#include <stdio.h>
#include <String16.h>
#include <String8.h>
#include <vector>
#include <iostream>
#include "sampleService.h"

using namespace android;

int main () {

    sp<sample::ISample> sample_srv = interface_cast<sample::ISample>(defaultServiceManager()->getService(String16("sampleService")));

    std::vector<String16> hellos;
    sample_srv->DoSomething(3, &hellos);

    for (String16 s:hellos ) {
        std::cout << String8(s.string()).string() << std::endl;
    }

    return 0;
}

客户端的mk文件

 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
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:=\
            sample_test.cpp \

LOCAL_MODULE_TAGS := optional

LOCAL_C_INCLUDES :=             \
            $(TOP)/frameworks/native/include \
            $(TOP)/system/core/base/include \
            $(TOP)/device/x/service/sample/include \
            $(TOP)/system/core/include/utils \
            $(TOP)/device/x/eva0/framerworks/service/sample/include \
            $(TARGET_OUT_INTERMEDIATES)/SHARED_LIBRARIES/libsample-aidl_intermediates/aidl-generated/include/sample

LOCAL_SHARED_LIBRARIES := \
            libbinder \
            libcutils \
            liblog \
            libutils \
            libsample-aidl \
            libsampleservice \

LOCAL_MODULE:= sampletest

include $(BUILD_EXECUTABLE)	

7. 测试

lunch之后输入emulator启动模拟器,将sampleService和Sampletest push进模拟器。

1
2
sampleService &
sampletest

我们客户端传入的参数是3,所以输出三行Hello就代表成功了。

8. 参考

https://android.googlesource.com/platform/system/tools/aidl/+/brillo-m10-dev/docs/aidl-cpp.md