J2me及其移植
1. 简介
Java ME 以往称作J2ME(Java Platform,Micro Edition),是为机顶盒、移动电话和PDA之类嵌入式消费电子设备提供的Java语言平台,包括虚拟机和一系列标准化的Java API。
JAVA ME的架构分为Configuration、Profile和Optional Packages(可选包)。它们的组合取舍形成了具体的运行环境。系统结构图如下:
J2ME系统结构图
Configuration主要是对设备纵向的分类,分类依据包括存储和处理能力,其中定义了虚拟机特性和基本的类库。已经标准化的Configuration有- Connected Limited DeviceConfiguration(CLDC)和Connected Device Configuration(CDC)。
Profile建立在Configuration基础之上,一起构成了完整的运行环境。它对设备横向分类,针对特定领域细分市场,内容主要包括特定用途的类库和API。CLDC上已经标准化的Profile有Mobile Information Device Profile (MIDP)和Information Module Profile(IMP),而CDC上标准化的Profile有Foundation Profile(FP)、Personal Basis Profile(PBP)和Personal Profile(PP)。
实质上配置就是用来支持硬件、简表用来支持应用程序。
可选包独立于前面两者提供附加的、模块化的和更为多样化的功能。目前标准化的可选包包括数据库访问、多媒体应用、蓝牙等等。
1.2 J2ME Configuration(CDC-CLDC)
J2ME configuration包含的内容
configuration(配置)包括虚拟机(virtual machine),核心的类库与API。configuration层定义一个java虚拟机的特性与java类库的最小子集。也就是说,configuration层提供了开发人员一个最基础,最核心的Java平台。
CDC与CLDC
CDC (Connected Device Configuration,连接设备配置),运行在这一配置上的程序称为J2ME Application,在CVM上进行解释。
CLDC(Connected Limited DeviceConfiguration,连接限制设备配置),运行在这一配置上的程序称为MIDlet ,在KVM上进行解释。
J2ME中的虚拟机
在 J2ME 中有两类虚拟机:CVM (C Virtual Machine,C虚拟机)与 KVM (K Virtual Machine,K虚拟机)。KVM 和 CVM均可被看作是一种 Java 虚拟机,是 JVM 的子集,在功能上都是 JVM 的缩减版。这两类虚拟机的适用范围并不相同,简单地说,CVM 的功能比KVM 功能更为强大。
这里再补充一点,J2ME还包括对了Java Card 的定义,用于各类IC卡。JavaCard 和CDC/CLDC在J2ME中是相同的地位。
CLDC 与CDC的对比
| CDC | CLDC |
硬件设备参数 | 针对32位的处理器主频通常在75MHz以上,内存可能在1~4MB | CPU为16位、32位主频在 16MHz以上的处理器,设备的内存比较少,可能只有512KB,甚至更少。现在硬件的发展非常快,以前所定义的CLDC的设备目前的设备甚至远远超过原来的定义。不过请注意一下,J2ME 对CLDC设备配置的定义只是一个最低要求的定义。要分辨CLDC设备主要从设备特点上进行区别 |
支持设备种类 | 数字电视、机顶盒、网络电话、车载计算设备等 | Nokia 7650,Nokia 3650, PDA设备、智能手机等 |
设备特点: | 有线连接 电源稳定 设备外设资源比较受限 | 无线连接 没有稳定的电源供应(通常使用电池) 设备外设资源极少 |
API | CDC 是建立在 CLDC 顶部的 API,是整个 J2SE API 的一个更完整的子集。它还包含一个额外的软件包 -- javax.microedition.io 软件包 -- 包含 CLDC 中定义的所有相同的类和接口,及其它。 | ·CLDC API 实际上只是 J2SE 的一个子集,它包括 java.lang、java.io 和 java.util, javax.microedition。 ·CLDC API 文档的副本位于安装 J2ME CLDC 时创建的 j2me_cldc/docs 目录下。 |
1.3 J2ME简表(MIDP等)
J2ME简表(Profile)的作用
简表用来描述特定的设备,是支持特定设备(某类功能的设备)的API的集合,以JAVA类的形式提供。所以它是建立在特定的配置(Configration)之上的。
简表和纲要简表
在纲要简表上,您可以创建自己的简表,这种纲要简表也称为基础表,它对于 CDC 也是可用的。
常用简表
Ø MIDP (Mobile Information Devices Profile,移动信息设备简表):定义了移动信息设备的类型和提供相关的API集合, MIDP 所定义的功能更加面向用户,而且比 CLDC 更高级。
Ø IMP (Mobile Information Device Profile,信息模块简表):定义了提供网络连接,但是显示方式比较单一的设备简表,例如告警器。
Ø Foundation Profile(基础简表):提供除了用户界面以外 J2SE 所能够提供的标准类库。
Ø Personal Profile(个人简表):针对那些资源相对有限,但是对网络访问要求很高,基于AWT图形界面的设备,例如Web-TV、汽车导航系统等。
Ø KJava 包含一个特定于 Sun 的、运行在 Palm 操作系统上的 API。这个 KJava API 和 J2SE 抽象视窗工具包 (AWT) 有很多地方都是相同。然而,由于它不是一个标准的 J2ME 软件包,它的主软件包是 com.sun.kjava。它不作为一种完整的、功能齐全的简表,而是作为一种示范,示范简表如何与 CLDC 一起工作。
配置与简表的搭配
CLDC – MIDP、Kjava
CDC – FP、PP、PFP
2. phoneme (advance) 移植
2.1 phoneme的由来
Sun公司于2000年发布CLDC 1.0规范及KVM的参考实现,之后于2006年将KVM参考实现转到开源社区。SUN公司虽然把JAVA的实现开源了,但仍然保留JAVA这个名字,所以出于法律上的考虑,开源的J2ME实现改名为phoneme。
Phoneme有两个版本,一个对硬件要求较低,功能也较弱,适用于一般的feature phone,取名为phoneME Feature。 另一个对硬件要求较高,功能更强大,适用于一般的smart phone,取名为phoneME Advanced。
2.2 移植CVM到ARM平台(Android 83000)
考虑到Android83000的硬件配置,我们选择phoneme advance进行移植。
1) 下载:
http://download.java.net/mobileembedded/phoneme/advanced/phoneme_advanced-mr2-dev-src-b97-20_nov_2008.zip
2) 修改:
/cdc/build/linux-arm-generi/GNUmakefile:
CVM_TARGET_TOOLS_PREFIX=/usr/local/arm/4.3.2/bin/arm-linux-改为自己的交叉编译器的地址
USE_AAPCS ?= false 改为 true
CVM_DEFINES += -DAAPCS # [arm程序调用标准选项]
\cdc\src\linux-arm\javavm\runtime\segvhandler_arch.c:
#define ucontextasm_ucontext
#include<asm/ucontext.h>
改为
//#define ucontextasm_ucontext //注释掉这句
#include<ucontext.h> //去掉arm/
3) 编译:
make
4) 结果:
可以看到在当前目录有 bin lib testclasses.zip
将它们PUSH进Android系统的data/j2me目录。
5) 运行测试:
chmod 777 cvm
./cvm -cp ../testclassesHelloWorld
出现熟悉的HelloWorld打印。
./cvm -cp ../testclasses.zipTest
结果中有:*CONGRATULATIONS: test Test completed with 411 tests passed and 0failures
cvm移植完成。
2.3 基于DirectFB的 phoneme(advance)移植
前面我们完成了CVM的移植,编译配置时,只配置了Configuration,没有配置Profile,所以,此cvm只能运行依赖基础库的J2ME程序,并且不支持图形界面显示;于是我们选用MIDP的作为Profile配置,而MIDP中已包含了对directFB接口的支持。目标移植平台依然选择Android 83000。
前置资源:
j2sdk1.4.2_15(www.oracle.com)
DirectFB-1.2.9(www.directfb.org)
2.3.1 MIDP配置编译
为了方便,我们编写一个脚本build.sh,将环境变量与编译命令置于一起,内容如下:
#!/bin/sh
export MEHOME=$PWD
export CPU_ALIAS="arm"
export JDK_DIR=/home/dh.yuan/softWare/j2sdk1.4.2_15
export DIRECTFB_INSTALL_DIR=/home/dh.yuan/softWare/directFB_inst
export PCSL_PLATFORM=linux_arm_gcc
export PATH=$JDK_DIR/bin:$PATH
export JDK_HOME=$JDK_DIR
exportCLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PCSL_OUTPUT_DIR=$MEHOME/pcsl/output
export CDC_DIR=$MEHOME/cdc
exportCDC_DIST_DIR=$CDC_DIR/build/linux-$CPU_ALIAS-generic/
export TOOLS_DIR=$MEHOME/tools
export CLDC_DIST_DIR=$CDC_DIST_DIR
cd $MEHOME/pcsl
make clean
make NETWORK_MODULE=bsd/generic
cd $MEHOME
CDC_DIST_DIR=$MEHOME/cdc/build/linux-arm-generic
echo CDC_DIST_DIR=$CDC_DIST_DIR
cd $CDC_DIST_DIR
make clean
make USE_MIDP=true CVM_DEBUG=true USE_DIRECTFB=trueUSE_QT_FB=false CVM_PRELOAD_LIB=true
cd $MEHOME
*注意:JDK_DIR变量与DIRECTFB_INSTALL_DIR变量,请根据实际情况调整。
关于CVM_PRELOAD_LIB=true选项,这个选项的作用,是在链接的时候,直接把库链接到cvm上,如果编译的时候不带这个选项,或者把cvm直接编成个库,编译phoneme时,不会有什么问题;但是,如果不带这个选项,编译出来的cvm,运行MIDlet程序时,会出现错误,错误提示如下:
java.lang.UnsatisfiedLinkError:com.sun.midp.main.Configuration.getProperty0
这是由于作为基础本地类库的midp包,在CVM运行时没有被找到,无论是加入-Xbootclasspath参数,还是设置环境变量,都无法解决。而加入CVM_PRELOAD_LIB=true选项后,编译会出现如下错误:
src/highlevelui/directfb_application/reference/native/directfbapp_export.c:173:undefined reference to `DirectFBInit'
这是由于连接编译时,没有加入-ldirectfb,修改/cdc/build/share/rules.mk:1000行左右,改为:
$(CVM_LINK_CMD) -ldirectfb -lfusion -ldirect -lpthread-ldl -L/home/dh.yuan/softWare/directFB_inst/lib/
上面的参数中-L/…部分,请根据您自己交叉编译的directFB的安装路径进行调整。
2.3.2 MIDlet程序编写(HelloWorld)
MIDlet(Mobile Information Devicesapplet),即移动信息设备小程序. 是在支持MIDP 的设备上运行的MIDP 应用。它仅利用MIDP 和CLDC 规范所定义的各种应用程序编程接口API(Application Programmer's Interface)。该应用必须继承MIDlet 类以便让应用管理软件来控制这个MIDlet、从应用描述器中获. 取各种属性,以及对各种状态变化进行通知和请求。
编写MIDlet程序,熟悉Eclipse的朋友可以搭建j2me开发环境(Eclipse+jdk1.4+wtk)进行编辑;此处,因为我们已经下好了j2sdk1.4.2,前面编译出来的midp中又有MIDlet依赖的基础库,所以我们直接在宿主机linux环境下编译。
建立HelloWorld文件夹,作为工程根目录。
环境变量:
因为cvm的运行环境是jdk1.4,所以编译环境也需要使用jdk1.4,我们将下好的j2sdk1.4.2加入环境变量(现在这个年代,一般默认的jdk肯定不是1.4):
export JAVA_HOME=/home/dh.yuan/softWare/j2sdk1.4.2_15
export PATH=${JAVA_HOME}/bin:$PATH
注:JAVA_HOME变量请根据实际解压路径进行调整。
MANIFEST编写:
建立META-INF/MANIFEST.MF文件,内容如下:
Manifest-Version: 1.0
MIDlet-Name: HelloWorld
MIDlet-1: HelloWorld,/icon.png,HelloWorld
MIDlet-Version: 1.0
MIDlet-Vendor: Yuan Dahua
MIDlet-Icon: /icon.png
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0
Main-Class: HelloWorld
注:其中MIDlet-Name,Main-Class项必须有。
编写源码:
建立HelloWorld.java,录入如下内容:
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
public class HelloWorld extends MIDlet implementsCommandListener
{
private Formform;
publicHelloWorld()
{
form = newForm("Test App");
form.append("Hello World!");
form.addCommand( new Command( "Exit", Command.EXIT, 1 ) );
form.setCommandListener( this );
}
public voidstartApp()
{
Displaydisplay = Display.getDisplay(this);
display.setCurrent( form );
}
public voidpauseApp()
{
}
public voiddestroyApp(boolean unconditional)
{
form =null;
}
public voidcommandAction(Command c, Displayable d)
{
destroyApp(true);
notifyDestroyed();
}
}
编写Makefile:
为了方便,我们在java工程中加入Makefile把命令整理进去。
PREFIX=/home/dh.yuan/phoneme/develop/phoneme_advanced_mr2/cdc/build/linux-arm-generic
JFLAGS=-bootclasspath $(PREFIX)/midp/midp_linux_fb_gcc/classes:$(PREFIX)/btclasses
.SUFFIXES: .class .java
.java.class:
javac $(JFLAGS) $<
all: HelloWorld.class
zip HelloWorld.jarHelloWorld.class META-INF/MANIFEST.MF
clean:
rm -f *.class *.jar
注:PREFIX参数,请根据实际路径调整。
编译:
make
编译完成后,生成HelloWorld.jar供平台上使用。
2.3.3 DirectFB移植
DirectFB是一个轻量级的提供硬件图形加速,输入设备处理和抽象的图形库,它集成了支持半透明的视窗系统以及在LinuxFramebuffer驱动之上的多层显示。它是一个用软件封装当前硬件无法支持的图形算法来完成硬件加速的层。DirectFB是为嵌入式系统而设计。它是以最小的资源开销来实现最高的硬件加速性能。
我在官网下过几个版本的directFB编译,发现新版本总是会有或多或少的问题,最后,选择的是DirectFB-1.2.9作移植。
1) 修改/midp/src/highlevelui/directfb_application/reference/native/
directfbapp_export.c,支持SDL显示。
static char *argv_array[] = {
"CVM",
"--dfb:force-windowed" /* use windows instead of surfaces */
",no-vt-switch" /* do not switch between Linux' VT */
",no-cursor" /* do not use pointer */
// ",no-deinit-check" /*do not check for deinit */
,NULL
};
2) 设置交叉编译工具:
export CC=arm-none-linux-gnueabi-gcc
export CXX=arm-none-linux-gnueabi-g++
export CXXLD=arm-none-linux-gnueabi-ld
3) 使用configure进行配置:
./configure --enable-sdl--prefix=/home/dh.yuan/softWare/directFB_inst --host=arm-linux
注:--prefix指定安装目录[默认/usr/local],--host指定交叉编译器。另外,configure的配置还有很多项,如字体、键盘等,可能通过./configure –help进行查看。
4) 编译,安装:
make
make install
5) 修改framebuffer设备
到此为止,交叉编译好的directFB已经安装在—prefix指定的目录中了,如果目标平台是一个linux平台,则可以直接安装即可运行,但是我们的目标平台是一个类Linux的Android平台,其framebuffer设备位置与普通Linux系统不一样(Linux系统中framebuffer设备在/dev/fb0,而Android中则是/dev/graphics/fb0)。
所以,需要对framebuffer设备进行修改。
其中,/gfxdrivers/davinci/davinci_gfxdriver.c,两处:
/systems/fbdev/fbdev.c,一处:
然后,重新:make; make install
现在,安装目录下的内容,只要PUSH进Android83000,即可运行。
2.3.4 phoneme advance(DirectFB)测试
接下来,我们要在目标平台上运行基于DirectFB的cvm,测试MIDlet程序HelloWorld。
cvm,directFB安装
将/cdc/build/linux-arm-generic/下的bin,lib,midp三个文件夹PUSH进Android 83000的/data/j2me/目录:
将2.3.3节directFB安装目录下的内容PUSH进Android 83000的/data/directFB/目录:
运行环境配置:
首先,添加DirectFB的配置/etc/directfbrc(若没有要自己创建):
system=sdl
mode=240x320
添加directFB环境变量:
exportLD_LIBRARY_PATH=/data/directFB/lib:$LD_LIBRARY_PATH
export PATH=/data/directFB/bin:$PATH
exportDFBARGS=module-dir=/data/directFB/lib/directfb-1.2-9
如果没有上面的声明,directFB运行时,可能会出现以下错误:
libdirectfb-1.2.so.9: cannot open sharedobject file
DirectFB/core/system: Nosystem found
安装Midlet:
./midp/midp_linux_fb_gcc/bin/arm/installMidlet file:data/j2me/HelloWorld.jar
上面的路径要用绝对路径,这个HelloWorld.jar就是上面我们编译的Midlet程序最后生成的jar包。安装成功后,会在串口中打印出一个该Midlet的ID。如下,所示:
The suite was succesfully installed, ID: 3
运行Midlet:
./midp/midp_linux_fb_gcc/bin/arm/runMidlet 3 HelloWorld
directFB将在framebuffer中画出一块区域显示Midlet的内容(HelloWorld)。
卸载Midlet:
./midp/midp_linux_fb_gcc/bin/arm/removeMidlet.sh3
*注:上面使用的三个脚本,如果直接使用会出现问题,需要作如下修改:
installMidlet、removeMidlet.sh:去掉第一行的” #!/bin/sh”,因为Android系统中是没有对应路径的。
runMidlet:将” /home/dh.yuan/phoneme/develop/phoneme_advanced_mr2/
cdc/build/linux-arm-generic/”改为”/data/j2me/”
3 J2ME移植总结
本文对J2ME及其开源phoneme进行了简要介绍,并选取了一个phoneme advance版本进行了移植,移植分为两个种:一种基础虚拟机CVM,一种配置了MIDP的CVM。文中详细描述了移植过程,及遇到的问题和解决方法。最后完成了移植。
虽然配置了MIDP的CVM已经可以运行图形Midlet应用,但是,如果需要支持声音,中字,输入法等,则还需要进行移植和修改。并且,配置了MIDP的CVM占用空间约25.6M。
对于java应用来说,J2ME确实是一个些许过时的方案,目前主流的java应用的目标平台是Android,为J2ME开发应用的团体也不多。Phonemefeature更新到2009年,advance更新到2008年后就没有再更新了,而且关于这方面的文档与论坛资源相当稀少。