使用Android NDK和Java测试Linux驱动
ndk_test_word_count.c文件用于访问word_count驱动。该文件包含两个供Java访问的函数,分别用来读取/dev/wordcount设备文件中的单词数和向/dev/wordcount设备文件写入字符串。下面先看看ndk_test_word_count.c文件的完整代码。
除了表6-1所示的Java简单类型外,还有一些数据类型需要在JNI代码中与其对应。表6-2是这些数据类型在JNI中的描述符。

从表6-2所示的数据类型对照关系很容易想到本例中的"(Ljava/lang/String;)[B"是什么意思。jstring_to_pchar函数调用的是如下的getBytes方法的重载形式。
public byte[] getBytes(String charsetName) throwsUnsupportedEncodingException
在JNI中调用Java方法需要指定方法参数和返回值的数据类型。在JNI中的格式如下:
"(参数类型)返回值类型"
getBytes方法的参数类型是String,根据表6-2的描述,String类型中JNI在的描述符是"Ljava/lang/String; "。getBytes方法的返回值类型是byte[]。这里就涉及到一个数组的表示法。在JNI中数组使用左中括号([]表示,后面是数组中元素的类型。每一维需要使用一个“[”。byte[]是一维字节数组,所以使用"[B"表示。如果是byte[][][],应使用"[[[B"表示。如果Java方法未返回任何值(返回值类型是void),则用V表示。如void mymethod(int value)的参数和返回值类型可表示为"(I)V"。
Android NDK程序还需要一个Android.mk文件,代码如下:
读者需要先在PC上运行build.sh脚本文件安装word_count驱动。然后单击“从/dev/wordcount读取单词数”按钮,会在按钮下方输出当前/dev/wordcount设备文件中统计出的单词数。读者也可以在输入框中输入一个由空格分隔的字符串,然后单击“向/dev/wordcount写入字符串”按钮,再单击“从/dev/wordcount读取单词数”按钮,就会统计出字符串中包含的单词数,效果如图6-19所示。
下面看一下本例中Java部分(WordCountNDKTestMain.java)的完整代码。
package mobile.android.word.count.java;import java.io.FileInputStream;import java.io.FileOutputStream;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class WordCountJavaTestMain extends Activity{ private TextView tvWordCount; private EditText etString; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tvWordCount = (TextView) findViewById(R.id.textview_wordcount); etString = (EditText) findViewById(R.id.edittext_string); } // “从/dev/wordcount读取单词数”按钮的执行代码 public void onClick_ReadWordCountFromDev(View view) { // 显示单词数 tvWordCount.setText("单词数:" + String.valueOf(readWordCountFromDev())); }// “向/dev/wordcount写入字符串”按钮的执行代码 public void onClick_WriteStringToDev(View view) { // 向/dev/wordcount设备文件写入字符串 writeStringToDev(etString.getText().toString()); Toast.makeText(this, "已向/dev/wordcount写入字符串", Toast.LENGTH_LONG).show(); } // 下面是用Java实现的操作/dev/wordcount设备文件的代码 // 读取/dev/wordcount设备文件中的单词数 private int readWordCountFromDev() { int n = 0; byte[] buffer = new byte[4]; try { // 打开/dev/wordcount设备文件 FileInputStream fis = new FileInputStream("/dev/wordcount"); // 从设备文件中读取4个字节 fis.read(buffer); // 将4个字节转换成int类型的值 n = ((int) buffer[0]) << 24 | ((int) buffer[1]) << 16 | ((int) buffer[2]) << 8 | ((int) buffer[3]); fis.close(); } catch (Exception e) { } return n; } // 向/dev/wordcount设备文件中写入字符串 private void writeStringToDev(String str) { try { // 打开/dev/wordcount设备文件 FileOutputStream fos = new FileOutputStream("/dev/wordcount"); // 写入字符串 fos.write(str.getBytes("iso-8859-1")); fos.close(); } catch (Exception e) { } }}本例的运行效果和使用方法与上一节的例子类似。读者可以运行随书光盘或虚拟环境中的例子与上一节的例子进行比较。
在Android模拟器和Ubuntu上测试Linux驱动本文节选至《Android深度探索(卷1):HAL与驱动开发》,接下来几篇文章将详细阐述如何开发ARM架构的Linux驱动,并分别利用android程序、NDK、可执行文件测试Linux驱动。可在ubuntu Linux、Android模拟器和S3C6410开发板(可以选购OK6410-A开发板,需要刷Android)
- 2楼nexttake昨天 22:11
- 你好,李老师,我把你得word_count驱动源代码拷贝到n我得android源码得kernel/drivers/目录下,把android.mk文件也考过去了n然后执行mmm kernel/drivers/word_countn出现了下面得错误nnbionic/libc/kernel/arch-arm/asm/arch/io.h:34: error: expected ':', ',', ';', '}' or '__attribute__' before 'offset'nbionic/libc/kernel/arch-arm/asm/arch/hardware.h:148:21: error: omap730.h: No such file or directorynbionic/libc/kernel/arch-arm/asm/arch/hardware.h:149:22: error: omap1510.h: No such file or directorynbionic/libc/kernel/arch-arm/asm/arch/hardware.h:151:22: error: omap16xx.h: No such file or directorynbionic/libc/kernel/common/linux/module.h:53: error: field 'attr' has incomplete typenbionic/libc/kernel/common/linux/module.h:54: error: expected specifier-qualifier-list before 'ssize_t'nbionic/libc/kernel/common/linux/module.h:64: error: field 'kobj' has incomplete typennn我只想编译当前这个驱动,不想为了这个驱动而编译整个android/kernel源码,这个错误是什么原因啊?
- Re: nokiaguy昨天 22:17
- 回复nexttaken编译驱动必须整个kernel要编译一遍,第二次就不用了,因为驱动程序要使用kernel中的其他library的。n具体的配置和编译过程可以参考http://blog.csdn.net/nokiaguy/article/details/8631981
- Re: nexttake昨天 22:17
- 回复nokiaguyn我之前使用make -j4 编译过整个android源码,生成了boot.img,这个步骤没有编译linxu内核吗?n您的意思是说 要在android源码/kernel 目录下,执行make命令吗?
- 1楼nexttake昨天 21:20
- 我之前使用make -j4 编译过整个android源码,生成了boot.img,这个步骤没有编译linxu内核吗?n您的意思是说 要在android源码/kernel 目录下,执行make命令吗?