blob: cabcdaa093461976444a30f831b5d5f015f72a29 [file] [log] [blame]
Doug Zongker9270a202012-01-09 15:16:13 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
xunchang34690ce2019-04-05 16:16:07 -070017#include "minadbd_services.h"
18
Doug Zongker9270a202012-01-09 15:16:13 -080019#include <errno.h>
Dan Albert8f6eb5c2015-02-24 22:07:18 -080020#include <inttypes.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
Doug Zongker9270a202012-01-09 15:16:13 -080025
Josh Gao038c4a12018-07-27 11:18:30 -070026#include <functional>
xunchang5e6832a2019-03-15 16:04:32 -070027#include <memory>
Tao Baod8db81a2019-06-04 11:20:00 -070028#include <set>
Tianjie Xu6af51a02017-04-19 14:00:52 -070029#include <string>
Tao Bao5de19e22019-01-02 09:35:59 -080030#include <string_view>
Josh Gao2aa0d3a2017-04-13 12:45:55 -070031#include <thread>
32
xunchang34690ce2019-04-05 16:16:07 -070033#include <android-base/file.h>
34#include <android-base/logging.h>
35#include <android-base/memory.h>
Tao Baoed717ca2019-04-04 18:37:58 -070036#include <android-base/parseint.h>
37#include <android-base/properties.h>
xunchang34690ce2019-04-05 16:16:07 -070038#include <android-base/stringprintf.h>
39#include <android-base/strings.h>
40
Doug Zongker9270a202012-01-09 15:16:13 -080041#include "adb.h"
Josh Gao038c4a12018-07-27 11:18:30 -070042#include "adb_unique_fd.h"
Tao Baoed717ca2019-04-04 18:37:58 -070043#include "adb_utils.h"
Dan Albert8f6eb5c2015-02-24 22:07:18 -080044#include "fuse_adb_provider.h"
xunchang5e6832a2019-03-15 16:04:32 -070045#include "fuse_sideload.h"
Tao Bao3305d482019-09-26 00:02:29 -070046#include "minadbd/types.h"
Josh Gao038c4a12018-07-27 11:18:30 -070047#include "services.h"
Elliott Hughes24eb8a02016-06-15 15:12:17 -070048#include "sysdeps.h"
Doug Zongker9270a202012-01-09 15:16:13 -080049
xunchang34690ce2019-04-05 16:16:07 -070050static int minadbd_socket = -1;
Tao Baoc6dc3252019-04-16 14:22:25 -070051static bool rescue_mode = false;
xunchang9c04eb42019-04-17 14:43:58 -070052static std::string sideload_mount_point = FUSE_SIDELOAD_HOST_MOUNTPOINT;
Tao Baoc6dc3252019-04-16 14:22:25 -070053
xunchang34690ce2019-04-05 16:16:07 -070054void SetMinadbdSocketFd(int socket_fd) {
55 minadbd_socket = socket_fd;
56}
57
Tao Baoc6dc3252019-04-16 14:22:25 -070058void SetMinadbdRescueMode(bool rescue) {
59 rescue_mode = rescue;
60}
61
xunchang9c04eb42019-04-17 14:43:58 -070062void SetSideloadMountPoint(const std::string& path) {
63 sideload_mount_point = path;
64}
65
Tao Bao10f441a2019-04-19 15:22:15 -070066static bool WriteCommandToFd(MinadbdCommand cmd, int fd) {
xunchang34690ce2019-04-05 16:16:07 -070067 char message[kMinadbdMessageSize];
68 memcpy(message, kMinadbdCommandPrefix, strlen(kMinadbdStatusPrefix));
69 android::base::put_unaligned(message + strlen(kMinadbdStatusPrefix), cmd);
70
71 if (!android::base::WriteFully(fd, message, kMinadbdMessageSize)) {
72 PLOG(ERROR) << "Failed to write message " << message;
73 return false;
74 }
75 return true;
76}
77
78// Blocks and reads the command status from |fd|. Returns false if the received message has a
79// format error.
80static bool WaitForCommandStatus(int fd, MinadbdCommandStatus* status) {
81 char buffer[kMinadbdMessageSize];
82 if (!android::base::ReadFully(fd, buffer, kMinadbdMessageSize)) {
83 PLOG(ERROR) << "Failed to response status from socket";
84 exit(kMinadbdSocketIOError);
85 }
86
87 std::string message(buffer, buffer + kMinadbdMessageSize);
88 if (!android::base::StartsWith(message, kMinadbdStatusPrefix)) {
89 LOG(ERROR) << "Failed to parse status in " << message;
90 return false;
91 }
92
93 *status = android::base::get_unaligned<MinadbdCommandStatus>(
94 message.substr(strlen(kMinadbdStatusPrefix)).c_str());
95 return true;
96}
97
Tao Baoed717ca2019-04-04 18:37:58 -070098static MinadbdErrorCode RunAdbFuseSideload(int sfd, const std::string& args,
99 MinadbdCommandStatus* status) {
100 auto pieces = android::base::Split(args, ":");
katao77d61732018-09-20 20:34:05 +0800101 int64_t file_size;
102 int block_size;
Tao Baoed717ca2019-04-04 18:37:58 -0700103 if (pieces.size() != 2 || !android::base::ParseInt(pieces[0], &file_size) || file_size <= 0 ||
104 !android::base::ParseInt(pieces[1], &block_size) || block_size <= 0) {
xunchang34690ce2019-04-05 16:16:07 -0700105 LOG(ERROR) << "bad sideload-host arguments: " << args;
xunchangfedeef62019-04-22 12:18:14 -0700106 return kMinadbdHostCommandArgumentError;
katao77d61732018-09-20 20:34:05 +0800107 }
Doug Zongker9270a202012-01-09 15:16:13 -0800108
xunchang34690ce2019-04-05 16:16:07 -0700109 LOG(INFO) << "sideload-host file size " << file_size << ", block size " << block_size;
110
Tao Bao10f441a2019-04-19 15:22:15 -0700111 if (!WriteCommandToFd(MinadbdCommand::kInstall, minadbd_socket)) {
Tao Baoed717ca2019-04-04 18:37:58 -0700112 return kMinadbdSocketIOError;
xunchang34690ce2019-04-05 16:16:07 -0700113 }
Doug Zongker9270a202012-01-09 15:16:13 -0800114
Tao Bao2be97372019-04-15 12:45:50 -0700115 auto adb_data_reader = std::make_unique<FuseAdbDataProvider>(sfd, file_size, block_size);
xunchang9c04eb42019-04-17 14:43:58 -0700116 if (int result = run_fuse_sideload(std::move(adb_data_reader), sideload_mount_point.c_str());
117 result != 0) {
xunchang34690ce2019-04-05 16:16:07 -0700118 LOG(ERROR) << "Failed to start fuse";
Tao Baoed717ca2019-04-04 18:37:58 -0700119 return kMinadbdFuseStartError;
xunchang34690ce2019-04-05 16:16:07 -0700120 }
Doug Zongker9270a202012-01-09 15:16:13 -0800121
Tao Baoed717ca2019-04-04 18:37:58 -0700122 if (!WaitForCommandStatus(minadbd_socket, status)) {
123 return kMinadbdMessageFormatError;
124 }
125
xunchangfedeef62019-04-22 12:18:14 -0700126 // Signal host-side adb to stop. For sideload mode, we always send kMinadbdServicesExitSuccess
Tao Baoed717ca2019-04-04 18:37:58 -0700127 // (i.e. "DONEDONE") regardless of the install result. For rescue mode, we send failure message on
128 // install error.
129 if (!rescue_mode || *status == MinadbdCommandStatus::kSuccess) {
xunchangfedeef62019-04-22 12:18:14 -0700130 if (!android::base::WriteFully(sfd, kMinadbdServicesExitSuccess,
131 strlen(kMinadbdServicesExitSuccess))) {
Tao Baoed717ca2019-04-04 18:37:58 -0700132 return kMinadbdHostSocketIOError;
133 }
134 } else {
xunchangfedeef62019-04-22 12:18:14 -0700135 if (!android::base::WriteFully(sfd, kMinadbdServicesExitFailure,
136 strlen(kMinadbdServicesExitFailure))) {
Tao Baoed717ca2019-04-04 18:37:58 -0700137 return kMinadbdHostSocketIOError;
138 }
139 }
140
141 return kMinadbdSuccess;
142}
143
144// Sideload service always exits after serving an install command.
145static void SideloadHostService(unique_fd sfd, const std::string& args) {
xunchang34690ce2019-04-05 16:16:07 -0700146 MinadbdCommandStatus status;
Tao Baoed717ca2019-04-04 18:37:58 -0700147 exit(RunAdbFuseSideload(sfd.get(), args, &status));
148}
xunchang34690ce2019-04-05 16:16:07 -0700149
Tao Baoed717ca2019-04-04 18:37:58 -0700150// Rescue service waits for the next command after an install command.
151static void RescueInstallHostService(unique_fd sfd, const std::string& args) {
152 MinadbdCommandStatus status;
153 if (auto result = RunAdbFuseSideload(sfd.get(), args, &status); result != kMinadbdSuccess) {
154 exit(result);
155 }
156}
157
Tao Bao57a27892019-06-10 12:41:44 -0700158// Answers the query on a given property |prop|, by writing the result to the given |sfd|. The
159// result will be newline-terminated, so nonexistent or nonallowed query will be answered with "\n".
160// If given an empty string, dumps all the supported properties (analogous to `adb shell getprop`)
161// in lines, e.g. "[prop]: [value]".
Tao Baoed717ca2019-04-04 18:37:58 -0700162static void RescueGetpropHostService(unique_fd sfd, const std::string& prop) {
Tao Baod8db81a2019-06-04 11:20:00 -0700163 static const std::set<std::string> kGetpropAllowedProps = {
Tao Baoed717ca2019-04-04 18:37:58 -0700164 "ro.build.date.utc",
Tao Bao3b9ef342019-06-03 12:10:54 -0700165 "ro.build.fingerprint",
166 "ro.build.flavor",
167 "ro.build.id",
168 "ro.build.product",
169 "ro.build.tags",
170 "ro.build.version.incremental",
171 "ro.product.device",
172 "ro.product.vendor.device",
Tao Baoed717ca2019-04-04 18:37:58 -0700173 };
Tao Baod8db81a2019-06-04 11:20:00 -0700174 std::string result;
175 if (prop.empty()) {
176 for (const auto& key : kGetpropAllowedProps) {
177 auto value = android::base::GetProperty(key, "");
178 if (value.empty()) {
179 continue;
180 }
181 result += "[" + key + "]: [" + value + "]\n";
182 }
Tao Bao57a27892019-06-10 12:41:44 -0700183 } else if (kGetpropAllowedProps.find(prop) != kGetpropAllowedProps.end()) {
184 result = android::base::GetProperty(prop, "") + "\n";
Tao Baod8db81a2019-06-04 11:20:00 -0700185 }
Tao Baoed717ca2019-04-04 18:37:58 -0700186 if (result.empty()) {
Tao Bao57a27892019-06-10 12:41:44 -0700187 result = "\n";
Tao Baoed717ca2019-04-04 18:37:58 -0700188 }
189 if (!android::base::WriteFully(sfd, result.data(), result.size())) {
190 exit(kMinadbdHostSocketIOError);
191 }
Tao Bao2223e6a2019-07-08 18:07:22 -0700192
193 // Send heartbeat signal to keep the rescue service alive.
194 if (!WriteCommandToFd(MinadbdCommand::kNoOp, minadbd_socket)) {
195 exit(kMinadbdSocketIOError);
196 }
197 if (MinadbdCommandStatus status; !WaitForCommandStatus(minadbd_socket, &status)) {
198 exit(kMinadbdMessageFormatError);
199 }
Doug Zongker9270a202012-01-09 15:16:13 -0800200}
201
Tao Bao10f441a2019-04-19 15:22:15 -0700202// Reboots into the given target. We don't reboot directly from minadbd, but going through recovery
203// instead. This allows recovery to finish all the pending works (clear BCB, save logs etc) before
204// the reboot.
205static void RebootHostService(unique_fd /* sfd */, const std::string& target) {
206 MinadbdCommand command;
207 if (target == "bootloader") {
208 command = MinadbdCommand::kRebootBootloader;
209 } else if (target == "rescue") {
210 command = MinadbdCommand::kRebootRescue;
211 } else if (target == "recovery") {
212 command = MinadbdCommand::kRebootRecovery;
213 } else if (target == "fastboot") {
214 command = MinadbdCommand::kRebootFastboot;
215 } else {
216 command = MinadbdCommand::kRebootAndroid;
217 }
218 if (!WriteCommandToFd(command, minadbd_socket)) {
219 exit(kMinadbdSocketIOError);
220 }
221 MinadbdCommandStatus status;
222 if (!WaitForCommandStatus(minadbd_socket, &status)) {
223 exit(kMinadbdMessageFormatError);
224 }
225}
226
xunchangfedeef62019-04-22 12:18:14 -0700227static void WipeDeviceService(unique_fd fd, const std::string& args) {
228 auto pieces = android::base::Split(args, ":");
229 if (pieces.size() != 2 || pieces[0] != "userdata") {
230 LOG(ERROR) << "Failed to parse wipe device command arguments " << args;
231 exit(kMinadbdHostCommandArgumentError);
232 }
233
234 size_t message_size;
235 if (!android::base::ParseUint(pieces[1], &message_size) ||
236 message_size < strlen(kMinadbdServicesExitSuccess)) {
237 LOG(ERROR) << "Failed to parse wipe device message size in " << args;
238 exit(kMinadbdHostCommandArgumentError);
239 }
240
241 WriteCommandToFd(MinadbdCommand::kWipeData, minadbd_socket);
242 MinadbdCommandStatus status;
243 if (!WaitForCommandStatus(minadbd_socket, &status)) {
244 exit(kMinadbdMessageFormatError);
245 }
246
247 std::string response = (status == MinadbdCommandStatus::kSuccess) ? kMinadbdServicesExitSuccess
248 : kMinadbdServicesExitFailure;
249 response += std::string(message_size - response.size(), '\0');
250 if (!android::base::WriteFully(fd, response.c_str(), response.size())) {
251 exit(kMinadbdHostSocketIOError);
252 }
253}
254
Tao Bao5de19e22019-01-02 09:35:59 -0800255unique_fd daemon_service_to_fd(std::string_view name, atransport* /* transport */) {
Tao Bao10f441a2019-04-19 15:22:15 -0700256 // Common services that are supported both in sideload and rescue modes.
Elliott Hughes93838f62019-05-03 10:33:04 -0700257 if (android::base::ConsumePrefix(&name, "reboot:")) {
Tao Bao10f441a2019-04-19 15:22:15 -0700258 // "reboot:<target>", where target must be one of the following.
259 std::string args(name);
260 if (args.empty() || args == "bootloader" || args == "rescue" || args == "recovery" ||
261 args == "fastboot") {
262 return create_service_thread("reboot",
263 std::bind(RebootHostService, std::placeholders::_1, args));
264 }
265 return unique_fd{};
266 }
267
268 // Rescue-specific services.
Tao Baoed717ca2019-04-04 18:37:58 -0700269 if (rescue_mode) {
Elliott Hughes93838f62019-05-03 10:33:04 -0700270 if (android::base::ConsumePrefix(&name, "rescue-install:")) {
Tao Baoed717ca2019-04-04 18:37:58 -0700271 // rescue-install:<file-size>:<block-size>
272 std::string args(name);
273 return create_service_thread(
274 "rescue-install", std::bind(RescueInstallHostService, std::placeholders::_1, args));
Elliott Hughes93838f62019-05-03 10:33:04 -0700275 } else if (android::base::ConsumePrefix(&name, "rescue-getprop:")) {
Tao Baoed717ca2019-04-04 18:37:58 -0700276 // rescue-getprop:<prop>
277 std::string args(name);
278 return create_service_thread(
279 "rescue-getprop", std::bind(RescueGetpropHostService, std::placeholders::_1, args));
Elliott Hughes93838f62019-05-03 10:33:04 -0700280 } else if (android::base::ConsumePrefix(&name, "rescue-wipe:")) {
xunchangfedeef62019-04-22 12:18:14 -0700281 // rescue-wipe:target:<message-size>
282 std::string args(name);
283 return create_service_thread("rescue-wipe",
284 std::bind(WipeDeviceService, std::placeholders::_1, args));
Tao Baoed717ca2019-04-04 18:37:58 -0700285 }
xunchangfedeef62019-04-22 12:18:14 -0700286
Tao Baoed717ca2019-04-04 18:37:58 -0700287 return unique_fd{};
288 }
289
Tao Bao10f441a2019-04-19 15:22:15 -0700290 // Sideload-specific services.
Tao Bao5de19e22019-01-02 09:35:59 -0800291 if (name.starts_with("sideload:")) {
292 // This exit status causes recovery to print a special error message saying to use a newer adb
293 // (that supports sideload-host).
xunchang34690ce2019-04-05 16:16:07 -0700294 exit(kMinadbdAdbVersionError);
Elliott Hughes93838f62019-05-03 10:33:04 -0700295 } else if (android::base::ConsumePrefix(&name, "sideload-host:")) {
Tao Baoed717ca2019-04-04 18:37:58 -0700296 // sideload-host:<file-size>:<block-size>
297 std::string args(name);
Josh Gao038c4a12018-07-27 11:18:30 -0700298 return create_service_thread("sideload-host",
Tao Baoed717ca2019-04-04 18:37:58 -0700299 std::bind(SideloadHostService, std::placeholders::_1, args));
Tao Bao99f0d9e2016-10-13 12:46:38 -0700300 }
Josh Gao038c4a12018-07-27 11:18:30 -0700301 return unique_fd{};
Doug Zongker9270a202012-01-09 15:16:13 -0800302}