Android架构分析之基于Android系统的C应用程序开发

 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文件,其代码如下:

[cpp] view plain copy print ?
  1.  1#include <stdio.h>  
  2.  2#include <unistd.h>  
  3.  3#include <fcntl.h>  
  4.  4#include <string.h>  
  5.  5#include <sys/types.h>  
  6.  6#include <sys/stat.h>  
  7.  7  
  8.  8#define DEVICE_FILE "/dev/example"  
  9.  9  
  10. 10int main(int argc, char *argv[])  
  11. 11{  
  12. 12    int ret = 0, num = 12, val = 0, fd = 0;  
  13. 13  
  14. 14    fd = open(DEVICE_FILE, O_RDWR);  
  15. 15    if(fd < 0)  
  16. 16    {  
  17. 17        printf("open device error!\n");  
  18. 18        return -1;  
  19. 19    }  
  20. 20  
  21. 21    ret = write(fd, &num, sizeof(int));  
  22. 22    if(ret < 0)  
  23. 23    {  
  24. 24        printf("write device error!\n");  
  25. 25        return -1;  
  26. 26    }  
  27. 27  
  28. 28    printf("write val %d to device!\n", num);  
  29. 29  
  30. 30    ret = read(fd, &val, sizeof(int));  
  31. 31    if(ret < 0)  
  32. 32    {  
  33. 33        printf("read device error!\n");  
  34. 34        return -1;  
  35. 35    }  
  36. 36  
  37. 37    printf("read val = %d\n", val);  
  38. 38  
  39. 39    return 0;  
  40. 40}  
 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系统中,其内容如下:

 

[cpp] view plain copy print ?
  1. 1LOCAL_PATH:= $(call my-dir)  
  2. 2include $(CLEAR_VARS)  
  3. 3  
  4. 4LOCAL_SRC_FILES := $(call all-subdir-c-files)  
  5. 5  
  6. 6LOCAL_MODULE := example_test  
  7. 7LOCAL_MODULE_TAGS := optional  
  8. 8include $(BUILD_EXECUTABLE)  
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成功了。

你可能感兴趣的:(android,C应用程序开发)