添加 Native 系统服务回调

添加 Native 系统服务回调

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

首先我们要明确的是无论是从 client 调用 server, 还是 server 回调 client,本质上都是跨进程通信,都是需要借助 binder 框架的。

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

首先我们在我们的自定义 Product device/jelly/rice14 下创建如下的文件与文件夹(关于自定义 Product,请查看 添加 Product):

bash 复制代码
AIDLCppCallbackDemo
├── aidl.sh
├── Android.bp
├── com
│   └── yuandaima
│       ├── ICallback.aidl
│       └── IHello.aidl
├── HelloClient.cpp
└── HelloServer.cpp

AIDL 文件编写

其中 ICallback.aidl 是我们定义的回调接口,其内容如下:

java 复制代码
package com.yuandaima;

interface ICallback
{
    void onCallback(String str);
}

接着我们通过如下命令,将 aidl 转换为对应的 cpp 源码:

bash 复制代码
# 第一个路径是头文件位置,会在这个路径下创建包对应的文件夹
# 第二路径是 cpp 文件路径
aidl-cpp com/yuandaima/ICallback.aidl ./ ./ICallback.cpp

通过上述命令生成如下的文件结构:

bash 复制代码
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 服务端对外提供的服务接口,其内容如下:

bash 复制代码
package com.yuandaima;

import com.yuandaima.ICallback;

interface IHello
{
    void hello();
    int sum(int x, int y);
    void registerCallback(ICallback cb);
}

接着我们通过如下命令,将 aidl 转换为对应的 cpp 源码:

bash 复制代码
# -I 用于指示我们 import 的部分在哪里找
# 第一个路径是头文件位置,会在这个路径下创建包对应的文件夹
# 第二路径是 cpp 文件路径
aidl-cpp -I./com/yuandaima com/yuandaima/IHello.aidl ./ ./IHello.cpp

通过上述命令生成如下的文件结构:

bash 复制代码
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 脚本即可生成新的源码文件了

bash 复制代码
#!/bin/bash

aidl-cpp com/yuandaima/ICallback.aidl ./ ./ICallback.cpp
aidl-cpp -I./com/yuandaima com/yuandaima/IHello.aidl ./ ./IHello.cpp

服务端实现

服务端实现在 HelloServer.cpp 中:

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 成员调用回调函数了。

客户端实现

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/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 编译文件:

json 复制代码
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 到模拟器上:

bash 复制代码
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 环境,执行可执行文件:

bash 复制代码
adb shell
cd /data/local/tmp/
#执行服务端
./BinderCallbackServer &
#执行客户端
./BinderCallbackClient &

接着查看 log:

从 log 的内容可以看出,我们的回调函数执行成功了。

相关推荐
数据猎手小k8 分钟前
AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
android·人工智能·机器学习·语言模型
你的小1043 分钟前
JavaWeb项目-----博客系统
android
风和先行1 小时前
adb 命令查看设备存储占用情况
android·adb
AaVictory.2 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰3 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
大风起兮云飞扬丶3 小时前
Android——网络请求
android
干一行,爱一行3 小时前
android camera data -> surface 显示
android
断墨先生3 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
无极程序员5 小时前
PHP常量
android·ide·android studio
萌面小侠Plus6 小时前
Android笔记(三十三):封装设备性能级别判断工具——低端机还是高端机
android·性能优化·kotlin·工具类·低端机