1:
joe@joe-Aspire-Z3730:~$ cd /media/sdb4/aosp/kernel/goldfish/drivers/
2:
joe@joe-Aspire-Z3730:/media/sdb4/aosp/kernel/goldfish/drivers$ mkdir hello
3:在hello 目录中增加hello.h 文件 参考 Android驱动开发全过程(有图有真相)的hello.h
#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
4:在hello 目录中增加hello.c 文件 参考 https://blog.csdn.net/eliot_shao/article/details/51864811 帖子中的链接 http://blog.csdn.net/eliot_shao/article/details/51860229
也参考了 https://blog.csdn.net/brantyou/article/details/8651385
/*
* hello.c -- A simple virtual char device driver
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/device.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("eliot shao");
#define DEVICE_SUM 1
static int hello_open(struct inode *inode, struct file *filp);
static int hello_release(struct inode *, struct file *filp);
static ssize_t hello_read(struct file*, char*, size_t, loff_t*);
static ssize_t hello_write(struct file*, const char*, size_t, loff_t*);
/* the major device number */
static int hello_major = 0;
static int hello_minor = 0;
static struct class* hello_class = NULL;
/* init the file_operations structure */
struct file_operations hello_fops =
{
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.read = hello_read,
.write = hello_write,
};
/* define a cdev device */
struct cdev *cdev;
static int global_var = 0; /* global var */
/* module init */
static int __init hello_init(void)
{
int ret = 0;
struct device* temp = NULL;
dev_t devno = 0;
printk("hello:hello_init .\n");
/*动态分配主设备和从设备号*/
ret = alloc_chrdev_region(&devno, hello_minor, DEVICE_SUM, "hello");
if(ret < 0) {
printk(KERN_ALERT"hello:Failed to alloc char dev region.\n");
goto fail;
}
hello_major = MAJOR(devno);
hello_minor = MINOR(devno);
cdev = cdev_alloc();
cdev->owner = THIS_MODULE;
cdev->ops = &hello_fops;
if ((ret = cdev_add(cdev, devno, 1)))
{
printk(KERN_NOTICE "hello:Error %d adding hello.\n", ret);
return 0;
}
else
printk("hello:hello register success.\n");
/*在/sys/class/目录下创建设备类别目录hello*/
hello_class = class_create(THIS_MODULE, "hello");
if(IS_ERR(hello_class)) {
ret = PTR_ERR(hello_class);
printk(KERN_ALERT"Failed to create hello class.\n");
goto destroy_cdev;
}
/*在/dev/目录和/sys/class/hello目录下分别创建设备文件hello*/
temp = device_create(hello_class, NULL, devno, "%s", "hello");
if(IS_ERR(temp)) {
ret = PTR_ERR(temp);
printk(KERN_ALERT"Failed to create hello device.");
goto destroy_class;
}
return ret;
destroy_class:
class_destroy(hello_class);
destroy_cdev:
cdev_del(cdev);
fail:
return ret;
}
/* module exit */
static void __exit hello_exit(void)
{
dev_t devno = MKDEV(hello_major, 0);
/* remove cdev from kernel */
cdev_del(cdev);
/* unregister the device driver */
unregister_chrdev_region(devno, 1);
/* free the dev structure */
if(cdev)
kfree(cdev);
cdev = NULL;
}
/* open device */
static int hello_open(struct inode *inode, struct file *filp)
{
int ret = 0;
printk("KERNEL:open success.\n");
return ret;
}
/* release device */
static int hello_release(struct inode *inode, struct file *filp)
{
printk("KERNEL:release success.\n");
return 0;
}
/* read device */
static ssize_t hello_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
printk("KERNEL:reading...\n");
if(copy_to_user(buf, &global_var, sizeof(int)))
{
return -EFAULT;
}
return sizeof(int);
}
/* write device */
static ssize_t hello_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
printk("KERNEL:writing...\n");
if(copy_from_user(&global_var, buf, sizeof(int)))
{
return -EFAULT;
}
return sizeof(int);
}
/* module register */
module_init(hello_init);
module_exit(hello_exit);
5:/media/sdb4/aosp/kernel/goldfish/drivers目录下的Makefile中增加一行:
obj-$(CONFIG_HELLO) += hello/
6:/media/sdb4/aosp/kernel/goldfish/drivers目录下的Kconfig中增加一行(注意位置):
menu "Device Drivers"
。。。。。
source "drivers/hello/Kconfig"
。。。
endmenu
7:/media/sdb4/aosp/kernel/goldfish/drivers/hello目录下增加Makefile文件,内容为:
obj-$(CONFIG_HELLO) += hello.o
8:/media/sdb4/aosp/kernel/goldfish/drivers/hello目录下增加Kconfig文件,内容为
config HELLO
tristate "First Android Driver"
default n
help
This is first Android Deiver for demo
9:
joe@joe-Aspire-Z3730:/media/sdb4/aosp/kernel/goldfish$ export CROSS_COMPILE=arm-eabi-
joe@joe-Aspire-Z3730:/media/sdb4/aosp/kernel/goldfish$ export ARCH=arm
joe@joe-Aspire-Z3730:/media/sdb4/aosp/kernel/goldfish$ export SUBARCH=arm
10:
joe@joe-Aspire-Z3730:/media/sdb4/aosp/kernel/goldfish$ make goldfish_armv7_defconfig
#
# configuration written to .config
#
#### make completed successfully (7 seconds) ####
11:
joe@joe-Aspire-Z3730:/media/sdb4/aosp/kernel/goldfish$ make
scripts/kconfig/conf --silentoldconfig Kconfig
CHK include/linux/version.h
CHK include/generated/utsrelease.h
make[1]: `include/generated/mach-types.h' is up to date.
CALL scripts/checksyscalls.sh
CHK include/generated/compile.h
GZIP kernel/config_data.gz
CHK kernel/config_data.h
UPD kernel/config_data.h
CC kernel/configs.o
LD kernel/built-in.o
LD vmlinux.o
MODPOST vmlinux.o
GEN .version
CHK include/generated/compile.h
UPD include/generated/compile.h
CC init/version.o
LD init/built-in.o
LD .tmp_vmlinux1
KSYM .tmp_kallsyms1.S
AS .tmp_kallsyms1.o
LD .tmp_vmlinux2
KSYM .tmp_kallsyms2.S
AS .tmp_kallsyms2.o
LD vmlinux
SYSMAP System.map
SYSMAP .tmp_System.map
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
GZIP arch/arm/boot/compressed/piggy.gzip
AS arch/arm/boot/compressed/piggy.gzip.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
#### make completed successfully (29 seconds) ####
总感觉不可能有这么快的编译速度?????
12:重新进到aosp目录
joe@joe-Aspire-Z3730:/media/sdb4/aosp$ emulator -kernel ./kernel/goldfish/arch/arm/boot/zImage
13:虽然用新的内核启动了模拟器,但我在/media/sdb4/aosp/kernel/goldfish/drivers/hello目录中没有看到 hello.o文件
14:在/dev和/proc中都没有看到hello设备
joe@joe-Aspire-Z3730:/media/sdb4/aosp$ adb shell
root@generic:/ # cd dev
root@generic:/dev # ls
__properties__
ashmem
binder
block
console
cpu_dma_latency
cpuctl
device-mapper
eac
fscklogs
full
fuse
graphics
input
kmem
kmsg
loop-control
mem
memcg
mtd
network_latency
network_throughput
null
psaux
ptmx
pts
qemu_pipe
random
rtc0
socket
tty
tty0
tty1
tty10
tty11
tty12
tty13
tty14
tty15
tty16
tty17
tty18
tty19
tty2
tty20
tty21
tty22
tty23
tty24
tty25
tty26
tty27
tty28
tty29
tty3
tty30
tty31
tty32
tty33
tty34
tty35
tty36
tty37
tty38
tty39
tty4
tty40
tty41
tty42
tty43
tty44
tty45
tty46
tty47
tty48
tty49
tty5
tty50
tty51
tty52
tty53
tty54
tty55
tty56
tty57
tty58
tty59
tty6
tty60
tty61
tty62
tty63
tty7
tty8
tty9
ttyS0
ttyS1
ttyS2
tun
urandom
vcs
vcs1
vcsa
vcsa1
xt_qtaguid
zero
root@generic:/dev # cd /proc
root@generic:/proc # ls
1
10
1013
1030
1061
1081
1098
11
1125
1162
1178
1186
12
13
139
14
2
25
26
27
28
29
3
30
31
33
337
34
37
39
40
43
447
45
46
47
48
49
5
50
51
52
54
57
58
587
59
6
60
61
62
63
64
646
65
66
663
682
7
709
73
739
783
8
822
839
897
9
923
940
963
995
buddyinfo
bus
cgroups
cmdline
config.gz
consoles
cpu
cpuinfo
crypto
devices
diskstats
dma-mappings
driver
execdomains
fb
filesystems
fs
interrupts
iomem
ioports
irq
kallsyms
kmsg
kpagecount
kpageflags
loadavg
locks
meminfo
misc
mounts
mtd
net
pagetypeinfo
partitions
sched_debug
schedstat
self
slabinfo
softirqs
stat
swaps
sys
sysrq-trigger
sysvipc
timer_list
tty
uptime
version
vmallocinfo
vmstat
yaffs
zoneinfo
15:/media/sdb4/aosp/kernel/goldfish/drivers/hello目录下修改Kconfig文件
config HELLO
tristate "First Android Driver"
default m
help
This is first Android Deiver for demo
16:重新执行第10和第11步,然后发现hello目录中出现了hello.o文件,说明驱动程序编译了
17:
joe@joe-Aspire-Z3730:/media/sdb4/aosp/kernel/goldfish$ cd ../..
joe@joe-Aspire-Z3730:/media/sdb4/aosp$ emulator -kernel ./kernel/goldfish/arch/arm/boot/zImage &
18:参考 android-----模拟器加载自己编译的内核(适用于驱动练习)https://blog.csdn.net/yf210yf/article/details/9901375 不成功。主要是因为权限问题,所以修改hello目录下的Kconfig,将驱动程序直接编译进内核中
config HELLO
tristate "First Android Driver"
default y
help
This is first Android Deiver for demo
19:重新执行第10和第11步
20:
joe@joe-Aspire-Z3730:/media/sdb4/aosp$ emulator -kernel ./kernel/goldfish/arch/arm/boot/zImage &
21:参考 https://blog.csdn.net/brantyou/article/details/8651385
joe@joe-Aspire-Z3730:/media/sdb4/aosp$ adb shell
root@generic:/ # cd dev
root@generic:/dev # ls
其中就出现了hello,但/proc目录中却没有hello
22:下面的帖子中说明了如何在android源码中写应用层程序测试hello驱动
https://blog.csdn.net/lzpdz/article/details/50562366
23:按照22中所说,先进入源码的external目录,然后:
joe@joe-Aspire-Z3730:/media/sdb4/aosp/external$ mkdir hello
joe@joe-Aspire-Z3730:/media/sdb4/aosp/external$ cd hello
joe@joe-Aspire-Z3730:/media/sdb4/aosp/external/hello$ gedit hello.c
#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;
}
24:在hello目录中增加Android.mk
joe@joe-Aspire-Z3730:/media/sdb4/aosp/external/hello$ gedit Android.mk
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)
25:在hello目录中编译模块
joe@joe-Aspire-Z3730:/media/sdb4/aosp/external/hello$ mm
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=5.1.1
TARGET_PRODUCT=aosp_arm
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.11.0-15-generic-x86_64-with-Ubuntu-12.04-precise
HOST_BUILD_TYPE=release
BUILD_ID=LMY47Z
OUT_DIR=out
============================================
make: Entering directory `/media/46bb100d-2505-4025-8425-34ecf3129209/aosp'
Import includes file: out/target/product/generic/obj/EXECUTABLES/hello_intermediates/import_includes
target thumb C: hello <= external/hello/hello.c
external/hello/hello.c: In function 'main':
external/hello/hello.c:5:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char** argv)
^
external/hello/hello.c:5:27: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char** argv)
^
target Executable: hello (out/target/product/generic/obj/EXECUTABLES/hello_intermediates/LINKED/hello)
target Symbolic: hello (out/target/product/generic/symbols/system/bin/hello)
Export includes file: external/hello/Android.mk -- out/target/product/generic/obj/EXECUTABLES/hello_intermediates/export_includes
target Strip: hello (out/target/product/generic/obj/EXECUTABLES/hello_intermediates/hello)
Install: out/target/product/generic/system/bin/hello
make: Leaving directory `/media/46bb100d-2505-4025-8425-34ecf3129209/aosp'
#### make completed successfully (4 seconds) ####
26:重新打包Android系统文件system.img:
joe@joe-Aspire-Z3730:/media/sdb4/aosp$ make snod
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=5.1.1
TARGET_PRODUCT=aosp_arm
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.11.0-15-generic-x86_64-with-Ubuntu-12.04-precise
HOST_BUILD_TYPE=release
BUILD_ID=LMY47Z
OUT_DIR=out
============================================
build/core/Makefile:1013: Warning: with dexpreopt enabled, you may need a full rebuild.
make snod: ignoring dependencies
Target system fs image: out/target/product/generic/system.img
Running: mkuserimg.sh out/target/product/generic/system out/target/product/generic/system.img ext4 system 576716800 out/target/product/generic/root/file_contexts
make_ext4fs -T -1 -S out/target/product/generic/root/file_contexts -l 576716800 -a system out/target/product/generic/system.img out/target/product/generic/system
Creating filesystem with parameters:
Size: 576716800
Block size: 4096
Blocks per group: 32768
Inodes per group: 7040
Inode size: 256
Journal blocks: 2200
Label:
Blocks: 140800
Block groups: 5
Reserved block group size: 39
Created filesystem with 1468/35200 inodes and 109538/140800 blocks
out/target/product/generic/system.img maxsize=588791808 blocksize=2112 total=576716800 reserve=5947392
#### make completed successfully (19 seconds) ####
27:重新启动模拟器
joe@joe-Aspire-Z3730:/media/sdb4/aosp$ emulator -kernel ./kernel/goldfish/arch/arm/boot/zImage -system out/target/product/generic/system.img
28:通过adb shell测试应用程序hello
root@generic:/system/bin # ls
-rwxr-xr-x root shell 5356 2018-04-25 16:29 hello
29:通过下面的测试,说明我们写的hello驱动程序和hello应用程序都成功运行了。
root@generic:/system/bin # hello
Read original value:
0.
Write value 5 to /dev/hello.
Read the value again:
5.
root@generic:/system/bin # hello //注意这次执行命令与第一次执行的结果
Read original value:
5.
Write value 5 to /dev/hello.
Read the value again:
5.
默认只有root 用户可读写,而hello_device_open 一般是由上层APP 来调用的,这些APP 一般不具有root 权限,这时候就
导致打开设备文件失败:
Hello Stub: failed to open /dev/hello -- Permission denied.
解决办法是类似于Linux 的udev 规则,打开Android 源代码工程目录下,进入到system/core/rootdir 目录,里面有一个名为
uevent.rc 文件,往里面添加一行:
/dev/hello 0666 root root
备注说明:参考 Android驱动开发全过程(有图有真相)中对此权限操作方面的说明
手机未root 查看data/data/某一app文件信息 笔者的小米3没有root,但是又想方便地查看data/data/目录下的一些文件,直接进入data会提示没有权限,查看的方式为进入data/data/后,运行下面的命令,就能直接进入你应用的包下了,可通用cp或者mv拷贝或移动到sdcard目录进行其他操作
run-as package_name