1 Android HAL HIDL
 1.1 Android中查看有哪些HIDL HAL
 HIDL是Treble Interface的一部分。
 adb root
 adb shell
 # lshal
 
 1.2 Android打印C++调用栈
 #include <utils/CallStack.h> 
 在需要打印的地方加如下的定义。
 android::CallStack stack("oem");
 
 logcat | grep oem
 
 1.3 GNSS和Sensors
 Refer to gnss and sensors
 hardware/interfaces/gnss/1.0/default
 hardware/interfaces/sensors/1.0/default
 
 1.4 产生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
 PACKAGE=android.hardware.oem1@1.0
 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.5 mk文件转换为bp文件
 . build/envsetup.sh
 make blueprint_tools
 androidmk Android.mk > Android.bp
 
 1.6 Java HIDL
 [28th-Mar-2022]
 ./hardware/interfaces/update-makefiles.sh
 Android.mk
 LOCAL_STATIC_JAVA_LIBRARIES += \
 android.hardware.foo-V1.0-java
 Android.bp
 static_libs: [
 "android.hardware.foo-V1.0-java",
 ],
 
 // out/target/common/gen/JAVA_LIBRARIES
 import android.hardware.foo.V1_0.IFoo;
 IFoo server = IFoo.getService();
 
 2 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
 
 3 LinkToDeath
 3.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
 
 3.2 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();
 }
 
 3.3 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);
 
 4 strace解析binder驱动数据插件
 4.1 知识
 A进程给B进程发送数据:A进程使用BC_TRANSACTION发送,经过binder驱动转换,B进程接收到是BR_TRANSACTION
 B进程给A进程回复数据:B进程使用BC_REPLY发送,经过binder驱动转换,A进程接收到是BR_REPLY。
 
 4.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";
 }
 
 /*
  * bc: binder command, from userland to driver
  * br: binder return, from driver to userland
  */
 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
     }
 }
 
 /*
  * mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
  * GET_SERVICE_TRANSACTION <-> struct binder_transaction_data.code
  * data                    <-> struct binder_transaction_data.data
  *
  * write_bufer: CMD + binder_transaction_data + CMD + binder_transaction_data...
  * byte 0-3: command, offset0 - nr, offset1 - magic 'c' = 0x63
  * byte 4-7: target
  *
  * read_bufer: BR_NOOP + CMD + binder_transaction_data + CMD + binder_transaction_data...
  * byte 0-3:  BR_NOOP, 0c 72 00 00, offset0 - nr, offset1 - magic 'r' = 0x72
  *
  */
 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;
     }
 
     /* VERBOSE mode */
     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;
 }
 
 4.3 查看hwbinder的数据
 ps -A| grep hwservicemanager
 strace -tt -T -x -v -p $PID 2>&1 |grep -vE "writev|futex|getuid|ppoll"
 
 5 Abbreviations
 VTS:Vendor Test Suite