Android版本:2.3.7_r1
Linux内核版本:android-goldfish-2.6.29
本文介绍基于Android系统的C应用程序开发。我们知道,Android应用程序开发使用的是JAVA语言,但有时候我们也需要一些基于命令行的小程序,这些小程序一般使用C语言开发,程序的写法与PC平台的C程序没有区别,但需要把C程序注册到Android系统中,使其能在Android平台上运行。在这篇博客中,我们就写一个基于Android平台的C应用程序,该程序用来访问我们在上篇博客中创建的底层Linux驱动程序example。
创建development/example_test/example_test.c文件,其代码如下:
1#include <stdio.h> 2#include <unistd.h> 3#include <fcntl.h> 4#include <string.h> 5#include <sys/types.h> 6#include <sys/stat.h> 7 8#define DEVICE_FILE "/dev/example" 9 10int main(int argc, char *argv[]) 11{ 12 int ret = 0, num = 12, val = 0, fd = 0; 13 14 fd = open(DEVICE_FILE, O_RDWR); 15 if(fd < 0) 16 { 17 printf("open device error!\n"); 18 return -1; 19 } 20 21 ret = write(fd, &num, sizeof(int)); 22 if(ret < 0) 23 { 24 printf("write device error!\n"); 25 return -1; 26 } 27 28 printf("write val %d to device!\n", num); 29 30 ret = read(fd, &val, sizeof(int)); 31 if(ret < 0) 32 { 33 printf("read device error!\n"); 34 return -1; 35 } 36 37 printf("read val = %d\n", val); 38 39 return 0; 40}
这个C程序打开/dev/example,向该设备寄存器写入一个数字12,再读取设备寄存器,所以读取得到的值应该也是12。
创建development/example_test/Android.mk文件,该文件用于注册本模块到Android系统中,其内容如下:
1LOCAL_PATH:= $(call my-dir) 2include $(CLEAR_VARS) 3 4LOCAL_SRC_FILES := $(call all-subdir-c-files) 5 6LOCAL_MODULE := example_test 7LOCAL_MODULE_TAGS := optional 8include $(BUILD_EXECUTABLE)
要看明白这个Android.mk,需要对Android编译系统有一个全面了解,这里,我不打算全面分析Android编译系统,只对这个Android.mk进行单独的分析。
第1行,定义变量LOCAL_PATH,其内容是通过$(call my-dir)语句调用自定义函数my-dir赋值的。这个my-dir函数定义在build/core/definitions.mk文件中的106-120行,其作用是返回这个Android.mk所在的目录。
第2行,包含变量CLEAR_VARS,这个变量定义在build/core/config.mk文件的第54行:
CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
变量BUILD_SYSTEM定义在build/core/main.mk文件的第46行
BUILD_SYSTEM := $(TOPDIR)build/core
所以,变量CLEAR_VARS就是build/core/ clear_vars.mk。打开该文件,可以看到,这个文件的作用就是将除LOCAL_PATH以外的全部编译相关变量清零。
第4行,设置变量LOCAL_SRC_FILES,其内容是通过$(call all-subdir-c-files)语句调用自定义函数all-subdir-c-files赋值的。all-subdir-c-files函数定义在build/core/definitions.mk文件中的195-202行,其作用是返回当前目录及其子目录下的所有".c"文件文件名。
第6行,设置变量LOCAL_MODULE为example_test。即模块名。
第7行,设置变量LOCAL_MODULE_TAGS为optional。
第8行,包含变量BUILD_EXECUTABLE,该变量定义在build/core/config.mk文件的第60行:
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
即包含build/core/executable.mk,包含这个文件表明是要编译成一个可执行程序。
编写完C程序源码和Android.mk,我们就可以编译C应用程序了。有两种编译方法
方法一:在模块Android.mk所在目录下执行mm命令,系统就会对该模块进行编译。
方法二:在Android主目录下执行mmm 模块路径名,这里即mmm development/example_test,系统也同样能开始对模块进行编译。
mmm和mm分别表示对指定目录和当前目录下的模块进行编译,这两个命令都定义在build/envsetup.sh文件中,我们在编译Android之前,首先要执行source build/envsetup.sh命令,这样才能使用这两个命令。
编译完模块后,在out/target/product/generic/system/bin目录下就能看到example_test程序,这就是我们写的C应用程序。
下一步是重新打包文件系统system.img,把example_test程序包含进文件系统镜像中,命令如下:
# make snod
重新启动Android模拟器:
# emulator -kernel kernel/goldfish/arch/arm/boot/zImage
进入命令行界面,执行C应用程序:
# adb shell
# example_test
write val 12 to device!
read val = 12
可以看到我们的C应用程序example_test访问Linux内核驱动程序example成功了。