对于应用程序访问jni库,是可以直接访问,即写个active,然后调用System.load函数,jni库加载进来,然后直接调用其中的api函数,从而实现操作硬件功能。但这不是android所规范的作法。
一般来说在framework写一些中间东西,我们称之为服务service。
关于android中的服务概念在android应用程序编写教程中,都会提及到,其中都提到服务的生命周期,此处不详细展开。
接下就着重点放在这个服务的实现上。
1 gpio serviced
在service目录下创建framework/service/java/com/ask/serviced/目录,即
cd framework
mkdir -p service/java/com/ask/serviced
再创建serviced.java文件,文件名应该就是类名。
内容如下:
package com.ask.server; //生成的包名为com.ask.server
import android.util.Config;
import android.util.Log;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
public final class serviced
{
static
{
System.load("/system/lib/libaskgpio.so"); //加载jni库文件
}
public serviced()
{
Log.i("GpioService", "Go to get Gpio Stub...");
_gpio_init();
}
/*
* Ctop Gpio native methods.
*/
public boolean GpioSet(int gpio)
{
Log.i("AskPlatform", "Gpio set");
return _gpio_set(gpio);
}
public boolean GpioClr(int gpio)
{
Log.i("AskPlatform", "Gpio clr");
return _gpio_clr(gpio);
}
private static native boolean _gpio_init();
private static native boolean _gpio_set(int gpio);
private static native boolean _gpio_clr(int gpio);
}
其中:
private static native boolean _gpio_init();
private static native boolean _gpio_set(int gpio);
private static native boolean _gpio_clr(int gpio);
是声明libaskgpio.so库中的函数,这样才可以给java程序调用。
Android.mk的编写,内容如下:
LOCAL_PATH := $(call my-dir)
# the library
# =============================================================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := /
$(call all-subdir-java-files)
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE := ask
include $(BUILD_JAVA_LIBRARY)
# The JNI component
include $(CLEAR_VARS)
include $(call all-makefiles-under,$(LOCAL_PATH))
保存到framework目录下
在应用程序中,要加入一些permissions才能使用这个java包,这个将在下节的应用程序中说明。
2 gpio service manager
在1中所描述的是service 可供应用程序直接调用,而在android,对于应用程序中,更规范的做法是通过service manager来调用管理service。即应用程序通过mangger访问jni库
这里面会涉及到aidl,aidl,可简单认为是一个接口。在编译过程中,会将aidl文件,编译成java文件,生成一个接口。
首先在在framework目录创建core/java/ask/hardware/目录
即cd framework目录
mkdir -p core/java/ask/hardware/
创建GpioManager.java文件和IGpioService.aidl文件
GpioManager.java内容如下:
package ask.hardware;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.util.Log;
import ask.hardware.IGpioService;
/**
* Class that lets you access the Ctop GpioService.
*/
public class GpioManager
{
private static final String TAG = "GpioManager";
private IGpioService mGpioService;
public GpioManager()
{
mGpioService = IGpioService.Stub.asInterface(ServiceManager.getService("Gpio")); //获取gpio的service,
if (mGpioService != null)
{
Log.i(TAG, "The GpioManager object is ready.");
}
}
public boolean GpioSet(int n)
{
boolean result = false;
try
{
result = mGpioService.GpioSet(n);
}
catch (RemoteException e)
{
Log.e(TAG, "RemoteException in GpioManager.Gpio set:", e);
}
return result;
}
public boolean GpioClr(int n)
{
boolean result = false;
try
{
result = mGpioService.GpioClr(n);
}
catch (RemoteException e)
{
Log.e(TAG, "RemoteException in GpioManager.Gpio clr:", e);
}
return result;
}
}
其中: mGpioService = IGpioService.Stub.asInterface(ServiceManager.getService("Gpio"));是获取gpio的service,这时gpio service不是1中所编写的gpio service内容,要重要编写,稍后给出。
IGpioService.aidl的内容如下:这个比较简单
package ask.hardware;
interface IGpioService
{
boolean GpioSet(int gpio);
boolean GpioClr(int gpio);
}
生成ask.hardware与GpioManager生成的包是一致的。
最后缩写gpioservice代码
这个与1所编写的 gpio serviced,类似。如下:
在framework/service目录下创建java/com/ask/service/目录,即
cd framework
mkdir -p service/java/com/ask/service
cd service/java/com/ask/service
在此目录下创建GpioSerivce.java,内容如下
package com.ask.server;
import android.util.Config;
import android.util.Log;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import ask.hardware.IGpioService;
public final class GpioService extends IGpioService.Stub
{
static
{
System.load("/system/lib/libaskgpio.so");
}
public GpioService()
{
Log.i("GpioService", "Go to get Gpio Stub...");
_gpio_init();
}
/*
* Ctop Gpio native methods.
*/
public boolean GpioSet(int gpio)
{
Log.i("CTOPPlatform", "Gpio set");
return _gpio_set(gpio);
}
public boolean GpioClr(int gpio)
{
Log.i("CTOPPlatform", "Gpio clr");
return _gpio_clr(gpio);
}
private static native boolean _gpio_init();
private static native boolean _gpio_set(int gpio);
private static native boolean _gpio_clr(int gpio);
}
应该说GpioService类与serviced类是比较相似的,只是GpioService继承于IGpioService.Stub。
Android.mk文件的编写
LOCAL_PATH := $(call my-dir)
# the library
# =============================================================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := /
$(call all-subdir-java-files)
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE := ask
# AIDL
LOCAL_SRC_FILES += /
core/java/ask/hardware/IGpioService.aidl
include $(BUILD_JAVA_LIBRARY)
# The JNI component
include $(CLEAR_VARS)
include $(call all-makefiles-under,$(LOCAL_PATH))
保存此文件到framework目录下
然后编译。
两种的service目录结构如下:
framework-|
|->core->java->ask->hardware-|
| |->GpioManager.java
| |->IGpioService.aid
|->service-|
| |->java->com->ask-|
| | |->service->GpioService.java
| | |->serviced->serviced.java
| |->jni->|
| |->Android.mk
| |->com_ask_gpio.cpp
|->Android.mk
最后make的时候可以在out/target/product/generic/system/framework目录下看到ask.jar包。
注,以上两种service方式在framework目录下的Android.mk文件是可以一样的。当然独立编译是最好的,因为我们没有必要用同时用两种方法来实现一个功能,择其善者而用之。
待续为应用程序编写