searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

最简单的Binder调用

2023-05-29 02:06:49
78
0

Android提供简单的binder服务测试命令service(代码), 比如说要打开或者关闭画面更新闪烁,可以发送指令:

# 打开
adb shell service call SurfaceFlinger 1002 i32 1

#关闭
adb shell service call SurfaceFlinger 1002 i32 0

其中,SurfaceFlinger是服务名称,1002是需要调用的函数id, i32 1 表示写一个32-bit integer为1的参数。

一,CPP的最简单调用

下面是提取了service.cpp的代码写的最简短的画面更新闪烁调用:

#define LOG_TAG "simplest_call"

#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>

using namespace android;

int main() {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> service = sm->checkService(String16("SurfaceFlinger"));
    String16 ifName("android.ui.ISurfaceComposer");
    if (service != nullptr && ifName.size() > 0) {
        Parcel data, reply;
        // the interface name is first
        data.writeInterfaceToken(ifName);
        data.writeInt32(1);
        service->transact(1002, data, &reply);
        aout << "Result: " << reply << endl;
    }
}

上面代码实现的就是adb shell service call SurfaceFlinger 1002 i32 1命令的功能,通过IServiceManager获取SurfaceFlinger服务,然后通过IServiceManager调用对应函数,其中Binder InterfaceToken "android.ui.ISurfaceComposer"也可以通过以下函数获取:

static String16 get_interface_name(sp<IBinder> service)
{
    if (service != nullptr) {
        Parcel data, reply;
        status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
        if (err == NO_ERROR) {
            return reply.readString16();
        }
    }
    return String16();
}
String16 ifName = get_interface_name(service);

二,JAVA的最简单调用

java的调用方式和cpp的基本一致,只是java的ServiceManager和cpp中的IServiceManager的最终调用并不一样,java最终还是需要在native cpp中去操作binder内核,但使用的是libbinder.so中的方法。

package simplestcall;

import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

public class Main {
    private static final String TAG = "SimplestCall";

    public static void main(String[] args) {
        IBinder service = ServiceManager.getService("SurfaceFlinger");
        final Parcel data = Parcel.obtain();
        final Parcel reply = Parcel.obtain();
        data.writeInterfaceToken("android.ui.ISurfaceComposer");
        data.writeInt(1);
        try {
            service.transact(1002, data, reply, 0 /* flags */);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        System.out.println(reply.toString());
        reply.recycle();
        data.recycle();
    }
}

三,更直接的方式

上面的Demo都用到了系统提供的ServiceManager, ServerManager本身也是一个binder服务,是否有方法可以直接获取呢,在Android 11之前,AOSP在测试类bctest.c(代码)上提供了svcmgr_lookup方法,通过binder_call方法直接操作binder节点获取包括ServerManager在内的所有系统服务。

uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name)
{
    uint32_t handle;
    unsigned iodata[512/4];
    struct binder_io msg, reply;

    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, SVC_MGR_NAME);
    bio_put_string16_x(&msg, name);

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
        return 0;

    handle = bio_get_ref(&reply);

    if (handle)
        binder_acquire(bs, handle);

    binder_done(bs, &msg, &reply);

    return handle;
}

在此基础上,我们就可以增加一个直接调用SurfaceFlinger服务获取的方法, 实现前面demo中一样的功能。

void simple_call_sf(struct binder_state *bs)
{
    uint32_t handle;
    unsigned iodata[512/4];
    struct binder_io msg, reply;

    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header

    bio_put_string16_x(&msg, "android.ui.ISurfaceComposer");
    bio_put_uint32(&msg, 1);
    handle = svcmgr_lookup(bs, BINDER_SERVICE_MANAGER, "SurfaceFlinger");
    if (binder_call(bs, &msg, &reply, handle, 1002 /*SHOW_UPDATES*/))
        return ;

    binder_done(bs, &msg, &reply);
}

参考资料

Gityuan-彻底理解Android Binder通信架构

0条评论
0 / 1000