添加 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 的内容可以看出,我们的回调函数执行成功了。

相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui