由于一直从事驱动开发, 一直想对整体流程有个了解, 刚好看到这篇文章 AndroidQ 从app到驱动 第一章 编写Linux内核驱动程序 . 于是参考这篇文章在 rk3566 上面完成了从驱动到 app 的实验验证. 文章记录用到的知识点以及遇到的问题和解决方法.
整体框架大致分为如下 5 层.
一、添加 kernel 驱动
1. 驱动编写
驱动部分写一个 misc 设备就行了, 提供简单的读写功能. 由于只是简单的验证功能所以没有越界处理和错误处理.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include <linux/fs.h> #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/uaccess.h> #define DEVICE_NAME "hello" static char my_data[100 ] = "Hello, this is my_misc_device!\n" ;static ssize_t my_read (struct file *file, char __user *buf, size_t count, loff_t *ppos) { printk ("baron %s\n" , __func__); if (copy_to_user (buf, my_data, count)) return -EFAULT; return count; } static ssize_t my_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos) { printk ("baron %s\n" , __func__); if (copy_from_user (my_data, buf, count)) return -EFAULT; return count; } static const struct file_operations my_fops = { .owner = THIS_MODULE, .read = my_read, .write = my_write, }; static struct miscdevice my_misc_device = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &my_fops, }; static int __init my_init (void ) { int ret = misc_register (&my_misc_device); if (ret) { pr_err ("Failed to register misc device\n" ); return ret; } return 0 ; } static void __exit my_exit (void ) { misc_deregister (&my_misc_device); } module_init (my_init);module_exit (my_exit);MODULE_LICENSE ("GPL" );MODULE_AUTHOR ("baron" );MODULE_DESCRIPTION ("A simple misc driver" );
对应的 makefile 部分直接将驱动编进内核.
修改的文件如下所示
编译下载查看成功创建节点
1 2 rk3566_rgo:/ # ls /dev/hello /dev/hello
2. 验证驱动
编写一个简单的应用程序验证驱动是 ok 的, 创建 external/test/test.c
, 应用程序的内容如下.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <stdio.h> #include <sys/ioctl.h> #include <fcntl.h> #include <sys/types.h> #include <unistd.h> #include <malloc.h> #include <string.h> int main (int argc, char * argv[]) { char * buff = (char *)malloc (100 ); int fd = -1 ; buff[99 ] = '\0' ; if (argc < 2 ) return 0 ; fd = open("/dev/hello" , O_RDWR); if (fd < 0 ){ printf ("open /dev/mycdev err\n" ); return -1 ; } if (!strcmp ("write" , argv[1 ])){ write(fd, argv[2 ], strlen (argv[2 ])); printf ("write %s to /dev/hello buf\n\n" , argv[2 ]); }else if (!strcmp ("read" , argv[1 ])){ read(fd, buff, 99 ); printf ("read data form /dev/hello : %s\n\n" , buff); }else { printf ("please use write or read cmd\n" ); } close(fd); return 0 ; }
添加 external/test/Android.bp
内容如下, 用来编译 bin 文件.
1 2 3 4 5 6 7 8 9 10 cc_binary { name: "mytest" , srcs: ["test.c" ], shared_libs: [ "libbase" , "libcutils" , "liblog" , "libutils" , ], }
添加完成之后进入 external/test/
运行 mmm .
编译. 编译完成之后如图, 得到 my_test
将其 push 到机器的 cache/
目录. 验证结果如图所示, 驱动正常运行.
二、hall 层
对 linux 驱动程序进行封装,其主要设计意图是向下屏蔽设备以及其驱动的实现细节,向上为系统服务以及 Framework 提供提供统一的设备访问接口。就是 linux 驱动只提供硬件读写接口, 业务逻辑通过 hall 封装成 so 库. 这样就不用遵循 kernel 的 gpl 开源协议, 从而保护厂商的利益. 不过也因为这个原因安卓被 linux 踢出了内核主线程.
1. 数据结构
1) hw_module_t
用来表示硬件的抽象
每一个模块都必须自定义一个硬件抽象层模块结构体,而且他的第一个成员变量的类型必须为 hw_module_t
.
硬件抽象层每一个模块都必须声明为HAL_MODULE_INFO_SYM
结构体 hw_module_t
的成员变量 tag
的值必须设置为HARDWARE_MODULE_TAG
dso 用来保存加载硬件抽象层模块后得到的句柄值.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 typedef struct hw_module_t { uint32_t tag; uint16_t module_api_version; #define version_major module_api_version uint16_t hal_api_version; #define version_minor hal_api_version const char *id; const char *name; const char *author; struct hw_module_methods_t * methods; void * dso; #ifdef __LP64__ uint64_t reserved[32 -7 ]; #else uint32_t reserved[32 -7 ]; #endif } hw_module_t ;
2) hw_module_methods_t
封装 open 函数, 通过 open 函数获取 hw_device_t
1 2 3 4 5 6 typedef struct hw_module_methods_t { int (*open)(const struct hw_module_t * module , const char * id, struct hw_device_t ** device); } hw_module_methods_t ;
3) hw_device_t
open 函数返回的结构, 硬件设备结构的第一个结构.
tag
的值必须设置为HARDWARE_DEVICE_TAG
close 回调接口用来关闭设备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 typedef struct hw_device_t { uint32_t tag; uint32_t version; struct hw_module_t * module ; #ifdef __LP64__ uint64_t reserved[12 ]; #else uint32_t reserved[12 ]; #endif int (*close)(struct hw_device_t * device); } hw_device_t ;
有了这几个接口就可以用来封装我们驱动接口了.
2. 程序编写
创建头文件: hardware/libhardware/include/hardware/hello.h
内容如下.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #ifndef ANDROID_INCLUDE_HARDWARE_HELLO_H #define ANDROID_INCLUDE_HARDWARE_HELLO_H #include <stdbool.h> #include <stdint.h> #include <sys/cdefs.h> #include <sys/types.h> #include <hardware/hardware.h> #include <hardware/hw_auth_token.h> #define HELLO_HARDWARE_MODULE_ID "hello" typedef struct hello_module { struct hw_module_t common; }hello_module_t ; typedef struct hello_device { struct hw_device_t common; int fd; int (*write_string)(struct hello_device* dev, const char *str); int (*read_string)(struct hello_device* dev, char * str); }hello_device_t ; #endif
创建 hardware/libhardware/modules/hello/hello.c
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 #define LOG_TAG "Legacy HelloHAL" #include <malloc.h> #include <stdint.h> #include <log/log.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <cutils/atomic.h> #include <stdlib.h> #include <unistd.h> #include <hardware/hardware.h> #include <hardware/hello.h> #define DEVICE_NAME "/dev/hello" #define MODULE_NAME "Default Hello HAL" #define MODULE_AUTHOR "The Android Open Source Project" static int hello_device_open (const struct hw_module_t * module , const char * name, struct hw_device_t ** device) ;static int hello_device_close (struct hw_device_t * device) ;static int hello_write_string (struct hello_device* dev, const char * str) ;static int hello_read_string (struct hello_device* dev, char * str) ;static struct hw_module_methods_t hello_module_methods = { .open = hello_device_open, }; hello_module_t HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = 1 , .hal_api_version = 1 , .id = HELLO_HARDWARE_MODULE_ID, .name = MODULE_NAME, .author = MODULE_AUTHOR, .methods = &hello_module_methods, }, }; static int hello_device_open (const struct hw_module_t * module , const char * name, struct hw_device_t ** device) { hello_device_t *dev = malloc (sizeof (hello_device_t )); memset (dev, 0 , sizeof (hello_device_t )); ALOGE ("Hello: hello_device_open name = %s" ,name); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0 ; dev->common.module = (hw_module_t *)module ; dev->common.close = hello_device_close; dev->write_string = hello_write_string; dev->read_string = hello_read_string; if ((dev->fd = open (DEVICE_NAME, O_RDWR)) == -1 ) { ALOGE ("Hello: open /dev/hello fail-- %s." , strerror (errno));free (dev); return -EFAULT; } *device = &(dev->common); ALOGE ("Hello: open /dev/hello successfully." ); return 0 ; } static int hello_device_close (struct hw_device_t * device) { struct hello_device * hello_device = (struct hello_device*)device; if (hello_device) { close (hello_device->fd); free (hello_device); } return 0 ; } static int hello_write_string (struct hello_device* dev,const char * str) { ALOGE ("Hello:write string: %s" , str); write (dev->fd, str, sizeof (str)); return 0 ; } static int hello_read_string (struct hello_device* dev, char * str) { ALOGE ("Hello:read hello_read_string" ); read (dev->fd,str, sizeof (str)); return 0 ; }
3. 编译程序
创建 hardware/libhardware/modules/hello/Android.bp
添加内容如下.
1 2 3 4 5 6 7 8 9 10 11 12 13 cc_library_shared { name: "hello.default" , relative_install_path: "hw" , proprietary: true , srcs: ["hello.c" ], cflags: ["-Wall" , "-Werror" ], header_libs: ["libhardware_headers" ], shared_libs: [ "liblog" , "libcutils" , "libutils" , ], }
在 build/make/target/product/full_base.mk
中添加如下内容, 将我们的添加的 hall 库编译进系统.对应的位置为 /vendor/lib/hw/hello.default.so
.
1 2 3 4 5 6 7 8 9 10 11 -- a/target/product/full_base.mk ++ b/target/product/full_base.mk @@ -32,7 +32,8 @@ PRODUCT_PACKAGES += \ # audio.a2dp.default is a system module. Generic system image includes # audio.a2dp.default to support A2DP if board has the capability. PRODUCT_PACKAGES += \ - audio.a2dp.default + audio.a2dp.default \ + hello.default
运行 ./build.sh -UKAup
编译代码. 编译完成之后可以在 out 目录下发现 hello.default
1 2 $ find out/ -name "hello\.default" out/soong/.intermediates/hardware/libhardware/modules/hello/hello.default
4. 验证程序
添加验证代码 frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp
修改如下
对应代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <hardware/hardware.h> #include <hardware/hello.h> struct hello_device * hello_device = NULL ; static inline int hello_device_open (const hw_module_t * module , struct hello_device** device) { return module ->methods->open (module , HELLO_HARDWARE_MODULE_ID, (struct hw_device_t **)device); } static jint HelloServiceInit () { ALOGE ("HelloServiceInit HelloServiceInit" ); const hw_module_t *hw_module = NULL ; ALOGE ("Hello JNI: initializing......" ); if (hw_get_module (HELLO_HARDWARE_MODULE_ID, &hw_module) == 0 ) { ALOGE ("Hello JNI: hello Stub found." ); if (hello_device_open (hw_module, &hello_device) == 0 ) { ALOGE ("Hello JNI: hello device is open." ); return 0 ; } ALOGE ("Hello JNI: failed to open hello device." ); return -1 ; } ALOGE ("Hello JNI: failed to get hello stub hw_module." ); return -1 ; }
修改 system/sepolicy/vendor/file_contexts
添加库的位置让系统能够找到, 该正则表达式指定了库的位置为 /vendor/lib64/hw/hello.default.so
1 2 3 4 5 6 7 8 9 -- a/vendor/file_contexts ++ b/vendor/file_contexts @@ -86,6 +86,7 @@ /(vendor|system/vendor)/lib(64)?/hw/android\.hardware\.graphics\.mapper@4\.0-impl\.so u:object_r:same_process_hal_file:s0 /(vendor|system/vendor)/lib(64)?/hw/android\.hardware\.renderscript@1\.0-impl\.so u:object_r:same_process_hal_file:s0 /(vendor|system/vendor)/lib(64)?/hw/gralloc\.default\.so u:object_r:same_process_hal_file:s0 +/(vendor|system/vendor)/lib(64)?/hw/hello\.default\.so u:object_r:same_process_hal_file:s0
刷机开机打印 log 如下
1 2 3 4 5 6 7 01 -18 07 :32 :55.775 419 419 E AlarmManagerService: HelloServiceInit HelloServiceInit01 -18 07 :32 :55.776 419 419 E AlarmManagerService: Hello JNI: initializing......01 -18 07 :32 :55.778 419 419 E AlarmManagerService: Hello JNI: hello Stub found.01 -18 07 :32 :55.778 419 419 E Legacy HelloHAL: Hello: hello_device_open name = hello01 -18 07 :32 :55.778 419 419 E Legacy HelloHAL: Hello: open /dev/hello fail-- Permission denied.01 -18 07 :32 :55.778 419 419 E AlarmManagerService: Hello JNI: failed to open hello device.
提示没没有权限
5. 添加权限
1) 设备节点添加权限
给我们的设备节点添加权限修改路径 system/core/rootdir/
如下
1 2 3 4 5 6 7 8 9 10 11 12 -- a/rootdir/ueventd.rc ++ b/rootdir/ueventd.rc @@ -39,6 +39,7 @@ subsystem sound /dev/vndbinder 0666 root root /dev/pmsg0 0222 root log +/dev/hello 0666 root root # kms driver for drm based gpu /dev/dri/* 0666 root graphics
添加权限之后报错如下
1 2 3 4 5 6 7 8 9 10 01 -17 09 :52 :50.271 265 265 E MtpDeviceJNI: HelloServiceInit HelloServiceInit01 -17 09 :52 :50.272 265 265 E MtpDeviceJNI: Hello JNI: initializing......01 -17 09 :52 :50.276 265 265 W main : type=1400 audit (0.0 :17 ): avc: denied { read write } for name="hello" dev="tmpfs" ino=11079 scontext=u:r:zygote:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=0 01 -17 09 :52 :50.280 265 265 E MtpDeviceJNI: Hello JNI: hello Stub found.01 -17 09 :52 :50.280 265 265 E Legacy HelloHAL: Hello: hello_device_open name = hello01 -17 09 :52 :50.281 265 265 E Legacy HelloHAL: Hello: open /dev/hello fail-- Permission denied.01 -17 09 :52 :50.281 265 265 E MtpDeviceJNI: Hello JNI: failed to open hello device.
2) 添加 shell linux 权限
在 system/sepolicy/public/device.te
中添加类别为 hello_device 的对象, 并且设置 attribute 为 dev_type. 修改如下
1 2 3 4 5 6 7 8 9 10 11 12 -- a/public/device.te ++ b/public/device.te @@ -39,6 +39,7 @@ type serial_device, dev_type; type socket_device, dev_type; type owntty_device, dev_type, mlstrustedobject; type tty_device, dev_type; +type hello_device, dev_type; type video_device, dev_type; type zero_device, dev_type, mlstrustedobject; type fuse_device, dev_type, mlstrustedobject;
修改的文件如下,修改的内容和上面是一样的.:
将 /dev/hello 设备节点和 SELinux 类别为 hello_device 的对象进行关联, 即我们前面创建的. 如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 zhaosheng@YF-zhaosheng:~/work2/ad500/system/sepolicy$ gf private/file_contexts -- a/private/file_contexts ++ b/private/file_contexts @@ -102,6 +102,7 @@ /dev/input(/.*)? u:object_r:input_device:s0 /dev/iio:device[0-9]+ u:object_r:iio_device:s0 /dev/ion u:object_r:ion_device:s0 +/dev/hello u:object_r:hello_device:s0 /dev/keychord u:object_r:keychord_device:s0 /dev/loop-control u:object_r:loop_control_device:s0 /dev/modem.* u:object_r:radio_device:s0
/dev/hello:
表示规则适用于 /dev/hello
这个设备节点
u:object_r:hello_device:s0:
指定 SELinux 上下文,hello_device
是 SELinux 类别,s0
表示 SELinux 安全等级为 0
需要修改的文件如下, 修改的内容和上面是一模一样的.
编译完成后报错如下
1 2 3 4 5 6 7 8 9 01 -18 07 :07 :17.681 421 421 E AlarmManagerService: HelloServiceInit HelloServiceInit01 -18 07 :07 :17.681 421 421 E AlarmManagerService: Hello JNI: initializing......01 -18 07 :07 :17.683 421 421 W system_server: type=1400 audit (0.0 :17 ): avc: denied { read write } for name="hello" dev="tmpfs" ino=3901 scontext=u:r:system_server:s0 tcontext=u:object_r:hello_device:s0 tclass=chr_file permissive=0 01 -18 07 :07 :17.683 421 421 E AlarmManagerService: Hello JNI: hello Stub found.01 -18 07 :07 :17.683 421 421 E Legacy HelloHAL: Hello: hello_device_open name = hello01 -18 07 :07 :17.683 421 421 E Legacy HelloHAL: Hello: open /dev/hello fail-- Permission denied.01 -18 07 :07 :17.683 421 421 E AlarmManagerService: Hello JNI: failed to open hello device.01 -18 07 :07 :17.685 421 421 E UsbAlsaJackDetectorJNI: Can' t register UsbAlsaJackDetector na
增加 avc 权限
关键信息是这句话缺少 avc 权限, 请注意前面的报错是 tcontext=u:object_r:device
这里是 tcontext=u:object_r:hello_device
说前面的 hello_device 修改已经生效.
1 2 01 -18 07 :07 :17.683 421 421 W system_server: type=1400 audit (0.0 :17 ): avc: denied { read write } for name="hello" dev="tmpfs" ino=3901 scontext=u:r:system_server:s0 tcontext=u:object_r:hello_device:s0 tclass=chr_file permissive=0
缺少什么权限: denied { read write }
==> 缺少 rw_file_perms
权限
那个文件缺少权限: scontext=u:r:system_server:s0
==> system_server.te
这个文件
谁缺少权限: tcontext=u:object_r:hello_device:s0
==> hello_device
这个对象
文件类型: tclass=chr_file
==> chr_file
字符设备
这里的知识详细请参考: 浅谈SEAndroid安全机制及应用方法
于是在 system/sepolicy/private/system_server.te
增加
1 2 3 4 5 6 7 8 9 10 11 12 13 -- a/private/system_server.te ++ b/private/system_server.te @@ -372,6 +372,7 @@ allow system_server video_device:chr_file rw_file_perms; allow system_server adbd_socket:sock_file rw_file_perms; allow system_server rtc_device:chr_file rw_file_perms; allow system_server audio_device:dir r_dir_perms; +allow system_server hello_device:chr_file rw_file_perms; # write access to ALSA interfaces (/dev/snd/*) needed for MIDI allow system_server audio_device:chr_file rw_file_perms;
修改的文件如下, 修改的内容和上面是一样的.
修改完成之后再次烧录验证查看 log, 正常发现设备正常打开 hall 层添加成功. 真不容易啊 =-=.
1 2 3 4 5 6 01 -18 07 :44 :49.688 415 415 E AlarmManagerService: HelloServiceInit HelloServiceInit01 -18 07 :44 :49.688 415 415 E AlarmManagerService: Hello JNI: initializing......01 -18 07 :44 :49.690 415 415 E AlarmManagerService: Hello JNI: hello Stub found.01 -18 07 :44 :49.691 415 415 E Legacy HelloHAL: Hello: hello_device_open name = hello01 -18 07 :44 :49.691 415 415 E Legacy HelloHAL: Hello: open /dev/hello successfully.01 -18 07 :44 :49.691 415 415 E AlarmManagerService: Hello JNI: hello device is open.
验证 hall 需要修改的 selinux 相关文件如下. 全部都要改到不要偷懒.
参考: https://blog.csdn.net/Luoshengyang/article/details/6567257
参考: https://developer.aliyun.com/article/651348
三、添加 HelloManager 服务.
hall 层是啥, 就是 so 库, 这个 so 库是 c++ 写的的, 而我们的系统服务和 app 有部分是 java 写的. 没法直接用啊, 于是 JNI 闪亮登场. JNI 是干啥的, 很简单, 就是将我们 hall 层的 c++ 接口转换成 java 接口. 然后我们的服务再将这个 java 接口导出到服务. app 就可以直接通过服务的接口操作我们的 hello 设备啦.
正常的顺序应该是添加 JNI, 但是添加之后没法直接验证, 所以先加服务方便验证和理解. 服务是啥, 服务就是长期在后台运行的进程, 我们也称之为任务组件. 它不需要用户界面进行操作. 服务的本质是进程, 因此服务与服务之间, 服务与app之间的接口调用的本质是进程间通讯. 在安卓中就是 binder.
1. 添加 aidl 接口
AIDL(Android Interface Definition Language)是 Android 中用于定义进程间通信(IPC)接口的一种语言,我们可以借助 AIDL 工具给我们自动生成继承 binder 方法的类. 来添加我们的 AIDL 吧.
创建文件 frameworks/base/core/java/android/os/IHelloService.aidl
文件的内容如下所示.
1 2 3 4 5 6 7 package android.os;interface IHelloService { void setVal (String value) ; String getVal () ; }
注意了在安卓 11 之后要加上 /** {@hide} */
这个注释, 不加会报错的. 我在这里卡了一天 =-= , 查不出任何问题. 这个问题请参考这篇文章, 增加aidl 文件提示Methods calling system APIs should rethrow `RemoteException` as `RuntimeException .
添加之后 AIDL 工具会帮我们生成支持 binder 的方法的类, 但我们还需扩展这个类并且实现对应的方法. 创建文件 frameworks/base/core/java/com/android/server/HelloService.java
. 内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package com.android.server;import android.content.Context;import android.content.Intent;import android.content.pm.PackageManager;import android.os.Binder;import android.os.Handler;import android.os.IBinder;import android.os.IHelloService;import android.os.RemoteException;import android.os.TokenWatcher;import android.os.UpdateLock;import android.os.UserHandle;import android.util.Slog;import com.android.internal.util.DumpUtils;import java.io.FileDescriptor;import java.io.PrintWriter;import java.util.HashMap;public class HelloService extends IHelloService .Stub { static final String TAG = "HelloService" ; Context mContext; public HelloService (Context context) { Slog.i(TAG, "HelloService init" ); mContext = context; } @Override public void setVal (String value) throws RemoteException { Slog.i(TAG, "setVal value = " +value); } @Override public String getVal () throws RemoteException { Slog.i(TAG, "getVal " ); return "getVal" ; } }
这里 setVal 方法和 getVal 方法直接打印 log 就行了, 后面会替换为 jni 转换 hall 接口 之后的接口. 打开 frameworks/base/Android.bp
我们可以发现
1 2 3 4 5 6 7 8 filegroup { name: "framework-core-sources" , srcs: [ "core/java/**/*.java" , "core/java/**/*.aidl" , ], path: "core/java" , }
安卓 11 之后默认就会添加 core/java/**/
下的 java 和 aidl 文件因此就不再需要我们修改 bp 文件了.
2. 添加 HelloService
添加服务之前首先需在 Context 中添加我们 HELLO_SERVICE 常量, 以后通过这个常量我们就能获取到对应的服务了.修改如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 -- a/core/java/android/content/Context.java ++ b/core/java/android/content/Context.java @@ -3400,6 +3400,7 @@ public abstract class Context { STORAGE_STATS_SERVICE, WALLPAPER_SERVICE, TIME_ZONE_RULES_MANAGER_SERVICE, + HELLO_SERVICE, VIBRATOR_SERVICE, //@hide: STATUS_BAR_SERVICE, CONNECTIVITY_SERVICE, @@ -5018,6 +5019,8 @@ public abstract class Context { */ public static final String TIME_ZONE_RULES_MANAGER_SERVICE = "timezone"; + public static final String HELLO_SERVICE = "hello"; + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.content.pm.CrossProfileApps} for cross profile operations.
接下来就是在 SystemServer 中注册 HelloService , 修改文件 frameworks/base/services/java/com/android/server/SystemServer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -- a/services/java/com/android/server/SystemServer.java ++ b/services/java/com/android/server/SystemServer.java @@ -1226,6 +1226,9 @@ public final class SystemServer { mSystemServiceManager.startService(PinnerService.class); t.traceEnd(); + Slog.i(TAG, "start hello Service"); + ServiceManager.addService(Context.HELLO_SERVICE, new HelloService(context)); + t.traceBegin("IorapForwardingService"); mSystemServiceManager.startService(IorapForwardingService.class); t.traceEnd();
我们的 HelloService 也是在这里实例化的. 注册之后我们就可以通过 ServiceManager.getServiceOrThrow(Context.HELLO_SERVICE)
拿到 HelloService
的 binder, 然后通过这个 binder 获取到这里注册的 IHelloService
了.
3. 添加 HelloManager 服务
为了 app 能够获取到服务, 我们需要对 HelloService 再一次进行封装, 添加文件 frameworks/base/core/java/android/app/HelloManager.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package android.app;import android.annotation.SdkConstant;import android.annotation.SystemApi;import android.content.Context;import android.content.Intent;import android.os.Build;import android.os.Parcel;import android.os.Parcelable;import android.os.RemoteException;import android.os.IHelloService;import android.util.Log;public class HelloManager { IHelloService mService; public HelloManager (Context ctx,IHelloService service) { mService = service; } public void setVal (String value) { try { Log.e("HelloManager" ,"HelloManager setVal" ); mService.setVal(value); }catch (Exception e){ Log.e("HelloManager" ,e.toString()); e.printStackTrace(); } } public String getVal () { try { Log.e("HelloManager" ,"HelloManager getVal" ); return mService.getVal(); }catch (Exception e){ Log.e("HelloManager" ,e.toString()); e.printStackTrace(); } return null ; } }
注意了 @hide
相关的注释不能去掉不然会报错. 接下来实例化这个服务并注册进系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 -- a/core/java/android/app/SystemServiceRegistry.java ++ b/core/java/android/app/SystemServiceRegistry.java @@ -169,6 +169,7 @@ import android.os.image.IDynamicSystemService; import android.os.incremental.IIncrementalService; import android.os.incremental.IncrementalManager; import android.os.storage.StorageManager; +import android.os.IHelloService; import android.os.IRnService; import android.permission.PermissionControllerManager; import android.permission.PermissionManager; @@ -1233,6 +1234,23 @@ public final class SystemServiceRegistry { } }); + registerService(Context.HELLO_SERVICE, HelloManager.class, + new CachedServiceFetcher<HelloManager>() { + @Override + public HelloManager createService(ContextImpl ctx) { + try { + IBinder b = ServiceManager.getServiceOrThrow(Context.HELLO_SERVICE); + Log.i(TAG, "registerService HELLO_SERVICE b = "+b); + IHelloService service = IHelloService.Stub.asInterface(b); + Log.i(TAG, "registerService HELLO_SERVICE service = "+service); + return new HelloManager(ctx, service); + } catch (ServiceNotFoundException e) { + Log.i(TAG, "registerService ServiceNotFoundException e = "+e); + onServiceNotFound(e); + return new HelloManager(ctx,null); + } + }}); + registerService(Context.TIME_DETECTOR_SERVICE, TimeDetector.class, new CachedServiceFetcher<TimeDetector>() { @Override
修改的全部文件如下所示
运行 make update-api
更新接口, 运行之后会增加下面两个文件, 就是编译器自动给我们新增对应的接口.
之后再运行 ./build.sh -UKAup
整编. 刷机报错如下所示.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 01 -18 11 :26 :10.933 429 429 I SystemServer: start hello Service01 -18 11 :26 :10.934 429 473 D PinnerService: pinRangeStream: null01 -18 11 :26 :10.935 429 429 I HelloService: HelloService init01 -18 11 :26 :10.935 429 473 D PinnerService: pinRangeStream: null01 -18 11 :26 :10.936 133 133 E SELinux : avc: denied { add } for pid=429 uid=1000 name=hello scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_service:s0 tclass=service_manager permissive=0 01 -18 11 :26 :10.936 429 473 D PinnerService: pinRangeStream: null01 -18 11 :26 :10.937 429 467 I DropBoxManagerService: add tag=system_server_strictmode isTagEnabled=true flags=0x2 01 -18 11 :26 :10.940 429 429 E System : ******************************************01 -18 11 :26 :10.941 429 429 E System : ************ Failure starting core service01 -18 11 :26 :10.941 429 429 E System : ******************************************01 -18 11 :26 :10.947 429 473 D PinnerService: pinRangeStream: null01 -18 11 :26 :10.948 429 473 I chatty : uid=1000 (system) android.bg identical 1 line01 -18 11 :26 :10.949 429 473 D PinnerService: pinRangeStream: null01 -18 11 :26 :10.955 429 429 E System : ************ Failure starting system services01 -18 11 :26 :10.955 429 429 E System : java.lang.SecurityException:
4. 增加 selinux 权限
请参考 SELinux权限问题解决参考
修改 system/sepolicy/public/service.te b/public/service.te
1 2 3 4 5 6 7 8 9 10 11 12 -- a/public/service.te ++ b/public/service.te @@ -146,6 +146,7 @@ type permissionmgr_service, app_api_service, ephemeral_app_api_service, system_s type persistent_data_block_service, system_api_service, system_server_service, service_manager_type; type pinner_service, system_server_service, service_manager_type; type power_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type; +type hello_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type; type print_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type; type processinfo_service, system_server_service, service_manager_type; type procstats_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type;
需要改的文件如下, 每个都要改
修改 system/sepolicy/private/service_contexts b/private/service_contexts
1 2 3 4 5 6 7 8 9 10 11 12 -- a/private/service_contexts ++ b/private/service_contexts @@ -166,6 +166,7 @@ phone2 u:object_r:radio_service:s0 phone u:object_r:radio_service:s0 pinner u:object_r:pinner_service:s0 power u:object_r:power_service:s0 +hello u:object_r:hello_service:s0 print u:object_r:print_service:s0 processinfo u:object_r:processinfo_service:s0 procstats u:object_r:procstats_service:s0
需要修改的文件如下, 每个都要改
改完之后编译下载. log 如下成功添加服务.
1 2 3 4 5 01 -18 12 :02 :30.899 429 429 D SystemServerTiming: PinnerService took to complete: 12 ms01 -18 12 :02 :30.899 429 429 I SystemServer: start hello Service01 -18 12 :02 :30.900 429 464 I DropBoxManagerService: add tag=system_server_strictmode isTagEnabled=true flags=0x2 01 -18 12 :02 :30.900 429 473 D PinnerService: pinRangeStream: null01 -18 12 :02 :30.901 429 429 I HelloService: HelloService init
我们 adb shell 之后运行 service list
在系统里面找见我们添加的服务.
四、Android studio 环境搭建
编写 app 调用 HelloManager 提供的服务. app 开发自然离不开 Android Studio . 这个工具是专门用来开发 app 的. 而不同版本之间对各个 api 的支持差异很大. 以下是我尝试使用过的不同版本的 Android Studio . 还有些被我删掉了. 总共试了十几个版本. 各版本下载地址 .
本次实验成功使用的版本信息如下, 为 Android Studio 4.2 Beta 6
1 2 3 4 5 6 7 8 9 Android Studio 4.2 Beta 6 Build #AI-202.7660.26.42.7188722, built on March 6, 2021 Runtime version: 11.0.8+10-b944.6842174 amd64 VM: OpenJDK 64-Bit Server VM by N/A Windows 10 10.0 GC: G1 Young Generation, G1 Old Generation Memory: 1280M Cores: 20 Registry: external.system.auto.import.disabled=true
对应的名字为 android-studio-ide-202.7188722-windows.exe
, 重要的事情说三遍, 一定要用这个版本, 一定要用这个版本, 一定要用这个版本 !!! . 这个破软件向下兼容性极差. =-=
1. 安装软件
双击 exe 文件, 会出现下面安装提示, 点击 next
这里记得勾选 android vitual device
.
接着设置安装路径, 我设置在 d 盘, 根据实际情况设置即可
接下来一直点 next 就行了
出现这个界面点击 cancel, 之后又是点击 next. 之后会提示配置 sdk 路径, 这里我选择默认 c 盘
接下来等待 sdk 的安装, 安装完成后界面如下.
到这里软件安装完成.
2. 配置软件
在打开新项目(project)之前要先配置 SDK manager
. 这一点很重要, 因为直接打开默认的 api 接口是 34 版本的, 而且使用的工具是也是 34 版本的.
如图所示在左下角打开 SDK manager
, 打开之后如下所示.
如图首先去掉 android api 34
然后勾选上 android 11
. 然后点击 SDK Tools
, 配置对应的工具
首先点击右下角 show package details
显示出详细的版本, 然后同样的把 34.0.0
去掉, 勾选上 30.0.2
和 30.0.3
. 之后点击 apply.
如图点击 next 进入安装. 等待安装完成
SKD Platforms
: 表示使用哪个 sdk , 安卓 11 对应的 sdk 是 30
SDK Tools
: 和前面的版本需要对应
3. 构建项目
下载完成之后回到前面, 点击创建新项目 project
选择一个 empty activity
.
语言选择 java, sdk 选择 Android 11, 之后点击 finish
这里选择 project 方便看代码
接下来会报错如下
到这里项目构建就结束了, 接下来就是配置项目解决报错
3. 配置项目
对目录结构有个了解. 此部分请参考 Android studio项目目录结构 . 其中需要关注的目录如下.
目录
功能
libs
存放第三方 jar 包的目录, 我们要用我们自己的sdk编译出来包替换掉 as 中默认的包
MainActivity.java
程序从这里开始运行, 可以理解为 c 语言的 main 函数
app/build.gradle
app 模块的构建配置, 包括 sdk 版本, 以及包含哪些 jar 包等
/build.gradle
根目录下的 build.gradle 是整个项目的配置文件, 用来指定整具体使用哪个 gradle 插件
gradle-wrapper.properties
指定了那个 gradle 工具
gradle 插件 : 插件提供一些默认的 api 版本, 比如这里使用的安卓 11 就需要使用 gradle:4.2.0
gradle 工具 : 用于整个项目的构建, 测试和部署.
gradle 插件
, gradle 工具
, 和 java 版本(jdk版本)
之间的对应关系请参考 Android Studio Gradle插件版本与Gradle 版本对应关系 .
1) 解决超时的报错
有了上述知识之后我们开始配置我们的项目, 首先解决超时报错, 修改文件 gradle\-wrapper.properties
, 首先更换 gradle 工具的下载地址.
具体修改如图所示
然后打开根目录下 build.gradle
做如下修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 buildscript { repositories { maven { url 'https://maven.aliyun.com/repository/jcenter' } maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } maven { url 'https://maven.aliyun.com/repository/public' } google() mavenCentral() } dependencies { classpath "com.android.tools.build:gradle:4.2.0" } }
具体修改如图所示
完成之后点击右上角的 try again
, 这个选项只有选中这个文件才会出现, 所以要构建项目要先选中这个文件, 不然右上角是不会出现这个选项的. 点击之后等待项目构建完成, 这个构建的时间比较长. 编译完成之后会有如下警告.
这个警告没有任何影响, 假装没看见就行了, 不要去注释掉 jcenter()
, 注释掉会报错. 插上机器, 点击运行, 如下所示显示 hello world 就是编译成功了.
2) 导入本地 sdk 的 jar
虽然编译成功了但是调用的接口是, gradle 工具提供的默认接口, 现在还没法调用, 我们需要我们的 app 调用我们 sdk 中添加的 hello 服务能编译通过, 得加入 sdk 中编译出来的 jar 包. 对应的路径
1 2 $ ls out/target/common/obj/JAVA_LIBRARIES/framework-minus-apex_intermediates/ classes-header.jar classes.jar javalib.jar
我们需要 classes.jar , 记得在编译之前要把这个删掉再编译, 不然这个可能不会更新的, 导致这个包里面没有更新接口 . 把这个拷贝到 app 的 libs 目录, 并且改名为 framework.jar
, 然后在 app/gradle 中添加以下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 gradle.projectsEvaluated { tasks.withType(JavaCompile) { Set<File> fileSet = options.bootstrapClasspath.getFiles() List<File> newFileList = new ArrayList <>(); newFileList.add(new File ("libs/framework.jar" )) newFileList.addAll(fileSet) options.bootstrapClasspath = files( newFileList.toArray() ) } } dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.1' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' compileOnly files ('libs/framework.jar' ) }
修改如图所示
注意了设置里面需要将 “generate *imx” 勾选上用于创建自动创建 imx 文件, 这个文件用来调整使用的 sdk 的顺序. 可以在这里将我们的 jar 提前.接着在根目录下的 build_gradle 中添加下面的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 allprojects { repositories { google() mavenCentral() jcenter() } tasks.withType(JavaCompile) { options.compilerArgs.add('-Xbootclasspath/p:app\\libs\\framework.jar' ) } } task clean (type: Delete) { delete rootProject.buildDir } gradle.projectsEvaluated { tasks.withType(JavaCompile) { options.compilerArgs.add('-Xbootclasspath/p:app\\libs\\framework.jar' ) } }
具体修改内容如图所示
然后点击右上角的 sync now
再次构建. 构建完之后可以看到 framework.jar
已经是可以打开的状态. 同时自动为我们创建了 My_Application.app.imx
文件, 现在需要修改编译顺序, 将默认的sdk 放到最后面, 这样就会优先使用我们的 framework.jar
中的内容了.
到这里 Android studio 的环境就搭建完成了, 终于可以开始 app 的编写了.
5、 编写 app
这一步就比较简单了, 修改文件
1 MyApplication\app\src\main\java\com\example\myapplication\MainActivity.java
修改内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.example.myapplication;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.app.HelloManager;import android.content.Context;import android.util.Slog;public class MainActivity extends AppCompatActivity { private HelloManager mHelloManager; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHelloManager = (HelloManager)getSystemService(Context.HELLO_SERVICE); mHelloManager.setVal("Hello" ); Slog.i("HelloServiceTest" , "HelloService TEST getVal = " +mHelloManager.getVal()); } }
修改完之后点击运行, 如下图所示.
同步 adb shell 之后 logcat 查看 log 如下, 系统服务接口调佣成功 ∧_∧
1 2 3 4 5 6 7 01 -26 02 :27 :10.359 2251 2251 I SystemServiceRegistry: registerService HELLO_SERVICE b = android.os.BinderProxy@48b 7bd801 -26 02 :27 :10.360 2251 2251 I SystemServiceRegistry: registerService HELLO_SERVICE service = android.os.IHelloService$Stub$Proxy@2f bb3101 -26 02 :27 :10.360 2251 2251 E HelloManager: HelloManager setVal01 -26 02 :27 :10.361 434 1429 I HelloService: setVal value = Hello01 -26 02 :27 :10.362 2251 2251 E HelloManager: HelloManager getVal01 -26 02 :27 :10.362 434 1429 I HelloService: getVal01 -26 02 :27 :10.363 2251 2251 I HelloServiceTest: HelloService TEST getVal = getVal
6、添加 jni
这个部分的内容照搬 AndroidQ 从app到驱动 第五章 编写J NI 层完成 HelloService与 Hal 层的对接
创建文件 services/core/jni/com_android_server_HelloService.cpp
, 将 hall 接口转换为 java 接口.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 #define LOG_TAG "Hello_JNI" #include "jni.h" #include "core_jni_helpers.h" #include <utils/Log.h> #include <openssl/crypto.h> #include <hardware/hardware.h> #include <hardware/hello.h> namespace { struct hello_device* hello_device = NULL; static inline int hello_device_open (const hw_module_t* module , struct hello_device** device) { return module ->methods->open(module , HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device); } static jint HelloServiceInit (JNIEnv* env, jobject ) { ALOGE("com_android_server_HelloService HelloServiceInit" ); const hw_module_t *hw_module = NULL; ALOGE("Hello JNI: initializing......" ); if (hw_get_module(HELLO_HARDWARE_MODULE_ID, &hw_module) == 0 ) { ALOGE("Hello JNI: hello Stub found." ); if (hello_device_open(hw_module, &hello_device) == 0 ) { ALOGE("Hello JNI: hello device is open." ); return 0 ; } ALOGE("Hello JNI: failed to open hello device." ); return -1 ; } ALOGE("Hello JNI: failed to get hello stub hw_module." ); return -1 ; } static void HelloServiceNativeSetVal (JNIEnv* env, jobject clazz,jstring nativeValue) { ALOGE("com_android_server_HelloService HelloServiceNativeSetVal" ); if (!hello_device) { ALOGI("Hello JNI: hello_device is not open." ); return ; } const char * local_value = (nativeValue) ? env->GetStringUTFChars(nativeValue, NULL) : NULL; ALOGE("com_android_server_HelloService HelloServiceNativeSetVal local_value = %s" ,local_value); hello_device->write_string(hello_device, local_value); ALOGI("Hello JNI: write string %s to Hello hello_device." , local_value); env->ReleaseStringUTFChars(nativeValue, local_value); } static jstring HelloServiceNativeGetVal (JNIEnv* env,jobject clazz) { ALOGE("com_android_server_HelloService HelloServiceNativeGetVal" ); if (!hello_device) { ALOGE("Hello JNI: hello_device is not open." ); return NULL; } char read_str[100 ]; read_str[99 ] = '\0' ; hello_device->read_string(hello_device,read_str); ALOGE("Hello JNI: read string %s from Hello hello_device." , read_str); jstring result = (env)->NewStringUTF(read_str); return result; } static const JNINativeMethod methods[] = { {"HelloServiceInit" , "()I" , (void *) HelloServiceInit}, {"HelloServiceNativeSetVal" , "(Ljava/lang/String;)V" ,(void *) HelloServiceNativeSetVal}, {"HelloServiceNativeGetVal" , "()Ljava/lang/String;" ,(void *) HelloServiceNativeGetVal}, }; } namespace android { int register_android_server_HelloService (JNIEnv *env) { return jniRegisterNativeMethods(env, "com/android/server/HelloService" , methods, NELEM(methods)); } }
修改 services/core/jni/Android.bp
编译这个文件
1 2 3 4 5 6 7 8 9 10 11 12 -- a/services/core/jni/Android.bp ++ b/services/core/jni/Android.bp @@ -62,6 +62,7 @@ cc_library_static { "com_android_server_rkdisplay_RkDisplayModes.cpp", "com_android_server_audio_RkAudioSetting.cpp", "com_android_server_RnService.cpp", + "com_android_server_HelloService.cpp", "onload.cpp", ":lib_networkStatsFactory_native", ],
修改 services/core/jni/onload.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 987 c8aca0a1f..34e41 d2a7273 100755 -- a/services/core/jni/onload.cpp ++ b/services/core/jni/onload.cpp @@ -67 ,6 +67 ,7 @@ int register_android_server_GpuService (JNIEnv* env) ; int register_com_android_server_rkdisplay_RkDisplayModes (JNIEnv* env) ; int register_com_android_server_audio_RkAudioSetting (JNIEnv* env) ; int register_android_server_RnService (JNIEnv *env) ; +int register_android_server_HelloService (JNIEnv *env) ; }; using namespace android; @@ -128 ,6 +129 ,7 @@ extern "C" jint JNI_OnLoad (JavaVM* vm, void * ) register_com_android_server_rkdisplay_RkDisplayModes (env) ; register_com_android_server_audio_RkAudioSetting (env); register_android_server_RnService (env); + register_android_server_HelloService (env); return JNI_VERSION_1_4; }
最后在 core/java/com/android/server/HelloService.java
中调用转换之后的 java 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -- a/core/java/com/android/server/HelloService.java ++ b/core/java/com/android/server/HelloService.java @@ -24,20 +24,26 @@ public class HelloService extends IHelloService.Stub { static final String TAG = "HelloService"; Context mContext; + private native int HelloServiceInit(); + private native void HelloServiceNativeSetVal(String value); + private native String HelloServiceNativeGetVal(); + public HelloService(Context context) { Slog.i(TAG, "HelloService init"); + HelloServiceInit(); mContext = context; } @Override public void setVal(String value) throws RemoteException { Slog.i(TAG, "setVal value = " + value); + HelloServiceNativeSetVal(value); } @Override public String getVal() throws RemoteException { Slog.i(TAG, "getVal "); - return "getVal"; + return HelloServiceNativeGetVal(); } }
需要修改的文件如下所示:
整编然后刷机打印 log 调用成功, app 成功调用驱动 hello 的接口.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 01 -26 06 :59 :38.281 2402 2402 I SystemServiceRegistry: registerService HELLO_SERVICE b = android.os.BinderProxy@f30b5b301 -26 06 :59 :38.283 2402 2402 I SystemServiceRegistry: registerService HELLO_SERVICE service = android.os.IHelloService$Stub$Proxy@a8c177001 -26 06 :59 :38.283 2402 2402 E HelloManager: HelloManager setVal01 -26 06 :59 :38.284 434 502 I HelloService: setVal value = Hello01 -26 06 :59 :38.284 434 502 E Hello_JNI: com_android_server_HelloService HelloServiceNativeSetVal01 -26 06 :59 :38.284 434 502 E Hello_JNI: com_android_server_HelloService HelloServiceNativeSetVal local_value = Hello01 -26 06 :59 :38.284 434 502 E Legacy HelloHAL: Hello:write string: Hello01 -26 06 :59 :38.284 434 502 I Hello_JNI: Hello JNI: write string Hello to Hello hello_device.01 -26 06 :59 :38.405 0 0 W : baron my_write01 -26 06 :59 :38.285 2402 2402 E HelloManager: HelloManager getVal01 -26 06 :59 :38.285 434 502 I HelloService: getVal01 -26 06 :59 :38.285 434 502 E Hello_JNI: com_android_server_HelloService HelloServiceNativeGetVal01 -26 06 :59 :38.285 434 502 E Legacy HelloHAL: Hello:read hello_read_string01 -26 06 :59 :38.285 434 502 E Hello_JNI: Hello JNI: read string Hello from Hello hello_device.01 -26 06 :59 :38.406 0 0 W : baron my_read01 -26 06 :59 :38.286 2402 2402 I HelloServiceTest: HelloService TEST getVal = Hello