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()));
}
相关推荐
恋猫de小郭5 分钟前
谷歌开启 Android 开发者身份验证,明年可能开始禁止“未经验证”应用的侧载,要求所有开发者向谷歌表明身份
android·前端·flutter
用户0921 分钟前
Gradle声明式构建总结
android
用户091 小时前
Gradle插件开发实践总结
android
Digitally11 小时前
如何将视频从安卓设备传输到Mac?
android·macos
alexhilton13 小时前
Compose Unstyled:Compose UI中失传的设计系统层
android·kotlin·android jetpack
刘龙超15 小时前
如何应对 Android 面试官 -> 玩转 RxJava (基础使用)
android·rxjava
柿蒂16 小时前
从动态缩放自定义View,聊聊为什么不要把问题复杂化
android·ai编程·android jetpack
kerli16 小时前
kotlin协程系列:callbackFlow
android·kotlin
没有了遇见17 小时前
Android 原生定位实现(替代融合定位收费,获取经纬度方案)
android·kotlin
一枚小小程序员哈17 小时前
基于Android的车位预售预租APP/基于Android的车位租赁系统APP/基于Android的车位管理系统APP
android·spring boot·后端·struts·spring·java-ee·maven