/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * RecoverySystem contains methods for interacting with the Android * recovery system (the separate partition that can be used to install * system updates, wipe user data, etc.) */ //#include #include //#include #include #include #include #include #include #include #include "update_recv/update_recv.h" #define LOG_FILE_LEN 512 #if 0 #define RECOVERY_PATH "/tmp/recovery" #define LOG_FILE_PATH "/tmp/recovery/log" #define COMMAND_FILE_PATH "/tmp/recovery/command" #else #define RECOVERY_PATH "/userdata/recovery" #define LOG_FILE_PATH "/userdata/recovery/log" #define COMMAND_FILE_PATH "/userdata/recovery/command" #endif #define SD_UPDATE_FILE "/sdcard/update.img" #define DATA_UPDATE_FILE "/userdata/update.img" #define MISC_FILE_PATH "/dev/block/by-name/misc" #define MISC_MSG_OFFSET 16 * 1024 /* Bootloader Message (2-KiB) * * This structure describes the content of a block in flash * that is used for recovery and the bootloader to talk to * each other. * * The command field is updated by linux when it wants to * reboot into recovery or to update radio or bootloader firmware. * It is also updated by the bootloader when firmware update * is complete (to boot into recovery for any final cleanup) * * The status field is written by the bootloader after the * completion of an "update-radio" or "update-hboot" command. * * The recovery field is only written by linux and used * for the system to send a message to recovery or the * other way around. * * The stage field is written by packages which restart themselves * multiple times, so that the UI can reflect which invocation of the * package it is. If the value is of the format "#/#" (eg, "1/3"), * the UI will add a simple indicator of that status. * * We used to have slot_suffix field for A/B boot control metadata in * this struct, which gets unintentionally cleared by recovery or * uncrypt. Move it into struct bootloader_message_ab to avoid the * issue. */ struct android_bootloader_message { char command[32]; char status[32]; char recovery[768]; /* The 'recovery' field used to be 1024 bytes. It has only ever * been used to store the recovery command line, so 768 bytes * should be plenty. We carve off the last 256 bytes to store the * stage string (for multistage packages) and possible future * expansion. */ char stage[32]; /* The 'reserved' field used to be 224 bytes when it was initially * carved off from the 1024-byte recovery field. Bump it up to * 1184-byte so that the entire bootloader_message struct rounds up * to 2048-byte. */ char reserved[1184]; }; /** * Reboot into the recovery system with the supplied argument. * @param arg to pass to the recovery utility. */ static void bootCommand(char *arg){ FILE *command_file; FILE *log_file; FILE *misc_file; char blank[LOG_FILE_LEN]; if(!arg) return; printf("command: %s\n", arg); mkdir(RECOVERY_PATH,0775); if((command_file = fopen(COMMAND_FILE_PATH,"wb")) == NULL){ printf("Open command file error.\n"); return; } if((log_file = fopen(LOG_FILE_PATH,"wb")) == NULL){ printf("Open log file error.\n"); return; } if((misc_file = fopen(MISC_FILE_PATH,"wb")) == NULL){ printf("Open misc file error.\n"); return; } printf("update: write command to command file: "); fwrite(arg, strlen(arg), 1, command_file); fwrite("\n", 1, 1, command_file); fclose(command_file); printf("done\n"); printf("update: write command to misc file: "); fseek(misc_file, MISC_MSG_OFFSET, SEEK_SET); struct android_bootloader_message msg; memset(&msg, 0, sizeof(msg)); char recovery_str[] = "recovery\n"; strcpy(msg.command, "boot-recovery"); strcpy(msg.recovery, recovery_str); memcpy(msg.recovery + strlen(recovery_str), arg, ((strlen(arg) > sizeof(msg.recovery))? sizeof(msg.recovery) : strlen(arg))); msg.recovery[strlen(msg.recovery) + 1] = '\n'; //strlcat(msg.recovery, update_file, sizeof(msg.recovery)); //strlcat(msg.recovery, "\n", sizeof(msg.recovery)); //strlcpy(msg.systemFlag, "false", sizeof(msg.systemFlag)); fwrite(&msg, sizeof(msg), 1, misc_file); fclose(misc_file); printf("done\n"); memset(blank, 0, LOG_FILE_LEN); fwrite(blank, LOG_FILE_LEN, 1, log_file); fclose(log_file); printf("update: reboot!\n"); //reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, // LINUX_REBOOT_CMD_RESTART2, "recovery"); sync(); reboot(RB_AUTOBOOT); return; } /** * Reboots the device in order to install the given update * package. * Requires the {@link android.Manifest.permission#REBOOT} permission. * * @param packageFile the update package to install. Must be on * a partition mountable by recovery. (The set of partitions * known to recovery may vary from device to device. Generally, * /cache and /data are safe.) */ static void installPackage(char *update_file){ char arg[512]; char *str_update_package = "--update_package="; int str_update_package_len = strlen(str_update_package); int str_update_file_len = strlen(update_file); memset(arg, 0, 512); strcpy(arg, str_update_package); strcpy(arg + str_update_package_len, update_file); arg[str_update_package_len + str_update_file_len] = 0; bootCommand(arg); } static void sdUpdate(){ installPackage(SD_UPDATE_FILE); } static void dataUpdate(){ installPackage(DATA_UPDATE_FILE); } /** * Reboots the device and wipes the user data partition. This is * sometimes called a "factory reset", which is something of a * misnomer because the system partition is not restored to its * factory state. * Requires the {@link android.Manifest.permission#REBOOT} permission. * * @param context the Context to use * */ void rebootWipeUserData(){ printf("update: --wipe_all\n"); bootCommand("--wipe_all"); } int rebootUpdate(char *path){ if(path){ printf("find %s\n", path); installPackage(path); return 0; } if(access(DATA_UPDATE_FILE,F_OK) == -1){ printf("%s does not exist! try to use %s to update\n", DATA_UPDATE_FILE, SD_UPDATE_FILE); if(access(SD_UPDATE_FILE,F_OK) == -1){ printf("%s does not exist!\n", SD_UPDATE_FILE); return -1; } printf("find %s\n", SD_UPDATE_FILE); installPackage(SD_UPDATE_FILE); return 0; } printf("find %s\n", DATA_UPDATE_FILE); installPackage(DATA_UPDATE_FILE); return 0; } int main(int argc, char** argv){ char* partition_name = "recovery"; printf("update: Rockchip Update Tool\n"); if(argc == 1) { rebootWipeUserData(); } else if(argc == 2){ if(!strcmp(argv[1], "ota") || !strcmp(argv[1], "update")) rebootUpdate(0); else if(!strcmp(argv[1], "factory") || !strcmp(argv[1], "reset")) rebootWipeUserData(); else return -1; return 0; } else if(argc == 3){ if(!strcmp(argv[1], "ota") || !strcmp(argv[1], "update")) { if(argv[2]) { int ret; ret = WriteFwData(argv[2], partition_name); if (ret < 0) { if (ret == -1) { printf(" Update partition %s fail \n", partition_name); //means no find recovery partition in update.img //return -1; } else if (ret == -2) { printf("Some errors happen, update process break...\n"); return -1; } } else { if (!CheckFwData(argv[2], partition_name)){ printf(" Check partition %s fail \n", partition_name); return -1; } } return rebootUpdate(argv[2]); } } } return -1; }