以操作rk3399板子上的led为例,上手来写代码!
先弄好环境变量:
source build/envsetup.sh
lunch
(一)编写AIDL文件:
编写ILedService.aidl来描述访问服务接口:
package android.os;
/** {@hide} */
interface ILedService
{
int ledOpen();
int ledCtrl(int status);
int ledClose();
}
core/java/android/os/ILedService.aidl \
(二) 编写Server文件:
1.编写LedService.java:
package com.android.server;
import android.os.ILedService;
//函数名字和aidl文件里一样
public class LedService extends ILedService.Stub {
private static final String TAG = "LedService";
/* call native c function to access hardware */
public int ledOpen() throws android.os.RemoteException
{
return native_ledOpen();
}
public int ledCtrl(int status) throws android.os.RemoteException
{
return native_ledCtrl(status);
}
public int ledClose() throws android.os.RemoteException
{
return native_ledClose();
}
public LedService() {
native_ledOpen();
}
public static native int native_ledOpen();
public static native int native_ledClose();
public static native int native_ledCtrl(int status);
}
2.将LedService.java上传到frameworks/base/services/core/java/com/android/server/
3.Sevice不需要修改 frameworks/base/services/core/Android.mk 它的内容里已经把该目录下所有JAVA文件自动包含进去了:
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
3.修改frameworks/base/services/java/com/android/server/SystemServer.java 找到startOtherServices方法,里面的try {}区域 ,添加如下:
traceBeginAndSlog("StartLedService");//仿照vibrator
/*vibrator = new LedService(context);*/
ServiceManager.addService("led", new LedService());//添加上面的LedService
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
(三) 编写HAL文件:
1.编写led_hal.c文件:
#define LOG_TAG "LedHal"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int fd;
/** Close this device */
static int led_close(struct hw_device_t* device)
{
int ret;
ret = close(fd);
ALOGI("led_demo_open : %d", ret);
return ret;
}
static int led_open(struct led_device_t* dev)
{
fd = open("/dev/led_demo", O_RDWR);//打开/dev下设备
ALOGI("led_demo_open : %d", fd);
if (fd >= 0)
return 0;
else
return -1;
}
static int led_ctrl(struct led_device_t* dev, int status)
{
int ret;
ret = ioctl(fd, status, which);
ALOGI("led_demo_ctrl : %d, %d",status, ret);
return ret;
}
static struct led_device_t led_dev = {
.common = {
.tag = HARDWARE_DEVICE_TAG,
.close = led_close,
},
.led_open = led_open,
.led_ctrl = led_ctrl,
};
static int led_device_open(const struct hw_module_t* module, const char* id,
struct hw_device_t** device)
{
*device = &led_dev;
return 0;
}
static struct hw_module_methods_t led_module_methods = {
.open = led_device_open,
};
//id:led_demo!!!
struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.id = "led_demo",
.methods = &led_module_methods,
};
2.编写led_hal.h文件:
#ifndef ANDROID_LED_INTERFACE_H
#define ANDROID_LED_INTERFACE_H
#include
#include
#include
#include
__BEGIN_DECLS
struct led_device_t {
struct hw_device_t common;
int (*led_open)(struct led_device_t* dev);
int (*led_ctrl)(struct led_device_t* dev, int status);
};
__END_DECLS
#endif // ANDROID_LED_INTERFACE_H
3.将led_hal.h 文件上传到hardware/libhardware/include/hardware/
在hardware/libhardware/modules/目录下新建led目录,并将led_hal.c文件长传到此led目录下。
4.在hardware/libhardware/modules/led/目录下编写Android.mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := led.default
# HAL module implementation stored in
# hw/.default.so
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_C_INCLUDES := hardware/libhardware
LOCAL_SRC_FILES := led_hal.c
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
5.源代码顶层目录下 mmm hardware/libhardware/modules/led
(四) 编写Service文件(JNI接口):
1.编写com_android_server_LedService.cpp文件:
#define LOG_TAG "LedService"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace android
{
static led_device_t* led_device;
jint ledOpen(JNIEnv *env, jobject cls)
{
jint err;
hw_module_t* module;
hw_device_t* device;
ALOGI("native ledOpen ...");
/* 1. hw_get_module */
err = hw_get_module("led_demo", (hw_module_t const**)&module);//和id匹配
if (err == 0) {
/* 2. get device : module->methods->open */
err = module->methods->open(module, NULL, &device);
if (err == 0) {
/* 3. call led_open */
led_device = (led_device_t *)device;
return led_device->led_open(led_device);
} else {
return -1;
}
}
return -1;
}
jint ledClose(JNIEnv *env, jobject cls)
{
ALOGI("native ledClose ...");
return led_device->common.close(NULL);
}
jint ledCtrl(JNIEnv *env, jobject cls, jint status)
{
ALOGI("native ledCtrl %d", status);
return led_device->led_ctrl(led_device, status);
}
static const JNINativeMethod methods[] = {
{"native_ledOpen", "()I", (void *)ledOpen},
{"native_ledClose", "()I", (void *)ledClose},
{"native_ledCtrl", "(I)I", (void *)ledCtrl},
};
int register_android_server_LedService(JNIEnv *env)
{
return jniRegisterNativeMethods(env, "com/android/server/LedService",
methods, NELEM(methods));
}
}
2.将com_android_server_LedService.cpp文件上传到 frameworks/base/services/core/jni/目录
3.修改frameworks/base/services/core/jni/目录下的onload.cpp文件:
在namespace android {} 区域添加声明:
int register_android_server_LedService(JNIEnv *env);
在JNI_OnLoad函数里添加:
register_android_server_LedService(env);
4.修改 frameworks/base/services/core/jni/Android.mk ,LOCAL_SRC_FILES += \ 下面添加:
$(LOCAL_REL_DIR)/com_android_server_LedService.cpp \
5.源代码顶层目录下 mmm frameworks/base/services
(五) 生成映像文件:
1.在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/目录下,取出 classes.jar 文件,编写Android APP代码时需要用到。
2.make snod 生成system.img映像文件。
3.执行nanopi m4的编译脚本:./build-nanopc-t4 -M,进行打包。
最后,从Android M开始,安卓源代码的默认编译器从javac改成了jack,这玩意还真不好用,而且如果不手动停止Jack Server,它还会在后台一直运行,占用内存不放,jack也不会生成中间件classes.jar了,真是麻烦啊。最后还是得执行./build-nanopc-t4 -a -M编译一下Android才看到classes.jar
APP可以参考韦老师的编写:https://github.com/weidongshan/APP_0001_LEDDemo/tree/v7