文章目录
硬件驱动层
qzbattery.h
hardware/libhardware/include/hardware/qzbattery.h
#define ANDROID_QZBATTERY_INTERFACE_H
#include <hardware/hardware.h>
__BEGIN_DECLS
#define QZBATTERY_HARDWARE_MODULE_ID "qzbattery"
// 此方法是固定写法
struct qzbattery_module_t
{
struct hw_module_t common;
char *description;
int methodsNum;
};
struct QZBatteryReadBlockData
{
int fd;
int cmd;
int len;
char val[6];
};
struct QZBatteryWriteBlockData
{
int fd;
int cmd;
int len;
int val;
};
struct QZBatteryReadWordData
{
int fd;
int cmd;
};
struct QZBatteryWriteWordData
{
int fd;
int cmd;
int value;
};
struct QZBatteryOpenData
{
int reg;
};
struct QZBatteryCloseData
{
int file;
};
struct qzbattery_device_t
{
struct hw_device_t common;
int (*qz_battery_read_block_data)(struct qzbattery_device_t *dev, struct QZBatteryReadBlockData *data);
int (*qz_battery_write_block_data)(struct qzbattery_device_t *dev, struct QZBatteryWriteBlockData *data);
int (*qz_battery_read_word_data)(struct qzbattery_device_t *dev, struct QZBatteryReadWordData *data);
int (*qz_battery_write_word_data)(struct qzbattery_device_t *dev, struct QZBatteryWriteWordData *data);
int (*qz_battery_open)(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data);
int (*qz_battery_test)(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data);
int (*qz_battery_close)(struct qzbattery_device_t *dev, struct QZBatteryCloseData *data);
/* data */
};
__END_DECLS
qzbattery.c
hardware/libhardware/modules/qzbattery/qzbattery_hw.c
#define LOG_TAG "qz battery"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
// #include <linux/i2c-smbus.h>
// #include <i2c/smbus.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <hardware/hardware.h>
#include <malloc.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <cutils/log.h>
#include <hardware/qzbattery.h>
#define MODULE_NAME "Hello Battery"
#define MODULE_DES "Battery : Implement read battery function"
#define MODULE_AUTHOR "zuocong@qiictech.com"
#define ADDR 0x0b
#define BQ40Z50_MANUFACTURER_ACCESS 0x00
#define BQ40Z50_MANUFACTURER_BLOCK_ACCESS 0x44
#define BQ40Z50_MANUFACTURER_DATE 0x1B
#define BQ40Z50_SERIAL_NUMBER 0x1C
#define BQ40Z50_MANUFACTURER_DATA 0x23
#define I2C_FILE_PATH "/dev/i2c-1"
// enum bq40z50_mac_cmd
// {
// BQ40Z50_MAC_CMD_
// }
// 读取 块(,传输连续的字节序列,数据量较大,长度在1-32字节之间) 数据
static int qz_battery_read_block_data(struct qzbattery_device_t *dev, struct QZBatteryReadBlockData *data);
// 写入 块 数据
static int qz_battery_write_block_data(struct qzbattery_device_t *dev, struct QZBatteryWriteBlockData *data);
// 读取 一个字》两个字节 数据
static int qz_battery_read_word_data(struct qzbattery_device_t *dev, struct QZBatteryReadWordData *data);
// 写入 字 数据
static int qz_battery_write_word_data(struct qzbattery_device_t *dev, struct QZBatteryWriteWordData *data);
// 打开电池
static int qz_battery_open(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data);
static int qz_battery_test(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data);
// 关闭电池
static int qz_battery_close(struct qzbattery_device_t *dev, struct QZBatteryCloseData *data);
// 固定写法,打开关闭模块
static int battery_module_close(struct hw_device_t *device);
static int battery_module_open(const struct hw_module_t *module, const char *id, struct hw_device_t **device);
int smbus_write_word(int fd, uint8_t cmd, uint16_t value)
{
struct i2c_smbus_ioctl_data msgs;
union i2c_smbus_data data;
data.word = value;
msgs.read_write = I2C_SMBUS_WRITE;
msgs.command = cmd;
msgs.size = I2C_SMBUS_WORD_DATA;
msgs.data = &data;
if (ioctl(fd, I2C_SMBUS, &msgs) < 0)
{
perror("error, failed to access smbus");
ALOGE("error, failed to access smbus");
return -errno;
}
return 0;
}
int smbus_read_word(int fd, uint8_t cmd)
{
union i2c_smbus_data data;
struct i2c_smbus_ioctl_data msg;
msg.read_write = I2C_SMBUS_READ;
msg.command = cmd;
msg.size = I2C_SMBUS_WORD_DATA;
msg.data = &data;
if (ioctl(fd, I2C_SMBUS, &msg) < 0)
{
perror("error, failed to access smbus");
ALOGE("error, failed to access smbus");
return -errno;
}
printf("raw data: %d\n", data.word);
ALOGE("raw data: %d\n", data.word);
return data.word;
}
int smbus_write_block(int fd, uint8_t cmd, uint8_t len, uint8_t *val)
{
union i2c_smbus_data data;
struct i2c_smbus_ioctl_data msg;
if (len > I2C_SMBUS_BLOCK_MAX)
{
len = I2C_SMBUS_BLOCK_MAX;
}
data.block[0] = len;
memcpy(data.block + 1, val, len);
msg.read_write = I2C_SMBUS_WRITE;
msg.command = cmd;
msg.size = I2C_SMBUS_BLOCK_DATA;
msg.data = &data;
if (ioctl(fd, I2C_SMBUS, &msg) < 0)
{
perror("smbus_write_block failed");
ALOGE("smbus_write_block failed");
return -errno;
}
return 0;
}
int smbus_read_block(int fd, uint8_t cmd, uint8_t len, char *val)
{
union i2c_smbus_data data;
struct i2c_smbus_ioctl_data msg;
if (len > I2C_SMBUS_BLOCK_MAX)
{
len = I2C_SMBUS_BLOCK_MAX;
}
data.block[0] = len;
data.block[1] = 0xff;
data.block[2] = 0xff;
data.block[3] = 0xff;
data.block[4] = 0xff;
data.block[5] = 0xff;
msg.read_write = I2C_SMBUS_READ;
msg.command = cmd;
msg.size = I2C_SMBUS_I2C_BLOCK_DATA;
msg.data = &data;
if (ioctl(fd, I2C_SMBUS, &msg) < 0)
{
perror("smbus_read_block failed");
ALOGE("smbus_read_block failed");
return -errno;
}
printf("smbus_read_block len=%d\n", msg.data->block[0]);
ALOGE("smbus_read_block len=%d\n", msg.data->block[0]);
for (int i = 0; i < msg.data->block[0]; i++)
{
printf("%02X ", msg.data->block[i + 1]);
ALOGE("%02X ", msg.data->block[i + 1]);
}
printf("\n");
ALOGE("\n");
memcpy(val, &msg.data->block[1], msg.data->block[0]-1);
return msg.data->block[0];
}
// int bq40z50_i2c_write_block(int fd, uint8_t cmd, uint8_t len, uint8_t *val)
// {
// int ret;
// struct i2c_rdwr_ioctl_data ioctl_data;
// struct i2c_msg msg;
// msg.addr = cmd;
// msg.flags = 0;
// msg.buf = val;
// msg.len = len;
// ioctl_data.msgs = &msg;
// ioctl_data.nmsgs = 1;
// if(ioctl(fd, I2C_RDWR, &ioctl_data) < 0)
// {
// perror("bq40z50_i2c_write_block failed");
// return -errno;
// }
// return 0;
// }
// int bq40z50_i2c_read_block(int fd, uint8_t cmd, uint8_t len, uint8_t *val)
// {
// int ret;
// struct i2c_rdwr_ioctl_data ioctl_data;
// struct i2c_msg msg[2];
// msg[0].addr = cmd;
// msg[0].flags = 0;
// msg[0].buf = val;
// msg[0].len = len;
// ioctl_data.msgs = &msg;
// ioctl_data.nmsgs = 1;
// if(ioctl(fd, I2C_RDWR, &ioctl_data) < 0)
// {
// perror("bq40z50_i2c_write_block failed");
// return -errno;
// }
// return 0;
// }
// int bq40z50_manufacturer_access_read(int fd, uint16_t cmd, uint8_t len, uint8_t *val)
// {
// int ret;
// uint8_t buf[2] = {0};
// struct i2c_rdwr_ioctl_data ioctl_data;
// struct i2c_msg msg[2];
// buf[0] = (uint8_t)(cmd >> 8);
// buf[1] = (uint8_t)cmd;
// msg[0].addr = BQ40Z50_MANUFACTURER_ACCESS;
// msg[0].flags = 0;
// msg[0].buf = buf;
// msg[0].len = 2;
// msg[0].addr = BQ40Z50_MANUFACTURER_DATA;
// msg[0].flags = I2C_M_RD;
// msg[0].buf = val;
// msg[0].len = len;
// ioctl_data.msgs = &msg;
// ioctl_data.nmsgs = 2;
// if(ioctl(fd, I2C_RDWR, &ioctl_data) < 0)
// {
// perror("bq40z50_i2c_write_block failed");
// return -errno;
// }
// printf("bq40z50_manufacturer_access_read len=%d\n", len);
// for (int i = 0; i < msg.data->block[0]; i++)
// {
// printf("%02X ", msg.data->block[i + 1]);
// }
// printf("\n");
// return 0;
// }
int bq40z50_get_sn(int fd, char *sn, int size)
{
int ret;
uint16_t date;
uint16_t seial_number;
ret = smbus_read_word(fd, BQ40Z50_MANUFACTURER_DATE);
if (ret < 0)
{
perror("error, failed to access smbus");
return ret;
}
date = ret;
ret = smbus_read_word(fd, BQ40Z50_SERIAL_NUMBER);
if (ret < 0)
{
perror("error, failed to access smbus");
return ret;
}
seial_number = ret;
sn[0] = 0;
snprintf(sn, size, "%04d%02d%02d%04X", date / 512 + 1980, (date % 512) / 32, (date % 512) % 32, seial_number);
return 0;
}
int bq40z50_set_serial_number(int fd, uint16_t serial_number)
{
int ret;
ret = smbus_write_word(fd, BQ40Z50_SERIAL_NUMBER, serial_number);
if (ret < 0)
{
return ret;
}
return 0;
}
int bq40z50_seal(int fd)
{
int ret;
ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, 0x3000);
if (ret < 0)
{
return ret;
}
return 0;
}
int bq40z50_unseal(int fd, uint32_t key)
{
int ret;
ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, (uint16_t)(key >> 16));
if (ret < 0)
{
return ret;
}
ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, (uint16_t)key);
if (ret < 0)
{
return ret;
}
return 0;
}
int bq40z50_full_access(int fd, uint32_t key)
{
int ret;
ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, (uint16_t)(key >> 16));
if (ret < 0)
{
return ret;
}
ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, (uint16_t)key);
if (ret < 0)
{
return ret;
}
return 0;
}
int bq40z50_get_operation_status(int fd, uint16_t reg)
{
int ret;
printf("reg = %04x \n", reg);
uint8_t buf[32] = {0};
// ret = smbus_write_word(fd, BQ40Z50_MANUFACTURER_ACCESS, reg);
// if (ret < 0)
// {
// return ret;
// }
buf[0] = 0x54;
buf[1] = 0x00;
ret = smbus_write_block(fd, BQ40Z50_MANUFACTURER_BLOCK_ACCESS, 2, buf);
if (ret < 0)
{
return ret;
}
// usleep(2000 * 1000); // usleep 接受的单位是微秒
ret = smbus_read_block(fd, BQ40Z50_MANUFACTURER_BLOCK_ACCESS, 6, (char*)buf);
if (ret < 0)
{
return ret;
}
printf("operation_status: ");
for (int i = 0; i < ret; i++)
{
printf("%02X ", buf[i]);
}
printf("\n");
return 0;
}
static int qz_battery_read_block_data(struct qzbattery_device_t *dev, struct QZBatteryReadBlockData *data)
{
(void)dev;
return smbus_read_block(data->fd, data->cmd, data->len, (char*)&data->val);
}
static int qz_battery_write_block_data(struct qzbattery_device_t *dev, struct QZBatteryWriteBlockData *data)
{
(void)dev;
return smbus_write_block(data->fd, data->cmd, data->len, (uint8_t*)&data->val);
}
static int qz_battery_read_word_data(struct qzbattery_device_t *dev, struct QZBatteryReadWordData *data)
{
(void)dev;
return smbus_read_word(data->fd, data->cmd);
}
static int qz_battery_write_word_data(struct qzbattery_device_t *dev, struct QZBatteryWriteWordData *data)
{
(void)dev;
return smbus_write_word(data->fd, data->cmd, (uint16_t)data->value);
}
static int qz_battery_open(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data)
{
(void)dev;
uint16_t addr1 = data->reg;
printf("QZBatteryOpenData = %04x \n", addr1);
int res = 0;
// I2C 设备路径
int i2cFile = open(I2C_FILE_PATH, O_RDWR);
if (i2cFile < 0)
{
ALOGI("...Failed to open I2C device");
return 1;
}
ALOGI("...Success to open I2C device");
int i2cAddress = 0x0B; // I2C 设备地址
// int registerAddress = 0x1C; // 要读取的寄存器地址
res = ioctl(i2cFile, I2C_SLAVE_FORCE, i2cAddress);
if (res < 0)
{
ALOGI("...Error message: %s\n", strerror(errno));
ALOGI("...Failed to set I2C address res : %d", res);
close(i2cFile);
return 1;
}
ALOGI("...Success to ioctl I2C device");
int val = 3;
res = ioctl(i2cFile, I2C_RETRIES, val);
if(res < 0)
{
printf("i2c: set i2c retry times err\n");
}
printf("i2c: set i2c retry times %d\n",val);
return i2cFile;
}
static int qz_battery_close(struct qzbattery_device_t *dev, struct QZBatteryCloseData *data)
{
(void)dev;
int fd = data->file;
if (fd < 0)
{
perror("qz battery close failed , fd < 0");
}
close(fd);
return 0;
}
// ============================================================测试================================================================
static int qz_battery_test(struct qzbattery_device_t *dev, struct QZBatteryOpenData *data)
{
(void)dev;
uint16_t addr1 = data->reg;
printf("QZBatteryOpenData = %04x \n", addr1);
int res = 0;
// I2C 设备路径
int i2cFile = open(I2C_FILE_PATH, O_RDWR);
if (i2cFile < 0)
{
ALOGI("...Failed to open I2C device");
return 1;
}
ALOGI("...Success to open I2C device");
int i2cAddress = 0x0B; // I2C 设备地址
// int registerAddress = 0x1C; // 要读取的寄存器地址
res = ioctl(i2cFile, I2C_SLAVE_FORCE, i2cAddress);
if (res < 0)
{
ALOGI("...Error message: %s\n", strerror(errno));
ALOGI("...Failed to set I2C address res : %d", res);
close(i2cFile);
return 1;
}
ALOGI("...Success to ioctl I2C device");
int val = 3;
res = ioctl(i2cFile, I2C_RETRIES, val);
if(res < 0)
{
printf("i2c: set i2c retry times err\n");
}
printf("i2c: set i2c retry times %d\n",val);
// 读取SN
// char sn[20] = {0};
// if (bq40z50_get_sn(i2cFile, sn, sizeof(sn)) != 0)
// {
// printf("...bq40z50_get_sn1 failed\n");
// }
// printf("...bq40z50_get_sn1 %s", sn);
// // 更改SN
// if (bq40z50_set_serial_number(i2cFile, 0x0011) != 0)
// {
// printf("...bq40z50_set_serial_number failed\n");
// }
// // 读取SN
// if (bq40z50_get_sn(i2cFile, sn, sizeof(sn)) != 0)
// {
// printf("...bq40z50_get_sn2 failed\n");
// }
// printf("...bq40z50_get_sn2 %s", sn);
// 读取电池操作状态
if (bq40z50_get_operation_status(i2cFile, addr1) != 0)
{
printf("...bq40z50_get_operation_status failed\n");
}
// unsigned char value;
// if (read(i2cFile, &value, 1) != 1)
// {
// ALOGI("...Failed to read from I2C device");
// close(i2cFile);
// return 1;
// }
// printf("Read value from register 0x%X: %02X\n", registerAddress, value);
// close(i2cFile);
return i2cFile;
}
/** =====================================================以下是固定结构========================================================== */
static struct hw_module_methods_t qzbattery_module_methods_t = {
.open = battery_module_open};
struct qzbattery_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = 1,
.hal_api_version = 0,
.id = QZBATTERY_HARDWARE_MODULE_ID,
.name = MODULE_NAME,
.author = MODULE_AUTHOR,
.methods = &qzbattery_module_methods_t},
.description = MODULE_DES,
.methodsNum = 3
};
// 打开电池硬件HAL模块
static int battery_module_open(const struct hw_module_t *module, const char *id, struct hw_device_t **device)
{
struct qzbattery_device_t *dev;
printf("ID: %s\n", id);
dev = (struct qzbattery_device_t *)malloc(sizeof(*dev));
if (!dev)
{
ALOGE("HelloBattery open: faild to alloc device space");
return -EFAULT;
}
// 固定的参数方法
memset(dev, 0, sizeof(*dev));
dev->common.tag = HARDWARE_MODULE_TAG;
dev->common.version = 0;
dev->common.module = (struct hw_module_t *)module;
dev->common.close = battery_module_close;
// 自己定义的方法,给服务层调用
dev->qz_battery_read_block_data = qz_battery_read_block_data;
dev->qz_battery_write_block_data = qz_battery_write_block_data;
dev->qz_battery_read_word_data = qz_battery_read_word_data;
dev->qz_battery_write_word_data = qz_battery_write_word_data;
dev->qz_battery_open = qz_battery_open;
dev->qz_battery_test = qz_battery_test;
dev->qz_battery_close = qz_battery_close;
*device = &(dev->common);
ALOGI("HelloBattery open: driver file successfully");
return 0;
};
// 关闭模块
static int battery_module_close(struct hw_device_t *device)
{
struct qzbattery_device_t *battry_device = (struct qzbattery_device_t *)device;
if (battry_device)
{
free(battry_device);
}
return 0;
}
JNI
com_android_server_qz_BatteryManagerService.cpp
frameworks/base/services/core/jni/com_android_server_qz_BatteryManagerService.cpp
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <hardware/hardware.h>
#include <hardware/qzbattery.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <utils/Log.h>
#include <utils/misc.h>
#include <iostream>
namespace android {
struct qzbattery_device_t* qz_device = NULL;
static jboolean qzbattery_init(JNIEnv* env, jobject clazz) {
qzbattery_module_t* module;
ALOGI("qzbattery jni init");
if (hw_get_module(QZBATTERY_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
ALOGI("hw_get_module success");
if (module->common.methods->open(&(module->common), QZBATTERY_HARDWARE_MODULE_ID,
(struct hw_device_t**)&qz_device) == 0) {
ALOGI("open success");
return JNI_TRUE;
}
ALOGI("open error");
return JNI_FALSE;
}
ALOGI("hw_get_module error");
return JNI_FALSE;
}
static jcharArray battery_read_block_data(JNIEnv* env, jobject clazz, jint _fd, jint _cmd, jint _len, jint _val) {
if (!qz_device) {
ALOGI("qz jni device is not open");
// return JNI_FALSE;
}
ALOGI("QZ jni of qz_battery_read_block_data param _fd = %d, _cmd = %d, _len = %d, _val=%d", _fd, _cmd, _len, _val);
QZBatteryReadBlockData data;
data.fd = _fd;
data.cmd = _cmd;
data.len = _len;
// data.val = _val;
qz_device->qz_battery_read_block_data(qz_device, &data);
jchar* j_version = (jchar*)calloc(sizeof(jchar), data.len);
for(int i=0; i <= data.len-1; i++){
j_version[i] = (jchar) data.val[i];
ALOGI("QZ jni of qz_battery_read_block_j_version = %02x", j_version[i]);
}
jcharArray j_version_array = env->NewCharArray(data.len);
env->SetCharArrayRegion(j_version_array, 0, data.len , j_version);
return j_version_array;
}
static int battery_write_block_data(JNIEnv* env, jobject clazz, jint _fd, jint _cmd, jint _len, jint _val) {
if (!qz_device) {
ALOGI("qz jni device is not open");
// return JNI_FALSE;
}
ALOGI("QZ jni of battery_write_block_data param _fd = %d, _cmd = %d, _len = %d, val=%d", _fd, _cmd, _len, _val);
QZBatteryWriteBlockData data;
data.fd = _fd;
data.cmd = _cmd;
data.len = _len;
data.val = _val;
qz_device->qz_battery_write_block_data(qz_device, &data);
jint blockData = data.val;
// if (blockData == NULL) {
// return 0;
// }
// 打印float数组的值
ALOGI("QZ jni of battery_write_block_data blockData = %d", blockData);
return blockData;
}
static int battery_read_word_data(JNIEnv* env, jobject clazz, jint _fd, jint _cmd) {
if (!qz_device) {
ALOGI("qz jni device is not open");
// return JNI_FALSE;
}
ALOGI("QZ jni of battery_read_word_data param _fd = %d, _cmd = %d", _fd, _cmd);
QZBatteryReadWordData data;
data.fd = _fd;
data.cmd = _cmd;
jint wordData = qz_device->qz_battery_read_word_data(qz_device, &data);
// if (blockData == NULL) {
// return 0;
// }
// 打印float数组的值
ALOGI("QZ jni of battery_read_word_data wordData = %d", wordData);
return wordData;
}
static int battery_write_word_data(JNIEnv* env, jobject clazz, jint _fd, jint _cmd, jint _val) {
if (!qz_device) {
ALOGI("qz jni device is not open");
// return JNI_FALSE;
}
ALOGI("QZ jni of battery_write_word_data param _fd = %d, _cmd = %d", _fd, _cmd);
QZBatteryWriteWordData data;
data.fd = _fd;
data.cmd = _cmd;
data.value = _val;
jint wordData = qz_device->qz_battery_write_word_data(qz_device, &data);
// if (blockData == NULL) {
// return 0;
// }
// 打印float数组的值
ALOGI("QZ jni of battery_write_word_data wordData = %d", wordData);
return wordData;
}
static int battery_open(JNIEnv* env, jobject clazz, jint _reg) {
if (!qz_device) {
ALOGI("qz jni device is not open");
// return JNI_FALSE;
}
ALOGI("QZ jni of qz_battery_open param _reg = %d", _reg);
QZBatteryOpenData data;
data.reg = _reg;
jint res_code = qz_device->qz_battery_open(qz_device, &data);
// if (blockData == NULL) {
// return 0;
// }
// 打印float数组的值
ALOGI("QZ jni of qz_battery_open res_code = %d", res_code);
return res_code;
}
static int battery_close(JNIEnv* env, jobject clazz, jint _file) {
if (!qz_device) {
ALOGI("qz jni device is not open");
// return JNI_FALSE;
}
ALOGI("QZ jni of qz_battery_close param _file = %d", _file);
QZBatteryCloseData data;
data.file = _file;
jint res_code = qz_device->qz_battery_close(qz_device, &data);
// if (blockData == NULL) {
// return 0;
// }
// 打印float数组的值
ALOGI("QZ jni of qz_battery_close res_code = %d", res_code);
return res_code;
}
static JNINativeMethod sMethods[] = {
{"init", "()Z", (void*)qzbattery_init},
{"QZbatteryReadBlockData", "(IIII)[C", (void*)battery_read_block_data},
{"QZbatteryWriteBlockData", "(IIII)I", (void*)battery_write_block_data},
{"QZbatteryReadWordData", "(II)I", (void*)battery_read_word_data},
{"QZbatteryWriteWordData", "(III)I", (void*)battery_write_word_data},
{"QZbatteryOpen", "(I)I", (void*)battery_open},
{"QZbatteryClose", "(I)I", (void*)battery_close},
};
int request_android_server_qz_BatteryManagerService(JNIEnv* env) {
return jniRegisterNativeMethods(env, "com/android/server/QzBatteryServerManagerService",
sMethods, NELEM(sMethods));
}
} // namespace android
android.bp
hardware/libhardware/modules/qzbattery/test/Android.bp
cc_library_shared {
name: "qzbattery.default",
relative_install_path: "hw",
proprietary: true,
srcs: ["qzbattery_hw.c"],
header_libs: ["libhardware_headers"],
shared_libs: ["liblog"],
}
JNI测试
qzbatterytest.cpp
hardware/libhardware/modules/qzbattery/test/qzbatterytest.cpp
#include <hardware/hardware.h>
#include <hardware/qzbattery.h>
#include <log/log.h>
#include <stdio.h>
#include <stdlib.h>
#define NULL __null
uint16_t addr = 0x0006;
int main(int argc, char *argv[])
{
printf("Number of arguments: %d\n", argc);
for (int i = 0; i < argc; i++)
{
printf("Argument %d: %s\n", i, argv[i]);
}
qzbattery_device_t *battery_device = NULL;
const qzbattery_module_t *module = NULL;
int ret = hw_get_module(QZBATTERY_HARDWARE_MODULE_ID, (const struct hw_module_t **)&module);
if (!ret)
{
ret = module->common.methods->open(&(module->common), QZBATTERY_HARDWARE_MODULE_ID, (struct hw_device_t **)&battery_device);
}
QZBatteryOpenData data;
data.reg = atoi(argv[1]);
printf("data.reg = %x\n", data.reg);
battery_device->qz_battery_test(battery_device, &data);
// if (ret < 0) {
// ALOGD("get battery-hal failed.......");
// return -1;
// }
// BatteryReadBlockData accdata;
// battery_device->battery_read_block_data(battery_device, &accdata);
// BatteryWriteBlockData anglveldata;
// battery_device->battery_write_block_data(battery_device, &anglveldata);
// // 打印加速度传感器数据
// ALOGD("Accelerometer sensor data: accdata = %s\n",accdata);
return 0;
}
android.bp
cc_binary {
name: "qzbattery_hal",
srcs: ["qzbatterytest.cpp"],
cflags: [
"-Wall",
"-Wno-unused-parameter",
"-Werror",
"-DAPP_PLATFORM=android-29",
],
shared_libs: [
"libcutils",
"libhardware",
"liblog",
],
}
HAL服务层
IQzBatteryServiceManager
frameworks/base/core/java/android/app/IQzBatteryServiceManager.aidl
package android.app;
interface IQzBatteryServiceManager{
char[] iBatteryReadBlockData(in int fd,in int cmd,in int len, in int val);
int iBatteryWriteBlockData(in int fd,in int cmd,in int len, in int val);
int iBatteryReadWordData(in int fd,in int cmd);
int iBatteryWriteWordData(in int fd,in int cmd,in int value);
int iBatteryOpen(in int reg);
int iBatteryClose(in int file);
}
QzBatteryServerManager
frameworks/base/core/java/android/app/QzBatteryServerManager.java
package android.app;
import android.content.Context;
import android.annotation.SystemService;
import android.os.RemoteException;
import android.annotation.Nullable;
import android.os.IBinder;
import android.util.Log;
import android.util.Singleton;
import android.util.Slog;
import android.os.ServiceManager;
import android.compat.annotation.UnsupportedAppUsage;
@SystemService(Context.QZ_BATTERY_SERVICE)
public class QzBatteryServerManager {
private static String TAG = "QzBatteryServerManager";
/**
* @hide
*/
@UnsupportedAppUsage
public static IQzBatteryServiceManager getService() {
return IQzBatteryServiceManagerSingleton.get();
}
@UnsupportedAppUsage
private static final Singleton<IQzBatteryServiceManager> IQzBatteryServiceManagerSingleton = new Singleton<IQzBatteryServiceManager>() {
@Override
protected IQzBatteryServiceManager create() {
final IBinder b = ServiceManager.getService(Context.QZ_BATTERY_SERVICE);
final IQzBatteryServiceManager am = IQzBatteryServiceManager.Stub.asInterface(b);
return am;
}
};
public char[] batteryReadBlockDataM(@Nullable int fd, @Nullable int cmd, @Nullable int len, @Nullable int val)
throws RemoteException {
Slog.d(TAG, "fd = " + fd + " cmd = " + cmd + " len=" + len+ " val="+val);
return getService().iBatteryReadBlockData(fd, cmd, len, val);
}
public int batteryWriteBlockData(@Nullable int fd, @Nullable int cmd, @Nullable int len, @Nullable int val) throws RemoteException {
Slog.d(TAG, "fd = " + fd + " cmd = " + cmd + " len=" + len+" val="+val);
return getService().iBatteryWriteBlockData(fd, cmd, len, val);
}
public int btteryReadWordDataM(@Nullable int fd, @Nullable int cmd) throws RemoteException {
Slog.d(TAG, "fd = " + fd + " cmd = " + cmd);
return getService().iBatteryReadWordData(fd, cmd);
}
public int batteryWriteWordDataM(@Nullable int fd, @Nullable int cmd, @Nullable int value) throws RemoteException {
Slog.d(TAG, "fd = " + fd + " cmd = " + cmd + " value=" + value);
return getService().iBatteryWriteWordData(fd, cmd, value);
}
public int batteryOpenM(@Nullable int reg) throws RemoteException {
Slog.d(TAG, "reg = " + reg);
return getService().iBatteryOpen(reg);
}
public int batteryCloseM(@Nullable int file) throws RemoteException {
Slog.d(TAG, "file = " + file);
return getService().iBatteryClose(file);
}
/**
* @hide
*/
public QzBatteryServerManager() {
Slog.d(TAG, "......start success!");
}
}
QzBatteryServerManagerService
frameworks/base/services/core/java/com/android/server/QzBatteryServerManagerService.java
package com.android.server;
import android.annotation.Nullable;
import android.os.RemoteException;
import android.util.Slog;
import android.app.IQzBatteryServiceManager;
public class QzBatteryServerManagerService extends IQzBatteryServiceManager.Stub {
private static final String TAG = "QzBatteryServerManagerService";
public QzBatteryServerManagerService() {
boolean result = init();
if(result){
Slog.d(TAG, "init success");
}else{
Slog.d(TAG, "init error");
}
Slog.d(TAG, "......start success! result = "+result);
}
public void charArrayToHex(char[] charArray) {
for (char c : charArray) {
String hexChar = String.format("%02x", (int) c); // 使用 %02x 格式化为十六进制
Slog.i(TAG, "......hexChar = "+hexChar);
}
}
@Override
@Nullable
public char[] iBatteryReadBlockData(int fd, int cmd, int len, int val) throws RemoteException {
Slog.d(TAG, "......exec qzbattery read block data fd =" + fd + " cmd=" + cmd + " len=" + len+" val="+val);
charArrayToHex(QZbatteryReadBlockData(fd, cmd, len, val));
return QZbatteryReadBlockData(fd, cmd, len, val);
}
@Override
@Nullable
public int iBatteryWriteBlockData(int fd, int cmd, int len, int val) throws RemoteException{
Slog.d(TAG, "......exec qzbattery write block data fd =" + fd + " cmd=" + cmd + " len=" + len+ " val="+val);
return QZbatteryWriteBlockData(fd, cmd, len, val);
}
@Override
@Nullable
public int iBatteryReadWordData(int fd, int cmd) throws RemoteException{
Slog.d(TAG, "......exec qzbattery read word data fd =" + fd + " cmd=" + cmd);
return QZbatteryReadWordData(fd, cmd);
}
@Override
@Nullable
public int iBatteryWriteWordData(int fd, int cmd, int value) throws RemoteException{
Slog.d(TAG, "......exec qzbattery write word data fd =" + fd + " cmd=" + cmd + " value=" + value);
return QZbatteryWriteWordData(fd, cmd, value);
}
@Override
@Nullable
public int iBatteryOpen(int reg) throws RemoteException {
Slog.d(TAG, "......exec qzbattery open reg =" + reg);
return QZbatteryOpen(reg);
}
@Override
@Nullable
public int iBatteryClose(int file) throws RemoteException {
Slog.d(TAG, "......exec qzbattery close file =" + file);
return QZbatteryClose(file);
}
private static native boolean init();
private static native char[] QZbatteryReadBlockData(int fd, int cmd, int len, int val);
private static native int QZbatteryWriteBlockData(int fd, int cmd, int len, int val);
private static native int QZbatteryReadWordData(int fd, int cmd);
private static native int QZbatteryWriteWordData(int fd, int cmd, int value);
private static native int QZbatteryOpen(int reg);
private static native int QZbatteryClose(int fd);
}
系统配置文件更改
frameworks/base/core/java/android/content/Context.java
frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/core/java/android/app/SystemServiceRegistry.java
Context.java
public static final String QZ_BATTERY_SERVICE = "qz_battery";
QZ_BATTERY_SERVICE
SystemServer.java
// 添加位置:startOtherServices方法
// 添加内容如下
// 此处一定要记得捕获异常
t.traceBegin("StartQzBatteryManagerService");
try {
ServiceManager.addService(Context.QZ_BATTERY_SERVICE,
new QzBatteryServerManagerService());
} catch (Throwable e) {
Slog.e(TAG, "Failure starting QzBatteryServerManagerService", e);
}
t.traceEnd();
SystemServiceRegistry.java
registerService(Context.QZ_BATTERY_SERVICE, QzBatteryServerManager.class,
new CachedServiceFetcher<QzBatteryServerManager>() {
@Override
public QzBatteryServerManager createService(ContextImpl ctx) {
return new QzBatteryServerManager();
}});
APP调用
安卓源码下导出Jar包
// 进入源码目录out/target/common/obj/JAVA_LIBRARIES/framework-minus-apex_intermediates下运行以下命令
// 解压查看是否有自定义的QzBatteryServerManager类源文件
jar -tf classes.jar
#解压出QzBatteryServerManager.class
jar -xvf classes.jar android/app/QzBatteryServerManager.class
#打包成QzBatteryServerManager.jar供APP使用
jar -cvf QzBatteryServerManager.jar android
APP调用
- 将Jar放置在APP-Demo的libs目录下
// app文件夹下build.gradle导入jar包
implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])
- 调用服务,读取数据
package com.example.testdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.app.QzBatteryServerManager;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.widget.TextView;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final String SERVICE_NAME = "qz_battery";
QzBatteryServerManager qzBatteryServerManager;
private int fd;
private String lastSn = null; // 上一次的SN
private String readSn = null; // 现在读到的SN
private String resultStr = "测试结果:"; // 测试结果提醒
private boolean resultFlag = true; // 测试结果标志
@SuppressLint("WrongConstant")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
try {
qzBatteryServerManager = (QzBatteryServerManager) getSystemService(SERVICE_NAME);
fd = qzBatteryServerManager.batteryOpenM(84);
// 第一步:连接一个电池然后读出参数显示
// 第二步:连接到新电池时,先读取SN,判断SN号不一样,则为界面赋值新的电池参数,然后改变上一次SN
readSN();
readBatteryParam();
} catch (RemoteException e) {
e.printStackTrace();
}
new MyThread().run();
}
public static String charArrayToHex(char[] charArray) {
StringBuilder hexBuilder = new StringBuilder();
for (char c : charArray) {
String hexChar = String.format("%02x", (int) c); // 使用 %02x 格式化为十六进制
Log.i(TAG, "......hexChar = " + hexChar);
hexBuilder.append(hexChar);
}
return hexBuilder.toString();
}
Handler handler = new Handler();
public class MyThread implements Runnable {
@Override
public void run() {
// 循环最开始初始化参数
resultFlag = true;
// 读取一次参数延迟时间
handler.postDelayed(this, 3000);
Log.i(TAG, "......readSN = " + readSn + " lastSn = " + lastSn);
readSN();
if (readSn.equals("001980-FFFFFFFA")) {
setWaiting();
return;
}
readBatteryParam();
}
}
private TextView text_relativeStateOfCharge;
private TextView text_absoluteStateOfCharge;
private TextView text_stateOfHealth;
private TextView text_serialNumber;
private TextView text_voltage;
private TextView text_remainingCapacity;
private TextView text_operationStatus;
private TextView text_temperature;
private TextView text_result;
public void initViews() {
text_relativeStateOfCharge = findViewById(R.id.text_relativeStateOfCharge);
text_absoluteStateOfCharge = findViewById(R.id.text_absoluteStateOfCharge);
text_stateOfHealth = findViewById(R.id.text_stateOfHealth);
text_serialNumber = findViewById(R.id.text_serialNumber);
text_voltage = findViewById(R.id.text_voltage);
text_remainingCapacity = findViewById(R.id.text_remainingCapacity);
text_operationStatus = findViewById(R.id.text_operationStatus);
text_temperature = findViewById(R.id.text_temperature);
text_result = findViewById(R.id.text_result);
}
/**
* 正则表达式验证SN号
*
* @param input
* @return
*/
public static boolean isFormatValid(String input) {
String pattern = "^(0[1-9]|1[0-2])(20\\d{2})-(\\d{4})$";
Pattern regex = Pattern.compile(pattern);
Matcher matcher = regex.matcher(input);
return matcher.matches();
}
private void readBatteryParam() {
try {
setTextView(text_serialNumber, isFormatValid(readSn) == true, readSn, BatteryParamEnum.SERIAL_NUMBER);
Log.i(TAG, "================= readSn= " + readSn + " lastSn = " + lastSn);
Log.i(TAG, "================= readSn==lastSn : " + (readSn.equals(lastSn)));
Log.i(TAG, "......QZ Battery 绝对电量");
int absoluteStateOfCharge = readWordData(fd, BatteryParamEnum.ABSOLUTE_STATE_OF_CHARGE.getCmd());// 绝对电量
Log.i(TAG, "......QZ Battery 相对电量");
int relativeStateOfCharge = readWordData(fd, BatteryParamEnum.RELATIVE_STATE_OF_CHARGE.getCmd());// 相对电量
Log.i(TAG, "......QZ Battery 电池健康");
int stateOfHealth = readWordData(fd, BatteryParamEnum.STATE_OF_HEALTH.getCmd());// 电池健康
Log.i(TAG, "......QZ Battery 电压");
int vo1 = readWordData(fd, BatteryParamEnum.VOLTAGE.getCmd());// Cell 1 电压
Log.i(TAG, "......QZ Battery 电池mode");
int batteryMode = readWordData(fd, BatteryParamEnum.BATTERY_MODE.getCmd());// 电池容量
Log.i(TAG, "......QZ batteryMode = " + Integer.toHexString(batteryMode));
Log.i(TAG, "......QZ Battery 电池容量");
int remainingCapacity = readWordData(fd, BatteryParamEnum.REMAINING_CAPACITY.getCmd());// 电池容量
Log.i(TAG, "......QZ Battery 操作状态");
int value = -1;
boolean operationStatus = getOperationStatus();// 操作状态
Log.i(TAG, "......QZ Battery value = " + value);
Log.i(TAG, "......QZ Battery 电池温度");
int temperature = readWordData(fd, BatteryParamEnum.TEMPERATURE.getCmd());// 电池温度
double formatTemperature = (double) (temperature - 2732) / 10;
Log.i(TAG, "......readSn ......更新UI");
setTextView(text_absoluteStateOfCharge, (absoluteStateOfCharge > 0 && absoluteStateOfCharge < 100), absoluteStateOfCharge, BatteryParamEnum.ABSOLUTE_STATE_OF_CHARGE);
setTextView(text_relativeStateOfCharge, (relativeStateOfCharge < 100 && relativeStateOfCharge > 0), relativeStateOfCharge, BatteryParamEnum.RELATIVE_STATE_OF_CHARGE);
setTextView(text_stateOfHealth, stateOfHealth >= 99, stateOfHealth, BatteryParamEnum.STATE_OF_HEALTH);
setTextView(text_voltage, (vo1 < 12000 && vo1 > 11000), vo1, BatteryParamEnum.VOLTAGE);
setTextView(text_remainingCapacity, remainingCapacity > 0, remainingCapacity, BatteryParamEnum.REMAINING_CAPACITY);
setTextView(text_operationStatus, operationStatus, operationStatus ? "正常" : "异常", BatteryParamEnum.OPERATION_STATUS);
setTextView(text_temperature, (Double.compare(formatTemperature, new Double("30.0")) == -1 && temperature > 0), formatTemperature, BatteryParamEnum.TEMPERATURE);
// 得出测试结果
resultStr = resultFlag ? "测试通过,请插入下一个电池" : "测试失败,请贴上不良标签";
text_result.setText(resultStr);
text_result.setBackgroundColor(resultFlag ? greenColor : redColor);
// 循环结束,给参数更新数值
lastSn = readSn;
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
* 未插入电池时,清空参数,提醒插入电池
*/
private void setWaiting() {
text_relativeStateOfCharge.setText("......请插入电池......");
text_absoluteStateOfCharge.setText("......请插入电池......");
text_stateOfHealth.setText("......请插入电池......");
text_serialNumber.setText("......请插入电池......");
text_voltage.setText("......请插入电池......");
text_remainingCapacity.setText("......请插入电池......");
text_operationStatus.setText("......请插入电池......");
text_temperature.setText("......请插入电池......");
text_result.setText("");
text_relativeStateOfCharge.setBackgroundColor(warningColor);
text_absoluteStateOfCharge.setBackgroundColor(warningColor);
text_stateOfHealth.setBackgroundColor(warningColor);
text_serialNumber.setBackgroundColor(warningColor);
text_voltage.setBackgroundColor(warningColor);
text_remainingCapacity.setBackgroundColor(warningColor);
text_operationStatus.setBackgroundColor(warningColor);
text_temperature.setBackgroundColor(warningColor);
text_result.setBackgroundColor(Color.WHITE);
}
/**
* 读取电池SN
*
* @return
*/
private String readSN() {
String sn = "";
try {
Log.i(TAG, "......QZ Battery 生产日期");
int date = 0;// 生产日期
date = readWordData(fd, BatteryParamEnum.MANUFACTURER_DATE.getCmd());
int year = date / 512 + 1980;
int month = (date % 512) / 32;
int day = (date % 512) % 32;
String manufacturerDate = (month < 10 ? "0" + month : month + "") + year;
Log.i(TAG, "......QZ Battery 生产日期 = " + manufacturerDate);
Log.i(TAG, "......QZ Battery 序列号");
int serialNumber = readWordData(fd, BatteryParamEnum.SERIAL_NUMBER.getCmd());// 序列号
Log.i(TAG, "......QZ Battery format serial number = " + String.format("%04X", serialNumber));
sn = manufacturerDate + "-" + String.format("%04X", serialNumber);
readSn = sn;
} catch (RemoteException e) {
e.printStackTrace();
}
return sn;
}
private boolean getOperationStatus() throws RemoteException {
int cmd = 0x44;
int len = 6;
int val = 0x5400;
char[] blockData = readBlockData(fd, cmd, len, val);
Log.i(TAG, "......QZ getOperationStatus = " + charArrayToHex(blockData));
String hexChar = String.format("%02x", (int) blockData[4]);
if (hexChar.equals("ff")) {
return false;
}
int data = blockData[4] & 3;
return data == 3;
}
/**
* 读取Block数据
*
* @param fd 文件
* @param cmd 读取命令
* @return
* @throws RemoteException
*/
private char[] readBlockData(int fd, int cmd, int len, int val) throws RemoteException {
int i = qzBatteryServerManager.batteryWriteBlockData(fd, cmd, 2, val);
Log.i(TAG, "......QzBatteryServerManagerService i= " + i);
return qzBatteryServerManager.batteryReadBlockDataM(fd, cmd, 6, val);
}
/**
* 读取Word数据
*
* @param fd 文件
* @param cmd 读取命令
* @return
* @throws RemoteException
*/
private int readWordData(int fd, int cmd) throws RemoteException {
return qzBatteryServerManager.btteryReadWordDataM(fd, cmd);
}
/**
* @param tv 文本框
* @param res 判断表达式
* @param data 数据
* @param labelEnum 数据Label
* @throws RemoteException
*/
private static final int greenColor = Color.GREEN;
private static final int redColor = Color.RED;
private static final int warningColor = Color.YELLOW;
private String setTextView(TextView tv, boolean res, Object data, BatteryParamEnum labelEnum) throws RemoteException {
if (res == false) {
resultFlag = false;
}
tv.setBackgroundColor(res == true ? greenColor : redColor);
String str = labelEnum.getLabel() + " : " + data + labelEnum.getSymbol();
tv.setText(str);
return str;
}
}