embedded linux ,android

2010年10月31日 星期日

以Android HAL 方式擴充 Framework

這邊詳細說明 Jollen Mokoid 專案如何擴充新硬體
首先給出整個架構,可以看到由上而下分成
應用程式層  LedTest.apk
框架層        mokioid.jar 
                --實作 Manager ( 透過 aidl 溝通 )
                --實作 Service
JNI 層        libmokoid_runtime.so
HAL 層       led.goldfish.so 
                
[root@localhost mokoid]# tree
.
|-- Android.mk
|-- apps              //應用程式層 LedTest.apk
|   |-- Android.mk
|   `-- LedTest
|       |-- Android.mk 
|       |-- AndroidManifest.xml
|       `-- src
|           `-- com
|               `-- mokoid
|                   `-- LedTest
|                       |-- LedSystemServer.java
|                       `-- LedTest.java
|-- dma6410xp         //新產品分支設定
|   |-- AndroidBoard.mk    //一般keypad設定在這檔案
|   |-- AndroidProducts.mk //andoird building system
                           //會自動去找這各檔案
|   |-- BoardConfig.mk     //一些board feature例如driver
|   |-- dma6410xp.mk
|-- frameworks        //框架層 mokioid.jar
|   |-- Android.mk
|   `-- base
|       |-- Android.mk
|       |-- core
|       |   `-- java  //Manager層
|       |       `-- mokoid
|       |           `-- hardware
|       |               |-- ILedService.aidl
|       |               `-- LedManager.java
|       `-- service
|           |-- Android.mk
|           |-- com.mokoid.server.xml
|           |-- java  //Service層
|           |   `-- com
|           |       `-- mokoid
|           |           `-- server
|           |               `-- LedService.java
|           `-- jni   //JNI層 libmokoid_runtime.so
|               |-- Android.mk
|               `-- com_mokoid_server_LedService.cpp
`-- hardware          //硬體抽象層 led.goldfish.so
    |-- Android.mk
    `-- modules
        |-- Android.mk
        |-- include
        |   `-- mokoid
        |       `-- led.h
        `-- led
            |-- Android.mk
            `-- led.c

26 directories, 35 files
[root@localhost mokoid]#

dma6410xp 新產品分支設定 
AndroidProduct.mk
PRODUCT_MAKEFILES := \
  $(LOCAL_DIR)/dma6410xp.mk
Dma6410xp.mk
// 繼承generic.mk的設定 包含標準的應用程式等
$(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk)
// 將新增的應用程式加入image中
PRODUCT_PACKAGES += \
 LedTest
// 將此檔案複製到正確的路徑
PRODUCT_COPY_FILES := \    
    vendor/mokoid/frameworks/base/service/com.mokoid.server.xml:
    system/etc/permissions/com.mokoid.server.xml
// 設定name 可用 make PRODUCT-dma6410xp-eng 來編譯image
PRODUCT_NAME := dma6410xp
PRODUCT_DEVICE := dma6410xp
AndroidBoard.mk
LOCAL_PATH := $(call my-dir)

ifeq ($(TARGET_PREBUILT_KERNEL),)
TARGET_PREBUILT_KERNEL := $(LOCAL_PATH)/kernel
endif
BoardConfig.mk
TARGET_CPU_ABI := armeabi
BOARD_USES_GENERIC_AUDIO := true
USE_CAMERA_STUB := true
TARGET_NO_KERNEL := true

hardware 硬體抽象層 
android.mk
//目前路徑
LOCAL_PATH := $(call my-dir)
//清除local變數
include $(CLEAR_VARS)

// c header file路徑
LOCAL_C_INCLUDES += \
 vendor/mokoid/hardware/modules/include/

LOCAL_PRELINK_MODULE := false
// 編譯完的so放在system/lib/hw下
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := led.c
// 模組名稱
LOCAL_MODULE := led.goldfish
// 編譯成.so
include $(BUILD_SHARED_LIBRARY)
led.h
#include <hardware/hardware.h>

