QFirehose 目前支持两种进度通知方式。基于文件的通知方式,基于消息队列的通知机制。两种方式均可使用。Android设备由于系统限制,system V IPC 机制支持不完善,不能支持消息队列的方式获取进度。
其中基于文件的形式很容易替换成,有名管道的形式,只需把创建并打开改成创建并打开管道的形式(参考
man mkfifio
)。「注:管道需要先以读方式打开,再以写方式打开,否则会有错误」
QFirehose 进度都是以整数形式写到文件或者消息队列里。
文件方式的交互文件路径为: Android “/data/update.conf”, 其他 “/tmp/update.conf”。(修改QFirehose 源码可以修改这个文件)。另外需要保证/data 或者/tmp 这个目录存在,且QFirehose有读写、创建文件的权限。 由于文件是持续存在磁盘上的。为了保证命令行方式的cat 读与标准API 的read 两种方式的可读性。进度写方式为覆盖写,意思就是新的进度会覆盖掉之前的内容。表现在实现上就是,每次写之前移动文件指针到文件头,然后写入进度。读进度时候需要注意这一点!!! 另外注意的是QFirehose 不负责文件的删除,如果需要删除需要由第三方程序在升级结束/出错删除进度文件!
QFirehose 默认不使能通知功能。如需使能文件方式通知逻辑需要在编译时指定宏 USE_IPC_FILE , 建议在Makefile里用 -DUSE_IPC_FILE来使能. 如下代码所示
NDK_BUILD:=/workspace/android-ndk/android-ndk-r10e/ndk-build
ifeq ($(CC),cc)
CC=${CROSS_COMPILE}gcc
endif
cflags += -Wno-format-overflow
linux: clean
${CC} -g -Wall -DUSE_IPC_FILE -s ${cflags} firehose_protocol.c qfirehose.c sahara_protocol.c usb_linux.c stream_download_protocol.c md5.c usb2tcp.c -o QFirehose -lpthread -ldl
clean:
rm -rf QFirehose obj libs android usb2tcp *~
System V 方式消息队列。QFirehose 负责创建消息队列,写入进度。不负责删除消息,不负责删除消息队列。 如下图,QFirehose 定义的消息结构体,消息类型,与message key 获取机制。第三方应用需要与QFirehose 保持一致。如需修改,可以修改QFirehose 源码。
System V message queue:
#define MSGBUFFSZ 16
struct message
{
long mtype;
char mtext[MSGBUFFSZ];
};
#define MSG_FILE "/etc/passwd"
#define MSG_TYPE_IPC 1
并同时修改编译脚本/源码,定义宏 USE_IPC_MSG, 如下所示
NDK_BUILD:=/workspace/android-ndk/android-ndk-r10e/ndk-build
ifeq ($(CC),cc)
CC=${CROSS_COMPILE}gcc
endif
cflags += -Wno-format-overflow
linux: clean
${CC} -g -Wall -DUSE_IPC_MSG -s ${cflags} firehose_protocol.c qfirehose.c sahara_protocol.c usb_linux.c stream_download_protocol.c md5.c usb2tcp.c -o QFirehose -lpthread -ldl
clean:
rm -rf QFirehose obj libs android usb2tcp *~
QFirehose 实现了四个操作函数:消息队列的创建,删除,写,读。但是只用到了创建与读函数。另外两个仅供参考与测试用。
QFirehose 负责创建消息队列,写入进度。不会删除消息以及消息队列。建议第三方应用在升级程序退出之后主动删除消息队列。
QFirehose 支持对消息队列的测试,这需要启用宏 IPC_TEST 。开启这个宏之后,QFirehose 会在写入消息后再次读取消息,并打印到STDOUT
,检查打印可知是否正确。
/**
* this function will not delete the msg queue
*/
int update_progress_msg(int percent)
{
char buff[MSGBUFFSZ];
int msgid = msg_get();
if (msgid < 0)
return -1;
snprintf(buff, sizeof(buff), "%d", percent);
#ifndef IPC_TEST
return msg_send(msgid, MSG_TYPE_IPC, buff);
#else
msg_send(msgid, MSG_TYPE_IPC, buff);
struct message info;
info.mtype = MSG_TYPE_IPC;
msg_recv(msgid, &info);
printf("msg queue read: %s\n", info.mtext);
#endif
}