對於應用程式訪問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檔案是可以一樣的。當然獨立編譯是最好的,因為我們沒有必要用同時用兩種方法來實現一個功能,擇其善者而用之。
待續為應用程式編寫