#include <fcntl.h>
#include <errno.h>

#include <cutils/log.h>
#include <cutils/atomic.h>

/***************************************************************************/

// 繼承 struct hw_module_t
struct led_module_t {
   struct hw_module_t common;
};

// 繼承 struct hw_module_t
struct led_control_device_t {
   struct hw_device_t common;

   /* open device node 返回的 fd */
   int fd;

   /* callback function 指向 led_on led_off 實作 */
   int (*set_on)(struct led_control_device_t *dev, int32_t led);
   int (*set_off)(struct led_control_device_t *dev, int32_t led);
};

/***************************************************************************/

struct led_control_context_t {
 struct led_control_device_t device;
};

#define LED_HARDWARE_MODULE_ID "led"
led.c
#define LOG_TAG "MokoidLedStub"

#include <hardware/hardware.h>

#include <fcntl.h>
#include <errno.h>

#include <cutils/log.h>
#include <cutils/atomic.h>

#include <mokoid/led.h>

/**
 * Definition of kernel-space driver.
 */
#define LED_DEVICE "/dev/led"
#define LED_C608 1
#define LED_C609 2

static int led_device_close(struct hw_device_t* device)
{
 struct led_control_device_t* ctx = 
               (struct led_control_device_t*)device;

 if (ctx) {
  close(ctx->fd);
  free(ctx);
 }
 return 0;
}

static int led_on(struct led_control_device_t *dev, int32_t led)
{
 int fd;

 LOGI("LED Stub: set %d on.", led);
 fd = dev->fd;

 switch (led) {
  case LED_C608: 
   ioctl(fd, 1, &led);
   break;
  case LED_C609:
   ioctl(fd, 1, &led);
   break;
  default:
   return -1;
 }

 return 0;
}

static int led_off(struct led_control_device_t *dev, int32_t led)
{
 int fd;

 LOGI("LED Stub: set %d off.", led);
 fd = dev->fd;

 switch (led) {
  case LED_C608: 
   ioctl(fd, 2, &led);
   break;
  case LED_C609:
   ioctl(fd, 2, &led);
   break;
  default:
   return -1;
 }

 return 0;
}

static int led_device_open(const struct hw_module_t* module, 
                           const char* name,
                           struct hw_device_t** device) 
{
 struct led_control_device_t *dev;

 dev = (struct led_control_device_t *)malloc(sizeof(*dev));
 memset(dev, 0, sizeof(*dev));

        //初始化 led_control_device_t 
 dev->common.tag =  HARDWARE_DEVICE_TAG;
 dev->common.version = 0;
 dev->common.module = module;
 dev->common.close = led_device_close;

        //設定實作函數指標
 dev->set_on = led_on;
 dev->set_off = led_off;

 *device = &dev->common;

 //open led device node
        dev->fd = open(LED_DEVICE, O_RDONLY);
 if (dev->fd < 0) 
     dev->fd = 2;   /* Error Handler */

 led_off(dev, LED_C608);
 led_off(dev, LED_C609);

success:
 return 0;
}

static struct hw_module_methods_t led_module_methods = {
    open: led_device_open
};

// 一定要 HAL_MODULE_INFO_SYM 這名稱 
const struct led_module_t HAL_MODULE_INFO_SYM = {
    common: {
        tag: HARDWARE_MODULE_TAG,
        version_major: 1,
        version_minor: 0,
        id: LED_HARDWARE_MODULE_ID,
        name: "Sample LED Stub",
        author: "The Mokoid Open Source Project",
        methods: &led_module_methods,
    }

    /* supporting APIs go here. */
};
jni 讓C與Java可以溝通 
android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

//# [optional, user, eng] 
//# eng = required
//# optinal = no install on target
LOCAL_MODULE_TAGS := eng

//# This is the target being built.
LOCAL_MODULE:= libmokoid_runtime

//# Target install path.
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)

//# All of the source files that we will compile.
LOCAL_SRC_FILES:= \
 com_mokoid_server_LedService.cpp

