本文以跑步机为假想场景介绍如何在Android Q(10)上添加HIDL,内容涉及HAL、HIDL进程间通讯、多线程以及串口操作,涵盖了标准的Android硬件服务的主要技术。编写时参考了两篇博客(见参考资料)经调试、扩充、查缺补漏而成。记录此文为后来者避坑,代码在RK3399_Android_10代码上验证通过。

目录

一、Hardware Interface

1.1 编写HAL -- 接口定义

1.2 使用hidl-gen生成变量

1.3 实现主程序CPP

1.4 VNDK相关

二、device部分

三、SELinux部分 -- hal service

3.1 vendor目录

3.2 public目录

3.3 private目录

四、framewors层实现

4.1 System Service 实现

4.1.1 Manager

4.1.2 Service端

4.1.3  添加Selinux策略

4.1.4  编译

4.2 APP实现调用

4.2.1 APP调用主Activity

4.2.2 Layout文件

4.2.2 Makefile文件Android.mk

参考资料


一、Hardware Interface

1.1 编写HAL -- 接口定义

源码目录下新建hardware/interfaces/ledtreadmill/1.0目录,然后创建文件

ILedTreadmill.hal (主接口)

package android.hardware.ledtreadmill@1.0;import ILedTreadmillCallback;interface ILedTreadmill {OpenInitSerialPort(string address, int32_t baudrate, int32_t flags);StartRead();//开始读取StopRead();//结束读取RCtlUnlock(int32_t inTime) generates (bool ret);//解锁RCtlLock() generates (bool ret);RCtlSetWeight(int32_t inWeight) generates (bool ret);//设置体重 --  计算卡路里用途 单位0.1千克RCtlSetResumeType(bool inToMinSpeed) generates (bool ret);RCtlStart() generates (int32_t ret);//开始RCtlFastSpeed(int32_t inSpeed) generates (int32_t ret); // 快捷速度 1 - 12 千米每小时RCtlFastIncline(int32_t inIncline) generates (int32_t ret); // 快捷速度 1 - 12 千米每小时RCtlIncSpeed() generates (int32_t ret); //速度加RCtlDecSpeed() generates (int32_t ret); //速度减RCtlIncIncline() generates (int32_t ret); //坡度加RCtlDecIncline() generates (int32_t ret); //坡度减RCtlSetUnit(int32_t inUnit) generates (bool ret); //RCtlPause() generates (bool ret);   //暂停RCtlResume() generates (bool ret);  //继续RCtlStop() generates (bool ret);    //停止setCallBack(ILedTreadmillCallback callback) generates (bool ret);//回调读取的数据
};

ILedTreadmillCallback.hal (回调接口)

package android.hardware.ledtreadmill@1.0;interface ILedTreadmillCallback {oneway onKeyDown(int32_t inKeyCode);oneway onKeyPress(int32_t inKeyCode);oneway onKeyUp(int32_t inKeyCode);oneway onFastSpeedKnobScroll(int32_t inKnobSpeed, int32_t inKnobType);//快速速度旋钮按键消息oneway onStartCountdown();    //倒计时开始oneway onCountdown(int32_t inCount);  //倒计时oneway onStartRun();       //开始跑步oneway onStopRun();        //停止跑步oneway onTargetSpeedChange(int inSpeed); //目标速度变化oneway onTargetInclineChange(int inIncline); //目标扬升变化oneway onTargetSpeedStatusChange(int inStatus); //目标速度 显示与隐藏 1 显示 0 隐藏oneway onTargetInclineStatusChange(int inStatus); //目标扬升 显示与隐藏 1 显示 0 隐藏
};

1.2 使用hidl-gen生成变量

首先确保代码进行过完全编译,然后执行  make hidl-gen -j4

. /opt/openjdk8-env.shsource build/envsetup.sh
lunch rk3399_Android10-userdebugmake -j8
make hidl-gen -j4
设置临时变量
PACKAGE=android.hardware.ledtreadmill@1.0
LOC=hardware/interfaces/ledtreadmill/1.0/default
使用hidl-gen生成default目录 里的C++文件
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
使用hidl-gen生成default目录 里的Android.bp文件
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
使用update-makefiles.sh生成1.0目录下的Android.bp
./hardware/interfaces/update-makefiles.sh

此时的目录结构为

.
└── 1.0├── Android.bp├── default│   ├── Android.bp│   ├── LedTreadmillCallback.cpp│   ├── LedTreadmillCallback.h│   ├── LedTreadmill.cpp│   └── LedTreadmill.h├── ILedTreadmillCallback.hal└── ILedTreadmill.hal

1.3 实现主程序CPP

LetTreadmill.h 代码由前文生成,手动增加了日志定义

