Merge "fs_mgr: Do not mount empty partitions."
diff --git a/adb/Android.bp b/adb/Android.bp
index 07f052f..906c5e3 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -277,26 +277,113 @@
},
}
+// libadbd_core contains the common sources to build libadbd and libadbd_services.
cc_library_static {
+ name: "libadbd_core",
+ defaults: ["adb_defaults"],
+ recovery_available: true,
+
+ // libminadbd wants both, as it's used to build native tests.
+ compile_multilib: "both",
+
+ srcs: libadb_srcs + libadb_posix_srcs + [
+ "daemon/auth.cpp",
+ "daemon/jdwp_service.cpp",
+ "daemon/usb.cpp",
+ ],
+
+ local_include_dirs: [
+ "daemon/include",
+ ],
+
+ static_libs: [
+ "libdiagnose_usb",
+ "libqemu_pipe",
+ ],
+
+ shared_libs: [
+ "libasyncio",
+ "libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "liblog",
+ ],
+}
+
+cc_library {
+ name: "libadbd_services",
+ defaults: ["adb_defaults"],
+ recovery_available: true,
+ compile_multilib: "both",
+
+ srcs: [
+ "daemon/file_sync_service.cpp",
+ "daemon/framebuffer_service.cpp",
+ "daemon/mdns.cpp",
+ "daemon/remount_service.cpp",
+ "daemon/services.cpp",
+ "daemon/set_verity_enable_state_service.cpp",
+ "daemon/shell_service.cpp",
+ "shell_service_protocol.cpp",
+ ],
+
+ cflags: [
+ "-D_GNU_SOURCE",
+ "-Wno-deprecated-declarations",
+ ],
+
+ static_libs: [
+ "libadbd_core",
+ "libavb_user",
+ "libdiagnose_usb",
+ "libqemu_pipe",
+
+ // `daemon/shell_service.cpp` uses selinux_android_setcon(), which is not exposed by
+ // libselinux.
+ "libselinux",
+ ],
+
+ shared_libs: [
+ "libasyncio",
+ "libbase",
+ "libbootloader_message",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "libext4_utils",
+ "libfec",
+ "libfec_rs",
+ "libfs_mgr",
+ "liblog",
+ "libmdnssd",
+ ],
+}
+
+cc_library {
name: "libadbd",
defaults: ["adb_defaults"],
recovery_available: true,
- // libminadbd wants both, for some reason.
+ // Avoid getting duplicate symbol of android::build::GetBuildNumber().
+ use_version_lib: false,
+
+ // libminadbd wants both, as it's used to build native tests.
compile_multilib: "both",
- srcs: libadb_srcs + libadb_posix_srcs + [
- "daemon/auth.cpp",
- "daemon/usb.cpp",
- "daemon/jdwp_service.cpp",
+
+ // libadbd doesn't build any additional source, but to expose libadbd_core as a shared library.
+ whole_static_libs: [
+ "libadbd_core",
],
- static_libs: [
+ shared_libs: [
+ "libadbd_services",
"libasyncio",
- "libcrypto_utils",
- "libcrypto",
- "libdiagnose_usb",
- "libqemu_pipe",
"libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "liblog",
],
export_include_dirs: [
@@ -307,19 +394,10 @@
cc_binary {
name: "adbd",
defaults: ["adb_defaults"],
-
recovery_available: true,
srcs: [
"daemon/main.cpp",
- "daemon/mdns.cpp",
- "daemon/file_sync_service.cpp",
- "daemon/framebuffer_service.cpp",
- "daemon/remount_service.cpp",
- "daemon/set_verity_enable_state_service.cpp",
- "daemon/services.cpp",
- "daemon/shell_service.cpp",
- "shell_service_protocol.cpp",
],
cflags: [
@@ -331,27 +409,16 @@
keep_symbols: true,
},
- static_libs: [
+ shared_libs: [
"libadbd",
- "libasyncio",
- "libavb_user",
- "libbootloader_message",
- "libcrypto_utils",
+ "libadbd_services",
+ "libbase",
+ "libcap",
"libcrypto",
- "libdiagnose_usb",
- "libfec",
- "libfec_rs",
- "libfs_mgr",
+ "libcutils",
"liblog",
- "libext4_utils",
- "libmdnssd",
"libminijail",
"libselinux",
- "libsquashfs_utils",
- "libqemu_pipe",
-
- "libbase",
- "libcutils",
],
}
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 3b1552e..b20dee9 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -453,10 +453,6 @@
return it->second;
}
-std::string getEmulatorSerialString(int console_port) {
- return android::base::StringPrintf("emulator-%d", console_port);
-}
-
atransport* find_emulator_transport_by_adb_port(int adb_port) {
std::lock_guard<std::mutex> lock(local_transports_lock);
return find_emulator_transport_by_adb_port_locked(adb_port);
@@ -467,6 +463,10 @@
}
#endif
+std::string getEmulatorSerialString(int console_port) {
+ return android::base::StringPrintf("emulator-%d", console_port);
+}
+
int init_socket_transport(atransport* t, unique_fd fd, int adb_port, int local) {
int fail = 0;
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 2b4a954..51cc62a 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -1,3 +1,17 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
cc_library_host_static {
name: "libfastboot2",
@@ -54,3 +68,54 @@
export_include_dirs: ["."],
}
+
+cc_defaults {
+ name: "fastboot_defaults",
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wvla",
+ ],
+ rtti: true,
+
+ clang_cflags: [
+ "-Wthread-safety",
+ ],
+}
+
+cc_binary {
+ name: "fastbootd",
+ defaults: ["fastboot_defaults"],
+
+ recovery: true,
+
+ srcs: [
+ "device/commands.cpp",
+ "device/fastboot_device.cpp",
+ "device/main.cpp",
+ "device/usb_client.cpp",
+ ],
+
+ shared_libs: [
+ "libasyncio",
+ "libext4_utils",
+ "libsparse",
+ "liblog",
+ "libbootloader_message",
+ "libhidltransport",
+ "libhidlbase",
+ "libhwbinder",
+ "libbase",
+ "libutils",
+ "libcutils",
+ "libfs_mgr",
+ ],
+
+ static_libs: [
+ "libadbd",
+ ],
+
+ cpp_std: "c++17",
+}
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 5e7e955..7caca3d 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -27,6 +27,8 @@
#define FB_CMD_REBOOT "reboot"
#define FB_CMD_SHUTDOWN "shutdown"
#define FB_CMD_REBOOT_BOOTLOADER "reboot-bootloader"
+#define FB_CMD_REBOOT_RECOVERY "reboot-recovery"
+#define FB_CMD_REBOOT_FASTBOOT "reboot-fastboot"
#define FB_CMD_POWERDOWN "powerdown"
#define RESPONSE_OKAY "OKAY"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
new file mode 100644
index 0000000..a3cbf96
--- /dev/null
+++ b/fastboot/device/commands.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "commands.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/android_reboot.h>
+
+#include "fastboot_device.h"
+
+bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ if (args.size() < 2) {
+ return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
+ }
+ // arg[0] is the command name, arg[1] contains size of data to be downloaded
+ unsigned int size;
+ if (!android::base::ParseUint("0x" + args[1], &size, UINT_MAX)) {
+ return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
+ }
+ device->get_download_data().resize(size);
+ if (!device->WriteStatus(FastbootResult::DATA, android::base::StringPrintf("%08x", size))) {
+ return false;
+ }
+
+ if (device->HandleData(true, &device->get_download_data())) {
+ return device->WriteStatus(FastbootResult::OKAY, "");
+ }
+
+ PLOG(ERROR) << "Couldn't download data";
+ return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data");
+}
+
+bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ return device->WriteStatus(FastbootResult::OKAY, "");
+}
+
+bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Shutting down");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,fastboot");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,from_fastboot");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting bootloader");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting fastboot");
+ android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot");
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return result;
+}
+
+static bool EnterRecovery() {
+ const char msg_switch_to_recovery = 'r';
+
+ android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
+ if (sock < 0) {
+ PLOG(ERROR) << "Couldn't create sock";
+ return false;
+ }
+
+ struct sockaddr_un addr = {.sun_family = AF_UNIX};
+ strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
+ if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ PLOG(ERROR) << "Couldn't connect to recovery";
+ return false;
+ }
+ // Switch to recovery will not update the boot reason since it does not
+ // require a reboot.
+ auto ret = write(sock, &msg_switch_to_recovery, sizeof(msg_switch_to_recovery));
+ if (ret != sizeof(msg_switch_to_recovery)) {
+ PLOG(ERROR) << "Couldn't write message to switch to recovery";
+ return false;
+ }
+
+ return true;
+}
+
+bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+ auto status = true;
+ if (EnterRecovery()) {
+ status = device->WriteStatus(FastbootResult::OKAY, "Rebooting to recovery");
+ } else {
+ status = device->WriteStatus(FastbootResult::FAIL, "Unable to reboot to recovery");
+ }
+ device->CloseDevice();
+ TEMP_FAILURE_RETRY(pause());
+ return status;
+}
diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h
new file mode 100644
index 0000000..cd984c8
--- /dev/null
+++ b/fastboot/device/commands.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <functional>
+#include <string>
+#include <vector>
+
+class FastbootDevice;
+
+enum class FastbootResult {
+ OKAY,
+ FAIL,
+ INFO,
+ DATA,
+};
+
+// Execute a command with the given arguments (possibly empty).
+using CommandHandler = std::function<bool(FastbootDevice*, const std::vector<std::string>&)>;
+
+bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& args);
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
new file mode 100644
index 0000000..4c3d23f
--- /dev/null
+++ b/fastboot/device/fastboot_device.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fastboot_device.h"
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+#include <algorithm>
+
+#include "constants.h"
+#include "usb_client.h"
+
+FastbootDevice::FastbootDevice()
+ : kCommandMap({
+ {FB_CMD_SET_ACTIVE, SetActiveHandler},
+ {FB_CMD_DOWNLOAD, DownloadHandler},
+ {FB_CMD_SHUTDOWN, ShutDownHandler},
+ {FB_CMD_REBOOT, RebootHandler},
+ {FB_CMD_REBOOT_BOOTLOADER, RebootBootloaderHandler},
+ {FB_CMD_REBOOT_FASTBOOT, RebootFastbootHandler},
+ {FB_CMD_REBOOT_RECOVERY, RebootRecoveryHandler},
+ }),
+ transport_(std::make_unique<ClientUsbTransport>()) {}
+
+FastbootDevice::~FastbootDevice() {
+ CloseDevice();
+}
+
+void FastbootDevice::CloseDevice() {
+ transport_->Close();
+}
+
+bool FastbootDevice::WriteStatus(FastbootResult result, const std::string& message) {
+ constexpr size_t kResponseReasonSize = 4;
+ constexpr size_t kNumResponseTypes = 4; // "FAIL", "OKAY", "INFO", "DATA"
+ char buf[FB_RESPONSE_SZ];
+ constexpr size_t kMaxMessageSize = sizeof(buf) - kResponseReasonSize;
+ size_t msg_len = std::min(kMaxMessageSize, message.size());
+
+ constexpr const char* kResultStrings[kNumResponseTypes] = {RESPONSE_OKAY, RESPONSE_FAIL,
+ RESPONSE_INFO, RESPONSE_DATA};
+
+ if (static_cast<size_t>(result) >= kNumResponseTypes) {
+ return false;
+ }
+
+ memcpy(buf, kResultStrings[static_cast<size_t>(result)], kResponseReasonSize);
+ memcpy(buf + kResponseReasonSize, message.c_str(), msg_len);
+
+ size_t response_len = kResponseReasonSize + msg_len;
+ auto write_ret = this->get_transport()->Write(buf, response_len);
+ if (write_ret != static_cast<ssize_t>(response_len)) {
+ PLOG(ERROR) << "Failed to write " << message;
+ return false;
+ }
+
+ return true;
+}
+
+bool FastbootDevice::HandleData(bool read, std::vector<char>* data) {
+ auto read_write_data_size = read ? this->get_transport()->Read(data->data(), data->size())
+ : this->get_transport()->Write(data->data(), data->size());
+ if (read_write_data_size == -1 || static_cast<size_t>(read_write_data_size) != data->size()) {
+ return false;
+ }
+ return true;
+}
+
+void FastbootDevice::ExecuteCommands() {
+ char command[FB_RESPONSE_SZ + 1];
+ for (;;) {
+ auto bytes_read = transport_->Read(command, FB_RESPONSE_SZ);
+ if (bytes_read == -1) {
+ PLOG(ERROR) << "Couldn't read command";
+ return;
+ }
+ command[bytes_read] = '\0';
+
+ LOG(INFO) << "Fastboot command: " << command;
+ auto args = android::base::Split(command, ":");
+ auto found_command = kCommandMap.find(args[0]);
+ if (found_command == kCommandMap.end()) {
+ WriteStatus(FastbootResult::FAIL, "Unrecognized command");
+ continue;
+ }
+ if (!found_command->second(this, args)) {
+ return;
+ }
+ }
+}
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
new file mode 100644
index 0000000..fec42a7
--- /dev/null
+++ b/fastboot/device/fastboot_device.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "commands.h"
+#include "transport.h"
+
+class FastbootDevice;
+
+class FastbootDevice {
+ public:
+ FastbootDevice();
+ ~FastbootDevice();
+
+ void CloseDevice();
+ void ExecuteCommands();
+ bool WriteStatus(FastbootResult result, const std::string& message);
+ bool HandleData(bool read, std::vector<char>* data);
+
+ std::vector<char>& get_download_data() { return download_data_; }
+ void set_upload_data(const std::vector<char>& data) { upload_data_ = data; }
+ void set_upload_data(std::vector<char>&& data) { upload_data_ = std::move(data); }
+ Transport* get_transport() { return transport_.get(); }
+
+ private:
+ const std::unordered_map<std::string, CommandHandler> kCommandMap;
+
+ std::unique_ptr<Transport> transport_;
+
+ std::vector<char> download_data_;
+ std::vector<char> upload_data_;
+};
diff --git a/fastboot/device/main.cpp b/fastboot/device/main.cpp
new file mode 100644
index 0000000..df9c900
--- /dev/null
+++ b/fastboot/device/main.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "fastboot_device.h"
+
+int main(int /*argc*/, char* argv[]) {
+ android::base::InitLogging(argv, &android::base::KernelLogger);
+
+ while (true) {
+ FastbootDevice device;
+ device.ExecuteCommands();
+ }
+}
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
new file mode 100644
index 0000000..215f99a
--- /dev/null
+++ b/fastboot/device/usb_client.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "usb_client.h"
+
+#include <endian.h>
+#include <fcntl.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+constexpr int kMaxPacketSizeFs = 64;
+constexpr int kMaxPacketSizeHs = 512;
+constexpr int kMaxPacketsizeSs = 1024;
+
+constexpr size_t kFbFfsNumBufs = 16;
+constexpr size_t kFbFfsBufSize = 32768;
+
+constexpr const char* kUsbFfsFastbootEp0 = "/dev/usb-ffs/fastboot/ep0";
+constexpr const char* kUsbFfsFastbootOut = "/dev/usb-ffs/fastboot/ep1";
+constexpr const char* kUsbFfsFastbootIn = "/dev/usb-ffs/fastboot/ep2";
+
+struct FuncDesc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_endpoint_descriptor_no_audio sink;
+} __attribute__((packed));
+
+struct SsFuncDesc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_ss_ep_comp_descriptor source_comp;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_ss_ep_comp_descriptor sink_comp;
+} __attribute__((packed));
+
+struct DescV2 {
+ struct usb_functionfs_descs_head_v2 header;
+ // The rest of the structure depends on the flags in the header.
+ __le32 fs_count;
+ __le32 hs_count;
+ __le32 ss_count;
+ struct FuncDesc fs_descs, hs_descs;
+ struct SsFuncDesc ss_descs;
+} __attribute__((packed));
+
+struct usb_interface_descriptor fastboot_interface = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 66,
+ .bInterfaceProtocol = 3,
+ .iInterface = 1, /* first string from the provided table */
+};
+
+static struct FuncDesc fs_descriptors = {
+ .intf = fastboot_interface,
+ .source =
+ {
+ .bLength = sizeof(fs_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeFs,
+ },
+ .sink =
+ {
+ .bLength = sizeof(fs_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeFs,
+ },
+};
+
+static struct FuncDesc hs_descriptors = {
+ .intf = fastboot_interface,
+ .source =
+ {
+ .bLength = sizeof(hs_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeHs,
+ },
+ .sink =
+ {
+ .bLength = sizeof(hs_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketSizeHs,
+ },
+};
+
+static struct SsFuncDesc ss_descriptors = {
+ .intf = fastboot_interface,
+ .source =
+ {
+ .bLength = sizeof(ss_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketsizeSs,
+ },
+ .source_comp =
+ {
+ .bLength = sizeof(ss_descriptors.source_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 15,
+ },
+ .sink =
+ {
+ .bLength = sizeof(ss_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = kMaxPacketsizeSs,
+ },
+ .sink_comp =
+ {
+ .bLength = sizeof(ss_descriptors.sink_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 15,
+ },
+};
+
+#define STR_INTERFACE_ "fastboot"
+
+static const struct {
+ struct usb_functionfs_strings_head header;
+ struct {
+ __le16 code;
+ const char str1[sizeof(STR_INTERFACE_)];
+ } __attribute__((packed)) lang0;
+} __attribute__((packed)) strings = {
+ .header =
+ {
+ .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = htole32(sizeof(strings)),
+ .str_count = htole32(1),
+ .lang_count = htole32(1),
+ },
+ .lang0 =
+ {
+ htole16(0x0409), /* en-us */
+ STR_INTERFACE_,
+ },
+};
+
+static struct DescV2 v2_descriptor = {
+ .header =
+ {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .length = htole32(sizeof(v2_descriptor)),
+ .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC,
+ },
+ .fs_count = 3,
+ .hs_count = 3,
+ .ss_count = 5,
+ .fs_descs = fs_descriptors,
+ .hs_descs = hs_descriptors,
+ .ss_descs = ss_descriptors,
+};
+
+// Reimplementing since usb_ffs_close() does not close the control FD.
+static void CloseFunctionFs(usb_handle* h) {
+ if (h->bulk_in > 0) {
+ close(h->bulk_in);
+ h->bulk_in = -1;
+ }
+ if (h->bulk_out > 0) {
+ close(h->bulk_out);
+ h->bulk_out = -1;
+ }
+ if (h->control > 0) {
+ close(h->control);
+ h->control = -1;
+ }
+}
+
+static bool InitFunctionFs(usb_handle* h) {
+ LOG(INFO) << "initializing functionfs";
+
+ if (h->control < 0) { // might have already done this before
+ LOG(INFO) << "opening control endpoint " << kUsbFfsFastbootEp0;
+ h->control = open(kUsbFfsFastbootEp0, O_RDWR);
+ if (h->control < 0) {
+ PLOG(ERROR) << "cannot open control endpoint " << kUsbFfsFastbootEp0;
+ goto err;
+ }
+
+ auto ret = write(h->control, &v2_descriptor, sizeof(v2_descriptor));
+ if (ret < 0) {
+ PLOG(ERROR) << "cannot write descriptors " << kUsbFfsFastbootEp0;
+ goto err;
+ }
+
+ ret = write(h->control, &strings, sizeof(strings));
+ if (ret < 0) {
+ PLOG(ERROR) << "cannot write strings " << kUsbFfsFastbootEp0;
+ goto err;
+ }
+ // Signal only when writing the descriptors to ffs
+ android::base::SetProperty("sys.usb.ffs.ready", "1");
+ }
+
+ h->bulk_out = open(kUsbFfsFastbootOut, O_RDONLY);
+ if (h->bulk_out < 0) {
+ PLOG(ERROR) << "cannot open bulk-out endpoint " << kUsbFfsFastbootOut;
+ goto err;
+ }
+
+ h->bulk_in = open(kUsbFfsFastbootIn, O_WRONLY);
+ if (h->bulk_in < 0) {
+ PLOG(ERROR) << "cannot open bulk-in endpoint " << kUsbFfsFastbootIn;
+ goto err;
+ }
+
+ h->read_aiob.fd = h->bulk_out;
+ h->write_aiob.fd = h->bulk_in;
+ h->reads_zero_packets = false;
+ return true;
+
+err:
+ CloseFunctionFs(h);
+ return false;
+}
+
+ClientUsbTransport::ClientUsbTransport()
+ : handle_(std::unique_ptr<usb_handle>(create_usb_handle(kFbFfsNumBufs, kFbFfsBufSize))) {
+ if (!InitFunctionFs(handle_.get())) {
+ handle_.reset(nullptr);
+ }
+}
+
+ssize_t ClientUsbTransport::Read(void* data, size_t len) {
+ if (handle_ == nullptr || len > SSIZE_MAX) {
+ return -1;
+ }
+ char* char_data = static_cast<char*>(data);
+ size_t bytes_read_total = 0;
+ while (bytes_read_total < len) {
+ auto bytes_to_read = std::min(len - bytes_read_total, kFbFfsNumBufs * kFbFfsBufSize);
+ auto bytes_read_now = handle_->read(handle_.get(), char_data, bytes_to_read);
+ if (bytes_read_now < 0) {
+ return bytes_read_total;
+ }
+ bytes_read_total += bytes_read_now;
+ char_data += bytes_read_now;
+ if (static_cast<size_t>(bytes_read_now) < bytes_to_read) {
+ break;
+ }
+ }
+ return bytes_read_total;
+}
+
+ssize_t ClientUsbTransport::Write(const void* data, size_t len) {
+ if (handle_ == nullptr || len > SSIZE_MAX) {
+ return -1;
+ }
+ const char* char_data = reinterpret_cast<const char*>(data);
+ size_t bytes_written_total = 0;
+ while (bytes_written_total < len) {
+ auto bytes_to_write = std::min(len - bytes_written_total, kFbFfsNumBufs * kFbFfsBufSize);
+ auto bytes_written_now = handle_->write(handle_.get(), data, bytes_to_write);
+ if (bytes_written_now < 0) {
+ return bytes_written_total;
+ }
+ bytes_written_total += bytes_written_now;
+ char_data += bytes_written_now;
+ if (static_cast<size_t>(bytes_written_now) < bytes_to_write) {
+ break;
+ }
+ }
+ return bytes_written_total;
+}
+
+int ClientUsbTransport::Close() {
+ if (handle_ == nullptr) {
+ return -1;
+ }
+ CloseFunctionFs(handle_.get());
+ return 0;
+}
diff --git a/fastboot/device/usb_client.h b/fastboot/device/usb_client.h
new file mode 100644
index 0000000..3694f9a
--- /dev/null
+++ b/fastboot/device/usb_client.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <memory>
+
+#include <adbd/usb.h>
+
+#include "transport.h"
+
+class ClientUsbTransport : public Transport {
+ public:
+ ClientUsbTransport();
+ ~ClientUsbTransport() override = default;
+
+ ssize_t Read(void* data, size_t len) override;
+ ssize_t Write(const void* data, size_t len) override;
+ int Close() override;
+
+ private:
+ std::unique_ptr<usb_handle> handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientUsbTransport);
+};
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 321e6ba..d787d09 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -111,12 +111,13 @@
const char* img_name;
const char* sig_name;
const char* part_name;
- bool is_optional;
- bool is_secondary;
+ bool optional_if_no_image;
+ bool optional_if_no_partition;
+ bool IsSecondary() const { return nickname == nullptr; }
} images[] = {
// clang-format off
{ "boot", "boot.img", "boot.sig", "boot", false, false },
- { nullptr, "boot_other.img", "boot.sig", "boot", true, true },
+ { nullptr, "boot_other.img", "boot.sig", "boot", true, false },
{ "dtbo", "dtbo.img", "dtbo.sig", "dtbo", true, false },
{ "dts", "dt.img", "dt.sig", "dts", true, false },
{ "odm", "odm.img", "odm.sig", "odm", true, false },
@@ -125,14 +126,14 @@
"product-services.img",
"product-services.sig",
"product-services",
- true, false },
+ true, true },
{ "recovery", "recovery.img", "recovery.sig", "recovery", true, false },
- { "super", "super.img", "super.sig", "super", true, false },
- { "system", "system.img", "system.sig", "system", false, false },
- { nullptr, "system_other.img", "system.sig", "system", true, true },
+ { "super", "super.img", "super.sig", "super", true, true },
+ { "system", "system.img", "system.sig", "system", false, true },
+ { nullptr, "system_other.img", "system.sig", "system", true, false },
{ "vbmeta", "vbmeta.img", "vbmeta.sig", "vbmeta", true, false },
- { "vendor", "vendor.img", "vendor.sig", "vendor", true, false },
- { nullptr, "vendor_other.img", "vendor.sig", "vendor", true, true },
+ { "vendor", "vendor.img", "vendor.sig", "vendor", true, true },
+ { nullptr, "vendor_other.img", "vendor.sig", "vendor", true, false },
// clang-format on
};
@@ -637,7 +638,8 @@
// "require partition-exists=x" is a special case, added because of the trouble we had when
// Pixel 2 shipped with new partitions and users used old versions of fastboot to flash them,
// missing out new partitions. A device with new partitions can use "partition-exists" to
- // override the `is_optional` field in the `images` array.
+ // override the fields `optional_if_no_image` and 'optional_if_no_partition' in the `images`
+ // array.
if (!strcmp(name, "partition-exists")) {
const char* partition_name = val[0];
std::string has_slot;
@@ -648,7 +650,8 @@
bool known_partition = false;
for (size_t i = 0; i < arraysize(images); ++i) {
if (images[i].nickname && !strcmp(images[i].nickname, partition_name)) {
- images[i].is_optional = false;
+ images[i].optional_if_no_image = false;
+ images[i].optional_if_no_partition = false;
known_partition = true;
}
}
@@ -1041,6 +1044,25 @@
}
}
+static bool if_partition_exists(const std::string& partition, const std::string& slot) {
+ std::string has_slot;
+ std::string partition_name = partition;
+
+ if (fb_getvar("has-slot:" + partition, &has_slot) && has_slot == "yes") {
+ if (slot == "") {
+ std::string current_slot = get_current_slot();
+ if (current_slot == "") {
+ die("Failed to identify current slot");
+ }
+ partition_name += "_" + current_slot;
+ } else {
+ partition_name += "_" + slot;
+ }
+ }
+ std::string partition_size;
+ return fb_getvar("partition-size:" + partition_name, &partition_size);
+}
+
static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) {
queue_info_dump();
@@ -1076,7 +1098,7 @@
}
for (size_t i = 0; i < arraysize(images); ++i) {
const char* slot = slot_override.c_str();
- if (images[i].is_secondary) {
+ if (images[i].IsSecondary()) {
if (!skip_secondary) {
slot = secondary.c_str();
} else {
@@ -1086,12 +1108,17 @@
int fd = unzip_to_file(zip, images[i].img_name);
if (fd == -1) {
- if (images[i].is_optional) {
+ if (images[i].optional_if_no_image) {
continue; // An optional file is missing, so ignore it.
}
die("non-optional file %s missing", images[i].img_name);
}
+ if (images[i].optional_if_no_partition &&
+ !if_partition_exists(images[i].part_name, slot)) {
+ continue;
+ }
+
fastboot_buffer buf;
if (!load_buf_fd(fd, &buf)) {
die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
@@ -1163,7 +1190,7 @@
for (size_t i = 0; i < arraysize(images); i++) {
const char* slot = NULL;
- if (images[i].is_secondary) {
+ if (images[i].IsSecondary()) {
if (!skip_secondary) slot = secondary.c_str();
} else {
slot = slot_override.c_str();
@@ -1172,10 +1199,13 @@
fname = find_item_given_name(images[i].img_name);
fastboot_buffer buf;
if (!load_buf(fname.c_str(), &buf)) {
- if (images[i].is_optional) continue;
+ if (images[i].optional_if_no_image) continue;
die("could not load '%s': %s", images[i].img_name, strerror(errno));
}
-
+ if (images[i].optional_if_no_partition &&
+ !if_partition_exists(images[i].part_name, slot)) {
+ continue;
+ }
auto flashall = [&](const std::string &partition) {
do_send_signature(fname.c_str());
flash_buf(partition.c_str(), &buf);
@@ -1333,6 +1363,8 @@
bool wants_wipe = false;
bool wants_reboot = false;
bool wants_reboot_bootloader = false;
+ bool wants_reboot_recovery = false;
+ bool wants_reboot_fastboot = false;
bool skip_reboot = false;
bool wants_set_active = false;
bool skip_secondary = false;
@@ -1555,6 +1587,12 @@
if (what == "bootloader") {
wants_reboot = false;
wants_reboot_bootloader = true;
+ } else if (what == "recovery") {
+ wants_reboot = false;
+ wants_reboot_recovery = true;
+ } else if (what == "fastboot") {
+ wants_reboot = false;
+ wants_reboot_fastboot = true;
} else {
syntax_error("unknown reboot target %s", what.c_str());
}
@@ -1563,6 +1601,10 @@
if (!args.empty()) syntax_error("junk after reboot command");
} else if (command == "reboot-bootloader") {
wants_reboot_bootloader = true;
+ } else if (command == "reboot-recovery") {
+ wants_reboot_recovery = true;
+ } else if (command == "reboot-fastboot") {
+ wants_reboot_fastboot = true;
} else if (command == "continue") {
fb_queue_command("continue", "resuming boot");
} else if (command == "boot") {
@@ -1680,6 +1722,12 @@
} else if (wants_reboot_bootloader) {
fb_queue_command("reboot-bootloader", "rebooting into bootloader");
fb_queue_wait_for_disconnect();
+ } else if (wants_reboot_recovery) {
+ fb_queue_command("reboot-recovery", "rebooting into recovery");
+ fb_queue_wait_for_disconnect();
+ } else if (wants_reboot_fastboot) {
+ fb_queue_command("reboot-fastboot", "rebooting into fastboot");
+ fb_queue_wait_for_disconnect();
}
int status = fb_execute_queue() ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 38df664..a91e92e 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -80,13 +80,17 @@
}
static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
- const LpMetadataPartition& partition, std::string* path) {
+ const LpMetadataPartition& partition, bool force_writable,
+ std::string* path) {
DeviceMapper& dm = DeviceMapper::Instance();
DmTable table;
if (!CreateDmTable(block_device, metadata, partition, &table)) {
return false;
}
+ if (force_writable) {
+ table.set_readonly(false);
+ }
std::string name = GetPartitionName(partition);
if (!dm.CreateDevice(name, table)) {
return false;
@@ -111,7 +115,7 @@
continue;
}
std::string path;
- if (!CreateLogicalPartition(block_device, *metadata.get(), partition, &path)) {
+ if (!CreateLogicalPartition(block_device, *metadata.get(), partition, false, &path)) {
LERROR << "Could not create logical partition: " << GetPartitionName(partition);
return false;
}
@@ -120,7 +124,8 @@
}
bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
- const std::string& partition_name, std::string* path) {
+ const std::string& partition_name, bool force_writable,
+ std::string* path) {
auto metadata = ReadMetadata(block_device.c_str(), metadata_slot);
if (!metadata) {
LOG(ERROR) << "Could not read partition table.";
@@ -128,7 +133,8 @@
}
for (const auto& partition : metadata->partitions) {
if (GetPartitionName(partition) == partition_name) {
- return CreateLogicalPartition(block_device, *metadata.get(), partition, path);
+ return CreateLogicalPartition(block_device, *metadata.get(), partition, force_writable,
+ path);
}
}
LERROR << "Could not find any partition with name: " << partition_name;
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index cac475c..f15c450 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -41,9 +41,11 @@
// Create a block device for a single logical partition, given metadata and
// the partition name. On success, a path to the partition's block device is
-// returned.
+// returned. If |force_writable| is true, the "readonly" flag will be ignored
+// so the partition can be flashed.
bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
- const std::string& partition_name, std::string* path);
+ const std::string& partition_name, bool force_writable,
+ std::string* path);
// Destroy the block device for a logical partition, by name.
bool DestroyLogicalPartition(const std::string& name);