//# All of the shared libraries we link against.
LOCAL_SHARED_LIBRARIES := \
 libandroid_runtime \
 libnativehelper \
 libcutils \
 libutils \
 libhardware

//# No static libraries.
LOCAL_STATIC_LIBRARIES :=

//# Also need the JNI headers.
LOCAL_C_INCLUDES += \
 $(JNI_H_INCLUDE) \
 vendor/mokoid/hardware/modules/include/

//# No specia compiler flags.
LOCAL_CFLAGS +=

//# Don't prelink this library.  For more efficient code, you may want
//# to add this library to the prelink map and set this to true.
LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)
com_mokoid_server_LedServoce.cpp
#define LOG_TAG "MokoidPlatform"
#include "utils/Log.h"

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

#include <jni.h>
#include <mokoid/led.h>

// -----------------------------------------------------------------

struct led_control_device_t *sLedDevice = NULL;

static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led) {

    LOGI("LedService JNI: mokoid_setOn() is invoked.");

    if (sLedDevice == NULL) {
        LOGI("LedService JNI: sLedDevice was not fetched correctly.");
        return -1;
    } else {
        return sLedDevice->set_on(sLedDevice, led);
    }
}

static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led) {

    LOGI("LedService JNI: mokoid_setOff() is invoked.");

    if (sLedDevice == NULL) {
        LOGI("LedService JNI: sLedDevice was not fetched correctly.");
        return -1;
    } else {
        return sLedDevice->set_off(sLedDevice, led);
    }
}

