From 6d99d4b4571b95ff221439c819826381f8bb96f9 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 25 Apr 2018 16:47:04 -0700 Subject: recovery: Split main() into recovery_main.cpp. This prepares for moving more codes from recovery into librecovery, so that they will become more easily testable. recovery_main.cpp will be the source code for recovery module, with the rest moved into librecovery. recovery_main.cpp mainly does the initializations, such as setting up the logger. Test: mmma -j bootable/recovery Test: recovery_component_test Test: Build and boot into recovery image on marlin. Change-Id: I8e846524546b6f3f0e32ed869e851f62261eef23 Merged-In: I8e846524546b6f3f0e32ed869e851f62261eef23 --- recovery_main.cpp | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 recovery_main.cpp (limited to 'recovery_main.cpp') diff --git a/recovery_main.cpp b/recovery_main.cpp new file mode 100644 index 000000000..9f579f7cd --- /dev/null +++ b/recovery_main.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include /* private pmsg functions */ + +#include "common.h" +#include "minadbd/minadbd.h" +#include "otautil/paths.h" +#include "private/recovery.h" +#include "rotate_logs.h" +#include "ui.h" + +static void UiLogger(android::base::LogId /* id */, android::base::LogSeverity severity, + const char* /* tag */, const char* /* file */, unsigned int /* line */, + const char* message) { + static constexpr char log_characters[] = "VDIWEF"; + if (severity >= android::base::ERROR && ui != nullptr) { + ui->Print("E:%s\n", message); + } else { + fprintf(stdout, "%c:%s\n", log_characters[severity], message); + } +} + +static void redirect_stdio(const char* filename) { + int pipefd[2]; + if (pipe(pipefd) == -1) { + PLOG(ERROR) << "pipe failed"; + + // Fall back to traditional logging mode without timestamps. If these fail, there's not really + // anywhere to complain... + freopen(filename, "a", stdout); + setbuf(stdout, nullptr); + freopen(filename, "a", stderr); + setbuf(stderr, nullptr); + + return; + } + + pid_t pid = fork(); + if (pid == -1) { + PLOG(ERROR) << "fork failed"; + + // Fall back to traditional logging mode without timestamps. If these fail, there's not really + // anywhere to complain... + freopen(filename, "a", stdout); + setbuf(stdout, nullptr); + freopen(filename, "a", stderr); + setbuf(stderr, nullptr); + + return; + } + + if (pid == 0) { + /// Close the unused write end. + close(pipefd[1]); + + auto start = std::chrono::steady_clock::now(); + + // Child logger to actually write to the log file. + FILE* log_fp = fopen(filename, "ae"); + if (log_fp == nullptr) { + PLOG(ERROR) << "fopen \"" << filename << "\" failed"; + close(pipefd[0]); + _exit(EXIT_FAILURE); + } + + FILE* pipe_fp = fdopen(pipefd[0], "r"); + if (pipe_fp == nullptr) { + PLOG(ERROR) << "fdopen failed"; + check_and_fclose(log_fp, filename); + close(pipefd[0]); + _exit(EXIT_FAILURE); + } + + char* line = nullptr; + size_t len = 0; + while (getline(&line, &len, pipe_fp) != -1) { + auto now = std::chrono::steady_clock::now(); + double duration = + std::chrono::duration_cast>(now - start).count(); + if (line[0] == '\n') { + fprintf(log_fp, "[%12.6lf]\n", duration); + } else { + fprintf(log_fp, "[%12.6lf] %s", duration, line); + } + fflush(log_fp); + } + + PLOG(ERROR) << "getline failed"; + + free(line); + check_and_fclose(log_fp, filename); + close(pipefd[0]); + _exit(EXIT_FAILURE); + } else { + // Redirect stdout/stderr to the logger process. Close the unused read end. + close(pipefd[0]); + + setbuf(stdout, nullptr); + setbuf(stderr, nullptr); + + if (dup2(pipefd[1], STDOUT_FILENO) == -1) { + PLOG(ERROR) << "dup2 stdout failed"; + } + if (dup2(pipefd[1], STDERR_FILENO) == -1) { + PLOG(ERROR) << "dup2 stderr failed"; + } + + close(pipefd[1]); + } +} + +int main(int argc, char** argv) { + // We don't have logcat yet under recovery; so we'll print error on screen and log to stdout + // (which is redirected to recovery.log) as we used to do. + android::base::InitLogging(argv, &UiLogger); + + // Take last pmsg contents and rewrite it to the current pmsg session. + static constexpr const char filter[] = "recovery/"; + // Do we need to rotate? + bool do_rotate = false; + + __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logbasename, &do_rotate); + // Take action to refresh pmsg contents + __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logrotate, &do_rotate); + + // If this binary is started with the single argument "--adbd", instead of being the normal + // recovery binary, it turns into kind of a stripped-down version of adbd that only supports the + // 'sideload' command. Note this must be a real argument, not anything in the command file or + // bootloader control block; the only way recovery should be run with this argument is when it + // starts a copy of itself from the apply_from_adb() function. + if (argc == 2 && strcmp(argv[1], "--adbd") == 0) { + minadbd_main(); + return 0; + } + + // redirect_stdio should be called only in non-sideload mode. Otherwise we may have two logger + // instances with different timestamps. + redirect_stdio(Paths::Get().temporary_log_file().c_str()); + + return start_recovery(argc, argv); +} -- cgit v1.2.3