xref: /OK3568_Linux_fs/external/recovery/update_engine/update.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (C) 2023 Rockchip Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <libgen.h>
25 #include <stdbool.h>
26 #include "update.h"
27 #include "log.h"
28 #include "download.h"
29 #include "rkimage.h"
30 #include "flash_image.h"
31 #include "rktools.h"
32 #include "md5sum.h"
33 #include "defineHeader.h"
34 #include "../mtdutils/mtdutils.h"
35 
36 
37 #define CMD4RECOVERY_FILENAME "/mnt/sdcard/cmd4recovery"
38 #define CMD4RECOVERY_UDISK_FILENAME "/mnt/usb_storage/cmd4recovery"
39 static char * _url = NULL;
40 static char const * _save_path = NULL;
41 static char _url_dir[128];
42 double processvalue = 0;
43 
RK_ota_set_url(char * url,char * savepath)44 void RK_ota_set_url(char *url, char *savepath)
45 {
46     LOGI("start RK_ota_url url [%s] save path [%s].\n", url, savepath);
47     if ( url == NULL ) {
48         LOGE("RK_ota_set_url : url is NULL.\n");
49         return ;
50     }
51     if (savepath == NULL) {
52         _save_path = DEFAULT_DOWNLOAD_PATH;
53     } else {
54         _save_path = savepath;
55     }
56     LOGI("save image to %s.\n", _save_path);
57     _url = url;
58 
59     sprintf(_url_dir, "%s", _url);
60     dirname(_url_dir);
61 }
62 
63 bool is_sdboot = false;
64 bool is_usbboot = false;
65 
66 UPDATE_CMD update_cmd[] = {
67     {"bootloader", false, false, 0, 0, 0, "", false, flash_bootloader},
68     {"parameter", false, false, 0, 0, 0, "", false, flash_parameter},
69     {"uboot", false, false, 0, 0, 0, "", false, flash_normal},
70     {"trust", false, false, 0, 0, 0, "", false, flash_normal},
71     {"boot", false, true, 0, 0, 0, "", false, flash_normal},
72     {"recovery", false, false, 0, 0, 0, "", false, flash_normal},
73     {"rootfs", false, true, 0, 0, 0, "", false, flash_normal},
74     {"oem", false, false, 0, 0, 0, "", false, flash_normal},
75     {"uboot_a", false, false, 0, 0, 0, "", false, flash_normal},
76     {"uboot_b", false, false, 0, 0, 0, "", false, flash_normal},
77     {"boot_a", false, false, 0, 0, 0, "", false, flash_normal},
78     {"boot_b", false, false, 0, 0, 0, "", false, flash_normal},
79     {"system_a", false, false, 0, 0, 0, "", false, flash_normal},
80     {"system_b", false, false, 0, 0, 0, "", false, flash_normal},
81     {"misc", false, false, 0, 0, 0, "", false, flash_normal},
82     {"userdata", false, false, 0, 0, 0, "", false, flash_normal},
83 };
84 
RK_ota_set_partition(int partition)85 bool RK_ota_set_partition(int partition)
86 {
87     //000000000000000000000000: 没有升级分区
88     //100000000000000000000000: 升级loader分区
89     //010000000000000000000000: 升级parameter分区
90     //001000000000000000000000: 升级uboot分区
91     //000100000000000000000000: 升级trust分区
92     //000010000000000000000000: 升级boot分区
93     //000001000000000000000000: 升级recovery分区
94     //000000100000000000000000: 升级rootfs分区
95     //000000010000000000000000: 升级oem分区
96     //000000001000000000000000: 升级uboot_a分区
97     //000000000100000000000000: 升级uboot_b分区
98     //000000000010000000000000: 升级boot_a分区
99     //000000000001000000000000: 升级boot_b分区
100     //000000000000100000000000: 升级system_a分区
101     //000000000000010000000000: 升级system_b分区
102     //000000000000001000000000: 升级misc分区,sdboot使用
103     //000000000000000100000000: 升级userdata分区
104 
105     int num = sizeof(update_cmd) / sizeof(UPDATE_CMD);
106     LOGI("[%s:%d] num [%d]\n", __func__, __LINE__, num);
107 
108     if (partition == -1) {
109         //设置目标分区大小
110         RKIMAGE_HDR rkimage_hdr;
111         if ( analyticImage(_url, &rkimage_hdr) != 0) {
112             LOGE("analyticImage error.\n");
113             return false;
114         }
115 
116         for (int i = 0; i < num; i++) {
117             if ( update_cmd[i].need_update || is_sdboot || is_usbboot) {
118                 update_cmd[i].need_update = false;
119                 for (int j = 0; j < rkimage_hdr.item_count; j++) {
120                     if (strcmp(rkimage_hdr.item[j].name, update_cmd[i].name) == 0) {
121                         LOGI("found rkimage_hdr.item[%d].name = %s.\n", j, update_cmd[i].name);
122                         if (rkimage_hdr.item[j].file[50] == 'H') {
123                             update_cmd[i].offset = *((DWORD *)(&rkimage_hdr.item[j].file[51]));
124                             update_cmd[i].offset <<= 32;
125                             update_cmd[i].offset += rkimage_hdr.item[j].offset;
126                             LOGI("offset more than 4G, after adjusting is %lld.\n", update_cmd[i].offset);
127                         } else {
128                             update_cmd[i].offset = rkimage_hdr.item[j].offset;
129                         }
130 
131                         if (rkimage_hdr.item[j].file[55] == 'H') {
132                             update_cmd[i].size = *((DWORD *)(&rkimage_hdr.item[j].file[56]));
133                             update_cmd[i].size <<= 32;
134                             update_cmd[i].size += rkimage_hdr.item[j].size;
135                             LOGI("size more than 4G, after adjusting is %lld.\n", update_cmd[i].size);
136                         } else {
137                             update_cmd[i].size = rkimage_hdr.item[j].size;
138                         }
139 
140                         if (is_sdboot || is_usbboot) {
141                             update_cmd[i].flash_offset = (long long)rkimage_hdr.item[j].flash_offset * SECTOR_SIZE;
142                         }
143                         update_cmd[i].need_update = true;
144                         continue ;
145                     }
146                 }
147             }
148         }
149 
150         if (!is_sdboot && !is_usbboot) {
151             for ( int i = 0; i < num; i++ ) {
152                 if (*update_cmd[i].dest_path && (update_cmd[i].need_update == false)) {
153 
154                     unsigned char len = strlen(update_cmd[i].name);
155                     if (update_cmd[i].name[len - 2] == '_' && (update_cmd[i].name[len - 1] == 'a' || update_cmd[i].name[len - 1] == 'b')) {
156 
157                         char slot_find = (update_cmd[i].name[len - 1] == 'a') ? 'b' : 'a';
158 
159                         update_cmd[i].name[len - 1] = slot_find;
160                         for (int j = 0; j < rkimage_hdr.item_count; j++) {
161                             if (strcmp(rkimage_hdr.item[j].name, update_cmd[i].name) == 0) {
162                                 LOGI("again found rkimage_hdr.item[%d].name = %s.\n", j, update_cmd[i].name);
163                                 if (rkimage_hdr.item[j].file[50] == 'H') {
164                                     update_cmd[i].offset = *((DWORD *)(&rkimage_hdr.item[j].file[51]));
165                                     update_cmd[i].offset <<= 32;
166                                     update_cmd[i].offset += rkimage_hdr.item[j].offset;
167                                     LOGI("offset more than 4G, after adjusting is %lld.\n", update_cmd[i].offset);
168                                 } else {
169                                     update_cmd[i].offset = rkimage_hdr.item[j].offset;
170                                 }
171 
172                                 if (rkimage_hdr.item[j].file[55] == 'H') {
173                                     update_cmd[i].size = *((DWORD *)(&rkimage_hdr.item[j].file[56]));
174                                     update_cmd[i].size <<= 32;
175                                     update_cmd[i].size += rkimage_hdr.item[j].size;
176                                     LOGI("size more than 4G, after adjusting is %lld.\n", update_cmd[i].size);
177                                 } else {
178                                     update_cmd[i].size = rkimage_hdr.item[j].size;
179                                 }
180 
181                                 update_cmd[i].need_update = true;
182                                 continue ;
183                             }
184                         }
185                     }
186                 }
187             }
188         }
189         // for ( int i=0; i<num; i++ ) {
190         // printf ( "[%s:%d] update_cmd[%d].name [%s] dest path [%s] flash offset [%#llx] offset [%#llx] size [%#llx] \n",
191         // __func__, __LINE__, i, update_cmd[i].name, update_cmd[i].dest_path, update_cmd[i].flash_offset, update_cmd[i].offset, update_cmd[i].size);
192         // }
193 
194         return true;
195     }
196 
197     for (int i = 0; i < num; i++) {
198         // For OTA and SD update MUST read gpt from update***.img
199         if ( (partition & 0x800000 || is_sdboot || is_usbboot || (strcmp(update_cmd[i].name, "parameter") == 0) ) ) {
200             LOGI("need update %s.\n", update_cmd[i].name);
201             update_cmd[i].need_update = true;
202 
203             if (is_sdboot || is_usbboot) {
204                 memset(update_cmd[i].dest_path, 0, sizeof(update_cmd[i].dest_path) / sizeof(update_cmd[i].dest_path[0]));
205                 if (strcmp(update_cmd[i].name, "parameter") == 0) {
206                     sprintf(update_cmd[i].dest_path, "%s/gpt", _url_dir);
207                 } else {
208                     sprintf(update_cmd[i].dest_path, "%s/%s", _url_dir, update_cmd[i].name);
209                 }
210             } else {
211                 if (strcmp(update_cmd[i].name, "parameter") == 0) {
212                     sprintf(update_cmd[i].dest_path, "/dev/block/by-name/gpt");
213                 } else {
214                     if (!isMtdDevice()) {
215                         sprintf(update_cmd[i].dest_path, "/dev/block/by-name/%s", update_cmd[i].name);
216                     } else {
217                         if ( update_cmd[i].need_update && (mtd_scan_partitions() > 0) ) {
218                             const MtdPartition *mtdp = mtd_find_partition_by_name(update_cmd[i].name);
219                             if (mtdp) {
220                                 sprintf(update_cmd[i].dest_path, "/dev/mtd%d", mtdp->device_index);
221                                 LOGI("need update %s ,.dest_path: %s.\n", update_cmd[i].name, update_cmd[i].dest_path);
222                             }
223                         } else {
224                             sprintf(update_cmd[i].dest_path, "/dev/block/by-name/%s", update_cmd[i].name);
225                         }
226                     }
227                 }
228             }
229         }
230         partition = (partition << 1);
231     }
232 
233     return true;
234 
235 }
236 
ota_recovery_cmds(long long flash_offset,const char * dest_path)237 static int ota_recovery_cmds (long long flash_offset, const char *dest_path)
238 {
239     char data_buf[256];
240     unsigned int write_count = 0;
241     int fd = -1;
242     if (dest_path == NULL) {
243         LOGE("[%s-%d] error dest path is NULL.\n", __func__, __LINE__);
244         return -1;
245     }
246 
247     LOGI("[%s:%d] parameter flash offset %#llx dest path %s\n", __func__, __LINE__, flash_offset, dest_path);
248     memset(data_buf, 0, sizeof(data_buf) / sizeof(data_buf[0]));
249 
250     if (is_sdboot) {
251         fd = open(CMD4RECOVERY_FILENAME, O_CREAT | O_RDWR | O_SYNC | O_APPEND, 0644);
252         if (fd < 0) {
253             LOGE("[%s-%d] error opening %s.\n", __func__, __LINE__,  CMD4RECOVERY_FILENAME);
254             return -1;
255         }
256     } else if (is_usbboot) {
257         fd = open(CMD4RECOVERY_UDISK_FILENAME, O_CREAT | O_RDWR | O_SYNC | O_APPEND, 0644);
258         if (fd < 0) {
259             LOGE("[%s-%d] error opening %s.\n", __func__, __LINE__,  CMD4RECOVERY_UDISK_FILENAME);
260             return -1;
261         }
262     }
263 
264     if (isMtdDevice()) {
265         sprintf(data_buf, "nandwrite -p /dev/mtd0 -s %#llx %s; \n", flash_offset, dest_path);
266     } else {
267         char flash_name[20];
268         getFlashPoint(flash_name);
269 
270 #define    DD_MALLOC_MAX_SIZE     (0x100000*10)        /* 10MB */
271 
272         unsigned int dd_bs = 0;
273         long long dd_seek  = 1;
274 
275         for ( int j = DD_MALLOC_MAX_SIZE / SECTOR_SIZE; j > 0 ; j-- ) {
276             dd_bs = j * SECTOR_SIZE;
277             if ( !(flash_offset % dd_bs) ) {
278                 dd_seek  = flash_offset / dd_bs;
279                 LOGI( "flash offset = [%#llx] j=%d bs=%#x  seek = %#llx  result = [%s]\n",
280                       flash_offset, j, dd_bs, dd_seek, (dd_bs * dd_seek == flash_offset) ? "YES" : "NO" );
281                 break;
282             } else {
283                 dd_bs = 1;
284                 dd_seek = flash_offset;
285             }
286         }
287         sprintf(data_buf, "dd of=%s if=%s bs=%d seek=%lld; \t###flash offset [%#10llx] \n", flash_name, dest_path, dd_bs, dd_seek, flash_offset);
288     }
289 
290     write_count = strlen(data_buf);
291 
292     if (write(fd, data_buf, write_count) != write_count) {
293         close(fd);
294         LOGE("[%s:%d] Write failed(%s)\n", __func__, __LINE__, strerror(errno));
295         return -2;
296     }
297 
298     close(fd);
299     return 0;
300 }
301 
RK_ota_start(RK_upgrade_callback cb,RK_print_callback print_cb)302 void RK_ota_start(RK_upgrade_callback cb, RK_print_callback print_cb)
303 {
304     LOGI("start RK_ota_start.\n");
305     processvalue = 95;
306     cb(NULL, RK_UPGRADE_START);
307 
308     //确认升级路径
309     if (_url == NULL) {
310         LOGE("url is NULL\n");
311         cb(NULL, RK_UPGRADE_ERR);
312         return ;
313     }
314 
315     // 1. 获取文件
316     int res = download_file(_url, _save_path);
317     if (res == 0) {
318         _url = (char *)_save_path;
319     } else if (res == -1) {
320         LOGE("download_file error.\n");
321         cb(NULL, RK_UPGRADE_ERR);
322         return ;
323     }
324 
325     // 2. 获取文件信息
326     if (!RK_ota_set_partition(-1)) {
327         LOGE("RK_ota_set_partition failed.\n");
328         cb(NULL, RK_UPGRADE_ERR);
329         return ;
330     }
331 
332     STRUCT_PARAM_ITEM param_item[20] = {0};
333     long long gpt_backup_offset = -1;
334     memset(param_item, 0, sizeof(param_item));
335     flash_register_partition_data(param_item, &gpt_backup_offset);
336 
337     int is_mtd_flag = isMtdDevice();
338 
339     // 3. 下载文件到分区并校验
340     int num = sizeof(update_cmd) / sizeof(UPDATE_CMD);
341     char prompt[128] = {0};
342     for (int i = 0; i < num; i++ ) {
343         if (update_cmd[i].need_update) {
344             if (update_cmd[i].cmd != NULL) {
345                 LOGI("now write %s to %s.\n", update_cmd[i].name, update_cmd[i].dest_path);
346                 sprintf(prompt, "[%s] upgrade start...\n", update_cmd[i].name);
347                 print_cb(prompt);
348                 if (!is_sdboot && !is_usbboot &&
349                     ( (strcmp(update_cmd[i].name, "misc") == 0) ||
350                       (strcmp(update_cmd[i].name, "parameter") == 0) )) {
351                     LOGI("ingore misc.\n");
352                     continue;
353                 }
354                 // 下载固件到分区
355                 LOGI("update_cmd.flash_offset = %lld.\n", update_cmd[i].flash_offset);
356                 if (update_cmd[i].cmd(_url, (void*)(&update_cmd[i])) != 0) {
357                     LOGE("update %s error.\n", update_cmd[i].dest_path);
358                     sprintf(prompt, "[%s] upgrade fail\n", update_cmd[i].name);
359                     print_cb(prompt);
360                     cb(NULL, RK_UPGRADE_ERR);
361                     return ;
362                 } else {
363                     sprintf(prompt, "[%s] upgraede success!\n", update_cmd[i].name);
364                     print_cb(prompt);
365                 }
366                 if (is_sdboot) {
367                     if (ota_recovery_cmds(update_cmd[i].flash_offset, update_cmd[i].dest_path)) {
368                         LOGE("write recovery cmds to %s failed.\n", CMD4RECOVERY_FILENAME);
369                         cb(NULL, RK_UPGRADE_ERR);
370                         return ;
371                     }
372                     LOGI("not check in sdboot (sdcard).\n");
373                     continue;
374                 } else if (is_usbboot) {
375                     if (ota_recovery_cmds(update_cmd[i].flash_offset, update_cmd[i].dest_path)) {
376                         LOGE("write recovery cmds to %s failed.\n", CMD4RECOVERY_UDISK_FILENAME);
377                         cb(NULL, RK_UPGRADE_ERR);
378                         return ;
379                     }
380                     LOGI("not check in usb storage (udisk).\n");
381                     continue;
382                 }
383                 // parameter 和loader 先不校验
384                 if (strcmp(update_cmd[i].name, "parameter") == 0 || strcmp(update_cmd[i].name, "bootloader") == 0) {
385                     LOGI("not check parameter and loader.\n");
386                     continue;
387                 }
388                 // 校验分区
389                 if (!update_cmd[i].skip_verify &&
390                     comparefile(update_cmd[i].dest_path, _url,
391                                 update_cmd[i].flash_offset,
392                                 update_cmd[i].offset, update_cmd[i].size)) {
393                     LOGI("check %s ok.\n", update_cmd[i].dest_path);
394                 } else if (!update_cmd[i].skip_verify) {
395                     LOGE("check %s failed.\n", update_cmd[i].dest_path);
396                     cb(NULL, RK_UPGRADE_ERR);
397                     return ;
398                 }
399             }
400         }
401     }
402 
403     /*
404      * Fix if update_xxx.img not found some A/B partition image.
405      */
406     if (is_sdboot || is_usbboot) {
407         for (int i = 0; i < num; i++) {
408             if ( (!update_cmd[i].need_update) || (update_cmd[i].cmd == NULL)) {
409                 continue;
410             }
411             unsigned char len = strlen(update_cmd[i].name);
412             if (update_cmd[i].name[len - 2] == '_' && (update_cmd[i].name[len - 1] == 'a' || update_cmd[i].name[len - 1] == 'b') ) {
413                 char slot_find = (update_cmd[i].name[len - 1] == 'a') ? 'b' : 'a';
414                 int part_need_fix = 1;
415                 char part_name[32];
416                 memset(part_name, 0, sizeof(part_name) / sizeof(part_name[0]));
417                 memcpy(part_name, update_cmd[i].name, len);
418                 part_name[len - 1] = slot_find;
419 
420                 for (int k = 0; k < num; k++) {
421                     if ( (!update_cmd[k].need_update) || (update_cmd[k].cmd == NULL)) {
422                         continue;
423                     }
424                     if ( (strcmp(update_cmd[k].name, part_name) == 0) ) {
425                         part_need_fix = 0;
426                     }
427                 }
428 
429                 if (part_need_fix) {
430                     for (int j = 0; j < sizeof(param_item) / sizeof(param_item[0]); j++) {
431                         if (strcmp(param_item[j].name, part_name) == 0) {
432                             if (ota_recovery_cmds(param_item[j].offset * SECTOR_SIZE, update_cmd[i].dest_path)) {
433                                 LOGE("sdboot fix write recovery cmds to %s failed.\n", CMD4RECOVERY_FILENAME);
434                                 cb(NULL, RK_UPGRADE_ERR);
435                                 return ;
436                             }
437                         }
438                     }
439                 }
440             }
441         }
442 
443         // write gpt backup
444         /*
445          * char gpt_backup_img_path[100] = {0};
446          * sprintf(gpt_backup_img_path, "%s/%s", _url_dir, GPT_BACKUP_FILE_NAME);
447          * if (ota_recovery_cmds(gpt_backup_offset, gpt_backup_img_path)) {
448          *     LOGE("write gpt backup to recovery cmds failed (%s).\n", gpt_backup_img_path);
449          *     cb(NULL, RK_UPGRADE_ERR);
450          *     return ;
451          * }
452          */
453 
454     }
455 
456     // 4. 是否设置misc
457 
458     LOGI("RK_ota_start is ok!");
459     processvalue = 100;
460     cb(NULL, RK_UPGRADE_FINISHED);
461     print_cb((char *)"updateEngine upgrade OK!\n");
462 
463     /* We're successful upgraded, Remove the done_file(see flash_image.cpp) if exist. */
464     {
465         char done_file[256];
466         snprintf(done_file, 256, "%s.done", _url);
467         unlink(done_file);
468     }
469 }
470 
RK_ota_get_progress()471 int RK_ota_get_progress()
472 {
473     return processvalue;
474 }
475 
RK_ota_get_sw_version(char * buffer,int maxLength)476 void RK_ota_get_sw_version(char *buffer, int  maxLength)
477 {
478     getLocalVersion(buffer, maxLength);
479 }
480 
RK_ota_check_version(char * url)481 bool RK_ota_check_version(char *url)
482 {
483     char source_version[20] = {0};
484     char target_version[20] = {0};
485     if (!getLocalVersion(source_version, sizeof(source_version))) {
486         return false;
487     }
488 
489     if (strncmp(url, "http", 4) == 0) {
490         //如果是远程文件,从远程获取版本号
491         if (!getRemoteVersion(url, target_version, sizeof(target_version))) {
492             return false;
493         }
494     } else {
495         //如果是本地文件,从固件获取版本号
496         if (!getImageVersion(url, target_version, sizeof(target_version))) {
497             return false;
498         }
499     }
500 
501     LOGI("check version new:%s  old:%s", target_version, source_version);
502     if (strcmp(target_version, source_version) > 0) {
503         return true;
504     }
505     return false;
506 }
507