前言 开始时间(2021年9月11日9点50分 ) 结束时间(2021年9月19日16点40分) 注意空间要留够,最好留500G空间用来存放AOSP的源代码。(笔者在第一次实验时只留了300G,结果做到最后发现实验空间不够了,临时切换到deepin系统使用gparted工具扩容到了600G以上)
该记录是为了自下而上的了解安卓程序运行的整个流程,参考的文档大部分都放在了本记录的参考内容之中,由于网络上的教程比较分散且部分内容和使用的源码版本不一致,故在此整理,以便日后复习使用。
环境准备(基于ubuntu16.04) 下载Android源代码 使用清华源下载源码
下载源码时可能需要把https换成http
1 repo init -u http://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-7.0.0_r28
另外如果碰到python环境有问题,可以重新安装python环境,之后就能执行repo脚本了
Python安装报错:”ModuleNotFoundError:No module named _ctypes“ 的解决方案
若担心网络不好中途断开链接,可以用一个shell脚本执行repo.sh
1 2 3 4 5 6 7 8 9 10 # !/bin/bash repo sync -j8 while [ $? = 1 ] do echo "======sync failed ,re-sync again======" sleep 3 repo sync -j8 done
编译Android源代码 安装openjdk 1.8 Ubuntu 16.04安装Java JDK
1 2 sudo apt-get update sudo apt-get install openjdk-8-jdk
安装依赖库 1 2 3 4 5 6 7 sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib git flex bison gperf build-essential libncurses5-dev:i386 tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386 dpkg-dev libsdl1.2-dev libesd0-dev git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip m4
编译AOSP项目的源代码 由于最后编写应用程序验证驱动时会碰到 selinux
的问题,在查阅了相关资料后修改 system/core/init/init.cpp
的一行代码,关闭安全选项 SELINUX_ENFORCING
。
1 2 3 4 5 6 7 8 9 static selinux_enforcing_status selinux_status_from_cmdline () { selinux_enforcing_status status = SELINUX_PERMISSIVE; import_kernel_cmdline (false , [&](const std::string& key, const std::string& value, bool in_qemu) { if (key == "androidboot.selinux" && value == "permissive" ) { status = SELINUX_PERMISSIVE; } });
开始编译源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 进入AOSP项目根目录 cd android # 设置环境变量 source build/envsetup.sh # 选择平台 选择2 2.aosp_arm64-eng lunch 2 # 执行编译 make -j8 # 编译SDK make sdk -j8 # 执行android启动sdk manager下载项目相关工具 android
下载好后通过 android list targets
命令来查看当前系统中可以创建哪些平台的虚拟设备,在我的系统下,这条命令的执行结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Available Android targets: ---------- id: 1 or "android-24" Name: Android 7.0 Type: Platform API level: 24 Revision: 2 Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in Tag/ABIs : default/armeabi-v7a ---------- id: 2 or "Google Inc.:Google APIs:24" Name: Google APIs Type: Add-On Vendor: Google Inc. Revision: 1 Description: Android + Google APIs Based on Android 7.0 (API level 24) Libraries: * com.android.future.usb.accessory (usb.jar) API for USB Accessories * com.google.android.media.effects (effects.jar) Collection of video effects * com.google.android.maps (maps.jar) API for Google Maps Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in Tag/ABIs : no ABIs.
接下来创建设备并运行模拟器
1 2 3 4 5 # 创建一个Android 7.0的虚拟设备。创建的命令如下: android create avd -n helloandroid -t 1 # 通过 emulator -help 查看说明,然后运行安卓模拟器 emulator -show-kernel -avd helloandroid -partition-size 4096 -memory 2048 -cache-size 2048
之后运行安卓模拟器需要先设置好环境变量和平台
1 2 3 4 5 6 # 设置环境变量 source build/envsetup.sh # 选择平台 与之前编译时的选择要相同 lunch 2 # 运行安卓模拟器 emulator -show-kernel -avd helloandroid -partition-size 4096 -memory 2048 -cache-size 2048
下载、编译与安装android内核源代码(linux kernel) 下载 Android kernel 代码
先设置代理,之后才能下载内核源码
1 2 3 4 5 6 7 8 9 10 11 # 设置代理 git config --global http.proxy IPaddress:port git config --global https.proxy IPaddress:port # 内核的下载花了点时间,执行命令后,可以去做其他事了 mkdir kernel && cd kernel git clone https://android.googlesource.com/kernel/goldfish # 取消代理 git config --global --unset http.proxy git config --global --unset https.proxy
下载好后进行内核版本选择,这里可以打开模拟器去看看预编译好的内核版本,然后再进行选择,笔者这里的安卓模拟器使用的Android版本是7.0内核版本显示3.10
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 进入goldfish版本内核 cd goldfish # 查看有哪些分支 git branch -a # 选择与预编译一致的linux内核版本的分支 git checkout remotes/origin/android-goldfish-3.10 git branch arm-3.10 git checkout arm-3.10 # 设置环境变量 source build/envsetup.sh # 选择平台 与之前编译源码时的选择要相同 lunch 2 # 使用安卓项目中的编译脚本来编译内核 ../../prebuilts/qemu-kernel/build-kernel.sh
或者导入环境变量再编译(后面编译驱动的时候就用这种方式)
1 2 3 4 5 export ARCH=arm64 export CROSS_COMPILE=aarch64-linux-android- # 如果无法使用make goldfish 可以直接cp arch/arm/configs/某个匹配的配置文件 .config make goldfish make -j8
运行安卓模拟器(使用编译好的内核)
1 2 3 4 5 6 # 设置环境变量 source build/envsetup.sh # 选择平台 lunch 2 # 运行安卓模拟器,指定编译好的文件 emulator -show-kernel -avd helloandroid -kernel ../kernel/goldfish/arch/arm64/boot/Image -system ./out/target/product/generic_arm64/system.img -data ./out/target/product/generic_arm64/userdata.img -ramdisk ./out/target/product/generic_arm64/ramdisk.img
编写Linux内核驱动程序 新编译的linux内核是3.10版本,代码变动可以在drivers目录中找例子
编写代码 1 2 3 4 # 从 Android kernel 根目录进入drivers,并创建相关文件夹和文件 cd drivers mkdir hello && cd hello touch hello.h hello.c Makefile Kconfig
各代码文件内容如下:
hello.h hello.h view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #ifndef _HELLO_Android_H_ #define _HELLO_ANDROID_H_ #include <linux/cdev.h> #include <linux/semaphore.h> #define HELLO_DEVICE_NODE_NAME "hello" #define HELLO_DEVICE_FILE_NAME "hello" #define HELLO_DEVICE_PROC_NAME "hello" #define HELLO_DEVICE_CLASS_NAME "hello" struct hello_android_dev { int val; struct semaphore sem ; struct cdev dev ; }; #endif
hello.c hello.c view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/device.h> #include <asm/uaccess.h> #include <linux/cdev.h> #include <linux/semaphore.h> #include <linux/slab.h> #include <linux/seq_file.h> #include "hello.h" static int hello_major = 0 ;static int hello_minor = 0 ;static struct class * hello_class = NULL ;static struct hello_android_dev * hello_dev = NULL ;static ssize_t hello_val_show (struct device* dev, struct device_attribute* attr, char * buf) ;static ssize_t hello_val_store (struct device* dev, struct device_attribute* attr, const char * buf, size_t count) ; static DEVICE_ATTR (val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store) ;static int hello_open (struct inode* inode, struct file* filp) ;static int hello_release (struct inode* inode, struct file* filp) ;static ssize_t hello_read (struct file* filp, char __user *buf, size_t count, loff_t * f_pos) ;static ssize_t hello_write (struct file* filp, const char __user *buf, size_t count, loff_t * f_pos) ;static struct file_operations hello_fops = { .owner = THIS_MODULE, .open = hello_open, .release = hello_release, .read = hello_read, .write = hello_write, }; static int hello_open (struct inode* inode, struct file* filp) { struct hello_android_dev * dev ; dev = container_of(inode->i_cdev, struct hello_android_dev, dev); filp->private_data = dev; return 0 ; } static int hello_release (struct inode* inode, struct file* filp) { return 0 ; } static ssize_t hello_read (struct file* filp, char __user *buf, size_t count, loff_t * f_pos) { printk("hello_read()\n" ); ssize_t err = 0 ; struct hello_android_dev * dev = filp->private_data; if (down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } if (count < sizeof (dev->val)) { goto out; } if (copy_to_user(buf, &(dev->val), sizeof (dev->val))) { err = -EFAULT; goto out; } err = sizeof (dev->val); out: up(&(dev->sem)); return err; } static ssize_t hello_write (struct file* filp, const char __user *buf, size_t count, loff_t * f_pos) { struct hello_android_dev * dev = filp->private_data; ssize_t err = 0 ; printk("hello_write()\n" ); if (down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } if (count != sizeof (dev->val)) { goto out; } if (copy_from_user(&(dev->val), buf, count)) { err = -EFAULT; goto out; } err = sizeof (dev->val); out: up(&(dev->sem)); return err; } static ssize_t __hello_get_val(struct hello_android_dev* dev, char * buf) { printk("__hello_get_val()\n" ); int val = 0 ; struct semaphore *p_sem = &(dev->sem); if (down_interruptible(p_sem)) { printk("sem is used,pls wait to free.\n" ); return -ERESTARTSYS; } val = dev->val; up(p_sem); printk("get val: %d\n" ,val); return snprintf (buf, PAGE_SIZE, "%d\n" , val); } static ssize_t __hello_set_val(struct hello_android_dev* dev, const char * buf, size_t count) { printk("__hello_set_val()\n" ); int val = 0 ; val = simple_strtol(buf, NULL , 10 ); printk("set val: %d\n" ,val); if (down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } dev->val = val; up(&(dev->sem)); return count; } static ssize_t hello_val_show (struct device* dev, struct device_attribute* attr, char * buf) { printk("hello_val_show()\n" ); struct hello_android_dev * hdev = (struct hello_android_dev*)dev_get_drvdata(dev); return __hello_get_val(hdev, buf); } static ssize_t hello_val_store (struct device* dev, struct device_attribute* attr, const char * buf, size_t count) { printk("hello_val_store()\n" ); struct hello_android_dev * hdev = (struct hello_android_dev*)dev_get_drvdata(dev); return __hello_set_val(hdev, buf, count); } static int hello_proc_show (struct seq_file *m, void *v) { seq_printf(m, "%d\n" , hello_dev->val); return 0 ; } static int hello_proc_open (struct inode *inode, struct file *filp) { return single_open(filp, hello_proc_show, NULL ); } static ssize_t hello_proc_read (char * page, char ** start, off_t off, int count, int * eof, void * data) { printk("hello_proc_read()\n" ); if (off > 0 ) { *eof = 1 ; return 0 ; } return __hello_get_val(hello_dev, page); } static ssize_t hello_proc_write (struct file* filp, const char __user *buff, unsigned long len, void * data) { printk("hello_proc_write()\n" ); int err = 0 ; char * page = NULL ; if (len > PAGE_SIZE) { printk(KERN_ALERT"The buff is too large: %lu./n" , len); return -EFAULT; } page = (char *)__get_free_page(GFP_KERNEL); if (!page) { printk(KERN_ALERT"Failed to alloc page./n" ); return -ENOMEM; } if (copy_from_user(page, buff, len)) { printk(KERN_ALERT"Failed to copy buff from user./n" ); err = -EFAULT; goto out; } err = __hello_set_val(hello_dev, page, len); out: free_page((unsigned long )page); return err; } static void hello_remove_proc (void ) { remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL ); } static const struct file_operations hello_proc_fops = { .owner = THIS_MODULE, .open = hello_proc_open, .write = hello_proc_write, .read = seq_read, .llseek = seq_lseek, .release= single_release, }; static void hello_create_proc (void ) { proc_create(HELLO_DEVICE_PROC_NAME, 0 , NULL , &hello_proc_fops); } static int __hello_setup_dev(struct hello_android_dev* dev) { int err; dev_t devno = MKDEV(hello_major, hello_minor); printk("__hello_setup_dev()\n" ); memset (dev, 0 , sizeof (struct hello_android_dev)); cdev_init(&(dev->dev), &hello_fops); dev->dev.owner = THIS_MODULE; dev->dev.ops = &hello_fops; err = cdev_add(&(dev->dev),devno, 1 ); if (err) { return err; } sema_init(&(dev->sem),1 ); dev->val = 0 ; return 0 ; } static int __init hello_init (void ) { int err = -1 ; dev_t dev = 0 ; struct device * temp = NULL ; printk(KERN_ALERT"Initializing hello device./n" ); err = alloc_chrdev_region(&dev, 0 , 1 , HELLO_DEVICE_NODE_NAME); if (err < 0 ) { printk(KERN_ALERT"Failed to alloc char dev region./n" ); goto fail; } hello_major = MAJOR(dev); hello_minor = MINOR(dev); hello_dev = kmalloc(sizeof (struct hello_android_dev), GFP_KERNEL); if (!hello_dev) { err = -ENOMEM; printk(KERN_ALERT"Failed to alloc hello_dev./n" ); goto unregister; } err = __hello_setup_dev(hello_dev); if (err) { printk(KERN_ALERT"Failed to setup dev: %d./n" , err); goto cleanup; } hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME); if (IS_ERR(hello_class)) { err = PTR_ERR(hello_class); printk(KERN_ALERT"Failed to create hello class./n" ); goto destroy_cdev; } temp = device_create(hello_class, NULL , dev, "%s" , HELLO_DEVICE_FILE_NAME); if (IS_ERR(temp)) { err = PTR_ERR(temp); printk(KERN_ALERT"Failed to create hello device." ); goto destroy_class; } err = device_create_file(temp, &dev_attr_val); if (err < 0 ) { printk(KERN_ALERT"Failed to create attribute val." ); goto destroy_device; } dev_set_drvdata(temp, hello_dev); hello_create_proc(); printk(KERN_ALERT"Succedded to initialize hello device./n" ); return 0 ; destroy_device: device_destroy(hello_class, dev); destroy_class: class_destroy(hello_class); destroy_cdev: cdev_del(&(hello_dev->dev)); cleanup: kfree(hello_dev); unregister: unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1 ); fail: return err; } static void __exit hello_exit (void ) { dev_t devno = MKDEV(hello_major, hello_minor); printk(KERN_ALERT"Destroy hello device./n" ); hello_remove_proc(); if (hello_class) { device_destroy(hello_class, MKDEV(hello_major, hello_minor)); class_destroy(hello_class); } if (hello_dev) { cdev_del(&(hello_dev->dev)); kfree(hello_dev); } unregister_chrdev_region(devno, 1 ); } MODULE_LICENSE("GPL" ); MODULE_DESCRIPTION("First Android Driver" ); module_init(hello_init); module_exit(hello_exit);
makefile Makefile view raw 1 obj-$(CONFIG_HELLO) += hello.o
Kconfig Kconfig view raw 1 2 3 4 5 config HELLO tristate "Frist Android Driver" default y help This is the first android driver.
接着在 kernel/drivers/Makefile 中添加如下代码:
1 obj-$(CONFIG_HELLO) += hello/
继续在 kernel/drivers/Kconfig 中添加如下代码:
1 source "drivers/hello/Kconfig"
其中配置Kconfig是为了在menuconfig中生成菜单项,如果不想在配置菜单中显示,可以直接将 $(CONFIG_HELLO)
替换成 y
将Kconfig文件删除即可,也不必在上层目录的Kconfig中添加代码。
重新编译内核 1 2 3 4 5 6 # 在kernel/goldfish 目录执行以下命令进行内核编译 cp arch/arm/configs/ranchu_defconfig .config # 打开内核编译配置选项 确认 Device Drivers --> [*]Frist Android Driver 是开启的 make menuconfig # 执行编译 make -j8
使用编译好的内核启动模拟器,再用 adb shell
进入安卓模拟器的终端界面,运行以下命令进行验证
1 2 # 运行安卓模拟器,指定编译好的文件 emulator -show-kernel -avd helloandroid -kernel ../kernel/goldfish/arch/arm64/boot/Image -system ./out/target/product/generic_arm64/system.img -data ./out/target/product/generic_arm64/userdata.img -ramdisk ./out/target/product/generic_arm64/ramdisk.img
这个时候也可以直接在执行模拟器命令的终端上按回车键即可输入命令进行驱动的验证。
下面是使用 adb shell
的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 nicho@PC:~/work/android$ adb shell generic_arm64:/ # cd dev generic_arm64:/dev # ls hello hello generic_arm64:/dev # cd /proc generic_arm64:/proc # ls hello hello generic_arm64:/proc # cat hello 0 generic_arm64:/proc # echo 9 > hello generic_arm64:/proc # cat hello 9 generic_arm64:/proc # cd /sys/class/hello/hello/ generic_arm64:/sys/class/hello/hello # cat val 9 generic_arm64:/sys/class/hello/hello # echo 0 > val generic_arm64:/sys/class/hello/hello # cat val 0
编写C可执行程序测试Linux内核驱动程序 编写代码 1 2 3 4 # 从 AOSP 根目录进入external,并创建相关文件夹和文件 cd external mkdir hello && cd hello touch hello.c Android.mk
各文件代码内容如下:
hello.c hello.c view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #define DEVICE_NAME "/dev/hello" int main (int argc, char ** argv) { int fd = -1 ; int val = 0 ; fd = open(DEVICE_NAME, O_RDWR); if (fd == -1 ) { printf ("Failed to open device %s.\n" , DEVICE_NAME); return -1 ; } printf ("read original value:\n" ); read(fd, &val, sizeof (val)); printf ("%d.\n\n" , val); val = 5 ; printf ("Write value %d to %s.\n\n" , val, DEVICE_NAME); write(fd, &val, sizeof (val)); printf ("Read the value again:\n" ); read(fd, &val, sizeof (val)); printf ("%d.\n\n" ,val); close(fd); return 0 ; }
Android.mk Android.mk view raw 1 2 3 4 5 6 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_MODULE := hello LOCAL_SRC_FILES := $(call all-subdir-c-files) include $(BUILD_EXECUTABLE)
编译hello程序 1 2 3 4 # 在AOSP根目录执行以下命令进行编译 mmm ./external/hello # 重新生成system.bin文件 make snod
最后重新启动模拟器即可直接在 adb shell
中执行 hello
命令验证
1 2 3 4 5 6 7 8 9 nicho@PC:~/work/android$ adb shell generic_arm64:/ # hello read original value: 0. Write value 5 to /dev/hello. Read the value again: 5.
增加硬件抽象层(HAL)模块访问Linux内核驱动程序 在 android/hardware/libhardware/include/hardware
目录中创建 hello.h
文件。 内容如下
hello.h view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #ifndef Android_HELLO_INTERFACE_H #define ANDROID_HELLO_INTERFACE_H #include <hardware/hardware.h> __BEGIN_DECLS #define HELLO_HARDWARE_MODULE_ID "hello" struct hello_module_t { struct hw_module_t common ; }; struct hello_device_t { struct hw_device_t common ; int fd; int (*set_val)(struct hello_device_t * dev, int val); int (*get_val)(struct hello_device_t * dev, int * val); }; __END_DECLS #endif
这里按照Android硬件抽象层规范的要求,分别定义模块ID、模块结构体以及硬件接口结构体。在硬件接口结构体中,fd表示设备文件描述符,对应我们将要处理的设备文件”/dev/hello”,set_val和get_val为该HAL对上提供的函数接口。
在 android/hardware/libhardware/modules/hello
目录中创建 hello.c
和 Android.mk
文件。 hello
目录需要手动创建
各文件内容如下
hello.c view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 #include <hardware/hardware.h> #include <hardware/hello.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include <cutils/log.h> #include <cutils/atomic.h> #include <android/log.h> #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"hello_stub" ,__VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"hello_stub" ,__VA_ARGS__) #define LOG_TAG "HelloStub" #define DEVICE_NAME "/dev/hello" #define MODULE_NAME "hello" #define MODULE_AUTHOR "y041039@gmail.com" static int hello_device_open (const struct hw_module_t * module , const char * name, struct hw_device_t ** device) ;static int hello_device_close (struct hw_device_t * device) ;static int hello_set_val (struct hello_device_t * dev, int val) ;static int hello_get_val (struct hello_device_t * dev, int * val) ;static struct hw_module_methods_t hello_module_methods = { open: hello_device_open }; struct hello_module_t HAL_MODULE_INFO_SYM = { common: { tag: HARDWARE_MODULE_TAG, version_major: 1 , version_minor: 0 , id: HELLO_HARDWARE_MODULE_ID, name: MODULE_NAME, author: MODULE_AUTHOR, methods: &hello_module_methods, } }; static int hello_device_open (const struct hw_module_t * module , const char * name, struct hw_device_t ** device) { struct hello_device_t * dev ; dev = (struct hello_device_t *)malloc (sizeof (struct hello_device_t )); if (!dev) { LOGE("Hello Stub: failed to alloc space" ); return -EFAULT; } memset (dev, 0 , sizeof (struct hello_device_t )); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0 ; dev->common.module = (hw_module_t *)module ; dev->common.close = hello_device_close; dev->set_val = hello_set_val;dev->get_val = hello_get_val; if ((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1 ) { LOGE("Hello Stub: failed to open /dev/hello -- %s." , strerror(errno));free (dev); return -EFAULT; } *device = &(dev->common); LOGI("Hello Stub: open /dev/hello successfully." ); return 0 ; } static int hello_device_close (struct hw_device_t * device) { struct hello_device_t * hello_device = (struct hello_device_t *)device; if (hello_device) { close(hello_device->fd); free (hello_device); } return 0 ; } static int hello_set_val (struct hello_device_t * dev, int val) { LOGI("Hello Stub: set value %d to device." , val); write(dev->fd, &val, sizeof (val)); return 0 ; } static int hello_get_val (struct hello_device_t * dev, int * val) { if (!val) { LOGE("Hello Stub: error val pointer" ); return -EFAULT; } read(dev->fd, val, sizeof (*val)); LOGI("Hello Stub: get value %d from device" , *val); return 0 ; }
Android.mk view raw 1 2 3 4 5 6 7 8 9 10 11 12 LOCAL_PATH := $(call my-dir ) include $(CLEAR_VARS) LOCAL_LDLIBS := -llog LOCAL_MODULE_TAGS := optional LOCAL_PRELINK_MODULE := false LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := hello.c LOCAL_MODULE := hello.default include $(BUILD_SHARED_LIBRARY)
最后记得在 android/system/core/rootdir/uevent.rc
文件中添加一行,使应用程序有权限访问设备节点
1 /dev/hello 0666 root root
开始编译并重新打包系统镜像
1 2 3 # 回到源码根目录执行 mmm hardware/libhardware/moudles/hello make snod
可以在 out/target/product/generic_arm64/system/lib/hw/
目录中看到有 hello.default.so
生成。这时的 system.img
就包含我们定义的硬件抽象层模块 hello.default
了。虽然我们在Android系统为我们自己的硬件增加了一个硬件抽象层模块,但是现在Java应用程序还不能访问到我们的硬件。还必须编写JNI方法和在Android的Application Frameworks层增加API接口,才能让上层Application访问到硬件。
编写JNI 方法在应用程序框架层提供Java 接口访问硬件 在com_android_server_HelloService.cpp文件中,实现JNI方法。注意文件的命令方法,com_android_server前缀表示的是包名,表示硬件服务HelloService是放在frameworks/base/services/java目录下的com/android/server目录的,即存在一个命令为com.android.server.HelloService的类。这里,我们暂时略去HelloService类的描述,在下一篇文章中,我们将回到HelloService类来。简单地说,HelloService是一个提供Java接口的硬件访问服务类。内容如下
com_android_server_HelloService.cpp view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 #include "jni.h" #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> #include <utils/misc.h> #include <utils/Log.h> #include <hardware/hardware.h> #include <hardware/hello.h> #include <stdio.h> #include <android/log.h> #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"hello_stub" ,__VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"hello_stub" ,__VA_ARGS__) namespace android{ struct hello_device_t * hello_device = NULL ; static void hello_setVal (JNIEnv* env, jobject clazz, jint value) { int val = value; LOGI ("Hello JNI: set value %d to device." , val); if (!hello_device) { LOGI ("Hello JNI: device is not open." ); return ; } hello_device->set_val (hello_device, val); } static jint hello_getVal (JNIEnv* env, jobject clazz) { int val = 0 ; if (!hello_device) { LOGI ("Hello JNI: device is not open." ); return val; } hello_device->get_val (hello_device, &val); LOGI ("Hello JNI: get value %d from device." , val); return val; } static inline int hello_device_open (const hw_module_t * module , struct hello_device_t ** device) { return module ->methods->open (module , HELLO_HARDWARE_MODULE_ID, (struct hw_device_t **)device); } static jboolean hello_init (JNIEnv* env, jclass clazz) { hello_module_t * module ; LOGI ("Hello JNI: initializing......" ); if (hw_get_module (HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t **)&module ) == 0 ) { LOGI ("Hello JNI: hello Stub found." ); if (hello_device_open (&(module ->common), &hello_device) == 0 ) { LOGI ("Hello JNI: hello device is open." ); return 0 ; } LOGE ("Hello JNI: failed to open hello device." ); return -1 ; } LOGE ("Hello JNI: failed to get hello stub module." ); return -1 ; } static const JNINativeMethod method_table[] = { {"init_native" , "()Z" , (void *)hello_init}, {"setVal_native" , "(I)V" , (void *)hello_setVal}, {"getVal_native" , "()I" , (void *)hello_getVal}, }; int register_android_server_HelloService (JNIEnv *env) { return jniRegisterNativeMethods (env, "com/android/server/HelloService" , method_table, NELEM (method_table)); } };
修改同目录的 onload.cpp
文件
onload.cpp view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include "JNIHelp.h" #include "jni.h" #include "utils/Log.h" #include "utils/misc.h" namespace android {int register_android_server_HelloService (JNIEnv* env) ; int register_android_server_ActivityManagerService (JNIEnv* env) ;int register_android_server_AlarmManagerService (JNIEnv* env) ;int register_android_server_AssetAtlasService (JNIEnv* env) ;int register_android_server_BatteryStatsService (JNIEnv* env) ;int register_android_server_ConsumerIrService (JNIEnv *env) ;int register_android_server_InputApplicationHandle (JNIEnv* env) ;int register_android_server_InputWindowHandle (JNIEnv* env) ;int register_android_server_InputManager (JNIEnv* env) ;int register_android_server_LightsService (JNIEnv* env) ;int register_android_server_PowerManagerService (JNIEnv* env) ;int register_android_server_SerialService (JNIEnv* env) ;int register_android_server_SystemServer (JNIEnv* env) ;int register_android_server_UsbDeviceManager (JNIEnv* env) ;int register_android_server_UsbMidiDevice (JNIEnv* env) ;int register_android_server_UsbHostManager (JNIEnv* env) ;int register_android_server_vr_VrManagerService (JNIEnv* env) ;int register_android_server_VibratorService (JNIEnv* env) ;int register_android_server_location_GnssLocationProvider (JNIEnv* env) ;int register_android_server_location_FlpHardwareProvider (JNIEnv* env) ;int register_android_server_connectivity_Vpn (JNIEnv* env) ;int register_android_server_hdmi_HdmiCecController (JNIEnv* env) ;int register_android_server_tv_TvUinputBridge (JNIEnv* env) ;int register_android_server_tv_TvInputHal (JNIEnv* env) ;int register_android_server_PersistentDataBlockService (JNIEnv* env) ;int register_android_server_Watchdog (JNIEnv* env) ;int register_android_server_HardwarePropertiesManagerService (JNIEnv* env) ;}; using namespace android;extern "C" jint JNI_OnLoad (JavaVM* vm, void * ) { JNIEnv* env = NULL ; jint result = -1 ; if (vm->GetEnv ((void **) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE ("GetEnv failed!" ); return result; } ALOG_ASSERT (env, "Could not retrieve the env!" ); register_android_server_HelloService (env); register_android_server_ActivityManagerService (env); register_android_server_PowerManagerService (env); register_android_server_SerialService (env); register_android_server_InputApplicationHandle (env); register_android_server_InputWindowHandle (env);
修改同目录下的 Android.mk
文件
Android.mk view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 ifneq ($(ENABLE_CPUSETS) ,)ifneq ($(ENABLE_SCHED_BOOST) ,)LOCAL_CFLAGS += -DUSE_SCHED_BOOST endif endif LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR) /com_android_server_HelloService.cpp \ $(LOCAL_REL_DIR) /com_android_server_AlarmManagerService.cpp \ $(LOCAL_REL_DIR) /com_android_server_am_BatteryStatsService.cpp \ $(LOCAL_REL_DIR) /com_android_server_am_ActivityManagerService.cpp \ $(LOCAL_REL_DIR) /com_android_server_AssetAtlasService.cpp \ $(LOCAL_REL_DIR) /com_android_server_connectivity_Vpn.cpp \
开始编译并重新打包系统镜像 1 2 3 # 回到源码根目录执行 mmm frameworks/base/services/core/jni make snod
这样,重新打包的system.img镜像文件就包含刚才编写的JNI方法,也就是可以通过Android系统的Application Frameworks层提供的硬件服务HelloService来调用这些JNI方法,进而调用低层的硬件抽象层接口去访问硬件。
在应用程序框架层增加硬件服务接口 首先定义通信接口 1 2 nicho@PC:~/work/android$ cd frameworks/base/core/java/android/os/ nicho@PC:~/work/android/frameworks/base/core/java/android/os$ vi IHelloService.aidl
IHelloService.aidl view raw 1 2 3 4 5 6 7 package android.os; interface IHelloService { void setVal(int val); int getVal(); }
修改 frameworks/base目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加IHelloService.aidl源文件
Android.mk view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 LOCAL_SRC_FILES += \ core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \ core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \ core/java/android/accounts/IAccountManager.aidl \
Android.mk view raw 1 2 3 core/java/android/os/IUserManager.aidl \ core/java/android/os/IVibratorService.aidl \ core/java/android/os/IHelloService.aidl \
编译IHelloService.aidl接口 1 nicho@PC:~/work/android$ mmm frameworks/base/
这样,就会根据IHelloService.aidl生成相应的IHelloService.Stub接口。
接下来在 frameworks/base/services/java/com/android/server
目录中添加 HelloService.java
文件
HelloService.java view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.android.server;import android.content.Context;import android.os.IHelloService;import android.util.Slog;public class HelloService extends IHelloService .Stub {private static final String TAG = "HelloService" ;HelloService() { System.out.println("frameworks/base/services/java/com/android/server/HelloService.java HelloService()" ); init_native(); } public void setVal (int val) { System.out.println("frameworks/base/services/java/com/android/server/HelloService.java setVal()" ); setVal_native(val); } public int getVal () { System.out.println("frameworks/base/services/java/com/android/server/HelloService.java getVal()" ); return getVal_native(); } private static native boolean init_native () ;private static native void setVal_native (int val) ;private static native int getVal_native () ;};
修改同目录的 SystemServer.java
文件
SystemServer.java view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mActivityManagerService.systemReady(new Runnable() { @Override public void run () { try { Slog.i(TAG, "Hello Service" ); ServiceManager.addService("hello" , new HelloService()); } catch (Throwable e) { Slog.i(TAG, "Failure starting Hello Service" , e); } Slog.i(TAG, "Making services ready" ); mSystemServiceManager.startBootPhase( SystemService.PHASE_ACTIVITY_MANAGER_READY);
开始编译并重新打包系统镜像 1 2 3 # 回到源码根目录执行 mmm frameworks/base/services make snod
这样,重新打包后的system.img系统镜像文件就在Application Frameworks层中包含了自定义的硬件服务HelloService,并且会在系统启动的时候,自动加载HelloService。这时,应用程序就可以通过Java接口来访问Hello硬件服务。
内置Java应用程序测试Application Frameworks层的硬件服务 原始教程是通过Android Studio创建工程项目的,这里笔者图了个方便直接在命令行中创建了。下面我们就可以开始创建我们第一个HelloAndroid工程了。在~/workandroid/external下建立helloandroid目录,进入helloandroid目录,执行下面命令(target 参数接的数字要与AOSP的版本对应):
1 2 3 cd ~/work/android/external mkdir helloandroid && cd helloandroid android create project --name helloandroid --activity HelloAndroid --path ./ --package com.examples.helloandroid --target 1
要修改的文件
1 2 3 4 helloandroid/src/com/examples/helloandroid/HelloAndroid.java helloandroid/res/layout/main.xml helloandroid/AndroidManifest.xml helloandroid/Android.mk
文件内容如下
HelloAndroid.java view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 package com.examples.helloandroid;import com.examples.helloandroid.R;import android.app.Activity;import android.os.ServiceManager;import android.os.Bundle;import android.os.IHelloService;import android.os.RemoteException;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText; public class HelloAndroid extends Activity implements OnClickListener { private final static String LOG_TAG = "shy.luo.renju.Hello" ; private IHelloService helloService = null ; private EditText valueText = null ; private Button readButton = null ; private Button writeButton = null ; private Button clearButton = null ; @Override public void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); System.out.println("Hello Started" ); helloService = IHelloService.Stub.asInterface( ServiceManager.getService("hello" )); valueText = (EditText)findViewById(R.id.edit_value); readButton = (Button)findViewById(R.id.button_read); writeButton = (Button)findViewById(R.id.button_write); clearButton = (Button)findViewById(R.id.button_clear); readButton.setOnClickListener(this ); writeButton.setOnClickListener(this ); clearButton.setOnClickListener(this ); Log.i(LOG_TAG, "Hello Activity Created" ); } @Override public void onClick (View v) { if (v.equals(readButton)) { try { int val = helloService.getVal(); String text = String.valueOf(val); valueText.setText(text); } catch (RemoteException e) { Log.e(LOG_TAG, "Remote Exception while reading value from device." ); } } else if (v.equals(writeButton)) { try { String text = valueText.getText().toString(); int val = Integer.parseInt(text); helloService.setVal(val); } catch (RemoteException e) { Log.e(LOG_TAG, "Remote Exception while writing value to device." ); } } else if (v.equals(clearButton)) { String text = "" ; valueText.setText(text); } } }
main.xml view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:orientation ="vertical" android:layout_width ="fill_parent" android:layout_height ="fill_parent" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="center"> <TextView android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:text ="@string/value" > </TextView > <EditText android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:id ="@+id/edit_value" android:hint ="@string/hint" > </EditText > </LinearLayout > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center"> <Button android:id ="@+id/button_read" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:text ="@string/read" > </Button > <Button android:id ="@+id/button_write" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:text ="@string/write" > </Button > <Button android:id ="@+id/button_clear" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:text ="@string/clear" > </Button > </LinearLayout > </LinearLayout >
AndroidManifest.xml view raw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android ="http://schemas.android.com/apk/res/android" package ="com.examples.helloandroid" android:versionCode ="1" android:versionName ="1.0" > <application android:label ="@string/app_name" android:icon ="@drawable/ic_launcher" > <activity android:name ="HelloAndroid" android:label ="@string/app_name" > <intent-filter > <action android:name ="android.intent.action.MAIN" /> <category android:name ="android.intent.category.LAUNCHER" /> </intent-filter > </activity > </application > </manifest >
Android.mk view raw 1 2 3 4 5 6 7 8 LOCAL_PATH:= $(call my-dir ) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := Hello include $(BUILD_PACKAGE)
编译并运行模拟器进行验证 1 2 3 4 5 # 回到源码根目录执行 nicho@PC:~/work/android$ mmm packages/experimental/helloandroid make snod # 运行安卓模拟器,指定编译好的文件 emulator -show-kernel -avd helloandroid -kernel ../kernel/goldfish/arch/arm64/boot/Image -system ./out/target/product/generic_arm64/system.img -data ./out/target/product/generic_arm64/userdata.img -ramdisk ./out/target/product/generic_arm64/ramdisk.img
至此,也就完整地学习了在Android的Linux内核空间添加硬件驱动程序、在Android的硬件抽象层添加硬件接口、在Android的Application Frameworks层提供硬件服务以及在Android的应用层调用硬件服务的整个过程。
参考内容 Android硬件抽象层(HAL)概要介绍和学习计划
(三)在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序 原始链接已经打不开了,重新找了一个
1.下载源码
在Ubuntu16.04上下载并编译Android源代码
国内不翻墙下载Android 源代码
Ubuntu下载编译android7.0源码教程从安装到编译
repo forall -c 用法
2.配置环境
下载jdk1.7
配置jdk的环境变量
用update-alternatives管理java版本
ubuntu安装和卸载jdk8
ubuntu16 安装openjdk java1.7
最终是使用open jdk8 进行编译
重新添加了 libwxgtk2.8-dev
的ppa
安装其他依赖
4.编译AOSP项目
Android6.0源码编译
使用openjdk1.8 编译android7 到37%出现严重错误
1 2 3 4 5 6 [ 34% 16828/48845] Ensure Jack server is installed and started FAILED: /bin/bash -c "(prebuilts/sdk/tools/jack-admin install-server prebuilts/sdk/tools/jack-launcher.jar prebuilts/sdk/tools/jack-server-4.8.ALPHA.jar 2>&1 || (exit 0) ) && (JACK_SERVER_VM_ARGUMENTS=\"-Dfile.encoding=UTF-8 -XX:+TieredCompilation\" prebuilts/sdk/tools/jack-admin start-server 2>&1 || exit 0 ) && (prebuilts/sdk/tools/jack-admin update server prebuilts/sdk/tools/jack-server-4.8.ALPHA.jar 4.8.ALPHA 2>&1 || exit 0 ) && (prebuilts/sdk/tools/jack-admin update jack prebuilts/sdk/tools/jacks/jack-2.28.RELEASE.jar 2.28.RELEASE || exit 47; prebuilts/sdk/tools/jack-admin update jack prebuilts/sdk/tools/jacks/jack-3.36.CANDIDATE.jar 3.36.CANDIDATE || exit 47; prebuilts/sdk/tools/jack-admin update jack prebuilts/sdk/tools/jacks/jack-4.7.BETA.jar 4.7.BETA || exit 47 )" Jack server already installed in "/home/nicho/.jack-server" Communication error with Jack server (35), try 'jack-diagnose' or see Jack server log SSL error when connecting to the Jack server. Try 'jack-diagnose' SSL error when connecting to the Jack server. Try 'jack-diagnose'
1 2 3 4 5 6 7 [ 37% 18114/48845] target thumb C: lib...rnal/icu/icu4c/source/i18n/decNumber.c ninja: build stopped: subcommand failed. build/core/ninja.mk:148: recipe for target 'ninja_wrapper' failed make: *** [ninja_wrapper] Error 1 #
编译报错:build/core/ninja.mk:148: recipe for target ‘ninja_wrapper’ failed
AOSP中make clean与make clobber的区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 make clean 它会删除本次设置所生成的所有的output与中间文件。 等价于指令 rm -rf $OUT 1 这里的$OUT指的是out/target/product/[product_name] make clobber 它会删除所有设置所生成的所有的output与中间文件。 等价于指令 rm -rf out/ 1 可以看到,make clobber的严格在于它把整个out目录都删除了。
5.下载编译安装 Android kernel
Building Kernels Manually-需要通过外网访问 这个文档比较全,在构建安卓系统的过程中可以全程使用
Android源代码Linux Kernel下载及编译
编译可用的Android模拟器ranchu内核
6.编写Linux 3.4.67的字符驱动
Learn How to Write a Driver for Linux 3.x With The Linux Driver Template
A Linux Driver Template (LDT) has been published to help new Linux kernel developers writing hardware device drivers.
Constantine Shulyupin posted the Linux Driver Template (LDT) on the Linux mailing list in order to merge it into the mainline Linux kernel. The code can be used as as a starting point for new drivers, and shows how to use several Linux facilities such as module, platform driver, file operations (read/write, mmap, ioctl, blocking and nonblocking mode, polling), kfifo, completion, interrupt, tasklet, work, kthread, timer, simple misc device, multiple char devices, Device Model, configfs, UART, hardware loopback, software loopback and ftracer.
This sample has been added to other device drivers samples in eLinux.org . And if you want to learn further there’s always the Linux driver bible: “Linux Device Drivers, Third Edition ” which can be downloaded for free as PDF, although it’s for 2.6.10 kernel and many parts may not be up-to date.
以上内容摘自: https://www.cnx-software.com/2012/11/14/learn-how-to-write-a-driver-for-linux-3-x-with-the-linux-driver-template/
Android 驱动之旅: 第一章 在Android 内核源代码工程中编写硬件驱动程序
Android 驱动之旅: 第二章 — 在Android 系统中增加C 可执行程序来访问硬件驱动程序
Android 驱动之旅: 第三章 硬件抽象层(HAL)增加接口模块访问硬件驱动程序
LOCAL_MODULE_PATH与LOCAL_MODULE_RELATIVE_PATH区别
Android7.0 APP调用驱动流程 JNI层开发流程
在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
Android HAL(硬件抽象层)介绍以及调用
ubuntu下使用命令行创建一个android项目
使用命令行方式开发Android应用
Android9.0 mm编译失败:ninja: error: ‘xxx’, needed by ‘xxx’, missing and no known rule to make it
Android架构实例分析之编写hello驱动的系统硬件服务
Android7关闭selinux(设置为Permissive模式)
忽然意识到,驱动的编写模板应该在内核目录drivers里头去找。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 cd ~/work/android && source build/envsetup.sh && lunch 2 mmm packages/experimental/helloandroid/ make snod emulator -show-kernel -avd helloandroid -kernel ../kernel/goldfish/arch/arm64/boot/Image -system ./out/target/product/generic_arm64/system.img -data ./out/target/product/generic_arm64/userdata.img -ramdisk ./out/target/product/generic_arm64/ramdisk.img 01-01 08:03:04.915 898 898 E ServiceManager: add_service('hello',6d) uid=1000 - PERMISSION DENIED 09-19 11:05:07.863 1866 1866 E AndroidRuntime: java.lang.NullPointerException: Attempt to invoke interface method 'int android.os.IHelloService.getVal()' on a null object reference
ServiceManager add_service SELinux Permission Denied
Android O 添加系统服务错误 add_service uid=1000 - PERMISSION DENIED
1 2 3 4 5 6 7 8 Android source code compile error: “Try increasing heap size with java option '-Xmx<size>'” export JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx4g" ./prebuilts/sdk/tools/jack-admin kill-server ./prebuilts/sdk/tools/jack-admin start-server
repo介绍
repo 撤销本地代码
使用repo丢弃本地的改动
repo如何取消本地改动(How to discard changes using repo)
驱动的编写模板应该在内核目录drivers里头去找例子
1 2 3 cd ~/work/android && source build/envsetup.sh && lunch 2 emulator -show-kernel -avd helloandroid -kernel ../kernel/goldfish/arch/arm64/boot/Image -system ./out/target/product/generic_arm64/system.img -data ./out/target/product/generic_arm64/userdata.img -ramdisk ./out/target/product/generic_arm64/ramdisk.img
总结 9月15日下午编译SDK之后,安卓模拟器就总是卡在开机动画界面,9月18日早上打算重新走一遍教程,捋一捋问题出在了哪里。9月19日终于把整个流程都走完了,然后重头梳理教程,理清思路。
最初下载好源码后是使用了 lunch 2
去编译 arm64
架构,且能正常运行,但当走到 adb devices
这一步的时候发现 device
总是 offline
,所以后来又回过头去使用 lunch 1
编译了 arm
架构,这一次非常顺利,并且也能通过 adb shell
进入终端,不过到了最后一个步骤需要编写 apk
进行验证的时候需要编译 SDK
,结果编译完 SDK
之后忽然发现所有的模拟器(源码预编译好的与 SDK
中新编译出来的)都卡在启动界面无法进入,在网上参考了许多资料都没效果,后来实在想不出办法了,就 make clean
了以下,又重新使用 lunch 2
去编译 arm64
架构的,这一次全部都通了,然后在命令行启动 android
开启 SDK manager
下载与安卓源码匹配的工具与镜像。通过在命令行下创建安卓项目工程,编写好相关代码文件,编译生成安卓系统预置应用程序 helloandroid
,启动模拟器验证结果,这时候碰到了 selinux
的问题,在查阅了相关资料后修改 system/core/init/init.cpp
的一行代码,关闭安全选项,重新执行 make -j8
进行编译,开启模拟器验证成功,自此自下而上的了解安卓系统算是有了一点眉目。
在此非常感谢同学的帮助,也感谢所有在互联网上无私分享知识的网友们,没有你们的付出,我很难收获到这些知识,更不会有这篇记录的产生,谢谢你们。