1*e7c364b6SAndroid Build Coastguard Worker /*
2*e7c364b6SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*e7c364b6SAndroid Build Coastguard Worker *
4*e7c364b6SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*e7c364b6SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*e7c364b6SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*e7c364b6SAndroid Build Coastguard Worker *
8*e7c364b6SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*e7c364b6SAndroid Build Coastguard Worker *
10*e7c364b6SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*e7c364b6SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*e7c364b6SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e7c364b6SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*e7c364b6SAndroid Build Coastguard Worker * limitations under the License.
15*e7c364b6SAndroid Build Coastguard Worker */
16*e7c364b6SAndroid Build Coastguard Worker
17*e7c364b6SAndroid Build Coastguard Worker #include <dlfcn.h>
18*e7c364b6SAndroid Build Coastguard Worker #include <errno.h>
19*e7c364b6SAndroid Build Coastguard Worker #include <fcntl.h>
20*e7c364b6SAndroid Build Coastguard Worker #include <getopt.h>
21*e7c364b6SAndroid Build Coastguard Worker #include <inttypes.h>
22*e7c364b6SAndroid Build Coastguard Worker #include <limits.h>
23*e7c364b6SAndroid Build Coastguard Worker #include <linux/fs.h>
24*e7c364b6SAndroid Build Coastguard Worker #include <stdarg.h>
25*e7c364b6SAndroid Build Coastguard Worker #include <stdio.h>
26*e7c364b6SAndroid Build Coastguard Worker #include <stdlib.h>
27*e7c364b6SAndroid Build Coastguard Worker #include <string.h>
28*e7c364b6SAndroid Build Coastguard Worker #include <sys/stat.h>
29*e7c364b6SAndroid Build Coastguard Worker #include <sys/types.h>
30*e7c364b6SAndroid Build Coastguard Worker #include <time.h>
31*e7c364b6SAndroid Build Coastguard Worker #include <unistd.h>
32*e7c364b6SAndroid Build Coastguard Worker
33*e7c364b6SAndroid Build Coastguard Worker #include <atomic>
34*e7c364b6SAndroid Build Coastguard Worker #include <string>
35*e7c364b6SAndroid Build Coastguard Worker #include <thread>
36*e7c364b6SAndroid Build Coastguard Worker #include <vector>
37*e7c364b6SAndroid Build Coastguard Worker
38*e7c364b6SAndroid Build Coastguard Worker #include <android-base/file.h>
39*e7c364b6SAndroid Build Coastguard Worker #include <android-base/logging.h>
40*e7c364b6SAndroid Build Coastguard Worker #include <android-base/properties.h>
41*e7c364b6SAndroid Build Coastguard Worker #include <android-base/strings.h>
42*e7c364b6SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
43*e7c364b6SAndroid Build Coastguard Worker #include <bootloader_message/bootloader_message.h>
44*e7c364b6SAndroid Build Coastguard Worker #include <cutils/sockets.h>
45*e7c364b6SAndroid Build Coastguard Worker #include <fs_mgr/roots.h>
46*e7c364b6SAndroid Build Coastguard Worker #include <private/android_logger.h> /* private pmsg functions */
47*e7c364b6SAndroid Build Coastguard Worker #include <selinux/android.h>
48*e7c364b6SAndroid Build Coastguard Worker #include <selinux/label.h>
49*e7c364b6SAndroid Build Coastguard Worker #include <selinux/selinux.h>
50*e7c364b6SAndroid Build Coastguard Worker
51*e7c364b6SAndroid Build Coastguard Worker #include "fastboot/fastboot.h"
52*e7c364b6SAndroid Build Coastguard Worker #include "install/wipe_data.h"
53*e7c364b6SAndroid Build Coastguard Worker #include "otautil/boot_state.h"
54*e7c364b6SAndroid Build Coastguard Worker #include "otautil/paths.h"
55*e7c364b6SAndroid Build Coastguard Worker #include "otautil/sysutil.h"
56*e7c364b6SAndroid Build Coastguard Worker #include "recovery.h"
57*e7c364b6SAndroid Build Coastguard Worker #include "recovery_ui/device.h"
58*e7c364b6SAndroid Build Coastguard Worker #include "recovery_ui/stub_ui.h"
59*e7c364b6SAndroid Build Coastguard Worker #include "recovery_ui/ui.h"
60*e7c364b6SAndroid Build Coastguard Worker #include "recovery_utils/logging.h"
61*e7c364b6SAndroid Build Coastguard Worker #include "recovery_utils/roots.h"
62*e7c364b6SAndroid Build Coastguard Worker
63*e7c364b6SAndroid Build Coastguard Worker static constexpr const char* COMMAND_FILE = "/cache/recovery/command";
64*e7c364b6SAndroid Build Coastguard Worker static constexpr const char* LOCALE_FILE = "/cache/recovery/last_locale";
65*e7c364b6SAndroid Build Coastguard Worker
66*e7c364b6SAndroid Build Coastguard Worker static RecoveryUI* ui = nullptr;
67*e7c364b6SAndroid Build Coastguard Worker
IsRoDebuggable()68*e7c364b6SAndroid Build Coastguard Worker static bool IsRoDebuggable() {
69*e7c364b6SAndroid Build Coastguard Worker return android::base::GetBoolProperty("ro.debuggable", false);
70*e7c364b6SAndroid Build Coastguard Worker }
71*e7c364b6SAndroid Build Coastguard Worker
IsDeviceUnlocked()72*e7c364b6SAndroid Build Coastguard Worker static bool IsDeviceUnlocked() {
73*e7c364b6SAndroid Build Coastguard Worker return "orange" == android::base::GetProperty("ro.boot.verifiedbootstate", "");
74*e7c364b6SAndroid Build Coastguard Worker }
75*e7c364b6SAndroid Build Coastguard Worker
UiLogger(android::base::LogId log_buffer_id,android::base::LogSeverity severity,const char * tag,const char * file,unsigned int line,const char * message)76*e7c364b6SAndroid Build Coastguard Worker static void UiLogger(android::base::LogId log_buffer_id, android::base::LogSeverity severity,
77*e7c364b6SAndroid Build Coastguard Worker const char* tag, const char* file, unsigned int line, const char* message) {
78*e7c364b6SAndroid Build Coastguard Worker android::base::KernelLogger(log_buffer_id, severity, tag, file, line, message);
79*e7c364b6SAndroid Build Coastguard Worker static constexpr auto&& log_characters = "VDIWEF";
80*e7c364b6SAndroid Build Coastguard Worker if (severity >= android::base::ERROR && ui != nullptr) {
81*e7c364b6SAndroid Build Coastguard Worker ui->Print("ERROR: %10s: %s\n", tag, message);
82*e7c364b6SAndroid Build Coastguard Worker } else {
83*e7c364b6SAndroid Build Coastguard Worker fprintf(stdout, "%c:%s\n", log_characters[severity], message);
84*e7c364b6SAndroid Build Coastguard Worker }
85*e7c364b6SAndroid Build Coastguard Worker }
86*e7c364b6SAndroid Build Coastguard Worker
87*e7c364b6SAndroid Build Coastguard Worker // Parses the command line argument from various sources; and reads the stage field from BCB.
88*e7c364b6SAndroid Build Coastguard Worker // command line args come from, in decreasing precedence:
89*e7c364b6SAndroid Build Coastguard Worker // - the actual command line
90*e7c364b6SAndroid Build Coastguard Worker // - the bootloader control block (one per line, after "recovery")
91*e7c364b6SAndroid Build Coastguard Worker // - the contents of COMMAND_FILE (one per line)
get_args(const int argc,char ** const argv,std::string * stage)92*e7c364b6SAndroid Build Coastguard Worker static std::vector<std::string> get_args(const int argc, char** const argv, std::string* stage) {
93*e7c364b6SAndroid Build Coastguard Worker CHECK_GT(argc, 0);
94*e7c364b6SAndroid Build Coastguard Worker
95*e7c364b6SAndroid Build Coastguard Worker bootloader_message boot = {};
96*e7c364b6SAndroid Build Coastguard Worker std::string err;
97*e7c364b6SAndroid Build Coastguard Worker if (!read_bootloader_message(&boot, &err)) {
98*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << err;
99*e7c364b6SAndroid Build Coastguard Worker // If fails, leave a zeroed bootloader_message.
100*e7c364b6SAndroid Build Coastguard Worker boot = {};
101*e7c364b6SAndroid Build Coastguard Worker }
102*e7c364b6SAndroid Build Coastguard Worker if (stage) {
103*e7c364b6SAndroid Build Coastguard Worker *stage = std::string(boot.stage);
104*e7c364b6SAndroid Build Coastguard Worker }
105*e7c364b6SAndroid Build Coastguard Worker
106*e7c364b6SAndroid Build Coastguard Worker std::string boot_command;
107*e7c364b6SAndroid Build Coastguard Worker if (boot.command[0] != 0) {
108*e7c364b6SAndroid Build Coastguard Worker if (memchr(boot.command, '\0', sizeof(boot.command))) {
109*e7c364b6SAndroid Build Coastguard Worker boot_command = std::string(boot.command);
110*e7c364b6SAndroid Build Coastguard Worker } else {
111*e7c364b6SAndroid Build Coastguard Worker boot_command = std::string(boot.command, sizeof(boot.command));
112*e7c364b6SAndroid Build Coastguard Worker }
113*e7c364b6SAndroid Build Coastguard Worker LOG(INFO) << "Boot command: " << boot_command;
114*e7c364b6SAndroid Build Coastguard Worker }
115*e7c364b6SAndroid Build Coastguard Worker
116*e7c364b6SAndroid Build Coastguard Worker if (boot.status[0] != 0) {
117*e7c364b6SAndroid Build Coastguard Worker std::string boot_status = std::string(boot.status, sizeof(boot.status));
118*e7c364b6SAndroid Build Coastguard Worker LOG(INFO) << "Boot status: " << boot_status;
119*e7c364b6SAndroid Build Coastguard Worker }
120*e7c364b6SAndroid Build Coastguard Worker
121*e7c364b6SAndroid Build Coastguard Worker std::vector<std::string> args(argv, argv + argc);
122*e7c364b6SAndroid Build Coastguard Worker
123*e7c364b6SAndroid Build Coastguard Worker // --- if arguments weren't supplied, look in the bootloader control block
124*e7c364b6SAndroid Build Coastguard Worker if (args.size() == 1) {
125*e7c364b6SAndroid Build Coastguard Worker boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
126*e7c364b6SAndroid Build Coastguard Worker std::string boot_recovery(boot.recovery);
127*e7c364b6SAndroid Build Coastguard Worker std::vector<std::string> tokens = android::base::Split(boot_recovery, "\n");
128*e7c364b6SAndroid Build Coastguard Worker if (!tokens.empty() && tokens[0] == "recovery") {
129*e7c364b6SAndroid Build Coastguard Worker for (auto it = tokens.begin() + 1; it != tokens.end(); it++) {
130*e7c364b6SAndroid Build Coastguard Worker // Skip empty and '\0'-filled tokens.
131*e7c364b6SAndroid Build Coastguard Worker if (!it->empty() && (*it)[0] != '\0') args.push_back(std::move(*it));
132*e7c364b6SAndroid Build Coastguard Worker }
133*e7c364b6SAndroid Build Coastguard Worker LOG(INFO) << "Got " << args.size() << " arguments from boot message " << android::base::Join(args, ", ");
134*e7c364b6SAndroid Build Coastguard Worker } else if (boot.recovery[0] != 0) {
135*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << "Bad boot message: \"" << boot_recovery << "\"";
136*e7c364b6SAndroid Build Coastguard Worker }
137*e7c364b6SAndroid Build Coastguard Worker }
138*e7c364b6SAndroid Build Coastguard Worker
139*e7c364b6SAndroid Build Coastguard Worker // --- if that doesn't work, try the command file (if we have /cache).
140*e7c364b6SAndroid Build Coastguard Worker if (args.size() == 1 && HasCache()) {
141*e7c364b6SAndroid Build Coastguard Worker std::string content;
142*e7c364b6SAndroid Build Coastguard Worker if (ensure_path_mounted(COMMAND_FILE) == 0 &&
143*e7c364b6SAndroid Build Coastguard Worker android::base::ReadFileToString(COMMAND_FILE, &content)) {
144*e7c364b6SAndroid Build Coastguard Worker std::vector<std::string> tokens = android::base::Split(content, "\n");
145*e7c364b6SAndroid Build Coastguard Worker // All the arguments in COMMAND_FILE are needed (unlike the BCB message,
146*e7c364b6SAndroid Build Coastguard Worker // COMMAND_FILE doesn't use filename as the first argument).
147*e7c364b6SAndroid Build Coastguard Worker for (auto it = tokens.begin(); it != tokens.end(); it++) {
148*e7c364b6SAndroid Build Coastguard Worker // Skip empty and '\0'-filled tokens.
149*e7c364b6SAndroid Build Coastguard Worker if (!it->empty() && (*it)[0] != '\0') args.push_back(std::move(*it));
150*e7c364b6SAndroid Build Coastguard Worker }
151*e7c364b6SAndroid Build Coastguard Worker LOG(INFO) << "Got " << args.size() << " arguments from " << COMMAND_FILE;
152*e7c364b6SAndroid Build Coastguard Worker }
153*e7c364b6SAndroid Build Coastguard Worker }
154*e7c364b6SAndroid Build Coastguard Worker
155*e7c364b6SAndroid Build Coastguard Worker // Write the arguments (excluding the filename in args[0]) back into the
156*e7c364b6SAndroid Build Coastguard Worker // bootloader control block. So the device will always boot into recovery to
157*e7c364b6SAndroid Build Coastguard Worker // finish the pending work, until FinishRecovery() is called.
158*e7c364b6SAndroid Build Coastguard Worker // This should only be done for boot-recovery command so that other commands
159*e7c364b6SAndroid Build Coastguard Worker // won't be overwritten.
160*e7c364b6SAndroid Build Coastguard Worker if (boot_command == "boot-recovery") {
161*e7c364b6SAndroid Build Coastguard Worker std::vector<std::string> options(args.cbegin() + 1, args.cend());
162*e7c364b6SAndroid Build Coastguard Worker if (!update_bootloader_message(options, &err)) {
163*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to set BCB message: " << err;
164*e7c364b6SAndroid Build Coastguard Worker }
165*e7c364b6SAndroid Build Coastguard Worker }
166*e7c364b6SAndroid Build Coastguard Worker
167*e7c364b6SAndroid Build Coastguard Worker // Finally, if no arguments were specified, check whether we should boot
168*e7c364b6SAndroid Build Coastguard Worker // into fastboot or rescue mode.
169*e7c364b6SAndroid Build Coastguard Worker if (args.size() == 1 && boot_command == "boot-fastboot") {
170*e7c364b6SAndroid Build Coastguard Worker args.emplace_back("--fastboot");
171*e7c364b6SAndroid Build Coastguard Worker } else if (args.size() == 1 && boot_command == "boot-rescue") {
172*e7c364b6SAndroid Build Coastguard Worker args.emplace_back("--rescue");
173*e7c364b6SAndroid Build Coastguard Worker }
174*e7c364b6SAndroid Build Coastguard Worker
175*e7c364b6SAndroid Build Coastguard Worker return args;
176*e7c364b6SAndroid Build Coastguard Worker }
177*e7c364b6SAndroid Build Coastguard Worker
load_locale_from_cache()178*e7c364b6SAndroid Build Coastguard Worker static std::string load_locale_from_cache() {
179*e7c364b6SAndroid Build Coastguard Worker if (ensure_path_mounted(LOCALE_FILE) != 0) {
180*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << "Can't mount " << LOCALE_FILE;
181*e7c364b6SAndroid Build Coastguard Worker return "";
182*e7c364b6SAndroid Build Coastguard Worker }
183*e7c364b6SAndroid Build Coastguard Worker
184*e7c364b6SAndroid Build Coastguard Worker std::string content;
185*e7c364b6SAndroid Build Coastguard Worker if (!android::base::ReadFileToString(LOCALE_FILE, &content)) {
186*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Can't read " << LOCALE_FILE;
187*e7c364b6SAndroid Build Coastguard Worker return "";
188*e7c364b6SAndroid Build Coastguard Worker }
189*e7c364b6SAndroid Build Coastguard Worker
190*e7c364b6SAndroid Build Coastguard Worker return android::base::Trim(content);
191*e7c364b6SAndroid Build Coastguard Worker }
192*e7c364b6SAndroid Build Coastguard Worker
193*e7c364b6SAndroid Build Coastguard Worker // Sets the usb config to 'state'.
SetUsbConfig(const std::string & state)194*e7c364b6SAndroid Build Coastguard Worker static bool SetUsbConfig(const std::string& state) {
195*e7c364b6SAndroid Build Coastguard Worker android::base::SetProperty("sys.usb.config", state);
196*e7c364b6SAndroid Build Coastguard Worker return android::base::WaitForProperty("sys.usb.state", state);
197*e7c364b6SAndroid Build Coastguard Worker }
198*e7c364b6SAndroid Build Coastguard Worker
ListenRecoverySocket(RecoveryUI * ui,std::atomic<Device::BuiltinAction> & action)199*e7c364b6SAndroid Build Coastguard Worker static void ListenRecoverySocket(RecoveryUI* ui, std::atomic<Device::BuiltinAction>& action) {
200*e7c364b6SAndroid Build Coastguard Worker android::base::unique_fd sock_fd(android_get_control_socket("recovery"));
201*e7c364b6SAndroid Build Coastguard Worker if (sock_fd < 0) {
202*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to open recovery socket";
203*e7c364b6SAndroid Build Coastguard Worker return;
204*e7c364b6SAndroid Build Coastguard Worker }
205*e7c364b6SAndroid Build Coastguard Worker listen(sock_fd, 4);
206*e7c364b6SAndroid Build Coastguard Worker
207*e7c364b6SAndroid Build Coastguard Worker while (true) {
208*e7c364b6SAndroid Build Coastguard Worker android::base::unique_fd connection_fd;
209*e7c364b6SAndroid Build Coastguard Worker connection_fd.reset(accept(sock_fd, nullptr, nullptr));
210*e7c364b6SAndroid Build Coastguard Worker if (connection_fd < 0) {
211*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to accept socket connection";
212*e7c364b6SAndroid Build Coastguard Worker continue;
213*e7c364b6SAndroid Build Coastguard Worker }
214*e7c364b6SAndroid Build Coastguard Worker char msg;
215*e7c364b6SAndroid Build Coastguard Worker constexpr char kSwitchToFastboot = 'f';
216*e7c364b6SAndroid Build Coastguard Worker constexpr char kSwitchToRecovery = 'r';
217*e7c364b6SAndroid Build Coastguard Worker ssize_t ret = TEMP_FAILURE_RETRY(read(connection_fd, &msg, sizeof(msg)));
218*e7c364b6SAndroid Build Coastguard Worker if (ret != sizeof(msg)) {
219*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Couldn't read from socket";
220*e7c364b6SAndroid Build Coastguard Worker continue;
221*e7c364b6SAndroid Build Coastguard Worker }
222*e7c364b6SAndroid Build Coastguard Worker switch (msg) {
223*e7c364b6SAndroid Build Coastguard Worker case kSwitchToRecovery:
224*e7c364b6SAndroid Build Coastguard Worker action = Device::BuiltinAction::ENTER_RECOVERY;
225*e7c364b6SAndroid Build Coastguard Worker break;
226*e7c364b6SAndroid Build Coastguard Worker case kSwitchToFastboot:
227*e7c364b6SAndroid Build Coastguard Worker action = Device::BuiltinAction::ENTER_FASTBOOT;
228*e7c364b6SAndroid Build Coastguard Worker break;
229*e7c364b6SAndroid Build Coastguard Worker default:
230*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << "Unrecognized char from socket " << msg;
231*e7c364b6SAndroid Build Coastguard Worker continue;
232*e7c364b6SAndroid Build Coastguard Worker }
233*e7c364b6SAndroid Build Coastguard Worker ui->InterruptKey();
234*e7c364b6SAndroid Build Coastguard Worker }
235*e7c364b6SAndroid Build Coastguard Worker }
236*e7c364b6SAndroid Build Coastguard Worker
redirect_stdio(const char * filename)237*e7c364b6SAndroid Build Coastguard Worker static void redirect_stdio(const char* filename) {
238*e7c364b6SAndroid Build Coastguard Worker android::base::unique_fd pipe_read, pipe_write;
239*e7c364b6SAndroid Build Coastguard Worker // Create a pipe that allows parent process sending logs over.
240*e7c364b6SAndroid Build Coastguard Worker if (!android::base::Pipe(&pipe_read, &pipe_write)) {
241*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to create pipe for redirecting stdio";
242*e7c364b6SAndroid Build Coastguard Worker
243*e7c364b6SAndroid Build Coastguard Worker // Fall back to traditional logging mode without timestamps. If these fail, there's not really
244*e7c364b6SAndroid Build Coastguard Worker // anywhere to complain...
245*e7c364b6SAndroid Build Coastguard Worker freopen(filename, "a", stdout);
246*e7c364b6SAndroid Build Coastguard Worker setbuf(stdout, nullptr);
247*e7c364b6SAndroid Build Coastguard Worker freopen(filename, "a", stderr);
248*e7c364b6SAndroid Build Coastguard Worker setbuf(stderr, nullptr);
249*e7c364b6SAndroid Build Coastguard Worker
250*e7c364b6SAndroid Build Coastguard Worker return;
251*e7c364b6SAndroid Build Coastguard Worker }
252*e7c364b6SAndroid Build Coastguard Worker
253*e7c364b6SAndroid Build Coastguard Worker pid_t pid = fork();
254*e7c364b6SAndroid Build Coastguard Worker if (pid == -1) {
255*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to fork for redirecting stdio";
256*e7c364b6SAndroid Build Coastguard Worker
257*e7c364b6SAndroid Build Coastguard Worker // Fall back to traditional logging mode without timestamps. If these fail, there's not really
258*e7c364b6SAndroid Build Coastguard Worker // anywhere to complain...
259*e7c364b6SAndroid Build Coastguard Worker freopen(filename, "a", stdout);
260*e7c364b6SAndroid Build Coastguard Worker setbuf(stdout, nullptr);
261*e7c364b6SAndroid Build Coastguard Worker freopen(filename, "a", stderr);
262*e7c364b6SAndroid Build Coastguard Worker setbuf(stderr, nullptr);
263*e7c364b6SAndroid Build Coastguard Worker
264*e7c364b6SAndroid Build Coastguard Worker return;
265*e7c364b6SAndroid Build Coastguard Worker }
266*e7c364b6SAndroid Build Coastguard Worker
267*e7c364b6SAndroid Build Coastguard Worker if (pid == 0) {
268*e7c364b6SAndroid Build Coastguard Worker // Child process reads the incoming logs and doesn't write to the pipe.
269*e7c364b6SAndroid Build Coastguard Worker pipe_write.reset();
270*e7c364b6SAndroid Build Coastguard Worker
271*e7c364b6SAndroid Build Coastguard Worker auto start = std::chrono::steady_clock::now();
272*e7c364b6SAndroid Build Coastguard Worker
273*e7c364b6SAndroid Build Coastguard Worker // Child logger to actually write to the log file.
274*e7c364b6SAndroid Build Coastguard Worker FILE* log_fp = fopen(filename, "ae");
275*e7c364b6SAndroid Build Coastguard Worker if (log_fp == nullptr) {
276*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "fopen \"" << filename << "\" failed";
277*e7c364b6SAndroid Build Coastguard Worker _exit(EXIT_FAILURE);
278*e7c364b6SAndroid Build Coastguard Worker }
279*e7c364b6SAndroid Build Coastguard Worker
280*e7c364b6SAndroid Build Coastguard Worker FILE* pipe_fp = android::base::Fdopen(std::move(pipe_read), "r");
281*e7c364b6SAndroid Build Coastguard Worker if (pipe_fp == nullptr) {
282*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "fdopen failed";
283*e7c364b6SAndroid Build Coastguard Worker check_and_fclose(log_fp, filename);
284*e7c364b6SAndroid Build Coastguard Worker _exit(EXIT_FAILURE);
285*e7c364b6SAndroid Build Coastguard Worker }
286*e7c364b6SAndroid Build Coastguard Worker
287*e7c364b6SAndroid Build Coastguard Worker char* line = nullptr;
288*e7c364b6SAndroid Build Coastguard Worker size_t len = 0;
289*e7c364b6SAndroid Build Coastguard Worker while (getline(&line, &len, pipe_fp) != -1) {
290*e7c364b6SAndroid Build Coastguard Worker auto now = std::chrono::steady_clock::now();
291*e7c364b6SAndroid Build Coastguard Worker double duration =
292*e7c364b6SAndroid Build Coastguard Worker std::chrono::duration_cast<std::chrono::duration<double>>(now - start).count();
293*e7c364b6SAndroid Build Coastguard Worker if (line[0] == '\n') {
294*e7c364b6SAndroid Build Coastguard Worker fprintf(log_fp, "[%12.6lf]\n", duration);
295*e7c364b6SAndroid Build Coastguard Worker } else {
296*e7c364b6SAndroid Build Coastguard Worker fprintf(log_fp, "[%12.6lf] %s", duration, line);
297*e7c364b6SAndroid Build Coastguard Worker }
298*e7c364b6SAndroid Build Coastguard Worker fflush(log_fp);
299*e7c364b6SAndroid Build Coastguard Worker }
300*e7c364b6SAndroid Build Coastguard Worker
301*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "getline failed";
302*e7c364b6SAndroid Build Coastguard Worker
303*e7c364b6SAndroid Build Coastguard Worker fclose(pipe_fp);
304*e7c364b6SAndroid Build Coastguard Worker free(line);
305*e7c364b6SAndroid Build Coastguard Worker check_and_fclose(log_fp, filename);
306*e7c364b6SAndroid Build Coastguard Worker _exit(EXIT_FAILURE);
307*e7c364b6SAndroid Build Coastguard Worker } else {
308*e7c364b6SAndroid Build Coastguard Worker // Redirect stdout/stderr to the logger process. Close the unused read end.
309*e7c364b6SAndroid Build Coastguard Worker pipe_read.reset();
310*e7c364b6SAndroid Build Coastguard Worker
311*e7c364b6SAndroid Build Coastguard Worker setbuf(stdout, nullptr);
312*e7c364b6SAndroid Build Coastguard Worker setbuf(stderr, nullptr);
313*e7c364b6SAndroid Build Coastguard Worker
314*e7c364b6SAndroid Build Coastguard Worker if (dup2(pipe_write.get(), STDOUT_FILENO) == -1) {
315*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "dup2 stdout failed";
316*e7c364b6SAndroid Build Coastguard Worker }
317*e7c364b6SAndroid Build Coastguard Worker if (dup2(pipe_write.get(), STDERR_FILENO) == -1) {
318*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "dup2 stderr failed";
319*e7c364b6SAndroid Build Coastguard Worker }
320*e7c364b6SAndroid Build Coastguard Worker }
321*e7c364b6SAndroid Build Coastguard Worker }
322*e7c364b6SAndroid Build Coastguard Worker
main(int argc,char ** argv)323*e7c364b6SAndroid Build Coastguard Worker int main(int argc, char** argv) {
324*e7c364b6SAndroid Build Coastguard Worker // We don't have logcat yet under recovery; so we'll print error on screen and log to stdout
325*e7c364b6SAndroid Build Coastguard Worker // (which is redirected to recovery.log) as we used to do.
326*e7c364b6SAndroid Build Coastguard Worker android::base::InitLogging(argv, &UiLogger);
327*e7c364b6SAndroid Build Coastguard Worker
328*e7c364b6SAndroid Build Coastguard Worker // Take last pmsg contents and rewrite it to the current pmsg session.
329*e7c364b6SAndroid Build Coastguard Worker static constexpr const char filter[] = "recovery/";
330*e7c364b6SAndroid Build Coastguard Worker // Do we need to rotate?
331*e7c364b6SAndroid Build Coastguard Worker bool do_rotate = false;
332*e7c364b6SAndroid Build Coastguard Worker
333*e7c364b6SAndroid Build Coastguard Worker __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logbasename, &do_rotate);
334*e7c364b6SAndroid Build Coastguard Worker // Take action to refresh pmsg contents
335*e7c364b6SAndroid Build Coastguard Worker __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logrotate, &do_rotate);
336*e7c364b6SAndroid Build Coastguard Worker
337*e7c364b6SAndroid Build Coastguard Worker time_t start = time(nullptr);
338*e7c364b6SAndroid Build Coastguard Worker
339*e7c364b6SAndroid Build Coastguard Worker // redirect_stdio should be called only in non-sideload mode. Otherwise we may have two logger
340*e7c364b6SAndroid Build Coastguard Worker // instances with different timestamps.
341*e7c364b6SAndroid Build Coastguard Worker redirect_stdio(Paths::Get().temporary_log_file().c_str());
342*e7c364b6SAndroid Build Coastguard Worker
343*e7c364b6SAndroid Build Coastguard Worker load_volume_table();
344*e7c364b6SAndroid Build Coastguard Worker
345*e7c364b6SAndroid Build Coastguard Worker std::string stage;
346*e7c364b6SAndroid Build Coastguard Worker std::vector<std::string> args = get_args(argc, argv, &stage);
347*e7c364b6SAndroid Build Coastguard Worker auto args_to_parse = StringVectorToNullTerminatedArray(args);
348*e7c364b6SAndroid Build Coastguard Worker
349*e7c364b6SAndroid Build Coastguard Worker static constexpr struct option OPTIONS[] = {
350*e7c364b6SAndroid Build Coastguard Worker { "fastboot", no_argument, nullptr, 0 },
351*e7c364b6SAndroid Build Coastguard Worker { "locale", required_argument, nullptr, 0 },
352*e7c364b6SAndroid Build Coastguard Worker { "reason", required_argument, nullptr, 0 },
353*e7c364b6SAndroid Build Coastguard Worker { "show_text", no_argument, nullptr, 't' },
354*e7c364b6SAndroid Build Coastguard Worker { nullptr, 0, nullptr, 0 },
355*e7c364b6SAndroid Build Coastguard Worker };
356*e7c364b6SAndroid Build Coastguard Worker
357*e7c364b6SAndroid Build Coastguard Worker bool show_text = false;
358*e7c364b6SAndroid Build Coastguard Worker bool fastboot = false;
359*e7c364b6SAndroid Build Coastguard Worker std::string locale;
360*e7c364b6SAndroid Build Coastguard Worker std::string reason;
361*e7c364b6SAndroid Build Coastguard Worker
362*e7c364b6SAndroid Build Coastguard Worker // The code here is only interested in the options that signal the intent to start fastbootd or
363*e7c364b6SAndroid Build Coastguard Worker // recovery. Unrecognized options are likely meant for recovery, which will be processed later in
364*e7c364b6SAndroid Build Coastguard Worker // start_recovery(). Suppress the warnings for such -- even if some flags were indeed invalid, the
365*e7c364b6SAndroid Build Coastguard Worker // code in start_recovery() will capture and report them.
366*e7c364b6SAndroid Build Coastguard Worker opterr = 0;
367*e7c364b6SAndroid Build Coastguard Worker
368*e7c364b6SAndroid Build Coastguard Worker int arg;
369*e7c364b6SAndroid Build Coastguard Worker int option_index;
370*e7c364b6SAndroid Build Coastguard Worker while ((arg = getopt_long(args_to_parse.size() - 1, args_to_parse.data(), "", OPTIONS,
371*e7c364b6SAndroid Build Coastguard Worker &option_index)) != -1) {
372*e7c364b6SAndroid Build Coastguard Worker switch (arg) {
373*e7c364b6SAndroid Build Coastguard Worker case 't':
374*e7c364b6SAndroid Build Coastguard Worker show_text = true;
375*e7c364b6SAndroid Build Coastguard Worker break;
376*e7c364b6SAndroid Build Coastguard Worker case 0: {
377*e7c364b6SAndroid Build Coastguard Worker std::string option = OPTIONS[option_index].name;
378*e7c364b6SAndroid Build Coastguard Worker if (option == "locale") {
379*e7c364b6SAndroid Build Coastguard Worker locale = optarg;
380*e7c364b6SAndroid Build Coastguard Worker } else if (option == "reason") {
381*e7c364b6SAndroid Build Coastguard Worker reason = optarg;
382*e7c364b6SAndroid Build Coastguard Worker } else if (option == "fastboot" &&
383*e7c364b6SAndroid Build Coastguard Worker android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
384*e7c364b6SAndroid Build Coastguard Worker fastboot = true;
385*e7c364b6SAndroid Build Coastguard Worker }
386*e7c364b6SAndroid Build Coastguard Worker break;
387*e7c364b6SAndroid Build Coastguard Worker }
388*e7c364b6SAndroid Build Coastguard Worker }
389*e7c364b6SAndroid Build Coastguard Worker }
390*e7c364b6SAndroid Build Coastguard Worker optind = 1;
391*e7c364b6SAndroid Build Coastguard Worker opterr = 1;
392*e7c364b6SAndroid Build Coastguard Worker
393*e7c364b6SAndroid Build Coastguard Worker if (locale.empty()) {
394*e7c364b6SAndroid Build Coastguard Worker if (HasCache()) {
395*e7c364b6SAndroid Build Coastguard Worker locale = load_locale_from_cache();
396*e7c364b6SAndroid Build Coastguard Worker }
397*e7c364b6SAndroid Build Coastguard Worker
398*e7c364b6SAndroid Build Coastguard Worker if (locale.empty()) {
399*e7c364b6SAndroid Build Coastguard Worker locale = DEFAULT_LOCALE;
400*e7c364b6SAndroid Build Coastguard Worker }
401*e7c364b6SAndroid Build Coastguard Worker }
402*e7c364b6SAndroid Build Coastguard Worker
403*e7c364b6SAndroid Build Coastguard Worker static constexpr const char* kDefaultLibRecoveryUIExt = "librecovery_ui_ext.so";
404*e7c364b6SAndroid Build Coastguard Worker // Intentionally not calling dlclose(3) to avoid potential gotchas (e.g. `make_device` may have
405*e7c364b6SAndroid Build Coastguard Worker // handed out pointers to code or static [or thread-local] data and doesn't collect them all back
406*e7c364b6SAndroid Build Coastguard Worker // in on dlclose).
407*e7c364b6SAndroid Build Coastguard Worker void* librecovery_ui_ext = dlopen(kDefaultLibRecoveryUIExt, RTLD_NOW);
408*e7c364b6SAndroid Build Coastguard Worker
409*e7c364b6SAndroid Build Coastguard Worker using MakeDeviceType = decltype(&make_device);
410*e7c364b6SAndroid Build Coastguard Worker MakeDeviceType make_device_func = nullptr;
411*e7c364b6SAndroid Build Coastguard Worker if (librecovery_ui_ext == nullptr) {
412*e7c364b6SAndroid Build Coastguard Worker printf("Failed to dlopen %s: %s\n", kDefaultLibRecoveryUIExt, dlerror());
413*e7c364b6SAndroid Build Coastguard Worker } else {
414*e7c364b6SAndroid Build Coastguard Worker reinterpret_cast<void*&>(make_device_func) = dlsym(librecovery_ui_ext, "make_device");
415*e7c364b6SAndroid Build Coastguard Worker if (make_device_func == nullptr) {
416*e7c364b6SAndroid Build Coastguard Worker printf("Failed to dlsym make_device: %s\n", dlerror());
417*e7c364b6SAndroid Build Coastguard Worker }
418*e7c364b6SAndroid Build Coastguard Worker }
419*e7c364b6SAndroid Build Coastguard Worker
420*e7c364b6SAndroid Build Coastguard Worker Device* device;
421*e7c364b6SAndroid Build Coastguard Worker if (make_device_func == nullptr) {
422*e7c364b6SAndroid Build Coastguard Worker printf("Falling back to the default make_device() instead\n");
423*e7c364b6SAndroid Build Coastguard Worker device = make_device();
424*e7c364b6SAndroid Build Coastguard Worker } else {
425*e7c364b6SAndroid Build Coastguard Worker printf("Loading make_device from %s\n", kDefaultLibRecoveryUIExt);
426*e7c364b6SAndroid Build Coastguard Worker device = (*make_device_func)();
427*e7c364b6SAndroid Build Coastguard Worker }
428*e7c364b6SAndroid Build Coastguard Worker
429*e7c364b6SAndroid Build Coastguard Worker if (android::base::GetBoolProperty("ro.boot.quiescent", false)) {
430*e7c364b6SAndroid Build Coastguard Worker printf("Quiescent recovery mode.\n");
431*e7c364b6SAndroid Build Coastguard Worker device->ResetUI(new StubRecoveryUI());
432*e7c364b6SAndroid Build Coastguard Worker } else {
433*e7c364b6SAndroid Build Coastguard Worker if (!device->GetUI()->Init(locale)) {
434*e7c364b6SAndroid Build Coastguard Worker printf("Failed to initialize UI; using stub UI instead.\n");
435*e7c364b6SAndroid Build Coastguard Worker device->ResetUI(new StubRecoveryUI());
436*e7c364b6SAndroid Build Coastguard Worker }
437*e7c364b6SAndroid Build Coastguard Worker }
438*e7c364b6SAndroid Build Coastguard Worker
439*e7c364b6SAndroid Build Coastguard Worker BootState boot_state(reason, stage); // recovery_main owns the state of boot.
440*e7c364b6SAndroid Build Coastguard Worker device->SetBootState(&boot_state);
441*e7c364b6SAndroid Build Coastguard Worker ui = device->GetUI();
442*e7c364b6SAndroid Build Coastguard Worker
443*e7c364b6SAndroid Build Coastguard Worker if (!HasCache()) {
444*e7c364b6SAndroid Build Coastguard Worker device->RemoveMenuItemForAction(Device::WIPE_CACHE);
445*e7c364b6SAndroid Build Coastguard Worker }
446*e7c364b6SAndroid Build Coastguard Worker
447*e7c364b6SAndroid Build Coastguard Worker if (!android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
448*e7c364b6SAndroid Build Coastguard Worker device->RemoveMenuItemForAction(Device::ENTER_FASTBOOT);
449*e7c364b6SAndroid Build Coastguard Worker }
450*e7c364b6SAndroid Build Coastguard Worker
451*e7c364b6SAndroid Build Coastguard Worker if (!IsRoDebuggable()) {
452*e7c364b6SAndroid Build Coastguard Worker device->RemoveMenuItemForAction(Device::ENTER_RESCUE);
453*e7c364b6SAndroid Build Coastguard Worker }
454*e7c364b6SAndroid Build Coastguard Worker
455*e7c364b6SAndroid Build Coastguard Worker ui->SetBackground(RecoveryUI::NONE);
456*e7c364b6SAndroid Build Coastguard Worker if (show_text) ui->ShowText(true);
457*e7c364b6SAndroid Build Coastguard Worker
458*e7c364b6SAndroid Build Coastguard Worker LOG(INFO) << "Starting recovery (pid " << getpid() << ") on " << ctime(&start);
459*e7c364b6SAndroid Build Coastguard Worker LOG(INFO) << "locale is [" << locale << "]";
460*e7c364b6SAndroid Build Coastguard Worker
461*e7c364b6SAndroid Build Coastguard Worker auto sehandle = selinux_android_file_context_handle();
462*e7c364b6SAndroid Build Coastguard Worker selinux_android_set_sehandle(sehandle);
463*e7c364b6SAndroid Build Coastguard Worker if (!sehandle) {
464*e7c364b6SAndroid Build Coastguard Worker ui->Print("Warning: No file_contexts\n");
465*e7c364b6SAndroid Build Coastguard Worker }
466*e7c364b6SAndroid Build Coastguard Worker
467*e7c364b6SAndroid Build Coastguard Worker SetLoggingSehandle(sehandle);
468*e7c364b6SAndroid Build Coastguard Worker
469*e7c364b6SAndroid Build Coastguard Worker std::atomic<Device::BuiltinAction> action;
470*e7c364b6SAndroid Build Coastguard Worker std::thread listener_thread(ListenRecoverySocket, ui, std::ref(action));
471*e7c364b6SAndroid Build Coastguard Worker listener_thread.detach();
472*e7c364b6SAndroid Build Coastguard Worker
473*e7c364b6SAndroid Build Coastguard Worker while (true) {
474*e7c364b6SAndroid Build Coastguard Worker // We start adbd in recovery for the device with userdebug build or a unlocked bootloader.
475*e7c364b6SAndroid Build Coastguard Worker std::string usb_config =
476*e7c364b6SAndroid Build Coastguard Worker fastboot ? "fastboot" : IsRoDebuggable() || IsDeviceUnlocked() ? "adb" : "none";
477*e7c364b6SAndroid Build Coastguard Worker std::string usb_state = android::base::GetProperty("sys.usb.state", "none");
478*e7c364b6SAndroid Build Coastguard Worker if (fastboot) {
479*e7c364b6SAndroid Build Coastguard Worker device->PreFastboot();
480*e7c364b6SAndroid Build Coastguard Worker } else {
481*e7c364b6SAndroid Build Coastguard Worker device->PreRecovery();
482*e7c364b6SAndroid Build Coastguard Worker }
483*e7c364b6SAndroid Build Coastguard Worker if (usb_config != usb_state) {
484*e7c364b6SAndroid Build Coastguard Worker if (!SetUsbConfig("none")) {
485*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to clear USB config";
486*e7c364b6SAndroid Build Coastguard Worker }
487*e7c364b6SAndroid Build Coastguard Worker if (!SetUsbConfig(usb_config)) {
488*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to set USB config to " << usb_config;
489*e7c364b6SAndroid Build Coastguard Worker }
490*e7c364b6SAndroid Build Coastguard Worker }
491*e7c364b6SAndroid Build Coastguard Worker
492*e7c364b6SAndroid Build Coastguard Worker auto ret = fastboot ? StartFastboot(device, args) : start_recovery(device, args);
493*e7c364b6SAndroid Build Coastguard Worker
494*e7c364b6SAndroid Build Coastguard Worker if (ret == Device::KEY_INTERRUPTED) {
495*e7c364b6SAndroid Build Coastguard Worker ret = action.exchange(ret);
496*e7c364b6SAndroid Build Coastguard Worker if (ret == Device::NO_ACTION) {
497*e7c364b6SAndroid Build Coastguard Worker continue;
498*e7c364b6SAndroid Build Coastguard Worker }
499*e7c364b6SAndroid Build Coastguard Worker }
500*e7c364b6SAndroid Build Coastguard Worker switch (ret) {
501*e7c364b6SAndroid Build Coastguard Worker case Device::SHUTDOWN:
502*e7c364b6SAndroid Build Coastguard Worker ui->Print("Shutting down...\n");
503*e7c364b6SAndroid Build Coastguard Worker Shutdown("userrequested,recovery");
504*e7c364b6SAndroid Build Coastguard Worker break;
505*e7c364b6SAndroid Build Coastguard Worker
506*e7c364b6SAndroid Build Coastguard Worker case Device::SHUTDOWN_FROM_FASTBOOT:
507*e7c364b6SAndroid Build Coastguard Worker ui->Print("Shutting down...\n");
508*e7c364b6SAndroid Build Coastguard Worker Shutdown("userrequested,fastboot");
509*e7c364b6SAndroid Build Coastguard Worker break;
510*e7c364b6SAndroid Build Coastguard Worker
511*e7c364b6SAndroid Build Coastguard Worker case Device::REBOOT_BOOTLOADER:
512*e7c364b6SAndroid Build Coastguard Worker ui->Print("Rebooting to bootloader...\n");
513*e7c364b6SAndroid Build Coastguard Worker Reboot("bootloader");
514*e7c364b6SAndroid Build Coastguard Worker break;
515*e7c364b6SAndroid Build Coastguard Worker
516*e7c364b6SAndroid Build Coastguard Worker case Device::REBOOT_FASTBOOT:
517*e7c364b6SAndroid Build Coastguard Worker ui->Print("Rebooting to recovery/fastboot...\n");
518*e7c364b6SAndroid Build Coastguard Worker Reboot("fastboot");
519*e7c364b6SAndroid Build Coastguard Worker break;
520*e7c364b6SAndroid Build Coastguard Worker
521*e7c364b6SAndroid Build Coastguard Worker case Device::REBOOT_RECOVERY:
522*e7c364b6SAndroid Build Coastguard Worker ui->Print("Rebooting to recovery...\n");
523*e7c364b6SAndroid Build Coastguard Worker Reboot("recovery");
524*e7c364b6SAndroid Build Coastguard Worker break;
525*e7c364b6SAndroid Build Coastguard Worker
526*e7c364b6SAndroid Build Coastguard Worker case Device::REBOOT_RESCUE: {
527*e7c364b6SAndroid Build Coastguard Worker // Not using `Reboot("rescue")`, as it requires matching support in kernel and/or
528*e7c364b6SAndroid Build Coastguard Worker // bootloader.
529*e7c364b6SAndroid Build Coastguard Worker bootloader_message boot = {};
530*e7c364b6SAndroid Build Coastguard Worker strlcpy(boot.command, "boot-rescue", sizeof(boot.command));
531*e7c364b6SAndroid Build Coastguard Worker std::string err;
532*e7c364b6SAndroid Build Coastguard Worker if (!write_bootloader_message(boot, &err)) {
533*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to write bootloader message: " << err;
534*e7c364b6SAndroid Build Coastguard Worker // Stay under recovery on failure.
535*e7c364b6SAndroid Build Coastguard Worker continue;
536*e7c364b6SAndroid Build Coastguard Worker }
537*e7c364b6SAndroid Build Coastguard Worker ui->Print("Rebooting to recovery/rescue...\n");
538*e7c364b6SAndroid Build Coastguard Worker Reboot("recovery");
539*e7c364b6SAndroid Build Coastguard Worker break;
540*e7c364b6SAndroid Build Coastguard Worker }
541*e7c364b6SAndroid Build Coastguard Worker
542*e7c364b6SAndroid Build Coastguard Worker case Device::ENTER_FASTBOOT:
543*e7c364b6SAndroid Build Coastguard Worker if (android::fs_mgr::LogicalPartitionsMapped()) {
544*e7c364b6SAndroid Build Coastguard Worker ui->Print("Partitions may be mounted - rebooting to enter fastboot.");
545*e7c364b6SAndroid Build Coastguard Worker Reboot("fastboot");
546*e7c364b6SAndroid Build Coastguard Worker } else {
547*e7c364b6SAndroid Build Coastguard Worker LOG(INFO) << "Entering fastboot";
548*e7c364b6SAndroid Build Coastguard Worker fastboot = true;
549*e7c364b6SAndroid Build Coastguard Worker }
550*e7c364b6SAndroid Build Coastguard Worker break;
551*e7c364b6SAndroid Build Coastguard Worker
552*e7c364b6SAndroid Build Coastguard Worker case Device::ENTER_RECOVERY:
553*e7c364b6SAndroid Build Coastguard Worker LOG(INFO) << "Entering recovery";
554*e7c364b6SAndroid Build Coastguard Worker fastboot = false;
555*e7c364b6SAndroid Build Coastguard Worker ui->SetEnableFastbootdLogo(fastboot);
556*e7c364b6SAndroid Build Coastguard Worker break;
557*e7c364b6SAndroid Build Coastguard Worker
558*e7c364b6SAndroid Build Coastguard Worker case Device::REBOOT:
559*e7c364b6SAndroid Build Coastguard Worker ui->Print("Rebooting...\n");
560*e7c364b6SAndroid Build Coastguard Worker Reboot("userrequested,recovery");
561*e7c364b6SAndroid Build Coastguard Worker break;
562*e7c364b6SAndroid Build Coastguard Worker
563*e7c364b6SAndroid Build Coastguard Worker case Device::REBOOT_FROM_FASTBOOT:
564*e7c364b6SAndroid Build Coastguard Worker ui->Print("Rebooting...\n");
565*e7c364b6SAndroid Build Coastguard Worker Reboot("userrequested,fastboot");
566*e7c364b6SAndroid Build Coastguard Worker break;
567*e7c364b6SAndroid Build Coastguard Worker
568*e7c364b6SAndroid Build Coastguard Worker default:
569*e7c364b6SAndroid Build Coastguard Worker ui->Print("Rebooting...\n");
570*e7c364b6SAndroid Build Coastguard Worker Reboot("unknown" + std::to_string(ret));
571*e7c364b6SAndroid Build Coastguard Worker break;
572*e7c364b6SAndroid Build Coastguard Worker }
573*e7c364b6SAndroid Build Coastguard Worker }
574*e7c364b6SAndroid Build Coastguard Worker
575*e7c364b6SAndroid Build Coastguard Worker // Should be unreachable.
576*e7c364b6SAndroid Build Coastguard Worker return EXIT_SUCCESS;
577*e7c364b6SAndroid Build Coastguard Worker }
578