当前位置:编程学习 > JAVA >>

使用Android NDK和Java测试Linux驱动

在Android系统中Linux驱动主要的使用者是APK程序。因此,Linux驱动做完后必须要用APK程序进行测试才能说明Linux驱动可以正常使用。由于上一节在Android虚拟机上使用C语言编写的可执行程序测试了Linux驱动,因此很容易想到可以利用Android NDK来测试Linux驱动,
由于Android NDK也使用C/C++来编写程序,因此可以利用上一节的C语言代码,当然,还得加上一些AndroidNDK特有的代码。在使用AndroidNDK测试Linux驱动之前需要做如下两件事。
1. 由于Linux驱动模块不会随Android系统启动而装载,因此必须执行build.sh脚本文件安装word_count驱动。
2. 不能使用默认方式启动Android模拟器,而要使用我们自己编译的Linux内核启动Android模拟器,启动模拟器的命令如下:
#  emulator-avd myavd -kernel /root/kernel/goldfish/arch/arm/boot/zImage
为了方便,读者也可以在随书光盘带的Ubuntu Linux虚拟环境中直接执行如下的命令来异步启动Android模拟器。其中emulator.sh文件在/root/drivers目录中。
# sh emulator.sh &
本节的例子已经包含在随书光盘和虚拟环境中,路径如下:
 
随书光盘:<光盘根目录>/sources/ch06/word_count/word_count_ndk
虚拟环境:/root/drivers/ch06/word_count/word_count_ndk
 
word_count_ndk工程的代码部分由WordCountNDKTestMain.java和ndk_test_word_count.c文件组成。工程结构如图6-17所示。
       ndk_test_word_count.c文件用于访问word_count驱动。该文件包含两个供Java访问的函数,分别用来读取/dev/wordcount设备文件中的单词数和向/dev/wordcount设备文件写入字符串。下面先看看ndk_test_word_count.c文件的完整代码。
[cpp]  
#include <string.h>  
#include <jni.h>  
#include <fcntl.h>  
#include <stdio.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <unistd.h>  
#include <stdlib.h>  
//  JNI函数:readWordCountFromDev  
//  用于从/dev/wordcount设备文件读取单词数  
jint Java_mobile_android_word_count_ndk_WordCountNDKTestMain_readWordCountFromDev(  
        JNIEnv* env, jobject thiz)  
{  
  
    int dev;                //  open函数打开/dev/wordcount设备文件后返回的句柄,打开失败返回-1  
    jint wordcount = 0;     //  单词数  
    unsigned char buf[4];   //  以4个字节形式存储的单词数  
  
        //  以只读方式打开/dev/wordcount设备文件  
    dev = open("/dev/wordcount", O_RDONLY);  
  
    //  从dev/wordcount设备文件中读取单词数  
    read(dev, buf, 4);  
  
    int n = 0;              //  存储单词数的int类型变量  
  
    //  将由4个字节表示的单词数转换成int类型的值  
    n = ((int) buf[0]) << 24 | ((int) buf[1]) << 16 | ((int) buf[2]) << 8 | ((int) buf[3]);  
         //  将int类型的单词数转换成jint类型的单词数  
    wordcount = (jint) n;  
    //  关闭/dev/wordcount设备文件  
    close(dev);  
    //  返回单词数  
    return wordcount;  
}  
//  将jstring类型的值转换成char *类型的值  
char* jstring_to_pchar(JNIEnv* env, jstring str)  
{  
    char* pstr = NULL;  
    //  下面的代码会调用Java中的String.getBytes方法获取字符串的字节数  
  
    //  获取java.lang.String类  
    jclass clsstring = (*env)->FindClass(env, "java/lang/String");  
    //  将字符串“utf-8”转换成jstring类型的值  
    jstring strencode = (*env)->NewStringUTF(env, "utf-8");  
    //  获取java.lang.String.getBytes方法  
    jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");  
    //  调用String.getBytes方法将str变量的值转换成jbytearray类型的值  
    jbyteArray byteArray = (jbyteArray)( (*env)->CallObjectMethod(env, str, mid, strencode));  
    //  获取字节长度  
    jsize size = (*env)->GetArrayLength(env, byteArray);  
    //  将jbytearray类型的值转换成jbyte*类型的值  
    jbyte* pbyte = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE);  
    if (size > 0)  
    {  
        //  为char*类型变量pstr分配空间  
        pstr = (char*) malloc(size);  
        //  将pbyte变量中的值复制到pstr变量中  
        memcpy(pstr, pbyte, size);  
    }  
    //  返回转换后的值  
    return pstr;  
}  
//  JNI函数:writeStringToDev  
//  用于向/dev/wordcount设备文件写入字符串  
void Java_mobile_android_word_count_ndk_WordCountNDKTestMain_writeStringToDev(  
        JNIEnv* env, jobject thiz, jstring str)  
{  
  
    int dev;   //  open函数打开/dev/wordcount设备文件后返回的句柄,打开失败返回-1  
    //  以只写方式打开/dev/wordcount设备文件  
    dev = open("/dev/wordcount", O_WRONLY);  
    //  将jstring类型字符串转换成char* 类型的值  
    char* pstr = jstring_to_pchar(env, str);  
    if (pstr != NULL)  
    {  
        //  向/dev/wordcount设备文件写入字符串  
        write(dev,pstr, strlen(pstr));  
    }  
    //  关闭/dev/wordcount设备文件  
    close(dev);  
}  
 
     编写上面的代码有一个重点就是jstring_to_pchar函数。该函数可以将jstring类型的数据转换成char*类型的数据。转换的基本思想就是调用Java方法String.getBytes,获取字符串对应的字节数组(jbyteArray)。由于write函数需要的是char *类型的数据,因此,还必须将jbyteArray类型的数据转换成char *类型的数据。采用的方法是先将jbyteArray类型的数据转换成jbyte类型的数据,然后调用memcpy函数将jbyte类型的数据复制到使用malloc函数分配的char *指针空间中。在jstring_to_pchar函数中有如下的一行代码。
jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B"];
     看到getMethodID方法最后一个参数的值是"(Ljava/lang/String;)[B",可能Android NDK初学者会对此感到困惑,以为是写错了。实际上这是JNI(Android NDK程序实际上就是遵循JNI规则的程序)对方法参数和返回类型的描述。在JNI程序中为了方便描述Java数据类型,将简单类型使用了一个大写英文字母表示,如表6-1所示。
补充:移动开发 , Android ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,