blob: 74c4d3ad16c05cbeca4b1821ffea449964fe30bd [file] [log] [blame]
bigbiff1f9e4842020-10-31 11:33:15 -04001/*
2 * Copyright (C) 2012 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 "twinstall/adb_install.h"
18
19#include <errno.h>
20#include <fcntl.h>
21#include <signal.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/epoll.h>
25#include <sys/socket.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28#include <sys/wait.h>
29#include <unistd.h>
30
31#include <atomic>
32#include <functional>
33#include <map>
34#include <utility>
35#include <vector>
36
37#include <android-base/file.h>
38#include <android-base/logging.h>
39#include <android-base/memory.h>
40#include <android-base/properties.h>
41#include <android-base/strings.h>
42#include <android-base/unique_fd.h>
43
44#include "fuse_sideload.h"
45#include "twinstall/install.h"
46#include "twinstall/wipe_data.h"
bigbiff673c7ae2020-12-02 19:44:56 -050047#include "minadbd/types.h"
bigbiff1f9e4842020-10-31 11:33:15 -040048#include "otautil/sysutil.h"
49#include "recovery_ui/device.h"
50#include "recovery_ui/ui.h"
51
52// A CommandFunction returns a pair of (result, should_continue), which indicates the command
53// execution result and whether it should proceed to the next iteration. The execution result will
54// always be sent to the minadbd side.
55using CommandFunction = std::function<std::pair<bool, bool>()>;
56
57pid_t child;
58
59pid_t GetMiniAdbdPid() {
60 return child;
61}
62
63static bool SetUsbConfig(const std::string& state) {
64 android::base::SetProperty("sys.usb.config", state);
65 return android::base::WaitForProperty("sys.usb.state", state);
66}
67
68// Parses the minadbd command in |message|; returns MinadbdCommand::kError upon errors.
69static MinadbdCommand ParseMinadbdCommand(const std::string& message) {
70 if (!android::base::StartsWith(message, kMinadbdCommandPrefix)) {
71 LOG(ERROR) << "Failed to parse command in message " << message;
72 return MinadbdCommand::kError;
73 }
74
75 auto cmd_code_string = message.substr(strlen(kMinadbdCommandPrefix));
76 auto cmd_code = android::base::get_unaligned<uint32_t>(cmd_code_string.c_str());
77 if (cmd_code >= static_cast<uint32_t>(MinadbdCommand::kError)) {
78 LOG(ERROR) << "Unsupported command code: " << cmd_code;
79 return MinadbdCommand::kError;
80 }
81
82 return static_cast<MinadbdCommand>(cmd_code);
83}
84
85static bool WriteStatusToFd(MinadbdCommandStatus status, int fd) {
86 char message[kMinadbdMessageSize];
87 memcpy(message, kMinadbdStatusPrefix, strlen(kMinadbdStatusPrefix));
88 android::base::put_unaligned(message + strlen(kMinadbdStatusPrefix), status);
89
90 if (!android::base::WriteFully(fd, message, kMinadbdMessageSize)) {
91 PLOG(ERROR) << "Failed to write message " << message;
92 return false;
93 }
94 return true;
95}
96
97// Installs the package from FUSE. Returns the installation result and whether it should continue
98// waiting for new commands.
99static auto AdbInstallPackageHandler(int* result) {
100 // How long (in seconds) we wait for the package path to be ready. It doesn't need to be too long
101 // because the minadbd service has already issued an install command. FUSE_SIDELOAD_HOST_PATHNAME
102 // will start to exist once the host connects and starts serving a package. Poll for its
103 // appearance. (Note that inotify doesn't work with FUSE.)
104 constexpr int ADB_INSTALL_TIMEOUT = 15;
105 bool should_continue = true;
106 *result = INSTALL_ERROR;
107 for (int i = 0; i < ADB_INSTALL_TIMEOUT; ++i) {
108 PLOG(ERROR) << "i: " << i;
109 struct stat st;
110 if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) {
111 if (errno == ENOENT && i < ADB_INSTALL_TIMEOUT - 1) {
112 sleep(1);
113 continue;
114 } else {
115 should_continue = false;
116 break;
117 }
118 }
119 *result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0);
120 break;
121 }
122
123 // Calling stat() on this magic filename signals the FUSE to exit.
124 struct stat st;
125 stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st);
126 return std::make_pair(*result == INSTALL_SUCCESS, should_continue);
127}
128
129static auto AdbRebootHandler(MinadbdCommand command, int* result,
130 Device::BuiltinAction* reboot_action) {
131 // Use Device::REBOOT_{FASTBOOT,RECOVERY,RESCUE}, instead of the ones with ENTER_. This allows
132 // rebooting back into fastboot/recovery/rescue mode through bootloader, which may use a newly
133 // installed bootloader/recovery image.
134 switch (command) {
135 case MinadbdCommand::kRebootBootloader:
136 *reboot_action = Device::REBOOT_BOOTLOADER;
137 break;
138 case MinadbdCommand::kRebootFastboot:
139 *reboot_action = Device::REBOOT_FASTBOOT;
140 break;
141 case MinadbdCommand::kRebootRecovery:
142 *reboot_action = Device::REBOOT_RECOVERY;
143 break;
144 case MinadbdCommand::kRebootRescue:
145 *reboot_action = Device::REBOOT_RESCUE;
146 break;
147 case MinadbdCommand::kRebootAndroid:
148 default:
149 *reboot_action = Device::REBOOT;
150 break;
151 }
152 *result = INSTALL_REBOOT;
153 return std::make_pair(true, false);
154}
155
156// Parses and executes the command from minadbd. Returns whether the caller should keep waiting for
157// next command.
158static bool HandleMessageFromMinadbd(int socket_fd,
159 const std::map<MinadbdCommand, CommandFunction>& command_map) {
160 char buffer[kMinadbdMessageSize];
161 if (!android::base::ReadFully(socket_fd, buffer, kMinadbdMessageSize)) {
162 PLOG(ERROR) << "Failed to read message from minadbd";
163 return false;
164 }
165
166 std::string message(buffer, buffer + kMinadbdMessageSize);
167 auto command_type = ParseMinadbdCommand(message);
168 if (command_type == MinadbdCommand::kError) {
169 return false;
170 }
171 if (command_map.find(command_type) == command_map.end()) {
172 LOG(ERROR) << "Unsupported command: "
173 << android::base::get_unaligned<unsigned int>(
174 message.substr(strlen(kMinadbdCommandPrefix)).c_str());
175 return false;
176 }
177
178 // We have received a valid command, execute the corresponding function.
179 const auto& command_func = command_map.at(command_type);
180 const auto [result, should_continue] = command_func();
181 LOG(INFO) << "Command " << static_cast<uint32_t>(command_type) << " finished with " << result;
182 if (!WriteStatusToFd(result ? MinadbdCommandStatus::kSuccess : MinadbdCommandStatus::kFailure,
183 socket_fd)) {
184 return false;
185 }
186 return should_continue;
187}
188
189// TODO(xunchang) add a wrapper function and kill the minadbd service there.
190static void ListenAndExecuteMinadbdCommands(
191 pid_t minadbd_pid, android::base::unique_fd&& socket_fd,
192 const std::map<MinadbdCommand, CommandFunction>& command_map) {
193 android::base::unique_fd epoll_fd(epoll_create1(O_CLOEXEC));
194 if (epoll_fd == -1) {
195 PLOG(ERROR) << "Failed to create epoll";
196 kill(minadbd_pid, SIGKILL);
197 return;
198 }
199
200 constexpr int EPOLL_MAX_EVENTS = 10;
201 struct epoll_event ev = {};
202 ev.events = EPOLLIN | EPOLLHUP;
203 ev.data.fd = socket_fd.get();
204 struct epoll_event events[EPOLL_MAX_EVENTS];
205 if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, socket_fd.get(), &ev) == -1) {
206 PLOG(ERROR) << "Failed to add socket fd to epoll";
207 kill(minadbd_pid, SIGKILL);
208 return;
209 }
210
211 // Set the timeout to be 300s when waiting for minadbd commands.
212 constexpr int TIMEOUT_MILLIS = 300 * 1000;
213 while (true) {
214 // Poll for the status change of the socket_fd, and handle the message if the fd is ready to
215 // read.
216 int event_count =
217 TEMP_FAILURE_RETRY(epoll_wait(epoll_fd.get(), events, EPOLL_MAX_EVENTS, TIMEOUT_MILLIS));
218 if (event_count == -1) {
219 PLOG(ERROR) << "Failed to wait for epoll events";
220 kill(minadbd_pid, SIGKILL);
221 return;
222 }
223 if (event_count == 0) {
224 LOG(ERROR) << "Timeout waiting for messages from minadbd";
225 kill(minadbd_pid, SIGKILL);
226 return;
227 }
228
229 for (int n = 0; n < event_count; n++) {
230 if (events[n].events & EPOLLHUP) {
231 LOG(INFO) << "Socket has been closed";
232 kill(minadbd_pid, SIGKILL);
233 return;
234 }
235 if (!HandleMessageFromMinadbd(socket_fd.get(), command_map)) {
236 kill(minadbd_pid, SIGKILL);
237 return;
238 }
239 }
240 }
241}
242
243// Recovery starts minadbd service as a child process, and spawns another thread to listen for the
244// message from minadbd through a socket pair. Here is an example to execute one command from adb
245// host.
246// a. recovery b. listener thread c. minadbd service
247//
248// a1. create socket pair
249// a2. fork minadbd service
250// c3. wait for the adb commands
251// from host
252// c4. after receiving host commands:
253// 1) set up pre-condition (i.e.
254// start fuse for adb sideload)
255// 2) issue command through
256// socket.
257// 3) wait for result
258// a5. start listener thread
259// b6. listen for message from
260// minadbd in a loop.
261// b7. After receiving a minadbd
262// command from socket
263// 1) execute the command function
264// 2) send the result back to
265// minadbd
266// ......
267// c8. exit upon receiving the
268// result
269// a9. wait for listener thread
270// to exit.
271//
272// a10. wait for minadbd to
273// exit
274// b11. exit the listening loop
275//
276static void CreateMinadbdServiceAndExecuteCommands(
277 const std::map<MinadbdCommand, CommandFunction>& command_map,
278 bool rescue_mode __unused, std::string install_file __unused) {
279 signal(SIGPIPE, SIG_IGN);
280
281 android::base::unique_fd recovery_socket;
282 android::base::unique_fd minadbd_socket;
283 if (!android::base::Socketpair(AF_UNIX, SOCK_STREAM, 0, &recovery_socket, &minadbd_socket)) {
284 PLOG(ERROR) << "Failed to create socket";
285 return;
286 }
287
288 child = fork();
289 if (child == -1) {
290 PLOG(ERROR) << "Failed to fork child process";
291 return;
292 }
293 if (child == 0) {
294 recovery_socket.reset();
295 std::vector<std::string> minadbd_commands = {
296 "/system/bin/minadbd",
297 "--socket_fd",
298 std::to_string(minadbd_socket.release()),
299 };
300 // if (rescue_mode) {
301 // minadbd_commands.push_back("--rescue");
302 // }
303 auto exec_args = StringVectorToNullTerminatedArray(minadbd_commands);
304 execv(exec_args[0], exec_args.data());
305 _exit(EXIT_FAILURE);
306 }
307
308 minadbd_socket.reset();
309
310 // We need to call SetUsbConfig() after forking minadbd service. Because the function waits for
311 // the usb state to be updated, which depends on sys.usb.ffs.ready=1 set in the adb daemon.
312 if (!SetUsbConfig("sideload")) {
313 LOG(ERROR) << "Failed to set usb config to sideload";
314 return;
315 }
316
317 std::thread listener_thread(ListenAndExecuteMinadbdCommands, child,
318 std::move(recovery_socket), std::ref(command_map));
319 if (listener_thread.joinable()) {
320 listener_thread.join();
321 }
322
323 int status;
324 waitpid(child, &status, 0);
325 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
326 if (WEXITSTATUS(status) == MinadbdErrorCode::kMinadbdAdbVersionError) {
327 LOG(ERROR) << "\nYou need adb 1.0.32 or newer to sideload\nto this device.\n";
328 } else if (!WIFSIGNALED(status)) {
329 LOG(ERROR) << "\n(adbd status " << WEXITSTATUS(status) << ")";
330 }
331 }
332
333 signal(SIGPIPE, SIG_DFL);
334}
335
336 int twrp_sideload(const char* install_file, Device::BuiltinAction* reboot_action) {
337
338 // Save the usb state to restore after the sideload operation.
339 std::string usb_state = android::base::GetProperty("sys.usb.state", "none");
340 // Clean up state and stop adbd.
341 if (usb_state != "none" && !SetUsbConfig("none")) {
342 LOG(ERROR) << "Failed to clear USB config";
343 return INSTALL_ERROR;
344 }
345
346 int install_result = INSTALL_ERROR;
347 std::map<MinadbdCommand, CommandFunction> command_map{
348 { MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, &install_result) },
349 { MinadbdCommand::kRebootAndroid, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootAndroid,
350 &install_result, reboot_action) },
351 { MinadbdCommand::kRebootBootloader,
352 std::bind(&AdbRebootHandler, MinadbdCommand::kRebootBootloader, &install_result,
353 reboot_action) },
354 { MinadbdCommand::kRebootFastboot, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootFastboot,
355 &install_result, reboot_action) },
356 { MinadbdCommand::kRebootRecovery, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootRecovery,
357 &install_result, reboot_action) },
358 { MinadbdCommand::kRebootRescue,
359 std::bind(&AdbRebootHandler, MinadbdCommand::kRebootRescue, &install_result, reboot_action) },
360};
361
362 CreateMinadbdServiceAndExecuteCommands(command_map, false, install_file);
363
364 // Clean up before switching to the older state, for example setting the state
365 // to none sets sys/class/android_usb/android0/enable to 0.
366 if (!SetUsbConfig("none")) {
367 LOG(ERROR) << "Failed to clear USB config";
368 }
369
370 if (usb_state != "none") {
371 if (!SetUsbConfig(usb_state)) {
372 LOG(ERROR) << "Failed to set USB config to " << usb_state;
373 }
374 }
375
376 return install_result;
377}