blob: 9f579f7cdeeaa5cad627f8ef206d5aada52fdd15 [file] [log] [blame]
Tao Bao6d99d4b2018-04-25 16:47:04 -07001/*
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 <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20
21#include <chrono>
22
23#include <android-base/logging.h>
24#include <private/android_logger.h> /* private pmsg functions */
25
26#include "common.h"
27#include "minadbd/minadbd.h"
28#include "otautil/paths.h"
29#include "private/recovery.h"
30#include "rotate_logs.h"
31#include "ui.h"
32
33static void UiLogger(android::base::LogId /* id */, android::base::LogSeverity severity,
34 const char* /* tag */, const char* /* file */, unsigned int /* line */,
35 const char* message) {
36 static constexpr char log_characters[] = "VDIWEF";
37 if (severity >= android::base::ERROR && ui != nullptr) {
38 ui->Print("E:%s\n", message);
39 } else {
40 fprintf(stdout, "%c:%s\n", log_characters[severity], message);
41 }
42}
43
44static void redirect_stdio(const char* filename) {
45 int pipefd[2];
46 if (pipe(pipefd) == -1) {
47 PLOG(ERROR) << "pipe failed";
48
49 // Fall back to traditional logging mode without timestamps. If these fail, there's not really
50 // anywhere to complain...
51 freopen(filename, "a", stdout);
52 setbuf(stdout, nullptr);
53 freopen(filename, "a", stderr);
54 setbuf(stderr, nullptr);
55
56 return;
57 }
58
59 pid_t pid = fork();
60 if (pid == -1) {
61 PLOG(ERROR) << "fork failed";
62
63 // Fall back to traditional logging mode without timestamps. If these fail, there's not really
64 // anywhere to complain...
65 freopen(filename, "a", stdout);
66 setbuf(stdout, nullptr);
67 freopen(filename, "a", stderr);
68 setbuf(stderr, nullptr);
69
70 return;
71 }
72
73 if (pid == 0) {
74 /// Close the unused write end.
75 close(pipefd[1]);
76
77 auto start = std::chrono::steady_clock::now();
78
79 // Child logger to actually write to the log file.
80 FILE* log_fp = fopen(filename, "ae");
81 if (log_fp == nullptr) {
82 PLOG(ERROR) << "fopen \"" << filename << "\" failed";
83 close(pipefd[0]);
84 _exit(EXIT_FAILURE);
85 }
86
87 FILE* pipe_fp = fdopen(pipefd[0], "r");
88 if (pipe_fp == nullptr) {
89 PLOG(ERROR) << "fdopen failed";
90 check_and_fclose(log_fp, filename);
91 close(pipefd[0]);
92 _exit(EXIT_FAILURE);
93 }
94
95 char* line = nullptr;
96 size_t len = 0;
97 while (getline(&line, &len, pipe_fp) != -1) {
98 auto now = std::chrono::steady_clock::now();
99 double duration =
100 std::chrono::duration_cast<std::chrono::duration<double>>(now - start).count();
101 if (line[0] == '\n') {
102 fprintf(log_fp, "[%12.6lf]\n", duration);
103 } else {
104 fprintf(log_fp, "[%12.6lf] %s", duration, line);
105 }
106 fflush(log_fp);
107 }
108
109 PLOG(ERROR) << "getline failed";
110
111 free(line);
112 check_and_fclose(log_fp, filename);
113 close(pipefd[0]);
114 _exit(EXIT_FAILURE);
115 } else {
116 // Redirect stdout/stderr to the logger process. Close the unused read end.
117 close(pipefd[0]);
118
119 setbuf(stdout, nullptr);
120 setbuf(stderr, nullptr);
121
122 if (dup2(pipefd[1], STDOUT_FILENO) == -1) {
123 PLOG(ERROR) << "dup2 stdout failed";
124 }
125 if (dup2(pipefd[1], STDERR_FILENO) == -1) {
126 PLOG(ERROR) << "dup2 stderr failed";
127 }
128
129 close(pipefd[1]);
130 }
131}
132
133int main(int argc, char** argv) {
134 // We don't have logcat yet under recovery; so we'll print error on screen and log to stdout
135 // (which is redirected to recovery.log) as we used to do.
136 android::base::InitLogging(argv, &UiLogger);
137
138 // Take last pmsg contents and rewrite it to the current pmsg session.
139 static constexpr const char filter[] = "recovery/";
140 // Do we need to rotate?
141 bool do_rotate = false;
142
143 __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logbasename, &do_rotate);
144 // Take action to refresh pmsg contents
145 __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logrotate, &do_rotate);
146
147 // If this binary is started with the single argument "--adbd", instead of being the normal
148 // recovery binary, it turns into kind of a stripped-down version of adbd that only supports the
149 // 'sideload' command. Note this must be a real argument, not anything in the command file or
150 // bootloader control block; the only way recovery should be run with this argument is when it
151 // starts a copy of itself from the apply_from_adb() function.
152 if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
153 minadbd_main();
154 return 0;
155 }
156
157 // redirect_stdio should be called only in non-sideload mode. Otherwise we may have two logger
158 // instances with different timestamps.
159 redirect_stdio(Paths::Get().temporary_log_file().c_str());
160
161 return start_recovery(argc, argv);
162}