blob: 6d5d3e823dbe5cfeceab45a6433c8ae78dc1d03a [file] [log] [blame]
#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, &notify_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, &notification_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, &notification_event, fota_request_id);
uloop_run();
ubus_unsubscribe(fota_ubus_ctx, &notification_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;
}