xref: /aosp_15_r20/bootable/recovery/recovery_main.cpp (revision e7c364b630b241adcb6c7726a21055250b91fdac)
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