#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <pthread.h> | |
#include <libubox/blobmsg_json.h> | |
#include "libubus.h" | |
#include <semaphore.h> | |
#include <cutils/properties.h> | |
#include <libubox/blob.h> | |
#include <libubox/uloop.h> | |
#include <libubox/usock.h> | |
#include <libubox/list.h> | |
#include <libubus.h> | |
#include <uci.h> | |
#include <sys/ioctl.h> | |
#include <mtd/mtd-user.h> | |
#include "mbtk_fota.h" | |
#include "mbtk_log.h" | |
#include "mbtk_utils.h" | |
#include "mbtk_type.h" | |
#ifdef DEBUG | |
#define fota_log(...) printf(__VA_ARGS__) | |
#else | |
#define fota_log(...) | |
#endif | |
#define OTA_MAX_STRING_LEN 128 | |
static struct ubus_context *fota_ubus_ctx = NULL; | |
static uint32_t fota_request_id; | |
static struct ubus_subscriber notification_event; | |
static pthread_t fota_status_pthread; | |
static struct blob_buf b; | |
static fota_callback fota_cb = NULL; | |
sem_t sem; | |
volatile int fota_dowload_flag = -1; | |
//3: upding | |
//4: updata success | |
//5: updata fail | |
enum { | |
ATTR_SMSGPS, | |
ATTR_SMSGPS_MAX, | |
}; | |
static const struct blobmsg_policy ota_info_attr_policy[] = { | |
[ATTR_SMSGPS] ={.name = "notification", .type = BLOBMSG_TYPE_STRING,}, | |
}; | |
/** | |
* \brief strstr_n | |
* | |
* find string return number | |
* | |
* \param param | |
* \return return type | |
*/ | |
static int strstr_n(const char *s1, const char *s2) | |
{ | |
int n; | |
int strlen = 0; | |
if(*s2) { | |
while(*s1) { | |
for(n = 0; *(s1+n) == *(s2 + n); n++) { | |
if(!*(s2 + n + 1)) { | |
strlen++; | |
return strlen; | |
} | |
} | |
s1++; | |
strlen++; | |
} | |
return 0; | |
} | |
else | |
return 0; | |
} | |
static int otad_notify(struct ubus_context* ctx, struct ubus_object* obj, | |
struct ubus_request_data* req, const char* method, | |
struct blob_attr* msg) | |
{ | |
UNUSEDPARAM(ctx); | |
UNUSEDPARAM(obj); | |
UNUSEDPARAM(req); | |
UNUSEDPARAM(method); | |
// User can get downloading process information from here | |
int ret, len; | |
char progress[4] = {0}; | |
char *notify_str; | |
struct blob_attr *tb[ATTR_SMSGPS_MAX]; | |
ret = blobmsg_parse(ota_info_attr_policy, ARRAY_SIZE(ota_info_attr_policy), tb, | |
blob_data(msg), blob_len(msg)); | |
if (ret || !tb[ATTR_SMSGPS]) { | |
printf("invalid SMS\n"); | |
return -1; | |
} | |
notify_str = blobmsg_get_string(tb[ATTR_SMSGPS]); | |
len = strlen(notify_str); | |
LOGE("%s : %s\r\n", __FUNCTION__, notify_str); | |
// printf("L11111%s : %s\r\n", __FUNCTION__, notify_str); | |
if (strstr_n(notify_str, "start")) { | |
fota_cb(0, 0); | |
} else if (strstr_n(notify_str, "end[1]")) { | |
fota_cb(0, 100); | |
fota_dowload_flag = 4; | |
// sem_post(&sem); | |
LOGE("download firmware success!\r\n"); | |
} else if (strstr_n(notify_str, "end[0]")) { | |
fota_cb(1, 100); | |
fota_dowload_flag = 5; | |
// sem_post(&sem); | |
LOGE("download firmware fail!\r\n"); | |
} | |
ret = strstr_n(notify_str, "progress"); | |
if (ret) { | |
memcpy(progress, ¬ify_str[ret + 8], len - ret - 9); | |
fota_cb(0, atoi(progress)); | |
} | |
return 0; | |
} | |
static void otad_subscriber_remove_cb(struct ubus_context* ctx, | |
struct ubus_subscriber* obj, uint32_t id) | |
{ | |
UNUSEDPARAM(ctx); | |
UNUSEDPARAM(obj); | |
UNUSEDPARAM(id); | |
LOGE("%s,%d\n", __FUNCTION__, __LINE__); | |
} | |
/******************************************************************************* | |
* @brief write firmware package, the firmware package is written in segments. | |
and The result of the write is output by calling the callback function. | |
the firmware package size must less than 32MB | |
@param | |
fname: firmware package file | |
segment_size: the length of once write, recommending 3*1024*1024 bytes | |
@return | |
if success return 0, else return -1 | |
*******************************************************************************/ | |
int mbtk_fota_fw_write(char* fname, int segment_size) | |
{ | |
fota_dowload_flag = 3; | |
LOGE("mbtk_fota_fw_write start3\n"); | |
int ret = -1; | |
static struct ubus_request req; | |
int _segment_size; | |
char cmd[128]={0}; | |
if(!access("/sys/power/wake_lock", W_OK)) | |
{ | |
sprintf(cmd, "echo %s > /sys/power/wake_lock", "ota_lock"); | |
mbtk_system(cmd); | |
LOGE("/sys/power/wake_lock success\n"); | |
} | |
else | |
{ | |
LOGE("/sys/power/wake_lock can not write.\n"); | |
} | |
blob_buf_init(&b, 0); | |
blobmsg_add_string(&b, "url", fname); | |
blobmsg_add_u32(&b, "type", 2); | |
blobmsg_add_u32(&b, "sync", 1); | |
_segment_size = segment_size; | |
if (_segment_size > 1024) { | |
blobmsg_add_u32(&b, "segment_size", _segment_size); | |
} | |
blobmsg_add_u32(&b, "sync", 1); | |
ubus_invoke_async(fota_ubus_ctx, fota_request_id, "download", b.head, &req); | |
ubus_complete_request_async(fota_ubus_ctx, &req); | |
while(1) | |
{ | |
/* V2������ */ | |
// sem_wait(&sem); | |
// break; | |
if(fota_dowload_flag != 3) | |
{ | |
// printf("break while(), fota_dowload_flag:%d", fota_dowload_flag); | |
break; | |
} | |
sleep(1); | |
} | |
if(!access("/sys/power/wake_unlock", W_OK)) | |
{ | |
char cmd[128]={0}; | |
sprintf(cmd, "echo %s > /sys/power/wake_unlock", "ota_lock"); | |
mbtk_system(cmd); | |
LOGE("/sys/power/wake_unlock success\n"); | |
} | |
else | |
{ | |
LOGE("/sys/power/wake_unlock can not write.\n"); | |
} | |
LOGE("%s, fota_dowload_flag = :%d", __FUNCTION__, fota_dowload_flag); | |
if(fota_dowload_flag == 4) | |
{ | |
ret = 0; | |
} | |
return ret; | |
} | |
/******************************************************************************* | |
* @brief download firmware by url, and write firmware package, the firmware | |
package is written in segments. The result of the write is output by | |
calling the callback function. the firmware package size must less than | |
32MB | |
@param | |
url: [IN] the address of download firmware package file, the url | |
support http or https protocol. | |
segment_size: [IN] the length of once write, recommending 3*1024*1024 bytes | |
conn_timeout: [IN] timeout to connect to the server, if set 0 that means | |
switch to the default build-in connection timeout(300s) | |
download_timeout: [IN] timeout for download the firmware file. if set 0 that means | |
it never time out | |
@return | |
if success return 0, else return -1 | |
*******************************************************************************/ | |
int mbtk_fota_fw_write_by_url(char* url, int segment_size, | |
int conn_timeout, int download_timeout) | |
{ | |
LOGE("mbtk_fota_fw_write_by_url start2\n"); | |
int ret = -1; | |
fota_dowload_flag = 3; | |
static struct ubus_request req; | |
int _segment_size; | |
char cmd[128]={0}; | |
if(!access("/sys/power/wake_lock", W_OK)) | |
{ | |
sprintf(cmd, "echo %s > /sys/power/wake_lock", "ota_lock"); | |
mbtk_system(cmd); | |
LOGE("/sys/power/wake_lock success\n"); | |
} | |
else | |
{ | |
LOGE("/sys/power/wake_lock can not write.\n"); | |
} | |
blob_buf_init(&b, 0); | |
blobmsg_add_string(&b, "url", url); | |
blobmsg_add_string(&b, "username", "user name"); | |
blobmsg_add_u32(&b, "type", 0); | |
blobmsg_add_u32(&b, "sync", 1); | |
_segment_size = segment_size; | |
if (_segment_size > 1024) { | |
blobmsg_add_u32(&b, "segment_size", _segment_size); | |
} | |
blobmsg_add_u32(&b, "sync", 1); | |
ubus_invoke_async(fota_ubus_ctx, fota_request_id, "download", b.head, &req); | |
ubus_complete_request_async(fota_ubus_ctx, &req); | |
while(1) | |
{ | |
/* V2������ */ | |
// sem_wait(&sem); | |
// break; | |
if(fota_dowload_flag != 3) | |
{ | |
// printf("break while(), fota_dowload_flag:%d", fota_dowload_flag); | |
break; | |
} | |
sleep(1); | |
} | |
if(!access("/sys/power/wake_unlock", W_OK)) | |
{ | |
char cmd[128]={0}; | |
sprintf(cmd, "echo %s > /sys/power/wake_unlock", "ota_lock"); | |
mbtk_system(cmd); | |
LOGE("/sys/power/wake_unlock success\n"); | |
} | |
else | |
{ | |
LOGE("/sys/power/wake_unlock can not write.\n"); | |
} | |
LOGE("%s, fota_dowload_flag = :%d", __FUNCTION__, fota_dowload_flag); | |
if(fota_dowload_flag == 4) | |
{ | |
ret = 0; | |
} | |
return ret; | |
} | |
/******************************************************************************* | |
* @brief reboot system and clear env | |
@param | |
is_reboot: if set 1, after fota success, reboot system | |
@return | |
if success return 0, else return -1 | |
*******************************************************************************/ | |
int mbtk_fota_done(int is_reboot) | |
{ | |
int ret; | |
ret = pthread_cancel(fota_status_pthread); | |
LOGE("kill pthread : %d \n", ret); | |
pthread_join(fota_status_pthread, NULL); | |
do { | |
ret = pthread_kill(fota_status_pthread, 0); | |
LOGE("kill pthread: %d \n", ret); | |
if (ret == ESRCH) { | |
LOGE("The specified thread does not exist or has terminated\n"); | |
} else if (ret == EINVAL) { | |
LOGE("Useless signal\n"); | |
} else { | |
LOGE("The thread exists\n"); | |
} | |
usleep(100000); | |
} while (0 == ret); | |
ubus_free(fota_ubus_ctx); | |
uloop_done(); | |
fota_cb = NULL; | |
if (is_reboot) { | |
mbtk_system("sync"); | |
mbtk_system("reboot"); | |
} | |
return 0; | |
} | |
int mbtk_fota_done1(int is_reboot) | |
{ | |
if (is_reboot) { | |
mbtk_system("sync"); | |
mbtk_system("reboot"); | |
} | |
return 0; | |
} | |
void* mbtk_fota_thread(void* argc) | |
{ | |
int ret; | |
UNUSEDPARAM(argc); | |
printf("mbtk_fota_thread() start\n"); | |
pthread_detach(pthread_self()); | |
//register for ril indication | |
ret = ubus_register_subscriber(fota_ubus_ctx, ¬ification_event); | |
if (ret) { | |
LOGE("%s,%d\n", __FUNCTION__, __LINE__); | |
pthread_exit(NULL); | |
} | |
notification_event.cb = otad_notify; | |
notification_event.remove_cb = otad_subscriber_remove_cb; | |
ubus_subscribe(fota_ubus_ctx, ¬ification_event, fota_request_id); | |
uloop_run(); | |
ubus_unsubscribe(fota_ubus_ctx, ¬ification_event, fota_request_id); | |
pthread_exit(NULL); | |
return NULL; | |
} | |
int mbtk_fota_init(fota_callback cb) | |
{ | |
int retries = 0; | |
/*create ubus loop to listen to RIL event*/ | |
uloop_init(); | |
fota_ubus_ctx = ubus_connect(NULL); | |
if (!fota_ubus_ctx) { | |
LOGE("%s,%d\n", __FUNCTION__, __LINE__); | |
uloop_done(); | |
return 0; | |
} | |
ubus_add_uloop(fota_ubus_ctx); | |
do { | |
//register for ril request | |
retries = 0; | |
if (ubus_lookup_id(fota_ubus_ctx, "ota", &fota_request_id)) { | |
LOGE("%s,%d\n", __FUNCTION__, __LINE__); | |
sleep(1); | |
} else { | |
break; | |
} | |
} while (retries++ < 20); | |
if (retries >= 20) { | |
LOGE("%s,%d\n", __FUNCTION__, __LINE__); | |
goto fail1; | |
} | |
pthread_create(&fota_status_pthread, NULL, (void*)mbtk_fota_thread, NULL); | |
fota_cb = cb; | |
return 0; | |
fail1: | |
return 1; | |
} | |
int mbtk_fota_get_asr_reboot_cnt_flag(void) | |
{ | |
int type = 0; | |
char time_type[] ={0}; | |
property_get("persist.mbtk.reboot_cnt", time_type, "0"); | |
type = atoi(time_type); | |
return type; | |
} | |
int mbtk_fota_status(void) | |
{ | |
return fota_dowload_flag; | |
} | |
void mbtk_fota_lib_info_print() | |
{ | |
MBTK_SOURCE_INFO_PRINT("mbtk_fota_lib"); | |
} | |
int mbtk_fota_get_active_absys_type(void) | |
{ | |
int type = 0; | |
char tmp_type[] ={0}; | |
property_get("persist.mbtk.absys_active", tmp_type, "0"); | |
type = atoi(tmp_type); | |
if (type == 97) | |
{ | |
type = mbtk_sys_A; | |
} | |
else if (type == 98) | |
{ | |
type = mbtk_sys_B; | |
} | |
else | |
{ | |
LOGE("get_active_absys_type %s fail",tmp_type); | |
type = -1; | |
} | |
return type; | |
} | |
int mbtk_fota_get_tmp_absys_type(void) | |
{ | |
int type = 0; | |
char tmp_type[] ={0}; | |
property_get("persist.mbtk.absys_tmp", tmp_type, "0"); | |
type = atoi(tmp_type); | |
if (type == 97) | |
{ | |
type = mbtk_sys_A; | |
} | |
else if (type == 98) | |
{ | |
type = mbtk_sys_B; | |
} | |
else | |
{ | |
LOGE("get_tmp_absys_type %s fail",tmp_type); | |
type = -1; | |
} | |
return type; | |
} | |
int mbtk_fota_get_sync_absys_type(void) | |
{ | |
int type = 0; | |
char tmp_type[] ={0}; | |
property_get("persist.mbtk.absys_sync", tmp_type, "0"); | |
type = atoi(tmp_type); | |
return type; | |
} | |
int mbtk_fota_get_mtd_check_type(void) | |
{ | |
int type = 0; | |
char tmp_type[] ={0}; | |
property_get("persist.mbtk.mtd_check", tmp_type, "0"); | |
type = atoi(tmp_type); | |
return type; | |
} | |