1 
2 /*
3  * Copyright (C) 2015-2019 Alibaba Group Holding Limited
4  */
5 
6 #include <stdarg.h>
7 #include <string.h>
8 
9 #include "aos_system.h"
10 #include "board_config.h"
11 #include "py/builtin.h"
12 #include "py/obj.h"
13 #include "py/runtime.h"
14 #include "py/stackctrl.h"
15 #include "py_defines.h"
16 //#include "be_inl.h"
17 #include "amp_utils.h"
18 #include "app_upgrade.h"
19 #include "module_aiot.h"
20 #include "ota_agent.h"
21 #include "ota_import.h"
22 
23 #define MOD_STR "APP_OTA"
24 
25 static ota_service_t customer_ota_ctx = { 0 };
26 static ota_store_module_info_t customer_module_info[3];
27 static aos_task_t user_module_ota_task = { 0 };
28 static char default_ver[128] = {0};
29 typedef struct ota_package_info {
30     int res;
31     int js_cb_ref;
32     unsigned int length;
33     char version[64];
34     char module_name[64];
35     int hash_type;
36     char hash[64];
37     char store_path[64];
38     char install_path[64];
39     char url[256];
40 } ota_package_info_t;
41 
42 typedef enum {
43     ON_TRIGGER = 1,
44     ON_DOWNLOAD = 2,
45     ON_VERIFY = 3,
46     ON_UPGRADE = 4,
47 } ota_cb_func_t;
48 
49 static mp_obj_t ota_on_trigger;
50 static mp_obj_t ota_on_download;
51 static mp_obj_t ota_on_verify;
52 static mp_obj_t ota_on_upgrade;
53 
ota_install_notify(void * pdata)54 static void ota_install_notify(void *pdata)
55 {
56     ota_package_info_t *ota_package_info = (ota_package_info_t *)pdata;
57 
58     if (mp_obj_is_fun(ota_on_upgrade)) {
59         callback_to_python(ota_on_upgrade,
60                            mp_obj_new_int(ota_package_info->res));
61     } else {
62         amp_error(MOD_STR, "ota_on_trigger is not function");
63     }
64 
65     aos_free(ota_package_info);
66 }
67 
ota_install_handler(void * pdata)68 static void ota_install_handler(void *pdata)
69 {
70     int res = -1;
71     int js_cb_ref;
72     ota_package_info_t *ota_package_info = (ota_package_info_t *)pdata;
73     /* clear jsengine timer, distory js app*/
74     // amp_module_free();
75     // app_js_stop();
76 
77     res = ota_install_pyapp(&customer_ota_ctx, ota_package_info->store_path,
78                             ota_package_info->length,
79                             ota_package_info->install_path);
80     if (res < 0) {
81         amp_error(MOD_STR, "module install failed!");
82     } else {
83         /*启动app.js*/
84         // res = ota_load_jsapp(&customer_ota_ctx);
85         // if(res < 0) {
86         //     amp_error(MOD_STR, "module load failed!");
87         // }
88     }
89     ota_package_info->res = 0;
90 
91     py_task_schedule_call(ota_install_notify, ota_package_info);
92     aos_task_exit(0);
93 }
94 
ota_upgrade(mp_obj_t data)95 static mp_obj_t ota_upgrade(mp_obj_t data)
96 {
97     int res = -1;
98     unsigned int length = 0;
99     const char *install_path = NULL;
100     const char *store_path = NULL;
101     aos_task_t ota_install_task;
102     ota_package_info_t *ota_package_info = NULL;
103 
104     if (!mp_obj_is_dict_or_ordereddict(data)) {
105         amp_error(MOD_STR, "ota_report function param must be dict");
106         return mp_obj_new_int(-1);
107     }
108 
109     /* get verify info */
110     mp_obj_t index = mp_obj_new_str_via_qstr("length", 6);
111     length = mp_obj_get_int(mp_obj_dict_get(data, index));
112 
113     /* get hash_type   */
114     index = mp_obj_new_str_via_qstr("store_path", 10);
115     store_path = mp_obj_str_get_str(mp_obj_dict_get(data, index));
116 
117     /* get install_path   */
118     index = mp_obj_new_str_via_qstr("install_path", 12);
119     install_path = mp_obj_str_get_str(mp_obj_dict_get(data, index));
120 
121     ota_package_info = aos_malloc(sizeof(ota_package_info_t));
122     if (!ota_package_info) {
123         amp_error(MOD_STR, "alloc device notify param fail");
124         return;
125     }
126     memset(ota_package_info, 0x00, sizeof(ota_package_info_t));
127     ota_package_info->length = length;
128     strncpy(ota_package_info->store_path, store_path,
129             sizeof(ota_package_info->store_path));
130     strncpy(ota_package_info->install_path, install_path,
131             sizeof(ota_package_info->install_path));
132 
133     res = aos_task_new_ext(&ota_install_task, "amp ota install task",
134                            ota_install_handler, ota_package_info, 1024 * 10,
135                            AOS_DEFAULT_APP_PRI);
136     if (res != 0) {
137         amp_warn(MOD_STR, "iot create task failed");
138         aos_free(ota_package_info);
139         goto out;
140     }
141 out:
142     mp_obj_new_int(0);
143 }
144 MP_DEFINE_CONST_FUN_OBJ_1(native_ota_upgrade, ota_upgrade);
145 
ota_verify_notify(void * pdata)146 static void ota_verify_notify(void *pdata)
147 {
148     ota_package_info_t *ota_package_info = (ota_package_info_t *)pdata;
149 
150     if (mp_obj_is_fun(ota_on_verify)) {
151         callback_to_python(ota_on_verify,
152                            mp_obj_new_int(ota_package_info->res));
153     } else {
154         amp_error(MOD_STR, "ota_on_verify is not function");
155     }
156 
157     aos_free(ota_package_info);
158 }
159 
ota_verify_handler(void * pdata)160 static void ota_verify_handler(void *pdata)
161 {
162     int res = -1;
163     int js_cb_ref;
164     ota_boot_param_t ota_param = { 0 };
165     ota_package_info_t *ota_package_info = (ota_package_info_t *)pdata;
166 
167     memset(&ota_param, 0, sizeof(ota_boot_param_t));
168 
169     ota_param.len = ota_package_info->length;
170     ota_param.hash_type = ota_package_info->hash_type;
171     strncpy(ota_param.hash, ota_package_info->hash,
172             strlen(ota_package_info->hash));
173     res = ota_verify_fsfile(&ota_param, ota_package_info->store_path);
174     if (res < 0) {
175         amp_error(MOD_STR, "amp jsota verified failed!");
176     }
177     ota_package_info->res = res;
178     py_task_schedule_call(ota_verify_notify, ota_package_info);
179     aos_task_exit(0);
180 }
181 
py_ota_verify(mp_obj_t data)182 static mp_obj_t py_ota_verify(mp_obj_t data)
183 {
184     int res = -1;
185     // int js_cb_ref;
186     aos_task_t ota_verify_task;
187     ota_package_info_t *ota_package_info = NULL;
188 
189     unsigned int length = 0;
190     const char *hash_type = NULL;
191     const char *hash = NULL;
192     const char *store_path = NULL;
193 
194     if (!mp_obj_is_dict_or_ordereddict(data)) {
195         amp_error(MOD_STR, "ota_report function param must be dict");
196         return mp_obj_new_int(-1);
197     }
198 
199     /* get verify info */
200     // duk_get_prop_string(ctx, 0, "length");
201     mp_obj_t index = mp_obj_new_str_via_qstr("length", 6);
202     length = mp_obj_get_int(mp_obj_dict_get(data, index));
203 
204     /* get hash_type   */
205     index = mp_obj_new_str_via_qstr("hash_type", 9);
206     hash_type = mp_obj_str_get_str(mp_obj_dict_get(data, index));
207 
208     /* get hash   */
209     index = mp_obj_new_str_via_qstr("hash", 4);
210     hash = mp_obj_str_get_str(mp_obj_dict_get(data, index));
211 
212     /* get store_path   */
213     index = mp_obj_new_str_via_qstr("store_path", 10);
214     store_path = mp_obj_str_get_str(mp_obj_dict_get(data, index));
215 
216     ota_package_info = aos_malloc(sizeof(ota_package_info_t));
217     if (!ota_package_info) {
218         amp_error(MOD_STR, "alloc device notify param fail");
219         return;
220     }
221     memset(ota_package_info, 0x00, sizeof(ota_package_info_t));
222     ota_package_info->length = length;
223     if (strcmp(hash_type, "null") == 0) {
224         ota_package_info->hash_type = 0;
225     } else if (strcmp(hash_type, "md5") == 0) {
226         ota_package_info->hash_type = 2;
227     } else if (strcmp(hash_type, "sha256") == 0) {
228         ota_package_info->hash_type = 1;
229     } else {
230         ota_package_info->hash_type = 3;
231     }
232     strncpy(ota_package_info->hash, hash, sizeof(ota_package_info->hash));
233     strncpy(ota_package_info->store_path, store_path,
234             sizeof(ota_package_info->store_path));
235 
236     res = aos_task_new_ext(&ota_verify_task, "amp ota verify task",
237                            ota_verify_handler, ota_package_info, 1024 * 10,
238                            AOS_DEFAULT_APP_PRI);
239     if (res != 0) {
240         amp_warn(MOD_STR, "iot create task failed");
241         aos_free(ota_package_info);
242         goto out;
243     }
244 out:
245     return mp_obj_new_int(1);
246 }
247 MP_DEFINE_CONST_FUN_OBJ_1(native_ota_verify, py_ota_verify);
248 
ota_download_notify(void * pdata)249 static void ota_download_notify(void *pdata)
250 {
251     ota_package_info_t *ota_package_info = (ota_package_info_t *)pdata;
252 
253     if (mp_obj_is_fun(ota_on_download)) {
254         callback_to_python(ota_on_download,
255                            mp_obj_new_int(ota_package_info->res));
256     } else {
257         amp_error(MOD_STR, "ota_on_download is not function");
258     }
259 
260     aos_free(ota_package_info);
261 }
262 
ota_download_handler(void * pdata)263 static void ota_download_handler(void *pdata)
264 {
265     int res = -1;
266     int js_cb_ref;
267     ota_package_info_t *ota_package_info = (ota_package_info_t *)pdata;
268 
269     res = ota_download_store_fs_start(
270         ota_package_info->url, strlen(ota_package_info->url),
271         ota_package_info->store_path,
272         customer_ota_ctx.report_func.report_status_cb,
273         customer_ota_ctx.report_func.param);
274     if (res < 0) {
275         amp_error(MOD_STR, "amp jsota download file failed!");
276     }
277 
278     ota_package_info->res = res;
279     py_task_schedule_call(ota_download_notify, ota_package_info);
280     aos_task_exit(0);
281 }
282 
ota_download(mp_obj_t data)283 static mp_obj_t ota_download(mp_obj_t data)
284 {
285     int res = -1;
286     int js_cb_ref;
287     aos_task_t ota_download_task;
288     ota_package_info_t *ota_package_info = NULL;
289     const char *url = NULL;
290     const char *store_path = NULL;
291 
292     if (!mp_obj_is_dict_or_ordereddict(data)) {
293         amp_error(MOD_STR, "ota_report function param must be dict");
294         return mp_obj_new_int(-1);
295     }
296 
297     /* get store path  */
298     mp_obj_t index = mp_obj_new_str_via_qstr("url", 3);
299     url = mp_obj_str_get_str(mp_obj_dict_get(data, index));
300 
301     /* get url  */
302     index = mp_obj_new_str_via_qstr("store_path", 10);
303     store_path = mp_obj_str_get_str(mp_obj_dict_get(data, index));
304 
305     ota_package_info = aos_malloc(sizeof(ota_package_info_t));
306     if (!ota_package_info) {
307         amp_error(MOD_STR, "alloc device notify param fail");
308         return;
309     }
310     memset(ota_package_info, 0x00, sizeof(ota_package_info_t));
311     strncpy(ota_package_info->url, url, sizeof(ota_package_info->url));
312     strncpy(ota_package_info->store_path, store_path,
313             sizeof(ota_package_info->store_path));
314 
315     res = aos_task_new_ext(&ota_download_task, "amp ota download task",
316                            ota_download_handler, ota_package_info, 1024 * 10,
317                            AOS_DEFAULT_APP_PRI);
318     if (res != 0) {
319         amp_warn(MOD_STR, "iot create task failed");
320         aos_free(ota_package_info);
321         goto out;
322     }
323 out:
324     return mp_obj_new_int(1);
325 }
326 MP_DEFINE_CONST_FUN_OBJ_1(native_ota_download, ota_download);
327 
ota_report(mp_obj_t data)328 static mp_obj_t ota_report(mp_obj_t data)
329 {
330     int res = -1;
331     int js_cb_ref;
332     iot_device_handle_t *iot_device_handle = NULL;
333 
334     if (!mp_obj_is_dict_or_ordereddict(data)) {
335         amp_error(MOD_STR, "ota_report function param must be dict");
336         return mp_obj_new_int(-1);
337     }
338 
339     /* get device handle */
340     mp_obj_t index = mp_obj_new_str_via_qstr("device_handle", 13);
341     iot_device_handle = MP_OBJ_TO_PTR(mp_obj_dict_get(data, index));
342 
343     /* get product_key  */
344     index = mp_obj_new_str_via_qstr("product_key", 11);
345     const char *productkey = mp_obj_str_get_str(mp_obj_dict_get(data, index));
346 
347     /* get devicename  */
348     index = mp_obj_new_str_via_qstr("device_name", 11);
349     const char *devicename = mp_obj_str_get_str(mp_obj_dict_get(data, index));
350 
351     /* get module_name  */
352     index = mp_obj_new_str_via_qstr("module_name", 11);
353     const char *modulename = mp_obj_str_get_str(mp_obj_dict_get(data, index));
354 
355     /* get version  */
356     index = mp_obj_new_str_via_qstr("version", 7);
357     const char *ver = mp_obj_str_get_str(mp_obj_dict_get(data, index));
358 
359     amp_warn(MOD_STR, "js report ver!");
360     if  (!strncmp(modulename, "default", strlen("default") + 1)) {
361         strcpy(default_ver, ver);
362     }
363     res = ota_transport_inform(iot_device_handle->mqtt_handle, productkey,
364                                devicename, modulename, ver);
365     if (res < 0) {
366         amp_error(MOD_STR, "amp pyota report ver failed!");
367     }
368 out:
369     return mp_obj_new_int(0);
370 }
371 MP_DEFINE_CONST_FUN_OBJ_1(native_ota_report, ota_report);
372 
ota_trigger_notify(void * pdata)373 static void ota_trigger_notify(void *pdata)
374 {
375     ota_package_info_t *ota_package_info = (ota_package_info_t *)pdata;
376 
377     mp_obj_t dict = mp_obj_new_dict(4);
378     mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), mp_obj_new_str("length", 6),
379                       mp_obj_new_int(ota_package_info->length));
380     mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), mp_obj_new_str("module_name", 11),
381                       mp_obj_new_str(ota_package_info->module_name,
382                                      strlen(ota_package_info->module_name)));
383     mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), mp_obj_new_str("version", 7),
384                       mp_obj_new_str(ota_package_info->version,
385                                      strlen(ota_package_info->version)));
386     mp_obj_dict_store(
387         MP_OBJ_FROM_PTR(dict), mp_obj_new_str("url", 3),
388         mp_obj_new_str(ota_package_info->url, strlen(ota_package_info->url)));
389     mp_obj_dict_store(
390         MP_OBJ_FROM_PTR(dict), mp_obj_new_str("hash", 4),
391         mp_obj_new_str(ota_package_info->hash, strlen(ota_package_info->hash)));
392 
393     const char *hash_type = NULL;
394     if (ota_package_info->hash_type == 0) {
395         hash_type = "null";
396     } else if (ota_package_info->hash_type == 1) {
397         hash_type = "sha256";
398     } else if (ota_package_info->hash_type == 2) {
399         hash_type = "md5";
400     } else {
401         hash_type = "sha512";
402     }
403     mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), mp_obj_new_str("hash_type", 9),
404                       mp_obj_new_str(hash_type, strlen(hash_type)));
405 
406     amp_debug(MOD_STR, "module_name is %s  ; length is %d",
407               ota_package_info->module_name,
408               strlen(ota_package_info->module_name));
409     amp_debug(MOD_STR, "version is %s ;  length is %d",
410               ota_package_info->version, strlen(ota_package_info->version));
411 
412     if (mp_obj_is_fun(ota_on_trigger)) {
413         callback_to_python(ota_on_trigger, dict);
414     } else {
415         amp_error(MOD_STR, "ota_on_trigger is not function");
416     }
417 
418     aos_free(ota_package_info);
419 }
420 
421 /* system image upgrade */
customer_upgrade_cb(void * pctx,char * ver,char * module_name,void * args)422 static int32_t customer_upgrade_cb(void *pctx, char *ver, char *module_name,
423                                    void *args)
424 {
425     int32_t ret = OTA_TRANSPORT_PAR_FAIL;
426     ota_package_info_t *ota_package_info = NULL;
427     ota_boot_param_t ota_param = { 0 };
428     aos_task_t customer_ota_task;
429     if ((pctx == NULL) || (ver == NULL) || (module_name == NULL) ||
430         (args == NULL)) {
431         amp_error(MOD_STR, "amp:ota triggered param err!");
432         return ret;
433     }
434     if (strncmp(module_name, "default", strlen(module_name)) == 0) {
435         ret = 0;
436         printf("ver:%s current_ver:%s\r\n", ver, default_ver);
437         if (strncmp(ver, default_ver, strlen(ver)) <= 0) {
438             ret = OTA_TRANSPORT_VER_FAIL;
439             amp_error(MOD_STR, "amp ota version too old!");
440         } else {
441             amp_debug(MOD_STR,
442                       "ota version:%s is coming, if OTA upgrade or not ?\n",
443                       ver);
444             /* clear jsengine timer, distory js app*/
445             if (aos_task_new_ext(&customer_ota_task, "amp_customer_ota",
446                                  internal_sys_upgrade_start, (void *)pctx,
447                                  1024 * 8, AOS_DEFAULT_APP_PRI) != 0) {
448                 amp_debug(MOD_STR, "internal ota task create failed!");
449                 ret = OTA_TRANSPORT_PAR_FAIL;
450             }
451             amp_debug(MOD_STR, "app management center start");
452         }
453     } else {
454         /*读取ota 触发时云端下发的文件信息*/
455         ret = ota_read_parameter(&ota_param);
456         if (ret < 0) {
457             amp_error(MOD_STR, "get store ota param info failed\n");
458         }
459 
460         ota_package_info = aos_malloc(sizeof(ota_package_info_t));
461         if (!ota_package_info) {
462             amp_error(MOD_STR, "alloc device notify param fail");
463             return;
464         }
465 
466         ota_package_info->js_cb_ref = (int)args;
467         ota_package_info->length = ota_param.len;
468         ota_package_info->hash_type = ota_param.hash_type;
469         strncpy(ota_package_info->url, ota_param.url,
470                 sizeof(ota_package_info->url));
471         strncpy(ota_package_info->version, ver, strlen(ver));
472         strncpy(ota_package_info->module_name, module_name,
473                 strlen(module_name));
474         strncpy(ota_package_info->hash, ota_param.hash,
475                 sizeof(ota_package_info->hash));
476 
477         /** todo call ota_trigger_notify */
478         py_task_schedule_call(ota_trigger_notify, ota_package_info);
479     }
480 }
481 
ota_init(mp_obj_t data)482 static mp_obj_t ota_init(mp_obj_t data)
483 {
484     int res = -1;
485     int productkey_len = IOTX_PRODUCT_KEY_LEN;
486     int productsecret_len = IOTX_PRODUCT_SECRET_LEN;
487     int devicename_len = IOTX_DEVICE_NAME_LEN;
488     int devicesecret_len = IOTX_DEVICE_SECRET_LEN;
489     iot_device_handle_t *iot_device_handle = NULL;
490     ota_package_info_t *ota_package_info = NULL;
491 
492     if (!mp_obj_is_dict_or_ordereddict(data)) {
493         return mp_obj_new_int(res);
494     }
495 
496     /* get http request url */
497     mp_obj_t index = mp_obj_new_str_via_qstr("device_handle", 13);
498 
499     iot_device_handle = MP_OBJ_TO_PTR(mp_obj_dict_get(data, index));
500     ota_service_param_reset(&customer_ota_ctx);
501     /* get device info
502     todo:save kv when do device_connect
503     */
504     aos_kv_get(AMP_CUSTOMER_PRODUCTKEY, customer_ota_ctx.pk, &productkey_len);
505     aos_kv_get(AMP_CUSTOMER_PRODUCTSECRET, customer_ota_ctx.ps,
506                &productsecret_len);
507     aos_kv_get(AMP_CUSTOMER_DEVICENAME, customer_ota_ctx.dn, &devicename_len);
508     aos_kv_get(AMP_CUSTOMER_DEVICESECRET, customer_ota_ctx.ds,
509                &devicesecret_len);
510 
511     memset(customer_module_info, 0x00, sizeof(customer_module_info));
512     customer_ota_ctx.mqtt_client = (void *)iot_device_handle->mqtt_handle;
513 
514     ota_package_info = aos_malloc(sizeof(ota_package_info_t));
515     if (!ota_package_info) {
516         amp_error(MOD_STR, "alloc device notify param fail");
517         goto out;
518     }
519     memset(ota_package_info, 0, sizeof(ota_package_info_t));
520     ota_package_info->js_cb_ref = 0;
521 
522     ota_register_module_store(&customer_ota_ctx, customer_module_info, 3);
523     ota_register_trigger_msg_cb(&customer_ota_ctx, (void *)customer_upgrade_cb,
524                                 1);
525 
526     /* init ota service */
527     res = ota_service_init(&customer_ota_ctx);
528     if (res < 0) {
529         amp_error(MOD_STR, "customer ota init failed!");
530     } else {
531         amp_error(MOD_STR, "customer ota init success!");
532     }
533 out:
534     if (res < 0) {
535         // todo:ota_package_info->js_cb_ref 是否需要free?
536         if (ota_package_info != NULL) {
537             aos_free(ota_package_info);
538         }
539         return mp_obj_new_int(-1);
540     }
541     mp_obj_new_int(0);
542 }
543 MP_DEFINE_CONST_FUN_OBJ_1(native_ota_init, ota_init);
544 
ota_register_cb(mp_obj_t id,mp_obj_t func)545 STATIC mp_obj_t ota_register_cb(mp_obj_t id, mp_obj_t func)
546 {
547     int res = -1;
548     int callback_id = mp_obj_get_int(id);
549     switch (callback_id) {
550         case ON_TRIGGER:
551             ota_on_trigger = func;
552             break;
553         case ON_DOWNLOAD:
554             ota_on_download = func;
555             break;
556         case ON_VERIFY:
557             ota_on_verify = func;
558             break;
559         case ON_UPGRADE:
560             ota_on_upgrade = func;
561             break;
562 
563         default:
564             break;
565     }
566     return mp_obj_new_int(0);
567 }
568 MP_DEFINE_CONST_FUN_OBJ_2(native_ota_register_cb, ota_register_cb);
569 
570 STATIC const mp_rom_map_elem_t ota_module_globals_table[] = {
571     { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ota) },
572     { MP_OBJ_NEW_QSTR(MP_QSTR_init), MP_ROM_PTR(&native_ota_init) },
573     { MP_OBJ_NEW_QSTR(MP_QSTR_on), MP_ROM_PTR(&native_ota_register_cb) },
574     { MP_OBJ_NEW_QSTR(MP_QSTR_download), MP_ROM_PTR(&native_ota_download) },
575     { MP_OBJ_NEW_QSTR(MP_QSTR_verify), MP_ROM_PTR(&native_ota_verify) },
576     { MP_OBJ_NEW_QSTR(MP_QSTR_report), MP_ROM_PTR(&native_ota_report) },
577     { MP_OBJ_NEW_QSTR(MP_QSTR_upgrade), MP_ROM_PTR(&native_ota_upgrade) },
578 };
579 
580 STATIC MP_DEFINE_CONST_DICT(ota_module_globals, ota_module_globals_table);
581 
582 const mp_obj_module_t ota_module = {
583     .base = { &mp_type_module },
584     .globals = (mp_obj_dict_t *)&ota_module_globals,
585 };
586