blob: 6739c1e931ca1b8058f538ee1506bd46f802fffe [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
Doug Zongker07e1dca2009-05-28 19:02:45 -070042// Return true if there is a firmware update pending.
43int firmware_update_pending() {
44 return update_data != NULL && update_length > 0;
45}
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080046
47/* Bootloader / Recovery Flow
48 *
49 * On every boot, the bootloader will read the bootloader_message
50 * from flash and check the command field. The bootloader should
51 * deal with the command field not having a 0 terminator correctly
52 * (so as to not crash if the block is invalid or corrupt).
53 *
54 * The bootloader will have to publish the partition that contains
55 * the bootloader_message to the linux kernel so it can update it.
56 *
57 * if command == "boot-recovery" -> boot recovery.img
58 * else if command == "update-radio" -> update radio image (below)
59 * else if command == "update-hboot" -> update hboot image (below)
60 * else -> boot boot.img (normal boot)
61 *
62 * Radio/Hboot Update Flow
63 * 1. the bootloader will attempt to load and validate the header
64 * 2. if the header is invalid, status="invalid-update", goto #8
65 * 3. display the busy image on-screen
66 * 4. if the update image is invalid, status="invalid-radio-image", goto #8
67 * 5. attempt to update the firmware (depending on the command)
68 * 6. if successful, status="okay", goto #8
69 * 7. if failed, and the old image can still boot, status="failed-update"
70 * 8. write the bootloader_message, leaving the recovery field
71 * unchanged, updating status, and setting command to
72 * "boot-recovery"
73 * 9. reboot
74 *
75 * The bootloader will not modify or erase the cache partition.
76 * It is recovery's responsibility to clean up the mess afterwards.
77 */
78
Doug Zongker687bc122010-01-20 16:34:10 -080079int maybe_install_firmware_update(const char *send_intent,
80 const char *log_filename) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080081 if (update_data == NULL || update_length == 0) return 0;
82
83 /* We destroy the cache partition to pass the update image to the
84 * bootloader, so all we can really do afterwards is wipe cache and reboot.
85 * Set up this instruction now, in case we're interrupted while writing.
86 */
87
88 struct bootloader_message boot;
89 memset(&boot, 0, sizeof(boot));
90 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
91 strlcpy(boot.recovery, "recovery\n--wipe_cache\n", sizeof(boot.command));
92 if (send_intent != NULL) {
93 strlcat(boot.recovery, "--send_intent=", sizeof(boot.recovery));
94 strlcat(boot.recovery, send_intent, sizeof(boot.recovery));
95 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
96 }
97 if (set_bootloader_message(&boot)) return -1;
98
99 int width = 0, height = 0, bpp = 0;
100 char *busy_image = ui_copy_image(
101 BACKGROUND_ICON_FIRMWARE_INSTALLING, &width, &height, &bpp);
102 char *fail_image = ui_copy_image(
103 BACKGROUND_ICON_FIRMWARE_ERROR, &width, &height, &bpp);
104
105 ui_print("Writing %s image...\n", update_type);
106 if (write_update_for_bootloader(
107 update_data, update_length,
Doug Zongker687bc122010-01-20 16:34:10 -0800108 width, height, bpp, busy_image, fail_image, log_filename)) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800109 LOGE("Can't write %s image\n(%s)\n", update_type, strerror(errno));
110 format_root_device("CACHE:"); // Attempt to clean cache up, at least.
111 return -1;
112 }
113
114 free(busy_image);
115 free(fail_image);
116
117 /* The update image is fully written, so now we can instruct the bootloader
118 * to install it. (After doing so, it will come back here, and we will
119 * wipe the cache and reboot into the system.)
120 */
121 snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
Doug Zongker687bc122010-01-20 16:34:10 -0800122 strlcat(boot.recovery, "--recover_log\n", sizeof(boot.recovery));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800123 if (set_bootloader_message(&boot)) {
124 format_root_device("CACHE:");
125 return -1;
126 }
127
128 reboot(RB_AUTOBOOT);
129
130 // Can't reboot? WTF?
131 LOGE("Can't reboot\n");
132 return -1;
133}