1 /*
2 * Copyright (C) 2018 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
17 #include "fastboot_device.h"
18
19 #include <algorithm>
20
21 #include <android-base/logging.h>
22 #include <android-base/properties.h>
23 #include <android-base/strings.h>
24 #include <android/hardware/boot/1.0/IBootControl.h>
25 #include <android/hardware/fastboot/1.1/IFastboot.h>
26 #include <fs_mgr.h>
27 #include <fs_mgr/roots.h>
28 #include <healthhalutils/HealthHalUtils.h>
29
30 #include "constants.h"
31 #include "flashing.h"
32 #include "tcp_client.h"
33 #include "usb_client.h"
34
35 using android::fs_mgr::EnsurePathUnmounted;
36 using android::fs_mgr::Fstab;
37 using ::android::hardware::hidl_string;
38 using ::android::hardware::boot::V1_0::IBootControl;
39 using ::android::hardware::boot::V1_0::Slot;
40 using ::android::hardware::fastboot::V1_1::IFastboot;
41 using ::android::hardware::health::V2_0::get_health_service;
42
43 namespace sph = std::placeholders;
44
FastbootDevice()45 FastbootDevice::FastbootDevice()
46 : kCommandMap({
47 {FB_CMD_SET_ACTIVE, SetActiveHandler},
48 {FB_CMD_DOWNLOAD, DownloadHandler},
49 {FB_CMD_GETVAR, GetVarHandler},
50 {FB_CMD_SHUTDOWN, ShutDownHandler},
51 {FB_CMD_REBOOT, RebootHandler},
52 {FB_CMD_REBOOT_BOOTLOADER, RebootBootloaderHandler},
53 {FB_CMD_REBOOT_FASTBOOT, RebootFastbootHandler},
54 {FB_CMD_REBOOT_RECOVERY, RebootRecoveryHandler},
55 {FB_CMD_ERASE, EraseHandler},
56 {FB_CMD_FLASH, FlashHandler},
57 {FB_CMD_CREATE_PARTITION, CreatePartitionHandler},
58 {FB_CMD_DELETE_PARTITION, DeletePartitionHandler},
59 {FB_CMD_RESIZE_PARTITION, ResizePartitionHandler},
60 {FB_CMD_UPDATE_SUPER, UpdateSuperHandler},
61 {FB_CMD_OEM, OemCmdHandler},
62 {FB_CMD_GSI, GsiHandler},
63 {FB_CMD_SNAPSHOT_UPDATE, SnapshotUpdateHandler},
64 {FB_CMD_FETCH, FetchHandler},
65 }),
66 boot_control_hal_(IBootControl::getService()),
67 health_hal_(get_health_service()),
68 fastboot_hal_(IFastboot::getService()),
69 active_slot_("") {
70 if (android::base::GetProperty("fastbootd.protocol", "usb") == "tcp") {
71 transport_ = std::make_unique<ClientTcpTransport>();
72 } else {
73 transport_ = std::make_unique<ClientUsbTransport>();
74 }
75
76 if (boot_control_hal_) {
77 boot1_1_ = android::hardware::boot::V1_1::IBootControl::castFrom(boot_control_hal_);
78 }
79
80 // Make sure cache is unmounted, since recovery will have mounted it for
81 // logging.
82 Fstab fstab;
83 if (ReadDefaultFstab(&fstab)) {
84 EnsurePathUnmounted(&fstab, "/cache");
85 }
86 }
87
~FastbootDevice()88 FastbootDevice::~FastbootDevice() {
89 CloseDevice();
90 }
91
CloseDevice()92 void FastbootDevice::CloseDevice() {
93 transport_->Close();
94 }
95
GetCurrentSlot()96 std::string FastbootDevice::GetCurrentSlot() {
97 // Check if a set_active ccommand was issued earlier since the boot control HAL
98 // returns the slot that is currently booted into.
99 if (!active_slot_.empty()) {
100 return active_slot_;
101 }
102 // Non-A/B devices must not have boot control HALs.
103 if (!boot_control_hal_) {
104 return "";
105 }
106 std::string suffix;
107 auto cb = [&suffix](hidl_string s) { suffix = s; };
108 boot_control_hal_->getSuffix(boot_control_hal_->getCurrentSlot(), cb);
109 return suffix;
110 }
111
WriteStatus(FastbootResult result,const std::string & message)112 bool FastbootDevice::WriteStatus(FastbootResult result, const std::string& message) {
113 constexpr size_t kResponseReasonSize = 4;
114 constexpr size_t kNumResponseTypes = 4; // "FAIL", "OKAY", "INFO", "DATA"
115
116 char buf[FB_RESPONSE_SZ];
117 constexpr size_t kMaxMessageSize = sizeof(buf) - kResponseReasonSize;
118 size_t msg_len = std::min(kMaxMessageSize, message.size());
119
120 constexpr const char* kResultStrings[kNumResponseTypes] = {RESPONSE_OKAY, RESPONSE_FAIL,
121 RESPONSE_INFO, RESPONSE_DATA};
122
123 if (static_cast<size_t>(result) >= kNumResponseTypes) {
124 return false;
125 }
126
127 memcpy(buf, kResultStrings[static_cast<size_t>(result)], kResponseReasonSize);
128 memcpy(buf + kResponseReasonSize, message.c_str(), msg_len);
129
130 size_t response_len = kResponseReasonSize + msg_len;
131 auto write_ret = this->get_transport()->Write(buf, response_len);
132 if (write_ret != static_cast<ssize_t>(response_len)) {
133 PLOG(ERROR) << "Failed to write " << message;
134 return false;
135 }
136
137 return true;
138 }
139
HandleData(bool read,std::vector<char> * data)140 bool FastbootDevice::HandleData(bool read, std::vector<char>* data) {
141 return HandleData(read, data->data(), data->size());
142 }
143
HandleData(bool read,char * data,uint64_t size)144 bool FastbootDevice::HandleData(bool read, char* data, uint64_t size) {
145 auto read_write_data_size = read ? this->get_transport()->Read(data, size)
146 : this->get_transport()->Write(data, size);
147 if (read_write_data_size == -1) {
148 LOG(ERROR) << (read ? "read from" : "write to") << " transport failed";
149 return false;
150 }
151 if (static_cast<size_t>(read_write_data_size) != size) {
152 LOG(ERROR) << (read ? "read" : "write") << " expected " << size << " bytes, got "
153 << read_write_data_size;
154 return false;
155 }
156 return true;
157 }
158
ExecuteCommands()159 void FastbootDevice::ExecuteCommands() {
160 char command[FB_RESPONSE_SZ + 1];
161 for (;;) {
162 auto bytes_read = transport_->Read(command, FB_RESPONSE_SZ);
163 if (bytes_read == -1) {
164 PLOG(ERROR) << "Couldn't read command";
165 return;
166 }
167 command[bytes_read] = '\0';
168
169 LOG(INFO) << "Fastboot command: " << command;
170
171 std::vector<std::string> args;
172 std::string cmd_name;
173 if (android::base::StartsWith(command, "oem ")) {
174 args = {command};
175 cmd_name = FB_CMD_OEM;
176 } else {
177 args = android::base::Split(command, ":");
178 cmd_name = args[0];
179 }
180
181 auto found_command = kCommandMap.find(cmd_name);
182 if (found_command == kCommandMap.end()) {
183 WriteStatus(FastbootResult::FAIL, "Unrecognized command " + args[0]);
184 continue;
185 }
186 if (!found_command->second(this, args)) {
187 return;
188 }
189 }
190 }
191
WriteOkay(const std::string & message)192 bool FastbootDevice::WriteOkay(const std::string& message) {
193 return WriteStatus(FastbootResult::OKAY, message);
194 }
195
WriteFail(const std::string & message)196 bool FastbootDevice::WriteFail(const std::string& message) {
197 return WriteStatus(FastbootResult::FAIL, message);
198 }
199
WriteInfo(const std::string & message)200 bool FastbootDevice::WriteInfo(const std::string& message) {
201 return WriteStatus(FastbootResult::INFO, message);
202 }
203