xref: /OK3568_Linux_fs/external/recovery/update_engine/main.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 <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <sys/reboot.h>
23 #include "log.h"
24 #include "update.h"
25 #include "../bootloader.h"
26 #include "../recovery_version.h"
27 #include "defineHeader.h"
28 #include "rktools.h"
29 
30 extern bool is_sdboot;
31 extern bool is_usbboot;
32 static bool rkdebug = false;
33 static char *ui_rotation = NULL;
34 static const char *update_engine_version = RECOVERY_VERSION_STRING;
35 
36 RK_Upgrade_Status_t m_status = RK_UPGRADE_ERR;
37 FILE* cmd_pipe = NULL;
38 
handle_upgrade_callback(void * user_data,RK_Upgrade_Status_t status)39 void handle_upgrade_callback(void *user_data, RK_Upgrade_Status_t status)
40 {
41     if (status == RK_UPGRADE_FINISHED) {
42         LOGI("rk ota success.\n");
43         setSlotActivity();
44     }
45     m_status = status;
46     LOGI("rk m_status = %d.\n", m_status);
47 }
48 
handle_print_callback(char * szPrompt)49 void handle_print_callback(char *szPrompt)
50 {
51     if (cmd_pipe != NULL) {
52         fprintf(cmd_pipe, "ui_print %s\n", szPrompt);
53     }
54 }
55 
MiscUpdate(char * url,char * update_partition,char * save_path)56 static int MiscUpdate(char *url,  char *update_partition, char *save_path)
57 {
58     int partition;
59     char *savepath = NULL;
60     int slot = -1;
61     if (url == NULL) {
62         //如果没有传入URL,则可以去查找是否有存在
63         LOGE("MiscUpdate URL must be set.\n");
64         return -1;
65     }
66     slot = getCurrentSlot();
67     if (update_partition == NULL) {
68         //没有传入要升级的分区,默认升级
69         if (slot == -1) {
70             // recovery mdoe
71             // u-boot/trust/boot/recovery/boot/rootfs/oem
72             partition = 0X3F0000;
73         } else {
74             // A/B mdoe
75             // uboot_a/uboot_b/boot_a/boot_b/system_a/system_b
76             partition = 0XFC00;
77         }
78     } else {
79         partition = strtol(update_partition + 2, NULL, 16);
80     }
81 
82     if (save_path == NULL) {
83         savepath = url;
84     } else {
85         savepath = save_path;
86     }
87 
88     RK_ota_set_url(url, savepath);
89     LOGI("url = %s.\n", url);
90     LOGI("[%s:%d] save path: %s\n", __func__, __LINE__, savepath);
91     // If it's recovery mode, upgrade recovery in normal system.
92     if (slot == -1 && !is_sdboot && !is_usbboot) {
93         if (partition & 0x040000) {
94             LOGI("update recovery in normal system.\n");
95             partition = partition & 0xFBFFFF;
96 
97             // upgrade recoery in normal system
98             if (!RK_ota_set_partition(0x040000)) {
99                 LOGE("ota file is error.\n");
100                 return -1;
101             }
102             RK_ota_start(handle_upgrade_callback, handle_print_callback);
103             if (m_status != RK_UPGRADE_FINISHED) {
104                 return -1;
105             }
106 
107             //写MISC
108             struct bootloader_message msg;
109             memset(&msg, 0, sizeof(msg));
110             char recovery_str[] = "recovery\n--update_package=";
111             strcpy(msg.command, "boot-recovery");
112             sprintf(msg.recovery, "%s%s\n", recovery_str, savepath);
113             memcpy(msg.needupdate, &partition, 4);
114             if (true == rkdebug) {
115                 strcat(msg.recovery, "--rkdebug\n");
116             }
117             if (NULL != ui_rotation) {
118                 strcat(msg.recovery, "--ui_rotation=");
119                 strcat(msg.recovery, ui_rotation);
120                 msg.recovery[strlen(msg.recovery)] = '\n';
121             }
122             set_bootloader_message(&msg);
123             return 0;
124         }
125     } else if (slot == 0) {
126         LOGI("In A system, now upgrade B system.\n");
127         partition = partition & 0x155ff;
128     } else if (slot == 1) {
129         LOGI("In B system, now upgrade A system.\n");
130         partition = partition & 0x1a9ff;
131     }
132 
133     if (!RK_ota_set_partition(partition)) {
134         LOGE("ota file is error.\n");
135         return -1;
136     }
137     RK_ota_start(handle_upgrade_callback, handle_print_callback);
138     if (m_status != RK_UPGRADE_FINISHED) {
139         return -1;
140     }
141 
142     return 0;
143 }
144 
display(void)145 void display(void)
146 {
147     LOGI("--misc=now             Linux A/B mode: Setting the current partition to bootable.\n");
148     LOGI("--misc=other           Linux A/B mode: Setting another partition to bootable.\n");
149     LOGI("--misc=update          Recovery mode: Setting the partition to be upgraded.\n");
150     LOGI("--misc=display         Display misc info.\n");
151     LOGI("--misc=wipe_userdata   Format data partition.\n");
152     LOGI("--misc_custom= < op >  Operation on misc for custom cmdline");
153     LOGI("        op:     read   Read custom cmdline to /tmp/custom_cmdline");
154     LOGI("                write  Write /tmp/custom_cmdline to custom area");
155     LOGI("                clean  clean custom area");
156     LOGI("--update               Upgrade mode.\n");
157     LOGI("--partition=0x3FFC00   Set the partition to be upgraded.(NOTICE: OTA not support upgrade loader and parameter)\n");
158     LOGI("                       0x3FFC00: 0011 1111 1111 1100 0000 0000.\n");
159     LOGI("                                 uboot trust boot recovery rootfs oem\n");
160     LOGI("                                 uboot_a uboot_b boot_a boot_b system_a system_b.\n");
161     LOGI("                       100000000000000000000000: Upgrade loader\n");
162     LOGI("                       010000000000000000000000: Upgrade parameter\n");
163     LOGI("                       001000000000000000000000: Upgrade uboot\n");
164     LOGI("                       000100000000000000000000: Upgrade trust\n");
165     LOGI("                       000010000000000000000000: Upgrade boot\n");
166     LOGI("                       000001000000000000000000: Upgrade recovery\n");
167     LOGI("                       000000100000000000000000: Upgrade rootfs\n");
168     LOGI("                       000000010000000000000000: Upgrade oem\n");
169     LOGI("                       000000001000000000000000: Upgrade uboot_a\n");
170     LOGI("                       000000000100000000000000: Upgrade uboot_b\n");
171     LOGI("                       000000000010000000000000: Upgrade boot_a\n");
172     LOGI("                       000000000001000000000000: Upgrade boot_b\n");
173     LOGI("                       000000000000100000000000: Upgrade system_a\n");
174     LOGI("                       000000000000010000000000: Upgrade system_b\n");
175     LOGI("                       000000000000001000000000: Upgrade misc\n");
176     LOGI("                       000000000000000100000000: Upgrade userdata\n");
177     LOGI("--reboot               Restart the machine at the end of the program.\n");
178     LOGI("--version_url=url      The path to the file of version.\n");
179     LOGI("--image_url=url        Path to upgrade firmware.\n");
180     LOGI("--savepath=url         save the update.img to url.\n");
181     LOGI("--version              the version of updateEngine\n");
182     LOGI("--rkdebug              Log output to serial port\n");
183     LOGI("--ui_rotation          UI rotation,has 4 angles(0-3).\n");
184 
185 }
186 
187 static const struct option engine_options[] = {
188     { "update", optional_argument, NULL, 'u' },
189     { "version_url", required_argument, NULL, 'v' + 'u' },
190     { "image_url", required_argument, NULL, 'i' + 'u'},
191     { "check", required_argument, NULL, 'c' },
192     { "misc", required_argument, NULL, 'm' },
193     { "misc_custom", required_argument, NULL, 'd' },
194     { "partition", required_argument, NULL, 'p' },
195     { "reboot", no_argument, NULL, 'r' },
196     { "help", no_argument, NULL, 'h' },
197     { "pipefd", required_argument, NULL, 'p' + 'f' },
198     { "savepath", required_argument, NULL, 's'},
199     { "version", no_argument, NULL, 'v'},
200     { "rkdebug", no_argument, NULL, 'k'},
201     { "ui_rotation", required_argument, NULL, 'o'},
202     { NULL, 0, NULL, 0 },
203 };
204 
main(int argc,char * argv[])205 int main(int argc, char *argv[])
206 {
207     LOGI("*** update_engine: %s ***.\n", update_engine_version);
208     int arg;
209     char *image_url = NULL;
210     char *version_url = NULL;
211     char *misc_func = NULL;
212     char *save_path = NULL;
213     char *partition = NULL;
214     char *custom_define = NULL;
215     bool is_update = false;
216     bool is_reboot = false;
217     int pipefd = -1;
218 
219     while ((arg = getopt_long(argc, argv, "", engine_options, NULL)) != -1) {
220         switch (arg) {
221         case 'u': is_update = true; if (optarg != NULL) is_sdboot = true; continue;
222         case 'c': version_url = optarg; continue;
223         case 'm': misc_func = optarg; continue;
224         case 'p': partition = optarg; continue;
225         case 's': save_path = optarg; continue;
226         case 'r': is_reboot = true; continue;
227         case 'v' + 'u': version_url = optarg; continue;
228         case 'i' + 'u': image_url = optarg; continue;
229         case 'p' + 'f': pipefd = atoi(optarg); continue;
230         case 'h': display(); break;
231         case 'd': custom_define = optarg; continue;
232         case 'v': LOGI("*** update_engine: %s ***.\n", update_engine_version); break;
233         case 'k': rkdebug = true; break;
234         case 'o': ui_rotation = optarg; break;
235         case '?':
236             LOGE("Invalid command argument\n");
237             continue;
238         }
239     }
240 
241     if (pipefd != -1) {
242         cmd_pipe = fdopen(pipefd, "wb");
243         setlinebuf(cmd_pipe);
244     }
245 
246     if (is_update) {
247         if (optarg && (strstr(optarg, "usb") != NULL || strstr(optarg, "udisk") != NULL)) {
248             is_usbboot = true;
249             is_sdboot = false;
250             LOGI("*** will upgrade firmware from udisk ***");
251         }
252 
253         if (is_sdboot || is_usbboot) {
254             int res = 0x3FFC00; //默认升级的分区
255             LOGI("%s-%d: is %s update.\n", __func__, __LINE__, is_usbboot ? "usbboot" : "sdboot");
256             if (partition != NULL) {
257                 res = strtol(partition + 2, NULL, 16);
258             }
259             RK_ota_set_url(image_url, save_path);
260             if ( !RK_ota_set_partition(res) ) {
261                 LOGE("ota file is error.\n");
262                 return -1;
263             }
264 
265             if (version_url != NULL) {
266                 if (!RK_ota_check_version(version_url) ) {
267                     LOGE("you shouldn't update the device.\n");
268                     return -1;
269                 }
270             }
271 
272             RK_ota_start(handle_upgrade_callback, handle_print_callback);
273         } else {
274             LOGI("%s-%d: is ota update\n", __func__, __LINE__);
275             if (MiscUpdate(image_url, partition, save_path) == 0) {
276                 m_status = RK_UPGRADE_FINISHED;
277             }
278         }
279     } else if (misc_func != NULL) {
280         if (strcmp(misc_func, "now") == 0) {
281             if (setSlotSucceed() == 0) {
282                 m_status = RK_UPGRADE_FINISHED;
283             }
284         } else if (strcmp(misc_func, "other") == 0) {
285             if (setSlotActivity() == 0) {
286                 m_status = RK_UPGRADE_FINISHED;
287             }
288         } else if (strcmp(misc_func, "wipe_userdata") == 0) {
289             if (wipe_userdata(0) == 0) {
290                 m_status = RK_UPGRADE_FINISHED;
291             }
292         } else if (strcmp(misc_func, "update") == 0) {
293             if (MiscUpdate(image_url, partition, save_path) == 0) {
294                 m_status = RK_UPGRADE_FINISHED;
295             }
296         } else if (strcmp(misc_func, "display") == 0) {
297             miscDisplay();
298         } else {
299             LOGE("unknow misc cmdline : %s.\n", misc_func);
300             return 0;
301         }
302     } else if (custom_define != NULL) {
303         if (strcmp(custom_define, "read") == 0) {
304             if (readCustomMiscCmdline())
305                 return -1;
306         } else if (strcmp(custom_define, "write") == 0) {
307             if (writeCustomMiscCmdline())
308                 return -1;
309         } else if (strcmp(custom_define, "clean") == 0) {
310             if (cleanCustomMiscCmdline())
311                 return -1;
312         } else {
313             LOGI("Not supported\n");
314             return m_status;
315         }
316         m_status = RK_UPGRADE_FINISHED;
317     }
318 
319     if (is_reboot && (m_status == RK_UPGRADE_FINISHED)) {
320         sync();
321         //reboot(RB_AUTOBOOT);
322         if (system(" echo b > /proc/sysrq-trigger ") == -1)
323             return -1;
324     }
325 
326     return m_status;
327 }
328