blob: 34b291835f8a95724ab74ff2d84f547934112aa2 [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
2 * Copyright (C) 2008 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#include "bootloader.h"
18#include "common.h"
19#include "firmware.h"
20#include "roots.h"
21
22#include <errno.h>
23#include <string.h>
24#include <sys/reboot.h>
25
26static const char *update_type = NULL;
27static const char *update_data = NULL;
28static int update_length = 0;
29
30int remember_firmware_update(const char *type, const char *data, int length) {
31 if (update_type != NULL || update_data != NULL) {
32 LOGE("Multiple firmware images\n");
33 return -1;
34 }
35
36 update_type = type;
37 update_data = data;
38 update_length = length;
39 return 0;
40}
41
42
43/* Bootloader / Recovery Flow
44 *
45 * On every boot, the bootloader will read the bootloader_message
46 * from flash and check the command field. The bootloader should
47 * deal with the command field not having a 0 terminator correctly
48 * (so as to not crash if the block is invalid or corrupt).
49 *
50 * The bootloader will have to publish the partition that contains
51 * the bootloader_message to the linux kernel so it can update it.
52 *
53 * if command == "boot-recovery" -> boot recovery.img
54 * else if command == "update-radio" -> update radio image (below)
55 * else if command == "update-hboot" -> update hboot image (below)
56 * else -> boot boot.img (normal boot)
57 *
58 * Radio/Hboot Update Flow
59 * 1. the bootloader will attempt to load and validate the header
60 * 2. if the header is invalid, status="invalid-update", goto #8
61 * 3. display the busy image on-screen
62 * 4. if the update image is invalid, status="invalid-radio-image", goto #8
63 * 5. attempt to update the firmware (depending on the command)
64 * 6. if successful, status="okay", goto #8
65 * 7. if failed, and the old image can still boot, status="failed-update"
66 * 8. write the bootloader_message, leaving the recovery field
67 * unchanged, updating status, and setting command to
68 * "boot-recovery"
69 * 9. reboot
70 *
71 * The bootloader will not modify or erase the cache partition.
72 * It is recovery's responsibility to clean up the mess afterwards.
73 */
74
75int maybe_install_firmware_update(const char *send_intent) {
76 if (update_data == NULL || update_length == 0) return 0;
77
78 /* We destroy the cache partition to pass the update image to the
79 * bootloader, so all we can really do afterwards is wipe cache and reboot.
80 * Set up this instruction now, in case we're interrupted while writing.
81 */
82
83 struct bootloader_message boot;
84 memset(&boot, 0, sizeof(boot));
85 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
86 strlcpy(boot.recovery, "recovery\n--wipe_cache\n", sizeof(boot.command));
87 if (send_intent != NULL) {
88 strlcat(boot.recovery, "--send_intent=", sizeof(boot.recovery));
89 strlcat(boot.recovery, send_intent, sizeof(boot.recovery));
90 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
91 }
92 if (set_bootloader_message(&boot)) return -1;
93
94 int width = 0, height = 0, bpp = 0;
95 char *busy_image = ui_copy_image(
96 BACKGROUND_ICON_FIRMWARE_INSTALLING, &width, &height, &bpp);
97 char *fail_image = ui_copy_image(
98 BACKGROUND_ICON_FIRMWARE_ERROR, &width, &height, &bpp);
99
100 ui_print("Writing %s image...\n", update_type);
101 if (write_update_for_bootloader(
102 update_data, update_length,
103 width, height, bpp, busy_image, fail_image)) {
104 LOGE("Can't write %s image\n(%s)\n", update_type, strerror(errno));
105 format_root_device("CACHE:"); // Attempt to clean cache up, at least.
106 return -1;
107 }
108
109 free(busy_image);
110 free(fail_image);
111
112 /* The update image is fully written, so now we can instruct the bootloader
113 * to install it. (After doing so, it will come back here, and we will
114 * wipe the cache and reboot into the system.)
115 */
116 snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
117 if (set_bootloader_message(&boot)) {
118 format_root_device("CACHE:");
119 return -1;
120 }
121
122 reboot(RB_AUTOBOOT);
123
124 // Can't reboot? WTF?
125 LOGE("Can't reboot\n");
126 return -1;
127}