blob: f430920a49f8e4e1883b47d7995aacc3ebcafe6f [file] [log] [blame]
Doug Zongker9270a202012-01-09 15:16:13 -08001/*
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
xunchang24788852019-03-22 16:08:52 -070017#include "install/adb_install.h"
Tao Bao0150d012017-05-01 11:31:28 -070018
Doug Zongker9270a202012-01-09 15:16:13 -080019#include <errno.h>
Tao Bao0150d012017-05-01 11:31:28 -070020#include <fcntl.h>
21#include <signal.h>
Doug Zongker9270a202012-01-09 15:16:13 -080022#include <stdlib.h>
23#include <string.h>
xunchang34690ce2019-04-05 16:16:07 -070024#include <sys/epoll.h>
25#include <sys/socket.h>
Tao Bao0150d012017-05-01 11:31:28 -070026#include <sys/stat.h>
Doug Zongker9270a202012-01-09 15:16:13 -080027#include <sys/types.h>
28#include <sys/wait.h>
Tao Bao0150d012017-05-01 11:31:28 -070029#include <unistd.h>
Doug Zongker9270a202012-01-09 15:16:13 -080030
xunchang34690ce2019-04-05 16:16:07 -070031#include <atomic>
32#include <functional>
33#include <map>
Tao Baoc6dc3252019-04-16 14:22:25 -070034#include <vector>
xunchang34690ce2019-04-05 16:16:07 -070035
36#include <android-base/file.h>
Tao Bao0167d4c2017-05-11 14:44:15 -070037#include <android-base/logging.h>
xunchang34690ce2019-04-05 16:16:07 -070038#include <android-base/memory.h>
Elliott Hughescb220402016-09-23 15:30:55 -070039#include <android-base/properties.h>
xunchang34690ce2019-04-05 16:16:07 -070040#include <android-base/strings.h>
41#include <android-base/unique_fd.h>
Elliott Hughescb220402016-09-23 15:30:55 -070042
Tao Bao0150d012017-05-01 11:31:28 -070043#include "fuse_sideload.h"
xunchang24788852019-03-22 16:08:52 -070044#include "install/install.h"
xunchang34690ce2019-04-05 16:16:07 -070045#include "minadbd_types.h"
Tao Baoc6dc3252019-04-16 14:22:25 -070046#include "otautil/sysutil.h"
Tianjie Xu8f397302018-08-20 13:40:47 -070047#include "recovery_ui/ui.h"
Tao Bao0150d012017-05-01 11:31:28 -070048
xunchang34690ce2019-04-05 16:16:07 -070049using CommandFunction = std::function<bool()>;
50
xunchang24788852019-03-22 16:08:52 -070051static bool SetUsbConfig(const std::string& state) {
52 android::base::SetProperty("sys.usb.config", state);
53 return android::base::WaitForProperty("sys.usb.state", state);
54}
55
xunchang34690ce2019-04-05 16:16:07 -070056// Parses the minadbd command in |message|; returns MinadbdCommands::kError upon errors.
57static MinadbdCommands ParseMinadbdCommands(const std::string& message) {
58 if (!android::base::StartsWith(message, kMinadbdCommandPrefix)) {
59 LOG(ERROR) << "Failed to parse command in message " << message;
60 return MinadbdCommands::kError;
61 }
62
63 auto cmd_code_string = message.substr(strlen(kMinadbdCommandPrefix));
64 auto cmd_code = android::base::get_unaligned<uint32_t>(cmd_code_string.c_str());
65 if (cmd_code >= static_cast<uint32_t>(MinadbdCommands::kError)) {
66 LOG(ERROR) << "Unsupported command code: " << cmd_code;
67 return MinadbdCommands::kError;
68 }
69
70 return static_cast<MinadbdCommands>(cmd_code);
71}
72
73static bool WriteStatusToFd(MinadbdCommandStatus status, int fd) {
74 char message[kMinadbdMessageSize];
75 memcpy(message, kMinadbdStatusPrefix, strlen(kMinadbdStatusPrefix));
76 android::base::put_unaligned(message + strlen(kMinadbdStatusPrefix), status);
77
78 if (!android::base::WriteFully(fd, message, kMinadbdMessageSize)) {
79 PLOG(ERROR) << "Failed to write message " << message;
80 return false;
81 }
82 return true;
83}
84
85// Installs the package from FUSE. Returns true if the installation succeeds, and false otherwise.
xunchang316e9712019-04-12 16:22:15 -070086static bool AdbInstallPackageHandler(RecoveryUI* ui, int* result) {
xunchang34690ce2019-04-05 16:16:07 -070087 // How long (in seconds) we wait for the package path to be ready. It doesn't need to be too long
88 // because the minadbd service has already issued an install command. FUSE_SIDELOAD_HOST_PATHNAME
89 // will start to exist once the host connects and starts serving a package. Poll for its
90 // appearance. (Note that inotify doesn't work with FUSE.)
91 constexpr int ADB_INSTALL_TIMEOUT = 15;
92 *result = INSTALL_ERROR;
93 for (int i = 0; i < ADB_INSTALL_TIMEOUT; ++i) {
94 struct stat st;
95 if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) {
96 if (errno == ENOENT && i < ADB_INSTALL_TIMEOUT - 1) {
97 sleep(1);
98 continue;
99 } else {
100 ui->Print("\nTimed out waiting for fuse to be ready.\n\n");
101 break;
102 }
103 }
xunchang316e9712019-04-12 16:22:15 -0700104 *result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0, ui);
xunchang34690ce2019-04-05 16:16:07 -0700105 break;
106 }
107
108 // Calling stat() on this magic filename signals the FUSE to exit.
109 struct stat st;
110 stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st);
111 return *result == INSTALL_SUCCESS;
112}
113
114// Parses and executes the command from minadbd. Returns false if we enter an invalid state so that
115// the caller can kill the minadbd service properly.
116static bool HandleMessageFromMinadbd(
117 int socket_fd, const std::map<MinadbdCommands, CommandFunction>& command_map) {
118 char buffer[kMinadbdMessageSize];
119 if (!android::base::ReadFully(socket_fd, buffer, kMinadbdMessageSize)) {
120 PLOG(ERROR) << "Failed to read message from minadbd";
121 return false;
122 }
123
124 std::string message(buffer, buffer + kMinadbdMessageSize);
125 auto command_type = ParseMinadbdCommands(message);
126 if (command_type == MinadbdCommands::kError) {
127 return false;
128 }
129 if (command_map.find(command_type) == command_map.end()) {
130 LOG(ERROR) << "Unsupported command: "
131 << android::base::get_unaligned<unsigned int>(
132 message.substr(strlen(kMinadbdCommandPrefix)).c_str());
133 return false;
134 }
135
136 // We have received a valid command, execute the corresponding function.
137 const auto& command_func = command_map.at(command_type);
138 if (!command_func()) {
139 LOG(ERROR) << "Failed to execute command " << static_cast<unsigned int>(command_type);
140 return WriteStatusToFd(MinadbdCommandStatus::kFailure, socket_fd);
141 }
142 return WriteStatusToFd(MinadbdCommandStatus::kSuccess, socket_fd);
143}
144
145// TODO(xunchang) add a wrapper function and kill the minadbd service there.
146static void ListenAndExecuteMinadbdCommands(
147 pid_t minadbd_pid, android::base::unique_fd&& socket_fd,
148 const std::map<MinadbdCommands, CommandFunction>& command_map) {
149 android::base::unique_fd epoll_fd(epoll_create1(O_CLOEXEC));
150 if (epoll_fd == -1) {
151 PLOG(ERROR) << "Failed to create epoll";
152 kill(minadbd_pid, SIGKILL);
153 return;
154 }
155
156 constexpr int EPOLL_MAX_EVENTS = 10;
157 struct epoll_event ev = {};
158 ev.events = EPOLLIN | EPOLLHUP;
159 ev.data.fd = socket_fd.get();
160 struct epoll_event events[EPOLL_MAX_EVENTS];
161 if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, socket_fd.get(), &ev) == -1) {
162 PLOG(ERROR) << "Failed to add socket fd to epoll";
163 kill(minadbd_pid, SIGKILL);
164 return;
165 }
166
167 // Set the timeout to be 300s when waiting for minadbd commands.
168 constexpr int TIMEOUT_MILLIS = 300 * 1000;
169 while (true) {
170 // Poll for the status change of the socket_fd, and handle the message if the fd is ready to
171 // read.
172 int event_count =
173 TEMP_FAILURE_RETRY(epoll_wait(epoll_fd.get(), events, EPOLL_MAX_EVENTS, TIMEOUT_MILLIS));
174 if (event_count == -1) {
175 PLOG(ERROR) << "Failed to wait for epoll events";
176 kill(minadbd_pid, SIGKILL);
177 return;
178 }
179 if (event_count == 0) {
180 LOG(ERROR) << "Timeout waiting for messages from minadbd";
181 kill(minadbd_pid, SIGKILL);
182 return;
183 }
184
185 for (int n = 0; n < event_count; n++) {
186 if (events[n].events & EPOLLHUP) {
187 LOG(INFO) << "Socket has been closed";
188 kill(minadbd_pid, SIGKILL);
189 return;
190 }
191 if (!HandleMessageFromMinadbd(socket_fd.get(), command_map)) {
192 kill(minadbd_pid, SIGKILL);
193 return;
194 }
195 }
196 }
197}
198
199// Recovery starts minadbd service as a child process, and spawns another thread to listen for the
200// message from minadbd through a socket pair. Here is an example to execute one command from adb
201// host.
202// a. recovery b. listener thread c. minadbd service
203//
204// a1. create socket pair
205// a2. fork minadbd service
206// c3. wait for the adb commands
207// from host
208// c4. after receiving host commands:
209// 1) set up pre-condition (i.e.
210// start fuse for adb sideload)
211// 2) issue command through
212// socket.
213// 3) wait for result
214// a5. start listener thread
215// b6. listen for message from
216// minadbd in a loop.
217// b7. After receiving a minadbd
218// command from socket
219// 1) execute the command function
220// 2) send the result back to
221// minadbd
222// ......
223// c8. exit upon receiving the
224// result
225// a9. wait for listener thread
226// to exit.
227//
228// a10. wait for minadbd to
229// exit
230// b11. exit the listening loop
231//
232static void CreateMinadbdServiceAndExecuteCommands(
Tao Baoc6dc3252019-04-16 14:22:25 -0700233 const std::map<MinadbdCommands, CommandFunction>& command_map, bool rescue_mode) {
xunchang34690ce2019-04-05 16:16:07 -0700234 signal(SIGPIPE, SIG_IGN);
235
236 android::base::unique_fd recovery_socket;
237 android::base::unique_fd minadbd_socket;
238 if (!android::base::Socketpair(AF_UNIX, SOCK_STREAM, 0, &recovery_socket, &minadbd_socket)) {
239 PLOG(ERROR) << "Failed to create socket";
240 return;
241 }
242
243 pid_t child = fork();
244 if (child == -1) {
245 PLOG(ERROR) << "Failed to fork child process";
246 return;
247 }
248 if (child == 0) {
249 recovery_socket.reset();
Tao Baoc6dc3252019-04-16 14:22:25 -0700250 std::vector<std::string> minadbd_commands = {
251 "/system/bin/minadbd",
252 "--socket_fd",
253 std::to_string(minadbd_socket.release()),
254 };
255 if (rescue_mode) {
256 minadbd_commands.push_back("--rescue");
257 }
258 auto exec_args = StringVectorToNullTerminatedArray(minadbd_commands);
259 execv(exec_args[0], exec_args.data());
xunchang34690ce2019-04-05 16:16:07 -0700260 _exit(EXIT_FAILURE);
261 }
262
263 minadbd_socket.reset();
264
265 // We need to call SetUsbConfig() after forking minadbd service. Because the function waits for
266 // the usb state to be updated, which depends on sys.usb.ffs.ready=1 set in the adb daemon.
267 if (!SetUsbConfig("sideload")) {
268 LOG(ERROR) << "Failed to set usb config to sideload";
269 return;
270 }
271
272 std::thread listener_thread(ListenAndExecuteMinadbdCommands, child, std::move(recovery_socket),
273 std::ref(command_map));
274
275 if (listener_thread.joinable()) {
276 listener_thread.join();
277 }
278
279 int status;
280 waitpid(child, &status, 0);
281 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
282 if (WEXITSTATUS(status) == MinadbdErrorCode::kMinadbdAdbVersionError) {
283 LOG(ERROR) << "\nYou need adb 1.0.32 or newer to sideload\nto this device.\n";
284 } else if (!WIFSIGNALED(status)) {
285 LOG(ERROR) << "\n(adbd status " << WEXITSTATUS(status) << ")";
286 }
287 }
288
289 signal(SIGPIPE, SIG_DFL);
290}
291
Tao Baoc6dc3252019-04-16 14:22:25 -0700292int ApplyFromAdb(RecoveryUI* ui, bool rescue_mode) {
Hridya Valsarajue4ef4532018-08-31 11:57:51 -0700293 // Save the usb state to restore after the sideload operation.
294 std::string usb_state = android::base::GetProperty("sys.usb.state", "none");
295 // Clean up state and stop adbd.
296 if (usb_state != "none" && !SetUsbConfig("none")) {
297 LOG(ERROR) << "Failed to clear USB config";
298 return INSTALL_ERROR;
299 }
Tao Bao682c34b2015-04-07 17:16:35 -0700300
Tao Baoc6dc3252019-04-16 14:22:25 -0700301 if (!rescue_mode) {
302 ui->Print(
303 "\n\nNow send the package you want to apply\n"
304 "to the device with \"adb sideload <filename>\"...\n");
305 } else {
306 ui->Print("\n\nWaiting for rescue commands...\n");
307 }
Doug Zongker9270a202012-01-09 15:16:13 -0800308
xunchang34690ce2019-04-05 16:16:07 -0700309 int install_result = INSTALL_ERROR;
310 std::map<MinadbdCommands, CommandFunction> command_map{
xunchang316e9712019-04-12 16:22:15 -0700311 { MinadbdCommands::kInstall, std::bind(&AdbInstallPackageHandler, ui, &install_result) },
xunchang34690ce2019-04-05 16:16:07 -0700312 };
Doug Zongker9270a202012-01-09 15:16:13 -0800313
Tao Baoc6dc3252019-04-16 14:22:25 -0700314 CreateMinadbdServiceAndExecuteCommands(command_map, rescue_mode);
Doug Zongker075ad802014-06-26 15:35:51 -0700315
Hridya Valsarajue4ef4532018-08-31 11:57:51 -0700316 // Clean up before switching to the older state, for example setting the state
317 // to none sets sys/class/android_usb/android0/enable to 0.
318 if (!SetUsbConfig("none")) {
319 LOG(ERROR) << "Failed to clear USB config";
320 }
321
322 if (usb_state != "none") {
323 if (!SetUsbConfig(usb_state)) {
324 LOG(ERROR) << "Failed to set USB config to " << usb_state;
325 }
326 }
Doug Zongker9270a202012-01-09 15:16:13 -0800327
xunchang34690ce2019-04-05 16:16:07 -0700328 return install_result;
Doug Zongker9270a202012-01-09 15:16:13 -0800329}