一個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。
相關文章
- Android HAL 層框架分析以及程式碼示例Android框架
- 在JSON中遇到的一些坑JSON
- linux安裝nginx時遇到的一個坑LinuxNginx
- android merge標籤 的使用 和 遇到的坑Android
- Android中單例模式的幾個坑Android單例模式
- weex與android互動初步接入,遇到的坑Android
- 初學 GoLang 遇到的一個關於時間的坑...Golang
- API 開發中可選擇傳遞 token 介面遇到的一個坑API
- Oracle資料庫中遇到的坑Oracle資料庫
- 記錄一個在 laradock 中執行 NPM install 或 yarn install 遇到的坑NPMYarn
- SpringBoot 專案中配置多個 Jackson 的 ObjectMapper ,以及配置遇到的坑Spring BootObjectAPP
- 遇到 MySQL 8.0.11 的一些坑MySql
- golang最近遇到的一些坑Golang
- 【eclipse遇到的坑】Eclipse
- NSString 遇到的坑
- mpvue遇到的坑Vue
- 記一些vue使用postcss中遇到的坑o(╯□╰)oVueCSS
- [微信小程式]開發中遇到的一些“坑”微信小程式
- 那些前端工作中遇到的坑(01)前端
- 在安裝snipe-it中遇到的坑
- 在 ReactNative 的 App 中,整合 Bugly 你會遇到的一些坑ReactAPP
- 使用Golang時遇到的一些坑Golang
- RSA加密遇到的坑加密
- Laravel Excel 遇到的坑LaravelExcel
- 使用dataX遇到的坑
- 小程式 遇到的坑
- Bootstrap 檔案中使用 $_SERVER ['REQUEST_URI'] 遇到的一個小坑bootServer
- ConfigParser.ConfigParser()中set的一個坑
- Android HAL模組的載入過程Android
- Springboot 開發過程中遇到坑點 (一)Spring Boot
- 記錄我開發工作中遇到HTTP跨域和OPTION請求的一個坑HTTP跨域
- 記一次單例模式遇到的坑單例模式
- 記一次版本升級遇到的坑
- centos下配置nginx遇到的一些基本的坑CentOSNginx
- Fragment中的那些坑——Android進階FragmentAndroid
- springboot整合swagger遇到的坑Spring BootSwagger
- webpack 4 配置遇到的坑Web
- libwebsocket demo以及遇到的坑。Web