This article talk about how to test device driver on JNI.
There are two ways to test the device driver :
(1) Create methods to control devices in .c/.cpp file, the .java call the methods in .c/.cpp :
This way is call JNI (Java Native Interface), means java works via native interface in C/C++.
(2) .java control devices via the class in FileInputStream and FileOutputStream.
TIPS :
I test these two methods in eclipse ADT. If you don't know how to write android application program, I think you'd better take some reading in books about android app design and do some practice firstly.
Error TIPS:
If there "R cannot be resolved to a variable" error in your project when created, try "Project -> clean"
1、JNI
(1) Create android project
File -> New -> Android Application Project
(2) Create jni native support
You must get the ndk work tools already and prefix the ndk path :
Windows -> Preferences -> Android -> NDK
Right click the project name :
Android Tools -> Add Native Support
There will be a new directory in project :
jni ——- Andoid.mk |—- wordcntjni.cpp
(3) string.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">wordcntjni</string> <string name="action_settings">Settings</string> <string name="wcstring">JNI test app.</string> <string name="wcwrite">Write</string> <string name="wcread">Read</string> </resources>
(4) activity_main.xml
Graphical Layout :
xml :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <EditText android:id="@+id/editText_wc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="text" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:ems="10" > <requestFocus /> </EditText> <Button android:id="@+id/onClick_wcRead" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignRight="@+id/editText_wc" android:layout_below="@+id/editText_wc" android:onClick="onClick_wcRead" android:text="@string/wcread" /> <Button android:id="@+id/onClick_wcWrite" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/editText_wc" android:layout_toLeftOf="@+id/onClick_wcRead" android:onClick="onClick_wcWrite" android:text="@string/wcwrite" /> <TextView android:id="@+id/textView_wc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/editText_wc" android:layout_below="@+id/onClick_wcWrite" android:text="@string/wcstring" /> </RelativeLayout>
(5) MainActivity.java
package com.example.wordcntjni; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity { private TextView tv_wc; private EditText et_wc; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv_wc = (TextView) findViewById(R.id.textView_wc); et_wc = (EditText) findViewById(R.id.editText_wc); } public void onClick_wcRead (View view) { tv_wc.setText("Read words :" + String.valueOf(readWordCnt())); } public void onClick_wcWrite (View view) { tv_wc.setText("Words write success."); writeWordCnt(et_wc.getText().toString()); } public native int readWordCnt(); public native void writeWordCnt(String str); static { System.loadLibrary("wordcntjni"); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
(6) wordcntjni.cpp wordcntjni.h
Before we edit wordcntjni.cpp, we should create wordcntjni.h first :
$ pwd ~/Software/ADT/project/wordcntjni/jni $ javah -classpath ../bin/classes/ -jni -o wordcntjni.h com.example.wordcntjni.MainActivity
Project clean the eclipse and we would find a new file wordcntjni.h in dir jni.
Finaly, we can edit the wordcntjni.cpp :
#include <jni.h> #include <string.h> #include <fcntl.h> #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include "wordcntjni.h" JNIEXPORT jint JNICALL Java_com_example_wordcntjni_MainActivity_readWordCnt (JNIEnv *env, jobject thiz) { int fd_dev; int num = 0; jint wordcnt = 0; unsigned char buf[4]; //fd_dev = open("/dev/wordcount2", O_RDONLY); fd_dev = open("/data/local/jnitest.txt", O_RDONLY); read(fd_dev, buf, 4); num = ((int) buf[0]) << 24 | ((int) buf[1]) << 16 | ((int) buf[2]) << 8 | ((int) buf[3]) ; wordcnt = (jint) num; close(fd_dev); return wordcnt; } char* jstring_to_pchar(JNIEnv* env, jstring str) { char* pstr = NULL; jclass clsstring = env->FindClass("java/lang/String"); jstring strencode = env->NewStringUTF("utf-8"); jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray byteArray = (jbyteArray) (env->CallObjectMethod(str, mid, strencode)); jsize size = env->GetArrayLength(byteArray); jbyte* pbyte = env->GetByteArrayElements(byteArray, JNI_FALSE); if (size > 0) { pstr = (char*) malloc(size); memcpy(pstr, pbyte, size); } return pstr; } JNIEXPORT void JNICALL Java_com_example_wordcntjni_MainActivity_writeWordCnt (JNIEnv *env, jobject thiz, jstring str) { int fd_dev; //fd_dev = open("/dev/wordcount2", O_WRONLY); fd_dev = open("/data/local/jnitest.txt", O_WRONLY); char* pstr = jstring_to_pchar(env, str); if (pstr != NULL) { write(fd_dev, pstr, strlen(pstr)); } close(fd_dev); }
When compilier the application, the following errors may occur :
[ error1 ]
Android NDK: WARNING: APP_PLATFORM android-14 is larger than android:minSdkVersion 8
[ Fix ]
$ vim /home/linx/Software/Android/ndk/build/core/add-$ application.mk // add the android-8 following android-14 APP_PLATFORM := android-14 APP_PLATFORM := android-8
[ error2 ]
There still the read error couldn't fix yet. The file writing is ok. If you have any idea about this error. I am very please to receive your reply.
2、Java FileStream
We don't need to create the jni files anymore by this way, just test the device in android application.
(1) string.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">file_test</string> <string name="action_settings">Settings</string> <string name="hello_world">Hello, Press button to write file.</string> <string name="wstring">Write</string> <string name="rstring">Read</string> </resources>
(2) activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_below="@+id/textView1" android:layout_marginRight="14dp" android:onClick="onClick_button2" android:text="@string/rstring" /> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/button2" android:layout_alignBottom="@+id/button2" android:layout_toLeftOf="@+id/button2" android:onClick="onClick_button1" android:text="@string/wstring" /> </RelativeLayout>
(3) MainActivity.java
package com.example.file_test; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.TextView; public class MainActivity extends Activity { public TextView fstream; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fstream = (TextView) findViewById(R.id.textView1); } public void onClick_button1 (View view) { writeFile("File text strings."); fstream.setText("File write success."); } public void onClick_button2 (View view) { fstream.setText("File read :" + String.valueOf(readFile())); } private int readFile () { byte[] buffer = new byte[4]; int num = 0; try { FileInputStream fis = new FileInputStream("/data/local/jnitest.txt"); //FileInputStream fis = new FileInputStream("/dev/wordcount2"); fis.read(buffer); ByteBuffer bbuf = ByteBuffer.wrap(buffer); num = bbuf.getInt(); // num = (int)((buffer[0]) & 0xff) << 24 | // (int)((buffer[1]) & 0xff) << 16 | // (int)((buffer[2]) & 0xff) << 8 | // (int)((buffer[3]) & 0xff) ; fis.close(); } catch (Exception e) { } return num; } private void writeFile (String str) { try { FileOutputStream fos = new FileOutputStream("/data/local/jnitest.txt"); //FileOutputStream fos = new FileOutputStream("/dev/wordcount2"); fos.write(str.getBytes("iso-8859-1")); fos.close(); } catch (Exception e) { } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
[error]
This file does't fix the read error too, and the write is also ok. If you have any idea about this error. I am very please to receive your reply.