1 /*
2 * Copyright (C) 2010 The Android Open Source Project
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 /**
18 * RecoverySystem contains methods for interacting with the Android
19 * recovery system (the separate partition that can be used to install
20 * system updates, wipe user data, etc.)
21 */
22
23 //#include <direct.h>
24 #include <linux/reboot.h>
25 //#include <io.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/reboot.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32
33 #include "update_recv/update_recv.h"
34
35 #define LOG_FILE_LEN 512
36
37 #if 0
38 #define RECOVERY_PATH "/tmp/recovery"
39 #define LOG_FILE_PATH "/tmp/recovery/log"
40 #define COMMAND_FILE_PATH "/tmp/recovery/command"
41 #else
42 #define RECOVERY_PATH "/userdata/recovery"
43 #define LOG_FILE_PATH "/userdata/recovery/log"
44 #define COMMAND_FILE_PATH "/userdata/recovery/command"
45 #endif
46
47 #define SD_UPDATE_FILE "/sdcard/update.img"
48 #define DATA_UPDATE_FILE "/userdata/update.img"
49 #define MISC_FILE_PATH "/dev/block/by-name/misc"
50 #define MISC_MSG_OFFSET 16 * 1024
51
52 /* Bootloader Message (2-KiB)
53 *
54 * This structure describes the content of a block in flash
55 * that is used for recovery and the bootloader to talk to
56 * each other.
57 *
58 * The command field is updated by linux when it wants to
59 * reboot into recovery or to update radio or bootloader firmware.
60 * It is also updated by the bootloader when firmware update
61 * is complete (to boot into recovery for any final cleanup)
62 *
63 * The status field is written by the bootloader after the
64 * completion of an "update-radio" or "update-hboot" command.
65 *
66 * The recovery field is only written by linux and used
67 * for the system to send a message to recovery or the
68 * other way around.
69 *
70 * The stage field is written by packages which restart themselves
71 * multiple times, so that the UI can reflect which invocation of the
72 * package it is. If the value is of the format "#/#" (eg, "1/3"),
73 * the UI will add a simple indicator of that status.
74 *
75 * We used to have slot_suffix field for A/B boot control metadata in
76 * this struct, which gets unintentionally cleared by recovery or
77 * uncrypt. Move it into struct bootloader_message_ab to avoid the
78 * issue.
79 */
80 struct android_bootloader_message {
81 char command[32];
82 char status[32];
83 char recovery[768];
84
85 /* The 'recovery' field used to be 1024 bytes. It has only ever
86 * been used to store the recovery command line, so 768 bytes
87 * should be plenty. We carve off the last 256 bytes to store the
88 * stage string (for multistage packages) and possible future
89 * expansion. */
90 char stage[32];
91
92 /* The 'reserved' field used to be 224 bytes when it was initially
93 * carved off from the 1024-byte recovery field. Bump it up to
94 * 1184-byte so that the entire bootloader_message struct rounds up
95 * to 2048-byte. */
96 char reserved[1184];
97 };
98
99
100
101 /**
102 * Reboot into the recovery system with the supplied argument.
103 * @param arg to pass to the recovery utility.
104 */
bootCommand(char * arg)105 static void bootCommand(char *arg){
106 FILE *command_file;
107 FILE *log_file;
108 FILE *misc_file;
109 char blank[LOG_FILE_LEN];
110
111 if(!arg) return;
112 printf("command: %s\n", arg);
113 mkdir(RECOVERY_PATH,0775);
114 if((command_file = fopen(COMMAND_FILE_PATH,"wb")) == NULL){
115 printf("Open command file error.\n");
116 return;
117 }
118
119 if((log_file = fopen(LOG_FILE_PATH,"wb")) == NULL){
120 printf("Open log file error.\n");
121 return;
122 }
123
124 if((misc_file = fopen(MISC_FILE_PATH,"wb")) == NULL){
125 printf("Open misc file error.\n");
126 return;
127 }
128
129 printf("update: write command to command file: ");
130 fwrite(arg, strlen(arg), 1, command_file);
131 fwrite("\n", 1, 1, command_file);
132 fclose(command_file);
133 printf("done\n");
134
135 printf("update: write command to misc file: ");
136 fseek(misc_file, MISC_MSG_OFFSET, SEEK_SET);
137 struct android_bootloader_message msg;
138 memset(&msg, 0, sizeof(msg));
139 char recovery_str[] = "recovery\n";
140 strcpy(msg.command, "boot-recovery");
141 strcpy(msg.recovery, recovery_str);
142 memcpy(msg.recovery + strlen(recovery_str), arg, ((strlen(arg) > sizeof(msg.recovery))? sizeof(msg.recovery) : strlen(arg)));
143 msg.recovery[strlen(msg.recovery) + 1] = '\n';
144 //strlcat(msg.recovery, update_file, sizeof(msg.recovery));
145 //strlcat(msg.recovery, "\n", sizeof(msg.recovery));
146 //strlcpy(msg.systemFlag, "false", sizeof(msg.systemFlag));
147 fwrite(&msg, sizeof(msg), 1, misc_file);
148 fclose(misc_file);
149 printf("done\n");
150
151 memset(blank, 0, LOG_FILE_LEN);
152 fwrite(blank, LOG_FILE_LEN, 1, log_file);
153 fclose(log_file);
154 printf("update: reboot!\n");
155 //reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
156 // LINUX_REBOOT_CMD_RESTART2, "recovery");
157 sync();
158 reboot(RB_AUTOBOOT);
159 return;
160 }
161
162
163 /**
164 * Reboots the device in order to install the given update
165 * package.
166 * Requires the {@link android.Manifest.permission#REBOOT} permission.
167 *
168 * @param packageFile the update package to install. Must be on
169 * a partition mountable by recovery. (The set of partitions
170 * known to recovery may vary from device to device. Generally,
171 * /cache and /data are safe.)
172 */
installPackage(char * update_file)173 static void installPackage(char *update_file){
174 char arg[512];
175 char *str_update_package = "--update_package=";
176 int str_update_package_len = strlen(str_update_package);
177 int str_update_file_len = strlen(update_file);
178
179 memset(arg, 0, 512);
180 strcpy(arg, str_update_package);
181 strcpy(arg + str_update_package_len, update_file);
182 arg[str_update_package_len + str_update_file_len] = 0;
183 bootCommand(arg);
184 }
185
sdUpdate()186 static void sdUpdate(){
187 installPackage(SD_UPDATE_FILE);
188 }
189
dataUpdate()190 static void dataUpdate(){
191 installPackage(DATA_UPDATE_FILE);
192 }
193
194 /**
195 * Reboots the device and wipes the user data partition. This is
196 * sometimes called a "factory reset", which is something of a
197 * misnomer because the system partition is not restored to its
198 * factory state.
199 * Requires the {@link android.Manifest.permission#REBOOT} permission.
200 *
201 * @param context the Context to use
202 *
203 */
rebootWipeUserData()204 void rebootWipeUserData(){
205 printf("update: --wipe_all\n");
206 bootCommand("--wipe_all");
207 }
208
rebootUpdate(char * path)209 int rebootUpdate(char *path){
210
211 if(path){
212 printf("find %s\n", path);
213 installPackage(path);
214 return 0;
215 }
216
217 if(access(DATA_UPDATE_FILE,F_OK) == -1){
218 printf("%s does not exist! try to use %s to update\n",
219 DATA_UPDATE_FILE, SD_UPDATE_FILE);
220 if(access(SD_UPDATE_FILE,F_OK) == -1){
221 printf("%s does not exist!\n", SD_UPDATE_FILE);
222 return -1;
223 }
224 printf("find %s\n", SD_UPDATE_FILE);
225 installPackage(SD_UPDATE_FILE);
226 return 0;
227 }
228
229 printf("find %s\n", DATA_UPDATE_FILE);
230 installPackage(DATA_UPDATE_FILE);
231 return 0;
232 }
233
main(int argc,char ** argv)234 int main(int argc, char** argv){
235 char* partition_name = "recovery";
236 printf("update: Rockchip Update Tool\n");
237
238 if(argc == 1) {
239 rebootWipeUserData();
240 } else if(argc == 2){
241 if(!strcmp(argv[1], "ota") || !strcmp(argv[1], "update"))
242 rebootUpdate(0);
243 else if(!strcmp(argv[1], "factory") || !strcmp(argv[1], "reset"))
244 rebootWipeUserData();
245 else return -1;
246
247 return 0;
248
249 } else if(argc == 3){
250 if(!strcmp(argv[1], "ota") || !strcmp(argv[1], "update")) {
251 if(argv[2]) {
252 int ret;
253 ret = WriteFwData(argv[2], partition_name);
254 if (ret < 0) {
255 if (ret == -1) {
256 printf(" Update partition %s fail \n", partition_name);
257 //means no find recovery partition in update.img
258 //return -1;
259 } else if (ret == -2) {
260 printf("Some errors happen, update process break...\n");
261 return -1;
262 }
263 } else {
264 if (!CheckFwData(argv[2], partition_name)){
265 printf(" Check partition %s fail \n", partition_name);
266 return -1;
267 }
268 }
269 return rebootUpdate(argv[2]);
270 }
271 }
272 }
273
274 return -1;
275 }
276
277