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