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#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#defineDEVICE_FILE"/dev/example"
- 9
- 10intmain(intargc,char*argv[])
- 11{
- 12intret=0,num=12,val=0,fd=0;
- 13
- 14fd=open(DEVICE_FILE,O_RDWR);
- 15if(fd<0)
- 16{
- 17printf("opendeviceerror!\n");
- 18return-1;
- 19}
- 20
- 21ret=write(fd,&num,sizeof(int));
- 22if(ret<0)
- 23{
- 24printf("writedeviceerror!\n");
- 25return-1;
- 26}
- 27
- 28printf("writeval%dtodevice!\n",num);
- 29
- 30ret=read(fd,&val,sizeof(int));
- 31if(ret<0)
- 32{
- 33printf("readdeviceerror!\n");
- 34return-1;
- 35}
- 36
- 37printf("readval=%d\n",val);
- 38
- 39return0;
- 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" 910int main(int argc, char *argv[])11{12 int ret = 0, num = 12, val = 0, fd = 0;1314 fd = open(DEVICE_FILE, O_RDWR);15 if(fd < 0)16 {17 printf("open device error!\n");18 return -1;19 }2021 ret = write(fd, &num, sizeof(int));22 if(ret < 0)23 {24 printf("write device error!\n");25 return -1;26 }2728 printf("write val %d to device!\n", num);2930 ret = read(fd, &val, sizeof(int));31 if(ret < 0)32 {33 printf("read device error!\n");34 return -1;35 }3637 printf("read val = %d\n", val);3839 return 0;40}
这个C程序打开/dev/example,向该设备寄存器写入一个数字12,再读取设备寄存器,所以读取得到的值应该也是12。
创建development/example_test/Android.mk文件,该文件用于注册本模块到Android系统中,其内容如下:
[cpp] view plain copy print ?- 1LOCAL_PATH:=$(callmy-dir)
- 2include$(CLEAR_VARS)
- 3
- 4LOCAL_SRC_FILES:=$(callall-subdir-c-files)
- 5
- 6LOCAL_MODULE:=example_test
- 7LOCAL_MODULE_TAGS:=optional
- 8include$(BUILD_EXECUTABLE)
1LOCAL_PATH:= $(call my-dir)2include $(CLEAR_VARS)34LOCAL_SRC_FILES := $(call all-subdir-c-files)56LOCAL_MODULE := example_test7LOCAL_MODULE_TAGS := optional8include $(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应用程序消息处理机制(Looper、Handler)分析
- Android中数据存储——文件存储数据
- 转:RTC搭建android下三层应用程序访问服务器MsSql-服务器端
- 老罗的Android之旅——Android应用程序的Activity启动过程简要介
- Android系统集成第三方pre-build库和程序
- 深入探究Android的WebView下载网络文件的盗链问题
- [Android设计模式]Android退出应用程序终极方法