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