一个android 的HAL示例中遇到的坑。

想在手机上做一些功能的扩展,本来是想从驱动层入手的,但驱动需要改内核。因为,1,手机自带的内核是没有源码的,没有其中的symbal的支持,自编的内核模块是不能在其下用的。2,自编全部内核因为没有电路的硬件信息,基本上没可能了。所以只能从HAL层去入手了。并且因为MTK的不开源性,从HAL层入手,对MTK手机更适当一些。

这样就要先去了解一下HAL吧。

从示例入手最快。网上找到一个mokoid的示例。这个是个教学示例。https://code.google.com/archive/p/mokoid/ google上的示例下了问题很多,要编译的.mk文件都少。github上找了一个,https://github.com/kangear/mokoid-read-only 这个git clone下来,要编译通的话,要改一些地方。

1,目录结构改一下,{android-source}/mokoid/trunk/{https://github.com/kangear/mokoid-read-only所见目录}.这是因为其下的文件中对相互引用时。当然改源码也可以。

2,先要android 源码编译过。android源码我下的是4.4.4 r2。因为真机是这个。这个需要oracle jkd.用openjdk通不过。oracle jkd需要的是1.6的版本,ubuntu的apt已不提供下载,自已找个地方下载bin包,解压。在build目录下,生成envjava.sh如下。

#oracle java 
export JAVA_HOME=/media/ququ/android/tools/jdk1.6.0_45 #解压的JDK目录。
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib
export PATH=$PATH:$JAVA_HOME/bin

进入源码目录要编译前,

source ./build/envjava.sh

source ./build/envsetup.sh

3,进入mokoid/trunk

mmm ./

会有一些报错。依提示不难解决。主要是因不编译环境不同,有些目录找不到,改一源码就可。可以单独进入子目录,用mmm ./去单独编译。

4,如上的都不是坑,很快就能过了。直的坑在下到真机去运行。编译时有提示输出的内容,这些就查要下载到手机中的。输出的内容主要在android-source/out/target/product/generic/system/下的目录去找。

5,android-source/out/target/product/generic/system/app 下,

adb install LedClient.apk 

adb uninstall com.mokoid.LedClient

install时会报错,因为lib找不到。

6,adp push /out/target/product/generic/system/lib/libmokoid_runtime.so  /system/lib

adp push /out/target/product/generic/system/lib/hw/led.default.so  /system/lib/hw

adp push /out/target/product/generic/system/framework/mokoid.jar /system/framework

adp push /out/target/product/generic/system/framework/mokoid.odex /system/framework

这个放到对应的目录,后看一下权限,改成与目录中其它内容一样的权限就可。有时下载下去的会是root只读的。

7,如下做了adb install LedClient.apk还是会报错。    

<uses-library android:name="com.mokoid.server" />
        <!--uses-library android:required="false" android:name="com.mokoid.server" /-->

改工程下的配置文件能让它安装,但不解决问题。

adb push mokoid/trunk/frameworks/base/service/com.mokoid.server.xml  /system/etc/permissions 

注意一下权限。这个改对了,让面的不要改就可以安装通过。

8,全部的内容已放到真机了,可以运行了。

am start com.mokoid.LedClient/com.mokoid.LedClient.LedClient

会闪退的。用adb logcat >1.txt 看一下log.可以发现,JNI_OnLoad LED这个信息就出现Fatal signal 11 (SIGSEGV) at 0x655c9e88 (code=2), thread 2458 (okoid.LedClient)。

JNI_OnLoad LED这个信息是com_mokoid_server_LedService.cpp中的。再进一步是在mokoid_init中的hw_get_module中出错的。hw_get_module在源码目录hardware/libhardware/hardware.c中定义。但改这里是没有做用的,因为它生成的lib民真机中的不一样。但可以看一下去找问题。我定位到是加载led.default.so时出错。具体原因这时因为不能改libhardware就不好定位了。

这时自已写个个可运行的代码,做libhardware的工作去加载这个代码。


#define LOG_TAG "Mokoid"
//#include "utils/Log.h"

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

//#include <jni.h>
//#include <mokoid/led.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "../hardware/modules/include/mokoid/led.h"
#define LIB_CACULATE_PATH "/system/lib/hw/led.default.so"
//#define LIB_CACULATE_PATH "/system/lib/libhardware.so"
#define ALOGE printf

typedef int (*CAC_FUNC)(void *, int);

int main(int argc, char **argv)
{
    int status;
    void *handle;
    const char *error;
    struct hw_module_t *hmi;
    struct hw_module_t **pHmi;
    const char *id="led";
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
CAC_FUNC cac_func = NULL;

    /*
     * load the symbols resolving undefined symbols before
     * dlopen returns. Since RTLD_GLOBAL is not or'd in with
     * RTLD_NOW the external symbols will not be global
     */
    ALOGE("dlopen ..\n");
    handle = dlopen(LIB_CACULATE_PATH, RTLD_NOW);
    if (!handle) {
        char const *err_str = dlerror();
        ALOGE("load: module=%s\n%s", LIB_CACULATE_PATH, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }
  
    *(void **) (&cac_func) = dlsym(handle, "led_on");
    if ((error = dlerror()) != NULL)  {
        fprintf(stderr, "%s\n", error);
        exit(EXIT_FAILURE);
    }
    ALOGE("led_on: 50\n");
    (*cac_func)(NULL,50);

    /* Get the address of the struct hal_module_info. */
     ALOGE("dlsym ..\n");
    hmi = (struct hw_module_t *)dlsym(handle, sym);
    if (hmi == NULL) {
        ALOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }
    ALOGE("hmi->id: %s\n",hmi->id);
    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
        status = -EINVAL;
        goto done;
    }
ALOGE("handle :%d \n",handle);
ALOGE("hmi :%d\n",hmi);
ALOGE("hmi->dso :%d \n",hmi->dso);
ALOGE("hmi->name :%s \n",hmi->name);

    hmi->dso = handle;
ALOGE("handle end ..\n");
    /* success */
    status = 0;

done:
    ALOGE("status : %d \n",status);
    if (status != 0) {
        hmi = NULL;
        if (handle != NULL) {
            dlclose(handle);
            handle = NULL;
        }
    } else {
        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, *pHmi, handle);
    }
    ALOGE("pHmi :%d\n",pHmi);
    *pHmi = hmi;

    return status;
}

同目录下


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:= jnitest

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

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

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

# 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 += -g -static -fPIC -ldl

# 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)

include $(BUILD_EXECUTABLE)

做了这些工作一步步定位到,hmi->dso = handle;这句通不过。呵呵。这个可以代码中坑。要改的地方在。

mokoid/trunk/hardware/modules/led/led.c中。

//const struct led_module_t HAL_MODULE_INFO_SYM = {
struct led_module_t HAL_MODULE_INFO_SYM = {

很明显这个是有意而为。因为有这些坑,用网上的代码,其实不比自已写代码少花多少时间。当然要看坑的大小。

然改对后就没什么问题了,这个代码是可以在真机上运行的。因为它把对驱动的调用代码给删了,只输出log. 真机上是一定没有相应的设备的,所以只能删去相关代码。这个没错。所以上这源码只要改对还有点用。并且我的主要目的是用直接调用HAL。

猜你喜欢

转载自blog.csdn.net/qushaobo/article/details/85274110