xref: /aosp_15_r20/bootable/recovery/minadbd/minadbd_services.cpp (revision e7c364b630b241adcb6c7726a21055250b91fdac)
1*e7c364b6SAndroid Build Coastguard Worker /*
2*e7c364b6SAndroid Build Coastguard Worker  * Copyright (C) 2007 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 "minadbd_services.h"
18*e7c364b6SAndroid Build Coastguard Worker 
19*e7c364b6SAndroid Build Coastguard Worker #include <errno.h>
20*e7c364b6SAndroid Build Coastguard Worker #include <inttypes.h>
21*e7c364b6SAndroid Build Coastguard Worker #include <stdio.h>
22*e7c364b6SAndroid Build Coastguard Worker #include <stdlib.h>
23*e7c364b6SAndroid Build Coastguard Worker #include <string.h>
24*e7c364b6SAndroid Build Coastguard Worker #include <unistd.h>
25*e7c364b6SAndroid Build Coastguard Worker 
26*e7c364b6SAndroid Build Coastguard Worker #include <chrono>
27*e7c364b6SAndroid Build Coastguard Worker #include <functional>
28*e7c364b6SAndroid Build Coastguard Worker #include <memory>
29*e7c364b6SAndroid Build Coastguard Worker #include <set>
30*e7c364b6SAndroid Build Coastguard Worker #include <string>
31*e7c364b6SAndroid Build Coastguard Worker #include <string_view>
32*e7c364b6SAndroid Build Coastguard Worker #include <thread>
33*e7c364b6SAndroid Build Coastguard Worker 
34*e7c364b6SAndroid Build Coastguard Worker #include <android-base/file.h>
35*e7c364b6SAndroid Build Coastguard Worker #include <android-base/logging.h>
36*e7c364b6SAndroid Build Coastguard Worker #include <android-base/memory.h>
37*e7c364b6SAndroid Build Coastguard Worker #include <android-base/parseint.h>
38*e7c364b6SAndroid Build Coastguard Worker #include <android-base/properties.h>
39*e7c364b6SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
40*e7c364b6SAndroid Build Coastguard Worker #include <android-base/strings.h>
41*e7c364b6SAndroid Build Coastguard Worker 
42*e7c364b6SAndroid Build Coastguard Worker #include "adb.h"
43*e7c364b6SAndroid Build Coastguard Worker #include "adb_unique_fd.h"
44*e7c364b6SAndroid Build Coastguard Worker #include "adb_utils.h"
45*e7c364b6SAndroid Build Coastguard Worker #include "fuse_adb_provider.h"
46*e7c364b6SAndroid Build Coastguard Worker #include "fuse_sideload.h"
47*e7c364b6SAndroid Build Coastguard Worker #include "minadbd/types.h"
48*e7c364b6SAndroid Build Coastguard Worker #include "recovery_utils/battery_utils.h"
49*e7c364b6SAndroid Build Coastguard Worker #include "services.h"
50*e7c364b6SAndroid Build Coastguard Worker #include "sysdeps.h"
51*e7c364b6SAndroid Build Coastguard Worker 
52*e7c364b6SAndroid Build Coastguard Worker static int minadbd_socket = -1;
53*e7c364b6SAndroid Build Coastguard Worker static bool rescue_mode = false;
54*e7c364b6SAndroid Build Coastguard Worker static std::string sideload_mount_point = FUSE_SIDELOAD_HOST_MOUNTPOINT;
55*e7c364b6SAndroid Build Coastguard Worker 
SetMinadbdSocketFd(int socket_fd)56*e7c364b6SAndroid Build Coastguard Worker void SetMinadbdSocketFd(int socket_fd) {
57*e7c364b6SAndroid Build Coastguard Worker   minadbd_socket = socket_fd;
58*e7c364b6SAndroid Build Coastguard Worker }
59*e7c364b6SAndroid Build Coastguard Worker 
SetMinadbdRescueMode(bool rescue)60*e7c364b6SAndroid Build Coastguard Worker void SetMinadbdRescueMode(bool rescue) {
61*e7c364b6SAndroid Build Coastguard Worker   rescue_mode = rescue;
62*e7c364b6SAndroid Build Coastguard Worker }
63*e7c364b6SAndroid Build Coastguard Worker 
SetSideloadMountPoint(const std::string & path)64*e7c364b6SAndroid Build Coastguard Worker void SetSideloadMountPoint(const std::string& path) {
65*e7c364b6SAndroid Build Coastguard Worker   sideload_mount_point = path;
66*e7c364b6SAndroid Build Coastguard Worker }
67*e7c364b6SAndroid Build Coastguard Worker 
WriteCommandToFd(MinadbdCommand cmd,int fd)68*e7c364b6SAndroid Build Coastguard Worker static bool WriteCommandToFd(MinadbdCommand cmd, int fd) {
69*e7c364b6SAndroid Build Coastguard Worker   char message[kMinadbdMessageSize];
70*e7c364b6SAndroid Build Coastguard Worker   memcpy(message, kMinadbdCommandPrefix, strlen(kMinadbdStatusPrefix));
71*e7c364b6SAndroid Build Coastguard Worker   android::base::put_unaligned(message + strlen(kMinadbdStatusPrefix), cmd);
72*e7c364b6SAndroid Build Coastguard Worker 
73*e7c364b6SAndroid Build Coastguard Worker   if (!android::base::WriteFully(fd, message, kMinadbdMessageSize)) {
74*e7c364b6SAndroid Build Coastguard Worker     PLOG(ERROR) << "Failed to write message " << message;
75*e7c364b6SAndroid Build Coastguard Worker     return false;
76*e7c364b6SAndroid Build Coastguard Worker   }
77*e7c364b6SAndroid Build Coastguard Worker   return true;
78*e7c364b6SAndroid Build Coastguard Worker }
79*e7c364b6SAndroid Build Coastguard Worker 
80*e7c364b6SAndroid Build Coastguard Worker // Blocks and reads the command status from |fd|. Returns false if the received message has a
81*e7c364b6SAndroid Build Coastguard Worker // format error.
WaitForCommandStatus(int fd,MinadbdCommandStatus * status)82*e7c364b6SAndroid Build Coastguard Worker static bool WaitForCommandStatus(int fd, MinadbdCommandStatus* status) {
83*e7c364b6SAndroid Build Coastguard Worker   char buffer[kMinadbdMessageSize];
84*e7c364b6SAndroid Build Coastguard Worker   if (!android::base::ReadFully(fd, buffer, kMinadbdMessageSize)) {
85*e7c364b6SAndroid Build Coastguard Worker     PLOG(ERROR) << "Failed to response status from socket";
86*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdSocketIOError);
87*e7c364b6SAndroid Build Coastguard Worker   }
88*e7c364b6SAndroid Build Coastguard Worker 
89*e7c364b6SAndroid Build Coastguard Worker   std::string message(buffer, buffer + kMinadbdMessageSize);
90*e7c364b6SAndroid Build Coastguard Worker   if (!android::base::StartsWith(message, kMinadbdStatusPrefix)) {
91*e7c364b6SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to parse status in " << message;
92*e7c364b6SAndroid Build Coastguard Worker     return false;
93*e7c364b6SAndroid Build Coastguard Worker   }
94*e7c364b6SAndroid Build Coastguard Worker 
95*e7c364b6SAndroid Build Coastguard Worker   *status = android::base::get_unaligned<MinadbdCommandStatus>(
96*e7c364b6SAndroid Build Coastguard Worker       message.substr(strlen(kMinadbdStatusPrefix)).c_str());
97*e7c364b6SAndroid Build Coastguard Worker   return true;
98*e7c364b6SAndroid Build Coastguard Worker }
99*e7c364b6SAndroid Build Coastguard Worker 
RunAdbFuseSideload(int sfd,const std::string & args,MinadbdCommandStatus * status)100*e7c364b6SAndroid Build Coastguard Worker static MinadbdErrorCode RunAdbFuseSideload(int sfd, const std::string& args,
101*e7c364b6SAndroid Build Coastguard Worker                                            MinadbdCommandStatus* status) {
102*e7c364b6SAndroid Build Coastguard Worker   auto pieces = android::base::Split(args, ":");
103*e7c364b6SAndroid Build Coastguard Worker   int64_t file_size;
104*e7c364b6SAndroid Build Coastguard Worker   int block_size;
105*e7c364b6SAndroid Build Coastguard Worker   if (pieces.size() != 2 || !android::base::ParseInt(pieces[0], &file_size) || file_size <= 0 ||
106*e7c364b6SAndroid Build Coastguard Worker       !android::base::ParseInt(pieces[1], &block_size) || block_size <= 0) {
107*e7c364b6SAndroid Build Coastguard Worker     LOG(ERROR) << "bad sideload-host arguments: " << args;
108*e7c364b6SAndroid Build Coastguard Worker     return kMinadbdHostCommandArgumentError;
109*e7c364b6SAndroid Build Coastguard Worker   }
110*e7c364b6SAndroid Build Coastguard Worker 
111*e7c364b6SAndroid Build Coastguard Worker   LOG(INFO) << "sideload-host file size " << file_size << ", block size " << block_size;
112*e7c364b6SAndroid Build Coastguard Worker 
113*e7c364b6SAndroid Build Coastguard Worker   if (!WriteCommandToFd(MinadbdCommand::kInstall, minadbd_socket)) {
114*e7c364b6SAndroid Build Coastguard Worker     return kMinadbdSocketIOError;
115*e7c364b6SAndroid Build Coastguard Worker   }
116*e7c364b6SAndroid Build Coastguard Worker 
117*e7c364b6SAndroid Build Coastguard Worker   auto adb_data_reader = std::make_unique<FuseAdbDataProvider>(sfd, file_size, block_size);
118*e7c364b6SAndroid Build Coastguard Worker   if (int result = run_fuse_sideload(std::move(adb_data_reader), sideload_mount_point.c_str());
119*e7c364b6SAndroid Build Coastguard Worker       result != 0) {
120*e7c364b6SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to start fuse";
121*e7c364b6SAndroid Build Coastguard Worker     return kMinadbdFuseStartError;
122*e7c364b6SAndroid Build Coastguard Worker   }
123*e7c364b6SAndroid Build Coastguard Worker 
124*e7c364b6SAndroid Build Coastguard Worker   if (!WaitForCommandStatus(minadbd_socket, status)) {
125*e7c364b6SAndroid Build Coastguard Worker     return kMinadbdMessageFormatError;
126*e7c364b6SAndroid Build Coastguard Worker   }
127*e7c364b6SAndroid Build Coastguard Worker 
128*e7c364b6SAndroid Build Coastguard Worker   // Signal host-side adb to stop. For sideload mode, we always send kMinadbdServicesExitSuccess
129*e7c364b6SAndroid Build Coastguard Worker   // (i.e. "DONEDONE") regardless of the install result. For rescue mode, we send failure message on
130*e7c364b6SAndroid Build Coastguard Worker   // install error.
131*e7c364b6SAndroid Build Coastguard Worker   if (!rescue_mode || *status == MinadbdCommandStatus::kSuccess) {
132*e7c364b6SAndroid Build Coastguard Worker     if (!android::base::WriteFully(sfd, kMinadbdServicesExitSuccess,
133*e7c364b6SAndroid Build Coastguard Worker                                    strlen(kMinadbdServicesExitSuccess))) {
134*e7c364b6SAndroid Build Coastguard Worker       return kMinadbdHostSocketIOError;
135*e7c364b6SAndroid Build Coastguard Worker     }
136*e7c364b6SAndroid Build Coastguard Worker   } else {
137*e7c364b6SAndroid Build Coastguard Worker     if (!android::base::WriteFully(sfd, kMinadbdServicesExitFailure,
138*e7c364b6SAndroid Build Coastguard Worker                                    strlen(kMinadbdServicesExitFailure))) {
139*e7c364b6SAndroid Build Coastguard Worker       return kMinadbdHostSocketIOError;
140*e7c364b6SAndroid Build Coastguard Worker     }
141*e7c364b6SAndroid Build Coastguard Worker   }
142*e7c364b6SAndroid Build Coastguard Worker 
143*e7c364b6SAndroid Build Coastguard Worker   return kMinadbdSuccess;
144*e7c364b6SAndroid Build Coastguard Worker }
145*e7c364b6SAndroid Build Coastguard Worker 
WaitForSocketClose(int fd,std::chrono::milliseconds timeout)146*e7c364b6SAndroid Build Coastguard Worker static bool WaitForSocketClose(int fd, std::chrono::milliseconds timeout) {
147*e7c364b6SAndroid Build Coastguard Worker   const auto begin = std::chrono::steady_clock::now();
148*e7c364b6SAndroid Build Coastguard Worker   const auto end = begin + timeout;
149*e7c364b6SAndroid Build Coastguard Worker   while (std::chrono::steady_clock::now() < end) {
150*e7c364b6SAndroid Build Coastguard Worker     // We don't care about reading the socket, we just want to wait until
151*e7c364b6SAndroid Build Coastguard Worker     // socket closes. In this case .events = 0 will tell the kernel to wait
152*e7c364b6SAndroid Build Coastguard Worker     // for close events.
153*e7c364b6SAndroid Build Coastguard Worker     struct pollfd pfd = { .fd = fd, .events = 0 };
154*e7c364b6SAndroid Build Coastguard Worker     auto timeout_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
155*e7c364b6SAndroid Build Coastguard Worker                           end - std::chrono::steady_clock::now())
156*e7c364b6SAndroid Build Coastguard Worker                           .count();
157*e7c364b6SAndroid Build Coastguard Worker     int rc = TEMP_FAILURE_RETRY(adb_poll(&pfd, 1, timeout_ms));
158*e7c364b6SAndroid Build Coastguard Worker     if (rc == 1) {
159*e7c364b6SAndroid Build Coastguard Worker       LOG(INFO) << "revents: " << pfd.revents;
160*e7c364b6SAndroid Build Coastguard Worker       if (pfd.revents & (POLLHUP | POLLRDHUP)) {
161*e7c364b6SAndroid Build Coastguard Worker         return true;
162*e7c364b6SAndroid Build Coastguard Worker       }
163*e7c364b6SAndroid Build Coastguard Worker     } else {
164*e7c364b6SAndroid Build Coastguard Worker       PLOG(ERROR) << "poll() failed";
165*e7c364b6SAndroid Build Coastguard Worker       // poll failed, almost definitely due to timeout
166*e7c364b6SAndroid Build Coastguard Worker       // If not, you're screwed anyway, because it probably means the kernel ran
167*e7c364b6SAndroid Build Coastguard Worker       // out of memory.
168*e7c364b6SAndroid Build Coastguard Worker       return false;
169*e7c364b6SAndroid Build Coastguard Worker     }
170*e7c364b6SAndroid Build Coastguard Worker   }
171*e7c364b6SAndroid Build Coastguard Worker   return false;
172*e7c364b6SAndroid Build Coastguard Worker }
173*e7c364b6SAndroid Build Coastguard Worker 
174*e7c364b6SAndroid Build Coastguard Worker // Sideload service always exits after serving an install command.
SideloadHostService(unique_fd sfd,const std::string & args)175*e7c364b6SAndroid Build Coastguard Worker static void SideloadHostService(unique_fd sfd, const std::string& args) {
176*e7c364b6SAndroid Build Coastguard Worker   using namespace std::chrono_literals;
177*e7c364b6SAndroid Build Coastguard Worker   MinadbdCommandStatus status;
178*e7c364b6SAndroid Build Coastguard Worker   auto error = RunAdbFuseSideload(sfd.get(), args, &status);
179*e7c364b6SAndroid Build Coastguard Worker   // No need to wait if the socket is already closed, meaning the other end
180*e7c364b6SAndroid Build Coastguard Worker   // already exited for some reason.
181*e7c364b6SAndroid Build Coastguard Worker   if (error != kMinadbdHostSocketIOError) {
182*e7c364b6SAndroid Build Coastguard Worker     // We sleep for a little bit just to wait for the host to receive last
183*e7c364b6SAndroid Build Coastguard Worker     // "DONEDONE" message. However minadbd process is likely to get terminated
184*e7c364b6SAndroid Build Coastguard Worker     // early due to exit_on_close
185*e7c364b6SAndroid Build Coastguard Worker     WaitForSocketClose(sfd, 3000ms);
186*e7c364b6SAndroid Build Coastguard Worker   }
187*e7c364b6SAndroid Build Coastguard Worker   exit(error);
188*e7c364b6SAndroid Build Coastguard Worker }
189*e7c364b6SAndroid Build Coastguard Worker 
190*e7c364b6SAndroid Build Coastguard Worker // Rescue service waits for the next command after an install command.
RescueInstallHostService(unique_fd sfd,const std::string & args)191*e7c364b6SAndroid Build Coastguard Worker static void RescueInstallHostService(unique_fd sfd, const std::string& args) {
192*e7c364b6SAndroid Build Coastguard Worker   MinadbdCommandStatus status;
193*e7c364b6SAndroid Build Coastguard Worker   if (auto result = RunAdbFuseSideload(sfd.get(), args, &status); result != kMinadbdSuccess) {
194*e7c364b6SAndroid Build Coastguard Worker     exit(result);
195*e7c364b6SAndroid Build Coastguard Worker   }
196*e7c364b6SAndroid Build Coastguard Worker }
197*e7c364b6SAndroid Build Coastguard Worker 
198*e7c364b6SAndroid Build Coastguard Worker // Answers the query on a given property |prop|, by writing the result to the given |sfd|. The
199*e7c364b6SAndroid Build Coastguard Worker // result will be newline-terminated, so nonexistent or nonallowed query will be answered with "\n".
200*e7c364b6SAndroid Build Coastguard Worker // If given an empty string, dumps all the supported properties (analogous to `adb shell getprop`)
201*e7c364b6SAndroid Build Coastguard Worker // in lines, e.g. "[prop]: [value]".
RescueGetpropHostService(unique_fd sfd,const std::string & prop)202*e7c364b6SAndroid Build Coastguard Worker static void RescueGetpropHostService(unique_fd sfd, const std::string& prop) {
203*e7c364b6SAndroid Build Coastguard Worker   constexpr const char* kRescueBatteryLevelProp = "rescue.battery_level";
204*e7c364b6SAndroid Build Coastguard Worker   static const std::set<std::string> kGetpropAllowedProps = {
205*e7c364b6SAndroid Build Coastguard Worker     // clang-format off
206*e7c364b6SAndroid Build Coastguard Worker     kRescueBatteryLevelProp,
207*e7c364b6SAndroid Build Coastguard Worker     "ro.build.date.utc",
208*e7c364b6SAndroid Build Coastguard Worker     "ro.build.fingerprint",
209*e7c364b6SAndroid Build Coastguard Worker     "ro.build.flavor",
210*e7c364b6SAndroid Build Coastguard Worker     "ro.build.id",
211*e7c364b6SAndroid Build Coastguard Worker     "ro.build.product",
212*e7c364b6SAndroid Build Coastguard Worker     "ro.build.tags",
213*e7c364b6SAndroid Build Coastguard Worker     "ro.build.version.incremental",
214*e7c364b6SAndroid Build Coastguard Worker     "ro.product.device",
215*e7c364b6SAndroid Build Coastguard Worker     "ro.product.vendor.device",
216*e7c364b6SAndroid Build Coastguard Worker     // clang-format on
217*e7c364b6SAndroid Build Coastguard Worker   };
218*e7c364b6SAndroid Build Coastguard Worker 
219*e7c364b6SAndroid Build Coastguard Worker   auto query_prop = [](const std::string& key) {
220*e7c364b6SAndroid Build Coastguard Worker     if (key == kRescueBatteryLevelProp) {
221*e7c364b6SAndroid Build Coastguard Worker       auto battery_info = GetBatteryInfo();
222*e7c364b6SAndroid Build Coastguard Worker       return std::to_string(battery_info.capacity);
223*e7c364b6SAndroid Build Coastguard Worker     }
224*e7c364b6SAndroid Build Coastguard Worker     return android::base::GetProperty(key, "");
225*e7c364b6SAndroid Build Coastguard Worker   };
226*e7c364b6SAndroid Build Coastguard Worker 
227*e7c364b6SAndroid Build Coastguard Worker   std::string result;
228*e7c364b6SAndroid Build Coastguard Worker   if (prop.empty()) {
229*e7c364b6SAndroid Build Coastguard Worker     for (const auto& key : kGetpropAllowedProps) {
230*e7c364b6SAndroid Build Coastguard Worker       auto value = query_prop(key);
231*e7c364b6SAndroid Build Coastguard Worker       if (value.empty()) {
232*e7c364b6SAndroid Build Coastguard Worker         continue;
233*e7c364b6SAndroid Build Coastguard Worker       }
234*e7c364b6SAndroid Build Coastguard Worker       result += "[" + key + "]: [" + value + "]\n";
235*e7c364b6SAndroid Build Coastguard Worker     }
236*e7c364b6SAndroid Build Coastguard Worker   } else if (kGetpropAllowedProps.contains(prop)) {
237*e7c364b6SAndroid Build Coastguard Worker     result = query_prop(prop) + "\n";
238*e7c364b6SAndroid Build Coastguard Worker   }
239*e7c364b6SAndroid Build Coastguard Worker   if (result.empty()) {
240*e7c364b6SAndroid Build Coastguard Worker     result = "\n";
241*e7c364b6SAndroid Build Coastguard Worker   }
242*e7c364b6SAndroid Build Coastguard Worker   if (!android::base::WriteFully(sfd, result.data(), result.size())) {
243*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdHostSocketIOError);
244*e7c364b6SAndroid Build Coastguard Worker   }
245*e7c364b6SAndroid Build Coastguard Worker 
246*e7c364b6SAndroid Build Coastguard Worker   // Send heartbeat signal to keep the rescue service alive.
247*e7c364b6SAndroid Build Coastguard Worker   if (!WriteCommandToFd(MinadbdCommand::kNoOp, minadbd_socket)) {
248*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdSocketIOError);
249*e7c364b6SAndroid Build Coastguard Worker   }
250*e7c364b6SAndroid Build Coastguard Worker   if (MinadbdCommandStatus status; !WaitForCommandStatus(minadbd_socket, &status)) {
251*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdMessageFormatError);
252*e7c364b6SAndroid Build Coastguard Worker   }
253*e7c364b6SAndroid Build Coastguard Worker }
254*e7c364b6SAndroid Build Coastguard Worker 
255*e7c364b6SAndroid Build Coastguard Worker // Reboots into the given target. We don't reboot directly from minadbd, but going through recovery
256*e7c364b6SAndroid Build Coastguard Worker // instead. This allows recovery to finish all the pending works (clear BCB, save logs etc) before
257*e7c364b6SAndroid Build Coastguard Worker // the reboot.
RebootHostService(unique_fd,const std::string & target)258*e7c364b6SAndroid Build Coastguard Worker static void RebootHostService(unique_fd /* sfd */, const std::string& target) {
259*e7c364b6SAndroid Build Coastguard Worker   MinadbdCommand command;
260*e7c364b6SAndroid Build Coastguard Worker   if (target == "bootloader") {
261*e7c364b6SAndroid Build Coastguard Worker     command = MinadbdCommand::kRebootBootloader;
262*e7c364b6SAndroid Build Coastguard Worker   } else if (target == "rescue") {
263*e7c364b6SAndroid Build Coastguard Worker     command = MinadbdCommand::kRebootRescue;
264*e7c364b6SAndroid Build Coastguard Worker   } else if (target == "recovery") {
265*e7c364b6SAndroid Build Coastguard Worker     command = MinadbdCommand::kRebootRecovery;
266*e7c364b6SAndroid Build Coastguard Worker   } else if (target == "fastboot") {
267*e7c364b6SAndroid Build Coastguard Worker     command = MinadbdCommand::kRebootFastboot;
268*e7c364b6SAndroid Build Coastguard Worker   } else {
269*e7c364b6SAndroid Build Coastguard Worker     command = MinadbdCommand::kRebootAndroid;
270*e7c364b6SAndroid Build Coastguard Worker   }
271*e7c364b6SAndroid Build Coastguard Worker   if (!WriteCommandToFd(command, minadbd_socket)) {
272*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdSocketIOError);
273*e7c364b6SAndroid Build Coastguard Worker   }
274*e7c364b6SAndroid Build Coastguard Worker   MinadbdCommandStatus status;
275*e7c364b6SAndroid Build Coastguard Worker   if (!WaitForCommandStatus(minadbd_socket, &status)) {
276*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdMessageFormatError);
277*e7c364b6SAndroid Build Coastguard Worker   }
278*e7c364b6SAndroid Build Coastguard Worker }
279*e7c364b6SAndroid Build Coastguard Worker 
WipeDeviceService(unique_fd fd,const std::string & args)280*e7c364b6SAndroid Build Coastguard Worker static void WipeDeviceService(unique_fd fd, const std::string& args) {
281*e7c364b6SAndroid Build Coastguard Worker   auto pieces = android::base::Split(args, ":");
282*e7c364b6SAndroid Build Coastguard Worker   if (pieces.size() != 2 || pieces[0] != "userdata") {
283*e7c364b6SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to parse wipe device command arguments " << args;
284*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdHostCommandArgumentError);
285*e7c364b6SAndroid Build Coastguard Worker   }
286*e7c364b6SAndroid Build Coastguard Worker 
287*e7c364b6SAndroid Build Coastguard Worker   size_t message_size;
288*e7c364b6SAndroid Build Coastguard Worker   if (!android::base::ParseUint(pieces[1], &message_size) ||
289*e7c364b6SAndroid Build Coastguard Worker       message_size < strlen(kMinadbdServicesExitSuccess)) {
290*e7c364b6SAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to parse wipe device message size in " << args;
291*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdHostCommandArgumentError);
292*e7c364b6SAndroid Build Coastguard Worker   }
293*e7c364b6SAndroid Build Coastguard Worker 
294*e7c364b6SAndroid Build Coastguard Worker   WriteCommandToFd(MinadbdCommand::kWipeData, minadbd_socket);
295*e7c364b6SAndroid Build Coastguard Worker   MinadbdCommandStatus status;
296*e7c364b6SAndroid Build Coastguard Worker   if (!WaitForCommandStatus(minadbd_socket, &status)) {
297*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdMessageFormatError);
298*e7c364b6SAndroid Build Coastguard Worker   }
299*e7c364b6SAndroid Build Coastguard Worker 
300*e7c364b6SAndroid Build Coastguard Worker   std::string response = (status == MinadbdCommandStatus::kSuccess) ? kMinadbdServicesExitSuccess
301*e7c364b6SAndroid Build Coastguard Worker                                                                     : kMinadbdServicesExitFailure;
302*e7c364b6SAndroid Build Coastguard Worker   response += std::string(message_size - response.size(), '\0');
303*e7c364b6SAndroid Build Coastguard Worker   if (!android::base::WriteFully(fd, response.c_str(), response.size())) {
304*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdHostSocketIOError);
305*e7c364b6SAndroid Build Coastguard Worker   }
306*e7c364b6SAndroid Build Coastguard Worker }
307*e7c364b6SAndroid Build Coastguard Worker 
daemon_service_to_socket(std::string_view,atransport *)308*e7c364b6SAndroid Build Coastguard Worker asocket* daemon_service_to_socket(std::string_view, atransport*) {
309*e7c364b6SAndroid Build Coastguard Worker   return nullptr;
310*e7c364b6SAndroid Build Coastguard Worker }
311*e7c364b6SAndroid Build Coastguard Worker 
daemon_service_to_fd(std::string_view name,atransport *)312*e7c364b6SAndroid Build Coastguard Worker unique_fd daemon_service_to_fd(std::string_view name, atransport* /* transport */) {
313*e7c364b6SAndroid Build Coastguard Worker   // Common services that are supported both in sideload and rescue modes.
314*e7c364b6SAndroid Build Coastguard Worker   if (android::base::ConsumePrefix(&name, "reboot:")) {
315*e7c364b6SAndroid Build Coastguard Worker     // "reboot:<target>", where target must be one of the following.
316*e7c364b6SAndroid Build Coastguard Worker     std::string args(name);
317*e7c364b6SAndroid Build Coastguard Worker     if (args.empty() || args == "bootloader" || args == "rescue" || args == "recovery" ||
318*e7c364b6SAndroid Build Coastguard Worker         args == "fastboot") {
319*e7c364b6SAndroid Build Coastguard Worker       return create_service_thread("reboot",
320*e7c364b6SAndroid Build Coastguard Worker                                    std::bind(RebootHostService, std::placeholders::_1, args));
321*e7c364b6SAndroid Build Coastguard Worker     }
322*e7c364b6SAndroid Build Coastguard Worker     return unique_fd{};
323*e7c364b6SAndroid Build Coastguard Worker   }
324*e7c364b6SAndroid Build Coastguard Worker 
325*e7c364b6SAndroid Build Coastguard Worker   // Rescue-specific services.
326*e7c364b6SAndroid Build Coastguard Worker   if (rescue_mode) {
327*e7c364b6SAndroid Build Coastguard Worker     if (android::base::ConsumePrefix(&name, "rescue-install:")) {
328*e7c364b6SAndroid Build Coastguard Worker       // rescue-install:<file-size>:<block-size>
329*e7c364b6SAndroid Build Coastguard Worker       std::string args(name);
330*e7c364b6SAndroid Build Coastguard Worker       return create_service_thread(
331*e7c364b6SAndroid Build Coastguard Worker           "rescue-install", std::bind(RescueInstallHostService, std::placeholders::_1, args));
332*e7c364b6SAndroid Build Coastguard Worker     } else if (android::base::ConsumePrefix(&name, "rescue-getprop:")) {
333*e7c364b6SAndroid Build Coastguard Worker       // rescue-getprop:<prop>
334*e7c364b6SAndroid Build Coastguard Worker       std::string args(name);
335*e7c364b6SAndroid Build Coastguard Worker       return create_service_thread(
336*e7c364b6SAndroid Build Coastguard Worker           "rescue-getprop", std::bind(RescueGetpropHostService, std::placeholders::_1, args));
337*e7c364b6SAndroid Build Coastguard Worker     } else if (android::base::ConsumePrefix(&name, "rescue-wipe:")) {
338*e7c364b6SAndroid Build Coastguard Worker       // rescue-wipe:target:<message-size>
339*e7c364b6SAndroid Build Coastguard Worker       std::string args(name);
340*e7c364b6SAndroid Build Coastguard Worker       return create_service_thread("rescue-wipe",
341*e7c364b6SAndroid Build Coastguard Worker                                    std::bind(WipeDeviceService, std::placeholders::_1, args));
342*e7c364b6SAndroid Build Coastguard Worker     }
343*e7c364b6SAndroid Build Coastguard Worker 
344*e7c364b6SAndroid Build Coastguard Worker     return unique_fd{};
345*e7c364b6SAndroid Build Coastguard Worker   }
346*e7c364b6SAndroid Build Coastguard Worker 
347*e7c364b6SAndroid Build Coastguard Worker   // Sideload-specific services.
348*e7c364b6SAndroid Build Coastguard Worker   if (name.starts_with("sideload:")) {
349*e7c364b6SAndroid Build Coastguard Worker     // This exit status causes recovery to print a special error message saying to use a newer adb
350*e7c364b6SAndroid Build Coastguard Worker     // (that supports sideload-host).
351*e7c364b6SAndroid Build Coastguard Worker     exit(kMinadbdAdbVersionError);
352*e7c364b6SAndroid Build Coastguard Worker   } else if (android::base::ConsumePrefix(&name, "sideload-host:")) {
353*e7c364b6SAndroid Build Coastguard Worker     // sideload-host:<file-size>:<block-size>
354*e7c364b6SAndroid Build Coastguard Worker     std::string args(name);
355*e7c364b6SAndroid Build Coastguard Worker     return create_service_thread("sideload-host",
356*e7c364b6SAndroid Build Coastguard Worker                                  std::bind(SideloadHostService, std::placeholders::_1, args));
357*e7c364b6SAndroid Build Coastguard Worker   }
358*e7c364b6SAndroid Build Coastguard Worker   return unique_fd{};
359*e7c364b6SAndroid Build Coastguard Worker }
360