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()));
}
相关推荐
深盾安全2 小时前
Android SO导出符号的深度解析与安全防护指南
android
顾林海2 小时前
Android安全防护:Runtime 调试检测与反制手段
android·安全·面试
什么半岛铁盒2 小时前
MySQL 约束知识体系:八大约束类型详细讲解
android·数据库·mysql
stringwu3 小时前
Flutter plugin开发小知识之:ActivityAware 详解
android
whysqwhw3 小时前
Matrix.setPolyToPoly() 函数使用指南
android
丐中丐9993 小时前
在Android中利用抽象类对外提供系统接口
android·操作系统
张可3 小时前
在 Voyager 中使用 SharedElement 共享元素动画
android·前端·kotlin
且随疾风前行.4 小时前
在安卓中使用 FFmpegKit 剪切视频并添加文字水印
android·音视频
Yang-Never4 小时前
设计模式 -> 策略模式(Strategy Pattern)
android·开发语言·设计模式·kotlin·android studio·策略模式