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()));
}
相关推荐
chlk12315 小时前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
阿巴斯甜15 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker15 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952716 小时前
Andorid Google 登录接入文档
android
黄林晴18 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android