android Q HIDL(小屏显示)
android Q HIDL(小屏顯示)
手機設備上添加了一個小的lcd屏,需求是可以顯示文字與圖片.且可以在每個應用里面使用,過CTS,那么可供選擇的實現方式也就沒幾種了.
?
(a)過cts的話最好是通過hidl與底層驅動通訊,hidl使用起來也挺方便.
(b)驅動使用的數據為32*40大小的char,大約1kB多點,數據量較小采用序列化的數據傳輸,不選擇使用共享內存
(c)需要滿足應用可使用則需要提供java接口,目前屬于調試階段,無法判斷后期第三方應用是否能使用,故選擇已有的DisplayManager服務 ,擴展其接口,有點是SE權限好控制,缺點是數據在傳輸過程中多了一次copy.
(d)數據的生成是采用從Bitmap中獲取像素點的方式.畢竟是需要圖片顯示的,同時圖片為了適配lcd顯示的大小,也要使用Canvas縮小或者擴大其Bitmap.
(一)添加hw hal module
(1)添加h532blcd.default hal模塊,創建h532blcd_t,同時生成HAL_MODULE_INFO_SYM.
#define H532BLCD_MODULE_API_VERSION_1_1 HARDWARE_MODULE_API_VERSION(1, 1) #define H532BLCD_HARDWARE_MODULE_ID "h532blcd"typedef struct h532blcd_module {struct hw_module_t common; } h532blcd_module_t;typedef struct h532blcd {struct hw_device_t common;int (*lcd_send_data)(struct h532blcd *dev,const signed char *data);} h532blcd_t;/** Generic device handling*/ static int h532blcd_open(const hw_module_t* module, const char* name,hw_device_t** device) {if (device == NULL) {__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "NULL device on open");return -EINVAL;}__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "Device open");h532blcd_t *dev = malloc(sizeof(h532blcd_t));memset(dev, 0, sizeof(h532blcd_t));dev->common.tag = HARDWARE_DEVICE_TAG;dev->common.version = 0;dev->common.module = (struct hw_module_t*) module;dev->common.close = h532blcd_close; #if 1dev->lcd_send_data = lcd_send_data; #endif*device = (hw_device_t*) dev;return 0; }static struct hw_module_methods_t h532blcd_module_methods = {.open = h532blcd_open, };h532blcd_module_t HAL_MODULE_INFO_SYM = {.common = {.tag = HARDWARE_MODULE_TAG,.module_api_version = H532BLCD_MODULE_API_VERSION_1_1,.hal_api_version = HARDWARE_HAL_API_VERSION,.id = H532BLCD_HARDWARE_MODULE_ID,.name = "h532blcd",.author = "The Android Open Source Project",.methods = &h532blcd_module_methods,}, };(2)打開設備節點與處于內核空間的lcd屏進行數據傳輸
typedef struct {unsigned char data[32*40]; // 1280 } __attribute__((packed))pixData;#define H532BLCD_SEND_DATA _IOW('C', 0x01, pixData)static int fd = -1;extern int open_dev(); extern int close_dev(); extern int send_data(pixData *data);(3)生成h532blcd.default.so文件至vendor/lib64/hw/h532blcd.default.so vendor/lib/hw/h532blcd.default.so.
注意H532BLCD_HARDWARE_MODULE_ID的值必須與生成的so文件前綴相同,這個是hal注冊的關鍵
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optional LOCAL_HEADER_LIBRARIES := libhardware_headers LOCAL_SHARED_LIBRARIES := liblog libcutils LOCAL_SRC_FILES := ioctl_h532blcd.c hw_h532blcd.c LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_MODULE := h532blcd.default LOCAL_INIT_RC := init.h532blcd.rcinclude $(BUILD_SHARED_LIBRARY)(4)修改設備節點權限 init.h532blcd.rc
on boot # h532blcdchmod 0666 /dev/h532blcdc(5)添加SE權限
device.te type simplelcd_device, dev_type;file_contexts /dev/h532blcdc u:object_r:simplelcd_device:s0(二)注冊hidl服務
開機后運行
(1)創建manifest.xml
<manifest version="1.0" type="device"><hal format="hidl"><name>vendor.hct.hardware.simplelcd</name><transport>hwbinder</transport><impl level="generic"></impl><version>1.0</version><interface><name>ISimpleLcd</name><instance>default</instance></interface></hal> </manifest>(2)創建hal文件ISimpleLcd.hal,同時運行hardware/interfaces/update-makefiles.sh自動生成Android.bp文件
package vendor.hct.hardware.simplelcd@1.0;interface ISimpleLcd {lcd_send_data(int8_t[1280] arg) generates (int32_t result); }(3)創建可執行文件vendor.hct.hardware.simplelcd@1.0-service
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS) LOCAL_MODULE := vendor.hct.hardware.simplelcd@1.0-service LOCAL_INIT_RC := vendor.hct.hardware.simplelcd@1.0-service.rc LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_SRC_FILES := \SimpleLcd.cpp \service.cpp \LOCAL_SHARED_LIBRARIES := \libcutils \liblog \libhidlbase \libhidltransport \libhardware \libutils \vendor.hct.hardware.simplelcd@1.0 \include $(BUILD_EXECUTABLE)vendor.hct.hardware.simplelcd@1.0-service.rc
service simplelcd_hal /vendor/bin/hw/vendor.hct.hardware.simplelcd@1.0-service# "class hal" causes a race condition on some devices due to files created# in /data. As a workaround, postpone startup until later in boot once# /data is mounted.class late_startuser systemgroup system inputSimpleLcd.cpp
namespace vendor { namespace hct { namespace hardware { namespace simplelcd { namespace V1_0 { namespace implementation {SimpleLcd *SimpleLcd::sInstance = nullptr;SimpleLcd::SimpleLcd() : mDevice(nullptr){LOGD("SimpleLcd()");sInstance = this; // keep track of the most recent instancemDevice = openHal(); } SimpleLcd::~SimpleLcd() {LOGD("~SimpleLcd()");if (mDevice == nullptr) {LOGD("No valid device");return;}int err;h532blcd_t* dev = reinterpret_cast<h532blcd_t*>(mDevice);if (0 != (err = dev->common.close(mDevice))) {LOGD("Can't close h532blcd module, error: %d", err);return;}mDevice = nullptr; }ISimpleLcd* SimpleLcd::getInstance() {if (!sInstance) {sInstance = new SimpleLcd();}return sInstance; } Return<int32_t> SimpleLcd::lcd_send_data(const hidl_array<int8_t, 1280>& arg){if(mDevice == NULL){return -1;}h532blcd_t* dev = reinterpret_cast<h532blcd_t*>(mDevice);LOGD("hal Device lcd_send_data \n");return dev-> lcd_send_data(dev,arg.data()); } hw_device_t* SimpleLcd::openHal(){hw_device_t* dev = nullptr;hw_module_t const* module;int err = hw_get_module(H532BLCD_HARDWARE_MODULE_ID, &module);if (err != 0) {LOGD("Can't open SimpleLcd detect HW Module, error: %d", err);return nullptr;}err = module->methods->open(module, "h532blcd", &dev);if (err < 0) {LOGD("Can't open SimpleLcd Detect, error: %d", err);return nullptr;}LOGD("Open SimpleLcd hal");return dev; }} //namespace implementation } //namespace V1_0 } //namespace simplelcd } //namespace hardware } //namespace hct } //namespace vendorservice.cpp
#define LOG_TAG "vendor.hct.hardware.simplelcd@1.0-service"#include <android/log.h> #include <hidl/HidlSupport.h> #include <hidl/HidlTransportSupport.h> #include <vendor/hct/hardware/simplelcd/1.0/ISimpleLcd.h> #include "SimpleLcd.h"using vendor::hct::hardware::simplelcd::V1_0::ISimpleLcd; using vendor::hct::hardware::simplelcd::V1_0::implementation::SimpleLcd; using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using android::sp;int main() {android::sp<ISimpleLcd> bio = SimpleLcd::getInstance();configureRpcThreadpool(1, true /*callerWillJoin*/);if (bio != nullptr) {bio->registerAsService();} else {ALOGE("Can't create instance of BiometricsFingerprint, nullptr");}joinRpcThreadpool();return 0; // should never get here }(三)frameworks曾添加接口
(1)frameworks/base/services/core/Android.bp
static_libs: ["vendor.hct.hardware.simplelcd-V1.0-java",],(2)frameworks/base/core/java/android/hardware/display/IDisplayManager.aidl
/** @hide */ interface IDisplayManager {// Temporarily sets the display brightness.void setSimpleLcdShow(in byte[] data); }(3)frameworks/base/core/java/android/hardware/display/DisplayManager.java
提供兩個接口(a)setSimpleLcdText顯示文字(b)setSimpleLcdDrawable顯示圖片
/*** @param text The text for LCD show.** @hide*/public void setSimpleLcdText(CharSequence text){Log.d("SimpleLcdDrawable","text ++ ");if (Looper.getMainLooper() != Looper.myLooper()) {throw new RuntimeException("setSimpleLcdText must called in MainThread!");}Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);paint.setStyle(Paint.Style.FILL);paint.setColor(Color.BLACK);setLedTextSize(paint,DEFAULT_TEXT_SIZE);measureTextBound(paint,text.toString(),LCD_HORIZONTAL_END,LCD_VERTICAL_END);byte[] data = generateLedBitmap(renderText(text.toString(), paint));Log.d("SimpleLcdDrawable","text -- ");mGlobal.setSimpleLcdShow(data);}/*** @param drawable The drawable for LCD show.** @hide*/public void setSimpleLcdDrawable(Drawable drawable){Log.d("SimpleLcdDrawable","drawable ++ ");if (Looper.getMainLooper() != Looper.myLooper()) {throw new RuntimeException("setSimpleLcdDrawable must called in MainThread!");}Drawable ledImage = drawable;byte[] data = generateLedBitmap(renderDrawable(ledImage, LCD_HORIZONTAL_END, LCD_VERTICAL_END));Log.d("SimpleLcdDrawable","drawable -- ");mGlobal.setSimpleLcdShow(data);}/*** set the text size* @param paint paint* @param size text size*/private void setLedTextSize(Paint paint ,float size) {Log.d("SimpleLcdText", "setLedTextSize :" + size);float ledTextSize = size;paint.setTextSize(ledTextSize);if(ledTextSize > 30){paint.setTypeface(Typeface.DEFAULT_BOLD);}else {paint.setTypeface(Typeface.MONOSPACE);}}/*** measure the text width and height* @param paint paint* @param text text content* @param width the Led Width* @param height the Led Height*/private void measureTextBound(Paint paint,String text, int width, int height) {Paint.FontMetrics m = paint.getFontMetrics();measureTextWidth = (int) paint.measureText(text);measureTextHeight = (int) (m.bottom - m.ascent);float sacle = Math.min((float) width / measureTextWidth, (float) height / measureTextHeight);if(sacle < 1){setLedTextSize(paint, paint.getTextSize() * sacle);measureTextBound(paint, text,width,height);}}/*** Transform text to bitmap** @param text text content* @param paint paint* @return the bitmap of text*/private Bitmap renderText(CharSequence text, Paint paint) {Bitmap bitmap = Bitmap.createBitmap(measureTextWidth, measureTextHeight, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);int yPos = (int) ((canvas.getHeight() / 2) - ((paint.descent() + paint.ascent()) / 2));canvas.drawText(text.toString(), 0, yPos, paint);return bitmap;}/*** Transform the image drawable to bitmap** @param drawable the content drawable* @param width the Led Width* @param height the Led Height* @return bitmap of drawable*/private static Bitmap renderDrawable(Drawable drawable, int width, int height) {Bitmap bitmap = getBitmapFromDrawable(drawable);float sacle = Math.min((float) width / bitmap.getWidth(), (float) height / bitmap.getHeight());if(sacle < 1){return Bitmap.createScaledBitmap(bitmap,(int)(bitmap.getWidth() * sacle),(int)(bitmap.getHeight() * sacle), true);}else {return bitmap;}}/*** Get bitmap from drawable, Copy from CircleImageView** @param drawable the drawable* @return the bitmap of drawable*/private static Bitmap getBitmapFromDrawable(Drawable drawable) {if (drawable == null) {return null;}if (drawable instanceof BitmapDrawable) {return ((BitmapDrawable) drawable).getBitmap();}try {Bitmap bitmap;if (drawable instanceof ColorDrawable) {bitmap = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888);} else {bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ALPHA_8);}Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());drawable.draw(canvas);return bitmap;} catch (Exception e) {e.printStackTrace();return null;}}/*** Transform a bitmap to a led bitmap** @param src the original bitmap* @return led bitmap*/private byte[] generateLedBitmap(Bitmap src) {byte[] data = new byte[LCD_VERTICAL_END * LCD_HORIZONTAL_END/8];int bitmapH = src.getHeight();int bitmapW = src.getWidth();int paddStart = (LCD_HORIZONTAL_END - bitmapW)/2;int paddTop = (LCD_VERTICAL_END- bitmapH)/2;//StringBuffer stringBuffer = new StringBuffer();for(int y = 0; y < src.getHeight();y++){for(int x = 0;x < src.getWidth();x++){int color = isInRange(src, x , y);int lcdX = paddStart + x;int lcdY = paddTop + y;int dataID = (lcdX/8 + lcdY*32);int byteId = 7 - lcdX%8;if (color != 0) {data[dataID] = (byte) (data[dataID] | (0x1<<byteId));//stringBuffer.append("1");}else {//stringBuffer.append("0");}}//stringBuffer.append("\n");}//Log.d("SimpleLcdDrawable",stringBuffer.toString());return data;}/*** Measure if x and y is in range of leds** @param bitmap the origin bitmap* @param x led x* @param y led y* @return the color , if color is zero means empty*/private int isInRange(Bitmap bitmap, int x, int y) {if (bitmap == null)return 0;if (y> 0 && y < bitmap.getHeight()&& x > 0 && x < bitmap.getWidth()) {int px = bitmap.getPixel(x, y);if(px == 0){return 0;}return Color.argb(0xff, 0x00, 0x00, 0x00);}else {return 0;}}(4)frameworks/base/core/java/android/hardware/display/DisplayManagerGlobal.java
實現IDisplayManager.aidl的接口
/**** @param data The data for LCD.** @hide*/public void setSimpleLcdShow(byte[] data) {if(data != null && data.length == 1280){StringBuffer stringBuffer = new StringBuffer();for (int iLine=0; iLine<40; iLine++) {for(int i = iLine*32; i < (iLine*32+31); i++) {byte pointChar = data[i];for(int j=7; j>=0; j--) {if((pointChar>>j&0x1)!= 0){stringBuffer.append("1");}else{stringBuffer.append("0");}}}if (DEBUG) {Log.d("SimpleLcdDrawable",stringBuffer.toString());}stringBuffer.setLength(0);}}else {throw new RuntimeException("setSimpleLcdShow data.length must 1280 ,but now is " + (data == null ? 0:data.length));}try {mDm.setSimpleLcdShow(data);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}}(5)frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
實現IDisplayManager.aidl接口,同時通過hidl傳遞到hal層
@Override // Binder callpublic void setSimpleLcdShow(byte[] data) {final long token = Binder.clearCallingIdentity();try {Slog.d(TAG, "setSimpleLcdShow");if (mSimpleLcd != null) {int result = mSimpleLcd.lcd_send_data(data);Slog.d(TAG, "setSimpleLcdShow dev(0) result = " + result);}else{mSimpleLcd = ISimpleLcd.getService();Slog.d(TAG, "ISimpleLcd.getService");int result = mSimpleLcd.lcd_send_data(data);Slog.d(TAG, "setSimpleLcdShow dev(0) result = " + result);}}catch (RemoteException re){Slog.d(TAG, "setSimpleLcdShow re = " + re.getMessage());} finally {Binder.restoreCallingIdentity(token);}}(6)添加system_service能掉hidl的權限
system_server.te allow system_server hal_simplelcd_hwservice:hwservice_manager find;(四)調用實例
通過getSystemService獲取到DisplayManager,然后調用setSimpleLcdText("HELLO")就可以在lcd屏上看到顯示了.
?
總結
以上是生活随笔為你收集整理的android Q HIDL(小屏显示)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【实用算法教学】——Apriori算法,
- 下一篇: 转载:与其亡羊补牢,不如血战群狼。——2