Android系统中如何在Native层调用java实现的系统服务

Android系统中如何在Native层调用java实现的系统服务

<在Android中利用抽象类对外提供系统接口>后,出现了个新需求,就是想在Native层代码中也能使用之前定制服务(用java实现的)中已经实现好的各种功能和机制。

实现原理

如上图,右边的java服务层部分已在<在Android中利用抽象类对外提供系统接口>中实现了,现在需要实现左边的BpCustomManagerService, 以供其它Native程序调用:

实现代码

ICustomManagerService.h
cpp 复制代码
#pragma once

#include <binder/IBinder.h>
#include <binder/IInterface.h>

#include <optional>

#ifdef __ANDROID_VNDK__
#error "This header is not visible to vendors"
#endif

namespace android {

// ----------------------------------------------------------------------

class ICustomManagerService : public IInterface
{
public:
    DECLARE_META_INTERFACE(CustomManagerService)

    virtual String16 getVersion() = 0;

    enum {
        TRANSACTION_getVersion = 1,
    };
};

其中TRANSACTION_getVersion需要在系统编译输出目录out下找到文件ICustomManagerService$Stub.class, 然后用java反编译工具JD-GUI打开, 查看TRANSACTION_getVersion的值:

java 复制代码
public abstract class Stub extends Binder implements ICustomManagerService {
  static final int TRANSACTION_getVersion = 1;
}

在binder通信中,通过类似于TRANSACTION_getVersion的硬编码值来确定调用的哪个接口。这个值与接口在aidl文件中的顺序有关。 如果ICustomManagerService.aidl的定义如下,

java 复制代码
interface ICustomManager {
    String getVersion();
    String xyz();
}

ICustomManagerService$Stub.class就会有以下2个接口编号:

java 复制代码
public abstract class Stub extends Binder implements ICustomManagerService {
  static final int TRANSACTION_getVersion = 1;
  static final int TRANSACTION_xyz = 2;
}

当ICustomManagerService.aidl里接口的顺序发生变化后,需要在ICustomManagerService.h中同步更改。

ICustomManagerService.cpp
cpp 复制代码
//#define LOG_NDEBUG 0
#define LOG_TAG "CustomManagerService"

#include <binder/ICustomManagerService.h>
#include <android-base/logging.h>
#include <binder/Parcel.h>
#include <utils/Log.h>
#include <utils/String8.h>

#include <optional>

namespace android {

// ----------------------------------------------------------------------

class BpCustomManagerService : public BpInterface<ICustomManagerService>
{
public:
    explicit BpCustomManagerService(const sp<IBinder>& impl)
        : BpInterface<ICustomManagerService>(impl)
    {
    }

    virtual String16 getVersion() {
        Parcel data, reply;
        data.writeInterfaceToken(ICustomManagerService::getInterfaceDescriptor());
        remote()->transact(TRANSACTION_getVersion, data, &reply);
        if (reply.readExceptionCode() != 0) return String16("");
        return reply.readString16();
    }
};

IMPLEMENT_META_INTERFACE(CustomManagerService, "com.android.internal.xyz.ICustomManagerService")
} // namespace android

ICustomManagerService.cpp为BpCustomManagerService的具体实现,在函数getVersion()中往binder传入com.android.internal.xyz.ICustomManagerService表示要调用的远程服务名称,传入TRANSACTION_getVersion表示要调用远程服务接口。返回的是一个Parcel类型的数据reply, reply里有服务端给的ExceptionCode和version值。

ICustomManagerService$Stub.class里可看到服务端收到TRANSACTION_getVersion命令号后的处理:

java 复制代码
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    switch (code) {
      case 1:
        str16 = getVersion();
        reply.writeNoException();
        reply.writeString(str16);
        return true;
      ......
    }
}
CustomManager.h
cpp 复制代码
#pragma once

#include <binder/ICustomManagerService.h>

#include <utils/threads.h>

#include <optional>

#ifdef __ANDROID_VNDK__
#error "This header is not visible to vendors"
#endif

// ---------------------------------------------------------------------------
namespace android {

class CustomManager
{
public:
    CustomManager();
    String16 getVersion();

private:
    Mutex mLock;
    sp<ICustomManagerService> mService;
    sp<ICustomManagerService> getService();
};
} // namespace android
CustomManager.cpp
cpp 复制代码
#define LOG_NDEBUG 0
#include <mutex>
#include <binder/CustomManager.h>
#include <binder/Binder.h>
#include <binder/IServiceManager.h>

