1 Android HAL HIDL
HIDL是Treble Interface的一部分。
1.1 GNSS和Sensors
Refer to gnss and sensors
hardware/interfaces/gnss/1.0/default
hardware/interfaces/sensors/1.0/default
1.2 産生HAL架構步驟
1)生成androidmk和hidl-gen
在Android項目根目錄下:
. build/envsetup.sh
lunch
make blueprint_tools
make hidl-gen
make c2hal // 将傳統HAL .h頭檔案轉換成hidl .hal檔案工具
2)産生.cpp和.h檔案
mkdir -p hardware/interfaces/oem1/1.0/default
路徑中出現的1.0表示HAL目前版本
仿照GNSS或者Sensors增加一個IOem1.hal
in hardware/interfaces/oem1/1.0/IOem1.hal
在Android項目源碼根目錄下編寫腳本my_oem1.sh,調用hidl-gen産生.cpp和.h檔案
in my_oem1.sh
[email protected]
LOC=hardware/interfaces/oem1/1.0/default
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
執行:
./my_oem1.sh
3)産生.bp和.mk檔案
執行:
./hardware/interfaces/update-makefiles.sh
4)
編譯最終在out/target/common/gen/JAVA_LIBRARIES目錄下生成Java源檔案。
1.3 mk檔案轉換為bp檔案
. build/envsetup.sh
make blueprint_tools
androidmk Android.mk > Android.bp
1.4 生成Android.mk模版
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw
generate-android-mk
https://github.com/WanghongLin/generate-android-mk
2 VNDK
3 VTS測試步驟
1) 安裝必須的python工具和adb - Linux需要
apt-get install android-tools-adb
2)
source build/envsetup.sh
lunch
make vts
3) 編譯完成後
in out/host/linux-x86/vts/
$cd android-vts/tools
$vts-tradefed
> run vts
or
> run vts-hal
or
> run vts-kernel
如果要在Windows上測試,需要将檔案夾android-vts拷貝到windows下 - 待完善
4) 測試完成後
檢視測試結果
android-vts/results
android-vts/logs
4 Android中檢視有哪些HIDL HAL
adb root
adb shell
# lshal
5 Android列印C++調用棧
#include <utils/CallStack.h>
在需要列印的地方加如下的定義。
android::CallStack stack("oem");
logcat | grep oem
6 LinkToDeath
6.1 Principle
Client很容易監控Service的died;但是Service監控Client的died,需要Client實作使用IBinder接口的ICallback,傳給Service,然後Service可以監控這個使用IBinder接口的ICallback的died,這樣就實作了監控Client的died。
1)一個BpBinder可以注冊多個死亡回調;但Kernel隻允許注冊一個死亡通知(ref->death隻能為空或者指向一個指針)
2)BC_REQUEST_DEATH_NOTIFICATION - linkToDeath()
3)BC_CLEAR_DEATH_NOTIFICATION - unlinkToDeath()
4)當process exit時會觸發系統關閉該程序已經打開的檔案節點/dev/hwbinder,進而調用binder_node_release();通知died - BINDER_WORK_DEAD_BINDER
5)
echo 0x18 > /sys/module/binder/parameters/debug_mask
dmesg -C
dmesg -w | grep binder &
kill -9 $PID
6)ftrace as shown below
echo 0 > /d/tracing/tracing_on
echo nop > /d/tracing/current_tracer
echo function_graph > /d/tracing/current_tracer
#echo function > /d/tracing/current_tracer
echo funcgraph-proc > /d/tracing/trace_options
echo binder_cleanup_ref_olocked > /d/tracing/set_graph_function
echo 1 > /d/tracing/tracing_on
cat /d/tracing/trace
debuggerd -b $PID
6.2 代碼實施
6.2.1 JAVA實施步驟
import android.os.IHwBinder.DeathRecipient;
private class xxxDeathRecipient implements DeathRecipient {
@Override
public void serviceDied(long cookie) {
Log.i(TAG, "serviceDied, re-connect XXX");
if (xxxService != null) {
xxxService.unlinkToDeath(this);
}
// TODO: 重連service
}
};
xxxDeathRecipient mxxxDeathRecipient = new xxxDeathRecipient();
擷取xxxService成功後:
try {
xxxService.linkToDeath(mxxxDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
6.2.2 CPP實施步驟
using android::hardware::hidl_death_recipient;
class MyDeathRecipient : public android::hardware::hidl_death_recipient {
virtual void serviceDied(uint64_t cookie, const android::wp<::android::hidl::base::V1_0::IBase>& who) {
// Deal with the fact that the service died
}
}
MyDeathRecipient mDeathRecipient = new MyDeathRecipient();
擷取xxxService成功後:
xxxService->linkToDeath(mDeathRecipient, 0);
7 strace解析binder驅動資料插件
7.1 知識
A程序給B程序發送資料:A程序使用BC_TRANSACTION發送,經過binder驅動轉換,B程序接收到是BR_TRANSACTION
B程序給A程序回複資料:B程序使用BC_REPLY發送,經過binder驅動轉換,A程序接收到是BR_REPLY。
7.2 代碼
#include "defs.h"
#include <linux/android/binder.h>
static inline unsigned int get_my_le32(const unsigned char *p)
{
return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
}
static const char *cmd_to_str(unsigned int cmd)
{
switch(cmd) {
case BC_TRANSACTION:
return "BC_TRANSACTION";
break;
case BC_REPLY:
return "BC_REPLY";
break;
case BR_TRANSACTION:
return "BR_TRANSACTION";
break;
case BR_REPLY:
return "BR_REPLY";
break;
}
return "UNDEFINED";
}
static void handle_bx_transaction(struct tcb *const tcp,
struct binder_write_read *bwr,
struct binder_transaction_data *txn)
{
binder_size_t txn_data_size = 0;
binder_size_t txn_offsets_size = 0;
#if defined (FEATURE_PRINT_DETAIL)
int n = 0;
unsigned char buf[256], buf_offsets[256];
#else
binder_uintptr_t txn_buffer;
binder_uintptr_t txn_offsets;
#endif
txn_data_size = txn->data_size;
txn_offsets_size = txn->offsets_size;
tprintf("handle=%d, ptr=%llx, target_cookie=0x%llx,\n"
"code=%d, flags=0x%02x, sender_pid=%d, sender_euid=%d",
txn->target.handle, txn->target.ptr, txn->cookie,
txn->code,
txn->flags,
txn->sender_pid,
txn->sender_euid);
if (txn_data_size <= 8) {
tprintf(", data_size=%llu, %02x %02x %02x %02x %02x %02x %02x %02x\n",
txn_data_size,
txn->data.buf[0], txn->data.buf[1],
txn->data.buf[2], txn->data.buf[3],
txn->data.buf[4], txn->data.buf[5],
txn->data.buf[6], txn->data.buf[7]);
} else {
#if defined (FEATURE_PRINT_DETAIL)
txn_data_size = (txn_data_size > 256) ? 256 : txn_data_size;
if (umoven(tcp, txn->data.ptr.buffer, txn_data_size, buf) < 0)
return;
txn_offsets_size = (txn_offsets_size > 256) ? 256 : txn_offsets_size;
if (umoven(tcp, txn->data.ptr.offsets, txn_offsets_size, buf_offsets) < 0)
return;
for (; n < (txn_offsets_size / sizeof(binder_size_t)); n++)
{
struct flat_binder_object* pbinder =
(struct flat_binder_object*)((char*)buf +
((int*)(buf_offsets))[n]);
unsigned long type = pbinder->type;
switch (type)
{
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER:
tprintf("binder=0x%llx, cookie=0x%llx\n",
pbinder->binder, pbinder->cookie);
break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE:
tprintf("handle=0x%08x\n", pbinder->handle);
break;
default:
break;
}
}
#else
txn_buffer = txn->data.ptr.buffer;
txn_offsets = txn->data.ptr.offsets;
tprintf(", \ndata_size=%llu, txn_buffer=0x%llx\n",
txn_data_size, txn_buffer);
dumpstr(tcp, (long) txn_buffer, txn_data_size);
tprintf("\noffsets_size=%llu, txn_offsets=0x%llx\n",
txn_offsets_size, txn_offsets);
dumpstr(tcp, (long) txn_offsets, txn_offsets_size);
#endif
}
}
static void decode_bwr(struct tcb *const tcp, const kernel_ulong_t addr)
{
struct binder_write_read bwr;
struct binder_transaction_data *txn;
int read_len, write_len, offset;
unsigned char buf[256], *p;
unsigned int cmd, cmd_data_len;
static int ioctl_count = 1;
if (umove_or_printaddr(tcp, addr, &bwr))
return;
if (abbrev(tcp)) {
tprints(", ");
tprintf("{BC_TRANS=0x%08x, BR_REPLY=0x%08x, "
"write_size=%llu, write_consumed=%llu, "
"read_size=%llu, read_consumed=%llu}",
BC_TRANSACTION, BR_REPLY,
bwr.write_size, bwr.write_consumed,
bwr.read_size, bwr.read_consumed);
return;
}
tprints(",\n");
tprintf("%d) ############################## WRITE ###################################\n",
ioctl_count++);
tprintf("write_size=%llu, write_consumed=%llu, write_buffer=\n",
bwr.write_size, bwr.write_consumed);
write_len = (bwr.write_size > 256) ? 256 : bwr.write_size;
if (umoven(tcp, bwr.write_buffer, write_len, buf) < 0)
goto out;
offset = 0;
while (offset < write_len) {
cmd = get_my_le32(buf + offset);
cmd_data_len = _IOC_SIZE(cmd);
switch (cmd) {
case BC_TRANSACTION:
case BC_REPLY:
tprintf("%s--->\n", cmd_to_str(cmd));
p = buf + offset + 4;
txn = (struct binder_transaction_data *)p;
handle_bx_transaction(tcp, &bwr, txn);
break;
}
offset += (4 + cmd_data_len);
}
dumpstr(tcp, (long) bwr.write_buffer, bwr.write_size);
tprints("\n");
tprintf("%d) ############################## READ ###################################\n",
ioctl_count++);
tprintf("read_size=%llu, read_consumed=%llu,\n",
bwr.read_size, bwr.read_consumed);
read_len = (bwr.read_size > 256) ? 256 : bwr.read_size;
if (umoven(tcp, bwr.read_buffer, read_len, buf) < 0)
goto out;
offset = 0;
while (offset < read_len) {
cmd = get_my_le32(buf + offset);
cmd_data_len = _IOC_SIZE(cmd);
switch (cmd) {
case BR_TRANSACTION:
case BR_REPLY:
tprintf("%s--->\n", cmd_to_str(cmd));
p = buf + offset + 4;
txn = (struct binder_transaction_data *)p;
handle_bx_transaction(tcp, &bwr, txn);
break;
}
offset += (4 + cmd_data_len);
}
tprints("\n");
dumpstr(tcp, (long) bwr.read_buffer, bwr.read_size);
out:
tprints("}");
}
int binder_ioctl(struct tcb *const tcp, const unsigned int code,
const kernel_ulong_t arg)
{
switch (code) {
case BINDER_WRITE_READ:
decode_bwr(tcp, arg);
break;
default:
return RVAL_DECODED;
}
return RVAL_DECODED | 1;
}
7.3 檢視hwbinder的資料
ps -A| grep hwservicemanager
strace -tt -T -x -v -p $PID 2>&1 |grep -vE "writev|futex|getuid|ppoll"
8 Abbreviations
VTS:Vendor Test Suite