2010年7月5日星期一

How to use NDK and Eclipse to setup and build a Android JNI project under Ubuntu 10.04

How to use NDK and Eclipse to setup and build a Android JNI project under Ubuntu 10.04

Assume the following software are installed:
- Eclipse 3.5.1
- Android SDK (version 8)
- ADT 0.9.7
- Android NDK r4

1. Use Eclipse and ADT to create a Android project. Remember to set a right min. version for your project.
More information can be found from Android SDK document, Android NDK section.

2. Declare your native functions and load library functions.

Here is a simple example:

In ActivityMain.java file, I wrote:

package com.xxx.TestJNI;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class ActivityMain extends Activity {
private static final String TAG = "TestJNI:ActivityMain";

// Declare native functions
public native String getString();

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "OnCreate >>>>>");

super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Log.d(TAG, "String from native library = " + getString());

Log.d(TAG, "OnCreate <<<<<");
}
// load native library
static {
System.loadLibrary("jnitest");
}
}

If "Project-->Build Automatically" option is enabled, Eclipse will generate the corresponding class file in the {bin} folder.
You can find the class file in {project}/bin/{package}/

3. Create {jni} folder under your project folder. I.e. mkdir {project}/jni

4. Create JNI header file:
Type the following command:

javah -classpath {project}/bin -d {project}/jni/ {full package name}.{class name}

For example:
javah -classpath workspace/TestJNI/bin -d workspace/TestJNI/jni/ com.xxx.TestJNI.ActivityMain

where "com.xxx.TestJNI" is the full package name and "ActivityMain" is the class name.

Then you should find a header file in the {jni} folder.

5. Create the corresponding C/C++ file in the {jni} folder and write your codes.
For example:

In the C++ file (com_xxx_TestJNI_ActivityMain.cpp), I wrote:

#include "com_xxx_TestJNI_ActivityMain.h"
// we want to use android logging functions such that we can use Logcat for debugging
#include <android/log.h>

#define TAG "TestJNI:jnitest"

// this function will be called when the library is loaded
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
// we want to use JDK/JRE 1.4 functions so we will return JNI 1.4 version to JAVA VM
// Otherwise, JAVA VM assumes we want to use JDK/JRE 1.1 functions
// More information can be found from JAVA Native Interface Specification (In the JDK documentation)

JNIEnv *env = 0;
jint result = -1;

__android_log_print(ANDROID_LOG_DEBUG, TAG, "On Load...");

if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
__android_log_print(ANDROID_LOG_WARN, TAG, "JNI 1.4 is not supported!");
return result;
}

result = JNI_VERSION_1_4;

return result;
}

JNIEXPORT jstring JNICALL Java_com_xxx_TestJNI_ActivityMain_getString(JNIEnv *env, jobject obj) {

__android_log_print(ANDROID_LOG_DEBUG, TAG, "Create and return String object");

return env->NewStringUTF("Hello native world");
}

Here, we can see that I use "env->NewStringUTF("Hello native world")" to create a String object.
However, if your source file is C, then you have to change the line to "(*env)->NewStringUTF(env, "Hello native world")".

You can find more information from {NDK}/build/platforms/android-(X)/arch-arm/usr/include/jni.h.
(X) = the selected android system version.

In fact, you can search all functions which can be used from {NDK}/build/platforms/android-(X)/arch-arm/usr/include/.
Also, you can read {NDK}/docs/STABLE-APIS.TXT for a quick reference.
For JNI programming, please read JDK 6 Documentation, Java Native Interface section.

6. Create a Make file (Android.mk) in {project}/jni:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := jnitest
LOCAL_SRC_FILES := com_xxx_TestJNI_ActivityMain.cpp
LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)

For the module name (LOCAL_MODULE), it should be as same as what you use for the System.loadLibrary() call in your JAVA source file.

For more information about Make file, please read {NDK}/docs/OVERVIEW.TXT and {NDK}/docs/ANDROID-MK.TXT

7. Build the native shared library.
Type the following commands:

cd {project}
{NDK}/ndk-build -B V=1

For more information about build process, please read {NDK}/docs/OVERVIEW.TXT and {NDK}/docs/NDK-BUILD.TXT

8. Rebuild your android project

Suppose the native library was built successfully, in Eclipse, select "Project-->Clean..." and then Eclipse will rebuild the project again.

Now, you can use DDMS, Logcat and software simulator/hardware to test your application.

2010年7月4日星期日

Setup QEMU under Ubuntu 8.04

1. Install QEMU package

2. Setup network bridge

2.1 install uml-utilities and bridge-utils package
2.2 setup bridge configuration:

In /etc/network/interfaces file, add the following lines:

iface br0 inet dhcp
bridge_ports eth0
bridge_fd 9
bridge_hello 2
bridge_maxage 12
bridge_stp off

auto br0

2.3 Disable Ubuntu roaming function for eth0

In the terminal, type network-admin. And then set eth0 to use "Static IP address".
Assign IP, subnet mask and gateway to eth0. After that, you should see the setting in /etc/network/interfaces file.
For example:

iface eth0 inet static
address 192.168.1.100
netmask 255.255.0.0
gateway 192.168.1.254

auto eth0

Then edit /etc/network/interfaces file to comment the line "auto eth0":

#auto eth0

2.4
Since we want to add default gateway to the bridge interface,
we can create a shell script in the /etc/network/if-up.d folder:

#! /bin/sh

#Not for loopback!
if [ "$IFACE" != "lo" ]; then
/sbin/route add -host 192.168.251.1 gw 192.168.252.254 dev $IFACE
fi

In the above script, route will be ran for each interface when network service is started.
You can adjust it to fit your situation.

3. Prepare qemu script for network bridge

In /etc/qemu-ifup file, add the following lines:

echo "Executing /etc/qemu-ifup"
echo "Bringing up $1 for bridged mode..."
sudo /sbin/ifconfig $1 0.0.0.0 promisc up
echo "Adding $1 to br0..."
sudo /usr/sbin/brctl addif br0 $1
sleep 2

4. Restart network service

sudo /etc/init.d/network restart

Normally, there is no IP for eth0 and br0 has a IP address.

5. Prepare system disk image

6. run Qemu

use qemu command to start the simulation. For example:

sudo qemu -hda sysimage.img -net nic,model=rtl8139 -net tap -serial /dev/ttyS0

-hda sysimage.img = the disk image (sysimage.img) is mapped to hda
-net,model=rtl8139 = use rtl8139 network card for the simulator (input)
-net tap = use TAP/TUN dirver (output), this dirver is already connected to the network bridge
-serial /dev/ttyS0 = enable serial port emulation and map guest's serial port to the host's port (/dev/ttyS0)

7. You can use "ping" command to check the network connection.

If the guest Linux system cannot detect the serial port, we can use "modprobe 8250" command and then you see the following output:

Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
serial8250: ttyS0 at I/O 0x3f8 (irq = 4) is a 16450

That means qemu will use 16450 chip set to emulate serial port for the guest linux system.

2010年7月3日星期六

Netbeans 有關 PHP Debug 設定

如果不想在 Debug PHP 的過程中每次進入新的 PHP 頁時停下來,我們可以在 Options-->PHP-->General 中不選擇 Stop at First Line 就可以了.