时隔多日,终于都抽出时间来写blog了。废话不多说,接着上一篇,这里将介绍如何编写HAL层(硬件抽象层)对应的JNI方法。
这里提到的都是在ICS源码里编译的。
1、定义JNI层接口
进入到android-4.0.4_r1.2/hardware/libhardware/include/hardware目录,并创建 ttt.h 文件,内容如下:
#ifndef ANDROID_TTT_INTERFACE_H#define ANDROID_TTT_INTERFACE_H#include <hardware/hardware.h>__BEGIN_DECLS// 定义模块ID#define HELLO_HARDWARE_MODULE_ID "ttt"// 硬件模块结构体struct ttt_module_t{ struct hw_module_t common;};// hardware interface structstruct ttt_device_t{ struct hw_device_t common; int fd; int(*set_val)(struct ttt_device_t* dev, int val); int(*get_val)(struct ttt_device_t* dev, int* val);};__END_DECLS#endif
2、实现JNI层接口功能
进入到android-4.0.4_r1.2/frameworks/base/services/jni目录,并创建com_android_server_TTTService.cpp文件,其内容如下:
#define LOG_TAG "TTTService"#include "jni.h"#include "JNIHelp.h"#include "android_runtime/AndroidRuntime.h"#include <utils/misc.h>#include <utils/Log.h>#include <hardware/hardware.h>#include <hardware/ttt.h>#include <stdio.h>namespace android{ struct ttt_device_t* ttt_device = NULL; // through the HAL interface to set the register value static void ttt_setVal(JNIEnv* env, jobject clazz, jint value){ int val = value; LOGI("TTT JNI: set value %d to device.", val); if(!ttt_device){ LOGI("TTT JNI: device is not open."); return; } ttt_device->set_val(ttt_device, val); } // through the HAL interface to read the register value static jint ttt_getVal(JNIEnv* env, jobject clazz){ int val = 0; if(!ttt_device){ LOGI("TTT JNI: device is not open."); return val; } ttt_device->get_val(ttt_device, &val); LOGI("TTT JNI: get value %d from device.", val); return val; } // through the HAL interface to open the hardware device static inline int ttt_device_open(const hw_module_t* module, struct ttt_device_t** device){ return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device); } // throught the hardware module ID to load the HAL module and open the device static jboolean ttt_init(JNIEnv* env, jclass clazz){ ttt_module_t* module; LOGI("TTT JNI: initializing..."); if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0){ LOGI("TTT JNI: ttt stub found."); if(ttt_device_open(&(module->common), &ttt_device) == 0){ LOGI("TTT JNI: ttt device is open."); return 0; } LOGE("TTT JNI: failed to open ttt device."); return -1; } LOGE("TTT JNI: failed to get ttt stub module."); return -1; } // JNI methods table static const JNINativeMethod method_table[] = { {"init_native", "()Z", (void*)ttt_init}, {"setVal_native", "(I)V", (void*)ttt_setVal}, {"getVal_native", "()I", (void*)ttt_getVal}, }; // regist JNI method int register_android_server_TTTService(JNIEnv* env){ return jniRegisterNativeMethods(env, "com/android/server/TTTService", method_table, NELEM(method_table)); }};
3、添加JNI初始化调用
修改android-4.0.4_r1.2/frameworks/base/services/jni目录下的 onload.cpp 文件,在 JNI_OnLoad函数中的return之前添加下面一句:
register_android_server_TTTService(env);
同时,在该文件中的namespace中添加下面一句声明:
int register_android_server_TTTService(JNIEnv* env);
这样,在系统初始化时,就会调用register_android_server_TTTService方法来加载JNI方法了。
4、添加编译JNI的配置
修改android-4.0.4_r1.2/frameworks/base/services/jni目录下的 Android.mk 文件,在 LOCAL_SRC_FILES 变量中添加下面一行:
com_android_server_TTTService.cpp \
这里是添加编译配置。
5、开始编译
[email protected]:~/workspace/android-4.0.4_r1.2# . build/envsetup.sh including device/moto/stingray/vendorsetup.shincluding device/moto/wingray/vendorsetup.shincluding device/samsung/crespo4g/vendorsetup.shincluding device/samsung/crespo/vendorsetup.shincluding device/samsung/maguro/vendorsetup.shincluding device/samsung/smdkc110/vendorsetup.shincluding device/samsung/smdkv210/vendorsetup.shincluding device/samsung/torospr/vendorsetup.shincluding device/samsung/toro/vendorsetup.shincluding device/samsung/tuna/vendorsetup.shincluding device/ti/panda/vendorsetup.shincluding sdk/bash_completion/adb.bash[email protected]:~/workspace/android-4.0.4_r1.2#
[email protected]:~/workspace/android-4.0.4_r1.2# mmm frameworks/base/services/jni============================================PLATFORM_VERSION_CODENAME=RELPLATFORM_VERSION=4.0.4TARGET_PRODUCT=fullTARGET_BUILD_VARIANT=engTARGET_BUILD_TYPE=releaseTARGET_BUILD_APPS=TARGET_ARCH=armTARGET_ARCH_VARIANT=armv7-aHOST_ARCH=x86HOST_OS=linuxHOST_BUILD_TYPE=releaseBUILD_ID=IMM76I============================================make:进入目录'/home/brantyou/workspace/android-4.0.4_r1.2'target thumb C++: libandroid_servers <= frameworks/base/services/jni/com_android_server_HelloService.cpptarget thumb C++: libandroid_servers <= frameworks/base/services/jni/com_android_server_TTTService.cpptarget thumb C++: libandroid_servers <= frameworks/base/services/jni/onload.cppmake: *** 没有规则可以创建“out/target/product/generic/obj/SHARED_LIBRARIES/libandroid_servers_intermediates/LINKED/libandroid_servers.so”需要的目标“out/target/product/generic/obj/lib/libsystem_server.so”。 停止。make:离开目录“/home/brantyou/workspace/android-4.0.4_r1.2”[email protected]:~/workspace/android-4.0.4_r1.2#
矮油~~~这里出错了,提示没有找到 libsystem_server.so 文件。
执行下面的命令,生成 libsystem_server.so 文件:
[email protected]:~/workspace/android-4.0.4_r1.2# make libsystem_server
生成之后的提示:
Install: out/target/product/generic/system/lib/libvorbisidec.soInstall: out/target/product/generic/system/lib/libstagefright_yuv.soInstall: out/target/product/generic/system/lib/libdrmframework.soInstall: out/target/product/generic/system/lib/libchromium_net.soInstall: out/target/product/generic/system/lib/libstagefright_amrnb_common.soInstall: out/target/product/generic/system/lib/libstagefright_enc_common.soInstall: out/target/product/generic/system/lib/libstagefright_avc_common.soInstall: out/target/product/generic/system/lib/libstagefright.soInstall: out/target/product/generic/system/lib/libstagefright_omx.soInstall: out/target/product/generic/system/lib/libmediaplayerservice.soInstall: out/target/product/generic/system/lib/libinput.soInstall: out/target/product/generic/system/lib/libsystem_server.so[email protected]:~/workspace/android-4.0.4_r1.2#
好了,这个问题解决了,我们继续编译这个JNI。
[email protected]:~/workspace/android-4.0.4_r1.2# mmm frameworks/base/services/jni============================================PLATFORM_VERSION_CODENAME=RELPLATFORM_VERSION=4.0.4TARGET_PRODUCT=fullTARGET_BUILD_VARIANT=engTARGET_BUILD_TYPE=releaseTARGET_BUILD_APPS=TARGET_ARCH=armTARGET_ARCH_VARIANT=armv7-aHOST_ARCH=x86HOST_OS=linuxHOST_BUILD_TYPE=releaseBUILD_ID=IMM76I============================================make:进入目录'/home/brantyou/workspace/android-4.0.4_r1.2'target SharedLib: libandroid_servers (out/target/product/generic/obj/SHARED_LIBRARIES/libandroid_servers_intermediates/LINKED/libandroid_servers.so)target Symbolic: libandroid_servers (out/target/product/generic/symbols/system/lib/libandroid_servers.so)target Strip: libandroid_servers (out/target/product/generic/obj/lib/libandroid_servers.so)Install: out/target/product/generic/system/lib/libandroid_servers.somake:离开目录“/home/brantyou/workspace/android-4.0.4_r1.2”[email protected]:~/workspace/android-4.0.4_r1.2#
很好,这一次已经顺利的编译完了。
下面我们需要重新打包这个 system.img,包我们编写的JNI方法包含进去:
[email protected]:~/workspace/android-4.0.4_r1.2# make snod============================================PLATFORM_VERSION_CODENAME=RELPLATFORM_VERSION=4.0.4TARGET_PRODUCT=fullTARGET_BUILD_VARIANT=engTARGET_BUILD_TYPE=releaseTARGET_BUILD_APPS=TARGET_ARCH=armTARGET_ARCH_VARIANT=armv7-aHOST_ARCH=x86HOST_OS=linuxHOST_BUILD_TYPE=releaseBUILD_ID=IMM76I============================================make snod: ignoring dependenciesTarget system fs image: out/target/product/generic/system.imgout/target/product/generic/system.img total size is 44107008[email protected]:~/workspace/android-4.0.4_r1.2#
这样就成功的把我们编写的JNI打包到 system.img中了。
这章到此结束,下一章将介绍,如何基于JNI接口编写对应的服务和编写对应的Android程序来访问服务。