// FIXME: your file license if you have one#pragma once#include <android/hardware/ledtreadmill/1.0/ILedTreadmill.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include "android/log.h"static const char *TAG="LedTreadmill";
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , TAG, __VA_ARGS__)namespace android {
namespace hardware {
namespace ledtreadmill {
namespace V1_0 {
namespace implementation {using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;struct LedTreadmill : public ILedTreadmill {// Methods from ::android::hardware::ledtreadmill::V1_0::ILedTreadmill follow.Return<void> OpenInitSerialPort(const hidl_string& address, int32_t baudrate, int32_t flags) override;Return<void> StartRead() override;Return<void> StopRead() override;Return<void> RCtlUnlock(int32_t inTime) override;Return<void> RCtlLock() override;Return<void> RCtlSetWeight(int32_t inWeight) override;Return<void> RCtlSetResumeType(bool inToMinSpeed) override;Return<void> RCtlStart() override;Return<void> RCtlFastSpeed(int32_t inSpeed) override;Return<void> RCtlFastIncline(int32_t inIncline) override;Return<void> RCtlIncSpeed() override;Return<void> RCtlDecSpeed() override;Return<void> RCtlIncIncline() override;Return<void> RCtlDecIncline() override;Return<void> RCtlSetUnit(int32_t inUnit) override;Return<void> RCtlPause() override;Return<void> RCtlResume() override;Return<void> RCtlStop() override;Return<void> setCallBack(const sp<::android::hardware::ledtreadmill::V1_0::ILedTreadmillCallback>& callback) override;// Methods from ::android::hidl::base::V1_0::IBase follow.};// FIXME: most likely delete, this is only for passthrough implementations
// extern "C" ILedTreadmill* HIDL_FETCH_ILedTreadmill(const char* name);}  // namespace implementation
}  // namespace V1_0
}  // namespace ledtreadmill
}  // namespace hardware
}  // namespace android

LetTreadmill.cpp

// FIXME: your file license if you have one#include <bitset>
#include <cstring>
#include <fcntl.h>
#include <list>
#include <stdio.h>
#include <thread>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sstream>
#include <vector>
#include <mutex>#include "LedTreadmill.h"using namespace std;
typedef unsigned char UC;namespace android {
namespace hardware {
namespace ledtreadmill {
namespace V1_0 {
namespace implementation {#define OUTPUT_HEX_COLS       16
void output_Hex(const unsigned char *ucPtr, int iNumBytes);int fd = -1;
sp<ILedTreadmillCallback> mCallback = nullptr;pthread_t mReadThread;//读取数据线程
pthread_t mWriteThread;//写入数据线程//获取波特率
static int getBaudrate(int baudrate) {switch(baudrate) {case 0: return B0;case 50: return B50;case 75: return B75;case 110: return B110;case 134: return B134;case 150: return B150;case 200: return B200;case 300: return B300;case 600: return B600;case 1200: return B1200;case 1800: return B1800;case 2400: return B2400;case 4800: return B4800;case 9600: return B9600;case 19200: return B19200;case 38400: return B38400;case 57600: return B57600;case 115200: return B115200;case 230400: return B230400;case 460800: return B460800;case 500000: return B500000;case 576000: return B576000;case 921600: return B921600;case 1000000: return B1000000;case 1152000: return B1152000;case 1500000: return B1500000;case 2000000: return B2000000;case 2500000: return B2500000;case 3000000: return B3000000;case 3500000: return B3500000;case 4000000: return B4000000;default: return -1;}
}//读取串口数据
int UART_recv(void *buf, int len) {//LOGD("UART_recv");//定义读事件集合fd_set fdRead;int ret;struct timeval aTime;FD_ZERO(&fdRead);FD_SET(fd,&fdRead);aTime.tv_sec = 0;aTime.tv_usec = 300000; //300ms//ret = select(fd + 1, &fdRead, NULL, NULL, &aTime );ret = select(fd + 1, &fdRead, NULL, NULL, NULL);if (ret < 0) {//关闭串口close(fd);} else if (ret > 0) {//判断是否读事件if (FD_ISSET(fd,&fdRead)) {//data available, so get it!ret = read(fd, buf, len);// 对接收的数据进行处理,这里为简单的数据回发}}return ret;
}//读取一位数据
void recvOne(UC receiveBuffer[], int index) {while(!UART_recv(&receiveBuffer[index], 1)) {LOGD("recvOne ---1--- recv error");}
}void *runRead(void* run) {long time = (long)run;int iLCnt = 0;LOGD("runRead %lu", time);UC receiveBuffer[256];int receiveLength;while(1) {//读取一包数据receiveLength = 0;recvOne(receiveBuffer, receiveLength++);//读取第一位if (receiveBuffer[receiveLength - 1] == 0x10) {for(int i = 0; i < 15; i++) {//LOGD("runRead --- read = %d", receiveBuffer[i]);recvOne(receiveBuffer, receiveLength++);}output_Hex(receiveBuffer, 16);if(iLCnt % 30 == 0){LOGD("NMW runRead  while: %d", iLCnt);if(mCallback != nullptr){if(iLCnt % 60 == 0){mCallback->onKeyPress(iLCnt);}elsemCallback->onTargetSpeedChange(iLCnt);}}++iLCnt;}usleep(10 * 1000);}
}// Methods from ::android::hardware::ledtreadmill::V1_0::ILedTreadmill follow.
Return<void> LedTreadmill::OpenInitSerialPort(const hidl_string& address, int32_t baudrate, int32_t flags) {// TODO implementLOGD("OpenInitSerialPort");int speed;speed = getBaudrate(baudrate);if (speed == -1) {return Void();}char c[20];strcpy(c, address.c_str());if (flags == 0) {fd = open(c, O_RDWR|O_NOCTTY);}if(fd < 0) {LOGD("open uart device error\n");}struct termios cfg;if (tcgetattr(fd, &cfg) < 0) {close(fd);return Void();}cfmakeraw(&cfg);cfsetispeed(&cfg, speed);cfsetospeed(&cfg, speed);//修改控制模式,保证程序不会占用串口?cfg.c_cflag |= CLOCAL;//printf("c_cflag |= CLOCAL => %x\r\n", new_opt.c_cflag);//修改控制模式,使得能够从串口读取输入数据cfg.c_cflag |= CREAD;//printf("c_cflag |= CREAD => %x\r\n", new_opt.c_cflag);if (tcsetattr(fd, TCSANOW, &cfg) < 0) {close(fd);return Void();}return Void();
}Return<void> LedTreadmill::StartRead() {// TODO implementint read = 1;LOGD("StartRead");pthread_create(&mReadThread, nullptr, runRead, &read);return Void();
}Return<void> LedTreadmill::StopRead() {// TODO implementLOGD("StopRead");return Void();
}Return<bool> LedTreadmill::RCtlUnlock(int32_t inTime) {// TODO implementLOGD("RCtlUnlock:%d", inTime);return bool {};
}Return<bool> LedTreadmill::RCtlLock() {// TODO implementLOGD("RCtlLock");return bool {};
}Return<bool> LedTreadmill::RCtlSetWeight(int32_t inWeight) {// TODO implementLOGD("RCtlSetWeight:%d", inWeight);return bool {};
}Return<bool> LedTreadmill::RCtlSetResumeType(bool inToMinSpeed) {// TODO implementif(inToMinSpeed)LOGD("RCtlSetResumeType to MinSpeed");elseLOGD("RCtlSetResumeType False");return bool {};
}Return<int32_t> LedTreadmill::RCtlStart() {// TODO implementLOGD("RCtlStart");return int32_t {};
}Return<int32_t> LedTreadmill::RCtlFastSpeed(int32_t inSpeed) {// TODO implementLOGD("RCtlFastSpeed:%d", inSpeed);return int32_t {};
}Return<int32_t> LedTreadmill::RCtlFastIncline(int32_t inIncline) {// TODO implementLOGD("RCtlFastIncline:%d", inIncline);return int32_t {};
}Return<int32_t> LedTreadmill::RCtlIncSpeed() {// TODO implementLOGD("RCtlIncSpeed");return int32_t {};
}Return<int32_t> LedTreadmill::RCtlDecSpeed() {// TODO implementLOGD("RCtlDecSpeed");return int32_t {};
}Return<int32_t> LedTreadmill::RCtlIncIncline() {// TODO implementLOGD("RCtlIncIncline");return int32_t {};
}Return<int32_t> LedTreadmill::RCtlDecIncline() {// TODO implementLOGD("RCtlDecIncline");return int32_t {};
}Return<bool> LedTreadmill::RCtlSetUnit(int32_t inUnit) {// TODO implementLOGD("RCtlSetUnit:%d", inUnit);return bool {};
}Return<bool> LedTreadmill::RCtlPause() {// TODO implementLOGD("RCtlPause");return bool {};
}Return<bool> LedTreadmill::RCtlResume() {// TODO implementLOGD("RCtlResume");return bool {};
}Return<bool> LedTreadmill::RCtlStop() {// TODO implementLOGD("RCtlStop");return bool {};
}Return<bool> LedTreadmill::setCallBack(const sp<::android::hardware::ledtreadmill::V1_0::ILedTreadmillCallback>& callback) {// TODO implementLOGD("setCallback");mCallback = callback;return bool {};
}void output_Hex(const unsigned char *ucPtr, int iNumBytes)
{int rowIdx, colIdx;const unsigned char *iPtr = ucPtr;char buf[128];char *ptr = buf;for (rowIdx = 0;rowIdx < (iNumBytes + OUTPUT_HEX_COLS - 1) / OUTPUT_HEX_COLS; rowIdx++){ptr = buf;sprintf(ptr, "%08XH ", rowIdx * OUTPUT_HEX_COLS);ptr += 10;int offset = rowIdx * OUTPUT_HEX_COLS;/* output hex characters */for (colIdx = 0; colIdx < OUTPUT_HEX_COLS; colIdx++){if ((offset + colIdx) >= iNumBytes) {sprintf(ptr, "%s", "   ");ptr += 3;}else {if ((colIdx + 1) == (OUTPUT_HEX_COLS / 2)) {sprintf(ptr, "%02X   ", (int)(iPtr[offset + colIdx]));ptr += 5;}else {sprintf(ptr, "%02X ", (int)(iPtr[offset + colIdx]));ptr += 3;}}}           /* end-for (colIdx) */sprintf(ptr, "%s", "   ");ptr += 3;/* output ascii characters (if printable) */for (colIdx = 0; colIdx < OUTPUT_HEX_COLS; colIdx++){if ((offset + colIdx) >= iNumBytes)sprintf(ptr, "%s", " ");else if ((iPtr[offset + colIdx] >= 33) && (iPtr[offset + colIdx] <= 126))sprintf(ptr, "%c", (char)(iPtr[offset + colIdx]));elsesprintf(ptr, "%s", ".");++ptr;}         /* end-for (colIdx) */LOGI("%s", buf);}               /* end-for (rowIdx) */return;
}// Methods from ::android::hidl::base::V1_0::IBase follow.//ILedTreadmill* HIDL_FETCH_ILedTreadmill(const char* /* name */) {//return new LedTreadmill();
//}
//
}  // namespace implementation
}  // namespace V1_0
}  // namespace ledtreadmill
}  // namespace hardware
}  // namespace android

添加启动脚本

新建android.hardware.ledtreadmill@1.0-service.rc脚本

service ledtreadmill-hal-1-0 /vendor/bin/hw/android.hardware.ledtreadmill@1.0-serviceclass hal user systemgroup system

新建service.cpp 用来启动并初始化

#define LOG_TAG "ledtreadmill-1.0-service"#include <android/log.h>
#include <hidl/HidlTransportSupport.h>
#include "LedTreadmill.h"using android::sp;
using android::status_t;
using android::OK;using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::ledtreadmill::V1_0::ILedTreadmill;
using android::hardware::ledtreadmill::V1_0::implementation::LedTreadmill;int main(int /* argc */, char* /* argv */ []) {android::sp<ILedTreadmill> service = new LedTreadmill();configureRpcThreadpool(4, true /*callerWillJoin*/);status_t status = service->registerAsService();if (status == OK) {LOGD("LedTreadmill HAL Ready.");service->initSerialPort("/dev/ttyS1", 9600, 0);service->startRead();joinRpcThreadpool();}LOGD("Cannot register LedTreadmill HAL service");return 1;
}

修改Android.bp 注意仔细检查

// FIXME: your file license if you have onecc_library_shared {// FIXME: this should only be -impl for a passthrough hal.// In most cases, to convert this to a binderized implementation, you should:// - change '-impl' to '-service' here and make it a cc_binary instead of a//   cc_library_shared.// - add a *.rc file for this module.// - delete HIDL_FETCH_I* functions.// - call configureRpcThreadpool and registerAsService on the instance.// You may also want to append '-impl/-service' with a specific identifier like// '-vendor' or '-<hardware identifier>' etc to distinguish it.name: "android.hardware.ledtreadmill@1.0-impl",relative_install_path: "hw",// FIXME: this should be 'vendor: true' for modules that will eventually be// on AOSP.proprietary: true,srcs: ["LedTreadmill.cpp","LedTreadmillCallback.cpp",],shared_libs: ["libhidlbase","libhidltransport","libutils","android.hardware.ledtreadmill@1.0",],
}cc_binary {name: "android.hardware.ledtreadmill@1.0-service",relative_install_path: "hw",defaults: ["hidl_defaults"],proprietary: true,init_rc: ["android.hardware.ledtreadmill@1.0-service.rc"],srcs: ["LedTreadmill.cpp","service.cpp",],shared_libs: ["libbase","liblog","libdl","libutils","libhardware","libhidlbase","libhidltransport","android.hardware.ledtreadmill@1.0",],
}

调用update-makefiles.sh更新一下

当前目录结构:

.
└── 1.0├── Android.bp├── default│   ├── Android.bp│   ├── android.hardware.ledtreadmill@1.0-service.rc│   ├── LedTreadmillCallback.cpp│   ├── LedTreadmillCallback.h│   ├── LedTreadmill.cpp│   ├── LedTreadmill.h│   └── service.cpp├── ILedTreadmillCallback.hal└── ILedTreadmill.hal

单独编译一下,并排错

mm ./hardware/interfaces/ledtreadmill/1.0

1.4 VNDK相关

目录build/target/product/gsi下,current.txt与29.txt按字母顺序添加

VNDK-core: android.hardware.ledtreadmill@1.0.so

二、device部分

我们使用RK3399来做,lunch是rk3399_Android10-userdebug,device/rockchip/rk3399目录下修改device.mk和manifest.xml,这里根据自己的环境变通。如果配置了ab分区manifest.xml可能是manifest_ab.xml

device.mk

# ledtreadmill HAL
PRODUCT_PACKAGES += \android.hardware.ledtreadmill@1.0-service \android.hardware.ledtreadmill@1.0-impl

manifest.xml

    <hal format="hidl"><name>android.hardware.ledtreadmill</name><transport>hwbinder</transport><version>1.0</version><interface><name>ILedTreadmill</name><instance>default</instance></interface></hal>

三、SELinux部分 -- hal service

3.1 vendor目录

file_contexts增加

/(vendor|system/vendor)/bin/hw/android\.hardware\.ledtreadmill@1\.0-service   u:object_r:hal_ledtreadmill_default_exec:s0

新建hal_ledtreadmill_default.te

type hal_ledtreadmill_default, domain;
hal_server_domain(hal_ledtreadmill_default, hal_ledtreadmill)type hal_ledtreadmill_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_ledtreadmill_default)
allow hal_ledtreadmill_default serial_device:chr_file rw_file_perms;

3.2 public目录

attributes添加

hal_attribute(ledtreadmill);

新建hal_ledtreadmill.te

# HwBinder IPC from client to server, and callbacks
binder_call(hal_ledtreadmill_client, hal_ledtreadmill_server)
binder_call(hal_ledtreadmill_server, hal_ledtreadmill_client)add_hwservice(hal_ledtreadmill_server, hal_ledtreadmill_hwservice)allow hal_ledtreadmill_client hal_ledtreadmill_hwservice:hwservice_manager find;

然后同步到prebuilts/api/29.0/public

3.3 private目录

hwservice_contexts添加

android.hardware.ledtreadmill::ILedTreadmill                    u:object_r:hal_ledtreadmill_hwservice:s0

private/compat/28.0/28.0.ignore.cil   private/compat/27.0/27.0.ignore.cil

private/compat/26.0/26.0.ignore.cil   三个文件均添加

hal_ledtreadmill_hwservice

然后同步到prebuilts/api/29.0/private

四、framewors层实现

4.1 System Service 实现

4.1.1 Manager

frameworks/base/core/java/android/os下创建ledtreadmill目录,在该目录下新建ILedTreadmillService.aidl与HAL层功能对应

// ILedTreadmillService.aidl
package android.os.ledtreadmill;import android.os.ledtreadmill.ILedTreadmillListener;
// Declare any non-default types here with import statementsinterface ILedTreadmillService {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*///解锁 --  单位:分钟  超时后跑步机停止运行。boolean RCtlUnlock(int inTime);//关闭 --  主动停止跑步机运行。boolean RCtlLock();//设置体重 --  计算卡路里用途 单位0.1千克boolean RCtlSetWeight(int inWeight);//决定暂停后启动是否恢复到最小速度,(默认为true);boolean RCtlSetResumeType(boolean inToMinSpeed);//APK按键启动、停止、快捷速度。int RCtlStart();int RCtlFastSpeed(int inSpeed); // 快捷速度 1 - 12 千米每小时int RCtlFastIncline(int inIncline); // 快捷速度 1 - 12 千米每小时int RCtlIncSpeed(); //速度加int RCtlDecSpeed(); //速度减int RCtlIncIncline(); //坡度加int RCtlDecIncline(); //坡度减boolean RCtlSetUnit(int inUnit);   //单位转换设置 0 为公制,1为英制。boolean RCtlPause();   //暂停boolean RCtlResume();  //继续boolean RCtlStop();    //停止boolean setLedTreadmillListener(ILedTreadmillListener listener);}

创建ILedTreadmillListener.aidl,与回调接口对应

package android.os.ledtreadmill;interface ILedTreadmillListener {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void onKeyDown(int inKeyCode);//键盘消息void onKeyPress(int inKeyCode);//键盘消息void onKeyUp(int inKeyCode);//键盘消息void onFastSpeedKnobScroll(int inKnobSpeed, int inKnobType);//快速速度旋钮按键消息void onStartCountdown();    //倒计时开始void onCountdown(int inCount);//倒计时void onStartRun();          //开始跑步void onStopRun();       //停止跑步void onTargetSpeedChange(int inSpeed); //目标速度变化void onTargetInclineChange(int inIncline); //目标扬升变化void onTargetSpeedStatusChange(int inStatus); //目标速度 显示与隐藏 1 显示 0 隐藏void onTargetInclineStatusChange(int inStatus); //目标扬升 显示与隐藏 1 显示 0 隐藏
}

创建LedTreadmillListener.java

package android.os.ledtreadmill;/*** android.os.ledtreadmill*/public abstract class LedTreadmillListener extends ILedTreadmillListener.Stub  {}

创建LedTreadmillManager.java供APP调用

package android.os.ledtreadmill;import android.os.RemoteException;
import android.os.ledtreadmill.LedTreadmillListener;
import android.util.Log;
import android.os.ledtreadmill.ILedTreadmillService;public class LedTreadmillManager {public static final String TAG = "LedTreadmillManager";private ILedTreadmillService mService;public LedTreadmillManager(ILedTreadmillService service) {mService = service;}public boolean RCtlUnlock(int inTime) {boolean bRet = false;try {Log.d(TAG, "RCtlUnlock: ");if(mService != null){bRet = mService.RCtlUnlock(inTime);}} catch (RemoteException e) {e.printStackTrace();}return bRet;}public boolean RCtlLock() {boolean bRet = false;try {if(mService != null){bRet = mService.RCtlLock();}} catch (RemoteException e) {e.printStackTrace();}return bRet;}public boolean RCtlSetWeight(int inWeight) {boolean bRet = false;try {Log.d(TAG, "IRCtlSetWeight: " + inWeight);if(mService != null){bRet = mService.RCtlSetWeight(inWeight);}} catch (RemoteException e) {e.printStackTrace();}return bRet;}public boolean RCtlSetResumeType(boolean inToMinSpeed) {boolean bRet = false;try {Log.d(TAG, "RCtlSetResumeType: ");if(mService != null){bRet = mService.RCtlSetResumeType(inToMinSpeed);}} catch (RemoteException e) {e.printStackTrace();}return bRet;}public int RCtlStart() {int iRet = -16;try {Log.d(TAG, "RCtlStart: ");if(mService != null){iRet = mService.RCtlStart();}} catch (RemoteException e) {e.printStackTrace();}return iRet;}public int RCtlFastSpeed(int inSpeed) {int iRet = -16;try {Log.d(TAG, "RCtlFastSpeed: ");if(mService != null)iRet = mService.RCtlFastSpeed(inSpeed);} catch (RemoteException e) {e.printStackTrace();}return iRet;}public int RCtlFastIncline(int inIncline) {int iRet = -16;try {Log.d(TAG, "RCtlFastIncline: ");if(mService != null)iRet = mService.RCtlFastIncline(inIncline);} catch (RemoteException e) {e.printStackTrace();}return iRet;}public int RCtlIncSpeed() {int iRet = -16;try {Log.d(TAG, "RCtlIncSpeed: ");if(mService != null)iRet = mService.RCtlIncSpeed();} catch (RemoteException e) {e.printStackTrace();}return iRet;}public int RCtlDecSpeed() {int iRet = -16;try {Log.d(TAG, "RCtlDecSpeed: ");if(mService != null)iRet = mService.RCtlDecSpeed();} catch (RemoteException e) {e.printStackTrace();}return iRet;}public int RCtlIncIncline() {int iRet = -16;try {Log.d(TAG, "RCtlIncIncline: ");if(mService != null)iRet = mService.RCtlIncIncline();} catch (RemoteException e) {e.printStackTrace();}return iRet;}public int RCtlDecIncline() {int iRet = -16;try {Log.d(TAG, "RCtlDecIncline: ");if(mService != null)iRet = mService.RCtlDecIncline();} catch (RemoteException e) {e.printStackTrace();}return iRet;}public boolean RCtlSetUnit(int inUnit) {boolean bRet = false;try {Log.d(TAG, "RCtlSetUnit: ");if(mService != null)bRet = mService.RCtlSetUnit(inUnit);RCtlSetUnit(inUnit);} catch (RemoteException e) {e.printStackTrace();}return bRet;}public boolean RCtlPause() {boolean bRet = false;try {Log.d(TAG, "IRCtlPause: ");if(mService != null)bRet = mService.RCtlPause();} catch (RemoteException e) {e.printStackTrace();}return bRet;}public boolean RCtlResume() {boolean bRet = false;try {Log.d(TAG, "IRCtlResume: ");if(mService != null)bRet = mService.RCtlResume();} catch (RemoteException e) {e.printStackTrace();}return bRet;}public boolean RCtlStop() {boolean bRet = false;try {Log.d(TAG, "IRCtlStop: ");//AIDL传消息过来时的处理必须放异常处理,否则本地APK异常时抛出异常会导致远程AIDL调用发生错误、崩溃。//代码写这里if(mService != null)bRet = mService.RCtlStop();} catch (RemoteException e) {e.printStackTrace();}return bRet;}public boolean setLedTreadmillListener(ILedTreadmillListener listener){Log.d(TAG, "setLedTreadmillListener: ");try {if (mService == null) {return false;}return  mService.setLedTreadmillListener(listener);} catch (RemoteException e) {e.printStackTrace();return false;}}}

frameworks\base\Android.bp里添加

        "core/java/android/os/ledtreadmill/ILedTreadmillListener.aidl","core/java/android/os/ledtreadmill/ILedTreadmillService.aidl",

4.1.2 Service端

frameworks/base/services/core/Android.bp添加引用

    static_libs: [......"android.hardware.ledtreadmill-V1.0-java",......],

frameworks\base\services\core\java\com\android\server下创建ledtreadmill目录,并新建文件 LedTreadmillService.java

package com.android.server.ledtreadmill;import android.hardware.ledtreadmill.V1_0.ILedTreadmill;
import android.hardware.ledtreadmill.V1_0.ILedTreadmillCallback;
import android.os.RemoteException;import android.util.Log;import android.os.ledtreadmill.ILedTreadmillListener;
import android.os.ledtreadmill.ILedTreadmillService;/*** com.android.server.ledtreadmill.LedTreadmillService** @author GW00175635* @date 2019/7/11*/
public class LedTreadmillService extends ILedTreadmillService.Stub {private String TAG = "LedTreadmillService";private ILedTreadmill mHalLedService ;public LedTreadmillService(){try {mHalLedService = ILedTreadmill.getService();//获取service} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic boolean RCtlUnlock(int inTime) throws RemoteException {Log.d(TAG, "RCtlUnlock: ");mHalLedService.RCtlUnlock(inTime);return true;}@Overridepublic boolean RCtlLock() throws RemoteException {Log.d(TAG, "RCtlLock: ");mHalLedService.RCtlLock();return true;}@Overridepublic boolean RCtlSetWeight(int inWeight) throws RemoteException {Log.d(TAG, "RCtlSetWeight: ");mHalLedService.RCtlSetWeight(inWeight);return true;}@Overridepublic boolean RCtlSetResumeType(boolean inToMinSpeed) throws RemoteException {Log.d(TAG, "RCtlSetResumeType: ");mHalLedService.RCtlSetResumeType(inToMinSpeed);return true;}@Overridepublic int RCtlStart() throws RemoteException {Log.d(TAG, "RCtlStart: ");mHalLedService.RCtlStart();return 0;}@Overridepublic int RCtlFastSpeed(int inSpeed) throws RemoteException {Log.d(TAG, "RCtlFastSpeed: ");mHalLedService.RCtlFastSpeed(inSpeed);return 0;}@Overridepublic int RCtlFastIncline(int inIncline) throws RemoteException {Log.d(TAG, "RCtlFastIncline: ");mHalLedService.RCtlFastIncline(inIncline);return 0;}@Overridepublic int RCtlIncSpeed() throws RemoteException {Log.d(TAG, "RCtlIncSpeed: ");mHalLedService.RCtlIncSpeed();return 0;}@Overridepublic int RCtlDecSpeed() throws RemoteException {Log.d(TAG, "RCtlDecSpeed: ");mHalLedService.RCtlDecSpeed();return 0;}@Overridepublic int RCtlIncIncline() throws RemoteException {Log.d(TAG, "RCtlIncIncline: ");mHalLedService.RCtlIncIncline();return 0;}@Overridepublic int RCtlDecIncline() throws RemoteException {Log.d(TAG, "RCtlDecIncline: ");mHalLedService.RCtlDecIncline();return 0;}@Overridepublic boolean RCtlSetUnit(int inUnit) throws RemoteException {Log.d(TAG, "RCtlSetUnit: ");mHalLedService.RCtlSetUnit(inUnit);return true;}@Overridepublic boolean RCtlPause() throws RemoteException {Log.d(TAG, "RCtlPause: ");mHalLedService.RCtlPause();return true;}@Overridepublic boolean RCtlResume() throws RemoteException {Log.d(TAG, "RCtlResume: ");mHalLedService.RCtlResume();return true;}@Overridepublic boolean RCtlStop() throws RemoteException {Log.d(TAG, "RCtlStop: ");mHalLedService.RCtlStop();return true;}@Overridepublic boolean setLedTreadmillListener(ILedTreadmillListener listener) throws RemoteException {Log.d(TAG, "setTestEventListener: ");LedTreadmillCallback ltCallback = new LedTreadmillCallback(listener);//return mHalLedService.setCallback(ltCallback);return false;}class LedTreadmillCallback extends ILedTreadmillCallback.Stub{ILedTreadmillListener mILTListener;LedTreadmillCallback (ILedTreadmillListener listener){mILTListener = listener;}@Overridepublic void onKeyDown(int inKeyCode) throws RemoteException {Log.d(TAG, "onKeyDown: ");mILTListener.onKeyDown(inKeyCode);}@Overridepublic void onKeyPress(int inKeyCode) throws RemoteException {Log.d(TAG, "onKeyPress: ");mILTListener.onKeyPress(inKeyCode);}@Overridepublic void onKeyUp(int inKeyCode) throws RemoteException {Log.d(TAG, "onKeyUp: ");mILTListener.onKeyUp(inKeyCode);}@Overridepublic void onFastSpeedKnobScroll(int inKnobSpeed, int inKnobType) throws RemoteException {Log.d(TAG, "onFastSpeedKnobScroll: ");mILTListener.onFastSpeedKnobScroll(inKnobSpeed, inKnobType);}@Overridepublic void onStartCountdown() throws RemoteException {Log.d(TAG, "onStartCountdown: ");mILTListener.onStartCountdown();}@Overridepublic void onCountdown(int inCount) throws RemoteException {Log.d(TAG, "onCountdown: ");mILTListener.onCountdown(inCount);}@Overridepublic void onStartRun() throws RemoteException {Log.d(TAG, "onStartRun: ");mILTListener.onStartRun();}@Overridepublic void onStopRun() throws RemoteException {Log.d(TAG, "onStopRun: ");mILTListener.onStopRun();}}}

在frameworks\base\core\java\android\content\Context.java里添加

    /*** {@link android.os.ledtreadmill.LedTreadmillManager} for receiving intents at a* time of your choosing.** @see #getSystemService(String)* @see android.os.ledtreadmill.LedTreadmillManager*/public static final String LEDTREADMILL_SERVICE = "led_treadmill";

frameworks/base/core/java/android/app/SystemServiceRegistry.java里添加

import android.os.ledtreadmill.LedTreadmillManager;
import android.os.ledtreadmill.ILedTreadmillService;......registerService(Context.LEDTREADMILL_SERVICE, LedTreadmillManager.class,new CachedServiceFetcher<LedTreadmillManager>() {@Overridepublic LedTreadmillManager createService(ContextImpl ctx) {IBinder iBinder = ServiceManager.getService(Context.LEDTREADMILL_SERVICE);if (iBinder == null) {Log.d(TAG, "NMW get LedTreadmillManager return null");return null;}ILedTreadmillService service = ILedTreadmillService.Stub.asInterface(iBinder);Log.d(TAG, "NMW get LedTreadmillManager return instance");return new LedTreadmillManager(service);}});......

在frameworks\base\services/java/com/android/server/SystemServer.java里添加

import com.android.server.ledtreadmill.LedTreadmillService;....../*** Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.*/private void startOtherServices() {......traceBeginAndSlog("MakeLedTreadmillServiceReady");try {Slog.i(TAG, "LedTreadmill Service");ServiceManager.addService(Context.LEDTREADMILL_SERVICE, new LedTreadmillService());} catch (Throwable e) {reportWtf("starting LedTreadmillService", e);}traceEnd();
......

4.1.3  添加Selinux策略

public/service.te添加

type ledtreadmill_service, system_api_service, system_server_service, service_manager_type;

private/service_contexts添加--注意这里的led_treadmill要与前文添加的Context.LEDTREADMILL_SERVICE保持一致

led_treadmill                              u:object_r:ledtreadmill_service:s0

private/system_server.te添加

hal_client_domain(system_server, hal_ledtreadmill)

private/compat/28.0/28.0.ignore.cil    private/compat/27.0/27.0.ignore.cil  以及

private/compat/26.0/26.0.ignore.cil添加

ledtreadmill_service

最后将这些修改同步到prebuilts/api/29.0/就完成了

4.1.4  编译

需要更新下API,然后才能编译通过

#./hardware/interfaces/update-makefiles.shmake update-apimake -j8

4.2 APP实现调用

编写一个APP来测试验证下,packages/apps目录下新建LedTreadmill目录,内容比较简单--我们将主要文件放上来,缺少的自己补充下。

4.2.1 APP调用主Activity

package com.genlt.ledtreadmill;import android.app.Activity;import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ledtreadmill.LedTreadmillManager;
import android.os.ledtreadmill.LedTreadmillListener;
import android.view.View;
import android.widget.Button;
import android.util.Log;/*** MainaActivity*/
public class MainActivity extends Activity implements View.OnClickListener {private final String TAG = "MainActivity";LedTreadmillManager mLedTreadmillManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mLedTreadmillManager = (LedTreadmillManager)getSystemService(Context.LEDTREADMILL_SERVICE);if(mLedTreadmillManager == null){Log.d("activity", "Get service for mLedTreadmillManager failed." + Context.LEDTREADMILL_SERVICE);}else{Log.d("activity", "Get service for mLedTreadmillManager OK. " + Context.LEDTREADMILL_SERVICE);}Button btn_start, btn_stop, btn_custprogram, btn_pause;Button btn_SpeedPlus, btn_SpeedDec;Button btn_InclinePlus, btn_InclineDec;Button btn_FastSpeedTwo, btn_FastSpeedSix;Button btn_SetCallback;btn_start = findViewById(R.id.btn_start);btn_stop = findViewById(R.id.btn_stop);btn_pause = findViewById(R.id.btn_pause);btn_custprogram = findViewById(R.id.btn_custprogram);btn_SpeedPlus = findViewById(R.id.btn_SpeedPlus);btn_SpeedDec = findViewById(R.id.btn_SpeedDec);btn_InclinePlus = findViewById(R.id.btn_InclinePlus);btn_InclineDec = findViewById(R.id.btn_InclineDec);btn_FastSpeedTwo = findViewById(R.id.btn_FastSpeedTwo);btn_FastSpeedSix = findViewById(R.id.btn_FastSpeedSix);btn_SetCallback = findViewById(R.id.button_setCallback);btn_start.setOnClickListener(this);btn_stop.setOnClickListener(this);btn_pause.setOnClickListener(this);btn_custprogram.setOnClickListener(this);btn_SpeedPlus.setOnClickListener(this);btn_SpeedDec.setOnClickListener(this);btn_FastSpeedTwo.setOnClickListener(this);btn_FastSpeedSix.setOnClickListener(this);btn_InclinePlus.setOnClickListener(this);btn_InclineDec.setOnClickListener(this);btn_SetCallback.setOnClickListener(this);}@Overridepublic void onClick(View view) {Log.d(TAG, "onClick");// TODO Auto-generated method stubswitch (view.getId()) {case R.id.btn_start:if(mLedTreadmillManager != null){Log.d(TAG, "btn_start: ");mLedTreadmillManager.RCtlStart();}else{Log.d(TAG, "mLedTreadmillManager is null: ");}break;case R.id.btn_stop:if(mLedTreadmillManager != null){Log.d(TAG, "btn_stop: ");mLedTreadmillManager.RCtlStart();}else{Log.d(TAG, "mLedTreadmillManager is null: ");}break;case R.id.btn_SpeedPlus:if(mLedTreadmillManager != null){Log.d(TAG, "btn_SpeedPlus: ");mLedTreadmillManager.RCtlStart();}else{Log.d(TAG, "mLedTreadmillManager is null: ");}break;case R.id.btn_SpeedDec:if(mLedTreadmillManager != null){Log.d(TAG, "btn_SpeedDec: ");mLedTreadmillManager.RCtlStart();}else{Log.d(TAG, "mLedTreadmillManager is null: ");}break;case R.id.btn_FastSpeedTwo:if(mLedTreadmillManager != null){Log.d(TAG, "btn_FastSpeedTwo: ");mLedTreadmillManager.RCtlFastSpeed(20);}else{Log.d(TAG, "mLedTreadmillManager is null: ");}break;case R.id.btn_FastSpeedSix:if(mLedTreadmillManager != null){Log.d(TAG, "btn_FastSpeedSix: ");mLedTreadmillManager.RCtlFastSpeed(60);}else{Log.d(TAG, "mLedTreadmillManager is null: ");}break;case R.id.btn_custprogram:if(mLedTreadmillManager != null){
//                    Log.d(TAG, "btn_custprogram: ");
//                    int []Speeds = {12, 15, 8};
//                    int []Incs = {2, 1, 9};
//                    int []Durations = {50, 50, 50};
//                    mLedTreadmillManager.RCtlCustProgram(Speeds, Incs, Durations);}else{Log.d(TAG, "mLedTreadmillManager is null: ");}break;case R.id.btn_pause:if(mLedTreadmillManager != null){Log.d(TAG, "btn_pause: ");mLedTreadmillManager.RCtlPause();}else{Log.d(TAG, "mLedTreadmillManager is null: ");}break;case R.id.btn_InclinePlus:if(mLedTreadmillManager != null){Log.d(TAG, "btn_InclinePlus: ");mLedTreadmillManager.RCtlIncIncline();}else{Log.d(TAG, "mLedTreadmillManager is null: ");}break;case R.id.btn_InclineDec:if(mLedTreadmillManager != null){Log.d(TAG, "btn_InclineDec: ");mLedTreadmillManager.RCtlDecIncline();}else{Log.d(TAG, "mLedTreadmillManager is null: ");}break;case R.id.button_setCallback:Log.d(TAG, "button_setCallback");mLedTreadmillManager.setLedTreadmillListener(new LedTreadmillListener(){@Overridepublic void onKeyDown(int inKeyCode) {Log.d(TAG, "onKeyDown: " + inKeyCode);}@Overridepublic void onKeyPress(int inKeyCode) {Log.d(TAG, "onKeyPress: " + inKeyCode);}@Overridepublic void onKeyUp(int inKeyCode) {Log.d(TAG, "onKeyUp: " + inKeyCode);}@Overridepublic void onFastSpeedKnobScroll(int inKnobSpeed, int inKnobType) {Log.d(TAG, "onFastSpeedKnobScroll inKnobSpeed: " + inKnobSpeed + " inKnobType:" + inKnobType);}@Overridepublic void onStartCountdown() {Log.d(TAG, "onStartCountdown: ");}@Overridepublic void onCountdown(int inCount) {Log.d(TAG, "onCountdown: " + inCount);}@Overridepublic void onStartRun() {Log.d(TAG, "onStartRun: ");}@Overridepublic void onStopRun() {Log.d(TAG, "onStopRun: ");}@Overridepublic void onTargetSpeedChange(int inSpeed) {Log.d(TAG, "onTargetSpeedChange: " + inSpeed);}@Overridepublic void onTargetInclineChange(int inIncline) {Log.d(TAG, "onTargetInclineChange: " + inIncline);}@Overridepublic void onTargetSpeedStatusChange(int inStatus) {Log.d(TAG, "onTargetSpeedStatusChange: " + inStatus);}@Overridepublic void onTargetInclineStatusChange(int inStatus) {Log.d(TAG, "onTargetInclineStatusChange: " + inStatus);}});break;default:break;}}}

4.2.2 Layout文件

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_centerHorizontal="true"android:orientation="vertical"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_start"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:text="启动 Start" /><Buttonandroid:id="@+id/btn_stop"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:text="停止 Stop" /></LinearLayout></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_SpeedPlus"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:text="加速 Plus" /><Buttonandroid:id="@+id/btn_SpeedDec"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:text="减速 Dec" /></LinearLayout></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_FastSpeedTwo"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:text="速度(Speed) 2 " /><Buttonandroid:id="@+id/btn_FastSpeedSix"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:text="速度(Speed) 6 " /></LinearLayout></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_custprogram"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:visibility="invisible"android:text="程式 CustProgram" /><Buttonandroid:id="@+id/btn_pause"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:text="暂停 Pause"/></LinearLayout></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_InclinePlus"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:text="扬升加 Incline Plus" /><Buttonandroid:id="@+id/btn_InclineDec"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:text="扬升减 Incline Dec" /></LinearLayout></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:orientation="horizontal"><Buttonandroid:id="@+id/button_setCallback"android:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:text="回调 SetCallBack" /><Buttonandroid:layout_width="360dp"android:layout_height="60dp"android:gravity="center"android:textSize="30sp"android:visibility="invisible"android:text="" /></LinearLayout></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:layout_centerInParent="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="36sp"android:text="跑步机控制示例Demo" /></RelativeLayout></LinearLayout>

4.2.2 Makefile文件Android.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)
LOCAL_CERTIFICATE := platform
LOCAL_MODULE_TAGS := optional
LOCAL_PACKAGE_NAME := LedTreadmillApp
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)

至此,一个完整的DEMO就完成了。当然这里只是个演示,里面是没有具体业务逻辑的,读者可以在此基础上根据自己的项目需要进行编写扩充。

参考资料

Android 9 HAL开发添加HIDL实现过程

Android HAL层添加HIDL实例实现串口通信_不会写bug的程序员不是好码农的博客-CSDN博客_android串口hal

Android 10 HAL 层添加HIDL实现过程相关推荐

  1. Android P HAL层添加HIDL实例(详细实现步骤)

    Android P HAL层添加HIDL实例 本文是参照 https://www.jianshu.com/p/b80865c61d8e 教程介绍实现,原理请参考原作者. 本文将介绍如何在P OS上添加 ...

  2. android音频hal层简介

    如下图为android音频hal层所处的位置: 从上图可以看出,HAL层下面使用TiniAlsa(Android下一个简约的Alsa版本).HAL层分为两部分,一部分为各种音频设备,每种音频设备由一个 ...

  3. 【Android】HAL层浅析

    一.HAL层的前世今生 二.HAL层的通用结构剖析 三.一个例子 四.击破Audio HAL Module 五.小的总结 一.HAL层的前世今生 HAL(Hardware Abstraction La ...

  4. 在Android C/C++层添加LOG调试(LOGI\LOGD\LOGE...)输出支持

    最近在研究Android 2.3.3源代码的C/C++层,需要对代码进行一些调试,但是奇怪的是,直接添加LOGD("XXXXXXXX");,使用logcat却看不到任何输出,换成L ...

  5. 在Android C/C++层添加LOG调试(LOGI/LOGD/LOGE

    最近在研究Android 2.3.3源代码的C/C++层,需要对代码进行一些调试,但是奇怪的是,直接添加LOGD("XXXXXXXX");,使用logcat却看不到任何输出,换成L ...

  6. 在Android C/C++层添加LOG调试(LOGI\LOGD\LOGE...)输出支持 [ZZ]

    最近在研究Android 2.3.3源代码的C/C++层,需要对代码进行一些调试,但是奇怪的是,直接添加LOGD("XXXXXXXX");,使用logcat却看不到任何输出,换成L ...

  7. Android 10 SystemUI 如何添加4G信号和WiFi图标

    代码路径: frameworks/base/packages/SystemUI/res/layout/system_icons.xml frameworks/base/packages/SystemU ...

  8. Android 10.0 app添加校验锁(输入密码才能进入app)

    1.概述 最近有客户有需求要求给app添加锁,就是点击app 图标时,会弹出Dialog,需要输入密码才能进入app中,就是应用校验锁, 最开始想到在Launcher3中实现,但是如果更换了默认Lau ...

  9. Android GNSS 模块分析(四)HAL 层

    紧接着上一篇(Android GNSS 模块分析(三)JNI 层),继续来分析下 Android GNSS HAL 层的功能,本篇准备先介绍下 HIDL 层的封装.至于后面的 HAL 层的功能,由于使 ...

最新文章

  1. 在Java中使用xpath对xml解析
  2. Android 优秀UI控件 ---- FlowingDrawer
  3. View及ViewGroup的事件分发及传递(一)
  4. Ubuntu17.10 下配置caffe 仅CPU i386可以直接apt install caffe-cpu,但是怎么运行mnist代码我懵逼了...
  5. html-mailto
  6. python的变量名必须以什么开头_python以下划线开头的变量名含义
  7. “引用作为函数参数”与 “引用作为函数返回值”
  8. Java File类void deleteOnExit()方法(带示例)
  9. Flask爱家租房--celery(总结)
  10. linux mysql 备份脚本_linux下mysql备份脚本
  11. 微课|Python编写代理服务器程序(48分钟)
  12. linux下的/dev/shm/ 以及与swap目录的区别
  13. 深度学习:自然语言生成-集束/柱搜索beam search和随机搜索random search
  14. EOJ3536 求蛇形矩阵每一行的和---找规律
  15. java ssm基于springboot的设备巡检系统
  16. 论文阅读《Contextual-based Image Inpainting: Infer, Match, and Translate》
  17. 马云思考阿里下一个15年:大数据是未来核心
  18. 腾讯优图NCNN详细分析及实践操作(含Yolov5实践)
  19. Comware: Port Link-mode Bridge vs Port Link-mode Route
  20. Bootstrap3黑色系个人网站单页

热门文章

  1. 我讨厌计算机作文500,矛盾——我讨厌
  2. 游戏系统开发笔记(九)——构建战斗系统
  3. 神一样的存在!SO 上首个声望值超过 100 万的程序员
  4. fopen函数阻塞的排查
  5. Word 2003 视频教程-Word 自动保存(转)
  6. 用devc++表白_中山院表白墙丨电科大中山院的帅哥,不会走路吗?没事出来走两步给我瞧瞧...
  7. 【翻译】西川善司为了3D游戏粉丝的[生化危机5]图形讲座(后篇)
  8. iOS 动画 swift 实现直播中状态动画
  9. Go语言学习之encoding/gob包(The way to go)
  10. Android如何制作漂亮的自适布局的键盘