增加 Native 体系服务回调

本文配套源码下载地址:github.com/yuandaimaah…

首要咱们要清晰的是无论是从 client 调用 server, 还是 server 回调 client,本质上都是跨进程通讯,都是需要借助 binder 框架的。

接下来咱们在Binder 程序示例之 aidl-cpp 篇介绍的示例程序上修改,给它增加回调功能。

首要咱们在咱们的自界说 Product device/jelly/rice14 下创立如下的文件与文件夹(关于自界说 Product,请检查 增加 Product):

AIDLCppCallbackDemo
├── aidl.sh
├── Android.bp
├── com
│   └── yuandaima
│       ├── ICallback.aidl
│       └── IHello.aidl
├── HelloClient.cpp
└── HelloServer.cpp

AIDL 文件编写

其中 ICallback.aidl 是咱们界说的回调接口,其内容如下:

package com.yuandaima;
interface ICallback
{
    void onCallback(String str);
}

接着咱们经过如下指令,将 aidl 转换为对应的 cpp 源码:

# 第一个途径是头文件方位,会在这个途径下创立包对应的文件夹
# 第二途径是 cpp 文件途径
aidl-cpp com/yuandaima/ICallback.aidl ./ ./ICallback.cpp

经过上述指令生成如下的文件结构:

AIDLCppCallbackDemo
├── aidl.sh
├── Android.bp
├── com
│   └── yuandaima
│       ├── BnCallback.h
│       ├── BpCallback.h
│       ├── ICallback.aidl
│       ├── ICallback.h
│       └── IHello.aidl
├── HelloClient.cpp
├── HelloServer.cpp
└── ICallback.cpp

IHello.aidl 是咱们界说的 binder 服务端对外提供的服务接口,其内容如下:

package com.yuandaima;
import com.yuandaima.ICallback;
interface IHello
{
    void hello();
    int sum(int x, int y);
    void registerCallback(ICallback cb);
}

接着咱们经过如下指令,将 aidl 转换为对应的 cpp 源码:

# -I 用于指示咱们 import 的部分在哪里找
# 第一个途径是头文件方位,会在这个途径下创立包对应的文件夹
# 第二途径是 cpp 文件途径
aidl-cpp -I./com/yuandaima com/yuandaima/IHello.aidl ./ ./IHello.cpp

经过上述指令生成如下的文件结构:

AIDLCppCallbackDemo
├── aidl.sh
├── Android.bp
├── com
│   └── yuandaima
│       ├── BnCallback.h
│       ├── BnHello.h
│       ├── BpCallback.h
│       ├── BpHello.h
│       ├── ICallback.aidl
│       ├── ICallback.h
│       ├── IHello.aidl
│       └── IHello.h
├── HelloClient.cpp
├── HelloServer.cpp
├── ICallback.cpp
└── IHello.cpp

为了方便,咱们把两个指令写为一个 shell 脚本 aidl.sh,后边修改了 aidl 文件,直接运用 shell 脚本即可生成新的源码文件了

#!/bin/bash
aidl-cpp com/yuandaima/ICallback.aidl ./ ./ICallback.cpp
aidl-cpp -I./com/yuandaima com/yuandaima/IHello.aidl ./ ./IHello.cpp

服务端完成

服务端完成在 HelloServer.cpp 中:

#define LOG_TAG "aidl_cpp"
#include <log/log.h>
#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"
#include "com/yuandaima/ICallback.h"
#include "com/yuandaima/BpCallback.h"
using namespace android;
//界说服务端
class IHelloServer : public com::yuandaima::BnHello
{
private:
    //回调接口
    sp<com::yuandaima::ICallback> mCallback;
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;
        //运用回调接口
        if(mCallback.get() != nullptr) {
            mCallback->onCallback(String16("str from server"));
        }
        return binder::Status();
    }
    //注册回调接口
    binder::Status registerCallback(const sp<::com::yuandaima::ICallback>& cb) override 
    {
        ALOGI("Server registerCallback");
        mCallback = cb;
        return binder::Status();
    }
};
int main(int argc, char const *argv[])
{   
    ALOGD("HelloServer is running");
    defaultServiceManager()->addService(String16("IHello"), new IHelloServer());
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    return 0;
}

首要咱们需要界说咱们的服务端类 IHelloServer,这个类继承自 BnHello,这个类来自 aidl 生成的头文件 com/yuandaima/BnHello.h。咱们需要完成三个函数的服务端完成,咱们重点关注 registerCallback,该函数用于组成回调接口,会把回调目标保存在成员变量 mCallback 中,当咱们的调用到 sum 函数时,就会经过 mCallback 成员调用回调函数了。

客户端完成

#define LOG_TAG "aidl_cpp"
#include <log/log.h>
#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/ICallback.h"
#include "com/yuandaima/BnCallback.h"
using namespace android;
class MyCallback : public com::yuandaima::BnCallback {
public:
    binder::Status onCallback(const String16 &str) override {
        ALOGD("client: onCallback, receive str: %s", String8(str).string());
        return binder::Status();
    }
};
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();
    sp<MyCallback> myCallback = new MyCallback();
    hello->registerCallback(myCallback);
    int ret = 0;
    hello->sum(1, 2, &ret);
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    return 0;
}

与之前的示例 不同的是:

  • 完成 MyCallback 类,其父类为 BnCallback,来自生成的源码 com/yuandaima/BnCallback.h,在类中需要完成对应的回调函数,这儿简略打印一些信息。
  • 主函数中需要敞开线程池,因为 Client 端需要等候 Server 端的回调,所以需要敞开线程池,让程序继续运转下去。

编译与测验

编写 Android.bp 编译文件:

cc_binary {
    name: "BinderCallbackServer",
    srcs: ["HelloServer.cpp", "IHello.cpp","ICallback.cpp"],
    shared_libs: [
        "liblog",
        "libcutils",
        "libutils",
        "libbinder",
    ],
}
cc_binary {
    name: "BinderCallbackClient",
    srcs: ["HelloClient.cpp", "IHello.cpp","ICallback.cpp"],
    shared_libs: [
        "liblog",
        "libcutils",
        "libutils",
        "libbinder",
    ],
}

接着在项目目录下履行 mm 指令,编译当前模块。接着咱们把模拟器翻开,然后把可履行文件 push 到模拟器上:

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

接着进入模拟器 shell 环境,履行可履行文件:

adb shell
cd /data/local/tmp/
#履行服务端
./BinderCallbackServer &
#履行客户端
./BinderCallbackClient &

接着检查 log:

添加 Native 系统服务回调

从 log 的内容能够看出,咱们的回调函数履行成功了。

关于

我叫阿豪,2015 年本科结业于国防科技大学指挥自动化专业,结业后,从事信息化装备的研发作业。首要研讨方向为 Android Framework 与 Linux Kernel,2023年春节后开端做 Android Framework 相关的技能共享。

如果你对 Framework 感兴趣或许正在学习 Framework,能够参阅我总结的Android Framework 学习道路指南,也可关注我的微信大众号,我会在大众号上继续共享我的经历,协助正在学习的你少走一些弯路。学习过程中如果你有疑问或许你的经历想要共享给大家能够增加我的微信,我拉你进技能交流群。

添加 Native 系统服务回调

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。