xref: /aosp_15_r20/bootable/recovery/install/adb_install.cpp (revision e7c364b630b241adcb6c7726a21055250b91fdac)
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