天天看點

Android HAL HIDL

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

繼續閱讀