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