| #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; | |
| } | |