├── 3.学穿Binder篇 ├── 019. Binder 系统源码演进.md ├── 024. Binder 面试题解析.md ├── 021. Binder 死亡通知机制分析.md ├── 023. Binder 疑难案例分析2.md ├── 018. AIDL 中的 in,out,inout 分析.md ├── 020. Binder 应用层数据结构 Parcel 实现分析.md ├── 源码 │ ├── hello_drv_test │ │ ├── build │ │ │ ├── CMakeFiles │ │ │ │ ├── progress.marks │ │ │ │ ├── hello_drv_test.dir │ │ │ │ │ ├── progress.make │ │ │ │ │ ├── hello_drv_test.c.o │ │ │ │ │ ├── depend.make │ │ │ │ │ ├── depend.internal │ │ │ │ │ ├── cmake_clean.cmake │ │ │ │ │ ├── C.includecache │ │ │ │ │ ├── flags.make │ │ │ │ │ ├── DependInfo.cmake │ │ │ │ │ ├── link.txt │ │ │ │ │ └── build.make │ │ │ │ ├── cmake.check_cache │ │ │ │ ├── 3.16.3 │ │ │ │ │ ├── CMakeDetermineCompilerABI_C.bin │ │ │ │ │ ├── CMakeDetermineCompilerABI_CXX.bin │ │ │ │ │ ├── CMakeSystem.cmake │ │ │ │ │ └── CMakeCCompiler.cmake │ │ │ │ ├── TargetDirectories.txt │ │ │ │ ├── CMakeDirectoryInformation.cmake │ │ │ │ ├── Makefile2 │ │ │ │ └── Makefile.cmake │ │ │ ├── hello_drv_test │ │ │ ├── cmake_install.cmake │ │ │ └── Makefile │ │ ├── CMakeLists.txt │ │ ├── build_hello_driver_test.sh │ │ └── hello_drv_test.c │ ├── BinderCDemo │ │ ├── README.md │ │ ├── Android.bp │ │ ├── binder_client.c │ │ ├── binder.h │ │ └── binder_server.c │ ├── BinderCppDemo │ │ ├── README.md │ │ ├── BinderServer.cpp │ │ ├── BpHelloService.cpp │ │ ├── BinderClient.cpp │ │ ├── IHelloService.h │ │ ├── Android.bp │ │ └── BnHelloService.cpp │ ├── AIDLCppDemo │ │ ├── com │ │ │ └── yuandaima │ │ │ │ ├── IHello.aidl │ │ │ │ ├── BnHello.h │ │ │ │ ├── BpHello.h │ │ │ │ └── IHello.h │ │ ├── HelloClient.cpp │ │ ├── HelloServer.cpp │ │ ├── Android.bp │ │ └── IHello.cpp │ ├── BinderJavaDemo │ │ └── com │ │ │ └── yuandaima │ │ │ ├── IHelloService.aidl │ │ │ ├── Android.bp │ │ │ ├── HelloService.java │ │ │ ├── Server.java │ │ │ ├── Client.java │ │ │ └── IHelloService.java │ ├── hello_drv │ │ ├── build_driver.sh │ │ ├── Makefile │ │ └── hello_drv.c │ └── datastructuretest │ │ └── data_structure_test.c ├── ppt与思维导图 │ ├── Binder架构.pptx │ ├── 学穿 Binder.png │ ├── Binder 基本原理.pptx │ ├── 内核常用数据结构图.pptx │ ├── Binder驱动源码分析.pptx │ ├── 学穿 Binder 大纲.xmind │ ├── Binder Java 层分析.pptx │ ├── 学习 Binder 的预备知识1.pptx │ ├── 学习 Binder 的预备知识2.pptx │ ├── 学习 Binder 的预备知识3.pptx │ ├── 学习 Binder 的预备知识4.pptx │ ├── Binder 程序示例之 C 语言篇.pptx │ ├── 学习 Binder 的预备知识示例图.pptx │ ├── binder_publish 函数分析.pptx │ ├── Android Binder 驱动框架设计与分析.pptx │ ├── Binder C 语言示例源码分析之服务注册过程.pptx │ ├── Binder C 语言示例源码分析之服务获取与使用.pptx │ ├── Android Binder 驱动情景分析之服务注册过程.pptx │ ├── 如何深入掌握 Android 系统开发的拦路虎 Binder.pptx │ ├── 000.Binder 专题导学 —— 如何深入掌握 Binder.pptx │ ├── Binder C 语言示例源码分析之 ServiceManager 启动.pptx │ ├── Binder 驱动情景分析之 ServiceManager 启动过程.pptx │ ├── ~$Binder架构.pptx │ ├── ~$内核常用数据结构图.pptx │ ├── ~$Binder驱动源码分析.pptx │ ├── ~$学习 Binder 的预备知识1.pptx │ ├── ~$学习 Binder 的预备知识3.pptx │ ├── ~$学习 Binder 的预备知识4.pptx │ ├── ~$学习 Binder 的预备知识示例图.pptx │ ├── ~$Binder C 语言示例源码分析之服务获取与使用.pptx │ ├── ~$如何深入掌握 Android 系统开发的拦路虎 Binder.pptx │ └── ~$Binder 驱动情景分析之 ServiceManager 启动过程.pptx ├── 022. Binder 疑难案例分析1.md ├── ~$Binder架构.pptx ├── 参考资料.md ├── 001. Binder 基本原理.md ├── 草稿.md ├── 视频课程讲稿 │ └── 000.Binder 专题导学 —— 如何深入掌握 Binder.md └── 013. Binder 程序示例之 Java 篇.md ├── 1.基础篇 ├── src │ └── AndroidRunCpp │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── main.cpp │ │ └── build.sh ├── JNI 编程上手指南 │ ├── src │ │ ├── DynamicRegister │ │ │ ├── .gitignore │ │ │ ├── com │ │ │ │ └── example │ │ │ │ │ └── ndk │ │ │ │ │ └── NativeTest.java │ │ │ └── NativeTest.c │ │ └── StaticRegister │ │ │ ├── .gitignore │ │ │ ├── HelloJNI.c │ │ │ ├── HelloJNI.h │ │ │ └── HelloJNI.java │ ├── JNI 编程上手指南.xmind │ ├── 参考资料.md │ ├── 003.JNI 编程上手指南之描述符.md │ ├── 005.JNI 编程上手指南之 JavaVM 详解.md │ ├── 012.JNI编程上手指南之多线程.md │ ├── 011.JNI 编程上手指南之 JNI 调用性能优化.md │ ├── 009.JNI 编程上手指南之异常处理.md │ ├── 004.JNI 编程上手指南之 JNIEnv 详解.md │ ├── 010.JNI 编程上手指南之从内存角度再看引用类型.md │ └── 008.JNI 编程上手指南之 Native 访问 Java.md ├── 003.Android 平台如何编译执行 C C++ 可执行程序.md └── 005.Linux Shell 脚本编程入门2——脚本自动化基础.md ├── 4.Hal与硬件服务 ├── src │ ├── HelloHidl_Bindered │ │ ├── sepolicy │ │ │ ├── device.te │ │ │ ├── hwservice.te │ │ │ ├── hwservice_contexts │ │ │ ├── file_contexts │ │ │ ├── hello_hidl_test.te │ │ │ └── hello_hidl.te │ │ └── jelly │ │ │ └── hardware │ │ │ └── interfaces │ │ │ ├── current.txt │ │ │ ├── Android.bp │ │ │ ├── update-makefiles.sh │ │ │ └── hello_hidl │ │ │ └── 1.0 │ │ │ ├── default │ │ │ ├── jelly.hardware.hello_hidl@1.0-service.rc │ │ │ ├── test │ │ │ │ ├── Android.bp │ │ │ │ └── hello_hidl_test.cpp │ │ │ ├── jelly.hardware.hello_hidl@1.0-service.xml │ │ │ ├── service.cpp │ │ │ ├── Android.bp │ │ │ ├── Hello.h │ │ │ └── Hello.cpp │ │ │ ├── IHello.hal │ │ │ └── Android.bp │ ├── HelloHidl_Passthrough │ │ ├── sepolicy │ │ │ ├── hwservice.te │ │ │ ├── hwservice_contexts │ │ │ ├── device.te │ │ │ ├── file_contexts │ │ │ └── hellohidl.te │ │ └── jelly │ │ │ └── hardware │ │ │ └── interfaces │ │ │ ├── current.txt │ │ │ ├── Android.bp │ │ │ ├── hello_hidl │ │ │ └── 1.0 │ │ │ │ ├── IHello.hal │ │ │ │ ├── default │ │ │ │ ├── jelly.hardware.hello_hidl@1.0-service.rc │ │ │ │ ├── test │ │ │ │ │ ├── Android.bp │ │ │ │ │ └── hello_hidl_test.cpp │ │ │ │ ├── service.cpp │ │ │ │ ├── jelly.hardware.hello_hidl@1.0-service.xml │ │ │ │ ├── Hello.cpp │ │ │ │ ├── Android.bp │ │ │ │ └── Hello.h │ │ │ │ └── Android.bp │ │ │ └── update-makefiles.sh │ ├── HelloDriver │ │ ├── CMakeLists.txt │ │ ├── build_driver.sh │ │ ├── Makefile │ │ ├── build_driver_test.sh │ │ ├── hello_drv_test.c │ │ └── hello_drv.c │ └── HelloModule │ │ └── hello_module.c ├── 4. Hal 层接口之直通模式.md └── 1.Kernel 下载与编译.md ├── 6.基础组件 ├── 课程介绍.pptx └── ~$课程介绍.pptx ├── 视频课程讲稿 ├── 添加可执行程序.pptx ├── AOSP极速上手.pptx ├── 添加Product.pptx ├── 添加Product.sai2 ├── 添加系统App源码.pptx ├── 系统开发工具推荐.pptx └── 001.AOSP 极速上手课程讲稿.md ├── 参考资料.md ├── 写给应用开发的 Android Framework 教程大纲.xmind ├── 疑难处理 └── module “dx-doc-stubs“ already defined错误.md └── 2.AOSP上手指南 ├── 011. Apk 预装入门.md ├── 006.添加配置文件与删除已有模块.md ├── 012.如何阅读系统源码——C C++篇.md └── 010.添加开机自启动 Shell 脚本.md /3.学穿Binder篇/019. Binder 系统源码演进.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /3.学穿Binder篇/024. Binder 面试题解析.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /3.学穿Binder篇/021. Binder 死亡通知机制分析.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /3.学穿Binder篇/023. Binder 疑难案例分析2.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /3.学穿Binder篇/018. AIDL 中的 in,out,inout 分析.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /1.基础篇/src/AndroidRunCpp/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /3.学穿Binder篇/020. Binder 应用层数据结构 Parcel 实现分析.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/src/DynamicRegister/.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.class -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/src/StaticRegister/.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.so -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/progress.marks: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCDemo/README.md: -------------------------------------------------------------------------------- 1 | # BinderCDemo 2 | Binder C 程序示例 3 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCppDemo/README.md: -------------------------------------------------------------------------------- 1 | # BinderCppDemo 2 | Binder C++ 示例程序 3 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/sepolicy/device.te: -------------------------------------------------------------------------------- 1 | type hello_hidl_dev_t, dev_type; -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/sepolicy/hwservice.te: -------------------------------------------------------------------------------- 1 | type hello_hidl_hwservice, hwservice_manager_type; -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/sepolicy/hwservice.te: -------------------------------------------------------------------------------- 1 | type hello_hidl_hwservice, hwservice_manager_type; -------------------------------------------------------------------------------- /6.基础组件/课程介绍.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/6.基础组件/课程介绍.pptx -------------------------------------------------------------------------------- /视频课程讲稿/添加可执行程序.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/视频课程讲稿/添加可执行程序.pptx -------------------------------------------------------------------------------- /视频课程讲稿/AOSP极速上手.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/视频课程讲稿/AOSP极速上手.pptx -------------------------------------------------------------------------------- /视频课程讲稿/添加Product.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/视频课程讲稿/添加Product.pptx -------------------------------------------------------------------------------- /视频课程讲稿/添加Product.sai2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/视频课程讲稿/添加Product.sai2 -------------------------------------------------------------------------------- /视频课程讲稿/添加系统App源码.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/视频课程讲稿/添加系统App源码.pptx -------------------------------------------------------------------------------- /视频课程讲稿/系统开发工具推荐.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/视频课程讲稿/系统开发工具推荐.pptx -------------------------------------------------------------------------------- /参考资料.md: -------------------------------------------------------------------------------- 1 | # 参考资料 2 | 3 | * [Android P SELinux (四) CTS neverallow处理总结](https://blog.csdn.net/headwind_/article/details/119711869) -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/progress.make: -------------------------------------------------------------------------------- 1 | CMAKE_PROGRESS_1 = 1 2 | CMAKE_PROGRESS_2 = 2 3 | 4 | -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/JNI 编程上手指南.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/1.基础篇/JNI 编程上手指南/JNI 编程上手指南.xmind -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Binder架构.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Binder架构.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/学穿 Binder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/学穿 Binder.png -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/sepolicy/hwservice_contexts: -------------------------------------------------------------------------------- 1 | jelly.hardware.hello_hidl::IHello u:object_r:hello_hidl_hwservice:s0 2 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/sepolicy/hwservice_contexts: -------------------------------------------------------------------------------- 1 | jelly.hardware.hello_hidl::IHello u:object_r:hello_hidl_hwservice:s0 2 | -------------------------------------------------------------------------------- /1.基础篇/src/AndroidRunCpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(main) 4 | 5 | add_executable(${PROJECT_NAME} main.cpp ) -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Binder 基本原理.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Binder 基本原理.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/内核常用数据结构图.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/内核常用数据结构图.pptx -------------------------------------------------------------------------------- /写给应用开发的 Android Framework 教程大纲.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/写给应用开发的 Android Framework 教程大纲.xmind -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Binder驱动源码分析.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Binder驱动源码分析.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/学穿 Binder 大纲.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/学穿 Binder 大纲.xmind -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/cmake.check_cache: -------------------------------------------------------------------------------- 1 | # This file is generated by cmake for dependency checking of the CMakeCache.txt file 2 | -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Binder Java 层分析.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Binder Java 层分析.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/学习 Binder 的预备知识1.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/学习 Binder 的预备知识1.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/学习 Binder 的预备知识2.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/学习 Binder 的预备知识2.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/学习 Binder 的预备知识3.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/学习 Binder 的预备知识3.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/学习 Binder 的预备知识4.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/学习 Binder 的预备知识4.pptx -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloDriver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(test) 4 | 5 | add_executable(${PROJECT_NAME} hello_drv_test.c) -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Binder 程序示例之 C 语言篇.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Binder 程序示例之 C 语言篇.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/学习 Binder 的预备知识示例图.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/学习 Binder 的预备知识示例图.pptx -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/sepolicy/device.te: -------------------------------------------------------------------------------- 1 | # 定义设备 /dev/hello_seandroid_dev 的类型 2 | type hello_se_dev_t, dev_type; 3 | type hello_hidl_dev_t, dev_type; -------------------------------------------------------------------------------- /3.学穿Binder篇/022. Binder 疑难案例分析1.md: -------------------------------------------------------------------------------- 1 | # Binder 疑难案例 2 | 3 | * 死锁 4 | * 线程池满了 5 | * 代理对象内存泄露 6 | * 传输数据过大 7 | * 关键方法内发起 Binder 同步调用导致卡顿 8 | * Android O 异步远程调用无限阻塞冻屏 bug -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/binder_publish 函数分析.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/binder_publish 函数分析.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/AIDLCppDemo/com/yuandaima/IHello.aidl: -------------------------------------------------------------------------------- 1 | package com.yuandaima; 2 | 3 | interface IHello 4 | { 5 | void hello(); 6 | int sum(int x, int y); 7 | } -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(hello_drv_test) 4 | 5 | add_executable(${PROJECT_NAME} hello_drv_test.c) -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Android Binder 驱动框架设计与分析.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Android Binder 驱动框架设计与分析.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Binder C 语言示例源码分析之服务注册过程.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Binder C 语言示例源码分析之服务注册过程.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Binder C 语言示例源码分析之服务获取与使用.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Binder C 语言示例源码分析之服务获取与使用.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/hello_drv_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/源码/hello_drv_test/build/hello_drv_test -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/current.txt: -------------------------------------------------------------------------------- 1 | 59d241f85a546e2618ea751636db9214610047701d2d54acd2560df3e47c62df jelly.hardware.hello_hidl@1.0::IHello 2 | -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Android Binder 驱动情景分析之服务注册过程.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Android Binder 驱动情景分析之服务注册过程.pptx -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/Android.bp: -------------------------------------------------------------------------------- 1 | hidl_package_root { 2 | name: "jelly.hardware", 3 | path: "vendor/jelly/hardware/interfaces", 4 | } 5 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/current.txt: -------------------------------------------------------------------------------- 1 | 746416bfc7df897c928a48dc38be7d04185d5e77b23974915bef5598c0271b18 jelly.hardware.hello_hidl@1.0::IHello 2 | -------------------------------------------------------------------------------- /6.基础组件/~$课程介绍.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/如何深入掌握 Android 系统开发的拦路虎 Binder.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/如何深入掌握 Android 系统开发的拦路虎 Binder.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderJavaDemo/com/yuandaima/IHelloService.aidl: -------------------------------------------------------------------------------- 1 | package com.yuandaima; 2 | 3 | interface IHelloService 4 | { 5 | void sayhello(); 6 | int sayhello_to(String name); 7 | } -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/Android.bp: -------------------------------------------------------------------------------- 1 | hidl_package_root { 2 | name: "jelly.hardware", 3 | path: "vendor/jelly/hardware/interfaces", 4 | } 5 | -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/000.Binder 专题导学 —— 如何深入掌握 Binder.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/000.Binder 专题导学 —— 如何深入掌握 Binder.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/~$Binder架构.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Binder C 语言示例源码分析之 ServiceManager 启动.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Binder C 语言示例源码分析之 ServiceManager 启动.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/Binder 驱动情景分析之 ServiceManager 启动过程.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/ppt与思维导图/Binder 驱动情景分析之 ServiceManager 启动过程.pptx -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/~$Binder架构.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/~$内核常用数据结构图.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/~$Binder驱动源码分析.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/~$学习 Binder 的预备知识1.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/~$学习 Binder 的预备知识3.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/~$学习 Binder 的预备知识4.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/~$学习 Binder 的预备知识示例图.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/~$Binder C 语言示例源码分析之服务获取与使用.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/~$如何深入掌握 Android 系统开发的拦路虎 Binder.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /3.学穿Binder篇/ppt与思维导图/~$Binder 驱动情景分析之 ServiceManager 启动过程.pptx: -------------------------------------------------------------------------------- 1 | ahao ahao -------------------------------------------------------------------------------- /1.基础篇/src/AndroidRunCpp/main.cpp: -------------------------------------------------------------------------------- 1 | # include 2 | 3 | int main(int argc, char const *argv[]) 4 | { 5 | for(int i = 0; i < 5; ++i) 6 | std::cout << "Hello World" << std::endl; 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/hello_hidl/1.0/IHello.hal: -------------------------------------------------------------------------------- 1 | package jelly.hardware.hello_hidl@1.0; 2 | 3 | interface IHello { 4 | addition_hidl(uint32_t a,uint32_t b) generates (uint32_t total); 5 | }; -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_C.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_C.bin -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_CXX.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuandaimaahao/AndroidFrameworkTutorial/HEAD/3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/3.16.3/CMakeDetermineCompilerABI_CXX.bin -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/src/StaticRegister/HelloJNI.c: -------------------------------------------------------------------------------- 1 | #include "HelloJNI.h" 2 | #include 3 | #include 4 | 5 | JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj) 6 | { 7 | return (*env)->NewStringUTF(env,"Hello from JNI !"); 8 | } -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/depend.make: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.16 3 | 4 | CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o: ../hello_drv_test.c 5 | 6 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/update-makefiles.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source $ANDROID_BUILD_TOP/system/tools/hidl/update-makefiles-helper.sh 4 | 5 | do_makefiles_update \ 6 | "jelly.hardware:vendor/jelly/hardware/interfaces" 7 | 8 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloDriver/build_driver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export ARCH=x86_64 3 | export SUBARCH=x86_64 4 | export CROSS_COMPILE=x86_64-linux-android- 5 | export PATH=/home/zzh0838/Project/Android10/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin:$PATH 6 | make -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/hello_hidl/1.0/default/jelly.hardware.hello_hidl@1.0-service.rc: -------------------------------------------------------------------------------- 1 | service vendor_hello_hidl_service /vendor/bin/hw/jelly.hardware.hello_hidl@1.0-service 2 | class hal 3 | user system 4 | group system 5 | 6 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/hello_hidl/1.0/default/jelly.hardware.hello_hidl@1.0-service.rc: -------------------------------------------------------------------------------- 1 | service vendor_hello_hidl_service /vendor/bin/hw/jelly.hardware.hello_hidl@1.0-service 2 | class hal 3 | user system 4 | group system 5 | 6 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/update-makefiles.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source $ANDROID_BUILD_TOP/system/tools/hidl/update-makefiles-helper.sh 4 | 5 | do_makefiles_update \ 6 | "jelly.hardware:vendor/jelly/hardware/interfaces" 7 | 8 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv/build_driver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export ARCH=x86_64 3 | export SUBARCH=x86_64 4 | export CROSS_COMPILE=x86_64-linux-android- 5 | export PATH=/home/android/Project/android10_r41/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin:$PATH 6 | 7 | make -C .. -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/TargetDirectories.txt: -------------------------------------------------------------------------------- 1 | /home/android/Project/hello_drv_test/build/CMakeFiles/rebuild_cache.dir 2 | /home/android/Project/hello_drv_test/build/CMakeFiles/edit_cache.dir 3 | /home/android/Project/hello_drv_test/build/CMakeFiles/hello_drv_test.dir 4 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloDriver/Makefile: -------------------------------------------------------------------------------- 1 | KERN_DIR = /home/zzh0838/Project/Kernel/goldfish 2 | 3 | all: 4 | make -C $(KERN_DIR) M=`pwd` modules 5 | 6 | clean: 7 | make -C $(KERN_DIR) M=`pwd` modules clean 8 | rm -rf modules.order 9 | rm -f hello_drv_test 10 | 11 | obj-m += hello_drv.o -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/sepolicy/file_contexts: -------------------------------------------------------------------------------- 1 | /dev/hello u:object_r:hello_hidl_dev_t:s0 2 | /vendor/bin/hw/jelly\.hardware\.hello_hidl@1\.0-service u:object_r:hello_hidl_exec:s0 3 | /vendor/bin/hello_hidl_test u:object_r:hello_hidl_test_exec:s0 4 | 5 | 6 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/depend.internal: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.16 3 | 4 | CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o 5 | /home/android/Project/hello_drv_test/hello_drv_test.c 6 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv/Makefile: -------------------------------------------------------------------------------- 1 | # 指向你自己的 Kernel 路径 2 | KERN_DIR = /home/android/Project/Kernel/goldfish 3 | 4 | all: 5 | make -C $(KERN_DIR) M=`pwd` modules 6 | 7 | clean: 8 | make -C $(KERN_DIR) M=`pwd` modules clean 9 | rm -rf modules.order 10 | rm -f hello_drv_test 11 | 12 | obj-m += hello_drv.o -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/hello_hidl/1.0/IHello.hal: -------------------------------------------------------------------------------- 1 | package jelly.hardware.hello_hidl@1.0; 2 | 3 | interface IHello { 4 | addition_hidl(uint32_t a,uint32_t b) generates (uint32_t total); 5 | write(string name) generates (uint32_t result); 6 | read() generates (string name); 7 | }; -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloModule/hello_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int __init hello_init(void) 5 | { 6 | printk("Hello World!\n"); 7 | return 0; 8 | } 9 | 10 | static void __exit hello_exit(void) 11 | { 12 | printk("hello exit\n"); 13 | } 14 | 15 | module_init(hello_init); 16 | module_exit(hello_exit); -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/sepolicy/hello_hidl_test.te: -------------------------------------------------------------------------------- 1 | type hello_hidl_test, domain; 2 | type hello_hidl_test_exec, exec_type, vendor_file_type, file_type; 3 | 4 | domain_auto_trans(shell, hello_hidl_test_exec, hello_hidl_test); 5 | 6 | get_prop(hello_hidl_test, hwservicemanager_prop) 7 | allow hello_hidl_test hello_hidl_hwservice:hwservice_manager find; 8 | hwbinder_use(hello_hidl_test); -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/cmake_clean.cmake: -------------------------------------------------------------------------------- 1 | file(REMOVE_RECURSE 2 | "CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o" 3 | "hello_drv_test" 4 | "hello_drv_test.pdb" 5 | ) 6 | 7 | # Per-language clean rules from dependency scanning. 8 | foreach(lang C) 9 | include(CMakeFiles/hello_drv_test.dir/cmake_clean_${lang}.cmake OPTIONAL) 10 | endforeach() 11 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/hello_hidl/1.0/Android.bp: -------------------------------------------------------------------------------- 1 | // This file is autogenerated by hidl-gen -Landroidbp. 2 | 3 | hidl_interface { 4 | name: "jelly.hardware.hello_hidl@1.0", 5 | root: "jelly.hardware", 6 | srcs: [ 7 | "IHello.hal", 8 | ], 9 | interfaces: [ 10 | "android.hidl.base@1.0", 11 | ], 12 | gen_java: false, 13 | } 14 | 15 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/sepolicy/file_contexts: -------------------------------------------------------------------------------- 1 | /vendor/bin/helloseandroid u:object_r:hello_se_dt_exec:s0 2 | /dev/hello_seandroid_dev u:object_r:hello_se_dev_t:s0 3 | /vendor/bin/initscript u:object_r:initscript_dt_exec:s0 4 | /dev/hello u:object_r:hello_hidl_dev_t:s0 5 | /vendor/bin/hw/jelly\.hardware\.hello_hidl@1\.0-service u:object_r:hello_hidl_exec:s0 6 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/hello_hidl/1.0/Android.bp: -------------------------------------------------------------------------------- 1 | // This file is autogenerated by hidl-gen -Landroidbp. 2 | 3 | hidl_interface { 4 | name: "jelly.hardware.hello_hidl@1.0", 5 | root: "jelly.hardware", 6 | srcs: [ 7 | "IHello.hal", 8 | ], 9 | interfaces: [ 10 | "android.hidl.base@1.0", 11 | ], 12 | gen_java: false, 13 | } 14 | 15 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/hello_hidl/1.0/default/test/Android.bp: -------------------------------------------------------------------------------- 1 | cc_binary { 2 | name: "hello_hidl_test", 3 | srcs: ["hello_hidl_test.cpp"], 4 | vendor: true, 5 | shared_libs: [ 6 | "liblog", 7 | "jelly.hardware.hello_hidl@1.0", 8 | "libhidlbase", 9 | "libhidltransport", 10 | "libhwbinder", 11 | "libutils", 12 | ], 13 | } 14 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/hello_hidl/1.0/default/test/Android.bp: -------------------------------------------------------------------------------- 1 | cc_binary { 2 | name: "hello_hidl_test", 3 | srcs: ["hello_hidl_test.cpp"], 4 | vendor: true, 5 | shared_libs: [ 6 | "liblog", 7 | "jelly.hardware.hello_hidl@1.0", 8 | "libhidlbase", 9 | "libhidltransport", 10 | "libhwbinder", 11 | "libutils", 12 | ], 13 | } 14 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderJavaDemo/com/yuandaima/Android.bp: -------------------------------------------------------------------------------- 1 | java_library { 2 | name: "BinderClient", 3 | installable: true, 4 | srcs: [ "Client.java", 5 | "HelloService.java", 6 | "IHelloService.java" ], 7 | } 8 | 9 | java_library { 10 | name: "BinderServer", 11 | installable: true, 12 | srcs: [ "Server.java", 13 | "HelloService.java", 14 | "IHelloService.java" ], 15 | } -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/C.includecache: -------------------------------------------------------------------------------- 1 | #IncludeRegexLine: ^[ ]*[#%][ ]*(include|import)[ ]*[<"]([^">]+)([">]) 2 | 3 | #IncludeRegexScan: ^.*$ 4 | 5 | #IncludeRegexComplain: ^$ 6 | 7 | #IncludeRegexTransform: 8 | 9 | /home/android/Project/hello_drv_test/hello_drv_test.c 10 | sys/types.h 11 | - 12 | sys/stat.h 13 | - 14 | fcntl.h 15 | - 16 | unistd.h 17 | - 18 | stdio.h 19 | - 20 | string.h 21 | - 22 | 23 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/hello_hidl/1.0/default/service.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using jelly::hardware::hello_hidl::V1_0::IHello; 6 | using android::hardware::defaultPassthroughServiceImplementation; 7 | 8 | int main() { 9 | ALOGD("hello-hidl is starting..."); 10 | return defaultPassthroughServiceImplementation(4); 11 | } 12 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/hello_hidl/1.0/default/jelly.hardware.hello_hidl@1.0-service.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | jelly.hardware.hello_hidl 4 | hwbinder 5 | 1.0 6 | 7 | IHello 8 | default 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/hello_hidl/1.0/default/jelly.hardware.hello_hidl@1.0-service.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | jelly.hardware.hello_hidl 4 | passthrough 5 | 1.0 6 | 7 | IHello 8 | default 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/flags.make: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.16 3 | 4 | # compile C with /home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang 5 | C_FLAGS = -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fPIE 6 | 7 | C_DEFINES = 8 | 9 | C_INCLUDES = 10 | 11 | -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/src/StaticRegister/HelloJNI.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class HelloJNI */ 4 | 5 | #ifndef _Included_HelloJNI 6 | #define _Included_HelloJNI 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: HelloJNI 12 | * Method: sayHello 13 | * Signature: ()Ljava/lang/String; 14 | */ 15 | JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello 16 | (JNIEnv *, jobject); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif 22 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/3.16.3/CMakeSystem.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_HOST_SYSTEM "Linux-5.15.0-76-generic") 2 | set(CMAKE_HOST_SYSTEM_NAME "Linux") 3 | set(CMAKE_HOST_SYSTEM_VERSION "5.15.0-76-generic") 4 | set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64") 5 | 6 | include("/home/android/android-ndk-r21e/build/cmake/android.toolchain.cmake") 7 | 8 | set(CMAKE_SYSTEM "Android-1") 9 | set(CMAKE_SYSTEM_NAME "Android") 10 | set(CMAKE_SYSTEM_VERSION "1") 11 | set(CMAKE_SYSTEM_PROCESSOR "x86_64") 12 | 13 | set(CMAKE_CROSSCOMPILING "TRUE") 14 | 15 | set(CMAKE_SYSTEM_LOADED 1) 16 | -------------------------------------------------------------------------------- /1.基础篇/src/AndroidRunCpp/build.sh: -------------------------------------------------------------------------------- 1 | export ANDROID_NDK=/home/zzh0838/android-ndk-r25b 2 | 3 | rm -r build 4 | mkdir build && cd build 5 | 6 | # cmake -DCMAKE_SYSTEM_NAME=Android \ 7 | # -DCMAKE_SYSTEM_VERSION=29 \ 8 | # -DCMAKE_ANDROID_ARCH_ABI=x86_64 \ 9 | # -DANDROID_NDK=$ANDROID_NDK \ 10 | # -DCMAKE_ANDROID_STL_TYPE=c++_shared \ 11 | # .. 12 | 13 | cmake \ 14 | -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ 15 | -DANDROID_ABI=x86_64 \ 16 | -DANDROID_PLATFORM=android-29 \ 17 | -DANDROID_STL=c++_shared \ 18 | .. 19 | 20 | cmake --build . -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/src/DynamicRegister/com/example/ndk/NativeTest.java: -------------------------------------------------------------------------------- 1 | package com.example.ndk; 2 | 3 | public class NativeTest { 4 | static { 5 | System.loadLibrary("nativetest"); 6 | } 7 | 8 | public native void init(); 9 | 10 | public native void init(int age); 11 | 12 | public native boolean init(String name); 13 | 14 | public native void update(); 15 | 16 | public static void main(String[] args) { 17 | NativeTest test = new NativeTest(); 18 | test.init(); 19 | test.init(2); 20 | test.init("hello"); 21 | test.update(); 22 | } 23 | } -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build_hello_driver_test.sh: -------------------------------------------------------------------------------- 1 | export ANDROID_NDK=/home/android/android-ndk-r21e 2 | 3 | rm -r build 4 | mkdir build && cd build 5 | 6 | # CMake的内置支持 7 | # cmake -DCMAKE_SYSTEM_NAME=Android \ 8 | # -DCMAKE_SYSTEM_VERSION=29 \ 9 | # -DCMAKE_ANDROID_ARCH_ABI=x86_64 \ 10 | # -DANDROID_NDK=$ANDROID_NDK \ 11 | # -DCMAKE_ANDROID_STL_TYPE=c++_shared \ 12 | # .. 13 | 14 | # 工具链文件支持 15 | cmake \ 16 | -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ 17 | -DANDROID_ABI=x86_64 \ 18 | -DANDROID_PLATFORM=android-29 \ 19 | -DANDROID_STL=c++_shared \ 20 | .. 21 | 22 | cmake --build . -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloDriver/build_driver_test.sh: -------------------------------------------------------------------------------- 1 | export ANDROID_NDK=/home/zzh0838/Android/Sdk/ndk/25.2.9519653 2 | 3 | rm -r build 4 | mkdir build && cd build 5 | 6 | # CMake的内置支持 7 | # cmake -DCMAKE_SYSTEM_NAME=Android \ 8 | # -DCMAKE_SYSTEM_VERSION=29 \ 9 | # -DCMAKE_ANDROID_ARCH_ABI=x86_64 \ 10 | # -DANDROID_NDK=$ANDROID_NDK \ 11 | # -DCMAKE_ANDROID_STL_TYPE=c++_shared \ 12 | # .. 13 | 14 | # 工具链文件支持 15 | cmake \ 16 | -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ 17 | -DANDROID_ABI=x86_64 \ 18 | -DANDROID_PLATFORM=android-29 \ 19 | -DANDROID_STL=c++_shared \ 20 | .. 21 | 22 | cmake --build . -------------------------------------------------------------------------------- /4.Hal与硬件服务/4. Hal 层接口之直通模式.md: -------------------------------------------------------------------------------- 1 | 以上是通过 hwbinder 跨进程通信的方式,来实现的。对于效率较高的模块,我们还是希望通过 dlopen 直接加载的方式来使用 hal 层。Android 的 Hidl 框架也是提供了支持的。这种方式称为直通模式(passthrough) 2 | 3 | 上面的 binder 方式稍作修改即可变为直通模式: 4 | 5 | 将 Hello.h 中: 6 | 7 | ```c++ 8 | // extern "C" IHello* HIDL_FETCH_IHello(const char* name); 9 | ``` 10 | 11 | 这一行的注释取消。 12 | 13 | 把 Hello.cpp 中,下面几行的注释取消: 14 | 15 | ```c++ 16 | // IHello* HIDL_FETCH_IHello(const char* /* name */) { 17 | // return new Hello(); 18 | //} 19 | ``` 20 | 21 | 将 service.cpp 改为如下内容: 22 | 23 | ```c++ 24 | int main() { 25 | ALOGD("hello-hidl is starting..."); 26 | return defaultPassthroughServiceImplementation(4); 27 | } 28 | ``` -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/参考资料.md: -------------------------------------------------------------------------------- 1 | 2 | ## 参考资料 3 | 4 | * [JNI内存方面说明以及相关类型手动释放内存](https://blog.csdn.net/nanke_yh/article/details/124863685) 5 | * [英文版官方文档《Java Native Interface 6.0 Specification》](http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html) 6 | * 《The Java Native Interface: Programmer's Guide and Specification》 7 | * [JNI/NDK入门指南之开篇](https://blog.csdn.net/tkwxty/article/details/103971798) 8 | * https://blog.csdn.net/tkwxty/article/details/103454842 9 | * https://blog.csdn.net/xyang81/category_9263427.html 10 | * https://blog.csdn.net/qq_32583189/article/details/53079270?spm=1001.2014.3001.5502 11 | * https://blog.csdn.net/tkwxty/article/details/103095119 -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderJavaDemo/com/yuandaima/HelloService.java: -------------------------------------------------------------------------------- 1 | package com.yuandaima; 2 | 3 | import android.util.Log; 4 | 5 | public class HelloService extends IHelloService.Stub { 6 | private static final String TAG = "HelloService"; 7 | private int cnt1 = 0; 8 | private int cnt2 = 0; 9 | 10 | public void sayhello() throws android.os.RemoteException { 11 | cnt1++; 12 | Log.i(TAG, "sayhello : cnt = "+cnt1); 13 | } 14 | 15 | public int sayhello_to(java.lang.String name) throws android.os.RemoteException { 16 | cnt2++; 17 | Log.i(TAG, "sayhello_to "+name+" : cnt = "+cnt2); 18 | return cnt2; 19 | } 20 | } -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/AIDLCppDemo/com/yuandaima/BnHello.h: -------------------------------------------------------------------------------- 1 | #ifndef AIDL_GENERATED_COM_YUANDAIMA_BN_HELLO_H_ 2 | #define AIDL_GENERATED_COM_YUANDAIMA_BN_HELLO_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace com { 8 | 9 | namespace yuandaima { 10 | 11 | class BnHello : public ::android::BnInterface { 12 | public: 13 | ::android::status_t onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) override; 14 | }; // class BnHello 15 | 16 | } // namespace yuandaima 17 | 18 | } // namespace com 19 | 20 | #endif // AIDL_GENERATED_COM_YUANDAIMA_BN_HELLO_H_ 21 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderJavaDemo/com/yuandaima/Server.java: -------------------------------------------------------------------------------- 1 | package com.yuandaima; 2 | 3 | import android.util.Log; 4 | import android.os.ServiceManager; 5 | 6 | public class Server { 7 | 8 | private static final String TAG = "BinderServer"; 9 | 10 | public static void main(String args[]) { 11 | /* add Service */ 12 | Log.i(TAG, "add hello service"); 13 | ServiceManager.addService("hello", new HelloService()); 14 | 15 | //app_process 启动时,会启动 binder 线程用于获取和解析 binder 消息,应用程序无需关心 16 | while (true) { 17 | try { 18 | Thread.sleep(100); 19 | } catch (Exception e){} 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /疑难处理/module “dx-doc-stubs“ already defined错误.md: -------------------------------------------------------------------------------- 1 | 2 | 编译报错: 3 | 4 | ```bash 5 | FAILED: out/soong/build.ninja 6 | out/soong/.bootstrap/bin/soong_build -t -l out/.module_paths/Android.bp.list -b out/soong -n out -d out/soong/build.ninja.d -globFile out/soong/.bootstrap/build-globs.ninja -o out/soong/build.ninja Android.bp 7 | error: dalvik/dx/src/Android.bp:15:1: module "dx-doc-stubs" already defined 8 | dalvik/dx/bin/Android.bp:15:1 <-- previous definition here 9 | error: dalvik/dx/src/Android.bp:32:1: module "dx-docs" already defined 10 | dalvik/dx/bin/Android.bp:32:1 <-- previous definition here 11 | 15:41:30 soong bootstrap failed with: exit status 1 12 | ``` 13 | 14 | 删除 dalvik/dx/bin 文件夹即可 -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/src/StaticRegister/HelloJNI.java: -------------------------------------------------------------------------------- 1 | public class HelloJNI { // Save as HelloJNI.java 2 | static { 3 | System.loadLibrary("hello"); // Load native library hello.dll (Windows) or libhello.so (Unixes) 4 | // at runtime 5 | // This library contains a native method called sayHello() 6 | } 7 | 8 | // Declare an instance native method sayHello() which receives no parameter and returns void 9 | private native String sayHello(); 10 | 11 | // Test Driver 12 | public static void main(String[] args) { 13 | System.out.println(new HelloJNI().sayHello()); // Create an instance and invoke the native method 14 | } 15 | } -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/hello_hidl/1.0/default/test/hello_hidl_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define LOG_TAG "hello_hidl" 5 | #include 6 | 7 | using android::sp; 8 | using jelly::hardware::hello_hidl::V1_0::IHello; 9 | using android::hardware::Return; 10 | int main(){ 11 | android::sp hw_device = IHello::getService(); 12 | if (hw_device == nullptr) { 13 | ALOGD("failed to get hello-hidl"); 14 | return -1; 15 | } 16 | ALOGD("success to get hello-hidl...."); 17 | Return total = hw_device->addition_hidl(3,4); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/DependInfo.cmake: -------------------------------------------------------------------------------- 1 | # The set of languages for which implicit dependencies are needed: 2 | set(CMAKE_DEPENDS_LANGUAGES 3 | "C" 4 | ) 5 | # The set of files for implicit dependencies of each language: 6 | set(CMAKE_DEPENDS_CHECK_C 7 | "/home/android/Project/hello_drv_test/hello_drv_test.c" "/home/android/Project/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o" 8 | ) 9 | set(CMAKE_C_COMPILER_ID "Clang") 10 | 11 | # The include file search paths: 12 | set(CMAKE_C_TARGET_INCLUDE_PATH 13 | ) 14 | 15 | # Targets to which this target links. 16 | set(CMAKE_TARGET_LINKED_INFO_FILES 17 | ) 18 | 19 | # Fortran module output directory. 20 | set(CMAKE_Fortran_TARGET_MODULE_DIR "") 21 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/link.txt: -------------------------------------------------------------------------------- 1 | /home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=x86_64-none-linux-android29 --gcc-toolchain=/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -Wl,--gc-sections CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o -o hello_drv_test -latomic -lm 2 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/CMakeDirectoryInformation.cmake: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.16 3 | 4 | # Relative path conversion top directories. 5 | set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/android/Project/hello_drv_test") 6 | set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/android/Project/hello_drv_test/build") 7 | 8 | # Force unix paths in dependencies. 9 | set(CMAKE_FORCE_UNIX_PATHS 1) 10 | 11 | 12 | # The C and CXX include file regular expressions for this directory. 13 | set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") 14 | set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") 15 | set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) 16 | set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) 17 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCppDemo/BinderServer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #include "IHelloService.h" 15 | 16 | 17 | using namespace android; 18 | 19 | int main(int argc, char const *argv[]) 20 | { 21 | sp proc(ProcessState::self()); 22 | sp sm = defaultServiceManager(); 23 | sm->addService(String16("hello"), new BnHelloService()); 24 | 25 | ProcessState::self()->startThreadPool(); 26 | IPCThreadState::self()->joinThreadPool(); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/AIDLCppDemo/com/yuandaima/BpHello.h: -------------------------------------------------------------------------------- 1 | #ifndef AIDL_GENERATED_COM_YUANDAIMA_BP_HELLO_H_ 2 | #define AIDL_GENERATED_COM_YUANDAIMA_BP_HELLO_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace com { 10 | 11 | namespace yuandaima { 12 | 13 | class BpHello : public ::android::BpInterface { 14 | public: 15 | explicit BpHello(const ::android::sp<::android::IBinder>& _aidl_impl); 16 | virtual ~BpHello() = default; 17 | ::android::binder::Status hello() override; 18 | ::android::binder::Status sum(int32_t x, int32_t y, int32_t* _aidl_return) override; 19 | }; // class BpHello 20 | 21 | } // namespace yuandaima 22 | 23 | } // namespace com 24 | 25 | #endif // AIDL_GENERATED_COM_YUANDAIMA_BP_HELLO_H_ 26 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/AIDLCppDemo/HelloClient.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_TAG "aidl_cpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "com/yuandaima/IHello.h" 14 | #include "com/yuandaima/BnHello.h" 15 | 16 | using namespace android; 17 | 18 | int main(int argc, char const *argv[]) 19 | { 20 | sp sm = defaultServiceManager(); 21 | sp binder = sm->getService(String16("IHello")); 22 | sp hello = interface_cast(binder); 23 | 24 | hello->hello(); 25 | int ret = 0; 26 | hello->sum(1, 2, &ret); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/hello_hidl/1.0/default/test/hello_hidl_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define LOG_TAG "hello_hidl" 5 | #include 6 | 7 | using android::sp; 8 | using jelly::hardware::hello_hidl::V1_0::IHello; 9 | using android::hardware::Return; 10 | using android::hardware::hidl_string; 11 | 12 | int main(){ 13 | android::sp hw_device = IHello::getService(); 14 | if (hw_device == nullptr) { 15 | ALOGD("failed to get hello-hidl"); 16 | return -1; 17 | } 18 | ALOGD("success to get hello-hidl...."); 19 | Return total = hw_device->addition_hidl(3,4); 20 | hw_device->write("hello"); 21 | sleep(2); 22 | hw_device->read([&](hidl_string result){ 23 | ALOGD("%s\n", result.c_str()); 24 | }); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/hello_hidl/1.0/default/Hello.cpp: -------------------------------------------------------------------------------- 1 | #include "Hello.h" 2 | #define LOG_TAG "hello_hidl" 3 | #include 4 | 5 | namespace jelly { 6 | namespace hardware { 7 | namespace hello_hidl { 8 | namespace V1_0 { 9 | namespace implementation { 10 | 11 | // Methods from ::jelly::hardware::hello_hidl::V1_0::IHello follow. 12 | Return Hello::addition_hidl(uint32_t a, uint32_t b) { 13 | ALOGE("hello_hidl service is init success....a :%d,b:%d",a,b); 14 | return uint32_t {}; 15 | } 16 | 17 | 18 | // Methods from ::android::hidl::base::V1_0::IBase follow. 19 | 20 | IHello* HIDL_FETCH_IHello(const char* /* name */) { 21 | ALOGE("hello_hidl service is init success...."); 22 | return new Hello(); 23 | } 24 | // 25 | } // namespace implementation 26 | } // namespace V1_0 27 | } // namespace hello_hidl 28 | } // namespace hardware 29 | } // namespace jelly 30 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/hello_hidl/1.0/default/service.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "Hello.h" 6 | 7 | using android::hardware::configureRpcThreadpool; 8 | using android::hardware::joinRpcThreadpool; 9 | using jelly::hardware::hello_hidl::V1_0::IHello; 10 | using jelly::hardware::hello_hidl::V1_0::implementation::Hello; 11 | 12 | int main() { 13 | ALOGD("hello-hidl is starting..."); 14 | 15 | configureRpcThreadpool(4, true /* callerWillJoin */); 16 | 17 | android::sp service = new Hello(); 18 | android::status_t ret = service->registerAsService(); 19 | 20 | if (ret != android::NO_ERROR) { 21 | } 22 | 23 | joinRpcThreadpool(); 24 | 25 | return 0; 26 | //Passthrough模式 27 | //return defaultPassthroughServiceImplementation(4); 28 | } 29 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCppDemo/BpHelloService.cpp: -------------------------------------------------------------------------------- 1 | #include "IHelloService.h" 2 | 3 | namespace android { 4 | 5 | BpHelloService::BpHelloService(const sp& impl):BpInterface(impl) { 6 | 7 | } 8 | 9 | void BpHelloService::sayHello() { 10 | Parcel data, reply; 11 | data.writeInt32(0); 12 | data.writeString16(String16("IHelloService")); 13 | remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply); 14 | } 15 | 16 | int BpHelloService::sayHelloTo(const char *name) { 17 | Parcel data, reply; 18 | int exception; 19 | 20 | data.writeInt32(0); 21 | data.writeString16(String16("IHelloService")); 22 | data.writeString16(String16(name)); 23 | remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply); 24 | exception = reply.readInt32(); 25 | if (exception) 26 | return -1; 27 | else 28 | return reply.readInt32(); 29 | } 30 | 31 | IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService"); 32 | } -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCppDemo/BinderClient.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "IHelloService.h" 12 | 13 | using namespace android; 14 | 15 | int main(int argc, char const *argv[]) 16 | { 17 | sp proc(ProcessState::self()); 18 | sp sm = defaultServiceManager(); 19 | 20 | sp binder = sm->getService(String16("hello")); 21 | 22 | sp service = 23 | interface_cast(binder); 24 | 25 | if (binder == 0) 26 | { 27 | ALOGI("can't get hello service\n"); 28 | return -1; 29 | } 30 | 31 | service->sayHello(); 32 | int cnt = service->sayHelloTo("nihao"); 33 | ALOGI("client call sayhello_to, cnt = %d", cnt); 34 | 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/AIDLCppDemo/com/yuandaima/IHello.h: -------------------------------------------------------------------------------- 1 | #ifndef AIDL_GENERATED_COM_YUANDAIMA_I_HELLO_H_ 2 | #define AIDL_GENERATED_COM_YUANDAIMA_I_HELLO_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace com { 11 | 12 | namespace yuandaima { 13 | 14 | class IHello : public ::android::IInterface { 15 | public: 16 | DECLARE_META_INTERFACE(Hello) 17 | virtual ::android::binder::Status hello() = 0; 18 | virtual ::android::binder::Status sum(int32_t x, int32_t y, int32_t* _aidl_return) = 0; 19 | }; // class IHello 20 | 21 | class IHelloDefault : public IHello { 22 | public: 23 | ::android::IBinder* onAsBinder() override; 24 | ::android::binder::Status hello() override; 25 | ::android::binder::Status sum(int32_t x, int32_t y, int32_t* _aidl_return) override; 26 | 27 | }; 28 | 29 | } // namespace yuandaima 30 | 31 | } // namespace com 32 | 33 | #endif // AIDL_GENERATED_COM_YUANDAIMA_I_HELLO_H_ 34 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/hello_drv_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * ./hello_drv_test -w abc 10 | * ./hello_drv_test -r 11 | */ 12 | int main(int argc, char **argv) 13 | { 14 | int fd; 15 | char buf[1024]; 16 | int len; 17 | 18 | /* 1. 判断参数 */ 19 | if (argc < 2) 20 | { 21 | printf("Usage: %s -w \n", argv[0]); 22 | printf(" %s -r\n", argv[0]); 23 | return -1; 24 | } 25 | 26 | /* 2. 打开文件 */ 27 | fd = open("/dev/hello", O_RDWR); 28 | if (fd == -1) 29 | { 30 | printf("can not open file /dev/hello\n"); 31 | return -1; 32 | } 33 | 34 | /* 3. 写文件或读文件 */ 35 | if ((0 == strcmp(argv[1], "-w")) && (argc == 3)) 36 | { 37 | len = strlen(argv[2]) + 1; 38 | len = len < 1024 ? len : 1024; 39 | write(fd, argv[2], len); 40 | } 41 | else 42 | { 43 | len = read(fd, buf, 1024); 44 | buf[1023] = '\0'; 45 | printf("APP read : %s\n", buf); 46 | } 47 | 48 | close(fd); 49 | 50 | return 0; 51 | } -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloDriver/hello_drv_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * ./hello_drv_test -w abc 10 | * ./hello_drv_test -r 11 | */ 12 | int main(int argc, char **argv) 13 | { 14 | int fd; 15 | char buf[1024]; 16 | int len; 17 | 18 | /* 1. 判断参数 */ 19 | if (argc < 2) 20 | { 21 | printf("Usage: %s -w \n", argv[0]); 22 | printf(" %s -r\n", argv[0]); 23 | return -1; 24 | } 25 | 26 | /* 2. 打开文件 */ 27 | fd = open("/dev/hello", O_RDWR); 28 | if (fd == -1) 29 | { 30 | printf("can not open file /dev/hello\n"); 31 | return -1; 32 | } 33 | 34 | /* 3. 写文件或读文件 */ 35 | if ((0 == strcmp(argv[1], "-w")) && (argc == 3)) 36 | { 37 | len = strlen(argv[2]) + 1; 38 | len = len < 1024 ? len : 1024; 39 | write(fd, argv[2], len); 40 | } 41 | else 42 | { 43 | len = read(fd, buf, 1024); 44 | buf[1023] = '\0'; 45 | printf("APP read : %s\n", buf); 46 | } 47 | 48 | close(fd); 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/hello_hidl/1.0/default/Android.bp: -------------------------------------------------------------------------------- 1 | // FIXME: your file license if you have one 2 | 3 | cc_library_shared { 4 | name: "jelly.hardware.hello_hidl@1.0-impl", 5 | relative_install_path: "hw", 6 | proprietary: true, 7 | srcs: [ 8 | "Hello.cpp", 9 | ], 10 | shared_libs: [ 11 | "libhidlbase", 12 | "libhidltransport", 13 | "libutils", 14 | "jelly.hardware.hello_hidl@1.0", 15 | "liblog", 16 | ], 17 | } 18 | 19 | cc_binary { 20 | name: "jelly.hardware.hello_hidl@1.0-service", 21 | init_rc: ["jelly.hardware.hello_hidl@1.0-service.rc"], 22 | vintf_fragments: ["jelly.hardware.hello_hidl@1.0-service.xml"], 23 | defaults: ["hidl_defaults"], 24 | relative_install_path: "hw", 25 | vendor: true, 26 | srcs: ["service.cpp"], 27 | shared_libs: [ 28 | "jelly.hardware.hello_hidl@1.0", 29 | "libhardware", 30 | "libhidlbase", 31 | "libhidltransport", 32 | "libutils", 33 | "liblog", 34 | ], 35 | 36 | } 37 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/hello_hidl/1.0/default/Android.bp: -------------------------------------------------------------------------------- 1 | // FIXME: your file license if you have one 2 | 3 | cc_library_shared { 4 | name: "jelly.hardware.hello_hidl@1.0-impl", 5 | relative_install_path: "hw", 6 | proprietary: true, 7 | srcs: [ 8 | "Hello.cpp", 9 | ], 10 | shared_libs: [ 11 | "libhidlbase", 12 | "libhidltransport", 13 | "libutils", 14 | "jelly.hardware.hello_hidl@1.0", 15 | "liblog", 16 | ], 17 | } 18 | 19 | cc_binary { 20 | name: "jelly.hardware.hello_hidl@1.0-service", 21 | init_rc: ["jelly.hardware.hello_hidl@1.0-service.rc"], 22 | vintf_fragments: ["jelly.hardware.hello_hidl@1.0-service.xml"], 23 | defaults: ["hidl_defaults"], 24 | relative_install_path: "hw", 25 | vendor: true, 26 | srcs: ["service.cpp", "Hello.cpp"], 27 | shared_libs: [ 28 | "jelly.hardware.hello_hidl@1.0", 29 | "libhardware", 30 | "libhidlbase", 31 | "libhidltransport", 32 | "libutils", 33 | "liblog", 34 | ], 35 | } 36 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCppDemo/IHelloService.h: -------------------------------------------------------------------------------- 1 | #ifndef IHELLOSERVICE_H 2 | #define IHELLOSERVICE_H 3 | 4 | #include // for status_t 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define HELLO_SVR_CMD_SAYHELLO 1 12 | #define HELLO_SVR_CMD_SAYHELLO_TO 2 13 | 14 | namespace android { 15 | 16 | class IHelloService: public IInterface { 17 | 18 | public: 19 | DECLARE_META_INTERFACE(HelloService); 20 | virtual void sayHello() = 0; 21 | virtual int sayHelloTo(const char *name) = 0; 22 | 23 | }; 24 | 25 | //服务端 26 | class BnHelloService: public BnInterface { 27 | 28 | public: 29 | status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); 30 | void sayHello(); 31 | int sayHelloTo(const char *name); 32 | }; 33 | 34 | //客户端 35 | class BpHelloService: public BpInterface { 36 | public: 37 | BpHelloService(const sp& impl); 38 | void sayHello(); 39 | int sayHelloTo(const char *name); 40 | }; 41 | 42 | } 43 | 44 | #endif -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCppDemo/Android.bp: -------------------------------------------------------------------------------- 1 | cc_defaults { 2 | name: "BinderCppDemoflags", 3 | 4 | cflags: [ 5 | "-Wall", 6 | "-Wextra", 7 | "-Werror", 8 | "-Wno-unused-parameter", 9 | "-Wno-missing-field-initializers", 10 | "-Wno-unused-parameter", 11 | "-Wno-unused-variable", 12 | "-Wno-incompatible-pointer-types", 13 | "-Wno-sign-compare", 14 | ], 15 | product_variables: { 16 | binder32bit: { 17 | cflags: ["-DBINDER_IPC_32BIT=1"], 18 | }, 19 | }, 20 | } 21 | 22 | cc_binary { 23 | name: "CppBinderClient", 24 | defaults: ["BinderCppDemoflags"], 25 | srcs: ["BinderClient.cpp", "BpHelloService.cpp"], 26 | shared_libs: [ 27 | "liblog", 28 | "libcutils", 29 | "libutils", 30 | "libbinder", 31 | ], 32 | } 33 | 34 | cc_binary { 35 | name: "CppBinderServer", 36 | defaults: ["BinderCppDemoflags"], 37 | srcs: ["BinderServer.cpp", "BnHelloService.cpp","BpHelloService.cpp"], 38 | shared_libs: [ 39 | "liblog", 40 | "libcutils", 41 | "libutils", 42 | "libbinder", 43 | ], 44 | } -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderJavaDemo/com/yuandaima/Client.java: -------------------------------------------------------------------------------- 1 | package com.yuandaima; 2 | 3 | import android.util.Log; 4 | import android.os.ServiceManager; 5 | import android.os.IBinder; 6 | 7 | public class Client { 8 | 9 | private static final String TAG = "BinderClient"; 10 | 11 | public static void main(String args[]) 12 | { 13 | 14 | /* 1. getService */ 15 | IBinder binder = ServiceManager.getService("hello"); 16 | 17 | if (binder == null) 18 | { 19 | Log.i(TAG, "can not get hello service"); 20 | return; 21 | } 22 | 23 | IHelloService svr = IHelloService.Stub.asInterface(binder); 24 | 25 | try { 26 | svr.sayhello(); 27 | Log.i(TAG, "call sayhello"); 28 | } catch (Exception e) { 29 | 30 | } 31 | 32 | try { 33 | int cnt = svr.sayhello_to("hello"); 34 | 35 | Log.i(TAG, "call sayhello_to " + " : cnt = " + cnt); 36 | } catch (Exception e) { 37 | System.out.println("call sayhello_to , err :"+e); 38 | Log.i(TAG, "call sayhello_to , err : "+e); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/AIDLCppDemo/HelloServer.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_TAG "aidl_cpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "com/yuandaima/IHello.h" 14 | #include "com/yuandaima/BnHello.h" 15 | 16 | using namespace android; 17 | 18 | class IHelloServer : public com::yuandaima::BnHello 19 | { 20 | public: 21 | binder::Status hello() 22 | { 23 | ALOGI("hello"); 24 | return binder::Status(); 25 | } 26 | 27 | binder::Status sum(int32_t v1, int32_t v2, int32_t *_aidl_return) override 28 | { 29 | ALOGI("server: sum: %d + %d", v1, v2); 30 | *_aidl_return = v1 + v2; 31 | return binder::Status(); 32 | } 33 | }; 34 | 35 | int main(int argc, char const *argv[]) 36 | { 37 | defaultServiceManager()->addService(String16("IHello"), new IHelloServer()); 38 | ProcessState::self()->startThreadPool(); 39 | IPCThreadState::self()->joinThreadPool(); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/AIDLCppDemo/Android.bp: -------------------------------------------------------------------------------- 1 | cc_defaults { 2 | name: "BinderCppAidlDemoflags", 3 | 4 | cflags: [ 5 | "-Wall", 6 | "-Wextra", 7 | "-Werror", 8 | "-Wno-unused-parameter", 9 | "-Wno-missing-field-initializers", 10 | "-Wno-unused-parameter", 11 | "-Wno-unused-variable", 12 | "-Wno-incompatible-pointer-types", 13 | "-Wno-sign-compare", 14 | ], 15 | product_variables: { 16 | binder32bit: { 17 | cflags: ["-DBINDER_IPC_32BIT=1"], 18 | }, 19 | }, 20 | } 21 | 22 | cc_binary { 23 | name: "IHelloClient", 24 | defaults: ["BinderCppAidlDemoflags"], 25 | srcs: ["HelloClient.cpp","IHello.cpp"], 26 | 27 | shared_libs: [ 28 | "liblog", 29 | "libcutils", 30 | "libandroidfw", 31 | "libutils", 32 | "libbinder", 33 | ], 34 | } 35 | 36 | cc_binary { 37 | name: "IHelloServer", 38 | defaults: ["BinderCppAidlDemoflags"], 39 | srcs: ["HelloServer.cpp","IHello.cpp"], 40 | shared_libs: [ 41 | "liblog", 42 | "libcutils", 43 | "libandroidfw", 44 | "libutils", 45 | "libbinder", 46 | ], 47 | } -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/jelly/hardware/interfaces/hello_hidl/1.0/default/Hello.h: -------------------------------------------------------------------------------- 1 | // FIXME: your file license if you have one 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace jelly { 10 | namespace hardware { 11 | namespace hello_hidl { 12 | namespace V1_0 { 13 | namespace implementation { 14 | 15 | using ::android::hardware::hidl_array; 16 | using ::android::hardware::hidl_memory; 17 | using ::android::hardware::hidl_string; 18 | using ::android::hardware::hidl_vec; 19 | using ::android::hardware::Return; 20 | using ::android::hardware::Void; 21 | using ::android::sp; 22 | 23 | struct Hello : public IHello { 24 | // Methods from ::jelly::hardware::hello_hidl::V1_0::IHello follow. 25 | Return addition_hidl(uint32_t a, uint32_t b) override; 26 | 27 | // Methods from ::android::hidl::base::V1_0::IBase follow. 28 | 29 | }; 30 | 31 | // FIXME: most likely delete, this is only for passthrough implementations 32 | extern "C" IHello* HIDL_FETCH_IHello(const char* name); 33 | 34 | } // namespace implementation 35 | } // namespace V1_0 36 | } // namespace hello_hidl 37 | } // namespace hardware 38 | } // namespace jelly 39 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCDemo/Android.bp: -------------------------------------------------------------------------------- 1 | cc_defaults { 2 | name: "bindertestflags", 3 | 4 | 5 | cflags: [ 6 | "-Wall", 7 | "-Wextra", 8 | "-Werror", 9 | "-Wno-unused-parameter", 10 | "-Wno-missing-field-initializers", 11 | "-Wno-unused-parameter", 12 | "-Wno-unused-variable", 13 | "-Wno-incompatible-pointer-types", 14 | "-Wno-sign-compare", 15 | ], 16 | product_variables: { 17 | binder32bit: { 18 | cflags: ["-DBINDER_IPC_32BIT=1"], 19 | }, 20 | }, 21 | 22 | shared_libs: ["liblog"], 23 | } 24 | 25 | cc_binary { 26 | name: "binderclient", 27 | defaults: ["bindertestflags"], 28 | vendor: true, 29 | srcs: [ 30 | "binder_client.c", 31 | "binder.c", 32 | ], 33 | } 34 | 35 | cc_binary { 36 | name: "binderserver", 37 | defaults: ["bindertestflags"], 38 | vendor: true, 39 | srcs: [ 40 | "binder_server.c", 41 | "binder.c", 42 | ], 43 | } 44 | 45 | // cc_binary { 46 | // name: "myservicemanager", 47 | // defaults: ["mybindertest_flags"], 48 | // srcs: [ 49 | // "service_manager.c", 50 | // "binder.c", 51 | // ], 52 | // shared_libs: ["libcutils", "libselinux"], 53 | // } 54 | 55 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCppDemo/BnHelloService.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_TAG "HelloService" 2 | #include 3 | #include "IHelloService.h" 4 | 5 | 6 | namespace android { 7 | 8 | 9 | status_t BnHelloService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { 10 | 11 | switch(code) { 12 | case HELLO_SVR_CMD_SAYHELLO: { 13 | sayHello(); 14 | reply->writeInt32(0); 15 | return NO_ERROR; 16 | } break; 17 | 18 | case HELLO_SVR_CMD_SAYHELLO_TO: { 19 | int32_t policy = data.readInt32(); 20 | String16 name16_tmp = data.readString16(); 21 | 22 | String16 name16 = data.readString16(); 23 | String8 name8(name16); 24 | 25 | int cnt = sayHelloTo(name8.string()); 26 | 27 | reply->writeInt32(0); 28 | reply->writeInt32(cnt); 29 | 30 | return NO_ERROR; 31 | } break; 32 | 33 | default: 34 | return BBinder::onTransact(code, data, reply, flags); 35 | 36 | } 37 | } 38 | 39 | void BnHelloService::sayHello() { 40 | static int count = 0; 41 | ALOGI("say hello :%d\n ", ++count); 42 | } 43 | 44 | int BnHelloService::sayHelloTo(const char *name) { 45 | static int cnt = 0; 46 | ALOGI("say hello to %s : %d\n", name, ++cnt); 47 | return cnt; 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/hello_hidl/1.0/default/Hello.h: -------------------------------------------------------------------------------- 1 | // FIXME: your file license if you have one 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace jelly { 10 | namespace hardware { 11 | namespace hello_hidl { 12 | namespace V1_0 { 13 | namespace implementation { 14 | 15 | using ::android::hardware::hidl_array; 16 | using ::android::hardware::hidl_memory; 17 | using ::android::hardware::hidl_string; 18 | using ::android::hardware::hidl_vec; 19 | using ::android::hardware::Return; 20 | using ::android::hardware::Void; 21 | using ::android::sp; 22 | 23 | struct Hello : public IHello { 24 | // Methods from ::jelly::hardware::hello_hidl::V1_0::IHello follow. 25 | Return addition_hidl(uint32_t a, uint32_t b) override; 26 | Return write(const hidl_string& name) override; 27 | Return read(read_cb _hidl_cb) override; 28 | 29 | // Methods from ::android::hidl::base::V1_0::IBase follow. 30 | 31 | }; 32 | 33 | // FIXME: most likely delete, this is only for passthrough implementations 34 | // extern "C" IHello* HIDL_FETCH_IHello(const char* name); 35 | 36 | } // namespace implementation 37 | } // namespace V1_0 38 | } // namespace hello_hidl 39 | } // namespace hardware 40 | } // namespace jelly 41 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/1.Kernel 下载与编译.md: -------------------------------------------------------------------------------- 1 | # Kernel 下载与编译 2 | 3 | ## 1. 内核下载 4 | 5 | 下载适用于模拟器的内核 6 | 7 | ```bash 8 | 9 | git clone https://aosp.tuna.tsinghua.edu.cn/android/kernel/goldfish.git 10 | 11 | #查看分支 12 | 13 | git branch -a 14 | 15 | git checkout android-goldfish-4.14-gchips 16 | 17 | ``` 18 | 19 | 编译脚本: 20 | 21 | ```bash 22 | 23 | #!/bin/bash 24 | 25 | export ARCH=x86_64 26 | 27 | export SUBARCH=x86_64 28 | 29 | export CROSS_COMPILE=x86_64-linux-android- 30 | 31 | export PATH=android源码目录/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin:$PATH 32 | 33 | make x86_64_ranchu_defconfig 34 | 35 | make -j16 36 | 37 | ``` 38 | 39 | 将上面的内容保存为 build.sh 脚本文件。执行 `sh build.sh` 开始编译。 40 | 41 | 编译有错误修改代码: 42 | 43 | * 删除 scripts/selinux/mdp/mdp.c 文件中的 #include 44 | * 删除 scripts/selinux/genheaders/genheaders.c 文件中的 #include 45 | * 在 security/selinux/include/classmap.h 头部添加 #include 46 | 47 | 执行编译脚本 `sh build.sh` 即可编译成功 48 | 49 | ## 2. 自定义内核启动 50 | 51 | 启动之前,需要把之前启动的模拟器和启动模拟器的终端都关掉。 52 | 53 | ```bash 54 | 55 | source build/envsetup.sh 56 | 57 | lunch aosp_x86_64-eng 58 | 59 | emulator -kernel 内核地址/goldfish/arch/x86_64/boot/bzImage 60 | 61 | ``` 62 | 63 | 启动成功,打开模拟器设置页面,进入版本信息。 64 | 65 | ![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6c95abb0c5ba4b668b001b9f3bdcbc77~tplv-k3u1fbpfcp-zoom-1.image) 66 | 67 | 可以看到 Kernel version 项里,已经是最新编译的内核版本了。 68 | 69 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCDemo/binder_client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "binder.h" 8 | 9 | #define HELLO_SVR_CMD_SAYHELLO 1 10 | #define HELLO_SVR_CMD_SAYHELLO_TO 2 11 | 12 | int g_handle = 0; 13 | struct binder_state *g_bs; 14 | 15 | void sayhello(void) 16 | { 17 | unsigned iodata[512/4]; 18 | struct binder_io msg, reply; 19 | 20 | /* 构造binder_io */ 21 | bio_init(&msg, iodata, sizeof(iodata), 4); 22 | 23 | 24 | /* 放入参数 */ 25 | bio_put_uint32(&msg, 0); // strict mode header 26 | bio_put_string16_x(&msg, "IHelloService"); 27 | 28 | /* 调用binder_call */ 29 | if (binder_call(g_bs, &msg, &reply, g_handle, HELLO_SVR_CMD_SAYHELLO)) 30 | return ; 31 | 32 | /* 从reply中解析出返回值 */ 33 | binder_done(g_bs, &msg, &reply); 34 | 35 | } 36 | 37 | int main(int argc, char **argv) 38 | { 39 | int fd; 40 | struct binder_state *bs; 41 | uint32_t svcmgr = BINDER_SERVICE_MANAGER; 42 | int ret; 43 | 44 | bs = binder_open("/dev/binder", 128*1024); 45 | if (!bs) { 46 | fprintf(stderr, "failed to open binder driver\n"); 47 | return -1; 48 | } 49 | 50 | g_bs = bs; 51 | 52 | /* get service */ 53 | g_handle = svcmgr_lookup(bs, svcmgr, "hello"); 54 | if (!g_handle) { 55 | return -1; 56 | } 57 | 58 | //调用服务 59 | sayhello(); 60 | 61 | } -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/cmake_install.cmake: -------------------------------------------------------------------------------- 1 | # Install script for directory: /home/android/Project/hello_drv_test 2 | 3 | # Set the install prefix 4 | if(NOT DEFINED CMAKE_INSTALL_PREFIX) 5 | set(CMAKE_INSTALL_PREFIX "/usr/local") 6 | endif() 7 | string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") 8 | 9 | # Set the install configuration name. 10 | if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) 11 | if(BUILD_TYPE) 12 | string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" 13 | CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") 14 | else() 15 | set(CMAKE_INSTALL_CONFIG_NAME "") 16 | endif() 17 | message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") 18 | endif() 19 | 20 | # Set the component getting installed. 21 | if(NOT CMAKE_INSTALL_COMPONENT) 22 | if(COMPONENT) 23 | message(STATUS "Install component: \"${COMPONENT}\"") 24 | set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") 25 | else() 26 | set(CMAKE_INSTALL_COMPONENT) 27 | endif() 28 | endif() 29 | 30 | # Install shared libraries without execute permission? 31 | if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) 32 | set(CMAKE_INSTALL_SO_NO_EXE "1") 33 | endif() 34 | 35 | # Is this installation the result of a crosscompile? 36 | if(NOT DEFINED CMAKE_CROSSCOMPILING) 37 | set(CMAKE_CROSSCOMPILING "TRUE") 38 | endif() 39 | 40 | if(CMAKE_INSTALL_COMPONENT) 41 | set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt") 42 | else() 43 | set(CMAKE_INSTALL_MANIFEST "install_manifest.txt") 44 | endif() 45 | 46 | string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT 47 | "${CMAKE_INSTALL_MANIFEST_FILES}") 48 | file(WRITE "/home/android/Project/hello_drv_test/build/${CMAKE_INSTALL_MANIFEST}" 49 | "${CMAKE_INSTALL_MANIFEST_CONTENT}") 50 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/sepolicy/hello_hidl.te: -------------------------------------------------------------------------------- 1 | # type hello_hidl, domain; 2 | # type hello_hidl_exec, exec_type, vendor_file_type, file_type; 3 | # hwbinder_use(hello_hidl); 4 | # init_daemon_domain(hello_hidl) 5 | # add_hwservice(hello_hidl, hello_hidl_hwservice) 6 | 7 | # allow hello_hidl hwservicemanager_prop:file {map read open getattr}; 8 | # allow hello_hidl system_file:dir {read open getattr search}; 9 | 10 | # allow { hello_hidl shell } hello_hidl_hwservice:hwservice_manager { find }; 11 | 12 | # type hello_hidl, domain; 13 | # type hello_hidl_service, service_manager_type; 14 | # type hello_hidl_hwservice, hwservice_manager_type; 15 | # type hello_hidl_exec, exec_type, vendor_file_type, file_type; 16 | 17 | # init_daemon_domain(hello_hidl) 18 | 19 | # get_prop(hello_hidl, hwservicemanager_prop) 20 | # add_hwservice(hello_hidl, hello_hidl_hwservice) 21 | # hwbinder_use(hello_hidl) 22 | 23 | 24 | # allow platform_app hello_hidl_hwservice:hwservice_manager { find }; 25 | # # allow hello_hidl default_android_hwservice:hwservice_manager add; 26 | # allow { hello_hidl shell } hello_hidl_hwservice:hwservice_manager { add find }; 27 | # allow platform_app hello_hidl:binder {call}; 28 | 29 | 30 | type hello_hidl, domain; 31 | type hello_hidl_exec, exec_type, vendor_file_type, file_type; 32 | 33 | init_daemon_domain(hello_hidl); 34 | add_hwservice(hello_hidl, hello_hidl_hwservice) 35 | hwbinder_use(hello_hidl) 36 | 37 | 38 | #allow hello_hidl hello_hidl_hwservice:hwservice_manager { add find }; 39 | #allow hello_hidl default_android_hwservice:hwservice_manager { add find }; 40 | allow hello_hidl hidl_base_hwservice:hwservice_manager { add }; 41 | allow hello_hidl hello_hidl_dev_t:chr_file { open read write }; 42 | binder_call(hello_hidl,hwservicemanager) 43 | get_prop(hello_hidl,hwservicemanager_prop) 44 | 45 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Passthrough/sepolicy/hellohidl.te: -------------------------------------------------------------------------------- 1 | # type hello_hidl, domain; 2 | # type hello_hidl_exec, exec_type, vendor_file_type, file_type; 3 | # hwbinder_use(hello_hidl); 4 | # init_daemon_domain(hello_hidl) 5 | # add_hwservice(hello_hidl, hello_hidl_hwservice) 6 | 7 | # allow hello_hidl hwservicemanager_prop:file {map read open getattr}; 8 | # allow hello_hidl system_file:dir {read open getattr search}; 9 | 10 | # allow { hello_hidl shell } hello_hidl_hwservice:hwservice_manager { find }; 11 | 12 | # type hello_hidl, domain; 13 | # type hello_hidl_service, service_manager_type; 14 | # type hello_hidl_hwservice, hwservice_manager_type; 15 | # type hello_hidl_exec, exec_type, vendor_file_type, file_type; 16 | 17 | # init_daemon_domain(hello_hidl) 18 | 19 | # get_prop(hello_hidl, hwservicemanager_prop) 20 | # add_hwservice(hello_hidl, hello_hidl_hwservice) 21 | # hwbinder_use(hello_hidl) 22 | 23 | 24 | # allow platform_app hello_hidl_hwservice:hwservice_manager { find }; 25 | # # allow hello_hidl default_android_hwservice:hwservice_manager add; 26 | # allow { hello_hidl shell } hello_hidl_hwservice:hwservice_manager { add find }; 27 | # allow platform_app hello_hidl:binder {call}; 28 | 29 | 30 | type hello_hidl, domain; 31 | type hello_hidl_exec, exec_type, vendor_file_type, file_type; 32 | 33 | init_daemon_domain(hello_hidl) 34 | 35 | add_hwservice(hello_hidl, hello_hidl_hwservice) 36 | hwbinder_use(hello_hidl) 37 | 38 | #allow hello_hidl hello_hidl_hwservice:hwservice_manager { add find }; 39 | #allow hello_hidl default_android_hwservice:hwservice_manager { add find }; 40 | allow hello_hidl hidl_base_hwservice:hwservice_manager { add }; 41 | allow hello_hidl hello_hidl_dev_t:chr_file { open read write }; 42 | binder_call(hello_hidl,hwservicemanager) 43 | get_prop(hello_hidl,hwservicemanager_prop) 44 | 45 | -------------------------------------------------------------------------------- /2.AOSP上手指南/011. Apk 预装入门.md: -------------------------------------------------------------------------------- 1 | # Apk 预装详解 2 | 3 | 文章基于 Aosp Android10_r41 版本。 4 | 5 | 本文介绍如何在 Aosp 中预装已经编译好的 apk。本文主要介绍基本操作,如果你熟练使用 Shell Python 等脚本类工具语言,可以参考本文的基本操作来实现 Apk 预装的自动化。 6 | 7 | ## 1. 不可卸载 Apk 8 | 9 | 不可卸载 Apk 一般是产品厂商开发的系统 App,比如闹钟,日历,浏览器等。 10 | 11 | 我们把[使用 Android Studio 开发系统 App](https://juejin.cn/post/7207358268804579386)创建的项目 build 一个 release 版本的 apk 12 | 13 | 然后在源码的 `device/Jelly/Rice14` 目录下创建如下的目录与文件: 14 | 15 | ```bash 16 | AsSystemApp/ 17 | ├── Android.mk 18 | └── app-release.apk 19 | ``` 20 | 21 | Android10 还未支持 Android.bp 中的 android_app_import 类型,所以我们目前只能使用 Android.mk 来添加我们的 apk。 22 | 23 | 其中 app-release.apk 是上述使用 Andrid Studio 打包好的 apk。 24 | 25 | Android.mk 的内容如下: 26 | 27 | ```Makefile 28 | LOCAL_PATH := $(call my-dir) 29 | include $(CLEAR_VARS) 30 | 31 | LOCAL_MODULE_TAGS := optional 32 | LOCAL_MODULE := AsSystemApp 33 | LOCAL_CERTIFICATE := PRESIGNED 34 | LOCAL_SRC_FILES := app-release.apk 35 | LOCAL_MODULE_CLASS := APPS 36 | LOCAL_PRODUCT_MODULE := true 37 | include $(BUILD_PREBUILT) 38 | ``` 39 | 40 | 接着在 `device/Jelly/Rice14/Rice14.mk` 中添加: 41 | 42 | ```Makefile 43 | PRODUCT_PACKAGES += \ 44 | AsSystemApp 45 | ``` 46 | 47 | 最后,编译系统,启动虚拟机: 48 | 49 | ```bash 50 | source build/envsetup.sh 51 | lunch Rice14-eng 52 | make -j16 53 | emulator 54 | ``` 55 | 56 | 打开虚拟机可以看到,我们的 app 已经预装好了且无法卸载: 57 | 58 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230410113847.png) 59 | 60 | 65 | 66 | 67 | 68 | ## 参考资料 69 | 70 | * [[RK3399] [android 7.1.2]添加预装应用](https://blog.csdn.net/qilvmilv/article/details/84344132) 71 | * [Android8.0.0-r4的APK的安装](https://blog.csdn.net/nwpushuai/article/details/79319651) 72 | -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/src/DynamicRegister/NativeTest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | //1 实现 java 层本地方法 9 | JNIEXPORT void JNICALL 10 | c_init1(JNIEnv *env, jobject thiz) { 11 | printf("c_init1\n"); 12 | } 13 | 14 | JNIEXPORT void JNICALL 15 | c_init2(JNIEnv *env, jobject thiz, jint age) { 16 | printf("c_init2\n"); 17 | } 18 | 19 | JNIEXPORT jboolean JNICALL 20 | c_init3(JNIEnv *env, jobject thiz, jstring name) { 21 | printf("c_init3\n"); 22 | } 23 | 24 | JNIEXPORT void JNICALL 25 | c_update(JNIEnv *env, jobject thiz) { 26 | printf("c_update\n"); 27 | } 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | 34 | // typedef struct { 35 | // //Java层native方法名称 36 | // const char* name; 37 | // //方法签名 38 | // const char* signature; 39 | // //native层方法指针 40 | // void* fnPtr; 41 | // } JNINativeMethod; 42 | 43 | //2 构建 JNINativeMethod 数组 44 | //中间的方法签名看上去有点怪异,后面我们来讲它的命名规则 45 | static JNINativeMethod methods[] = { 46 | {"init", "()V", (void *)c_init1}, 47 | {"init", "(I)V", (void *)c_init2}, 48 | {"init", "(Ljava/lang/String;)Z", (void *)c_init3}, 49 | {"update", "()V", (void *)c_update}, 50 | }; 51 | 52 | /** 53 | * 3 完成动态注册的入口函数 54 | * 其内容基本固定 55 | */ 56 | JNIEXPORT jint JNICALL 57 | JNI_OnLoad(JavaVM *vm, void *reserved) { 58 | JNIEnv *env = NULL; 59 | jint result = -1; 60 | 61 | // 获取JNI env变量 62 | if (vm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) { 63 | // 失败返回-1 64 | return result; 65 | } 66 | 67 | // 获取native方法所在类 68 | const char* className = "com/example/ndk/NativeTest"; 69 | jclass clazz = env->FindClass(className); 70 | if (clazz == NULL) { 71 | return result; 72 | } 73 | 74 | // 动态注册native方法 75 | if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) { 76 | return result; 77 | } 78 | 79 | // 返回成功 80 | result = JNI_VERSION_1_6; 81 | return result; 82 | } 83 | -------------------------------------------------------------------------------- /2.AOSP上手指南/006.添加配置文件与删除已有模块.md: -------------------------------------------------------------------------------- 1 | # 添加配置文件与删除已有模块 2 | 3 | 本文基于 AOSP Android10_r41 源码环境。 4 | 5 | 如果提前阅读了以下文章,本文阅读起来会更加顺利: 6 | 7 | * [玩转 AOSP 篇之极速上手]() 8 | * [玩转 AOSP 篇之添加 Product]() 9 | * [添加可执行程序]() 10 | 11 | ## 1. 添加配置文件 12 | 13 | PRODUCT_COPY_FILES 常用于产品的配置文件中,在本文中就是 Rice14.mk 文件,用于将源码的文件拷贝到 Android 文件系统中。 14 | 15 | 这里看一个源码中的示例: 16 | 17 | `aosp/build/target/product/core_64_bit.mk` 中有如下内容: 18 | 19 | ```makefile 20 | PRODUCT_COPY_FILES += system/core/rootdir/init.zygote64_32.rc:system/etc/init/hw/init.zygote64_32.rc 21 | ``` 22 | 23 | 这一行表示将源码中的 `system/core/rootdir/init.zygote64_32.rc` 拷贝到 Android 文件系统的 system/etc/init/hw/init.zygote64_32.rc 文件中。 24 | 25 | init.zygote64_32.rc 是 init 程序使用的一个配置文件,当我们的程序需要配置文件时,也可以参考以上的方式来完成。 26 | 27 | ## 2. 删除已有模块 28 | 29 | 有的时候,我们需要删除系统中已有的模块,比如我们系统的应用场景是广告牌、电视,那我们就需要删除电话,通信录等应用。下面以删除通信录(Contacts)为例,演示如何操作: 30 | 31 | ```bash 32 | grep -r "Contacts" . 33 | ./make/target/product/handheld_product.mk: Contacts \ 34 | ./make/target/product/mainline_arm64.mk: system/priv-app/Contacts/Contacts.apk \ 35 | ./make/target/product/base_system.mk: ContactsProvider \ 36 | ./make/core/build-system.html:Dialer, Contacts, etc. This will probably change or go away when we switch 37 | ``` 38 | 39 | 在 `./make/target/product/handheld_product.mk` 中删除 PRODUCT_PACKAGES 变量的 Contacts 40 | 41 | 接着重新编译启动模拟器: 42 | 43 | ```bash 44 | source build/envsetup.sh 45 | lunch Rice14-eng 46 | make clean 47 | make -j16 48 | emulator 49 | ``` 50 | 可以看到,Contacts 应用已经没有了: 51 | 52 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230403115334.png) 53 | 54 | 55 | ## 参考资料 56 | 57 | * [How to include prebuilt library in Android.bp file?](https://stackoverflow.com/questions/48578960/how-to-include-prebuilt-library-in-android-bp-file) 58 | * [Android系统开发入门-5.添加预编译模块](http://qiushao.net/2019/12/10/Android%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8/5-%E6%B7%BB%E5%8A%A0%E9%A2%84%E7%BC%96%E8%AF%91%E6%A8%A1%E5%9D%97/) 59 | * [Android系统开发入门-6.删除Android原生内置APK](http://qiushao.net/2019/12/12/Android%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8/6-%E5%88%A0%E9%99%A4%E5%8E%9F%E7%94%9F%E5%86%85%E7%BD%AEAPK/) 60 | * [Android.bp 文件中引入aar、jar、so库正确编译方法(值得收藏)](https://blog.csdn.net/u012932409/article/details/108119443) 61 | * [在AOSP中添加jar包和aar包依赖](https://blog.csdn.net/ItsFated/article/details/108844860) -------------------------------------------------------------------------------- /1.基础篇/003.Android 平台如何编译执行 C C++ 可执行程序.md: -------------------------------------------------------------------------------- 1 | # Android 平台如何编译执行 C C++ 可执行程序 2 | 3 | 我们直接看一个示例: 4 | 5 | 写一个 helloworld c++ 可执行程序: 6 | 7 | main.c: 8 | 9 | ```cpp 10 | # include 11 | 12 | int main(int argc, char const *argv[]) 13 | { 14 | for(int i = 0; i < 5; ++i) 15 | std::cout << "Hello World" << std::endl; 16 | 17 | return 0; 18 | } 19 | 20 | ``` 21 | 22 | Android 平台通常使用 CMake 调用 NDK 工具链编译 C/C++ 代码,具体地: 23 | 24 | 写 CMakeLists.txt: 25 | google 给了两种方式用于支持 CMake 调用 NDK 工具链编译 C/C++ 代码, 26 | 一种是 [CMake的内置支持](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android-with-the-ndk),需要 CMake 版本 >= 3.21,NDK 版本需要大于 r23,是未来的主流。 27 | 一种是通过[工具链文件支持](https://developer.android.com/ndk/guides/cmake),是当前的主流。Android Gradle 插件使用的是 NDK 的工具链文件。 28 | 29 | CMakeLists.txt 30 | 31 | ```cmake 32 | cmake_minimum_required(VERSION 3.0) 33 | 34 | project(main) 35 | 36 | add_executable(${PROJECT_NAME} main.cpp ) 37 | ``` 38 | 39 | 编译脚本 build.sh: 40 | 41 | ```cmake 42 | export ANDROID_NDK=你的ndk完整路径 43 | 44 | rm -r build 45 | mkdir build && cd build 46 | 47 | # CMake的内置支持 48 | # cmake -DCMAKE_SYSTEM_NAME=Android \ 49 | # -DCMAKE_SYSTEM_VERSION=29 \ 50 | # -DCMAKE_ANDROID_ARCH_ABI=x86_64 \ 51 | # -DANDROID_NDK=$ANDROID_NDK \ 52 | # -DCMAKE_ANDROID_STL_TYPE=c++_shared \ 53 | # .. 54 | 55 | # 工具链文件支持 56 | cmake \ 57 | -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ 58 | -DANDROID_ABI=x86_64 \ 59 | -DANDROID_PLATFORM=android-29 \ 60 | -DANDROID_STL=c++_shared \ 61 | .. 62 | 63 | cmake --build . 64 | ``` 65 | 66 | 在模拟器上执行我们的程序: 67 | 68 | ```cmake 69 | # 编译程序 70 | chmod +x build.sh 71 | ./build.sh 72 | # 打开模拟器,流程略 73 | # 上传可执行文件 74 | adb push build/test /data/local/tmp 75 | # 上传 STL 动态库 76 | adb push 你的ndk完整路径/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so /data/local/tmp 77 | # 进入到模拟器 shell 78 | adb shell 79 | # 执行程序 80 | cd /data/local/tmp 81 | export LD_LIBRARY_PATH=/data/local/tmp && ./test 82 | ``` 83 | 84 | ## 源码 85 | 86 | 你可在我的 github 仓库 https://github.com/yuandaimaahao/AndroidFrameworkTutorial/tree/main/1.%E5%9F%BA%E7%A1%80%E7%AF%87/src/AndroidRunCpp 中下载到示例代码。 87 | 88 | ## 参考资料 89 | 90 | - [[CMake 文档] Cross Compiling for Android with the NDK](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android-with-the-ndk) 91 | - [Google CMake 文档](https://developer.android.com/ndk/guides/cmake) -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/003.JNI 编程上手指南之描述符.md: -------------------------------------------------------------------------------- 1 | # JNI 编程上手指南之描述符 2 | 3 | ## 1. 类描述符 4 | 5 | 在 JNI 的 Native 方法中,我们要使用 Java 中的对象怎么办?即在 C/C++ 中怎么找到 Java 中的类,这就要使用到 JNI 开发中的类描述符了 6 | 7 | JNI 提供的函数中有个 FindClass() 就是用来查找 Java 类的,其参数必须放入一个类描述符字符串,类描述符一般是类的完整名称(包名+类名) 8 | 9 | 一个 Java 类对应的描述符,就是类的全名,其中 . 要换成 / : 10 | 11 | ```c++ 12 | 完整类名:   java.lang.String 13 | 对应类描述符: java/lang/String 14 | 15 | jclass intArrCls = env->FindClass(“java/lang/String”) 16 | 17 | jclass clazz = FindClassOrDie(env, "android/view/Surface"); 18 | ``` 19 | 20 | ## 2. 域描述符 21 | 22 | 域描述符是 JNI 中对 Java 数据类型的一种表示方法。在 JVM 虚拟机中,存储数据类型的名称时,是使用指定的描述符来存储,而不是我们习惯的 int,float 等。 23 | 24 | 虽然有类描述符,但是类描述符里并没有说明基本类型和数组类型如何表示,所以在 JNI 中就引入了域描述符的概念。 25 | 26 | 接着我们通过一个表格来了解域描述符的定义: 27 | 28 | | 类型标识 | Java数据类型 | 29 | | ----------- | ------------ | 30 | | Z | boolean | 31 | | B | byte | 32 | | C | char | 33 | | S | short | 34 | | I | int | 35 | | J | long | 36 | | F | float | 37 | | D | double | 38 | | L包名/类名; | 各种引用类型 | 39 | | V | void | 40 | | [ | 数组 | 41 | | 方法 | (参数)返回值 | 42 | 43 | 接着我们来看几个例子: 44 | 45 | ```java 46 | Java类型:  java.lang.String 47 | JNI 域描述符:Ljava/lang/String; //注意结尾有分号 48 | 49 | Java类型:   int[] 50 | JNI域描述符: [I 51 | 52 | Java类型:   float[] 53 | JNI域描述符: [F 54 | 55 | Java类型:   String[] 56 | JNI域描述符: [Ljava/lang/String; 57 | 58 | Java类型:   Object[ ] 59 | JNI域描述符: [[Ljava/lang/Object; 60 | 61 | Java类型:   int[][] 62 | JNI域描述符: [[I 63 | 64 | Java类型:   float[][] 65 | JNI域描述符: [[F 66 | ``` 67 | 68 | ## 3. 方法描述符 69 | 70 | 方法描述符是 JVM 中对函数(方法)的标记方式,看几个例子就能基本掌握其命名特点了: 71 | 72 | ```c 73 | Java 方法 方法描述符 74 | 75 | String fun() ()Ljava/lang/String; 76 | int fun(int i, Object object) (ILjava/lang/Object;)I 77 | void fun(byte[] bytes) ([B)V 78 | int fun(byte data1, byte data2) (BB)I 79 | void fun() ()V 80 | ``` 81 | 82 | # 关于 83 | 84 | 我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研发工作。主要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术分享。 85 | 86 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 87 | 88 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/005.JNI 编程上手指南之 JavaVM 详解.md: -------------------------------------------------------------------------------- 1 | # JNI 编程上手指南之 JavaVM 详解 2 | 3 | 4 | ## JavaVM 是什么? 5 | 6 | * JavaVM 是一个结构体,用于描述 Java 虚拟机。 7 | * 一个 JVM 中只有一个 JavaVM 对象。在 Android 平台上,一个 Java 进程只能有一个 ART 虚拟机,也就是说一个进程只有一个 JavaVM 对象。 8 | * JavaVM 可以在进程中的各线程间共享 9 | 10 | 接着我来看一下 JavaVM 在代码中是如何被定义的: 11 | 12 | ```c++ 13 | struct JavaVM_; 14 | 15 | #ifdef __cplusplus 16 | typedef JavaVM_ JavaVM; //c++ 中,是 JavaVM_ 17 | #else 18 | typedef const struct JNIInvokeInterface_ *JavaVM; //c 中,是 JNIInvokeInterface_ 19 | #endif 20 | 21 | // JavaVM_ 主要是定义了几个成员函数 22 | struct JavaVM_ { 23 | const struct JNIInvokeInterface_ *functions; 24 | #ifdef __cplusplus 25 | 26 | jint DestroyJavaVM() { 27 | return functions->DestroyJavaVM(this); 28 | } 29 | jint AttachCurrentThread(void **penv, void *args) { 30 | return functions->AttachCurrentThread(this, penv, args); 31 | } 32 | jint DetachCurrentThread() { 33 | return functions->DetachCurrentThread(this); 34 | } 35 | 36 | jint GetEnv(void **penv, jint version) { 37 | return functions->GetEnv(this, penv, version); 38 | } 39 | jint AttachCurrentThreadAsDaemon(void **penv, void *args) { 40 | return functions->AttachCurrentThreadAsDaemon(this, penv, args); 41 | } 42 | #endif 43 | }; 44 | 45 | //JNIInvokeInterface_ 主要定义了几个函数指针 46 | struct JNIInvokeInterface_ { 47 | void *reserved0; 48 | void *reserved1; 49 | void *reserved2; 50 | 51 | jint (JNICALL *DestroyJavaVM)(JavaVM *vm); 52 | 53 | jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args); 54 | 55 | jint (JNICALL *DetachCurrentThread)(JavaVM *vm); 56 | 57 | jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version); 58 | 59 | jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args); 60 | }; 61 | ``` 62 | 63 | 64 | ## 如何获得 JavaVM 65 | 66 | 动态注册时,可以在 JNI_OnLoad 的参数中获取到 JavaVM: 67 | 68 | ```c++ 69 | JavaVM *gJavaVM; 70 | 71 | jint JNI_OnLoad(JavaVM * vm, void * reserved) { 72 | gJavaVM = vm 73 | //...... 74 | } 75 | ``` 76 | 77 | 也可以通过 JNIEnv 的函数获取到 JavaVM: 78 | 79 | ```c++ 80 | JavaVM *gJavaVM; 81 | 82 | JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj) 83 | { 84 | env->GetJavaVM(&gJavaVM); 85 | return (*env)->NewStringUTF(env,"Hello from JNI !"); 86 | } 87 | ``` 88 | 89 | # 关于 90 | 91 | 我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研发工作。主要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术分享。 92 | 93 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 94 | 95 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloHidl_Bindered/jelly/hardware/interfaces/hello_hidl/1.0/default/Hello.cpp: -------------------------------------------------------------------------------- 1 | // FIXME: your file license if you have one 2 | 3 | #include "Hello.h" 4 | #define LOG_TAG "hello_hidl" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace jelly 13 | { 14 | namespace hardware 15 | { 16 | namespace hello_hidl 17 | { 18 | namespace V1_0 19 | { 20 | namespace implementation 21 | { 22 | 23 | // Methods from ::jelly::hardware::hello_hidl::V1_0::IHello follow. 24 | Return Hello::addition_hidl(uint32_t a, uint32_t b) 25 | { 26 | ALOGE("hello_hidl service is init success....a :%d,b:%d", a, b); 27 | return uint32_t{}; 28 | return uint32_t{}; 29 | } 30 | 31 | Return Hello::write(const hidl_string &name) 32 | { 33 | 34 | ALOGD("service is writing \n"); 35 | int fd = open("/dev/hello", O_RDWR); 36 | if (fd == -1) 37 | { 38 | ALOGD("can not open file /dev/hello\n"); 39 | return uint32_t{0}; 40 | } 41 | 42 | ::write(fd, name.c_str(), 100); 43 | 44 | close(fd); 45 | return uint32_t{1}; 46 | } 47 | 48 | // 通过 read_cb 接口,回传数据 49 | Return Hello::read(read_cb _hidl_cb) 50 | { 51 | ALOGD("service is reading \n"); 52 | char buf[100]; 53 | int fd = open("/dev/hello", O_RDWR); 54 | if (fd == -1) 55 | { 56 | ALOGD("can not open file /dev/hello\n"); 57 | return Void(); 58 | } 59 | 60 | ::read(fd, buf, 100); 61 | 62 | hidl_string result(buf); 63 | _hidl_cb(result); 64 | 65 | close(fd); 66 | return Void(); 67 | } 68 | 69 | // Methods from ::android::hidl::base::V1_0::IBase follow. 70 | 71 | // IHello* HIDL_FETCH_IHello(const char* /* name */) { 72 | // return new Hello(); 73 | //} 74 | // 75 | } // namespace implementation 76 | } // namespace V1_0 77 | } // namespace hello_hidl 78 | } // namespace hardware 79 | } // namespace jelly 80 | -------------------------------------------------------------------------------- /3.学穿Binder篇/参考资料.md: -------------------------------------------------------------------------------- 1 | # 参考资料 2 | 3 | * 韦东山 Android 系统教程 4 | * 《Android 框架解密》 5 | * 《Android 源代码情景分析》 6 | * 《深入理解 Android 》系统图书 7 | * [Android Binder 魅族团队](http://kernel.meizu.com/android-binder.html) 8 | * [IT先森 Binder 系列博客](https://blog.csdn.net/tkwxty/article/details/102824924) 9 | * [Android Binder实战开发指南](https://blog.csdn.net/tkwxty/article/details/102816075?spm=1001.2014.3001.5502) 10 | * [芦半山 Binder 分析文章](https://juejin.cn/post/6844903961128878094) 11 | 12 | * [Binder中的SEAndroid控制](https://mp.weixin.qq.com/s/O0t2wOPmSDo-ZTYhTHidfQ) 13 | * [快乐安卓 Android Binder通信](https://blog.csdn.net/yangwen123/category_1609389.html) 14 | 15 | * [Binder Driver缺陷导致定屏的实战分析](https://mp.weixin.qq.com/s/8lr0q-6cKY8b5c-V_XZLNA) 16 | 17 | * [Binder | 代理对象的泄露及其检测](https://juejin.cn/post/7024432171779620894) 18 | * [Android 12 系统源码分析 | Native Binder 代码变迁](https://www.cnblogs.com/wanghongzhu/p/15551978.html) 19 | * [Android Binder机制(一) Binder的设计和框架](http://wangkuiwu.github.io/2014/09/01/Binder-Introduce/) 20 | * [Android性能优化:getResources()与Binder交火导致的界面卡顿优化](https://juejin.cn/post/7198430801851531324) 21 | * [Binder的一次事务通信数据量分析及优化思路](https://www.jianshu.com/p/6ac715e2e81f) 22 | * [APP性能设计及优化专题——影响性能的不良实现](https://blog.csdn.net/software_test010/article/details/125608505) 23 | * [Android Systrace 基础知识 - Binder 和锁竞争解读](https://androidperformance.com/2019/12/06/Android-Systrace-Binder/) 24 | * [你真的理解AIDL中的in,out,inout么?](https://blog.csdn.net/luoyanglizi/article/details/51958091) 25 | * [Binder问题分享](https://www.cnblogs.com/tgltt/p/9550113.html) 26 | * [携程ANR 优化实践 - Binder开辟线程数过多导致主线程ANR异常](https://www.sohu.com/a/563991492_121124375) 27 | * [Android 跨进程通信-(十)Binder机制传输数据限制—罪魁祸首Binder线程池](https://blog.csdn.net/nihaomabmt/article/details/116701810) 28 | * [Android 使用AIDL传输超大型文件](https://juejin.cn/post/7218615271384088633) 29 | * [车载Android应用开发与分析 - AIDL实践与封装(上)](https://juejin.cn/post/7221328463692120119) 30 | * [车载Android应用开发与分析 - AIDL实践与封装(下)](https://juejin.cn/post/7236009756530933819) 31 | * [一道面试题:使用AIDL实现跨进程传输一个2M大小的文件](https://juejin.cn/post/6990379493235884062) 32 | * [由浅入深 学习 Android Binder(四)- ibinderForJavaObject 与 javaObjectForIBinder](https://blog.csdn.net/Double2hao/article/details/111027972) 33 | * [图解 Binder:线程池](https://juejin.cn/post/7244174211970662455) 34 | * [Android使用binder访问service的方式(一)](https://blog.csdn.net/xinfuqizao/article/details/7742521) 35 | * [一类无法捕获的异常:binder 传输数据带来的一些坑](https://www.wanandroid.com/blog/show/2906) 36 | * [应用稳定性优化系列(一),ANR问题全面解析](https://cloud.tencent.com/developer/article/1969659) 37 | * [关于binder,有这样一个问题,你明白不](https://blog.csdn.net/Innost/article/details/45670567) 38 | * [WifiStateMachine死锁导致Binder Thread超限触发Watchdog重启](https://blog.csdn.net/Donald_Zhuang/article/details/106654452) 39 | * [由Monkey测试引发的跨多个进程的Android系统死锁问题分析](https://developer.aliyun.com/article/254749) 40 | 41 | Framework 教程更新计划: 42 | 43 | 1. aosp 入门 (已更新完,免费) 44 | 2. Binder 原理 (6月中旬) 45 | 3. Init 流程 (7月中旬) 46 | 4. 四大组件原理(AMS/ATMS PMS 9月底) 47 | 5. HAL 与硬件服务 (10月底) 48 | 6. 显示系统(WMS SufraceFlinger 11月底) 49 | 7. 输入系统(IMS 春节前) 50 | 51 | -------------------------------------------------------------------------------- /3.学穿Binder篇/001. Binder 基本原理.md: -------------------------------------------------------------------------------- 1 | # Binder 基本原理 2 | 3 | ## 1. 基本原理 4 | 5 | 首先要明确一点 Binder 是一个 RPC(Remote Procedure Call) 框架,也就是说借助于 Binder,我们可以在 A 进程中访问 B 进程中的函数。 6 | 7 | ### 1.1 IPC 原理 8 | 9 | RPC 一般基于 IPC 来实现的,IPC 就是跨进程数据传输,大白话就是在 A 进程可以访问到 B 进程中的数据,或者说 B 进程中的数据可以传递给 A 进程,都是一个意思。 10 | 11 | 在 Linux 中,每个进程都有自己的**虚拟内存地址空间**。虚拟内存地址空间又分为了用户地址空间和内核地址空间。 12 | 13 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20221117212450.png) 14 | 15 | 不同进程之间用户地址空间的变量和函数是不能相互访问的。 16 | 17 | 使得 A 进程能访问到 B 进程中数据的手段我们就称之为 IPC。 18 | 19 | 虽然用户地址空间是不能互相访问的,但是不同进程的内核地址空间是映射到相同物理地址的,它们是相同和共享的,我们可以借助内核地址空间作为中转站来实现进程间数据的传输。 20 | 21 | 具体的我们在 B 进程使用 copy_from_user 将用户态数据 `int a` 拷贝到内核态,这样就可以在 A 进程的内核态中访问到 `int a` 22 | 23 | 24 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20221117214847.png) 25 | 26 | 更进一步,可以在 A 进程中调用 copy_to_user 可以将 `int a` 从内核地址空间拷贝到用户地址空间。至此,我们的进程 A 用户态程序就可以访问到进程 B 中的用户地址空间数据 `int a` 了 27 | 28 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20221117215145.png) 29 | 30 | 为了访问 `int a` ,需要拷贝两次数据。能不能优化一下?我们可以通过 mmap 将进程 A 的用户地址空间与内核地址空间进行映射,让他们指向相同的物理地址空间: 31 | 32 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20221117220739.png) 33 | 34 | 完成映射后,B 进程只需调用一次 copy_from_user,A 进程的用户空间中就可以访问到 `int a`了。这里就优化到了一次拷贝。 35 | 36 | ### 1.2 RPC 原理 37 | 38 | Binder 是一个 RPC 框架,也就是说,基于 Binder,Client 进程可以访问 Server 进程中定义的函数。 39 | 40 | 那 Binder 的 RPC 是如何实现的?一般来说,Client 进程访问 Server 进程函数,我们需要: 41 | 42 | * 在 Client 进程中按照固定的规则打包数据,这些数据包含了: 43 | * 数据发给哪个进程,Binder 中是一个整型变量 Handle 44 | * 要调用目标进程中的那个函数,Binder 中用一个整型变量 Code 表示 45 | * 目标函数的参数 46 | * 要执行具体什么操作,也就是 Binder 协议 47 | * Client 进程通过 IPC 机制将数据传输给 Server 进程 48 | * Server 进程收到数据,按照固定的格式解析出数据,调用函数,并使用相同的格式将函数的返回值传递给 Client 进程。 49 | 50 | ![](https://gitee.com/androidframeworkahao/pic-bed/raw/master/img/20230628110756.png) 51 | 52 | Binder 要实现的效果就是,整体上看过去,Client 进程执行 Server 进程中的函数就和执行当前进程中的函数是一样的。 53 | 54 | 55 | ## 2. Binder 应用层工作流程 56 | 57 | Binder 是一个 **RPC**(Remote Procedure Call) 框架,翻译成中文就是**远程过程调用**。也就是说通过 Binder: 58 | 59 | * 可以在 A 进程中访问 B 进程中定义的函数 60 | * 进程 B 中的这些等待着被远程调用的函数的集合,我们称其为 **Binder 服务(Binder Service)** 61 | * 进程 A 称之为 **Binder 客户端(Binder Client)**,进程 B 称之为 **Binder 服务端(Binder Server)** 62 | * 通常,系统中的服务很多,我们需要一个管家来管理它们,**服务管家(ServiceManager)** 是 Android 系统启动时,启动的一个用于管理 **Binder 服务(Binder Service)** 的进程。通常,**服务(Service)** 需要事先注册到**服务管家(ServiceManager)**,其他进程向**服务管家(ServiceManager)** 查询服务后才能使用服务。 63 | * Binder 的 RPC 能力通过 **Binder 驱动**实现 64 | 65 | 66 | 通常一个完整的 Binder 程序涉及 4 个流程: 67 | 1. 在 Binder Server 端定义好服务 68 | 2. 然后向 ServiceManager 注册服务 69 | 3. 在 Binder Client 中向 ServiceManager 获取到服务 70 | 4. 发起远程调用,调用 Binder Server 中定义好的服务 71 | 72 | 整个流程都是建立在 Binder 驱动提供的跨进程调用能力之上: 73 | 74 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230201090305.png) 75 | 76 | 77 | ## 关于 78 | 79 | 我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研发工作。主要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术分享。 80 | 81 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 82 | 83 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) 84 | -------------------------------------------------------------------------------- /4.Hal与硬件服务/src/HelloDriver/hello_drv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /* 1. 确定主设备号 */ 18 | static int major = 0; 19 | static char kernel_buf[1024]; 20 | static struct class *hello_class; 21 | 22 | 23 | #define MIN(a, b) (a < b ? a : b) 24 | 25 | /* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */ 26 | static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) 27 | { 28 | int err; 29 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 30 | err = copy_to_user(buf, kernel_buf, MIN(1024, size)); 31 | return MIN(1024, size); 32 | } 33 | 34 | static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset) 35 | { 36 | int err; 37 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 38 | err = copy_from_user(kernel_buf, buf, MIN(1024, size)); 39 | return MIN(1024, size); 40 | } 41 | 42 | static int hello_drv_open (struct inode *node, struct file *file) 43 | { 44 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 45 | return 0; 46 | } 47 | 48 | static int hello_drv_close (struct inode *node, struct file *file) 49 | { 50 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 51 | return 0; 52 | } 53 | 54 | /* 2. 定义自己的file_operations结构体 */ 55 | static struct file_operations hello_drv = { 56 | .owner = THIS_MODULE, 57 | .open = hello_drv_open, 58 | .read = hello_drv_read, 59 | .write = hello_drv_write, 60 | .release = hello_drv_close, 61 | }; 62 | 63 | /* 4. 把file_operations结构体告诉内核:注册驱动程序 */ 64 | /* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */ 65 | static int __init hello_init(void) 66 | { 67 | int err; 68 | 69 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 70 | major = register_chrdev(0, "hello", &hello_drv); /* /dev/hello */ 71 | 72 | //提供设备信息,自动创建设备节点。 73 | hello_class = class_create(THIS_MODULE, "hello_class"); 74 | err = PTR_ERR(hello_class); 75 | if (IS_ERR(hello_class)) { 76 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 77 | unregister_chrdev(major, "hello"); 78 | return -1; 79 | } 80 | 81 | device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */ 82 | //到这里我们就可以通过 /dev/hello 文件来访问我们的驱动程序了。 83 | return 0; 84 | } 85 | 86 | /* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */ 87 | static void __exit hello_exit(void) 88 | { 89 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 90 | device_destroy(hello_class, MKDEV(major, 0)); 91 | class_destroy(hello_class); 92 | unregister_chrdev(major, "hello"); 93 | } 94 | 95 | 96 | /* 7. 其他完善:提供设备信息,自动创建设备节点 */ 97 | 98 | module_init(hello_init); 99 | module_exit(hello_exit); 100 | 101 | MODULE_LICENSE("GPL"); -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv/hello_drv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /* 1. 确定主设备号 */ 18 | static int major = 0; 19 | static char kernel_buf[1024]; 20 | static struct class *hello_class; 21 | 22 | 23 | #define MIN(a, b) (a < b ? a : b) 24 | 25 | /* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */ 26 | static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) 27 | { 28 | int err; 29 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 30 | err = copy_to_user(buf, kernel_buf, MIN(1024, size)); 31 | return MIN(1024, size); 32 | } 33 | 34 | static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset) 35 | { 36 | int err; 37 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 38 | err = copy_from_user(kernel_buf, buf, MIN(1024, size)); 39 | return MIN(1024, size); 40 | } 41 | 42 | static int hello_drv_open (struct inode *node, struct file *file) 43 | { 44 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 45 | return 0; 46 | } 47 | 48 | static int hello_drv_close (struct inode *node, struct file *file) 49 | { 50 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 51 | return 0; 52 | } 53 | 54 | /* 2. 定义自己的file_operations结构体 */ 55 | static struct file_operations hello_drv = { 56 | .owner = THIS_MODULE, 57 | .open = hello_drv_open, 58 | .read = hello_drv_read, 59 | .write = hello_drv_write, 60 | .release = hello_drv_close, 61 | }; 62 | 63 | /* 4. 把file_operations结构体告诉内核:注册驱动程序 */ 64 | /* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */ 65 | static int __init hello_init(void) 66 | { 67 | int err; 68 | 69 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 70 | major = register_chrdev(0, "hello", &hello_drv); /* /dev/hello */ 71 | 72 | //提供设备信息,自动创建设备节点。 73 | hello_class = class_create(THIS_MODULE, "hello_class"); 74 | err = PTR_ERR(hello_class); 75 | if (IS_ERR(hello_class)) { 76 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 77 | unregister_chrdev(major, "hello"); 78 | return -1; 79 | } 80 | 81 | device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */ 82 | //到这里我们就可以通过 /dev/hello 文件来访问我们的驱动程序了。 83 | return 0; 84 | } 85 | 86 | /* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */ 87 | static void __exit hello_exit(void) 88 | { 89 | printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 90 | device_destroy(hello_class, MKDEV(major, 0)); 91 | class_destroy(hello_class); 92 | unregister_chrdev(major, "hello"); 93 | } 94 | 95 | 96 | /* 7. 其他完善:提供设备信息,自动创建设备节点 */ 97 | 98 | module_init(hello_init); 99 | module_exit(hello_exit); 100 | 101 | MODULE_LICENSE("GPL"); 102 | -------------------------------------------------------------------------------- /3.学穿Binder篇/草稿.md: -------------------------------------------------------------------------------- 1 | ### 3.1 binder_init 阶段 2 | 3 | 当内核启动时,会加载 binder 驱动,加载的过程会执行 binder_init 函数,该函数内部会初始化一个 binder_device 结构体: 4 | 5 | ```cpp 6 | struct binder_device { 7 | struct hlist_node hlist; 8 | struct miscdevice miscdev; 9 | struct binder_context context; 10 | }; 11 | ``` 12 | 13 | 从成员变量 hlist_node 可以看出,binder_device 是双向链表中的一个节点。其内部的 binder_context 成员使用较多,其实现如下: 14 | 15 | ```cpp 16 | struct binder_context { 17 | struct binder_node *binder_context_mgr_node; 18 | struct mutex context_mgr_node_lock; 19 | kuid_t binder_context_mgr_uid; 20 | const char *name; 21 | }; 22 | ``` 23 | 24 | 其中最重要的是 binder_context_mgr_node 这个成员。这里先知道有这么一个成员,后面遇到会讲。 25 | 26 | ### 3.2 binder_open 阶段 27 | 28 | 应用程序调用 open 完成 binder 初始化时,最终会调用到驱动中的 binder_open 函数,在该函数中会构建一个 binder_proc 结构体实例,并挂载在全局链表 binder_procs 中。binder_proc 结构体是对应用层进程的描述,其内部有多个重要成员。 29 | 30 | ```cpp 31 | struct binder_proc { 32 | struct hlist_node proc_node; //挂载在全局 binder_proc s链表中的节点。 33 | struct rb_root threads; //使用红黑树来保存使用 Binder 机制通信的进程的 Binder 线程池的线程ID 34 | struct rb_root nodes; //使用红黑树来保存 Binder 服务对象 binder_node 的成员变量 ptr 35 | struct rb_root refs_by_desc; //使用红黑树来保存 binder_node 对应的 binder_ref 的成员变量 desc 36 | struct rb_root refs_by_node; //使用红黑树来保存 binder_node 对应的 binder_ref 的成员变量 node 37 | struct list_head waiting_threads; //空闲线程队列 38 | int pid; //当前进程的 pid 39 | struct task_struct *tsk; //当前主线程的 task_struct 40 | struct files_struct *files; //打开文件结构体 41 | struct mutex files_lock; 42 | struct hlist_node deferred_work_node; //挂载在全局延迟工作项链表binder_deferred_list中的节点 43 | int deferred_work; //描述延迟工作项的具体类型 44 | bool is_dead; //process is dead and awaiting free when outstanding transactions are cleaned up 45 | struct list_head todo; //进程待处理工作项队列 46 | struct binder_stats stats; //统计进程接收到的进程间通信请求次数 47 | struct list_head delivered_death; //死亡通知队列 48 | int max_threads; //保存Binder驱动程序最多可以主动请求进程注册的线程数量 49 | int requested_threads; //number of binder threads requested but not yet started. In current implementation, can only be 0 or 1 50 | int requested_threads_started; //number binder threads started 51 | int tmp_ref; //temporary reference to indicate proc is in use 52 | struct binder_priority default_priority; //default scheduler priority 53 | struct dentry *debugfs_entry; //debugfs node 54 | struct binder_alloc alloc; //用于管理 binder_buffer,binder_buffer 是对一次 RPC 调用使用的内存的描述 55 | struct binder_context *context; //驱动上下文 56 | spinlock_t inner_lock; 57 | spinlock_t outer_lock; 58 | }; 59 | ``` 60 | 61 | binder_open 主要是对 binder_proc 结构体实例的成员变量做一些初始化工作,没有实际的业务操作。 62 | 63 | 其中有两点点我们需要注意一下, 64 | 65 | * binder_device 66 | 67 | 我们可以通过 binder_open 传过来的 `struct file *filp` 参数获取到 binder_init 中构建的 binder_device 结构体实例。 68 | 69 | ```cpp 70 | //struct binder_device *binder_dev; 71 | binder_dev = container_of(filp->private_data, struct binder_device,miscdev); 72 | ``` 73 | 接着会把 binder_device 的 binder_context 成员赋值给 binder_proc 的 context 成员。 74 | 75 | * filp->private_data 76 | 程序会把构建好的 binder_proc 实例赋值给 `filp->private_data`,方便后面的函数获取到 binder_proc 实例 77 | 78 | ```cpp 79 | filp->private_data = proc; 80 | ``` 81 | 82 | ### 3.3 binder_mmap 阶段 83 | 84 | binder_alloc 85 | binder_buffer 86 | 87 | 88 | ### 3.4 ServiceManager 调用 binder_become_context_manager 时 89 | 90 | 91 | 构建一个 binder_node 结构体,binder_node 是对应用层 binder 服务(service)的描述,ServiceManager 也是一个binder 服务。 92 | 93 | 接着会将 binder_node 保存到 `binder_proc-> binder_context->binder_context_mgr_node`,因为 binder_context 来自 binder_device 的内部成员。而 binder_device 是全局唯一的,所以其他进程都可以访问到 ServiceManager 对应的 binder_node 结构体 binder_context_mgr_node。 94 | 95 | 96 | ### 3.5 应用程序发起写操作时 97 | 98 | 内核收到的数据格式 binder_write_read 99 | 100 | 101 | 102 | 103 | ### 3.6 应用程序发起读操作时 -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/012.JNI编程上手指南之多线程.md: -------------------------------------------------------------------------------- 1 | # JNI 编程上手指南之多线程 2 | 3 | ## 核心要点 4 | 5 | JNI 环境下,进行多线程编程,有以下两点是需明确的: 6 | 7 | * JNIEnv 是一个线程作用域的变量,不能跨线程传递,每个线程都有自己的 JNIEnv 且彼此独立 8 | * 局部引用不能在本地函数中跨函数使用,不能跨线前使用,当然也不能直接缓存起来使用 9 | 10 | ## 示例程序 11 | 12 | 示例程序主要演示: 13 | 14 | * 如何在子线程获取到属于子线程自己的 JNIEnv 15 | * 上面说了局部引用不能再线程之间直接传递,所以我们只有另觅他法。 16 | 17 | Java 层: 18 | 19 | ```java 20 | public void javaCallback(int count) { 21 | Log.e(TAG, "onNativeCallBack : " + count); 22 | } 23 | 24 | public native void threadTest(); 25 | ``` 26 | 27 | Native 层: 28 | 29 | ```c++ 30 | static int count = 0; 31 | JavaVM *gJavaVM = NULL;//全局 JavaVM 变量 32 | jobject gJavaObj = NULL;//全局 Jobject 变量 33 | jmethodID nativeCallback = NULL;//全局的方法ID 34 | 35 | //这里通过标志位来确定 两个线程的工作都完成了再执行 DeleteGlobalRef 36 | //当然也可以通过加锁实现 37 | bool main_finished = false; 38 | bool background_finished = false; 39 | 40 | static void *native_thread_exec(void *arg) { 41 | 42 | LOGE(TAG, "nativeThreadExec"); 43 | LOGE(TAG, "The pthread id : %d\n", pthread_self()); 44 | JNIEnv *env; 45 | //从全局的JavaVM中获取到环境变量 46 | gJavaVM->AttachCurrentThread(&env, NULL); 47 | 48 | //线程循环 49 | for (int i = 0; i < 5; i++) { 50 | usleep(2); 51 | //跨线程回调Java层函数 52 | env->CallVoidMethod(gJavaObj, nativeCallback, count++); 53 | } 54 | gJavaVM->DetachCurrentThread(); 55 | 56 | background_finished = true; 57 | 58 | if (main_finished && background_finished) { 59 | env->DeleteGlobalRef(gJavaObj); 60 | LOGE(TAG, "全局引用在子线程销毁"); 61 | } 62 | 63 | return ((void *) 0); 64 | 65 | } 66 | 67 | 68 | extern "C" 69 | JNIEXPORT void JNICALL 70 | Java_com_yuandaima_myjnidemo_MainActivity_threadTest(JNIEnv *env, jobject thiz) { 71 | //创建全局引用,方便其他函数或线程使用 72 | gJavaObj = env->NewGlobalRef(thiz); 73 | jclass clazz = env->GetObjectClass(thiz); 74 | nativeCallback = env->GetMethodID(clazz, "javaCallback", "(I)V"); 75 | //保存全局 JavaVM,注意 JavaVM 不是 JNI 引用类型 76 | env->GetJavaVM(&gJavaVM); 77 | 78 | pthread_t id; 79 | if (pthread_create(&id, NULL, native_thread_exec, NULL) != 0) { 80 | return; 81 | } 82 | 83 | for (int i = 0; i < 5; i++) { 84 | usleep(20); 85 | //跨线程回调Java层函数 86 | env->CallVoidMethod(gJavaObj, nativeCallback, count++); 87 | } 88 | 89 | main_finished = true; 90 | 91 | if (main_finished && background_finished && !env->IsSameObject(gJavaObj, NULL)) { 92 | env->DeleteGlobalRef(gJavaObj); 93 | LOGE(TAG, "全局引用在主线程销毁"); 94 | } 95 | } 96 | ``` 97 | 98 | 示例代码中,我们的子线程需要使用主线程中的 `jobject thiz`,该变量是一个局部引用,不能赋值给一个全局变量然后跨线程跨函数使用,我们通过 `NewGlobalRef` 将局部引用装换为全局引用并保存在全局变量 `jobject gJavaObj` 中,在使用完成后我们需要使用 DeleteGlobalRef 来释放全局引用,因为多个线程执行顺序的不确定性,我们使用了标志位来确保两个线程所有的工作完成后再执行释放操作。 99 | 100 | JNIEnv 是一个线程作用域的变量,不能跨线程传递,每个线程都有自己的 JNIEnv 且彼此独立,实际开发中,我们通过以下代码: 101 | 102 | ```c++ 103 | JavaVM *gJavaVM = NULL; 104 | //主线程获取到 JavaVM 105 | env->GetJavaVM(&gJavaVM); 106 | 107 | //子线程通过 JavaVM 获取到自己的 JNIEnv 108 | JNIEnv *env; 109 | gJavaVM->AttachCurrentThread(&env, NULL); 110 | ``` 111 | 112 | 在子线程中获取到 JNIEnv。JavaVM 是一个普通指针,由 JVM 来管理其内存的分配与回收,不是 JNI 引用类型,所以 113 | 我们可以把它赋值给一个全局变量,直接用,也不用考虑他的内存分配与后手问题。 114 | 115 | # 关于 116 | 117 | 我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研发工作。主要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术分享。 118 | 119 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 120 | 121 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCDemo/binder.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2008 The Android Open Source Project 2 | */ 3 | 4 | #ifndef _BINDER_H_ 5 | #define _BINDER_H_ 6 | 7 | #include 8 | #include 9 | 10 | struct binder_state; 11 | 12 | struct binder_io 13 | { 14 | char *data; /* pointer to read/write from */ 15 | binder_size_t *offs; /* array of offsets */ 16 | size_t data_avail; /* bytes available in data buffer */ 17 | size_t offs_avail; /* entries available in offsets array */ 18 | 19 | char *data0; /* start of data buffer */ 20 | binder_size_t *offs0; /* start of offsets buffer */ 21 | uint32_t flags; 22 | uint32_t unused; 23 | }; 24 | 25 | struct binder_death { 26 | void (*func)(struct binder_state *bs, void *ptr); 27 | void *ptr; 28 | }; 29 | 30 | /* the one magic handle */ 31 | #define BINDER_SERVICE_MANAGER 0U 32 | 33 | #define SVC_MGR_NAME "android.os.IServiceManager" 34 | 35 | enum { 36 | /* Must match definitions in IBinder.h and IServiceManager.h */ 37 | PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), 38 | SVC_MGR_GET_SERVICE = 1, 39 | SVC_MGR_CHECK_SERVICE, 40 | SVC_MGR_ADD_SERVICE, 41 | SVC_MGR_LIST_SERVICES, 42 | }; 43 | 44 | typedef int (*binder_handler)(struct binder_state *bs, 45 | struct binder_transaction_data_secctx *txn, 46 | struct binder_io *msg, 47 | struct binder_io *reply); 48 | 49 | struct binder_state *binder_open(const char* driver, size_t mapsize); 50 | void binder_close(struct binder_state *bs); 51 | 52 | /* initiate a blocking binder call 53 | * - returns zero on success 54 | */ 55 | int binder_call(struct binder_state *bs, 56 | struct binder_io *msg, struct binder_io *reply, 57 | uint32_t target, uint32_t code); 58 | 59 | void binder_set_maxthreads(struct binder_state *bs, int threads); 60 | 61 | /* release any state associate with the binder_io 62 | * - call once any necessary data has been extracted from the 63 | * binder_io after binder_call() returns 64 | * - can safely be called even if binder_call() fails 65 | */ 66 | void binder_done(struct binder_state *bs, 67 | struct binder_io *msg, struct binder_io *reply); 68 | 69 | /* manipulate strong references */ 70 | void binder_acquire(struct binder_state *bs, uint32_t target); 71 | void binder_release(struct binder_state *bs, uint32_t target); 72 | 73 | void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death); 74 | 75 | void binder_loop(struct binder_state *bs, binder_handler func); 76 | 77 | int binder_become_context_manager(struct binder_state *bs); 78 | 79 | /* allocate a binder_io, providing a stack-allocated working 80 | * buffer, size of the working buffer, and how many object 81 | * offset entries to reserve from the buffer 82 | */ 83 | void bio_init(struct binder_io *bio, void *data, 84 | size_t maxdata, size_t maxobjects); 85 | 86 | void bio_put_obj(struct binder_io *bio, void *ptr); 87 | void bio_put_ref(struct binder_io *bio, uint32_t handle); 88 | void bio_put_uint32(struct binder_io *bio, uint32_t n); 89 | void bio_put_string16(struct binder_io *bio, const uint16_t *str); 90 | void bio_put_string16_x(struct binder_io *bio, const char *_str); 91 | 92 | uint32_t bio_get_uint32(struct binder_io *bio); 93 | uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz); 94 | uint32_t bio_get_ref(struct binder_io *bio); 95 | 96 | int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr); 97 | uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name); 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /3.学穿Binder篇/视频课程讲稿/000.Binder 专题导学 —— 如何深入掌握 Binder.md: -------------------------------------------------------------------------------- 1 | # Binder 专题导学 —— 如何深入掌握 Binder 2 | 3 | Hello,Hello 大家好,这里是“写给应用开发的 Android Framework 教程”,我是阿豪,今天我们学习的内容是 “如何深入掌握 Binder”。 4 | 5 | 首先我们看到的是`Binder 专题导学 —— 学穿 Binder 篇`专题的大纲: 6 | 7 | ![](https://cdn.jsdelivr.net/gh/zzh0838/MyImages@main/img/%E5%AD%A6%E7%A9%BF%20Binder.png) 8 | 9 | 10 | 我可以把这个时间图作为一个向导,来指引我们 Binder 的学习。 11 | 12 | ## 为什么要学习和掌握 Binder 13 | 14 | 在学习之前我们要明白我们为什么要学习和掌握 Binder?主要有以下几点原因: 15 | 16 | * Binder 是整个 Android 的基石,所有的系统服务都是基于 Binder,Android 四大组件的底层实现离不开 Binder。如果你要成为 Android 领域的资深研发人员,Binder 是必须要深入掌握的知识之一。 17 | * 系统开发领域,自定义 Native 和 Java 系统服务是日常工作之一,这需要我们需要熟悉 Android 中与 Binder 相关的类库以及相关的辅助工具。 18 | * 对于应用开发,ANR 冻屏 卡顿 卡死等偶现 BUG 很可能与 Binder 调用相关,解决这些 bug,需要我们深入掌握理解 Binder 的内部原理。 19 | 20 | 21 | ## 学习 Binder 的预备知识 22 | 23 | Binder 是一个 RPC(Remote Procedure Call) 框架,涉及的技术点横跨了 内核 Native JNI Java 四层,学习 Binder 需要较为广泛的知识面,针对大部分 Android 应用开发的知识体系,我总结了以下几点必须要掌握的预备知识: 24 | 25 | * 首先,我们需要入门 Linux 驱动开发,Binder 是一个字符驱动,了解驱动的基本开发流程是阅读 Binder 驱动源码的前提条件 26 | * 其次,我们需要了解 Linux 内核中常用数据结构的基本使用,Binder 驱动中涉及了很多内核中的数据结构,我们需要了解如何使用这些数据结构 27 | * 接着,我们需要学习虚拟内存,这是掌握 Binder 工作原理的理论基础 28 | * 然后,我们需要学习 Linux 文件访问接口,学习了这部分知识才能知道 Binder 驱动是怎么被访问的 29 | * 最后,我们需要学习 JNI 编程,因为 Binder 的 Java 层中大量的 JNI 函数 30 | 31 | 32 | ## 了解 Binder 基本原理 33 | 34 | 有了预备知识的铺垫,我们就可以开始学习 Binder 的基本理论了,主要从 IPC(跨进程数据传输) 和 RPC(远程过程调用) 两个角度来理解 Binder 的工作原理。 35 | 36 | ![](https://cdn.jsdelivr.net/gh/zzh0838/MyImages@main/img/20230706114515.png) 37 | 38 | ![](https://cdn.jsdelivr.net/gh/zzh0838/MyImages@main/img/20230706114455.png) 39 | 40 | 41 | ## C 层 42 | 43 | 在了解了 Binder 基本原理后,我们就可以开始写应用了。 44 | 45 | 写应用之前,我们要明白,Binder 是一个字符驱动,linux 系统提供了 `open ioctl mmap close` 等系统调用来使用 Binder 驱动,这些函数是应用层最底层的操作了。 46 | 47 | AOSP 源码中有一个 binder.c 源文件,对 `open ioctl mmap close` 等做了封装以适应和简化 Binder 应用层程序的编写。源码中有一个 binder 的测试程序 bctest.c 以及系统服务管家 servicemanager(Android10 及以前) 都是基于 binder.c 的封装实现的。 48 | 49 | 相比 libbinder 库 C++ 的封装,binder.c 会简单不少 ,方便初学者理解 binder 应用层工作流程。 50 | 51 | 我们可以模仿 bctest.c service_manager.c 写一个完整的 Binder 应用层 demo。 52 | 53 | 这个工作已经有大佬完成了: 54 | 55 | https://github.com/weidongshan/APP_0003_Binder_C_App 56 | 57 | 但是也有一些问题,这个代码是基于 Android5 的,稍微有点老了,我在以上实现的基础上做了一些修改和适配工作,使得代码可以在 Android10 上跑起来: 58 | 59 | https://github.com/yuandaimaahao/AndroidFrameworkTutorial/tree/main/3.%E5%AD%A6%E7%A9%BFBinder%E7%AF%87/%E6%BA%90%E7%A0%81/BinderCDemo 60 | 61 | 后续的课程我们会从服务的注册、获取和使用过程来分析示例程序。 62 | 63 | 通过这个示例程序,我们可以学习到: 64 | 65 | * Binder 应用层涉及的三个进程 66 | * Binder 应用层工作的流程 67 | * Binder 与驱动交互的数据结构 68 | 69 | ## 驱动分析 70 | 71 | 结合 C 层的示例来分析驱动的实现,主要搞清楚: 72 | 73 | * 三个情景的流程:注册,获取,使用 74 | * 三个情景下内核中各种数据结构的变化 75 | 76 | 通过驱动的分析,我们就能彻底搞懂 Binder 的内部原理了,包括了: 77 | 78 | * 数据传输大小的限制 79 | * 数据是怎么跨进程传输的 80 | * 一次拷贝原理 81 | * 进程/线层的阻塞和唤醒是如何实现的。 82 | 83 | 84 | ## C++ 层分析 85 | 86 | C++ 层有一个 libbinder 库,这个库也是对 `open ioctl mmap close` 这些系统调用的封装,相比 binder.c 的封装更为完善,功能更多,内部实现更为复杂。 87 | 88 | 首先我们要写一个基于 libbinder 库的 [Demo](https://github.com/yuandaimaahao/AndroidFrameworkTutorial/tree/main/3.%E5%AD%A6%E7%A9%BFBinder%E7%AF%87/%E6%BA%90%E7%A0%81/BinderCppDemo)。基于这个 Demo, 我们来分析 libbinder 库中的类和函数,理清楚服务的注册获取使用三大流程。 89 | 90 | 基于这个 Demo,我们还需要分析 libbinder 中对几个特殊场景的处理: 91 | 92 | * 死亡通知 93 | * 多线程 94 | * 匿名服务 95 | 96 | 97 | ## Java 层分析 98 | 99 | 首先,我们先写一个 Java 层的完整示例。我们要明白 Java 层只是一层马甲,其核心功能都是通过 JNI 调用到 libbinder 库实现的,所以我们需要对 JNI 编程有基本的了解。 100 | 101 | 接着我们基于这个示例,分析三个情景下的执行过程与各个类与函数的流程与功能: 102 | 103 | * Java 层初始化 104 | * 服务注册过程分析 105 | * 服务获取与使用过程分析 106 | 107 | 当然还有一些其他高级特性也需要我们分析: 108 | 109 | * AIDL 中 in out inout oneway 的分析 110 | * Parcel 数据结构分析 111 | * Java 层死亡通知 112 | * Java 层多线程分析 113 | * 匿名服务 114 | 115 | ## 疑难问题 116 | 117 | 不论是应用开发还是系统开发我们都会遇到一些棘手的 bug,很多时候这些 bug 都和 binder 有关,总结起来,大概可以分为几类: 118 | 119 | * 死锁 120 | * 线程池满了 121 | * 代理对象内存泄露 122 | * 传输数据过大 123 | * 关键方法内发起 Binder 同步调用导致卡顿 124 | 125 | 这类 bug 很多都难以复现,很多时候都不了了之了,导致拥有这部分经验的同学很少。后续课程中,我们会逐一进行分析。 126 | 127 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/3.16.3/CMakeCCompiler.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_C_COMPILER "/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang") 2 | set(CMAKE_C_COMPILER_ARG1 "") 3 | set(CMAKE_C_COMPILER_ID "Clang") 4 | set(CMAKE_C_COMPILER_VERSION "9.0") 5 | set(CMAKE_C_COMPILER_VERSION_INTERNAL "") 6 | set(CMAKE_C_COMPILER_WRAPPER "") 7 | set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "11") 8 | set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert") 9 | set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes") 10 | set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros") 11 | set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert") 12 | 13 | set(CMAKE_C_PLATFORM_ID "") 14 | set(CMAKE_C_SIMULATE_ID "") 15 | set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU") 16 | set(CMAKE_C_SIMULATE_VERSION "") 17 | 18 | 19 | 20 | set(CMAKE_AR "/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android-ar") 21 | set(CMAKE_C_COMPILER_AR "CMAKE_C_COMPILER_AR-NOTFOUND") 22 | set(CMAKE_RANLIB "/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android-ranlib") 23 | set(CMAKE_C_COMPILER_RANLIB "CMAKE_C_COMPILER_RANLIB-NOTFOUND") 24 | set(CMAKE_LINKER "/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android-ld") 25 | set(CMAKE_MT "") 26 | set(CMAKE_COMPILER_IS_GNUCC ) 27 | set(CMAKE_C_COMPILER_LOADED 1) 28 | set(CMAKE_C_COMPILER_WORKS TRUE) 29 | set(CMAKE_C_ABI_COMPILED TRUE) 30 | set(CMAKE_COMPILER_IS_MINGW ) 31 | set(CMAKE_COMPILER_IS_CYGWIN ) 32 | if(CMAKE_COMPILER_IS_CYGWIN) 33 | set(CYGWIN 1) 34 | set(UNIX 1) 35 | endif() 36 | 37 | set(CMAKE_C_COMPILER_ENV_VAR "CC") 38 | 39 | if(CMAKE_COMPILER_IS_MINGW) 40 | set(MINGW 1) 41 | endif() 42 | set(CMAKE_C_COMPILER_ID_RUN 1) 43 | set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m) 44 | set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) 45 | set(CMAKE_C_LINKER_PREFERENCE 10) 46 | 47 | # Save compiler ABI information. 48 | set(CMAKE_C_SIZEOF_DATA_PTR "8") 49 | set(CMAKE_C_COMPILER_ABI "ELF") 50 | set(CMAKE_C_LIBRARY_ARCHITECTURE "") 51 | 52 | if(CMAKE_C_SIZEOF_DATA_PTR) 53 | set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}") 54 | endif() 55 | 56 | if(CMAKE_C_COMPILER_ABI) 57 | set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}") 58 | endif() 59 | 60 | if(CMAKE_C_LIBRARY_ARCHITECTURE) 61 | set(CMAKE_LIBRARY_ARCHITECTURE "") 62 | endif() 63 | 64 | set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "") 65 | if(CMAKE_C_CL_SHOWINCLUDES_PREFIX) 66 | set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}") 67 | endif() 68 | 69 | 70 | 71 | 72 | 73 | set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/local/include;/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/9.0.9/include;/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/x86_64-linux-android;/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include") 74 | set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "gcc;dl;c;gcc;dl") 75 | set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/9.0.9/lib/linux/x86_64;/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/lib/gcc/x86_64-linux-android/4.9.x;/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/x86_64-linux-android/lib64;/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/29;/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android;/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/x86_64-linux-android/lib;/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib") 76 | set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") 77 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/Makefile2: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.16 3 | 4 | # Default target executed when no arguments are given to make. 5 | default_target: all 6 | 7 | .PHONY : default_target 8 | 9 | #============================================================================= 10 | # Special targets provided by cmake. 11 | 12 | # Disable implicit rules so canonical targets will work. 13 | .SUFFIXES: 14 | 15 | 16 | # Remove some rules from gmake that .SUFFIXES does not remove. 17 | SUFFIXES = 18 | 19 | .SUFFIXES: .hpux_make_needs_suffix_list 20 | 21 | 22 | # Suppress display of executed commands. 23 | $(VERBOSE).SILENT: 24 | 25 | 26 | # A target that is always out of date. 27 | cmake_force: 28 | 29 | .PHONY : cmake_force 30 | 31 | #============================================================================= 32 | # Set environment variables for the build. 33 | 34 | # The shell in which to execute make rules. 35 | SHELL = /bin/sh 36 | 37 | # The CMake executable. 38 | CMAKE_COMMAND = /usr/bin/cmake 39 | 40 | # The command to remove a file. 41 | RM = /usr/bin/cmake -E remove -f 42 | 43 | # Escaping for special characters. 44 | EQUALS = = 45 | 46 | # The top-level source directory on which CMake was run. 47 | CMAKE_SOURCE_DIR = /home/android/Project/hello_drv_test 48 | 49 | # The top-level build directory on which CMake was run. 50 | CMAKE_BINARY_DIR = /home/android/Project/hello_drv_test/build 51 | 52 | #============================================================================= 53 | # Directory level rules for the build root directory 54 | 55 | # The main recursive "all" target. 56 | all: CMakeFiles/hello_drv_test.dir/all 57 | 58 | .PHONY : all 59 | 60 | # The main recursive "preinstall" target. 61 | preinstall: 62 | 63 | .PHONY : preinstall 64 | 65 | # The main recursive "clean" target. 66 | clean: CMakeFiles/hello_drv_test.dir/clean 67 | 68 | .PHONY : clean 69 | 70 | #============================================================================= 71 | # Target rules for target CMakeFiles/hello_drv_test.dir 72 | 73 | # All Build rule for target. 74 | CMakeFiles/hello_drv_test.dir/all: 75 | $(MAKE) -f CMakeFiles/hello_drv_test.dir/build.make CMakeFiles/hello_drv_test.dir/depend 76 | $(MAKE) -f CMakeFiles/hello_drv_test.dir/build.make CMakeFiles/hello_drv_test.dir/build 77 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --progress-dir=/home/android/Project/hello_drv_test/build/CMakeFiles --progress-num=1,2 "Built target hello_drv_test" 78 | .PHONY : CMakeFiles/hello_drv_test.dir/all 79 | 80 | # Build rule for subdir invocation for target. 81 | CMakeFiles/hello_drv_test.dir/rule: cmake_check_build_system 82 | $(CMAKE_COMMAND) -E cmake_progress_start /home/android/Project/hello_drv_test/build/CMakeFiles 2 83 | $(MAKE) -f CMakeFiles/Makefile2 CMakeFiles/hello_drv_test.dir/all 84 | $(CMAKE_COMMAND) -E cmake_progress_start /home/android/Project/hello_drv_test/build/CMakeFiles 0 85 | .PHONY : CMakeFiles/hello_drv_test.dir/rule 86 | 87 | # Convenience name for target. 88 | hello_drv_test: CMakeFiles/hello_drv_test.dir/rule 89 | 90 | .PHONY : hello_drv_test 91 | 92 | # clean rule for target. 93 | CMakeFiles/hello_drv_test.dir/clean: 94 | $(MAKE) -f CMakeFiles/hello_drv_test.dir/build.make CMakeFiles/hello_drv_test.dir/clean 95 | .PHONY : CMakeFiles/hello_drv_test.dir/clean 96 | 97 | #============================================================================= 98 | # Special targets to cleanup operation of make. 99 | 100 | # Special rule to run CMake to check the build system integrity. 101 | # No rule that depends on this can have commands that come from listfiles 102 | # because they might be regenerated. 103 | cmake_check_build_system: 104 | $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 105 | .PHONY : cmake_check_build_system 106 | 107 | -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/011.JNI 编程上手指南之 JNI 调用性能优化.md: -------------------------------------------------------------------------------- 1 | # JNI 编程上手指南之 JNI 调用性能优化 2 | 3 | ## 为什么要做性能优化 4 | 5 | * Java 程序中,调用一个 Native 方法相比调用一个 Java 方法要耗时很多,我们应该减少 JNI 方法的调用,同时一次 JNI 调用尽量完成更多的事情。对于过于耗时的 JNI 调用,应该放到后台线程调用。 6 | * Native 程序要访问 Java 对象的字段或调用它们的方法时,本机代码必须调用 FindClass()、GetFieldID()、GetStaticFieldID、GetMethodID() 和 GetStaticMethodID() 等方法,返回的 ID 不会在 JVM 进程的生存期内发生变化。但是,获取字段或方法的调用有时会需要在 JVM 中完成大量工作,因为字段和方法可能是从超类中继承而来的,这会让 JVM 向上遍历类层次结构来找到它们。为了提高性能,我们可以把这些 ID 缓存起来,用内存换性能。 7 | 8 | 9 | ## 使用时缓存 10 | 11 | Java 层: 12 | 13 | ```java 14 | public class TestJavaClass { 15 | 16 | //...... 17 | private void myMethod() { 18 | Log.i("JNI", "this is java myMethod"); 19 | } 20 | //...... 21 | } 22 | 23 | public native void cacheTest(); 24 | 25 | ``` 26 | 27 | Natice 层 28 | 29 | ```c++ 30 | extern "C" 31 | JNIEXPORT void JNICALL 32 | Java_com_yuandaima_myjnidemo_MainActivity_cacheTest(JNIEnv *env, jobject thiz) { 33 | 34 | jclass clazz = env->FindClass("com/yuandaima/myjnidemo/TestJavaClass"); 35 | if (clazz == NULL) { 36 | return; 37 | } 38 | 39 | static jmethodID java_construct_method_id = NULL; 40 | static jmethodID java_method_id = NULL; 41 | 42 | //实现缓存的目的,下次调用不用再获取 methodid 了 43 | if (java_construct_method_id == NULL) { 44 | //构造函数 id 45 | java_construct_method_id = env->GetMethodID(clazz, "", "()V"); 46 | if (java_construct_method_id == NULL) { 47 | return; 48 | } 49 | } 50 | 51 | //调用构造函数,创建一个对象 52 | jobject object_test = env->NewObject(clazz, java_construct_method_id); 53 | if (object_test == NULL) { 54 | return; 55 | } 56 | //相同的手法,缓存 methodid 57 | if (java_method_id == NULL) { 58 | java_method_id = env->GetMethodID(clazz, "myMethod", "()V"); 59 | if (java_method_id == NULL) { 60 | return; 61 | } 62 | } 63 | 64 | //调用 myMethod 方法 65 | env->CallVoidMethod(object_test, java_method_id); 66 | 67 | env->DeleteLocalRef(clazz); 68 | env->DeleteLocalRef(object_test); 69 | } 70 | ``` 71 | 72 | 手法还是比较简单的,主要是通过一个全局变量保存 methodid,这样只有第一次调用 native 函数时,才会调用 GetMethodID 去获取,后面的调用都使用缓存起来的值了。这样就避免了不必要的调用,提升了性能。 73 | 74 | ## 静态初始化缓存 75 | 76 | Java 层: 77 | 78 | ```java 79 | static { 80 | System.loadLibrary("myjnidemo"); 81 | initIDs(); 82 | } 83 | 84 | public static native void initIDs(); 85 | ``` 86 | 87 | C++ 层: 88 | 89 | ```c++ 90 | //定义用于缓存的全局变量 91 | static jmethodID java_construct_method_id2 = NULL; 92 | static jmethodID java_method_id2 = NULL; 93 | 94 | extern "C" 95 | JNIEXPORT void JNICALL 96 | Java_com_yuandaima_myjnidemo_MainActivity_initIDs(JNIEnv *env, jclass clazz) { 97 | 98 | jclass clazz2 = env->FindClass("com/yuandaima/myjnidemo/TestJavaClass"); 99 | 100 | if (clazz == NULL) { 101 | return; 102 | } 103 | 104 | //实现缓存的目的,下次调用不用再获取 methodid 了 105 | if (java_construct_method_id2 == NULL) { 106 | //构造函数 id 107 | java_construct_method_id2 = env->GetMethodID(clazz2, "", "()V"); 108 | if (java_construct_method_id2 == NULL) { 109 | return; 110 | } 111 | } 112 | 113 | if (java_method_id2 == NULL) { 114 | java_method_id2 = env->GetMethodID(clazz2, "myMethod", "()V"); 115 | if (java_method_id2 == NULL) { 116 | return; 117 | } 118 | } 119 | } 120 | ``` 121 | 122 | 手法和使用时缓存是一样的,只是缓存的时机变了。如果是动态注册的 JNI 还可以在 Onload 函数中来执行缓存操作。 123 | 124 | 125 | # 关于 126 | 127 | 我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研发工作。主要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术分享。 128 | 129 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 130 | 131 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) 132 | 133 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderCDemo/binder_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "binder.h" 9 | 10 | #define LOG_TAG "BinderServer" 11 | #include 12 | 13 | #define HELLO_SVR_CMD_SAYHELLO 1 14 | #define HELLO_SVR_CMD_SAYHELLO_TO 2 15 | 16 | 17 | void sayhello(void) 18 | { 19 | static int cnt = 0; 20 | //fprintf(stderr, "say hello : %d\n", ++cnt); 21 | ALOGW("say hello : %d\n", ++cnt); 22 | } 23 | 24 | 25 | int sayhello_to(char *name) 26 | { 27 | static int cnt = 0; 28 | //fprintf(stderr, "say hello to %s : %d\n", name, ++cnt); 29 | ALOGW("say hello to %s : %d\n", name, ++cnt); 30 | return cnt; 31 | } 32 | 33 | 34 | 35 | int hello_service_handler(struct binder_state *bs, 36 | struct binder_transaction_data_secctx *txn_secctx, 37 | struct binder_io *msg, 38 | struct binder_io *reply) 39 | { 40 | struct binder_transaction_data *txn = &txn_secctx->transaction_data; 41 | 42 | /* 根据txn->code知道要调用哪一个函数 43 | * 如果需要参数, 可以从msg取出 44 | * 如果要返回结果, 可以把结果放入reply 45 | */ 46 | 47 | /* sayhello 48 | * sayhello_to 49 | */ 50 | 51 | uint16_t *s; 52 | char name[512]; 53 | size_t len; 54 | //uint32_t handle; 55 | uint32_t strict_policy; 56 | int i; 57 | 58 | 59 | // Equivalent to Parcel::enforceInterface(), reading the RPC 60 | // header with the strict mode policy mask and the interface name. 61 | // Note that we ignore the strict_policy and don't propagate it 62 | // further (since we do no outbound RPCs anyway). 63 | strict_policy = bio_get_uint32(msg); 64 | 65 | switch(txn->code) { 66 | case HELLO_SVR_CMD_SAYHELLO: 67 | sayhello(); 68 | bio_put_uint32(reply, 0); /* no exception */ 69 | return 0; 70 | 71 | case HELLO_SVR_CMD_SAYHELLO_TO: 72 | /* 从msg里取出字符串 */ 73 | s = bio_get_string16(msg, &len); //"IHelloService" 74 | s = bio_get_string16(msg, &len); // name 75 | if (s == NULL) { 76 | return -1; 77 | } 78 | for (i = 0; i < len; i++) 79 | name[i] = s[i]; 80 | name[i] = '\0'; 81 | 82 | /* 处理 */ 83 | i = sayhello_to(name); 84 | 85 | /* 把结果放入reply */ 86 | bio_put_uint32(reply, 0); /* no exception */ 87 | bio_put_uint32(reply, i); 88 | 89 | break; 90 | 91 | default: 92 | fprintf(stderr, "unknown code %d\n", txn->code); 93 | return -1; 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | int test_server_handler(struct binder_state *bs, 100 | struct binder_transaction_data_secctx *txn_secctx, 101 | struct binder_io *msg, 102 | struct binder_io *reply) 103 | { 104 | struct binder_transaction_data *txn = &txn_secctx->transaction_data; 105 | 106 | int (*handler)(struct binder_state *bs, 107 | struct binder_transaction_data *txn, 108 | struct binder_io *msg, 109 | struct binder_io *reply); 110 | 111 | handler = (int (*)(struct binder_state *bs, 112 | struct binder_transaction_data *txn, 113 | struct binder_io *msg, 114 | struct binder_io *reply))txn->target.ptr; 115 | 116 | return handler(bs, txn, msg, reply); 117 | } 118 | 119 | 120 | int main(int argc, char **argv) 121 | { 122 | struct binder_state *bs; 123 | uint32_t svcmgr = BINDER_SERVICE_MANAGER; 124 | uint32_t handle; 125 | int ret; 126 | 127 | 128 | //打开驱动 129 | bs = binder_open("/dev/binder", 128*1024); 130 | if (!bs) { 131 | fprintf(stderr, "failed to open binder driver\n"); 132 | return -1; 133 | } 134 | 135 | //添加服务 136 | ret = svcmgr_publish(bs, svcmgr, "hello", hello_service_handler); 137 | if (ret) { 138 | fprintf(stderr, "failed to publish hello service\n"); 139 | return -1; 140 | } 141 | 142 | binder_loop(bs, test_server_handler); 143 | 144 | return 0; 145 | } -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/Makefile.cmake: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.16 3 | 4 | # The generator used is: 5 | set(CMAKE_DEPENDS_GENERATOR "Unix Makefiles") 6 | 7 | # The top level Makefile was generated from the following files: 8 | set(CMAKE_MAKEFILE_DEPENDS 9 | "CMakeCache.txt" 10 | "../CMakeLists.txt" 11 | "CMakeFiles/3.16.3/CMakeCCompiler.cmake" 12 | "CMakeFiles/3.16.3/CMakeCXXCompiler.cmake" 13 | "CMakeFiles/3.16.3/CMakeSystem.cmake" 14 | "/home/android/android-ndk-r21e/build/cmake/android.toolchain.cmake" 15 | "/home/android/android-ndk-r21e/build/cmake/platforms.cmake" 16 | "/usr/share/cmake-3.16/Modules/CMakeCCompiler.cmake.in" 17 | "/usr/share/cmake-3.16/Modules/CMakeCCompilerABI.c" 18 | "/usr/share/cmake-3.16/Modules/CMakeCInformation.cmake" 19 | "/usr/share/cmake-3.16/Modules/CMakeCXXCompiler.cmake.in" 20 | "/usr/share/cmake-3.16/Modules/CMakeCXXCompilerABI.cpp" 21 | "/usr/share/cmake-3.16/Modules/CMakeCXXInformation.cmake" 22 | "/usr/share/cmake-3.16/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake" 23 | "/usr/share/cmake-3.16/Modules/CMakeCommonLanguageInclude.cmake" 24 | "/usr/share/cmake-3.16/Modules/CMakeDetermineCCompiler.cmake" 25 | "/usr/share/cmake-3.16/Modules/CMakeDetermineCXXCompiler.cmake" 26 | "/usr/share/cmake-3.16/Modules/CMakeDetermineCompileFeatures.cmake" 27 | "/usr/share/cmake-3.16/Modules/CMakeDetermineCompiler.cmake" 28 | "/usr/share/cmake-3.16/Modules/CMakeDetermineCompilerABI.cmake" 29 | "/usr/share/cmake-3.16/Modules/CMakeDetermineSystem.cmake" 30 | "/usr/share/cmake-3.16/Modules/CMakeFindBinUtils.cmake" 31 | "/usr/share/cmake-3.16/Modules/CMakeGenericSystem.cmake" 32 | "/usr/share/cmake-3.16/Modules/CMakeInitializeConfigs.cmake" 33 | "/usr/share/cmake-3.16/Modules/CMakeLanguageInformation.cmake" 34 | "/usr/share/cmake-3.16/Modules/CMakeParseImplicitIncludeInfo.cmake" 35 | "/usr/share/cmake-3.16/Modules/CMakeParseImplicitLinkInfo.cmake" 36 | "/usr/share/cmake-3.16/Modules/CMakeSystem.cmake.in" 37 | "/usr/share/cmake-3.16/Modules/CMakeSystemSpecificInformation.cmake" 38 | "/usr/share/cmake-3.16/Modules/CMakeSystemSpecificInitialize.cmake" 39 | "/usr/share/cmake-3.16/Modules/CMakeTestCCompiler.cmake" 40 | "/usr/share/cmake-3.16/Modules/CMakeTestCXXCompiler.cmake" 41 | "/usr/share/cmake-3.16/Modules/CMakeTestCompilerCommon.cmake" 42 | "/usr/share/cmake-3.16/Modules/CMakeUnixFindMake.cmake" 43 | "/usr/share/cmake-3.16/Modules/Compiler/CMakeCommonCompilerMacros.cmake" 44 | "/usr/share/cmake-3.16/Modules/Compiler/Clang-C.cmake" 45 | "/usr/share/cmake-3.16/Modules/Compiler/Clang-CXX.cmake" 46 | "/usr/share/cmake-3.16/Modules/Compiler/Clang-FindBinUtils.cmake" 47 | "/usr/share/cmake-3.16/Modules/Compiler/Clang.cmake" 48 | "/usr/share/cmake-3.16/Modules/Compiler/GNU.cmake" 49 | "/usr/share/cmake-3.16/Modules/Internal/CMakeCheckCompilerFlag.cmake" 50 | "/usr/share/cmake-3.16/Modules/Internal/FeatureTesting.cmake" 51 | "/usr/share/cmake-3.16/Modules/Platform/Android-Clang-C.cmake" 52 | "/usr/share/cmake-3.16/Modules/Platform/Android-Clang-CXX.cmake" 53 | "/usr/share/cmake-3.16/Modules/Platform/Android-Clang.cmake" 54 | "/usr/share/cmake-3.16/Modules/Platform/Android-Determine-C.cmake" 55 | "/usr/share/cmake-3.16/Modules/Platform/Android-Determine-CXX.cmake" 56 | "/usr/share/cmake-3.16/Modules/Platform/Android-Determine.cmake" 57 | "/usr/share/cmake-3.16/Modules/Platform/Android-Initialize.cmake" 58 | "/usr/share/cmake-3.16/Modules/Platform/Android.cmake" 59 | "/usr/share/cmake-3.16/Modules/Platform/Android/Determine-Compiler.cmake" 60 | "/usr/share/cmake-3.16/Modules/Platform/Linux.cmake" 61 | "/usr/share/cmake-3.16/Modules/Platform/UnixPaths.cmake" 62 | ) 63 | 64 | # The corresponding makefile is: 65 | set(CMAKE_MAKEFILE_OUTPUTS 66 | "Makefile" 67 | "CMakeFiles/cmake.check_cache" 68 | ) 69 | 70 | # Byproducts of CMake generate step: 71 | set(CMAKE_MAKEFILE_PRODUCTS 72 | "CMakeFiles/3.16.3/CMakeSystem.cmake" 73 | "CMakeFiles/3.16.3/CMakeCCompiler.cmake" 74 | "CMakeFiles/3.16.3/CMakeCXXCompiler.cmake" 75 | "CMakeFiles/3.16.3/CMakeCCompiler.cmake" 76 | "CMakeFiles/3.16.3/CMakeCXXCompiler.cmake" 77 | "CMakeFiles/CMakeDirectoryInformation.cmake" 78 | ) 79 | 80 | # Dependency information for all targets: 81 | set(CMAKE_DEPEND_INFO_FILES 82 | "CMakeFiles/hello_drv_test.dir/DependInfo.cmake" 83 | ) 84 | -------------------------------------------------------------------------------- /视频课程讲稿/001.AOSP 极速上手课程讲稿.md: -------------------------------------------------------------------------------- 1 | # AOSP 上手课程讲稿 2 | 3 | Hello,大家好,这里是写给应用开发的 Android Framework 教程,我是阿豪,今天给大家分享的内容是**AOSP 极速上手**,(切 ppt)主要包含了 5 个方面的内容: 4 | 5 | * 硬件要求 6 | * 虚拟机安装 7 | * 开发环境搭建 8 | * 下载编译源码 9 | * 从一个简单的实际开发需求体验 Framework 开发 10 | 11 | (ppt 下一页) 12 | 13 | 用于 Android Framework 开发的电脑需要较强的 CPU,大内存,大存储,一般来说需要满足以下要求: 14 | 15 | * CPU 不低于 6 核心,建议 8 核及以上 16 | * 内存不低于 32G,建议 64G 及以上 17 | * 存储空间不低于 500G,建议 1TB SSD 硬盘 18 | 19 | 配置不够可能导致无法完成编译,使用卡顿等问题,建议升级配置后在进行源码的下载编译等操作。 20 | 21 | 我们推荐在 Windows 下使用 VMware 虚拟机软件安装 Ubuntu 来进行开发工作 22 | 23 | 接下来开始演示虚拟机的安装过程(切出 ppt,打开浏览器) 24 | 25 | 26 | 第一步,我们需要下载 Ubuntu 2004 镜像,打开官网,点击下载按钮完成镜像的下载 27 | 28 | 第二步,在 Vmware 中新建虚拟机 29 | 30 | (演示操作,注意最后调整 cpu 虚拟化设置) 31 | 32 | 33 | 最后一步,启动虚拟机,安装 Ubuntu。 34 | 35 | (内存低的同学,注意配置大 swap) 36 | 37 | 38 | 39 | ## 开发环境搭建 40 | 41 | 系统安装完成后我们就可以开始搭建我们的开发环境了,搭建开发环境比较简单,主要就是安装一些软件。 42 | 43 | ```bash 44 | sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig python 45 | ``` 46 | 47 | 至此,开发环境就搭建好了。 48 | 49 | 50 | 接下来我们就可以开始下载我们的源码,aosp 源码的下载分为以下几部: 51 | 52 | * 下载 repo 工具 53 | * 初始化仓库并同步远程代码 54 | * 编译源码 55 | * 运行模拟器 56 | 57 | repo 是一个 google 发布的一个 python 脚本,用于管理多个 git 仓库。下载源码之前我们需要先下载 repo 58 | 59 | ```bash 60 | mkdir ~/bin 61 | curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o ~/bin/repo 62 | chmod +x ~/bin/repo 63 | ``` 64 | 65 | repo 的运行过程中会尝试访问官方的 git 源更新自己,有的时候会因为网络问题,非常的慢,如果想使用清华的镜像源进行更新,我们需要修改家目录下的 .bashrc 文件: 66 | 67 | ```bash 68 | export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo' 69 | PATH=~/bin:$PATH 70 | ``` 71 | 72 | 然后 source 一下: 73 | 74 | ```bash 75 | source ~/.bashrc 76 | #如果使用的是 zsh 77 | #source ~/.zshrc 78 | ``` 79 | 80 | repo 下载配置完成后,就可以开始下载源码了: 81 | 82 | ```bash 83 | # 下载源码之前需要配置好 git 84 | git config --global user.email "you@example.com" 85 | git config --global user.name "Your Name" 86 | mkdir aosp 87 | cd asop 88 | #初始化仓库,-b 指示分支,这里使用 android10 89 | repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-10.0.0_r41 90 | #同步远程代码 91 | repo sync 92 | ``` 93 | 94 | -b 后面的值参考[源代码标记和 build](https://source.android.com/docs/setup/start/build-numbers?hl=zh-cn#source-code-tags-and-builds)。这里选用了 android-10.0.0_r41 版本用于学习。Android 每年都会更新一个大版本,学习的角度来说,选择一个不太老的版本即可,不必追新。 95 | 96 | 在经过漫长的等待以后我们的源码就下载好了,编译分为 3 步: 97 | 98 | ```bash 99 | # source 一个 shell 脚本,引用相关的变量和命令 100 | source build/envsetup.sh 101 | # 选择适用于模拟器的 Product 102 | lunch aosp_x86_64-eng 103 | # 开始编译 104 | make -j16 105 | ``` 106 | 107 | 编译完成以后,就可以通过命令打开模拟器: 108 | 109 | ```bash 110 | emulator 111 | ``` 112 | 113 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230220231917.png) 114 | 115 | 从一个简单的实际开发需求体验 Framework 开发 116 | 117 | 需求:去掉原生 Launcher 中的 google 搜索栏。 118 | 119 | 很多产品,比如用于仓库,电商,物流的 pda 等,更多的是考虑功能性和稳定性,UI 的美观和易用性是其次的。这些产品一般是不会重新开发和定制 Launcher 的,但是会对 Launcher 做一些修改,比如一个常见的需求是:**去掉原生 Launcher 中的 google 搜索栏**。 120 | 121 | 由于众所周知的原因 google 搜索栏在中国是没有办法使用的。在中国销售的产品,肯定是要把它去掉的。 122 | 123 | 124 | 第一步:修改文件 `packages/apps/Launcher3/res/layout/search_container_workspace.xml`,将以下内容注释掉: 125 | 126 | ```xml 127 | 132 | ``` 133 | 134 | 第二步:修改文件:`packages/apps/Launcher3/src/com/android/launcher3/Workspace.java` 将以下内容注释掉 135 | 136 | ```java 137 | // CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, firstPage.getCountX(), 1); 138 | // lp.canReorder = false; 139 | // if (!firstPage.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true)) { 140 | // Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout"); 141 | // } 142 | ``` 143 | 144 | 第三步:重新编译源码,启动模拟器 145 | 146 | ``` 147 | make -j16 148 | emulator 149 | ``` 150 | 151 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230221095253.png) 152 | 153 | 可以看到 Google 搜索框没有了。 154 | 155 | 很多同学可能有疑问,你怎么知道这么改就可以了?其实办法就一个——**读源码**。Launcher 也是一个 Android 应用,和我们平时开发的 App 没有本质的区别。就像我们接手别人开发的项目,去解决项目中的 bug,添加新的需求是一样的。 156 | 157 | Android Framework 不同的是,代码量大,涉及知识广泛,App 开发同学如果没有人指导,阅读起来比较吃力。后续内容我们带着大家由浅入深,步步分解,为应用开发的同学解开 Android Framework 的神秘面纱。 158 | 159 | 160 | ## 总结 161 | 162 | 课程主要介绍了: 163 | 164 | * 虚拟机安装 165 | * 开发环境搭建 166 | * 下载编译源码 167 | * 从一个简单的实际开发需求体验 Framework 开发 168 | 169 | 基本是偏向实际操作的内容,感兴趣的同学可以按照上面介绍的步骤体验一番。 -------------------------------------------------------------------------------- /2.AOSP上手指南/012.如何阅读系统源码——C C++篇.md: -------------------------------------------------------------------------------- 1 | # 如何阅读 Android 系统源码 —— C/C++ 篇 2 | 3 | ## 1. 工具篇 4 | 5 | 对于 Android 系统源码中的 C/C++ 代码,CLion 是一个不错的工具。 6 | 7 | 较新版本的 Android 源码支持使用 AIDEgen 调用 Clion 查看 C/C++ 代码。但是,对于我们学习使用的 Android10 是不支持的。不过我们可以通过其他办法实现 Clion 查看 C/C++ 代码: 8 | 9 | ```bash 10 | # 准备工作 11 | source build/envsetup.sh 12 | lunch aosp_x86_64-eng #选择一个合适的 Product 13 | export SOONG_GEN_CMAKEFILES=1 14 | export SOONG_GEN_CMAKEFILES_DEBUG=1 15 | make -j16 16 | ``` 17 | 18 | 接着我们就可以使用 Clion 打开我们的代码了。 19 | 20 | 假设我们需要看 SurfaceFlinger 相关代码: 21 | 22 | ```bash 23 | #系统源码目录下搜索 24 | find . -name "SurfaceFlinger*" 25 | ./frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp 26 | ./frameworks/native/services/surfaceflinger/SurfaceFlingerProperties.cpp 27 | ./frameworks/native/services/surfaceflinger/SurfaceFlinger.h 28 | ./frameworks/native/services/surfaceflinger/SurfaceFlingerProperties.h 29 | ./frameworks/native/services/surfaceflinger/SurfaceFlingerFactory.h 30 | ....... 31 | ``` 32 | 33 | 这里我们知道 SurfaceFlinger 定义在 `frameworks/native/services` 目录: 34 | 35 | 36 | 接着我们打开 Clion,点击 Open: 37 | 38 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512043810.png) 39 | 40 | 选择 `out/development/ide/clion/frameworks/native` 目录 41 | 42 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512044216.png) 43 | 44 | 这样我们就可以使用 CLion 查看系统源码了,需要注意的是我们的源码需要在 External Libraries 中查看: 45 | 46 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512044745.png) 47 | 48 | 我们也可以通过点击 Change Project Root 按钮调整目录结构: 49 | 50 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512054649.png) 51 | 52 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512054745.png) 53 | 54 | 55 | ## 2. 手段篇 56 | 57 | 阅读源码主要两个手段: 58 | 59 | * 打印 Log + 打印调用堆栈 60 | * 使用 CLion 调试 61 | 62 | 这里我们修改 SurfaceFlinger 的主函数 main_surfaceflinger.cpp 来演示打印 Log 和打印调用堆栈: 63 | 64 | ```c++ 65 | //log的头文件 66 | #include "log/log.h" 67 | //直接 define LOG_TAG 会报已定义错误,因为 SurFaceFlinger 模块的 Android.bp 已经定义了 LOG_Tag 68 | //下面这样定义就不会出错了 69 | #ifdef LOG_TAG 70 | #undef LOG_TAG 71 | #define LOG_TAG "yuandaima_sf" 72 | #endif 73 | 74 | //打印堆栈的头文件 75 | #include 76 | 77 | //在 main 函数中打印信息 78 | 79 | int main(int, char**) { 80 | 81 | //打印日志 82 | ALOGD("surfaceflinger is starting"); 83 | 84 | //打印堆栈 85 | android::CallStack callStack(LOG_TAG, 1); 86 | 87 | //省略后面的代码 88 | //...... 89 | } 90 | ``` 91 | 92 | 修改 /frameworks/native/services/surfaceflinger/Android.bp,添加 CallStack 的库依赖: 93 | 94 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512060159.png) 95 | 96 | 97 | 接着我们重新编译代码,启动模拟器,进入 adb shell,查看 log: 98 | 99 | ```bash 100 | rice14:/ # logcat | grep yuandaima_sf 101 | 05-11 09:54:10.291 1531 1531 D yuandaima_sf: surfaceflinger is starting 102 | 103 | 05-11 09:54:10.296 1531 1531 D yuandaima_sf: #00 pc 00000000000030a1 /system/bin/surfaceflinger (main+65) 104 | 05-11 09:54:10.296 1531 1531 D yuandaima_sf: #01 pc 000000000008a985 /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+117) 105 | ``` 106 | 107 | 通过 log 信息我们可以知道程序的运行状态和运行过程中的关键参数。通过调用栈我们可以知道函数的执行流程。 108 | 109 | 110 | 我们还可以通过 Clion 来调试 C/C++ 代码: 111 | 112 | 这里以调试 service_manager.c 为例: 113 | 114 | 我们在如下位置打印好断点: 115 | 116 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512054931.png) 117 | 118 | 接着配置远程调试: 119 | 120 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512055029.png) 121 | 122 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512055121.png) 123 | 124 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512055156.png) 125 | 126 | 这样我们的 Clion 就配置好了。 127 | 128 | 接着我们查看 servicemanage 进程的 pid: 129 | 130 | ```bash 131 | adb shell ps -A | grep servicemanager 132 | system 1406 1 14116 5532 binder_ioctl 0 S servicemanager 133 | system 1407 1 21764 9772 SyS_epoll_wait 0 S hwservicemanager 134 | system 1408 1 14816 2584 binder_ioctl 0 S vndservicemanage 135 | ``` 136 | 137 | servicemanager 的 pid 为 1406,接着在模拟器上开启 gdbserver: 138 | 139 | ```bash 140 | adb forward tcp:1235 tcp:1235 141 | adb shell gdbserver64 :1235 --attach 1406 142 | ``` 143 | 144 | 接着点击 Clion 右上角的 debug 按钮就进入 debug 环境了: 145 | 146 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230512055546.png) 147 | 148 | 149 | 这样我们就可以开始调试 C/C++ 代码了。 150 | 151 | ## 关于 152 | 153 | 154 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 155 | 156 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) 157 | -------------------------------------------------------------------------------- /1.基础篇/005.Linux Shell 脚本编程入门2——脚本自动化基础.md: -------------------------------------------------------------------------------- 1 | # Linux Shell 脚本编程入门2——脚本自动化基础 2 | 3 | tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb;setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0';bootm 0x60003000 - 0x60500000; 4 | 5 | tftp 0x60003000 uImage;tftp 0x60800000 vexpress-v2p-ca9.dtb;setenv bootargs 'root=/dev/nfs rw nfsroot=10.0.0.103:/home/zzh0838/nfs,proto=tcp,nfsvers=3,nolock init=/linuxrc ip=10.0.0.144 console=ttyAMA0';bootm 0x60003000 - 0x60800000; 6 | 7 | ## 1. 字符串的判断与比较 8 | 9 | 在 shell 中,可以使用 test 或者 [] 来做判断: 10 | 11 | ```bash 12 | # 使用 $? 查看上一条命令的退出码,0 代表正确(true),非 0 代表错误(false) 13 | #这里的 a b 就是字符串本身,而不是变量 14 | # 注意 == 两边的空格不能少 15 | test a == b ; echo $? 16 | 1 17 | test a != b ; echo $? 18 | 0 19 | 20 | test $a == $b ; echo $? #这里的 a b 是变量 21 | 22 | # 注意 == 两边的空格不能少,[ 右侧空格不能少, ] 左侧空格不能少 23 | [ $USER == root ]; echo $? 24 | 25 | # 相等输出 Y,不相等输出 N 26 | [ $USER == root ] && echo Y || echo N 27 | 28 | [ $USER != root ] && echo Y || echo N 29 | 30 | # 用 -z 可以测试一个字符串是否为空 31 | [ -z "$TEST" ] && echo Y || echo N 32 | 33 | # -n 测试一个字符串是否非空 34 | # 注意点: $ 引用一个值时,使用 "" 括起来,否则 -n 判断会出错 35 | [ -n "$TEST" ] && echo Y || echo N 36 | ``` 37 | 38 | ## 2. 整数的判断与比较 39 | 40 | ```bash 41 | # -eq 判断两个数是否相等 42 | test 3 -eq 3 && echo Y || echo N 43 | [ 3 -eq 3 ] && echo Y || echo N 44 | 45 | # -gt 大于 46 | [ 6 -gt 4 ] && echo Y || echo N 47 | # -ge 大于等于 48 | [ 6 -ge 4 ] && echo Y || echo N 49 | # -lt 小于 50 | [ 4 -lt 3 ] && echo Y || echo N 51 | # -le 小于等于 52 | [ 3 -le 4 ] && echi Y || echo N 53 | ``` 54 | 55 | ## 3.文件属性判断 56 | 57 | ```bash 58 | # 判断文件是否存在 59 | [ -e test.txt ] && echo Y || N 60 | # 判断文件是否不存在 61 | [ ! -e test.txt ] && echo Y || N 62 | # 判断文件存在,且类型是文件 63 | [ -f test.txt ] && echo Y || N 64 | # 判断文件存在,且类型是目录 65 | [ -d hello ] && echo Y || N 66 | # 判断是否为软链接 67 | [ -L soft.txt ] && echo Y || echo N 68 | # 两个文件使用相同设备、相同inode编号,则返回真,否则返回假 即硬链接判断 69 | [ /root/hard -ef /etc/hosts ] && echo Y || echo N 70 | # 判断当前用户对文件是否有读权限 71 | [ -r test.txt ] && echo Y || echo N 72 | # 判断当前用户对文件是否有写权限 73 | [ -w test.txt ] && echo Y || echo N 74 | # 判断当前用户对文件是否有执行权限 75 | [ -x ver1.txt ] && echo Y || echo N 76 | 77 | # 需要注意的是 root 用户对所有文件都具有读写权限,但是 root 对文件没有可执行权限的情况下是不可执行该文件的 78 | ``` 79 | 80 | ## 4. if 语句 81 | 82 | ```bash 83 | # if 84 | x=3 85 | if [ x -gt 1 ] then 86 | echo "hello" 87 | fi 88 | 89 | # 双分支 if 90 | if [ x -lt 5 ] then 91 | echo "hello" 92 | else 93 | echo "hello world" 94 | fi 95 | 96 | # 多分支 if 97 | num=$[RANDOM%10+1] 98 | read -p "请输入 1~10 之间的整数:" guess 99 | if [ $guess -eq $num ];then 100 | echo "恭喜,猜对了,就是:$num" 101 | elif [ $guess -lt $num ];then 102 | echo "Oops,猜小了." 103 | else 104 | echo "Oops,猜大了." 105 | fi 106 | ``` 107 | 108 | ## 5. case 语句 109 | 110 | ```bash 111 | read -p "请输入一个 a~f 之间的字母:" key 112 | 113 | case $key in 114 | a) 115 | echo "I am a.";; 116 | b) 117 | echo "I am b.";; 118 | c) 119 | echo "I am c.";; 120 | d) 121 | echo "I am d.";; 122 | e) 123 | echo "I am e.";; 124 | f) 125 | echo "I am f.";; 126 | *) 127 | echo "Out of range.";; 128 | esac 129 | ``` 130 | 131 | ## 6. for 循环 132 | 133 | ```bash 134 | for i in 1 2 3 4 5 135 | do 136 | ehco $i 137 | done 138 | 139 | for ((i=1;i<=5;i++)) 140 | do 141 | echo $i 142 | done 143 | 144 | for i in `cat user.txt` 145 | do 146 | if id $i &>/dev/null ;then 147 | echo "$i,该账户已经存在!" 148 | else 149 | useradd $i 150 | echo "123456" | passwd --stdin $i 151 | fi 152 | done 153 | 154 | # continue 的使用 155 | for i in {1..5} 156 | do 157 | [ $i -eq 3 ] && continue 158 | echo $i 159 | done 160 | 161 | # break 的使用 162 | for i in {1..5} 163 | do 164 | [ $i -eq 3 ] && break 165 | echo $i 166 | done 167 | echo "game over." 168 | 169 | 170 | # exit 171 | for i in {1..5} 172 | do 173 | [ $i -eq 3 ] && exit 174 | echo $i 175 | done 176 | echo "game over." 177 | ``` 178 | 179 | ## 7. 数组 180 | 181 | 数组是一组数据的集合,数组中的每个数据被称为一个数组元素。目前 Bash 仅支持一维索引数组和关联数组,Bash 对数组大小没有限制。 182 | 183 | ```bash 184 | # 数组的定义 185 | name[0]="hello" 186 | name[1]="world" 187 | 188 | # 数组的引用 189 | echo ${name[0]} 190 | ehco ${name[1]} 191 | 192 | # 数组的遍历 193 | for i in "${name[@]}" 194 | do 195 | echo $i 196 | done 197 | ``` 198 | 199 | 关联数组类似 Java 中的 Map,关联数组的下标可以是 200 | 任意字符串。关联数组的索引要求具有唯一性。 201 | 202 | ```bash 203 | declare -A man 204 | 205 | man[name]=Jack 206 | man[age]=18 207 | 208 | # 将数组作为一个整体输出 209 | echo ${man[*]} 210 | 211 | # 数组的遍历 212 | for i in "${man[@]}" 213 | do 214 | echo $i 215 | done 216 | ``` 217 | 218 | ## 8.函数 219 | 220 | 221 | ```bash 222 | # 定义函数 223 | mymkdir() { 224 | mkdir /tmp/test 225 | touch /tmp/t.txt 226 | } 227 | 228 | #定义函数并不会导致函数内的任何命令被执行,仅当通过函数名称调用时,函数内的命令才会被触发执行 229 | mymkdir 230 | ``` 231 | 232 | 233 | ## 参考资料 234 | 235 | * 《Linux Shell 核心编程指南》 丁明一 236 | * [Bash 脚本教程](https://wangdoc.com/bash/intro) -------------------------------------------------------------------------------- /2.AOSP上手指南/010.添加开机自启动 Shell 脚本.md: -------------------------------------------------------------------------------- 1 | # 添加开机自启动 Shell 脚本 2 | 3 | 很多时候,我们想在系统启动的时候干一些“私活”,这个时候,我们就可以添加开机自启动的脚本来完成。下面我们介绍一个简单的示例: 4 | 5 | 在 `device/Jelly/Rice14` 目录下添加如下的文件与文件夹: 6 | 7 | ```bash 8 | initscript 9 | ├── Android.bp 10 | ├── initscript.rc 11 | └── initscript.sh 12 | 13 | sepolicy #部分文件为 seandroid 入门添加的内容 14 | ├── device.te 15 | ├── file_contexts 16 | ├── hello_se.te 17 | └── initscript.te 18 | ``` 19 | 20 | initscript.sh 是一个简单的 shell 脚本: 21 | 22 | ```bash 23 | #!/vendor/bin/sh 24 | 25 | echo "this is init script" 26 | log -t initscript "this is initscript!" #打 log 27 | ``` 28 | 29 | 需要注意的是 shebang 的内容是 `#!/vendor/bin/sh`。 30 | 31 | 32 | initscript.rc 的内容如下: 33 | 34 | ```rc 35 | service initscript /vendor/bin/initscript 36 | class main 37 | user root 38 | group root system 39 | oneshot 40 | ``` 41 | 42 | * class main 指明当前服务时系统的基本服务,保证了系统启动时,会启动这个服务 43 | * oneshot 表示服务只执行一次 44 | 45 | Android.bp 的内容如下: 46 | 47 | ```json 48 | cc_prebuilt_binary { 49 | name: "initscript", 50 | srcs: ["initscript.sh"], 51 | init_rc: ["initscript.rc"], 52 | strip: { 53 | none: true, 54 | }, 55 | vendor: true 56 | } 57 | 58 | ``` 59 | 60 | 接着是配置 selinux: 61 | 62 | initscript.te 的内容如下: 63 | 64 | ```te 65 | type initscript_dt, domain; 66 | type initscript_dt_exec, exec_type, vendor_file_type, file_type; 67 | 68 | init_daemon_domain(initscript_dt) 69 | domain_auto_trans(shell, initscript_dt_exec, initscript_dt); 70 | ``` 71 | 72 | file_contexts 中添加如下内容: 73 | 74 | ```te 75 | /vendor/bin/initscript u:object_r:initscript_dt_exec:s0 76 | ``` 77 | 78 | 最后修改 `device/Jelly/Rice14/Rice14.mk`: 79 | 80 | ```Makefile 81 | PRODUCT_PACKAGES += \ 82 | helloseandroid \ 83 | initscript 84 | 85 | BOARD_SEPOLICY_DIRS += \ 86 | device/Jelly/Rice14/sepolicy 87 | ``` 88 | 89 | 90 | 接着编译系统,启动模拟器: 91 | 92 | ```Makefile 93 | source build/envsetup.sh 94 | lunch Rice14-userdebug 95 | make -j16 96 | emulator 97 | ``` 98 | 99 | 100 | 接着我们查看 log: 101 | 102 | ```bash 103 | logcat | grep initscript 104 | 105 | 04-08 23:34:06.250 1600 1600 W initscript: type=1400 audit(0.0:6): avc: denied { execute_no_trans } for path="/vendor/bin/toybox_vendor" dev="dm-1" ino=205 scontext=u:r:initscript_dt:s0 tcontext=u:object_r:vendor_toolbox_exec:s0 tclass=file permissive=0 106 | ``` 107 | 108 | 错误信息,提示我们缺少权限,按照之前介绍的方法使用 audit2allow 命令,发现并没有生成缺失的权限。那怎么办?看报错信息喽: 109 | 110 | 报错信息的意思是:当 initscript_dt 执行安全上下文为 `u:object_r:vendor_toolbox_exec:s0` 的 `/vendor/bin/toybox_vendor` 时,缺少 execute_no_trans 权限。 111 | 112 | 什么意思呢? 113 | 114 | 我们先看下 `/vendor/bin/toybox_vendor` 文件: 115 | 116 | ```bash 117 | #切换为 root 118 | su 119 | #带 x 权限,是一个可执行文件 120 | -rwxr-xr-x 1 root shell 503304 2023-04-08 23:04 /vendor/bin/toybox_vendor 121 | #不带参数执行一下 122 | /vendor/bin/toybox_vendor 123 | acpi base64 basename bc blkid blockdev cal cat chattr chcon chgrp 124 | chmod chown chroot chrt cksum clear cmp comm cp cpio cut date dd devmem 125 | df diff dirname dmesg dos2unix du echo egrep env expand expr fallocate 126 | false fgrep file find flock fmt free freeramdisk fsfreeze fsync getconf 127 | getenforce getfattr grep groups gunzip gzip head help hostname hwclock 128 | i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd insmod 129 | install ionice iorenice iotop kill killall ln load_policy log logname 130 | losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom 131 | mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount mountpoint 132 | mv nbd-client nc netcat netstat nice nl nohup nproc nsenter od partprobe 133 | paste patch pgrep pidof ping ping6 pivot_root pkill pmap printenv 134 | printf prlimit ps pwd pwdx readlink realpath renice restorecon rev 135 | rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr 136 | setprop setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep 137 | sort split start stat stop strings stty swapoff swapon sync sysctl 138 | tac tail tar taskset tee time timeout top touch tr traceroute traceroute6 139 | true truncate tty tunctl ulimit umount uname uniq unix2dos unlink 140 | unshare uptime usleep uudecode uuencode uuidgen vconfig vmstat watch 141 | ``` 142 | 143 | 从以上的操作可以看出 toybox_vendor 是一个命令集合,我们常用的 shell 命令均会通过 toybox_vendor 来执行。 144 | 145 | 再回到权限那里,我们的脚本调用了 echo log 两个命令,这两个命令会通过执行 toybox_vendor 来实现,当执行 toybox_vendor 时,我们就需要 toybox_vendor 的打开,读取,执行权限,以及配置 domain 转换(A 程序到 B 程序都需要配置域转换)。 domain 转换可以简单配置执行时不转换 execute_no_trans 即可,综上,我们在 initscript.te 中添加如下权限: 146 | 147 | ```bash 148 | allow initscript_dt vendor_toolbox_exec:file { read open execute execute_no_trans }; 149 | ``` 150 | 151 | 接着再次编译系统,启动模拟器: 152 | 153 | ```Makefile 154 | source build/envsetup.sh 155 | lunch Rice14-userdebug 156 | make -j16 157 | emulator 158 | ``` 159 | 160 | 进入 adb shell 查看信息: 161 | 162 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/20230409095814.png) 163 | 164 | 启动时打的 log,以及启动相关的属性值均正常,证明我们添加的脚本执行成功了。 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/009.JNI 编程上手指南之异常处理.md: -------------------------------------------------------------------------------- 1 | # JNI 编程上手指南之异常处理 2 | 3 | JNI 程序中的异常分为以下几种: 4 | 5 | * Native 程序原生异常,一般通过函数返回值和 linux 信号处理, C++ 中也有 try catch 机制解决异常,不是本文重点 6 | * JNIEnv 内部函数抛出的异常,一般通过返回值判断,发现异常直接 return, jvm 会给将异常传递给 Java 层 7 | * Native 回调 Java 层方法,被回调的方法抛出异常,JNI 提供了特定的 API 来处理这类异常 8 | 9 | 10 | ## 1. JNIEnv 内部函数抛出的异常 11 | 12 | 很多 JNIEnv 中的函数都会抛出异常,处理方法大体上是一致的: 13 | 14 | * 返回值与特殊值(一般是 NULL)比较,知晓函数是否发生异常 15 | * 如果发生异常立即 return 16 | * jvm 会将异常抛给 java 层,我们可以在 java 层通过 try catch 机制捕获异常 17 | 18 | 接着我们来看一个例子: 19 | 20 | Java 层: 21 | ```java 22 | public native void exceptionTest(); 23 | 24 | //调用 25 | try { 26 | exceptionTest(); 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | } 30 | ``` 31 | 32 | Native 层: 33 | 34 | ```c++ 35 | extern "C" 36 | JNIEXPORT void JNICALL 37 | Java_com_yuandaima_myjnidemo_MainActivity_exceptionTest(JNIEnv *env, jobject thiz) { 38 | //查找的类不存在,返回 NULL; 39 | jclass clazz = env->FindClass("com/yuandaima/myjnidemo/xxx"); 40 | if (clazz == NULL) { 41 | return; //return 后,jvm 会向 java 层抛出 ClassNotFoundException 42 | } 43 | } 44 | ``` 45 | 46 | 执行后的 log: 47 | 48 | ```bash 49 | java.lang.ClassNotFoundException: Didn't find class "com.yuandaima.myjnidemo.xxx" 50 | ``` 51 | 说明,java 层捕获到了异常 52 | 53 | ## 2. Native 回调 Java 层方法,被回调的方法抛出异常 54 | 55 | Native 回调 Java 层方法,被回调的方法抛出异常。这样情况下一般有两种解决办法: 56 | 57 | * Java 层 Try catch 本地方法,这是比较推荐的办法。 58 | * Native 层处理异常,异常处理如果和 native 层相关,可以采用这种方式 59 | 60 | ### 2.1 Java 层 Try catch 本地方法 61 | 62 | Java 层: 63 | 64 | ```java 65 | //执行这个方法会抛出异常 66 | private static int exceptionMethod() { 67 | return 20 / 0; 68 | } 69 | 70 | //native 方法,在 native 中,会调用到 exceptionMethod() 方法 71 | public native void exceptionTest(); 72 | 73 | //Java 层调用 74 | try { 75 | exceptionTest(); 76 | } catch (Exception e) { 77 | //这里处理异常 78 | //一般是打 log 和弹 toast 通知用户 79 | e.printStackTrace(); 80 | } 81 | ``` 82 | 83 | Native 层: 84 | 85 | ```c++ 86 | extern "C" 87 | JNIEXPORT void JNICALL 88 | Java_com_yuandaima_myjnidemo_MainActivity_exceptionTest(JNIEnv *env, jobject thiz) { 89 | jclass clazz = env->FindClass("com/yuandaima/myjnidemo/TestJavaClass"); 90 | if (clazz == NULL) { 91 | return; 92 | } 93 | 94 | //调用 java 层会抛出异常的方法 95 | jmethodID static_method_id = env->GetStaticMethodID(clazz, "exceptionMethod", "()I"); 96 | 97 | if (NULL == static_method_id) { 98 | return; 99 | } 100 | 101 | //直接调用,发生 ArithmeticException 异常,传回 Java 层 102 | env->CallStaticIntMethod(clazz, static_method_id); 103 | 104 | env->DeleteLocalRef(clazz); 105 | } 106 | ``` 107 | 108 | ### 2.2 Native 层处理异常 109 | 110 | 有的异常需要在 Native 处理,这里又分为两类: 111 | 112 | * 异常在 Native 层就处理完了 113 | * 异常在 Native 层处理了,还需要返回给 Java 层,Java 层继续处理 114 | 115 | 接着我们看下示例: 116 | 117 | Java 层: 118 | 119 | ```java 120 | //执行这个方法会抛出异常 121 | private static int exceptionMethod() { 122 | return 20 / 0; 123 | } 124 | 125 | //native 方法,在 native 中,会调用到 exceptionMethod() 方法 126 | public native void exceptionTest(); 127 | 128 | //Java 层调用 129 | try { 130 | exceptionTest(); 131 | } catch (Exception e) { 132 | //这里处理异常 133 | //一般是打 log 和弹 toast 通知用户 134 | e.printStackTrace(); 135 | } 136 | ``` 137 | 138 | Native 层: 139 | 140 | ```c++ 141 | extern "C" 142 | JNIEXPORT void JNICALL 143 | Java_com_yuandaima_myjnidemo_MainActivity_exceptionTest(JNIEnv *env, jobject thiz) { 144 | jthrowable mThrowable; 145 | jclass clazz = env->FindClass("com/yuandaima/myjnidemo/TestJavaClass"); 146 | if (clazz == NULL) { 147 | return; 148 | } 149 | 150 | jmethodID static_method_id = env->GetStaticMethodID(clazz, "exceptionMethod", "()I"); 151 | if (NULL == static_method_id) { 152 | return; 153 | } 154 | 155 | env->CallStaticIntMethod(clazz, static_method_id); 156 | 157 | //检测是否有异常发生 158 | if (env->ExceptionCheck()) { 159 | //获取到异常对象 160 | mThrowable = env->ExceptionOccurred(); 161 | //这里就可以根据实际情况处理异常了 162 | //....... 163 | //打印异常信息堆栈 164 | env->ExceptionDescribe(); 165 | //清除异常信息 166 | //如果,异常还需要 Java 层处理,可以不调用 ExceptionClear,让异常传递给 Java 层 167 | env->ExceptionClear(); 168 | //如果调用了 ExceptionClear 后,异常还需要 Java 层处理,我们可以抛出一个新的异常给 Java 层 169 | jclass clazz_exception = env->FindClass("java/lang/Exception"); 170 | env->ThrowNew(clazz_exception, "JNI抛出的异常!"); 171 | 172 | env->DeleteLocalRef(clazz_exception); 173 | } 174 | 175 | env->DeleteLocalRef(clazz); 176 | env->DeleteLocalRef(mThrowable); 177 | } 178 | ``` 179 | 180 | 181 | # 关于 182 | 183 | 我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研发工作。主要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术分享。 184 | 185 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 186 | 187 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/004.JNI 编程上手指南之 JNIEnv 详解.md: -------------------------------------------------------------------------------- 1 | # JNI 编程上手指南之 JNIEnv 详解 2 | 3 | ## 1. JNIEnv 是什么 4 | 5 | JNIEnv 即 Java Native Interface Environment,Java 本地编程接口环境。JNIEnv 内部定义了很多函数用于简化我们的 JNI 编程。 6 | 7 | JNI 把 Java 中的所有对象或者对象数组当作一个 C 指针传递到本地方法中,这个指针指向 JVM 中的内部数据结构(对象用jobject来表示,而对象数组用jobjectArray或者具体是基本类型数组),而内部的数据结构在内存中的存储方式是不可见的。只能从 JNIEnv 指针指向的函数表中选择合适的 JNI 函数来操作JVM 中的数据结构。 8 | 9 | 在 C 语言中,JNIEnv 是一个指向 JNINativeInterface_ 结构体的指针: 10 | 11 | ```c 12 | #ifdef __cplusplus 13 | typedef JNIEnv_ JNIEnv; 14 | #else 15 | typedef const struct JNINativeInterface_ *JNIEnv; // C 语言 16 | #endif 17 | 18 | struct JNINativeInterface_ { 19 | void *reserved0; 20 | void *reserved1; 21 | void *reserved2; 22 | 23 | void *reserved3; 24 | jint (JNICALL *GetVersion)(JNIEnv *env); 25 | 26 | jclass (JNICALL *DefineClass) 27 | (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, 28 | jsize len); 29 | 30 | jstring (JNICALL *NewStringUTF) 31 | (JNIEnv *env, const char *utf); 32 | 33 | //省略其他函数指针 34 | //...... 35 | } 36 | ``` 37 | 38 | JNINativeInterface_ 结构体中定义了非常多的函数指针,这些函数用于简化我们的 JNI 编程。C 语言中,JNIEnv 中函数的使用方式如下: 39 | 40 | ```c 41 | //JNIEnv * env 42 | // env 的实际类型是 JNINativeInterface_** 43 | (*env)->NewStringUTF(env,"Hello from JNI !"); 44 | ``` 45 | 46 | 47 | 在 C++ 代码中,JNIEnv 是一个 JNIEnv_ 结构体: 48 | 49 | ```c++ 50 | #ifdef __cplusplus 51 | typedef JNIEnv_ JNIEnv; 52 | #else 53 | typedef const struct JNINativeInterface_ *JNIEnv; 54 | #endif 55 | 56 | struct JNIEnv_ { 57 | const struct JNINativeInterface_ *functions; 58 | #ifdef __cplusplus 59 | 60 | jint GetVersion() { 61 | return functions->GetVersion(this); 62 | } 63 | jclass DefineClass(const char *name, jobject loader, const jbyte *buf, 64 | jsize len) { 65 | return functions->DefineClass(this, name, loader, buf, len); 66 | } 67 | jclass FindClass(const char *name) { 68 | return functions->FindClass(this, name); 69 | } 70 | jmethodID FromReflectedMethod(jobject method) { 71 | return functions->FromReflectedMethod(this,method); 72 | } 73 | jfieldID FromReflectedField(jobject field) { 74 | return functions->FromReflectedField(this,field); 75 | } 76 | 77 | jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) { 78 | return functions->ToReflectedMethod(this, cls, methodID, isStatic); 79 | } 80 | 81 | jclass GetSuperclass(jclass sub) { 82 | return functions->GetSuperclass(this, sub); 83 | } 84 | //省略其他函数 85 | //...... 86 | } 87 | ``` 88 | 89 | JNIEnv_ 结构体中同样定义了非常多的成员函数,这些函数用于简化我们的 JNI 编程。C++ 语言中,JNIEnv 中函数的使用方式如下: 90 | 91 | ```c 92 | //JNIEnv * env 93 | // env 的实际类型是 JNIEnv_* 94 | env->NewstringUTF ( "Hello from JNI ! "); 95 | ``` 96 | 97 | ## 2. 如何获取到 JNIEnv 98 | 99 | 对于单线程的情况,我们可以直接通过 JNI 方法传入的参数获取到 JNIEnv 100 | 101 | 102 | ```c 103 | // 第一个参数就是 JNIEnv 104 | JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj) 105 | { 106 | return (*env)->NewStringUTF(env,"Hello from JNI !"); 107 | } 108 | ``` 109 | 110 | 对于多线程的情况,首先我们要知道,**JNIEnv 是一个线程作用域的变量,不能跨线程传递,不同线程的 JNIEnv 彼此独立**。那如何在不同的线程中获取到 JNIEnv 呢: 111 | 112 | ```c 113 | //定义全局变量 114 | //JavaVM 是一个结构体,用于描述 Java 虚拟机,后面会讲 115 | JavaVM* gJavaVM; 116 | 117 | JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj) 118 | { 119 | //线程不允许共用env环境变量,但是JavaVM指针是整个jvm共用的,所以可以通过下面的方法保存JavaVM指针,在线程中使用 120 | env->GetJavaVM(&gJavaVM); 121 | return (*env)->NewStringUTF(env,"Hello from JNI !"); 122 | } 123 | 124 | //假设这是一个工具函数,可能被多个线程调用 125 | void util_xxx() 126 | { 127 | JNIEnv *env; 128 | //从全局的JavaVM中获取到环境变量 129 | gJavaVM->AttachCurrentThread(&env,NULL); 130 | 131 | //就可以使用 JNIEnv 了 132 | 133 | //最后需要做清理操作 134 | gJavaVM->DetachCurrentThread(); 135 | } 136 | ``` 137 | 138 | 139 | ## 3. JNIEnv 内部函数分类 140 | 141 | JNIEnv 中定义的函数可以分为以下几类: 142 | 143 | | 函数名 | 功能 | 144 | | --------- | -------------------------------- | 145 | | FindClass | 用于获取类 | 146 | | GetObjectClass | 通过对象获取这个类 | 147 | | NewGlobalRef | 创建 obj 参数所引用对象的新全局引用 | 148 | | NewObject | 构造新 Java 对象 | 149 | | NewString | 利用 Unicode 字符数组构造新的 java.lang.String 对象 | 150 | | NewStringUTF | 利用 UTF-8 字符数组构造新的 java.lang.String 对象 | 151 | | New\Array | 创建类型为Type的数组对象 | 152 | | Get\Field | 获取类型为Type的字段 | 153 | | Set\Field | 设置类型为Type的字段的值 | 154 | | GetStatic\Field | 获取类型为Type的static的字段 | 155 | | SetStatic\Field | 设置类型为Type的static的字段的值 | 156 | | Call\Method | 调用返回类型为Type的方法 | 157 | | CallStatic\Method | 调用返回值类型为Type的static方法 | 158 | 159 | 相关的函数不止上面的这些,这些函数的介绍和使用方法,我们可以在开发过程中参考官方文档 160 | https://docs.oracle.com/en/java/javase/11/docs/specs/jni/index.html 161 | 162 | 163 | # 关于 164 | 165 | 我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研发工作。主要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术分享。 166 | 167 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 168 | 169 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/build.make: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.16 3 | 4 | # Delete rule output on recipe failure. 5 | .DELETE_ON_ERROR: 6 | 7 | 8 | #============================================================================= 9 | # Special targets provided by cmake. 10 | 11 | # Disable implicit rules so canonical targets will work. 12 | .SUFFIXES: 13 | 14 | 15 | # Remove some rules from gmake that .SUFFIXES does not remove. 16 | SUFFIXES = 17 | 18 | .SUFFIXES: .hpux_make_needs_suffix_list 19 | 20 | 21 | # Suppress display of executed commands. 22 | $(VERBOSE).SILENT: 23 | 24 | 25 | # A target that is always out of date. 26 | cmake_force: 27 | 28 | .PHONY : cmake_force 29 | 30 | #============================================================================= 31 | # Set environment variables for the build. 32 | 33 | # The shell in which to execute make rules. 34 | SHELL = /bin/sh 35 | 36 | # The CMake executable. 37 | CMAKE_COMMAND = /usr/bin/cmake 38 | 39 | # The command to remove a file. 40 | RM = /usr/bin/cmake -E remove -f 41 | 42 | # Escaping for special characters. 43 | EQUALS = = 44 | 45 | # The top-level source directory on which CMake was run. 46 | CMAKE_SOURCE_DIR = /home/android/Project/hello_drv_test 47 | 48 | # The top-level build directory on which CMake was run. 49 | CMAKE_BINARY_DIR = /home/android/Project/hello_drv_test/build 50 | 51 | # Include any dependencies generated for this target. 52 | include CMakeFiles/hello_drv_test.dir/depend.make 53 | 54 | # Include the progress variables for this target. 55 | include CMakeFiles/hello_drv_test.dir/progress.make 56 | 57 | # Include the compile flags for this target's objects. 58 | include CMakeFiles/hello_drv_test.dir/flags.make 59 | 60 | CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o: CMakeFiles/hello_drv_test.dir/flags.make 61 | CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o: ../hello_drv_test.c 62 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/android/Project/hello_drv_test/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building C object CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o" 63 | /home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=x86_64-none-linux-android29 --gcc-toolchain=/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -o CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o -c /home/android/Project/hello_drv_test/hello_drv_test.c 64 | 65 | CMakeFiles/hello_drv_test.dir/hello_drv_test.c.i: cmake_force 66 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/hello_drv_test.dir/hello_drv_test.c.i" 67 | /home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=x86_64-none-linux-android29 --gcc-toolchain=/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -E /home/android/Project/hello_drv_test/hello_drv_test.c > CMakeFiles/hello_drv_test.dir/hello_drv_test.c.i 68 | 69 | CMakeFiles/hello_drv_test.dir/hello_drv_test.c.s: cmake_force 70 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/hello_drv_test.dir/hello_drv_test.c.s" 71 | /home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=x86_64-none-linux-android29 --gcc-toolchain=/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/home/android/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/sysroot $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -S /home/android/Project/hello_drv_test/hello_drv_test.c -o CMakeFiles/hello_drv_test.dir/hello_drv_test.c.s 72 | 73 | # Object files for target hello_drv_test 74 | hello_drv_test_OBJECTS = \ 75 | "CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o" 76 | 77 | # External object files for target hello_drv_test 78 | hello_drv_test_EXTERNAL_OBJECTS = 79 | 80 | hello_drv_test: CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o 81 | hello_drv_test: CMakeFiles/hello_drv_test.dir/build.make 82 | hello_drv_test: CMakeFiles/hello_drv_test.dir/link.txt 83 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/home/android/Project/hello_drv_test/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Linking C executable hello_drv_test" 84 | $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/hello_drv_test.dir/link.txt --verbose=$(VERBOSE) 85 | 86 | # Rule to build all files generated by this target. 87 | CMakeFiles/hello_drv_test.dir/build: hello_drv_test 88 | 89 | .PHONY : CMakeFiles/hello_drv_test.dir/build 90 | 91 | CMakeFiles/hello_drv_test.dir/clean: 92 | $(CMAKE_COMMAND) -P CMakeFiles/hello_drv_test.dir/cmake_clean.cmake 93 | .PHONY : CMakeFiles/hello_drv_test.dir/clean 94 | 95 | CMakeFiles/hello_drv_test.dir/depend: 96 | cd /home/android/Project/hello_drv_test/build && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/android/Project/hello_drv_test /home/android/Project/hello_drv_test /home/android/Project/hello_drv_test/build /home/android/Project/hello_drv_test/build /home/android/Project/hello_drv_test/build/CMakeFiles/hello_drv_test.dir/DependInfo.cmake --color=$(COLOR) 97 | .PHONY : CMakeFiles/hello_drv_test.dir/depend 98 | 99 | -------------------------------------------------------------------------------- /3.学穿Binder篇/013. Binder 程序示例之 Java 篇.md: -------------------------------------------------------------------------------- 1 | # Binder 程序示例之 java 篇 2 | 3 | 本文基于 `AOSP Android10 r41` 源码环境 4 | 5 | 本文示例程序可以在 https://github.com/yuandaimaahao/AndroidFrameworkTutorial/tree/main/3.Binder/src/BinderJavaDemo 下载到 6 | 7 | 本文给出一个简单的 binder java 示例程序,后文的分析会基于该示例程序: 8 | 9 | ## 1. 定义 aidl 协议文件 10 | 11 | 在 `device/jelly/rice14` 目录下创建 `BinderJavaDemo/com/yuandaima` 三个文件夹,然后在 `device/jelly/rice14/BinderJavaDemo/com/yuandaima` 目录下创建 IHelloService.aidl 12 | 13 | ```java 14 | //IHelloService.aidl 15 | package com.yuandaima; 16 | 17 | interface IHelloService 18 | { 19 | void sayhello(); 20 | int sayhello_to(String name); 21 | } 22 | ``` 23 | 24 | 将 aidl 编译为 java 文件: 25 | 26 | 在系统源码下: 27 | 28 | ```bash 29 | source build/envsetup.sh 30 | aidl IHelloService.aidl 31 | ``` 32 | 即可生成对应的 Java 文件 33 | 34 | 35 | ## 2. 实现 Hello 服务 36 | 37 | 在 `device/jelly/rice14/BinderJavaDemo/com/yuandaima` 目录下创建 `HelloService.java` 38 | 39 | ```java 40 | //HelloService.java 41 | package com.yuandaima; 42 | 43 | import android.util.Log; 44 | 45 | public class HelloService extends IHelloService.Stub { 46 | private static final String TAG = "HelloService"; 47 | private int cnt1 = 0; 48 | private int cnt2 = 0; 49 | 50 | public void sayhello() throws android.os.RemoteException { 51 | cnt1++; 52 | Log.i(TAG, "sayhello : cnt = "+cnt1); 53 | } 54 | 55 | public int sayhello_to(java.lang.String name) throws android.os.RemoteException { 56 | cnt2++; 57 | Log.i(TAG, "sayhello_to "+name+" : cnt = "+cnt2); 58 | return cnt2; 59 | } 60 | } 61 | ``` 62 | 63 | ## 3.实现服务端 64 | 65 | 在 `device/jelly/rice14/BinderJavaDemo/com/yuandaima` 目录下创建 `Server.java` 66 | 67 | ```java 68 | //Server.java 69 | package com.yuandaima; 70 | 71 | import android.util.Log; 72 | import android.os.ServiceManager; 73 | 74 | public class Server { 75 | 76 | private static final String TAG = "BinderServer"; 77 | 78 | public static void main(String args[]) { 79 | /* add Service */ 80 | Log.i(TAG, "add hello service"); 81 | ServiceManager.addService("hello", new HelloService()); 82 | 83 | //app_process 启动时,会启动 binder 线程用于获取和解析 binder 消息,应用程序无需关心 84 | while (true) { 85 | try { 86 | Thread.sleep(100); 87 | } catch (Exception e){} 88 | } 89 | } 90 | } 91 | ``` 92 | 93 | ## 4.实现客户端 94 | 95 | 在 `device/jelly/rice14/BinderJavaDemo/com/yuandaima` 目录下创建 `Client.java` 96 | 97 | ```java 98 | //Client.java 99 | package com.yuandaima; 100 | 101 | import android.util.Log; 102 | import android.os.ServiceManager; 103 | import android.os.IBinder; 104 | 105 | public class Client { 106 | 107 | private static final String TAG = "BinderClient"; 108 | 109 | public static void main(String args[]) 110 | { 111 | 112 | /* 1. getService */ 113 | IBinder binder = ServiceManager.getService("hello"); 114 | 115 | if (binder == null) 116 | { 117 | Log.i(TAG, "can not get hello service"); 118 | return; 119 | } 120 | 121 | IHelloService svr = IHelloService.Stub.asInterface(binder); 122 | 123 | try { 124 | svr.sayhello(); 125 | Log.i(TAG, "call sayhello"); 126 | } catch (Exception e) { 127 | 128 | } 129 | 130 | try { 131 | int cnt = svr.sayhello_to("hello"); 132 | 133 | Log.i(TAG, "call sayhello_to " + " : cnt = " + cnt); 134 | } catch (Exception e) { 135 | System.out.println("call sayhello_to , err :"+e); 136 | Log.i(TAG, "call sayhello_to , err : "+e); 137 | } 138 | } 139 | } 140 | ``` 141 | 142 | 143 | ## 5. 编译运行 144 | 145 | 编写 Android.bp 文件: 146 | 147 | ```json 148 | java_library { 149 | name: "BinderClient", 150 | installable: true, 151 | srcs: [ "Client.java", 152 | "HelloService.java", 153 | "IHelloService.java" ], 154 | } 155 | 156 | java_library { 157 | name: "BinderServer", 158 | installable: true, 159 | srcs: [ "Server.java", 160 | "HelloService.java", 161 | "IHelloService.java" ], 162 | } 163 | ``` 164 | 165 | 166 | 接着把 jar 包 push 到模拟器上并执行: 167 | 168 | ```bash 169 | # 将项目源码放到系统源码下 170 | # 在项目目录下执行 171 | mm 172 | # 将 jar 包 push 到虚拟机上 173 | cd out/target/product/generic_x86_64/system/framework 174 | adb push BinderClient.jar /data/local/tmp 175 | adb push BinderServer.jar /data/local/tmp 176 | 177 | # 执行 java 程序 178 | export CLASSPATH=/data/local/tmp/BinderClient.jar:/data/local/tmp/BinderServer.jar 179 | # 启动服务端 180 | app_process /data/local/tmp com.yuandaima.Server 181 | # 启动客户端 182 | app_process /data/local/tmp com.yuandaima.Client 183 | ``` 184 | 185 | 查看 log: 186 | 187 | ```bash 188 | logcat | grep "BinderServer" 189 | 190 | 02-15 12:20:20.493 4171 4171 I BinderServer: add hello service 191 | 192 | logcat | grep "BinderClient" 193 | 194 | 02-15 12:20:43.169 4183 4183 I BinderClient: call sayhello 195 | 02-15 12:20:43.169 4183 4183 I BinderClient: call sayhello_to : cnt = 1 196 | ``` 197 | 198 | ## 关于 199 | 200 | 我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研发工作。主要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术分享。 201 | 202 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 203 | 204 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/010.JNI 编程上手指南之从内存角度再看引用类型.md: -------------------------------------------------------------------------------- 1 | # JNI 编程上手指南之从内存角度再看引用类型 2 | 3 | ## 1. Java 程序使用的内存 4 | 5 | Java 程序使用的内存从逻辑上可以分为两个部分: 6 | 7 | * Java Memory 8 | * Native Memory 9 | 10 | Java Memory 就是我们的 Java 程序使用的内存,通常从逻辑上区分为栈和堆。方法中的局部变量通常存储在栈中,引用类型指向的对象一般存储在堆中。Java Memory 由 JVM 分配和管理,JVM 中通常会有一个 GC 线程,用于回收不再使用的内存。 11 | 12 | Java 程序的执行依托于 JVM ,JVM 一般使用 C/C++ 代码编写,需要根据 Native 编程规范去操作内存。如:C/C++ 使用 malloc()/new 分配内存,需要手动使用 free()/delete 回收内存。这部分内存我们称为 Native Memory。 13 | 14 | 15 | Java 中的对象对应的内存,由 JVM 来管理,他们都有自己的数据结构。当我们通过 JNI 将一个 Java 对象传递给 Native 程序时,Native 程序要操作这块内存时(即操作这个对象),就需要了解这个数据结构,显然这有点麻烦了,所以 JVM 的设计者在 JNIenv 中定义了很多函数(NewStringUTF,FindClass,NewObject 等)来帮你操作和构造这些对象。同时也提供了引用类型(jobject、jstring、jclass、jarray、jintArray等)来引用这些对象。 16 | 17 | 18 | ## 2. 内存角度的 JNI 引用类型 19 | 20 | 之前我们介绍了,JNI 引用类型有三种:Local Reference、Global Reference、Weak Global Reference。接下来我们就从内存的角度来进一步解析这三类引用。 21 | 22 | 首先,我们需要明确的是引用类型是指针,指向的是 **Java 中的对象在 JVM 中对应的内存**。引用类型的定义如下: 23 | 24 | ```cpp 25 | #ifdef __cplusplus 26 | 27 | class _jobject {}; 28 | class _jclass : public _jobject {}; 29 | class _jthrowable : public _jobject {}; 30 | class _jstring : public _jobject {}; 31 | class _jarray : public _jobject {}; 32 | class _jbooleanArray : public _jarray {}; 33 | class _jbyteArray : public _jarray {}; 34 | class _jcharArray : public _jarray {}; 35 | class _jshortArray : public _jarray {}; 36 | class _jintArray : public _jarray {}; 37 | class _jlongArray : public _jarray {}; 38 | class _jfloatArray : public _jarray {}; 39 | class _jdoubleArray : public _jarray {}; 40 | class _jobjectArray : public _jarray {}; 41 | 42 | typedef _jobject *jobject; 43 | typedef _jclass *jclass; 44 | typedef _jthrowable *jthrowable; 45 | typedef _jstring *jstring; 46 | typedef _jarray *jarray; 47 | typedef _jbooleanArray *jbooleanArray; 48 | typedef _jbyteArray *jbyteArray; 49 | typedef _jcharArray *jcharArray; 50 | typedef _jshortArray *jshortArray; 51 | typedef _jintArray *jintArray; 52 | typedef _jlongArray *jlongArray; 53 | typedef _jfloatArray *jfloatArray; 54 | typedef _jdoubleArray *jdoubleArray; 55 | typedef _jobjectArray *jobjectArray; 56 | 57 | #else 58 | 59 | struct _jobject; 60 | 61 | typedef struct _jobject *jobject; 62 | typedef jobject jclass; 63 | typedef jobject jthrowable; 64 | typedef jobject jstring; 65 | typedef jobject jarray; 66 | typedef jarray jbooleanArray; 67 | typedef jarray jbyteArray; 68 | typedef jarray jcharArray; 69 | typedef jarray jshortArray; 70 | typedef jarray jintArray; 71 | typedef jarray jlongArray; 72 | typedef jarray jfloatArray; 73 | typedef jarray jdoubleArray; 74 | typedef jarray jobjectArray; 75 | 76 | #endif 77 | ``` 78 | 79 | 不是以上类型的指针就不是 JNI 引用类型,比如容易混淆的 jmethod jfield 都不是 JNI 引用类型。 80 | 81 | JNI 引用类型是指针,但是和 C/C++ 中的普通指针不同,C/C++ 中的指针需要我们自己分配和回收内存(C/C++ 使用 malloc()/new 分配内存,需要手动使用 free()/delete 回收内存)。JNI 引用不需要我们分配和回收内存,这部分工作由 JVM 完成。我们额外需要做的工作是在 JNI 引用类型使用完后,将其从引用表中删除,防止引用表满了。 82 | 83 | 接下来我们就从内存角度分类解析三种类型引用类型。 84 | 85 | ### 2.1 局部引用(Local Reference) 86 | 87 | 通过 JNI 接口从 Java 传递下来或者通过 NewLocalRef 和各种 JNI 接口(FindClass、NewObject、GetObjectClass和NewCharArray等)创建的引用称为局部引用。 88 | 89 | 当从 Java 环境切换到 Native 环境时,JVM 分配一块内存用于创建一个 Local Reference Table,这个 Table 用来存放本次 Native Method 执行中创建的所有局部引用(Local Reference)。每当在 Native 代码中引用到一个 Java 对象时,JVM 就会在这个 Table 中创建一个 Local Reference。比如,我们调用 NewStringUTF() 在 Java Heap 中创建一个 String 对象后,在 Local Reference Table 中就会相应新增一个 Local Reference。 90 | 91 | 对于开发者来说,Local Reference Table 是不可见的,Local Reference Table 的内存不大,所能存放的 Local Reference 数量也是有限的(在 Android 中默认最大容量是512个)。在开发中应该及时使用 DeleteLocalRef( )删除不必要的 Local Reference,不然可能会出现溢出错误。 92 | 93 | 很多人会误将 JNI 中的 Local Reference 理解为 Native Code 的局部变量。这是错误的: 94 | 95 | * 局部变量存储在线程堆栈中,而 Local Reference 存储在 Local Ref 表中。 96 | * 局部变量在函数退栈后被删除,而 Local Reference 在调用 DeleteLocalRef() 后才会从 Local Ref 表中删除,并且失效,或者在整个 Native Method 执行结束后被删除。 97 | * 可以在代码中直接访问局部变量,而 Local Reference 的内容无法在代码中直接访问,必须通过 JNI function 间接访问。JNI function 实现了对 Local Reference 的间接访问,JNI function 的内部实现依赖于具体 JVM。 98 | 99 | 100 | ### 2.2 全局引用(Global Reference) 101 | 102 | Global Reference 是通过 JNI 函数 NewGlobalRef() 和D eleteGlobalRef() 来创建和删除的。 Global Reference 具有全局性,可以在多个 Native Method 调用过程和多线程中使用。 103 | 104 | 使用 Global reference时,当 native code 不再需要访问 Global reference 时,应当调用 JNI 函数 DeleteGlobalRef() 删除 Global reference 和它引用的 Java 对象。否则 Global Reference 引用的 Java 对象将永远停留在 Java Heap 中,从而导致 Java Heap 的内存泄漏。 105 | 106 | ### 2.3 弱全局引用(Weak Global Reference) 107 | 108 | 弱全局引用使用 NewWeakGlobalRef() 和 DeleteWeakGlobalRef() 进行创建和删除,它与 Global Reference 的区别在于该类型的引用随时都可能被 GC 回收。对于 Weak Global Reference 而言,可以通过 isSameObject() 将其与 NULL 比较,看看是否已经被回收了。如果返回 JNI_TRUE,则表示已经被回收了,需要重新初始化弱全局引用。Weak Global Reference 的回收时机是不确定的,有可能在前一行代码判断它是可用的,后一行代码就被 GC 回收掉了。为了避免这事事情发生,JNI官方给出了正确的做法,通过 NewLocalRef() 获取 Weak Global Reference,避免被GC回收。 109 | 110 | 111 | ## 参考资料 112 | 113 | * https://developer.aliyun.com/article/1112357 114 | * https://stackoverflow.com/questions/2093112/why-i-should-not-reuse-a-jclass-and-or-jmethodid-in-jni 115 | * https://stackoverflow.com/questions/51760630/can-i-delete-jmethodid-and-jfieldid-safely 116 | * https://stackoverflow.com/questions/11027822/newglobalref-for-jmethodid 117 | * https://stackoverflow.com/questions/2093112/why-i-should-not-reuse-a-jclass-and-or-jmethodid-in-jni?rq=3 118 | 119 | # 关于 120 | 121 | 我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研发工作。主要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术分享。 122 | 123 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 124 | 125 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/datastructuretest/data_structure_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | //定义链表节点 7 | struct list_node_student { 8 | char *name; 9 | int age; 10 | int score; 11 | struct list_head list; 12 | }; 13 | 14 | //定义红黑树节点类型 15 | struct my_tree_node { 16 | int data; 17 | struct rb_node node; 18 | }; 19 | 20 | //内核中没有提供现成的插入,查找函数,需要使用者自己实现 21 | int rb_insert(struct rb_root *root, struct my_tree_node *insert_node) { 22 | struct rb_node **n = &(root->rb_node); 23 | struct rb_node *parent = NULL; 24 | while (*n) { 25 | struct my_tree_node *thiz = container_of(*n, struct my_tree_node, node); 26 | parent = *n; 27 | if (thiz->data > insert_node->data) { 28 | n = &((*n)->rb_left); 29 | } else if (thiz->data < insert_node->data) { 30 | n = &((*n)->rb_right); 31 | } else { 32 | return -1; 33 | } 34 | } 35 | 36 | rb_link_node(&insert_node->node, parent, n); 37 | rb_insert_color(&insert_node->node, root); 38 | } 39 | 40 | struct my_tree_node *rb_search(struct rb_root *root, int new) { 41 | struct rb_node *node = root->rb_node; 42 | while (node) { 43 | struct my_tree_node *my_node = container_of(node, struct my_tree_node, node); 44 | 45 | if (my_node->data > new) { 46 | node = node->rb_left; 47 | } else if (my_node->data < new) { 48 | node = node->rb_right; 49 | } else { 50 | return my_node; 51 | } 52 | } 53 | 54 | return NULL; 55 | } 56 | 57 | static int __init ds_init(void) { 58 | //printk 是内核中的日志打印函数 59 | printk("data structure test init!\n"); 60 | 61 | //定义并初始化链表头 62 | LIST_HEAD(header); 63 | 64 | //定义并初始化一个节点 65 | struct list_node_student jack = { 66 | .name = "jack", 67 | .age = 18, 68 | .score = 99, 69 | .list = LIST_HEAD_INIT(jack.list) 70 | }; 71 | 72 | //链表插入节点,加入链表头 73 | list_add(&jack.list, &header); 74 | 75 | //定义并初始化第二个节点 76 | struct list_node_student bob = { 77 | .name = "bob", 78 | .age = 19, 79 | .score = 99, 80 | .list = LIST_HEAD_INIT(bob.list) 81 | }; 82 | 83 | //链表插入节点,加入链表尾 84 | list_add_tail(&bob.list, &header); 85 | 86 | //删除节点 87 | list_del(&bob.list); 88 | 89 | //链表遍历 90 | //list_head 遍历 91 | struct list_head *pos; 92 | list_for_each(pos, &header) { 93 | 94 | } 95 | 96 | list_for_each_prev(pos, &header) { 97 | 98 | } 99 | 100 | //宿主结构的遍历 101 | struct list_node_student *student; 102 | list_for_each_entry(student, &header, list) { 103 | 104 | } 105 | 106 | //hlist 的基本使用 107 | 108 | //定义宿主结构体 109 | struct hdata_node { 110 | int data; 111 | struct hlist_node list; 112 | }; 113 | 114 | //hash 数组 115 | struct hlist_head htable[256]; 116 | 117 | struct hdata_node *hnode; 118 | 119 | //初始化 120 | for (int i = 0; i < 256; ++i) { 121 | INIT_HLIST_HEAD(&htable[i]); 122 | hnode = kmalloc(sizeof(struct hdata_node), GFP_KERNEL); 123 | INIT_HLIST_NODE(&(hnode->list)); 124 | hnode->data = i * 9; 125 | //链表中插入数据 126 | //自定义 hash 算法,这里简单取余 127 | int key = hnode->data % 256; 128 | //添加到链表首部 129 | hlist_add_head(&hnode->list, &htable[key]); 130 | } 131 | 132 | //查询 133 | int search = 67 * 9; 134 | int key = search % 256; 135 | 136 | if (hlist_empty(&htable[key])) { 137 | //没有需要查询的项 138 | } else { 139 | //遍历查询 140 | hlist_for_each_entry(hnode, &htable[key], list) { 141 | if (hnode->data == search) { 142 | //找到了 143 | break; 144 | } 145 | } 146 | } 147 | 148 | //删除 149 | int delete = 88 * 9; 150 | int key2 = search % 256; 151 | struct hlist_node *n; 152 | 153 | if (hlist_empty(&htable[key])) { 154 | //没有需要查询的项 155 | } else { 156 | //遍历查询 157 | hlist_for_each_entry_safe(hnode, n, &htable[key], list) { 158 | if (hnode->data == search) { 159 | //找到了 160 | hlist_del(hnode); 161 | break; 162 | } 163 | } 164 | } 165 | 166 | //退出程序前释放资源 167 | for (i = 0; i < 256; i++) { 168 | //遍历每一个槽,有结点就删除 169 | hlist_for_each_entry_safe(hnode, n, &htable[i], list) { 170 | hlist_del(&hnode->list); 171 | kfree(hnode); 172 | hnode = NULL; 173 | } 174 | } 175 | 176 | struct my_tree_node *data; 177 | struct rb_node *node; 178 | 179 | struct rb_root mytree = RB_ROOT; 180 | 181 | //插入元素 182 | for (int j = 0; j < 10; ++j) { 183 | data = kmalloc(sizeof(struct my_tree_node), GFP_KERNEL); 184 | data->data = i * 36; 185 | rb_insert(&mytree, data); 186 | } 187 | 188 | //遍历红黑树 189 | for(node = rb_first(&mytree); node; node = rb_next(node)) { 190 | printk("key=%d\n", rb_entry(node, struct my_tree_node, node)->data); 191 | } 192 | 193 | //红黑树内存清理 194 | for(node = rb_first(&mytree); node; node = rb_next(node)) { 195 | data = rb_entry(node, struct my_tree_node, node); 196 | if (data) { 197 | rb_erase(&data->node, &mytree); 198 | kfree(data); 199 | } 200 | } 201 | 202 | return 0; 203 | } 204 | 205 | 206 | 207 | static void __exit ds_exit(void) { 208 | printk("data structure test exit\n"); 209 | } 210 | 211 | 212 | module_init(ds_init); 213 | module_exit(ds_exit); 214 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/BinderJavaDemo/com/yuandaima/IHelloService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is auto-generated. DO NOT MODIFY. 3 | */ 4 | package com.yuandaima; 5 | public interface IHelloService extends android.os.IInterface 6 | { 7 | /** Default implementation for IHelloService. */ 8 | public static class Default implements com.yuandaima.IHelloService 9 | { 10 | @Override public void sayhello() throws android.os.RemoteException 11 | { 12 | } 13 | @Override public int sayhello_to(java.lang.String name) throws android.os.RemoteException 14 | { 15 | return 0; 16 | } 17 | @Override 18 | public android.os.IBinder asBinder() { 19 | return null; 20 | } 21 | } 22 | /** Local-side IPC implementation stub class. */ 23 | public static abstract class Stub extends android.os.Binder implements com.yuandaima.IHelloService 24 | { 25 | private static final java.lang.String DESCRIPTOR = "com.yuandaima.IHelloService"; 26 | /** Construct the stub at attach it to the interface. */ 27 | public Stub() 28 | { 29 | this.attachInterface(this, DESCRIPTOR); 30 | } 31 | /** 32 | * Cast an IBinder object into an com.yuandaima.IHelloService interface, 33 | * generating a proxy if needed. 34 | */ 35 | public static com.yuandaima.IHelloService asInterface(android.os.IBinder obj) 36 | { 37 | if ((obj==null)) { 38 | return null; 39 | } 40 | android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 41 | if (((iin!=null)&&(iin instanceof com.yuandaima.IHelloService))) { 42 | return ((com.yuandaima.IHelloService)iin); 43 | } 44 | return new com.yuandaima.IHelloService.Stub.Proxy(obj); 45 | } 46 | @Override public android.os.IBinder asBinder() 47 | { 48 | return this; 49 | } 50 | @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException 51 | { 52 | java.lang.String descriptor = DESCRIPTOR; 53 | switch (code) 54 | { 55 | case INTERFACE_TRANSACTION: 56 | { 57 | reply.writeString(descriptor); 58 | return true; 59 | } 60 | case TRANSACTION_sayhello: 61 | { 62 | data.enforceInterface(descriptor); 63 | this.sayhello(); 64 | reply.writeNoException(); 65 | return true; 66 | } 67 | case TRANSACTION_sayhello_to: 68 | { 69 | data.enforceInterface(descriptor); 70 | java.lang.String _arg0; 71 | _arg0 = data.readString(); 72 | int _result = this.sayhello_to(_arg0); 73 | reply.writeNoException(); 74 | reply.writeInt(_result); 75 | return true; 76 | } 77 | default: 78 | { 79 | return super.onTransact(code, data, reply, flags); 80 | } 81 | } 82 | } 83 | private static class Proxy implements com.yuandaima.IHelloService 84 | { 85 | private android.os.IBinder mRemote; 86 | Proxy(android.os.IBinder remote) 87 | { 88 | mRemote = remote; 89 | } 90 | @Override public android.os.IBinder asBinder() 91 | { 92 | return mRemote; 93 | } 94 | public java.lang.String getInterfaceDescriptor() 95 | { 96 | return DESCRIPTOR; 97 | } 98 | @Override public void sayhello() throws android.os.RemoteException 99 | { 100 | android.os.Parcel _data = android.os.Parcel.obtain(); 101 | android.os.Parcel _reply = android.os.Parcel.obtain(); 102 | try { 103 | _data.writeInterfaceToken(DESCRIPTOR); 104 | boolean _status = mRemote.transact(Stub.TRANSACTION_sayhello, _data, _reply, 0); 105 | if (!_status && getDefaultImpl() != null) { 106 | getDefaultImpl().sayhello(); 107 | return; 108 | } 109 | _reply.readException(); 110 | } 111 | finally { 112 | _reply.recycle(); 113 | _data.recycle(); 114 | } 115 | } 116 | @Override public int sayhello_to(java.lang.String name) throws android.os.RemoteException 117 | { 118 | android.os.Parcel _data = android.os.Parcel.obtain(); 119 | android.os.Parcel _reply = android.os.Parcel.obtain(); 120 | int _result; 121 | try { 122 | _data.writeInterfaceToken(DESCRIPTOR); 123 | _data.writeString(name); 124 | boolean _status = mRemote.transact(Stub.TRANSACTION_sayhello_to, _data, _reply, 0); 125 | if (!_status && getDefaultImpl() != null) { 126 | return getDefaultImpl().sayhello_to(name); 127 | } 128 | _reply.readException(); 129 | _result = _reply.readInt(); 130 | } 131 | finally { 132 | _reply.recycle(); 133 | _data.recycle(); 134 | } 135 | return _result; 136 | } 137 | public static com.yuandaima.IHelloService sDefaultImpl; 138 | } 139 | static final int TRANSACTION_sayhello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 140 | static final int TRANSACTION_sayhello_to = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); 141 | public static boolean setDefaultImpl(com.yuandaima.IHelloService impl) { 142 | if (Stub.Proxy.sDefaultImpl == null && impl != null) { 143 | Stub.Proxy.sDefaultImpl = impl; 144 | return true; 145 | } 146 | return false; 147 | } 148 | public static com.yuandaima.IHelloService getDefaultImpl() { 149 | return Stub.Proxy.sDefaultImpl; 150 | } 151 | } 152 | public void sayhello() throws android.os.RemoteException; 153 | public int sayhello_to(java.lang.String name) throws android.os.RemoteException; 154 | } 155 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/hello_drv_test/build/Makefile: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.16 3 | 4 | # Default target executed when no arguments are given to make. 5 | default_target: all 6 | 7 | .PHONY : default_target 8 | 9 | # Allow only one "make -f Makefile2" at a time, but pass parallelism. 10 | .NOTPARALLEL: 11 | 12 | 13 | #============================================================================= 14 | # Special targets provided by cmake. 15 | 16 | # Disable implicit rules so canonical targets will work. 17 | .SUFFIXES: 18 | 19 | 20 | # Remove some rules from gmake that .SUFFIXES does not remove. 21 | SUFFIXES = 22 | 23 | .SUFFIXES: .hpux_make_needs_suffix_list 24 | 25 | 26 | # Suppress display of executed commands. 27 | $(VERBOSE).SILENT: 28 | 29 | 30 | # A target that is always out of date. 31 | cmake_force: 32 | 33 | .PHONY : cmake_force 34 | 35 | #============================================================================= 36 | # Set environment variables for the build. 37 | 38 | # The shell in which to execute make rules. 39 | SHELL = /bin/sh 40 | 41 | # The CMake executable. 42 | CMAKE_COMMAND = /usr/bin/cmake 43 | 44 | # The command to remove a file. 45 | RM = /usr/bin/cmake -E remove -f 46 | 47 | # Escaping for special characters. 48 | EQUALS = = 49 | 50 | # The top-level source directory on which CMake was run. 51 | CMAKE_SOURCE_DIR = /home/android/Project/hello_drv_test 52 | 53 | # The top-level build directory on which CMake was run. 54 | CMAKE_BINARY_DIR = /home/android/Project/hello_drv_test/build 55 | 56 | #============================================================================= 57 | # Targets provided globally by CMake. 58 | 59 | # Special rule for the target rebuild_cache 60 | rebuild_cache: 61 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." 62 | /usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) 63 | .PHONY : rebuild_cache 64 | 65 | # Special rule for the target rebuild_cache 66 | rebuild_cache/fast: rebuild_cache 67 | 68 | .PHONY : rebuild_cache/fast 69 | 70 | # Special rule for the target edit_cache 71 | edit_cache: 72 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." 73 | /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. 74 | .PHONY : edit_cache 75 | 76 | # Special rule for the target edit_cache 77 | edit_cache/fast: edit_cache 78 | 79 | .PHONY : edit_cache/fast 80 | 81 | # The main all target 82 | all: cmake_check_build_system 83 | $(CMAKE_COMMAND) -E cmake_progress_start /home/android/Project/hello_drv_test/build/CMakeFiles /home/android/Project/hello_drv_test/build/CMakeFiles/progress.marks 84 | $(MAKE) -f CMakeFiles/Makefile2 all 85 | $(CMAKE_COMMAND) -E cmake_progress_start /home/android/Project/hello_drv_test/build/CMakeFiles 0 86 | .PHONY : all 87 | 88 | # The main clean target 89 | clean: 90 | $(MAKE) -f CMakeFiles/Makefile2 clean 91 | .PHONY : clean 92 | 93 | # The main clean target 94 | clean/fast: clean 95 | 96 | .PHONY : clean/fast 97 | 98 | # Prepare targets for installation. 99 | preinstall: all 100 | $(MAKE) -f CMakeFiles/Makefile2 preinstall 101 | .PHONY : preinstall 102 | 103 | # Prepare targets for installation. 104 | preinstall/fast: 105 | $(MAKE) -f CMakeFiles/Makefile2 preinstall 106 | .PHONY : preinstall/fast 107 | 108 | # clear depends 109 | depend: 110 | $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 111 | .PHONY : depend 112 | 113 | #============================================================================= 114 | # Target rules for targets named hello_drv_test 115 | 116 | # Build rule for target. 117 | hello_drv_test: cmake_check_build_system 118 | $(MAKE) -f CMakeFiles/Makefile2 hello_drv_test 119 | .PHONY : hello_drv_test 120 | 121 | # fast build rule for target. 122 | hello_drv_test/fast: 123 | $(MAKE) -f CMakeFiles/hello_drv_test.dir/build.make CMakeFiles/hello_drv_test.dir/build 124 | .PHONY : hello_drv_test/fast 125 | 126 | hello_drv_test.o: hello_drv_test.c.o 127 | 128 | .PHONY : hello_drv_test.o 129 | 130 | # target to build an object file 131 | hello_drv_test.c.o: 132 | $(MAKE) -f CMakeFiles/hello_drv_test.dir/build.make CMakeFiles/hello_drv_test.dir/hello_drv_test.c.o 133 | .PHONY : hello_drv_test.c.o 134 | 135 | hello_drv_test.i: hello_drv_test.c.i 136 | 137 | .PHONY : hello_drv_test.i 138 | 139 | # target to preprocess a source file 140 | hello_drv_test.c.i: 141 | $(MAKE) -f CMakeFiles/hello_drv_test.dir/build.make CMakeFiles/hello_drv_test.dir/hello_drv_test.c.i 142 | .PHONY : hello_drv_test.c.i 143 | 144 | hello_drv_test.s: hello_drv_test.c.s 145 | 146 | .PHONY : hello_drv_test.s 147 | 148 | # target to generate assembly for a file 149 | hello_drv_test.c.s: 150 | $(MAKE) -f CMakeFiles/hello_drv_test.dir/build.make CMakeFiles/hello_drv_test.dir/hello_drv_test.c.s 151 | .PHONY : hello_drv_test.c.s 152 | 153 | # Help Target 154 | help: 155 | @echo "The following are some of the valid targets for this Makefile:" 156 | @echo "... all (the default if no target is provided)" 157 | @echo "... clean" 158 | @echo "... depend" 159 | @echo "... rebuild_cache" 160 | @echo "... edit_cache" 161 | @echo "... hello_drv_test" 162 | @echo "... hello_drv_test.o" 163 | @echo "... hello_drv_test.i" 164 | @echo "... hello_drv_test.s" 165 | .PHONY : help 166 | 167 | 168 | 169 | #============================================================================= 170 | # Special targets to cleanup operation of make. 171 | 172 | # Special rule to run CMake to check the build system integrity. 173 | # No rule that depends on this can have commands that come from listfiles 174 | # because they might be regenerated. 175 | cmake_check_build_system: 176 | $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 177 | .PHONY : cmake_check_build_system 178 | 179 | -------------------------------------------------------------------------------- /3.学穿Binder篇/源码/AIDLCppDemo/IHello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace com { 5 | 6 | namespace yuandaima { 7 | 8 | IMPLEMENT_META_INTERFACE(Hello, "com.yuandaima.IHello") 9 | 10 | ::android::IBinder* IHelloDefault::onAsBinder() { 11 | return nullptr; 12 | } 13 | 14 | ::android::binder::Status IHelloDefault::hello() { 15 | return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); 16 | } 17 | 18 | ::android::binder::Status IHelloDefault::sum(int32_t, int32_t, int32_t* ) { 19 | return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); 20 | } 21 | 22 | } // namespace yuandaima 23 | 24 | } // namespace com 25 | #include 26 | #include 27 | #include 28 | 29 | namespace com { 30 | 31 | namespace yuandaima { 32 | 33 | BpHello::BpHello(const ::android::sp<::android::IBinder>& _aidl_impl) 34 | : BpInterface(_aidl_impl){ 35 | } 36 | 37 | ::android::binder::Status BpHello::hello() { 38 | ::android::Parcel _aidl_data; 39 | ::android::Parcel _aidl_reply; 40 | ::android::status_t _aidl_ret_status = ::android::OK; 41 | ::android::binder::Status _aidl_status; 42 | _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); 43 | if (((_aidl_ret_status) != (::android::OK))) { 44 | goto _aidl_error; 45 | } 46 | _aidl_ret_status = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* hello */, _aidl_data, &_aidl_reply); 47 | if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IHello::getDefaultImpl())) { 48 | return IHello::getDefaultImpl()->hello(); 49 | } 50 | if (((_aidl_ret_status) != (::android::OK))) { 51 | goto _aidl_error; 52 | } 53 | _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); 54 | if (((_aidl_ret_status) != (::android::OK))) { 55 | goto _aidl_error; 56 | } 57 | if (!_aidl_status.isOk()) { 58 | return _aidl_status; 59 | } 60 | _aidl_error: 61 | _aidl_status.setFromStatusT(_aidl_ret_status); 62 | return _aidl_status; 63 | } 64 | 65 | ::android::binder::Status BpHello::sum(int32_t x, int32_t y, int32_t* _aidl_return) { 66 | ::android::Parcel _aidl_data; 67 | ::android::Parcel _aidl_reply; 68 | ::android::status_t _aidl_ret_status = ::android::OK; 69 | ::android::binder::Status _aidl_status; 70 | _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); 71 | if (((_aidl_ret_status) != (::android::OK))) { 72 | goto _aidl_error; 73 | } 74 | _aidl_ret_status = _aidl_data.writeInt32(x); 75 | if (((_aidl_ret_status) != (::android::OK))) { 76 | goto _aidl_error; 77 | } 78 | _aidl_ret_status = _aidl_data.writeInt32(y); 79 | if (((_aidl_ret_status) != (::android::OK))) { 80 | goto _aidl_error; 81 | } 82 | _aidl_ret_status = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* sum */, _aidl_data, &_aidl_reply); 83 | if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IHello::getDefaultImpl())) { 84 | return IHello::getDefaultImpl()->sum(x, y, _aidl_return); 85 | } 86 | if (((_aidl_ret_status) != (::android::OK))) { 87 | goto _aidl_error; 88 | } 89 | _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); 90 | if (((_aidl_ret_status) != (::android::OK))) { 91 | goto _aidl_error; 92 | } 93 | if (!_aidl_status.isOk()) { 94 | return _aidl_status; 95 | } 96 | _aidl_ret_status = _aidl_reply.readInt32(_aidl_return); 97 | if (((_aidl_ret_status) != (::android::OK))) { 98 | goto _aidl_error; 99 | } 100 | _aidl_error: 101 | _aidl_status.setFromStatusT(_aidl_ret_status); 102 | return _aidl_status; 103 | } 104 | 105 | } // namespace yuandaima 106 | 107 | } // namespace com 108 | #include 109 | #include 110 | 111 | namespace com { 112 | 113 | namespace yuandaima { 114 | 115 | ::android::status_t BnHello::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) { 116 | ::android::status_t _aidl_ret_status = ::android::OK; 117 | switch (_aidl_code) { 118 | case ::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* hello */: 119 | { 120 | if (!(_aidl_data.checkInterface(this))) { 121 | _aidl_ret_status = ::android::BAD_TYPE; 122 | break; 123 | } 124 | ::android::binder::Status _aidl_status(hello()); 125 | _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); 126 | if (((_aidl_ret_status) != (::android::OK))) { 127 | break; 128 | } 129 | if (!_aidl_status.isOk()) { 130 | break; 131 | } 132 | } 133 | break; 134 | case ::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* sum */: 135 | { 136 | int32_t in_x; 137 | int32_t in_y; 138 | int32_t _aidl_return; 139 | if (!(_aidl_data.checkInterface(this))) { 140 | _aidl_ret_status = ::android::BAD_TYPE; 141 | break; 142 | } 143 | _aidl_ret_status = _aidl_data.readInt32(&in_x); 144 | if (((_aidl_ret_status) != (::android::OK))) { 145 | break; 146 | } 147 | _aidl_ret_status = _aidl_data.readInt32(&in_y); 148 | if (((_aidl_ret_status) != (::android::OK))) { 149 | break; 150 | } 151 | ::android::binder::Status _aidl_status(sum(in_x, in_y, &_aidl_return)); 152 | _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); 153 | if (((_aidl_ret_status) != (::android::OK))) { 154 | break; 155 | } 156 | if (!_aidl_status.isOk()) { 157 | break; 158 | } 159 | _aidl_ret_status = _aidl_reply->writeInt32(_aidl_return); 160 | if (((_aidl_ret_status) != (::android::OK))) { 161 | break; 162 | } 163 | } 164 | break; 165 | default: 166 | { 167 | _aidl_ret_status = ::android::BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags); 168 | } 169 | break; 170 | } 171 | if (_aidl_ret_status == ::android::UNEXPECTED_NULL) { 172 | _aidl_ret_status = ::android::binder::Status::fromExceptionCode(::android::binder::Status::EX_NULL_POINTER).writeToParcel(_aidl_reply); 173 | } 174 | return _aidl_ret_status; 175 | } 176 | 177 | } // namespace yuandaima 178 | 179 | } // namespace com 180 | -------------------------------------------------------------------------------- /1.基础篇/JNI 编程上手指南/008.JNI 编程上手指南之 Native 访问 Java.md: -------------------------------------------------------------------------------- 1 | # JNI 编程上手指南之 Native 访问 Java 2 | 3 | 本文接着介绍如何在 C/C++ 中访问 Java,主要从以下几个方面来讲述: 4 | 5 | * 访问 Java 的成员变量,包括了实例成员和静态成员 6 | * 访问 Java 的方法,包括了成员方法和静态方法 7 | 8 | 9 | ## 1. Native 访问 Java 成员变量 10 | 11 | 我们直接看 Demo: 12 | 13 | Java 层: 14 | 15 | ```Java 16 | //定义一个被访问的类 17 | public class TestJavaClass { 18 | 19 | private String mString = "Hello JNI, this is normal string !"; 20 | 21 | private static int mStaticInt = 0; 22 | } 23 | 24 | //定义两个 native 方法 25 | public native void accessJavaFiled(TestJavaClass testJavaClass); 26 | public native void accessStaticField(TestJavaClass testJavaClass); 27 | ``` 28 | 29 | c++ 层: 30 | 31 | ```c++ 32 | //访问成员变量 33 | extern "C" 34 | JNIEXPORT void JNICALL 35 | Java_com_yuandaima_myjnidemo_MainActivity_accessJavaFiled(JNIEnv *env, jobject thiz, 36 | jobject test_java_class) { 37 | jclass clazz; 38 | jfieldID mString_fieldID; 39 | 40 | //获得 TestJavaClass 的 jclass 对象 41 | // jclass 类型是一个局部引用 42 | clazz = env->GetObjectClass(test_java_class); 43 | 44 | if (clazz == NULL) { 45 | return; 46 | } 47 | 48 | //获得 mString 的 fieldID 49 | mString_fieldID = env->GetFieldID(clazz, "mString", "Ljava/lang/String;"); 50 | if (mString_fieldID == NULL) { 51 | return; 52 | } 53 | 54 | //获得 mString 的值 55 | jstring j_string = (jstring) env->GetObjectField(test_java_class, mString_fieldID); 56 | //GetStringUTFChars 分配了内存,需要使用 ReleaseStringUTFChars 释放 57 | const char *buf = env->GetStringUTFChars(j_string, NULL); 58 | 59 | //修改 mString 的值 60 | char *buf_out = "Hello Java, I am JNI!"; 61 | jstring temp = env->NewStringUTF(buf_out); 62 | env->SetObjectField(test_java_class, mString_fieldID, temp); 63 | 64 | //jfieldID 不是 JNI 引用类型,不用 DeleteLocalRef 65 | // jfieldID 是一个指针类型,其内存的分配与回收由 JVM 负责,不需要我们去 free 66 | //free(mString_fieldID); 67 | 68 | //释放内存 69 | env->ReleaseStringUTFChars(j_string, buf); 70 | //释放局部引用表 71 | env->DeleteLocalRef(j_string); 72 | env->DeleteLocalRef(clazz); 73 | 74 | } 75 | 76 | //访问静态成员变量 77 | extern "C" 78 | JNIEXPORT void JNICALL 79 | Java_com_yuandaima_myjnidemo_MainActivity_accessStaticField(JNIEnv *env, jobject thiz, 80 | jobject test_java_class) { 81 | jclass clazz; 82 | jfieldID mStaticIntFiledID; 83 | 84 | clazz = env->GetObjectClass(test_java_class); 85 | 86 | if (clazz == NULL) { 87 | return; 88 | } 89 | 90 | mStaticIntFiledID = env->GetStaticFieldID(clazz, "mStaticInt", "I"); 91 | 92 | //获取静态成员 93 | jint mInt = env->GetStaticIntField(clazz, mStaticIntFiledID); 94 | //修改静态成员 95 | env->SetStaticIntField(clazz, mStaticIntFiledID, 10086); 96 | 97 | env->DeleteLocalRef(clazz); 98 | 99 | } 100 | ``` 101 | 102 | 访问一个类成员基本分为三部: 103 | 104 | * 获取到类对应的 jclass 对象(对应于 Java 层的 Class 对象),jclss 是一个局部引用,使用完后记得使用 DeleteLocalRef 以避免局部引用表溢出。 105 | * 获取到需要访问的类成员的 jfieldID,jfieldID 不是一个 JNI 引用类型,是一个普通指针,指针指向的内存又 JVM 管理,我们无需在使用完后执行 free 清理操作 106 | * 根据被访问对象的类型,使用 GetxxxField 和 SetxxxField 来获得/设置成员变量的值 107 | 108 | 109 | ## 2. Native 访问 Java 方法 110 | 111 | 我们直接看 Demo: 112 | 113 | Java 层 114 | 115 | ```java 116 | //等待被 native 层访问的 java 类 117 | public class TestJavaClass { 118 | 119 | //...... 120 | private void myMethod() { 121 | Log.i("JNI", "this is java myMethod"); 122 | } 123 | 124 | private static void myStaticMethod() { 125 | Log.d("JNI", "this is Java myStaticMethod"); 126 | } 127 | 128 | } 129 | 130 | //本地方法 131 | public native void accessJavaMethod(); 132 | 133 | public native void accessStaticMethod(); 134 | ``` 135 | 136 | C++ 层: 137 | 138 | ```c++ 139 | extern "C" 140 | JNIEXPORT void JNICALL 141 | Java_com_yuandaima_myjnidemo_MainActivity_accessJavaMethod(JNIEnv *env, jobject thiz) { 142 | 143 | //获取 TestJavaClass 对应的 jclass 144 | jclass clazz = env->FindClass("com/yuandaima/myjnidemo/TestJavaClass"); 145 | if (clazz == NULL) { 146 | return; 147 | } 148 | 149 | //构造函数 id 150 | jmethodID java_construct_method_id = env->GetMethodID(clazz, "", "()V"); 151 | 152 | if (java_construct_method_id == NULL) { 153 | return; 154 | } 155 | 156 | //创建一个对象 157 | jobject object_test = env->NewObject(clazz, java_construct_method_id); 158 | if (object_test == NULL) { 159 | return; 160 | } 161 | 162 | //获得 methodid 163 | jmethodID java_method_id = env->GetMethodID(clazz, "myMethod", "()V"); 164 | if (java_method_id == NULL) { 165 | return; 166 | } 167 | 168 | //调用 myMethod 方法 169 | env->CallVoidMethod(object_test,java_method_id); 170 | 171 | //清理临时引用吧 172 | env->DeleteLocalRef(clazz); 173 | env->DeleteLocalRef(object_test); 174 | } 175 | extern "C" 176 | JNIEXPORT void JNICALL 177 | Java_com_yuandaima_myjnidemo_MainActivity_accessStaticMethod(JNIEnv *env, jobject thiz) { 178 | 179 | jclass clazz = env->FindClass("com/yuandaima/myjnidemo/TestJavaClass"); 180 | if (clazz == NULL) { 181 | return; 182 | } 183 | 184 | jmethodID static_method_id = env->GetStaticMethodID(clazz, "myStaticMethod", "()V"); 185 | if(NULL == static_method_id) 186 | { 187 | return; 188 | } 189 | 190 | env->CallStaticVoidMethod(clazz, static_method_id); 191 | 192 | env->DeleteLocalRef(clazz); 193 | 194 | } 195 | ``` 196 | 197 | Native 访问一个 Java 方法基本分为三部: 198 | 199 | * 获取到类对应的 jclass 对象(对应于 Java 层的 Class 对象),jclss 是一个局部引用,使用完后记得使用 DeleteLocalRef 以避免局部引用表溢出。 200 | * 获取到需要访问的方法的 jmethodID,jmethodID 不是一个 JNI 引用类型,是一个普通指针,指针指向的内存由 JVM 管理,我们无需在使用完后执行 free 清理操作 201 | * 接着就可以调用 CallxxxMethod/CallStaticxxxMethod 来调用对于的方法,xxx 是方法的返回类型。 202 | 203 | ## 参考资料 204 | 205 | * [JNI 引用, DeleteLocalRef使用场景详解](https://blog.csdn.net/tabactivity/article/details/106902540) 206 | * [JNI内存方面说明以及相关类型手动释放内存](JNI内存方面说明以及相关类型手动释放内存) 207 | 208 | # 关于 209 | 210 | 我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研发工作。主要研究方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技术分享。 211 | 212 | 如果你对 Framework 感兴趣或者正在学习 Framework,可以参考我总结的[Android Framework 学习路线指南](https://github.com/yuandaimaahao/AndroidFrameworkTutorial),也可关注我的微信公众号,我会在公众号上持续分享我的经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。 213 | 214 | ![](https://gitee.com/stingerzou/pic-bed/raw/master/img/4e7348e352774883ecb19ab021d6cee.jpg) --------------------------------------------------------------------------------