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);
}