#include <utils/SystemClock.h>

#include <sys/types.h>
#include <private/android_filesystem_config.h>
#include <fcntl.h>
#include <termios.h>

#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "CustomManager"

namespace android {

CustomManager::CustomManager()
{
}

sp<ICustomManager> CustomManager::getService()
{
    static String16 _cmser("CustomManagerService");

    std::lock_guard<Mutex> scoped_lock(mLock);
    int64_t startTime = 0;
    sp<ICustomManagerService> service = mService;
    while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) {
        sp<IBinder> binder = defaultServiceManager()->checkService(_cmser);
        if (binder == nullptr) {
            if (startTime == 0) {
                startTime = uptimeMillis();
                ALOGI("Waiting for CustomManagerService");
            } else if ((uptimeMillis()-startTime) > 10000) {
                ALOGW("Waiting too long for CustomManagerService, giving up");
                service = nullptr;
                break;
            }
            sleep(1);
        } else {
            service = interface_cast<ICustomManagerService>(binder);
            mService = service;
        }
    }
    return service;
}

String16 CustomManager::getVersion()
{
    sp<ICustomManagerService> service = getService();
    if (service == nullptr) {
        return String16("");
    }
    return service->getVersion();
}
}

将ICustomManagerService.h, ICustomManagerService.cpp, CustomManager.h, CustomManager.cpp编译成libcustommanager.so:

makefile 复制代码
cc_library {
    name: "libcustommanager",
    double_loadable: true,
    target: {
        android: {
            compile_multilib: "both",
        },
    },
    cflags: [
        "-Wall",
        "-Wextra",
        "-Werror",
    ],
    srcs: [
        "CustomManager.cpp",
        "ICustomManagerService.cpp",
    ],
    export_include_dirs: ["include"],
    shared_libs: [
        "libutils",
        "libbinder",
        "libcutils",
        "liblog",
    ],
}

还有个地方需要添加个白名单:

frameworks/native/libs/binder/include/binder/IInterface.h

diff 复制代码
constexpr const char* const kManualInterfaces[] = {
   "IAAudioService",
   "VtsFuzzer",
+  "com.android.internal.xyz.ICustomManagerService",
   nullptr,
 };

其中,CustomManager.h为对外提供的头文件。

使用范例

在准备使用CustomManager的程序的Android.bp加入:

ini 复制代码
shared_libs: [
    libcustommanager
]

或Android.mk里加入

makefile 复制代码
LOCAL_SHARED_LIBRARIES += libcustommanager

代码里:

cpp 复制代码
#include <binder/CustomManager.h>
#include <binder/IServiceManager.h>

const char* string16ToChar(const android::String16& str16) {
    // 创建 String8 对象进行自动转换(UTF-16 → UTF-8)
    android::String8 str8(str16);
    // 返回 UTF-8 字符串(生命周期与 str8 对象绑定)
    return str8.string();
}

void test() {
    android::CustomManager cm;
    cm.getVersion();
    ALOGD("%s: getVersion = %s\n", __func__, string16ToChar(cm.getVersion()));
}
相关推荐
BD_Marathon1 天前
【MySQL】函数
android·数据库·mysql
西西学代码1 天前
安卓开发---耳机的按键设置的UI实例
android·ui
崎岖Qiu1 天前
【OS笔记04】:进程和线程2-进程控制
笔记·操作系统·os
maki0771 天前
虚幻版Pico大空间VR入门教程 05 —— 原点坐标和项目优化技巧整理
android·游戏引擎·vr·虚幻·pico·htc vive·大空间
千里马学框架1 天前
音频焦点学习之AudioFocusRequest.Builder类剖析
android·面试·智能手机·车载系统·音视频·安卓framework开发·audio
fundroid1 天前
掌握 Compose 性能优化三步法
android·android jetpack
TeleostNaCl1 天前
如何在 IDEA 中使用 Proguard 自动混淆 Gradle 编译的Java 项目
android·java·经验分享·kotlin·gradle·intellij-idea
旷野说1 天前
Android Studio Narwhal 3 特性
android·ide·android studio
maki0772 天前
VR大空间资料 01 —— 常用VR框架对比
android·ue5·游戏引擎·vr·虚幻·pico
xhBruce2 天前
InputReader与InputDispatcher关系 - android-15.0.0_r23
android·ims