/** helper APIs */
static inline int led_control_open(const struct hw_module_t* module,
        struct led_control_device_t** device) {
    //取得 sLedDevice instance 指標 
    return module->methods->open(module,
            LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
}

static jboolean
mokoid_init(JNIEnv *env, jclass clazz)
{
    led_module_t* module;
    //利用 hw_get_module API 取得 hw_module_t
    if ( hw_get_module(LED_HARDWARE_MODULE_ID, 
         (const hw_module_t**)&module) == 0 ) 
    {
        LOGI("LedService JNI: LED Stub found.");
        if (led_control_open(&module->common, &sLedDevice) == 0) {
         LOGI("LedService JNI: Got Stub operations.");
            return 0;
        }
    }

    LOGE("LedService JNI: Get Stub operations failed.");
    return -1;
}

// --------------------------------------------------------------

static const JNINativeMethod gMethods[] = 
{
    //java call            c function
    {"_init",     "()Z",  (void*)mokoid_init},
    { "_set_on",  "(I)Z", (void*)mokoid_setOn },
    { "_set_off", "(I)Z", (void*)mokoid_setOff },
};

static int registerMethods(JNIEnv* env) {
    static const char* const kClassName =
        "com/mokoid/server/LedService";
    jclass clazz;

    /* look up the class */
    clazz = env->FindClass(kClassName);
    if (clazz == NULL) {
        LOGE("Can't find class %s\n", kClassName);
        return -1;
    }

    /* register all the methods */
    if (env->RegisterNatives(clazz, gMethods,
            sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
    {
        LOGE("Failed registering methods for %s\n", kClassName);
        return -1;
    }

    /* fill out the rest of the ID cache */
    return 0;
}

// ----------------------------------------------------------------

/*
 * 當這個so被VM載入 則呼叫此function
 */
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("ERROR: GetEnv failed\n");
        goto bail;
    }
    assert(env != NULL);

    if (registerMethods(env) != 0) {
        LOGE("ERROR: PlatformLibrary native registration failed\n");
        goto bail;
    }

    /* success -- return valid version number */
    result = JNI_VERSION_1_4;

bail:
    return result;
}
framework 框架層
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
            $(call all-subdir-java-files)
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE := mokoid
LOCAL_SRC_FILES += \
 core/java/mokoid/hardware/ILedService.aidl

include $(BUILD_JAVA_LIBRARY)

# The JNI component
include $(CLEAR_VARS)
include $(call all-makefiles-under,$(LOCAL_PATH))
com.mokoid.server.xml

    

LedService.java
package com.mokoid.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 mokoid.hardware.ILedService;

public final class LedService extends ILedService.Stub {    

    static {
        System.load("/system/lib/libmokoid_runtime.so");
    }

    public LedService() {
        Log.i("LedService", "Go to get LED Stub...");
 _init();
    }

    /*
     * Mokoid LED native methods.
     */
    public boolean setOn(int led) {
        Log.i("MokoidPlatform", "LED On");
 return _set_on(led);
    }

    public boolean setOff(int led) {
        Log.i("MokoidPlatform", "LED Off");
 return _set_off(led);
    }

    private static native boolean _init();
    private static native boolean _set_on(int led);
    private static native boolean _set_off(int led);
}
ILedService.aidl
package mokoid.hardware;

interface ILedService
{
    boolean setOn(int led);
    boolean setOff(int led);
}
LedManager.java
package mokoid.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 mokoid.hardware.ILedService;

/**
 * Class that lets you access the Mokoid LedService.
 */
public class LedManager
{
    private static final String TAG = "LedManager";
    private ILedService mLedService;

    public LedManager() {
 
        mLedService = ILedService.Stub.asInterface(
                             ServiceManager.getService("led"));

 if (mLedService != null) {
            Log.i(TAG, "The LedManager object is ready.");
 }
    }

    public boolean LedOn(int n) {
        boolean result = false;

        try {
            result = mLedService.setOn(n);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in LedManager.LedOn:", e);
        }
        return result;
    }

    public boolean LedOff(int n) {
        boolean result = false;

        try {
            result = mLedService.setOff(n);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in LedManager.LedOff:", e);
        }
        return result;
    }
}
apps 應用程式層
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := user

# This is the target being built.
LOCAL_PACKAGE_NAME := LedTest

# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)

# Link against the current Android SDK.
LOCAL_SDK_VERSION := current

# Also link against our own custom library.
LOCAL_JAVA_LIBRARIES := mokoid framework

# We need to assign platform key to use ServiceManager.addService.
LOCAL_CERTIFICATE := platform

include $(BUILD_PACKAGE)
AndroidManifest.xml


      

    
    
    
    

    
        
        
        
            
                
                
                
                
            
        

        
            
                
                
            
        
    

LedSystemServer.java
package com.mokoid.LedTest;

import com.mokoid.server.LedService;

import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
import android.app.Service;
import android.content.Context;
import android.content.Intent;

public class LedSystemServer extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    public void onStart(Intent intent, int startId) {
        Log.i("LedSystemServer", "Start LedService...");

 /* Please also see SystemServer.java for your interests. */
 LedService ls = new LedService();

        try {
            ServiceManager.addService("led", ls);
        } catch (RuntimeException e) {
            Log.e("LedSystemServer", "Start LedService failed.");
        }
    }
}
LedTest.java
package com.mokoid.LedTest;
import mokoid.hardware.LedManager;
import com.mokoid.server.LedService;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Button;
import android.content.Intent;
import android.view.View;

public class LedTest extends Activity implements View.OnClickListener {
    private LedManager mLedManager = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Start LedService in a seperated process.
        startService(new Intent("com.mokoid.systemserver"));

 // Just for testing. !! PLEASE DON't DO THIS !!
 //LedService ls = new LedService();

        Button btn = new Button(this);
        btn.setText("Click to turn LED 1 On");
 btn.setOnClickListener(this);

        setContentView(btn);
    }

    public void onClick(View v) {

        // Get LedManager.
        if (mLedManager == null) {
     Log.i("LedTest", "Creat a new LedManager object.");
     mLedManager = new LedManager();
        }

        if (mLedManager != null) {
     Log.i("LedTest", "Got LedManager object.");
 }

        /** Call methods in LedService via proxy object 
         * which is provided by LedManager. 
         */
        mLedManager.LedOn(1);

        TextView tv = new TextView(this);
        tv.setText("LED 1 is On.");
        setContentView(tv);
    }
}

沒有留言:

張貼留言