Merge "init: clean up logging initialization"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 20d0db5..9b48702 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -264,15 +264,6 @@
send_packet(cp, t);
}
-// qual_overwrite is used to overwrite a qualifier string. dst is a
-// pointer to a char pointer. It is assumed that if *dst is non-NULL, it
-// was malloc'ed and needs to freed. *dst will be set to a dup of src.
-// TODO: switch to std::string for these atransport fields instead.
-static void qual_overwrite(char** dst, const std::string& src) {
- free(*dst);
- *dst = strdup(src.c_str());
-}
-
void parse_banner(const std::string& banner, atransport* t) {
D("parse_banner: %s", banner.c_str());
@@ -296,11 +287,11 @@
const std::string& key = key_value[0];
const std::string& value = key_value[1];
if (key == "ro.product.name") {
- qual_overwrite(&t->product, value);
+ t->product = value;
} else if (key == "ro.product.model") {
- qual_overwrite(&t->model, value);
+ t->model = value;
} else if (key == "ro.product.device") {
- qual_overwrite(&t->device, value);
+ t->device = value;
} else if (key == "features") {
t->SetFeatures(value);
}
@@ -424,8 +415,8 @@
/* Other READY messages must use the same local-id */
s->ready(s);
} else {
- D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s",
- p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
+ D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s", p->msg.arg0,
+ p->msg.arg1, s->peer->id, p->msg.arg1, t->serial.c_str());
}
} else {
// When receiving A_OKAY from device for A_OPEN request, the host server may
@@ -451,8 +442,8 @@
* socket has a peer on the same transport.
*/
if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
- D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s",
- p->msg.arg1, t->serial, s->peer->transport->serial);
+ D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s", p->msg.arg1,
+ t->serial.c_str(), s->peer->transport->serial.c_str());
} else {
s->close(s);
}
@@ -1171,7 +1162,7 @@
std::string error;
atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (t) {
- return SendOkay(reply_fd, t->serial ? t->serial : "unknown");
+ return SendOkay(reply_fd, !t->serial.empty() ? t->serial : "unknown");
} else {
return SendFail(reply_fd, error);
}
@@ -1180,7 +1171,7 @@
std::string error;
atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (t) {
- return SendOkay(reply_fd, t->devpath ? t->devpath : "unknown");
+ return SendOkay(reply_fd, !t->devpath.empty() ? t->devpath : "unknown");
} else {
return SendFail(reply_fd, error);
}
diff --git a/adb/adb.h b/adb/adb.h
index c884166..7e9af9e 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -156,11 +156,6 @@
int handle_forward_request(const char* service, atransport* transport, int reply_fd);
-#if !ADB_HOST
-void framebuffer_service(int fd, void* cookie);
-void set_verity_enabled_state_service(int fd, void* cookie);
-#endif
-
/* packet allocator */
apacket* get_apacket(void);
void put_apacket(apacket* p);
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index ea5a44e..f4a92e3 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -136,9 +136,10 @@
}
// <device-serial> " " <local-name> " " <remote-name> "\n"
// Entries from "adb reverse" have no serial.
- android::base::StringAppendF(&result, "%s %s %s\n",
- l->transport->serial ? l->transport->serial : "(reverse)",
- l->local_name.c_str(), l->connect_to.c_str());
+ android::base::StringAppendF(
+ &result, "%s %s %s\n",
+ !l->transport->serial.empty() ? l->transport->serial.c_str() : "(reverse)",
+ l->local_name.c_str(), l->connect_to.c_str());
}
return result;
}
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 80d0dd3..7791895 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -362,9 +362,8 @@
}
static void copy_to_file(int inFd, int outFd) {
- const size_t BUFSIZE = 32 * 1024;
- char* buf = (char*) malloc(BUFSIZE);
- if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
+ constexpr size_t BUFSIZE = 32 * 1024;
+ std::vector<char> buf(BUFSIZE);
int len;
long total = 0;
int old_stdin_mode = -1;
@@ -376,9 +375,9 @@
while (true) {
if (inFd == STDIN_FILENO) {
- len = unix_read(inFd, buf, BUFSIZE);
+ len = unix_read(inFd, buf.data(), BUFSIZE);
} else {
- len = adb_read(inFd, buf, BUFSIZE);
+ len = adb_read(inFd, buf.data(), BUFSIZE);
}
if (len == 0) {
D("copy_to_file() : read 0 bytes; exiting");
@@ -389,10 +388,10 @@
break;
}
if (outFd == STDOUT_FILENO) {
- fwrite(buf, 1, len, stdout);
+ fwrite(buf.data(), 1, len, stdout);
fflush(stdout);
} else {
- adb_write(outFd, buf, len);
+ adb_write(outFd, buf.data(), len);
}
total += len;
}
@@ -400,7 +399,6 @@
stdinout_raw_epilogue(inFd, outFd, old_stdin_mode, old_stdout_mode);
D("copy_to_file() finished after %lu bytes", total);
- free(buf);
}
static void send_window_size_change(int fd, std::unique_ptr<ShellProtocol>& shell) {
@@ -1142,24 +1140,22 @@
static void write_zeros(int bytes, int fd) {
int old_stdin_mode = -1;
int old_stdout_mode = -1;
- char* buf = (char*) calloc(1, bytes);
- if (buf == nullptr) fatal("couldn't allocate buffer for write_zeros");
+ std::vector<char> buf(bytes);
D("write_zeros(%d) -> %d", bytes, fd);
stdinout_raw_prologue(-1, fd, old_stdin_mode, old_stdout_mode);
if (fd == STDOUT_FILENO) {
- fwrite(buf, 1, bytes, stdout);
+ fwrite(buf.data(), 1, bytes, stdout);
fflush(stdout);
} else {
- adb_write(fd, buf, bytes);
+ adb_write(fd, buf.data(), bytes);
}
stdinout_raw_prologue(-1, fd, old_stdin_mode, old_stdout_mode);
D("write_zeros() finished");
- free(buf);
}
static int backup(int argc, const char** argv) {
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index f7be8f9..0b71363 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -525,12 +525,11 @@
return true;
}
-void file_sync_service(int fd, void*) {
+void file_sync_service(android::base::unique_fd fd) {
std::vector<char> buffer(SYNC_DATA_MAX);
- while (handle_sync_command(fd, buffer)) {
+ while (handle_sync_command(fd.get(), buffer)) {
}
D("sync: done");
- adb_close(fd);
}
diff --git a/adb/daemon/framebuffer_service.cpp b/adb/daemon/framebuffer_service.cpp
index 20e03f9..9a620ab 100644
--- a/adb/daemon/framebuffer_service.cpp
+++ b/adb/daemon/framebuffer_service.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "framebuffer_service.h"
+
#include <errno.h>
#include <fcntl.h>
#include <linux/fb.h>
@@ -55,8 +57,7 @@
unsigned int alpha_length;
} __attribute__((packed));
-void framebuffer_service(int fd, void *cookie)
-{
+void framebuffer_service(android::base::unique_fd fd) {
struct fbinfo fbinfo;
unsigned int i, bsize;
char buf[640];
@@ -65,7 +66,7 @@
int fds[2];
pid_t pid;
- if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail;
+ if (pipe2(fds, O_CLOEXEC) < 0) return;
pid = fork();
if (pid < 0) goto done;
@@ -168,7 +169,7 @@
}
/* write header */
- if(!WriteFdExactly(fd, &fbinfo, sizeof(fbinfo))) goto done;
+ if (!WriteFdExactly(fd.get(), &fbinfo, sizeof(fbinfo))) goto done;
/* write data */
for(i = 0; i < fbinfo.size; i += bsize) {
@@ -176,13 +177,11 @@
if (i + bsize > fbinfo.size)
bsize = fbinfo.size - i;
if(!ReadFdExactly(fd_screencap, buf, bsize)) goto done;
- if(!WriteFdExactly(fd, buf, bsize)) goto done;
+ if (!WriteFdExactly(fd.get(), buf, bsize)) goto done;
}
done:
adb_close(fds[0]);
TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0));
-pipefail:
- adb_close(fd);
}
diff --git a/adb/daemon/framebuffer_service.h b/adb/daemon/framebuffer_service.h
new file mode 100644
index 0000000..d99c6fe
--- /dev/null
+++ b/adb/daemon/framebuffer_service.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#ifndef _DAEMON_FRAMEBUFFER_SERVICE_H_
+#define _DAEMON_FRAMEBUFFER_SERVICE_H_
+
+#include <android-base/unique_fd.h>
+
+void framebuffer_service(android::base::unique_fd fd);
+
+#endif // _DAEMON_FRAMEBUFFER_SERVICE_H_
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index 830b35d..dfdc365 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
+#include <sys/statvfs.h>
#include <sys/vfs.h>
#include <unistd.h>
@@ -43,6 +44,7 @@
#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "fs_mgr.h"
+#include "set_verity_enable_state_service.h"
// Returns the device used to mount a directory in /proc/mounts.
static std::string find_proc_mount(const char* dir) {
@@ -145,6 +147,17 @@
return true;
}
+static unsigned long get_mount_flags(int fd, const char* dir) {
+ struct statvfs st_vfs;
+ if (statvfs(dir, &st_vfs) == -1) {
+ // Even though we could not get the original mount flags, assume that
+ // the mount was originally read-only.
+ WriteFdFmt(fd, "statvfs of the %s mount failed: %s.\n", dir, strerror(errno));
+ return MS_RDONLY;
+ }
+ return st_vfs.f_flag;
+}
+
static bool remount_partition(int fd, const char* dir) {
if (!directory_exists(dir)) {
return true;
@@ -163,14 +176,23 @@
dir, dev.c_str(), strerror(errno));
return false;
}
- if (mount(dev.c_str(), dir, "none", MS_REMOUNT | MS_BIND, nullptr) == -1) {
+
+ unsigned long remount_flags = get_mount_flags(fd, dir);
+ if ((remount_flags & MS_RDONLY) == 0) {
+ // Mount is already writable.
+ return true;
+ }
+ remount_flags &= ~MS_RDONLY;
+ remount_flags |= MS_REMOUNT;
+
+ if (mount(dev.c_str(), dir, "none", remount_flags | MS_BIND, nullptr) == -1) {
// This is useful for cases where the superblock is already marked as
// read-write, but the mount itself is read-only, such as containers
// where the remount with just MS_REMOUNT is forbidden by the kernel.
WriteFdFmt(fd, "remount of the %s mount failed: %s.\n", dir, strerror(errno));
return false;
}
- if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
+ if (mount(dev.c_str(), dir, "none", remount_flags, nullptr) == -1) {
WriteFdFmt(fd, "remount of the %s superblock failed: %s\n", dir, strerror(errno));
return false;
}
@@ -197,14 +219,11 @@
android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd.c_str());
}
-void remount_service(int fd, void* cookie) {
- unique_fd close_fd(fd);
-
- const char* cmd = reinterpret_cast<const char*>(cookie);
- bool user_requested_reboot = cmd && !strcmp(cmd, "-R");
+void remount_service(android::base::unique_fd fd, const std::string& cmd) {
+ bool user_requested_reboot = cmd != "-R";
if (getuid() != 0) {
- WriteFdExactly(fd, "Not running as root. Try \"adb root\" first.\n");
+ WriteFdExactly(fd.get(), "Not running as root. Try \"adb root\" first.\n");
return;
}
@@ -225,7 +244,7 @@
if (dev.empty() || !fs_has_shared_blocks(dev.c_str())) {
continue;
}
- if (can_unshare_blocks(fd, dev.c_str())) {
+ if (can_unshare_blocks(fd.get(), dev.c_str())) {
dedup.emplace(partition);
}
}
@@ -236,12 +255,12 @@
if (user_requested_reboot) {
if (!dedup.empty() || verity_enabled) {
if (verity_enabled) {
- set_verity_enabled_state_service(fd, nullptr);
+ set_verity_enabled_state_service(android::base::unique_fd(dup(fd.get())), false);
}
- reboot_for_remount(fd, !dedup.empty());
+ reboot_for_remount(fd.get(), !dedup.empty());
return;
}
- WriteFdExactly(fd, "No reboot needed, skipping -R.\n");
+ WriteFdExactly(fd.get(), "No reboot needed, skipping -R.\n");
}
// If we need to disable-verity, but we also need to perform a recovery
@@ -250,17 +269,14 @@
if (verity_enabled && dedup.empty()) {
// Allow remount but warn of likely bad effects
bool both = system_verified && vendor_verified;
- WriteFdFmt(fd,
- "dm_verity is enabled on the %s%s%s partition%s.\n",
- system_verified ? "system" : "",
- both ? " and " : "",
- vendor_verified ? "vendor" : "",
- both ? "s" : "");
- WriteFdExactly(fd,
+ WriteFdFmt(fd.get(), "dm_verity is enabled on the %s%s%s partition%s.\n",
+ system_verified ? "system" : "", both ? " and " : "",
+ vendor_verified ? "vendor" : "", both ? "s" : "");
+ WriteFdExactly(fd.get(),
"Use \"adb disable-verity\" to disable verity.\n"
"If you do not, remount may succeed, however, you will still "
"not be able to write to these volumes.\n");
- WriteFdExactly(fd,
+ WriteFdExactly(fd.get(),
"Alternately, use \"adb remount -R\" to disable verity "
"and automatically reboot.\n");
}
@@ -271,29 +287,29 @@
if (dedup.count(partition)) {
continue;
}
- success &= remount_partition(fd, partition.c_str());
+ success &= remount_partition(fd.get(), partition.c_str());
}
if (!dedup.empty()) {
- WriteFdExactly(fd,
+ WriteFdExactly(fd.get(),
"The following partitions are deduplicated and cannot "
"yet be remounted:\n");
for (const std::string& name : dedup) {
- WriteFdFmt(fd, " %s\n", name.c_str());
+ WriteFdFmt(fd.get(), " %s\n", name.c_str());
}
- WriteFdExactly(fd,
+ WriteFdExactly(fd.get(),
"To reboot and un-deduplicate the listed partitions, "
"please retry with adb remount -R.\n");
if (system_verified || vendor_verified) {
- WriteFdExactly(fd, "Note: verity will be automatically disabled after reboot.\n");
+ WriteFdExactly(fd.get(), "Note: verity will be automatically disabled after reboot.\n");
}
return;
}
if (!success) {
- WriteFdExactly(fd, "remount failed\n");
+ WriteFdExactly(fd.get(), "remount failed\n");
} else {
- WriteFdExactly(fd, "remount succeeded\n");
+ WriteFdExactly(fd.get(), "remount succeeded\n");
}
}
diff --git a/adb/daemon/set_verity_enable_state_service.cpp b/adb/daemon/set_verity_enable_state_service.cpp
index dbeee28..0f804e9 100644
--- a/adb/daemon/set_verity_enable_state_service.cpp
+++ b/adb/daemon/set_verity_enable_state_service.cpp
@@ -16,6 +16,7 @@
#define TRACE_TAG ADB
+#include "set_verity_enable_state_service.h"
#include "sysdeps.h"
#include <fcntl.h>
@@ -25,8 +26,8 @@
#include <stdio.h>
#include <sys/stat.h>
-#include "android-base/properties.h"
-#include "android-base/stringprintf.h"
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <log/log_properties.h>
#include "adb.h"
@@ -131,12 +132,9 @@
return true;
}
-void set_verity_enabled_state_service(int fd, void* cookie) {
- unique_fd closer(fd);
+void set_verity_enabled_state_service(android::base::unique_fd fd, bool enable) {
bool any_changed = false;
- bool enable = (cookie != nullptr);
-
// Figure out if we're using VB1.0 or VB2.0 (aka AVB) - by
// contract, androidboot.vbmeta.digest is set by the bootloader
// when using AVB).
@@ -147,12 +145,12 @@
// VB1.0 dm-verity is only enabled on certain builds.
if (!using_avb) {
if (!kAllowDisableVerity) {
- WriteFdFmt(fd, "%s-verity only works for userdebug builds\n",
+ WriteFdFmt(fd.get(), "%s-verity only works for userdebug builds\n",
enable ? "enable" : "disable");
}
if (!android::base::GetBoolProperty("ro.secure", false)) {
- WriteFdFmt(fd, "verity not enabled - ENG build\n");
+ WriteFdFmt(fd.get(), "verity not enabled - ENG build\n");
return;
}
}
@@ -160,7 +158,7 @@
// Should never be possible to disable dm-verity on a USER build
// regardless of using AVB or VB1.0.
if (!__android_log_is_debuggable()) {
- WriteFdFmt(fd, "verity cannot be disabled/enabled - USER build\n");
+ WriteFdFmt(fd.get(), "verity cannot be disabled/enabled - USER build\n");
return;
}
@@ -168,10 +166,10 @@
// Yep, the system is using AVB.
AvbOps* ops = avb_ops_user_new();
if (ops == nullptr) {
- WriteFdFmt(fd, "Error getting AVB ops\n");
+ WriteFdFmt(fd.get(), "Error getting AVB ops\n");
return;
}
- if (set_avb_verity_enabled_state(fd, ops, enable)) {
+ if (set_avb_verity_enabled_state(fd.get(), ops, enable)) {
any_changed = true;
}
avb_ops_user_free(ops);
@@ -181,14 +179,14 @@
// read all fstab entries at once from all sources
fstab = fs_mgr_read_fstab_default();
if (!fstab) {
- WriteFdFmt(fd, "Failed to read fstab\nMaybe run adb root?\n");
+ WriteFdFmt(fd.get(), "Failed to read fstab\nMaybe run adb root?\n");
return;
}
// Loop through entries looking for ones that vold manages.
for (int i = 0; i < fstab->num_entries; i++) {
if (fs_mgr_is_verified(&fstab->recs[i])) {
- if (set_verity_enabled_state(fd, fstab->recs[i].blk_device,
+ if (set_verity_enabled_state(fd.get(), fstab->recs[i].blk_device,
fstab->recs[i].mount_point, enable)) {
any_changed = true;
}
@@ -197,6 +195,6 @@
}
if (any_changed) {
- WriteFdFmt(fd, "Now reboot your device for settings to take effect\n");
+ WriteFdFmt(fd.get(), "Now reboot your device for settings to take effect\n");
}
}
diff --git a/adb/daemon/set_verity_enable_state_service.h b/adb/daemon/set_verity_enable_state_service.h
new file mode 100644
index 0000000..9f84f35
--- /dev/null
+++ b/adb/daemon/set_verity_enable_state_service.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#ifndef _DAEMON_SET_VERITY_ENABLED_STATE_SERVICE_H_
+#define _DAEMON_SET_VERITY_ENABLED_STATE_SERVICE_H_
+
+#include <android-base/unique_fd.h>
+
+void set_verity_enabled_state_service(android::base::unique_fd fd, bool enable);
+
+#endif // _DAEMON_SET_VERITY_ENABLED_STATE_SERVICE_H_
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 6606efd..608b3ad 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -20,6 +20,8 @@
#include <string>
#include <vector>
+#include <android-base/unique_fd.h>
+
#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
#define ID_LSTAT_V1 MKID('S','T','A','T')
@@ -79,7 +81,7 @@
} status;
};
-void file_sync_service(int fd, void* cookie);
+void file_sync_service(android::base::unique_fd fd);
bool do_sync_ls(const char* path);
bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync);
bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
diff --git a/adb/remount_service.h b/adb/remount_service.h
index 7bda1be..45821ee 100644
--- a/adb/remount_service.h
+++ b/adb/remount_service.h
@@ -19,7 +19,9 @@
#include <string>
+#include <android-base/unique_fd.h>
+
bool make_block_device_writable(const std::string&);
-void remount_service(int, void*);
+void remount_service(android::base::unique_fd, const std::string&);
#endif
diff --git a/adb/services.cpp b/adb/services.cpp
index 1fa7ecc..3d418cb 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -37,6 +37,7 @@
#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
#if !ADB_HOST
@@ -49,6 +50,10 @@
#include "adb.h"
#include "adb_io.h"
#include "adb_utils.h"
+#if !ADB_HOST
+#include "daemon/framebuffer_service.h"
+#include "daemon/set_verity_enable_state_service.h"
+#endif
#include "file_sync_service.h"
#include "remount_service.h"
#include "services.h"
@@ -57,81 +62,67 @@
#include "sysdeps.h"
#include "transport.h"
-struct stinfo {
- const char* service_name;
- void (*func)(int fd, void *cookie);
- int fd;
- void *cookie;
-};
+namespace {
-static void service_bootstrap_func(void* x) {
- stinfo* sti = reinterpret_cast<stinfo*>(x);
- adb_thread_setname(android::base::StringPrintf("%s svc %d", sti->service_name, sti->fd));
- sti->func(sti->fd, sti->cookie);
- free(sti);
+void service_bootstrap_func(std::string service_name,
+ std::function<void(android::base::unique_fd)> func,
+ android::base::unique_fd fd) {
+ adb_thread_setname(android::base::StringPrintf("%s svc %d", service_name.c_str(), fd.get()));
+ func(std::move(fd));
}
#if !ADB_HOST
-void restart_root_service(int fd, void *cookie) {
+void restart_root_service(android::base::unique_fd fd) {
if (getuid() == 0) {
- WriteFdExactly(fd, "adbd is already running as root\n");
- adb_close(fd);
- } else {
- if (!__android_log_is_debuggable()) {
- WriteFdExactly(fd, "adbd cannot run as root in production builds\n");
- adb_close(fd);
- return;
- }
-
- android::base::SetProperty("service.adb.root", "1");
- WriteFdExactly(fd, "restarting adbd as root\n");
- adb_close(fd);
+ WriteFdExactly(fd.get(), "adbd is already running as root\n");
+ return;
}
+ if (!__android_log_is_debuggable()) {
+ WriteFdExactly(fd.get(), "adbd cannot run as root in production builds\n");
+ return;
+ }
+
+ android::base::SetProperty("service.adb.root", "1");
+ WriteFdExactly(fd.get(), "restarting adbd as root\n");
}
-void restart_unroot_service(int fd, void *cookie) {
+void restart_unroot_service(android::base::unique_fd fd) {
if (getuid() != 0) {
- WriteFdExactly(fd, "adbd not running as root\n");
- adb_close(fd);
- } else {
- android::base::SetProperty("service.adb.root", "0");
- WriteFdExactly(fd, "restarting adbd as non root\n");
- adb_close(fd);
+ WriteFdExactly(fd.get(), "adbd not running as root\n");
+ return;
}
+ android::base::SetProperty("service.adb.root", "0");
+ WriteFdExactly(fd.get(), "restarting adbd as non root\n");
}
-void restart_tcp_service(int fd, void *cookie) {
- int port = (int) (uintptr_t) cookie;
+void restart_tcp_service(android::base::unique_fd fd, int port) {
if (port <= 0) {
- WriteFdFmt(fd, "invalid port %d\n", port);
- adb_close(fd);
+ WriteFdFmt(fd.get(), "invalid port %d\n", port);
return;
}
android::base::SetProperty("service.adb.tcp.port", android::base::StringPrintf("%d", port));
- WriteFdFmt(fd, "restarting in TCP mode port: %d\n", port);
- adb_close(fd);
+ WriteFdFmt(fd.get(), "restarting in TCP mode port: %d\n", port);
}
-void restart_usb_service(int fd, void *cookie) {
+void restart_usb_service(android::base::unique_fd fd) {
android::base::SetProperty("service.adb.tcp.port", "0");
- WriteFdExactly(fd, "restarting in USB mode\n");
- adb_close(fd);
+ WriteFdExactly(fd.get(), "restarting in USB mode\n");
}
-static bool reboot_service_impl(int fd, const char* arg) {
- const char* reboot_arg = arg;
+bool reboot_service_impl(android::base::unique_fd fd, const std::string& arg) {
+ std::string reboot_arg = arg;
bool auto_reboot = false;
- if (strcmp(reboot_arg, "sideload-auto-reboot") == 0) {
+ if (reboot_arg == "sideload-auto-reboot") {
auto_reboot = true;
reboot_arg = "sideload";
}
// It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot"
// in the command file.
- if (strcmp(reboot_arg, "sideload") == 0) {
+ if (reboot_arg == "sideload") {
if (getuid() != 0) {
WriteFdExactly(fd, "'adb root' is required for 'adb reboot sideload'.\n");
return false;
@@ -151,8 +142,8 @@
sync();
- if (!reboot_arg || !reboot_arg[0]) reboot_arg = "adb";
- std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg);
+ if (reboot_arg.empty()) reboot_arg = "adb";
+ std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
if (!android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_string)) {
WriteFdFmt(fd, "reboot (%s) failed\n", reboot_string.c_str());
return false;
@@ -161,23 +152,19 @@
return true;
}
-void reboot_service(int fd, void* arg) {
- if (reboot_service_impl(fd, static_cast<const char*>(arg))) {
- // Don't return early. Give the reboot command time to take effect
- // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
- while (true) {
- pause();
- }
+void reboot_service(android::base::unique_fd fd, const std::string& arg) {
+ if (!reboot_service_impl(std::move(fd), arg)) {
+ return;
}
-
- free(arg);
- adb_close(fd);
+ // Don't return early. Give the reboot command time to take effect
+ // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
+ while (true) {
+ pause();
+ }
}
-static void reconnect_service(int fd, void* arg) {
+void reconnect_service(android::base::unique_fd fd, atransport* t) {
WriteFdExactly(fd, "done");
- adb_close(fd);
- atransport* t = static_cast<atransport*>(arg);
kick_transport(t);
}
@@ -197,7 +184,7 @@
// Shell service string can look like:
// shell[,arg1,arg2,...]:[command]
-static int ShellService(const std::string& args, const atransport* transport) {
+int ShellService(const std::string& args, const atransport* transport) {
size_t delimiter_index = args.find(':');
if (delimiter_index == std::string::npos) {
LOG(ERROR) << "No ':' found in shell service arguments: " << args;
@@ -236,16 +223,17 @@
#endif // !ADB_HOST
-static int create_service_thread(const char* service_name, void (*func)(int, void*), void* cookie) {
+android::base::unique_fd create_service_thread(const char* service_name,
+ std::function<void(android::base::unique_fd)> func) {
int s[2];
if (adb_socketpair(s)) {
printf("cannot create service socket pair\n");
- return -1;
+ return android::base::unique_fd();
}
D("socketpair: (%d,%d)", s[0], s[1]);
#if !ADB_HOST
- if (func == &file_sync_service) {
+ if (strcmp(service_name, "sync") == 0) {
// Set file sync service socket to maximum size
int max_buf = LINUX_MAX_SOCKET_SIZE;
adb_setsockopt(s[0], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
@@ -253,21 +241,14 @@
}
#endif // !ADB_HOST
- stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
- if (sti == nullptr) {
- fatal("cannot allocate stinfo");
- }
- sti->service_name = service_name;
- sti->func = func;
- sti->cookie = cookie;
- sti->fd = s[1];
-
- std::thread(service_bootstrap_func, sti).detach();
+ std::thread(service_bootstrap_func, service_name, func, android::base::unique_fd(s[1])).detach();
D("service thread started, %d:%d",s[0], s[1]);
- return s[0];
+ return android::base::unique_fd(s[0]);
}
+} // namespace
+
int service_to_fd(const char* name, atransport* transport) {
int ret = -1;
@@ -280,54 +261,60 @@
#if !ADB_HOST
} else if(!strncmp("dev:", name, 4)) {
ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
- } else if(!strncmp(name, "framebuffer:", 12)) {
- ret = create_service_thread("fb", framebuffer_service, nullptr);
+ } else if (!strncmp(name, "framebuffer:", 12)) {
+ ret = create_service_thread("fb", framebuffer_service).release();
} else if (!strncmp(name, "jdwp:", 5)) {
- ret = create_jdwp_connection_fd(atoi(name+5));
- } else if(!strncmp(name, "shell", 5)) {
+ ret = create_jdwp_connection_fd(atoi(name + 5));
+ } else if (!strncmp(name, "shell", 5)) {
ret = ShellService(name + 5, transport);
- } else if(!strncmp(name, "exec:", 5)) {
+ } else if (!strncmp(name, "exec:", 5)) {
ret = StartSubprocess(name + 5, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
- } else if(!strncmp(name, "sync:", 5)) {
- ret = create_service_thread("sync", file_sync_service, nullptr);
- } else if(!strncmp(name, "remount:", 8)) {
- const char* options = name + strlen("remount:");
- void* cookie = const_cast<void*>(reinterpret_cast<const void*>(options));
- ret = create_service_thread("remount", remount_service, cookie);
- } else if(!strncmp(name, "reboot:", 7)) {
- void* arg = strdup(name + 7);
- if (arg == NULL) return -1;
- ret = create_service_thread("reboot", reboot_service, arg);
- if (ret < 0) free(arg);
- } else if(!strncmp(name, "root:", 5)) {
- ret = create_service_thread("root", restart_root_service, nullptr);
- } else if(!strncmp(name, "unroot:", 7)) {
- ret = create_service_thread("unroot", restart_unroot_service, nullptr);
- } else if(!strncmp(name, "backup:", 7)) {
- ret = StartSubprocess(android::base::StringPrintf("/system/bin/bu backup %s",
- (name + 7)).c_str(),
- nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
- } else if(!strncmp(name, "restore:", 8)) {
+ } else if (!strncmp(name, "sync:", 5)) {
+ ret = create_service_thread("sync", file_sync_service).release();
+ } else if (!strncmp(name, "remount:", 8)) {
+ std::string options(name + strlen("remount:"));
+ ret = create_service_thread("remount",
+ std::bind(remount_service, std::placeholders::_1, options))
+ .release();
+ } else if (!strncmp(name, "reboot:", 7)) {
+ std::string arg(name + strlen("reboot:"));
+ ret = create_service_thread("reboot", std::bind(reboot_service, std::placeholders::_1, arg))
+ .release();
+ } else if (!strncmp(name, "root:", 5)) {
+ ret = create_service_thread("root", restart_root_service).release();
+ } else if (!strncmp(name, "unroot:", 7)) {
+ ret = create_service_thread("unroot", restart_unroot_service).release();
+ } else if (!strncmp(name, "backup:", 7)) {
+ ret = StartSubprocess(
+ android::base::StringPrintf("/system/bin/bu backup %s", (name + 7)).c_str(),
+ nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
+ } else if (!strncmp(name, "restore:", 8)) {
ret = StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw,
SubprocessProtocol::kNone);
- } else if(!strncmp(name, "tcpip:", 6)) {
+ } else if (!strncmp(name, "tcpip:", 6)) {
int port;
if (sscanf(name + 6, "%d", &port) != 1) {
return -1;
}
- ret = create_service_thread("tcp", restart_tcp_service, reinterpret_cast<void*>(port));
- } else if(!strncmp(name, "usb:", 4)) {
- ret = create_service_thread("usb", restart_usb_service, nullptr);
+ ret = create_service_thread("tcp",
+ std::bind(restart_tcp_service, std::placeholders::_1, port))
+ .release();
+ } else if (!strncmp(name, "usb:", 4)) {
+ ret = create_service_thread("usb", restart_usb_service).release();
} else if (!strncmp(name, "reverse:", 8)) {
ret = reverse_service(name + 8, transport);
- } else if(!strncmp(name, "disable-verity:", 15)) {
- ret = create_service_thread("verity-on", set_verity_enabled_state_service,
- reinterpret_cast<void*>(0));
- } else if(!strncmp(name, "enable-verity:", 15)) {
- ret = create_service_thread("verity-off", set_verity_enabled_state_service,
- reinterpret_cast<void*>(1));
+ } else if (!strncmp(name, "disable-verity:", 15)) {
+ ret = create_service_thread("verity-on", std::bind(set_verity_enabled_state_service,
+ std::placeholders::_1, false))
+ .release();
+ } else if (!strncmp(name, "enable-verity:", 15)) {
+ ret = create_service_thread("verity-off", std::bind(set_verity_enabled_state_service,
+ std::placeholders::_1, true))
+ .release();
} else if (!strcmp(name, "reconnect")) {
- ret = create_service_thread("reconnect", reconnect_service, transport);
+ ret = create_service_thread("reconnect",
+ std::bind(reconnect_service, std::placeholders::_1, transport))
+ .release();
#endif
}
if (ret >= 0) {
@@ -420,19 +407,16 @@
}
}
-static void connect_service(int fd, void* data) {
- char* host = reinterpret_cast<char*>(data);
+static void connect_service(android::base::unique_fd fd, std::string host) {
std::string response;
- if (!strncmp(host, "emu:", 4)) {
- connect_emulator(host + 4, &response);
+ if (!strncmp(host.c_str(), "emu:", 4)) {
+ connect_emulator(host.c_str() + 4, &response);
} else {
- connect_device(host, &response);
+ connect_device(host.c_str(), &response);
}
- free(host);
// Send response for emulator and device
- SendProtocolString(fd, response);
- adb_close(fd);
+ SendProtocolString(fd.get(), response);
}
#endif
@@ -445,7 +429,7 @@
} else if (android::base::StartsWith(name, "wait-for-")) {
name += strlen("wait-for-");
- std::unique_ptr<state_info> sinfo(new state_info);
+ std::unique_ptr<state_info> sinfo = std::make_unique<state_info>();
if (sinfo == nullptr) {
fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
return nullptr;
@@ -481,17 +465,18 @@
return nullptr;
}
- int fd = create_service_thread("wait", wait_for_state, sinfo.get());
+ int fd = create_service_thread(
+ "wait", std::bind(wait_for_state, std::placeholders::_1, sinfo.get()))
+ .release();
if (fd != -1) {
sinfo.release();
}
return create_local_socket(fd);
} else if (!strncmp(name, "connect:", 8)) {
- char* host = strdup(name + 8);
- int fd = create_service_thread("connect", connect_service, host);
- if (fd == -1) {
- free(host);
- }
+ std::string host(name + strlen("connect:"));
+ int fd = create_service_thread("connect",
+ std::bind(connect_service, std::placeholders::_1, host))
+ .release();
return create_local_socket(fd);
}
return nullptr;
diff --git a/adb/sysdeps/memory.h b/adb/sysdeps/memory.h
index 0e4c509..4108aff 100644
--- a/adb/sysdeps/memory.h
+++ b/adb/sysdeps/memory.h
@@ -23,6 +23,23 @@
// We don't have C++14 on Windows yet.
// Reimplement std::make_unique ourselves until we do.
+namespace internal {
+
+template <typename T>
+struct array_known_bounds;
+
+template <typename T>
+struct array_known_bounds<T[]> {
+ constexpr static bool value = false;
+};
+
+template <typename T, size_t N>
+struct array_known_bounds<T[N]> {
+ constexpr static bool value = true;
+};
+
+} // namespace internal
+
namespace std {
template <typename T, typename... Args>
@@ -31,6 +48,18 @@
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
+template <typename T>
+typename std::enable_if<std::is_array<T>::value && !internal::array_known_bounds<T>::value,
+ std::unique_ptr<T>>::type
+make_unique(std::size_t size) {
+ return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
+}
+
+template <typename T, typename... Args>
+typename std::enable_if<std::is_array<T>::value && internal::array_known_bounds<T>::value,
+ std::unique_ptr<T>>::type
+make_unique(Args&&... args) = delete;
+
} // namespace std
#endif
diff --git a/adb/transport.cpp b/adb/transport.cpp
index f2c40d2..638940c 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -173,18 +173,18 @@
attempt = reconnect_queue_.front();
reconnect_queue_.pop();
if (attempt.transport->kicked()) {
- D("transport %s was kicked. giving up on it.", attempt.transport->serial);
+ D("transport %s was kicked. giving up on it.", attempt.transport->serial.c_str());
remove_transport(attempt.transport);
continue;
}
}
- D("attempting to reconnect %s", attempt.transport->serial);
+ D("attempting to reconnect %s", attempt.transport->serial.c_str());
if (!attempt.transport->Reconnect()) {
- D("attempting to reconnect %s failed.", attempt.transport->serial);
+ D("attempting to reconnect %s failed.", attempt.transport->serial.c_str());
if (attempt.attempts_left == 0) {
D("transport %s exceeded the number of retry attempts. giving up on it.",
- attempt.transport->serial);
+ attempt.transport->serial.c_str());
remove_transport(attempt.transport);
continue;
}
@@ -197,7 +197,7 @@
continue;
}
- D("reconnection to %s succeeded.", attempt.transport->serial);
+ D("reconnection to %s succeeded.", attempt.transport->serial.c_str());
register_transport(attempt.transport);
}
}
@@ -402,14 +402,14 @@
p->msg.data_check = calculate_apacket_checksum(p);
}
- VLOG(TRANSPORT) << dump_packet(t->serial, "to remote", p);
+ VLOG(TRANSPORT) << dump_packet(t->serial.c_str(), "to remote", p);
if (t == nullptr) {
fatal("Transport is null");
}
if (t->Write(p) != 0) {
- D("%s: failed to enqueue packet, closing transport", t->serial);
+ D("%s: failed to enqueue packet, closing transport", t->serial.c_str());
t->Kick();
}
}
@@ -619,19 +619,13 @@
t = m.transport;
if (m.action == 0) {
- D("transport: %s deleting", t->serial);
+ D("transport: %s deleting", t->serial.c_str());
{
std::lock_guard<std::recursive_mutex> lock(transport_lock);
transport_list.remove(t);
}
- if (t->product) free(t->product);
- if (t->serial) free(t->serial);
- if (t->model) free(t->model);
- if (t->device) free(t->device);
- if (t->devpath) free(t->devpath);
-
delete t;
update_transports();
@@ -646,11 +640,11 @@
t->connection()->SetTransportName(t->serial_name());
t->connection()->SetReadCallback([t](Connection*, std::unique_ptr<apacket> p) {
if (!check_header(p.get(), t)) {
- D("%s: remote read: bad header", t->serial);
+ D("%s: remote read: bad header", t->serial.c_str());
return false;
}
- VLOG(TRANSPORT) << dump_packet(t->serial, "from remote", p.get());
+ VLOG(TRANSPORT) << dump_packet(t->serial.c_str(), "from remote", p.get());
apacket* packet = p.release();
// TODO: Does this need to run on the main thread?
@@ -658,7 +652,7 @@
return true;
});
t->connection()->SetErrorCallback([t](Connection*, const std::string& error) {
- D("%s: connection terminated: %s", t->serial, error.c_str());
+ D("%s: connection terminated: %s", t->serial.c_str(), error.c_str());
fdevent_run_on_main_thread([t]() {
handle_offline(t);
transport_unref(t);
@@ -717,7 +711,7 @@
tmsg m;
m.transport = transport;
m.action = 1;
- D("transport: %s registered", transport->serial);
+ D("transport: %s registered", transport->serial.c_str());
if (transport_write_action(transport_registration_send, &m)) {
fatal_errno("cannot write transport registration socket\n");
}
@@ -727,7 +721,7 @@
tmsg m;
m.transport = transport;
m.action = 0;
- D("transport: %s removed", transport->serial);
+ D("transport: %s removed", transport->serial.c_str());
if (transport_write_action(transport_registration_send, &m)) {
fatal_errno("cannot write transport registration socket\n");
}
@@ -743,38 +737,38 @@
if (t->ref_count == 0) {
t->connection()->Stop();
if (t->IsTcpDevice() && !t->kicked()) {
- D("transport: %s unref (attempting reconnection) %d", t->serial, t->kicked());
+ D("transport: %s unref (attempting reconnection) %d", t->serial.c_str(), t->kicked());
reconnect_handler.TrackTransport(t);
} else {
- D("transport: %s unref (kicking and closing)", t->serial);
+ D("transport: %s unref (kicking and closing)", t->serial.c_str());
remove_transport(t);
}
} else {
- D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
+ D("transport: %s unref (count=%zu)", t->serial.c_str(), t->ref_count);
}
}
-static int qual_match(const char* to_test, const char* prefix, const char* qual,
+static int qual_match(const std::string& to_test, const char* prefix, const std::string& qual,
bool sanitize_qual) {
- if (!to_test || !*to_test) /* Return true if both the qual and to_test are null strings. */
- return !qual || !*qual;
+ if (to_test.empty()) /* Return true if both the qual and to_test are empty strings. */
+ return qual.empty();
- if (!qual) return 0;
+ if (qual.empty()) return 0;
+ const char* ptr = to_test.c_str();
if (prefix) {
while (*prefix) {
- if (*prefix++ != *to_test++) return 0;
+ if (*prefix++ != *ptr++) return 0;
}
}
- while (*qual) {
- char ch = *qual++;
+ for (char ch : qual) {
if (sanitize_qual && !isalnum(ch)) ch = '_';
- if (ch != *to_test++) return 0;
+ if (ch != *ptr++) return 0;
}
- /* Everything matched so far. Return true if *to_test is a NUL. */
- return !*to_test;
+ /* Everything matched so far. Return true if *ptr is a NUL. */
+ return !*ptr;
}
atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
@@ -921,7 +915,7 @@
void atransport::Kick() {
if (!kicked_.exchange(true)) {
- D("kicking transport %p %s", this, this->serial);
+ D("kicking transport %p %s", this, this->serial.c_str());
this->connection()->Stop();
}
}
@@ -1040,7 +1034,7 @@
}
bool atransport::MatchesTarget(const std::string& target) const {
- if (serial) {
+ if (!serial.empty()) {
if (target == serial) {
return true;
} else if (type == kTransportLocal) {
@@ -1069,10 +1063,9 @@
}
}
- return (devpath && target == devpath) ||
- qual_match(target.c_str(), "product:", product, false) ||
- qual_match(target.c_str(), "model:", model, true) ||
- qual_match(target.c_str(), "device:", device, false);
+ return (target == devpath) || qual_match(target, "product:", product, false) ||
+ qual_match(target, "model:", model, true) ||
+ qual_match(target, "device:", device, false);
}
void atransport::SetConnectionEstablished(bool success) {
@@ -1093,9 +1086,9 @@
return str;
}
-static void append_transport_info(std::string* result, const char* key, const char* value,
+static void append_transport_info(std::string* result, const char* key, const std::string& value,
bool alphanumeric) {
- if (value == nullptr || *value == '\0') {
+ if (value.empty()) {
return;
}
@@ -1105,8 +1098,8 @@
}
static void append_transport(const atransport* t, std::string* result, bool long_listing) {
- const char* serial = t->serial;
- if (!serial || !serial[0]) {
+ std::string serial = t->serial;
+ if (serial.empty()) {
serial = "(no serial number)";
}
@@ -1115,7 +1108,8 @@
*result += '\t';
*result += t->connection_state_name();
} else {
- android::base::StringAppendF(result, "%-22s %s", serial, t->connection_state_name().c_str());
+ android::base::StringAppendF(result, "%-22s %s", serial.c_str(),
+ t->connection_state_name().c_str());
append_transport_info(result, "", t->devpath, false);
append_transport_info(result, "product:", t->product, false);
@@ -1138,7 +1132,7 @@
if (x->type != y->type) {
return x->type < y->type;
}
- return strcmp(x->serial, y->serial) < 0;
+ return x->serial < y->serial;
});
std::string result;
@@ -1181,7 +1175,7 @@
std::unique_lock<std::recursive_mutex> lock(transport_lock);
for (const auto& transport : pending_list) {
- if (transport->serial && strcmp(serial, transport->serial) == 0) {
+ if (strcmp(serial, transport->serial.c_str()) == 0) {
VLOG(TRANSPORT) << "socket transport " << transport->serial
<< " is already in pending_list and fails to register";
delete t;
@@ -1190,7 +1184,7 @@
}
for (const auto& transport : transport_list) {
- if (transport->serial && strcmp(serial, transport->serial) == 0) {
+ if (strcmp(serial, transport->serial.c_str()) == 0) {
VLOG(TRANSPORT) << "socket transport " << transport->serial
<< " is already in transport_list and fails to register";
delete t;
@@ -1199,7 +1193,7 @@
}
pending_list.push_front(t);
- t->serial = strdup(serial);
+ t->serial = serial;
lock.unlock();
@@ -1220,7 +1214,7 @@
std::lock_guard<std::recursive_mutex> lock(transport_lock);
for (auto& t : transport_list) {
- if (t->serial && strcmp(serial, t->serial) == 0) {
+ if (strcmp(serial, t->serial.c_str()) == 0) {
result = t;
break;
}
@@ -1251,11 +1245,11 @@
D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
init_usb_transport(t, usb);
if (serial) {
- t->serial = strdup(serial);
+ t->serial = serial;
}
if (devpath) {
- t->devpath = strdup(devpath);
+ t->devpath = devpath;
}
{
diff --git a/adb/transport.h b/adb/transport.h
index cb20615..e9c9d37 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -238,11 +238,11 @@
TransportType type = kTransportAny;
// Used to identify transports for clients.
- char* serial = nullptr;
- char* product = nullptr;
- char* model = nullptr;
- char* device = nullptr;
- char* devpath = nullptr;
+ std::string serial;
+ std::string product;
+ std::string model;
+ std::string device;
+ std::string devpath;
bool IsTcpDevice() const { return type == kTransportLocal; }
@@ -253,7 +253,7 @@
char token[TOKEN_SIZE] = {};
size_t failed_auth_attempts = 0;
- std::string serial_name() const { return serial ? serial : "<unknown>"; }
+ std::string serial_name() const { return !serial.empty() ? serial : "<unknown>"; }
std::string connection_state_name() const;
void update_version(int version, size_t payload);
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index d987d4f..8c628d8 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -86,9 +86,9 @@
ASSERT_EQ(0U, t.features().size());
ASSERT_EQ(kCsHost, t.GetConnectionState());
- ASSERT_EQ(nullptr, t.product);
- ASSERT_EQ(nullptr, t.model);
- ASSERT_EQ(nullptr, t.device);
+ ASSERT_EQ(std::string(), t.product);
+ ASSERT_EQ(std::string(), t.model);
+ ASSERT_EQ(std::string(), t.device);
}
TEST(transport, parse_banner_product_features) {
diff --git a/adb/types.h b/adb/types.h
index c6b3f07..a3e5d48 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -18,6 +18,7 @@
#include <algorithm>
#include <deque>
+#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
@@ -37,7 +38,7 @@
template <typename Iterator>
Block(Iterator begin, Iterator end) : Block(end - begin) {
- std::copy(begin, end, data_);
+ std::copy(begin, end, data_.get());
}
Block(const Block& copy) = delete;
@@ -73,11 +74,11 @@
void assign(InputIt begin, InputIt end) {
clear();
allocate(end - begin);
- std::copy(begin, end, data_);
+ std::copy(begin, end, data_.get());
}
void clear() {
- free(data_);
+ data_.reset();
capacity_ = 0;
size_ = 0;
}
@@ -86,11 +87,11 @@
size_t size() const { return size_; }
bool empty() const { return size() == 0; }
- char* data() { return data_; }
- const char* data() const { return data_; }
+ char* data() { return data_.get(); }
+ const char* data() const { return data_.get(); }
- char* begin() { return data_; }
- const char* begin() const { return data_; }
+ char* begin() { return data_.get(); }
+ const char* begin() const { return data_.get(); }
char* end() { return data() + size_; }
const char* end() const { return data() + size_; }
@@ -108,13 +109,13 @@
CHECK_EQ(0ULL, capacity_);
CHECK_EQ(0ULL, size_);
if (size != 0) {
- data_ = static_cast<char*>(malloc(size));
+ data_ = std::make_unique<char[]>(size);
capacity_ = size;
size_ = size;
}
}
- char* data_ = nullptr;
+ std::unique_ptr<char[]> data_;
size_t capacity_ = 0;
size_t size_ = 0;
};
diff --git a/base/Android.bp b/base/Android.bp
index 3d80d97..46a0233 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -135,6 +135,7 @@
"strings_test.cpp",
"test_main.cpp",
"test_utils_test.cpp",
+ "unique_fd_test.cpp",
],
target: {
android: {
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index fc68d56..bb54c99 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -47,7 +47,9 @@
if (max < result) {
return false;
}
- *out = static_cast<T>(result);
+ if (out != nullptr) {
+ *out = static_cast<T>(result);
+ }
return true;
}
@@ -87,7 +89,9 @@
if (result < min || max < result) {
return false;
}
- *out = static_cast<T>(result);
+ if (out != nullptr) {
+ *out = static_cast<T>(result);
+ }
return true;
}
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index c733081..c6936f1 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -42,10 +42,35 @@
//
// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
// you find this class if you're searching for one of those names.
+
+#if defined(__BIONIC__)
+#include <android/fdsan.h>
+#endif
+
namespace android {
namespace base {
struct DefaultCloser {
+#if defined(__BIONIC__)
+ static void Tag(int fd, void* old_addr, void* new_addr) {
+ if (android_fdsan_exchange_owner_tag) {
+ uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+ reinterpret_cast<uint64_t>(old_addr));
+ uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+ reinterpret_cast<uint64_t>(new_addr));
+ android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
+ }
+ }
+ static void Close(int fd, void* addr) {
+ if (android_fdsan_close_with_tag) {
+ uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
+ reinterpret_cast<uint64_t>(addr));
+ android_fdsan_close_with_tag(fd, tag);
+ } else {
+ close(fd);
+ }
+ }
+#else
static void Close(int fd) {
// Even if close(2) fails with EINTR, the fd will have been closed.
// Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
@@ -53,40 +78,75 @@
// http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
::close(fd);
}
+#endif
};
template <typename Closer>
class unique_fd_impl final {
public:
- unique_fd_impl() : value_(-1) {}
+ unique_fd_impl() {}
- explicit unique_fd_impl(int value) : value_(value) {}
+ explicit unique_fd_impl(int fd) { reset(fd); }
~unique_fd_impl() { reset(); }
- unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
+ unique_fd_impl(unique_fd_impl&& other) { reset(other.release()); }
unique_fd_impl& operator=(unique_fd_impl&& s) {
- reset(s.release());
+ int fd = s.fd_;
+ s.fd_ = -1;
+ reset(fd, &s);
return *this;
}
- void reset(int new_value = -1) {
- if (value_ != -1) {
- Closer::Close(value_);
- }
- value_ = new_value;
- }
+ void reset(int new_value = -1) { reset(new_value, nullptr); }
- int get() const { return value_; }
+ int get() const { return fd_; }
operator int() const { return get(); }
int release() __attribute__((warn_unused_result)) {
- int ret = value_;
- value_ = -1;
+ tag(fd_, this, nullptr);
+ int ret = fd_;
+ fd_ = -1;
return ret;
}
private:
- int value_;
+ void reset(int new_value, void* previous_tag) {
+ if (fd_ != -1) {
+ close(fd_, this);
+ }
+
+ fd_ = new_value;
+ if (new_value != -1) {
+ tag(new_value, previous_tag, this);
+ }
+ }
+
+ int fd_ = -1;
+
+ // Template magic to use Closer::Tag if available, and do nothing if not.
+ // If Closer::Tag exists, this implementation is preferred, because int is a better match.
+ // If not, this implementation is SFINAEd away, and the no-op below is the only one that exists.
+ template <typename T = Closer>
+ static auto tag(int fd, void* old_tag, void* new_tag)
+ -> decltype(T::Tag(fd, old_tag, new_tag), void()) {
+ T::Tag(fd, old_tag, new_tag);
+ }
+
+ template <typename T = Closer>
+ static void tag(long, void*, void*) {
+ // No-op.
+ }
+
+ // Same as above, to select between Closer::Close(int) and Closer::Close(int, void*).
+ template <typename T = Closer>
+ static auto close(int fd, void* tag_value) -> decltype(T::Close(fd, tag_value), void()) {
+ T::Close(fd, tag_value);
+ }
+
+ template <typename T = Closer>
+ static auto close(int fd, void*) -> decltype(T::Close(fd), void()) {
+ T::Close(fd);
+ }
unique_fd_impl(const unique_fd_impl&);
void operator=(const unique_fd_impl&);
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index fb1c339..8f9ed77 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -36,6 +36,10 @@
ASSERT_EQ(12, i);
ASSERT_FALSE(android::base::ParseInt("-12", &i, 0, 15));
ASSERT_FALSE(android::base::ParseInt("16", &i, 0, 15));
+
+ ASSERT_FALSE(android::base::ParseInt<int>("x", nullptr));
+ ASSERT_FALSE(android::base::ParseInt<int>("123x", nullptr));
+ ASSERT_TRUE(android::base::ParseInt<int>("1234", nullptr));
}
TEST(parseint, unsigned_smoke) {
@@ -55,6 +59,10 @@
ASSERT_EQ(12u, i);
ASSERT_FALSE(android::base::ParseUint("-12", &i, 15u));
ASSERT_FALSE(android::base::ParseUint("16", &i, 15u));
+
+ ASSERT_FALSE(android::base::ParseUint<unsigned short>("x", nullptr));
+ ASSERT_FALSE(android::base::ParseUint<unsigned short>("123x", nullptr));
+ ASSERT_TRUE(android::base::ParseUint<unsigned short>("1234", nullptr));
}
TEST(parseint, no_implicit_octal) {
diff --git a/base/unique_fd_test.cpp b/base/unique_fd_test.cpp
new file mode 100644
index 0000000..3fdf12a
--- /dev/null
+++ b/base/unique_fd_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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/unique_fd.h"
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+using android::base::unique_fd;
+
+TEST(unique_fd, unowned_close) {
+#if defined(__BIONIC__)
+ unique_fd fd(open("/dev/null", O_RDONLY));
+ EXPECT_DEATH(close(fd.get()), "incorrect tag");
+#endif
+}
+
+TEST(unique_fd, untag_on_release) {
+ unique_fd fd(open("/dev/null", O_RDONLY));
+ close(fd.release());
+}
+
+TEST(unique_fd, move) {
+ unique_fd fd(open("/dev/null", O_RDONLY));
+ unique_fd fd_moved = std::move(fd);
+ ASSERT_EQ(-1, fd.get());
+ ASSERT_GT(fd_moved.get(), -1);
+}
+
+TEST(unique_fd, unowned_close_after_move) {
+#if defined(__BIONIC__)
+ unique_fd fd(open("/dev/null", O_RDONLY));
+ unique_fd fd_moved = std::move(fd);
+ ASSERT_EQ(-1, fd.get());
+ ASSERT_GT(fd_moved.get(), -1);
+ EXPECT_DEATH(close(fd_moved.get()), "incorrect tag");
+#endif
+}
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
new file mode 100644
index 0000000..2b4a954
--- /dev/null
+++ b/fastboot/Android.bp
@@ -0,0 +1,56 @@
+cc_library_host_static {
+ name: "libfastboot2",
+
+ //host_supported: true,
+
+ compile_multilib: "first",
+ srcs: [
+ "bootimg_utils.cpp",
+ "fs.cpp",
+ "socket.cpp",
+ "tcp.cpp",
+ "udp.cpp",
+ "util.cpp",
+ "fastboot_driver.cpp",
+ ],
+
+ static_libs: [
+ "libziparchive",
+ "libsparse",
+ "libutils",
+ "liblog",
+ "libz",
+ "libdiagnose_usb",
+ "libbase",
+ "libcutils",
+ "libgtest",
+ "libgtest_main",
+ "libbase",
+ "libadb_host"
+ ],
+
+ header_libs: [
+ "bootimg_headers"
+ ],
+
+ export_header_lib_headers: [
+ "bootimg_headers"
+ ],
+
+
+ target: {
+ linux: {
+ srcs: ["usb_linux.cpp"],
+ },
+ },
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wunreachable-code",
+ ],
+
+ export_include_dirs: ["."],
+
+}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 983e195..60c338c 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -50,12 +50,12 @@
bootimg_utils.cpp \
engine.cpp \
fastboot.cpp \
- fs.cpp\
- protocol.cpp \
+ fs.cpp \
socket.cpp \
tcp.cpp \
udp.cpp \
util.cpp \
+ fastboot_driver.cpp \
LOCAL_SRC_FILES_darwin := usb_osx.cpp
LOCAL_SRC_FILES_linux := usb_linux.cpp
diff --git a/fastboot/OWNERS b/fastboot/OWNERS
index 2d12d50..2088ae3 100644
--- a/fastboot/OWNERS
+++ b/fastboot/OWNERS
@@ -1,3 +1,4 @@
dpursell@google.com
enh@google.com
jmgao@google.com
+tomcherry@google.com
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index c9814e4..1152007 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -28,7 +28,7 @@
#include "bootimg_utils.h"
-#include "fastboot.h"
+#include "util.h"
#include <stdio.h>
#include <stdlib.h>
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 1087573..63ee2af 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -25,8 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-
-#include "fastboot.h"
+#include "engine.h"
#include <errno.h>
#include <stdarg.h>
@@ -78,17 +77,20 @@
};
static std::vector<std::unique_ptr<Action>> action_list;
+static fastboot::FastBootDriver* fb = nullptr;
-bool fb_getvar(Transport* transport, const std::string& key, std::string* value) {
- std::string cmd = FB_CMD_GETVAR ":" + key;
+void fb_init(fastboot::FastBootDriver& fbi) {
+ fb = &fbi;
+ auto cb = [](std::string& info) { fprintf(stderr, "(bootloader) %s\n", info.c_str()); };
+ fb->SetInfoCallback(cb);
+}
- char buf[FB_RESPONSE_SZ + 1];
- memset(buf, 0, sizeof(buf));
- if (fb_command_response(transport, cmd, buf)) {
- return false;
- }
- *value = buf;
- return true;
+const std::string fb_get_error() {
+ return fb->Error();
+}
+
+bool fb_getvar(const std::string& key, std::string* value) {
+ return !fb->GetVar(key, value);
}
static int cb_default(Action& a, int status, const char* resp) {
@@ -310,7 +312,7 @@
queue_action(OP_WAIT_FOR_DISCONNECT, "");
}
-int64_t fb_execute_queue(Transport* transport) {
+int64_t fb_execute_queue() {
int64_t status = 0;
for (auto& a : action_list) {
a->start = now();
@@ -319,33 +321,34 @@
verbose("\n");
}
if (a->op == OP_DOWNLOAD) {
- status = fb_download_data(transport, a->data, a->size);
+ char* cbuf = static_cast<char*>(a->data);
+ status = fb->Download(cbuf, a->size);
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_DOWNLOAD_FD) {
- status = fb_download_data_fd(transport, a->fd, a->size);
+ status = fb->Download(a->fd, a->size);
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_COMMAND) {
- status = fb_command(transport, a->cmd);
+ status = fb->RawCommand(a->cmd);
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_QUERY) {
- char resp[FB_RESPONSE_SZ + 1] = {};
- status = fb_command_response(transport, a->cmd, resp);
- status = a->func(*a, status, status ? fb_get_error().c_str() : resp);
+ std::string resp;
+ status = fb->RawCommand(a->cmd, &resp);
+ status = a->func(*a, status, status ? fb_get_error().c_str() : resp.c_str());
if (status) break;
} else if (a->op == OP_NOTICE) {
// We already showed the notice because it's in `Action::msg`.
fprintf(stderr, "\n");
} else if (a->op == OP_DOWNLOAD_SPARSE) {
- status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
+ status = fb->Download(reinterpret_cast<sparse_file*>(a->data));
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_WAIT_FOR_DISCONNECT) {
- transport->WaitForDisconnect();
+ fb->WaitForDisconnect();
} else if (a->op == OP_UPLOAD) {
- status = fb_upload_data(transport, reinterpret_cast<char*>(a->data));
+ status = fb->Upload(reinterpret_cast<const char*>(a->data));
status = a->func(*a, status, status ? fb_get_error().c_str() : "");
} else {
die("unknown action: %d", a->op);
diff --git a/fastboot/fastboot.h b/fastboot/engine.h
similarity index 74%
rename from fastboot/fastboot.h
rename to fastboot/engine.h
index a93c0ac..74aaa6a 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/engine.h
@@ -34,23 +34,24 @@
#include <string>
#include <bootimg.h>
+#include "fastboot_driver.h"
+#include "util.h"
#include "constants.h"
class Transport;
struct sparse_file;
-/* protocol.c - fastboot protocol */
-int fb_command(Transport* transport, const std::string& cmd);
-int fb_command_response(Transport* transport, const std::string& cmd, char* response);
-int64_t fb_download_data(Transport* transport, const void* data, uint32_t size);
-int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size);
-int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
-int64_t fb_upload_data(Transport* transport, const char* outfile);
const std::string fb_get_error();
+//#define FB_COMMAND_SZ (fastboot::FB_COMMAND_SZ)
+//#define FB_RESPONSE_SZ (fastboot::FB_RESPONSE_SZ)
+
/* engine.c - high level command queue engine */
-bool fb_getvar(Transport* transport, const std::string& key, std::string* value);
+
+void fb_init(fastboot::FastBootDriver& fbi);
+
+bool fb_getvar(const std::string& key, std::string* value);
void fb_queue_flash(const std::string& partition, void* data, uint32_t sz);
void fb_queue_flash_fd(const std::string& partition, int fd, uint32_t sz);
void fb_queue_flash_sparse(const std::string& partition, struct sparse_file* s, uint32_t sz,
@@ -68,24 +69,13 @@
void fb_queue_upload(const std::string& outfile);
void fb_queue_notice(const std::string& notice);
void fb_queue_wait_for_disconnect(void);
-int64_t fb_execute_queue(Transport* transport);
+int64_t fb_execute_queue();
void fb_set_active(const std::string& slot);
-/* util stuff */
-double now();
-char* xstrdup(const char*);
-void set_verbose();
-
-// These printf-like functions are implemented in terms of vsnprintf, so they
-// use the same attribute for compile-time format string checking.
-void die(const char* fmt, ...) __attribute__((__noreturn__))
-__attribute__((__format__(__printf__, 1, 2)));
-void verbose(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
-
/* Current product */
extern char cur_product[FB_RESPONSE_SZ + 1];
-class FastBoot {
+class FastBootTool {
public:
int Main(int argc, char* argv[]);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 5aa87d9..263ea17 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -60,7 +60,7 @@
#include "bootimg_utils.h"
#include "diagnose_usb.h"
-#include "fastboot.h"
+#include "engine.h"
#include "fs.h"
#include "tcp.h"
#include "transport.h"
@@ -592,7 +592,7 @@
}
#define MAX_OPTIONS 32
-static void check_requirement(Transport* transport, char* line) {
+static void check_requirement(char* line) {
char *val[MAX_OPTIONS];
unsigned count;
char *x;
@@ -635,7 +635,7 @@
if (!strcmp(name, "partition-exists")) {
const char* partition_name = val[0];
std::string has_slot;
- if (!fb_getvar(transport, std::string("has-slot:") + partition_name, &has_slot) ||
+ if (!fb_getvar(std::string("has-slot:") + partition_name, &has_slot) ||
(has_slot != "yes" && has_slot != "no")) {
die("device doesn't have required partition %s!", partition_name);
}
@@ -674,18 +674,18 @@
fb_queue_require(product, var, invert, count, out);
}
-static void check_requirements(Transport* transport, char* data, int64_t sz) {
+static void check_requirements(char* data, int64_t sz) {
char* s = data;
while (sz-- > 0) {
if (*s == '\n') {
*s++ = 0;
- check_requirement(transport, data);
+ check_requirement(data);
data = s;
} else {
s++;
}
}
- if (fb_execute_queue(transport)) die("requirements not met!");
+ if (fb_execute_queue()) die("requirements not met!");
}
static void queue_info_dump() {
@@ -716,9 +716,9 @@
return out_s;
}
-static int64_t get_target_sparse_limit(Transport* transport) {
+static int64_t get_target_sparse_limit() {
std::string max_download_size;
- if (!fb_getvar(transport, "max-download-size", &max_download_size) ||
+ if (!fb_getvar("max-download-size", &max_download_size) ||
max_download_size.empty()) {
verbose("target didn't report max-download-size");
return 0;
@@ -736,13 +736,13 @@
return limit;
}
-static int64_t get_sparse_limit(Transport* transport, int64_t size) {
+static int64_t get_sparse_limit(int64_t size) {
int64_t limit = sparse_limit;
if (limit == 0) {
// Unlimited, so see what the target device's limit is.
// TODO: shouldn't we apply this limit even if you've used -S?
if (target_sparse_limit == -1) {
- target_sparse_limit = get_target_sparse_limit(transport);
+ target_sparse_limit = get_target_sparse_limit();
}
if (target_sparse_limit > 0) {
limit = target_sparse_limit;
@@ -758,14 +758,14 @@
return 0;
}
-static bool load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
+static bool load_buf_fd(int fd, struct fastboot_buffer* buf) {
int64_t sz = get_file_size(fd);
if (sz == -1) {
return false;
}
lseek64(fd, 0, SEEK_SET);
- int64_t limit = get_sparse_limit(transport, sz);
+ int64_t limit = get_sparse_limit(sz);
if (limit) {
sparse_file** s = load_sparse_files(fd, limit);
if (s == nullptr) {
@@ -783,7 +783,7 @@
return true;
}
-static bool load_buf(Transport* transport, const char* fname, struct fastboot_buffer* buf) {
+static bool load_buf(const char* fname, struct fastboot_buffer* buf) {
unique_fd fd(TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_BINARY)));
if (fd == -1) {
@@ -799,7 +799,7 @@
return false;
}
- return load_buf_fd(transport, fd.release(), buf);
+ return load_buf_fd(fd.release(), buf);
}
static void rewrite_vbmeta_buffer(struct fastboot_buffer* buf) {
@@ -871,23 +871,23 @@
}
}
-static std::string get_current_slot(Transport* transport) {
+static std::string get_current_slot() {
std::string current_slot;
- if (!fb_getvar(transport, "current-slot", ¤t_slot)) return "";
+ if (!fb_getvar("current-slot", ¤t_slot)) return "";
return current_slot;
}
-static int get_slot_count(Transport* transport) {
+static int get_slot_count() {
std::string var;
int count = 0;
- if (!fb_getvar(transport, "slot-count", &var) || !android::base::ParseInt(var, &count)) {
+ if (!fb_getvar("slot-count", &var) || !android::base::ParseInt(var, &count)) {
return 0;
}
return count;
}
-static bool supports_AB(Transport* transport) {
- return get_slot_count(transport) >= 2;
+static bool supports_AB() {
+ return get_slot_count() >= 2;
}
// Given a current slot, this returns what the 'other' slot is.
@@ -898,25 +898,25 @@
return std::string(1, next);
}
-static std::string get_other_slot(Transport* transport, const std::string& current_slot) {
- return get_other_slot(current_slot, get_slot_count(transport));
+static std::string get_other_slot(const std::string& current_slot) {
+ return get_other_slot(current_slot, get_slot_count());
}
-static std::string get_other_slot(Transport* transport, int count) {
- return get_other_slot(get_current_slot(transport), count);
+static std::string get_other_slot(int count) {
+ return get_other_slot(get_current_slot(), count);
}
-static std::string get_other_slot(Transport* transport) {
- return get_other_slot(get_current_slot(transport), get_slot_count(transport));
+static std::string get_other_slot() {
+ return get_other_slot(get_current_slot(), get_slot_count());
}
-static std::string verify_slot(Transport* transport, const std::string& slot_name, bool allow_all) {
+static std::string verify_slot(const std::string& slot_name, bool allow_all) {
std::string slot = slot_name;
if (slot == "all") {
if (allow_all) {
return "all";
} else {
- int count = get_slot_count(transport);
+ int count = get_slot_count();
if (count > 0) {
return "a";
} else {
@@ -925,11 +925,11 @@
}
}
- int count = get_slot_count(transport);
+ int count = get_slot_count();
if (count == 0) die("Device does not support slots");
if (slot == "other") {
- std::string other = get_other_slot(transport, count);
+ std::string other = get_other_slot( count);
if (other == "") {
die("No known slots");
}
@@ -946,22 +946,22 @@
exit(1);
}
-static std::string verify_slot(Transport* transport, const std::string& slot) {
- return verify_slot(transport, slot, true);
+static std::string verify_slot(const std::string& slot) {
+ return verify_slot(slot, true);
}
-static void do_for_partition(Transport* transport, const std::string& part, const std::string& slot,
+static void do_for_partition(const std::string& part, const std::string& slot,
const std::function<void(const std::string&)>& func, bool force_slot) {
std::string has_slot;
std::string current_slot;
- if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
+ if (!fb_getvar("has-slot:" + part, &has_slot)) {
/* If has-slot is not supported, the answer is no. */
has_slot = "no";
}
if (has_slot == "yes") {
if (slot == "") {
- current_slot = get_current_slot(transport);
+ current_slot = get_current_slot();
if (current_slot == "") {
die("Failed to identify current slot");
}
@@ -983,30 +983,30 @@
* partition names. If force_slot is true, it will fail if a slot is specified, and the given
* partition does not support slots.
*/
-static void do_for_partitions(Transport* transport, const std::string& part, const std::string& slot,
+static void do_for_partitions(const std::string& part, const std::string& slot,
const std::function<void(const std::string&)>& func, bool force_slot) {
std::string has_slot;
if (slot == "all") {
- if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
+ if (!fb_getvar("has-slot:" + part, &has_slot)) {
die("Could not check if partition %s has slot %s", part.c_str(), slot.c_str());
}
if (has_slot == "yes") {
- for (int i=0; i < get_slot_count(transport); i++) {
- do_for_partition(transport, part, std::string(1, (char)(i + 'a')), func, force_slot);
+ for (int i=0; i < get_slot_count(); i++) {
+ do_for_partition(part, std::string(1, (char)(i + 'a')), func, force_slot);
}
} else {
- do_for_partition(transport, part, "", func, force_slot);
+ do_for_partition(part, "", func, force_slot);
}
} else {
- do_for_partition(transport, part, slot, func, force_slot);
+ do_for_partition(part, slot, func, force_slot);
}
}
-static void do_flash(Transport* transport, const char* pname, const char* fname) {
+static void do_flash(const char* pname, const char* fname) {
struct fastboot_buffer buf;
- if (!load_buf(transport, fname, &buf)) {
+ if (!load_buf(fname, &buf)) {
die("cannot load '%s': %s", fname, strerror(errno));
}
flash_buf(pname, &buf);
@@ -1022,20 +1022,20 @@
// Sets slot_override as the active slot. If slot_override is blank,
// set current slot as active instead. This clears slot-unbootable.
-static void set_active(Transport* transport, const std::string& slot_override) {
- if (!supports_AB(transport)) return;
+static void set_active(const std::string& slot_override) {
+ if (!supports_AB()) return;
if (slot_override != "") {
fb_set_active(slot_override);
} else {
- std::string current_slot = get_current_slot(transport);
+ std::string current_slot = get_current_slot();
if (current_slot != "") {
fb_set_active(current_slot);
}
}
}
-static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool skip_secondary) {
+static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) {
queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -1052,17 +1052,17 @@
die("update package '%s' has no android-info.txt", filename);
}
- check_requirements(transport, reinterpret_cast<char*>(data), sz);
+ check_requirements(reinterpret_cast<char*>(data), sz);
std::string secondary;
if (!skip_secondary) {
if (slot_override != "") {
- secondary = get_other_slot(transport, slot_override);
+ secondary = get_other_slot(slot_override);
} else {
- secondary = get_other_slot(transport);
+ secondary = get_other_slot();
}
if (secondary == "") {
- if (supports_AB(transport)) {
+ if (supports_AB()) {
fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
}
skip_secondary = true;
@@ -1087,7 +1087,7 @@
}
fastboot_buffer buf;
- if (!load_buf_fd(transport, fd, &buf)) {
+ if (!load_buf_fd(fd, &buf)) {
die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
}
@@ -1099,13 +1099,13 @@
* program exits.
*/
};
- do_for_partitions(transport, images[i].part_name, slot, update, false);
+ do_for_partitions(images[i].part_name, slot, update, false);
}
if (slot_override == "all") {
- set_active(transport, "a");
+ set_active("a");
} else {
- set_active(transport, slot_override);
+ set_active(slot_override);
}
CloseArchive(zip);
@@ -1125,7 +1125,7 @@
fb_queue_command("signature", "installing signature");
}
-static void do_flashall(Transport* transport, const std::string& slot_override, bool skip_secondary) {
+static void do_flashall(const std::string& slot_override, bool skip_secondary) {
std::string fname;
queue_info_dump();
@@ -1138,17 +1138,17 @@
void* data = load_file(fname.c_str(), &sz);
if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno));
- check_requirements(transport, reinterpret_cast<char*>(data), sz);
+ check_requirements(reinterpret_cast<char*>(data), sz);
std::string secondary;
if (!skip_secondary) {
if (slot_override != "") {
- secondary = get_other_slot(transport, slot_override);
+ secondary = get_other_slot(slot_override);
} else {
- secondary = get_other_slot(transport);
+ secondary = get_other_slot();
}
if (secondary == "") {
- if (supports_AB(transport)) {
+ if (supports_AB()) {
fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
}
skip_secondary = true;
@@ -1165,7 +1165,7 @@
if (!slot) continue;
fname = find_item_given_name(images[i].img_name);
fastboot_buffer buf;
- if (!load_buf(transport, fname.c_str(), &buf)) {
+ if (!load_buf(fname.c_str(), &buf)) {
if (images[i].is_optional) continue;
die("could not load '%s': %s", images[i].img_name, strerror(errno));
}
@@ -1174,13 +1174,13 @@
do_send_signature(fname.c_str());
flash_buf(partition.c_str(), &buf);
};
- do_for_partitions(transport, images[i].part_name, slot, flashall, false);
+ do_for_partitions(images[i].part_name, slot, flashall, false);
}
if (slot_override == "all") {
- set_active(transport, "a");
+ set_active("a");
} else {
- set_active(transport, slot_override);
+ set_active(slot_override);
}
}
@@ -1210,9 +1210,9 @@
return var;
}
-static unsigned fb_get_flash_block_size(Transport* transport, std::string name) {
+static unsigned fb_get_flash_block_size(std::string name) {
std::string sizeString;
- if (!fb_getvar(transport, name, &sizeString) || sizeString.empty()) {
+ if (!fb_getvar(name, &sizeString) || sizeString.empty()) {
// This device does not report flash block sizes, so return 0.
return 0;
}
@@ -1230,7 +1230,7 @@
return size;
}
-static void fb_perform_format(Transport* transport,
+static void fb_perform_format(
const std::string& partition, int skip_if_not_supported,
const std::string& type_override, const std::string& size_override,
const std::string& initial_dir) {
@@ -1250,7 +1250,7 @@
limit = sparse_limit;
}
- if (!fb_getvar(transport, "partition-type:" + partition, &partition_type)) {
+ if (!fb_getvar("partition-type:" + partition, &partition_type)) {
errMsg = "Can't determine partition type.\n";
goto failed;
}
@@ -1262,7 +1262,7 @@
partition_type = type_override;
}
- if (!fb_getvar(transport, "partition-size:" + partition, &partition_size)) {
+ if (!fb_getvar("partition-size:" + partition, &partition_size)) {
errMsg = "Unable to get partition size\n";
goto failed;
}
@@ -1294,8 +1294,8 @@
}
unsigned eraseBlkSize, logicalBlkSize;
- eraseBlkSize = fb_get_flash_block_size(transport, "erase-block-size");
- logicalBlkSize = fb_get_flash_block_size(transport, "logical-block-size");
+ eraseBlkSize = fb_get_flash_block_size("erase-block-size");
+ logicalBlkSize = fb_get_flash_block_size("logical-block-size");
if (fs_generator_generate(gen, output.path, size, initial_dir,
eraseBlkSize, logicalBlkSize)) {
@@ -1308,7 +1308,7 @@
fprintf(stderr, "Cannot open generated image: %s\n", strerror(errno));
return;
}
- if (!load_buf_fd(transport, fd.release(), &buf)) {
+ if (!load_buf_fd(fd.release(), &buf)) {
fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
return;
}
@@ -1323,7 +1323,7 @@
fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str());
}
-int FastBoot::Main(int argc, char* argv[]) {
+int FastBootTool::Main(int argc, char* argv[]) {
bool wants_wipe = false;
bool wants_reboot = false;
bool wants_reboot_bootloader = false;
@@ -1470,23 +1470,25 @@
if (transport == nullptr) {
return 1;
}
+ fastboot::FastBootDriver fb(transport);
+ fb_init(fb);
const double start = now();
- if (slot_override != "") slot_override = verify_slot(transport, slot_override);
- if (next_active != "") next_active = verify_slot(transport, next_active, false);
+ if (slot_override != "") slot_override = verify_slot(slot_override);
+ if (next_active != "") next_active = verify_slot(next_active, false);
if (wants_set_active) {
if (next_active == "") {
if (slot_override == "") {
std::string current_slot;
- if (fb_getvar(transport, "current-slot", ¤t_slot)) {
- next_active = verify_slot(transport, current_slot, false);
+ if (fb_getvar("current-slot", ¤t_slot)) {
+ next_active = verify_slot(current_slot, false);
} else {
wants_set_active = false;
}
} else {
- next_active = verify_slot(transport, slot_override, false);
+ next_active = verify_slot(slot_override, false);
}
}
}
@@ -1502,7 +1504,7 @@
std::string partition = next_arg(&args);
auto erase = [&](const std::string& partition) {
std::string partition_type;
- if (fb_getvar(transport, std::string("partition-type:") + partition,
+ if (fb_getvar(std::string("partition-type:") + partition,
&partition_type) &&
fs_get_generator(partition_type) != nullptr) {
fprintf(stderr, "******** Did you mean to fastboot format this %s partition?\n",
@@ -1511,7 +1513,7 @@
fb_queue_erase(partition);
};
- do_for_partitions(transport, partition, slot_override, erase, true);
+ do_for_partitions(partition, slot_override, erase, true);
} else if (android::base::StartsWith(command, "format")) {
// Parsing for: "format[:[type][:[size]]]"
// Some valid things:
@@ -1529,9 +1531,9 @@
std::string partition = next_arg(&args);
auto format = [&](const std::string& partition) {
- fb_perform_format(transport, partition, 0, type_override, size_override, "");
+ fb_perform_format(partition, 0, type_override, size_override, "");
};
- do_for_partitions(transport, partition.c_str(), slot_override, format, true);
+ do_for_partitions(partition.c_str(), slot_override, format, true);
} else if (command == "signature") {
std::string filename = next_arg(&args);
data = load_file(filename.c_str(), &sz);
@@ -1579,9 +1581,9 @@
if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str());
auto flash = [&](const std::string &partition) {
- do_flash(transport, partition.c_str(), fname.c_str());
+ do_flash(partition.c_str(), fname.c_str());
};
- do_for_partitions(transport, pname.c_str(), slot_override, flash, true);
+ do_for_partitions(pname.c_str(), slot_override, flash, true);
} else if (command == "flash:raw") {
std::string partition = next_arg(&args);
std::string kernel = next_arg(&args);
@@ -1594,13 +1596,13 @@
auto flashraw = [&](const std::string& partition) {
fb_queue_flash(partition, data, sz);
};
- do_for_partitions(transport, partition, slot_override, flashraw, true);
+ do_for_partitions(partition, slot_override, flashraw, true);
} else if (command == "flashall") {
if (slot_override == "all") {
fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
- do_flashall(transport, slot_override, true);
+ do_flashall(slot_override, true);
} else {
- do_flashall(transport, slot_override, skip_secondary);
+ do_flashall(slot_override, skip_secondary);
}
wants_reboot = true;
} else if (command == "update") {
@@ -1612,16 +1614,16 @@
if (!args.empty()) {
filename = next_arg(&args);
}
- do_update(transport, filename.c_str(), slot_override, skip_secondary || slot_all);
+ do_update(filename.c_str(), slot_override, skip_secondary || slot_all);
wants_reboot = true;
} else if (command == "set_active") {
- std::string slot = verify_slot(transport, next_arg(&args), false);
+ std::string slot = verify_slot(next_arg(&args), false);
fb_set_active(slot);
} else if (command == "stage") {
std::string filename = next_arg(&args);
struct fastboot_buffer buf;
- if (!load_buf(transport, filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
+ if (!load_buf(filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
die("cannot load '%s'", filename.c_str());
}
fb_queue_download_fd(filename, buf.fd, buf.sz);
@@ -1650,16 +1652,16 @@
std::vector<std::string> partitions = { "userdata", "cache", "metadata" };
for (const auto& partition : partitions) {
std::string partition_type;
- if (!fb_getvar(transport, std::string{"partition-type:"} + partition, &partition_type)) continue;
+ if (!fb_getvar(std::string{"partition-type:"} + partition, &partition_type)) continue;
if (partition_type.empty()) continue;
fb_queue_erase(partition);
if (partition == "userdata" && set_fbe_marker) {
fprintf(stderr, "setting FBE marker on initial userdata...\n");
std::string initial_userdata_dir = create_fbemarker_tmpdir();
- fb_perform_format(transport, partition, 1, "", "", initial_userdata_dir);
+ fb_perform_format(partition, 1, "", "", initial_userdata_dir);
delete_fbemarker_tmpdir(initial_userdata_dir);
} else {
- fb_perform_format(transport, partition, 1, "", "", "");
+ fb_perform_format(partition, 1, "", "", "");
}
}
}
@@ -1674,12 +1676,12 @@
fb_queue_wait_for_disconnect();
}
- int status = fb_execute_queue(transport) ? EXIT_FAILURE : EXIT_SUCCESS;
+ int status = fb_execute_queue() ? EXIT_FAILURE : EXIT_SUCCESS;
fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
return status;
}
-void FastBoot::ParseOsPatchLevel(boot_img_hdr_v1* hdr, const char* arg) {
+void FastBootTool::ParseOsPatchLevel(boot_img_hdr_v1* hdr, const char* arg) {
unsigned year, month, day;
if (sscanf(arg, "%u-%u-%u", &year, &month, &day) != 3) {
syntax_error("OS patch level should be YYYY-MM-DD: %s", arg);
@@ -1689,7 +1691,7 @@
hdr->SetOsPatchLevel(year, month);
}
-void FastBoot::ParseOsVersion(boot_img_hdr_v1* hdr, const char* arg) {
+void FastBootTool::ParseOsVersion(boot_img_hdr_v1* hdr, const char* arg) {
unsigned major = 0, minor = 0, patch = 0;
std::vector<std::string> versions = android::base::Split(arg, ".");
if (versions.size() < 1 || versions.size() > 3 ||
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
new file mode 100644
index 0000000..c308420
--- /dev/null
+++ b/fastboot/fastboot_driver.cpp
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "fastboot_driver.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+#include <chrono>
+#include <fstream>
+#include <memory>
+#include <regex>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <utils/FileMap.h>
+#include "fastboot_driver.h"
+#include "transport.h"
+
+namespace fastboot {
+
+/*************************** PUBLIC *******************************/
+FastBootDriver::FastBootDriver(Transport* transport, std::function<void(std::string&)> info,
+ bool no_checks)
+ : transport(transport) {
+ info_cb_ = info;
+ disable_checks_ = no_checks;
+}
+
+RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
+ return RawCommand(Commands::BOOT, response, info);
+}
+
+RetCode FastBootDriver::Continue(std::string* response, std::vector<std::string>* info) {
+ return RawCommand(Commands::CONTINUE, response, info);
+}
+
+RetCode FastBootDriver::Erase(const std::string& part, std::string* response,
+ std::vector<std::string>* info) {
+ return RawCommand(Commands::ERASE + part, response, info);
+}
+
+RetCode FastBootDriver::Flash(const std::string& part, std::string* response,
+ std::vector<std::string>* info) {
+ return RawCommand(Commands::FLASH + part, response, info);
+}
+
+RetCode FastBootDriver::GetVar(const std::string& key, std::string* val,
+ std::vector<std::string>* info) {
+ return RawCommand(Commands::GET_VAR + key, val, info);
+}
+
+RetCode FastBootDriver::GetVarAll(std::vector<std::string>* response) {
+ std::string tmp;
+ return GetVar("all", &tmp, response);
+}
+
+RetCode FastBootDriver::Powerdown(std::string* response, std::vector<std::string>* info) {
+ return RawCommand(Commands::POWERDOWN, response, info);
+}
+
+RetCode FastBootDriver::Reboot(std::string* response, std::vector<std::string>* info) {
+ return RawCommand(Commands::REBOOT, response, info);
+}
+
+RetCode FastBootDriver::SetActive(const std::string& part, std::string* response,
+ std::vector<std::string>* info) {
+ return RawCommand(Commands::SET_ACTIVE + part, response, info);
+}
+
+RetCode FastBootDriver::Verify(uint32_t num, std::string* response, std::vector<std::string>* info) {
+ std::string cmd = android::base::StringPrintf("%s%08" PRIx32, Commands::VERIFY.c_str(), num);
+ return RawCommand(cmd, response, info);
+}
+
+RetCode FastBootDriver::FlashPartition(const std::string& part, const std::vector<char>& data) {
+ RetCode ret;
+ if ((ret = Download(data))) {
+ return ret;
+ }
+ return RawCommand(Commands::FLASH + part);
+}
+
+RetCode FastBootDriver::FlashPartition(const std::string& part, int fd, uint32_t sz) {
+ RetCode ret;
+ if ((ret = Download(fd, sz))) {
+ return ret;
+ }
+ return RawCommand(Commands::FLASH + part);
+}
+
+RetCode FastBootDriver::FlashPartition(const std::string& part, sparse_file* s) {
+ RetCode ret;
+ if ((ret = Download(s))) {
+ return ret;
+ }
+ return RawCommand(Commands::FLASH + part);
+}
+
+RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint32_t>>* parts) {
+ std::vector<std::string> all;
+ RetCode ret;
+ if ((ret = GetVarAll(&all))) {
+ return ret;
+ }
+
+ std::regex reg("partition-size[[:s:]]*:[[:s:]]*([[:w:]]+)[[:s:]]*:[[:s:]]*0x([[:d:]]+)");
+ std::smatch sm;
+
+ for (auto& s : all) {
+ if (std::regex_match(s, sm, reg)) {
+ std::string m1(sm[1]);
+ std::string m2(sm[2]);
+ uint32_t tmp = strtol(m2.c_str(), 0, 16);
+ parts->push_back(std::make_tuple(m1, tmp));
+ }
+ }
+ return SUCCESS;
+}
+
+RetCode FastBootDriver::Require(const std::string& var, const std::vector<std::string>& allowed,
+ bool* reqmet, bool invert) {
+ *reqmet = invert;
+ RetCode ret;
+ std::string response;
+ if ((ret = GetVar(var, &response))) {
+ return ret;
+ }
+
+ // Now check if we have a match
+ for (const auto s : allowed) {
+ // If it ends in *, and starting substring match
+ if (response == s || (s.length() && s.back() == '*' &&
+ !response.compare(0, s.length() - 1, s, 0, s.length() - 1))) {
+ *reqmet = !invert;
+ break;
+ }
+ }
+
+ return SUCCESS;
+}
+
+RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
+ std::vector<std::string>* info) {
+ RetCode ret;
+
+ if ((size <= 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
+ error_ = "File is too large to download";
+ return BAD_ARG;
+ }
+
+ uint32_t u32size = static_cast<uint32_t>(size);
+ if ((ret = DownloadCommand(u32size, response, info))) {
+ return ret;
+ }
+
+ // Write the buffer
+ if ((ret = SendBuffer(fd, size))) {
+ return ret;
+ }
+
+ // Wait for response
+ return HandleResponse(response, info);
+}
+
+RetCode FastBootDriver::Download(const std::vector<char>& buf, std::string* response,
+ std::vector<std::string>* info) {
+ return Download(buf.data(), buf.size(), response, info);
+}
+
+RetCode FastBootDriver::Download(const char* buf, uint32_t size, std::string* response,
+ std::vector<std::string>* info) {
+ RetCode ret;
+ error_ = "";
+ if ((size == 0 || size > MAX_DOWNLOAD_SIZE) && !disable_checks_) {
+ error_ = "Buffer is too large or 0 bytes";
+ return BAD_ARG;
+ }
+
+ if ((ret = DownloadCommand(size, response, info))) {
+ return ret;
+ }
+
+ // Write the buffer
+ if ((ret = SendBuffer(buf, size))) {
+ return ret;
+ }
+
+ // Wait for response
+ return HandleResponse(response, info);
+}
+
+RetCode FastBootDriver::Download(sparse_file* s, std::string* response,
+ std::vector<std::string>* info) {
+ error_ = "";
+ int64_t size = sparse_file_len(s, true, false);
+ if (size <= 0 || size > MAX_DOWNLOAD_SIZE) {
+ error_ = "Sparse file is too large or invalid";
+ return BAD_ARG;
+ }
+
+ RetCode ret;
+ uint32_t u32size = static_cast<uint32_t>(size);
+ if ((ret = DownloadCommand(u32size, response, info))) {
+ return ret;
+ }
+
+ struct SparseCBPrivate {
+ FastBootDriver* self;
+ std::vector<char> tpbuf;
+ } cb_priv;
+ cb_priv.self = this;
+
+ auto cb = [](void* priv, const void* buf, size_t len) -> int {
+ SparseCBPrivate* data = static_cast<SparseCBPrivate*>(priv);
+ const char* cbuf = static_cast<const char*>(buf);
+ return data->self->SparseWriteCallback(data->tpbuf, cbuf, len);
+ };
+
+ if (sparse_file_callback(s, true, false, cb, &cb_priv) < 0) {
+ error_ = "Error reading sparse file";
+ return IO_ERROR;
+ }
+
+ // Now flush
+ if (cb_priv.tpbuf.size() && (ret = SendBuffer(cb_priv.tpbuf))) {
+ return ret;
+ }
+
+ return HandleResponse(response, info);
+}
+
+RetCode FastBootDriver::Upload(const std::string& outfile, std::string* response,
+ std::vector<std::string>* info) {
+ RetCode ret;
+ int dsize;
+ if ((ret = RawCommand(Commands::UPLOAD, response, info, &dsize)) || dsize == 0) {
+ error_ = "Upload request failed";
+ return ret;
+ }
+
+ std::vector<char> data;
+ data.resize(dsize);
+
+ if ((ret = ReadBuffer(data))) {
+ return ret;
+ }
+
+ std::ofstream ofs;
+ ofs.open(outfile, std::ofstream::out | std::ofstream::binary);
+ if (ofs.fail()) {
+ error_ = android::base::StringPrintf("Failed to open '%s'", outfile.c_str());
+ return IO_ERROR;
+ }
+ ofs.write(data.data(), data.size());
+ if (ofs.fail() || ofs.bad()) {
+ error_ = android::base::StringPrintf("Writing to '%s' failed", outfile.c_str());
+ return IO_ERROR;
+ }
+ ofs.close();
+
+ return HandleResponse(response, info);
+}
+
+// Helpers
+void FastBootDriver::SetInfoCallback(std::function<void(std::string&)> info) {
+ info_cb_ = info;
+}
+
+const std::string FastBootDriver::RCString(RetCode rc) {
+ switch (rc) {
+ case SUCCESS:
+ return std::string("Success");
+
+ case BAD_ARG:
+ return std::string("Invalid Argument");
+
+ case IO_ERROR:
+ return std::string("I/O Error");
+
+ case BAD_DEV_RESP:
+ return std::string("Invalid Device Response");
+
+ case DEVICE_FAIL:
+ return std::string("Device Error");
+
+ case TIMEOUT:
+ return std::string("Timeout");
+
+ default:
+ return std::string("Unknown Error");
+ }
+}
+
+std::string FastBootDriver::Error() {
+ return error_;
+}
+
+RetCode FastBootDriver::WaitForDisconnect() {
+ return transport->WaitForDisconnect() ? IO_ERROR : SUCCESS;
+}
+
+/****************************** PROTECTED *************************************/
+RetCode FastBootDriver::RawCommand(const std::string& cmd, std::string* response,
+ std::vector<std::string>* info, int* dsize) {
+ error_ = ""; // Clear any pending error
+ if (cmd.size() > FB_COMMAND_SZ && !disable_checks_) {
+ error_ = "Command length to RawCommand() is too long";
+ return BAD_ARG;
+ }
+
+ if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
+ error_ = ErrnoStr("Write to device failed");
+ return IO_ERROR;
+ }
+
+ // Read the response
+ return HandleResponse(response, info, dsize);
+}
+
+RetCode FastBootDriver::DownloadCommand(uint32_t size, std::string* response,
+ std::vector<std::string>* info) {
+ std::string cmd(android::base::StringPrintf("%s%08" PRIx32, Commands::DOWNLOAD.c_str(), size));
+ RetCode ret;
+ if ((ret = RawCommand(cmd, response, info))) {
+ return ret;
+ }
+ return SUCCESS;
+}
+
+RetCode FastBootDriver::HandleResponse(std::string* response, std::vector<std::string>* info,
+ int* dsize) {
+ char status[FB_RESPONSE_SZ + 1];
+ auto start = std::chrono::system_clock::now();
+
+ auto set_response = [response](std::string s) {
+ if (response) *response = std::move(s);
+ };
+ auto add_info = [info](std::string s) {
+ if (info) info->push_back(std::move(s));
+ };
+
+ // erase response
+ set_response("");
+ while ((std::chrono::system_clock::now() - start) < std::chrono::seconds(RESP_TIMEOUT)) {
+ int r = transport->Read(status, FB_RESPONSE_SZ);
+ if (r < 0) {
+ error_ = ErrnoStr("Status read failed");
+ return IO_ERROR;
+ }
+
+ status[r] = '\0'; // Need the null terminator
+ std::string input(status);
+ if (android::base::StartsWith(input, "INFO")) {
+ std::string tmp = input.substr(strlen("INFO"));
+ info_cb_(tmp);
+ add_info(std::move(tmp));
+ } else if (android::base::StartsWith(input, "OKAY")) {
+ set_response(input.substr(strlen("OKAY")));
+ return SUCCESS;
+ } else if (android::base::StartsWith(input, "FAIL")) {
+ error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
+ set_response(input.substr(strlen("FAIL")));
+ return DEVICE_FAIL;
+ } else if (android::base::StartsWith(input, "DATA")) {
+ std::string tmp = input.substr(strlen("DATA"));
+ uint32_t num = strtol(tmp.c_str(), 0, 16);
+ if (num > MAX_DOWNLOAD_SIZE) {
+ error_ = android::base::StringPrintf("Data size too large (%d)", num);
+ return BAD_DEV_RESP;
+ }
+ if (dsize) *dsize = num;
+ set_response(std::move(tmp));
+ return SUCCESS;
+ } else {
+ error_ = android::base::StringPrintf("Device sent unknown status code: %s", status);
+ return BAD_DEV_RESP;
+ }
+
+ } // End of while loop
+
+ return TIMEOUT;
+}
+
+std::string FastBootDriver::ErrnoStr(const std::string& msg) {
+ return android::base::StringPrintf("%s (%s)", msg.c_str(), strerror(errno));
+}
+
+const std::string FastBootDriver::Commands::BOOT = "boot";
+const std::string FastBootDriver::Commands::CONTINUE = "continue";
+const std::string FastBootDriver::Commands::DOWNLOAD = "download:";
+const std::string FastBootDriver::Commands::ERASE = "erase:";
+const std::string FastBootDriver::Commands::FLASH = "flash:";
+const std::string FastBootDriver::Commands::GET_VAR = "getvar:";
+const std::string FastBootDriver::Commands::POWERDOWN = "powerdown";
+const std::string FastBootDriver::Commands::REBOOT = "reboot";
+const std::string FastBootDriver::Commands::SET_ACTIVE = "set_active:";
+const std::string FastBootDriver::Commands::UPLOAD = "upload";
+const std::string FastBootDriver::Commands::VERIFY = "verify:";
+
+/******************************* PRIVATE **************************************/
+RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
+ static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
+ off64_t offset = 0;
+ uint32_t remaining = size;
+ RetCode ret;
+
+ while (remaining) {
+ // Memory map the file
+ android::FileMap filemap;
+ size_t len = std::min(remaining, MAX_MAP_SIZE);
+
+ if (!filemap.create(NULL, fd, offset, len, true)) {
+ error_ = "Creating filemap failed";
+ return IO_ERROR;
+ }
+
+ if ((ret = SendBuffer(filemap.getDataPtr(), len))) {
+ return ret;
+ }
+
+ remaining -= len;
+ offset += len;
+ }
+
+ return SUCCESS;
+}
+
+RetCode FastBootDriver::SendBuffer(const std::vector<char>& buf) {
+ // Write the buffer
+ return SendBuffer(buf.data(), buf.size());
+}
+
+RetCode FastBootDriver::SendBuffer(const void* buf, size_t size) {
+ // Write the buffer
+ ssize_t tmp = transport->Write(buf, size);
+
+ if (tmp < 0) {
+ error_ = ErrnoStr("Write to device failed in SendBuffer()");
+ return IO_ERROR;
+ } else if (static_cast<size_t>(tmp) != size) {
+ error_ = android::base::StringPrintf("Failed to write all %zu bytes", size);
+
+ return IO_ERROR;
+ }
+
+ return SUCCESS;
+}
+
+RetCode FastBootDriver::ReadBuffer(std::vector<char>& buf) {
+ // Read the buffer
+ return ReadBuffer(buf.data(), buf.size());
+}
+
+RetCode FastBootDriver::ReadBuffer(void* buf, size_t size) {
+ // Read the buffer
+ ssize_t tmp = transport->Read(buf, size);
+
+ if (tmp < 0) {
+ error_ = ErrnoStr("Read from device failed in ReadBuffer()");
+ return IO_ERROR;
+ } else if (static_cast<size_t>(tmp) != size) {
+ error_ = android::base::StringPrintf("Failed to read all %zu bytes", size);
+ return IO_ERROR;
+ }
+
+ return SUCCESS;
+}
+
+int FastBootDriver::SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len) {
+ size_t total = 0;
+ size_t to_write = std::min(TRANSPORT_CHUNK_SIZE - tpbuf.size(), len);
+
+ // Handle the residual
+ tpbuf.insert(tpbuf.end(), data, data + to_write);
+ if (tpbuf.size() < TRANSPORT_CHUNK_SIZE) { // Nothing enough to send rn
+ return 0;
+ }
+
+ if (SendBuffer(tpbuf)) {
+ error_ = ErrnoStr("Send failed in SparseWriteCallback()");
+ return -1;
+ }
+ tpbuf.clear();
+ total += to_write;
+
+ // Now we need to send a multiple of chunk size
+ size_t nchunks = (len - total) / TRANSPORT_CHUNK_SIZE;
+ size_t nbytes = TRANSPORT_CHUNK_SIZE * nchunks;
+ if (SendBuffer(data + total, nbytes)) {
+ error_ = ErrnoStr("Send failed in SparseWriteCallback()");
+ return -1;
+ }
+ total += nbytes;
+
+ if (len - total > 0) { // We have residual data to save for next time
+ tpbuf.assign(data + total, data + len);
+ }
+
+ return 0;
+}
+
+} // End namespace fastboot
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
new file mode 100644
index 0000000..9fdd317
--- /dev/null
+++ b/fastboot/fastboot_driver.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#pragma once
+#include <cstdlib>
+#include <deque>
+#include <limits>
+#include <string>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <bootimg.h>
+#include <inttypes.h>
+#include <sparse/sparse.h>
+#include "transport.h"
+
+class Transport;
+
+namespace fastboot {
+
+static constexpr int FB_COMMAND_SZ = 64;
+static constexpr int FB_RESPONSE_SZ = 64;
+
+enum RetCode : int {
+ SUCCESS = 0,
+ BAD_ARG,
+ IO_ERROR,
+ BAD_DEV_RESP,
+ DEVICE_FAIL,
+ TIMEOUT,
+};
+
+class FastBootDriver {
+ public:
+ static constexpr int RESP_TIMEOUT = 10; // 10 seconds
+ static constexpr uint32_t MAX_DOWNLOAD_SIZE = std::numeric_limits<uint32_t>::max();
+ static constexpr size_t TRANSPORT_CHUNK_SIZE = 1024;
+
+ FastBootDriver(Transport* transport,
+ std::function<void(std::string&)> info = [](std::string&) {},
+ bool no_checks = false);
+
+ RetCode Boot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+ RetCode Continue(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+ RetCode Download(int fd, size_t size, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+ RetCode Download(const std::vector<char>& buf, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+ // This will be removed after fastboot is modified to use a vector
+ RetCode Download(const char* buf, uint32_t size, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+ RetCode Download(sparse_file* s, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+ RetCode Erase(const std::string& part, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+ RetCode Flash(const std::string& part, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+ RetCode GetVar(const std::string& key, std::string* val,
+ std::vector<std::string>* info = nullptr);
+ RetCode GetVarAll(std::vector<std::string>* response);
+ RetCode Powerdown(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+ RetCode Reboot(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+ RetCode SetActive(const std::string& part, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+ RetCode Upload(const std::string& outfile, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+ RetCode Verify(uint32_t num, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+
+ /* HIGHER LEVEL COMMANDS -- Composed of the commands above */
+ RetCode FlashPartition(const std::string& part, const std::vector<char>& data);
+ RetCode FlashPartition(const std::string& part, int fd, uint32_t sz);
+ RetCode FlashPartition(const std::string& part, sparse_file* s);
+
+ RetCode Partitions(std::vector<std::tuple<std::string, uint32_t>>* parts);
+ RetCode Require(const std::string& var, const std::vector<std::string>& allowed, bool* reqmet,
+ bool invert = false);
+
+ /* HELPERS */
+ void SetInfoCallback(std::function<void(std::string&)> info);
+ const std::string RCString(RetCode rc);
+ std::string Error();
+ RetCode WaitForDisconnect();
+
+ // This is temporarily public for engine.cpp
+ RetCode RawCommand(const std::string& cmd, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr, int* dsize = nullptr);
+
+ protected:
+ RetCode DownloadCommand(uint32_t size, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
+ RetCode HandleResponse(std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr, int* dsize = nullptr);
+
+ std::string ErrnoStr(const std::string& msg);
+
+ // More like a namespace...
+ struct Commands {
+ static const std::string BOOT;
+ static const std::string CONTINUE;
+ static const std::string DOWNLOAD;
+ static const std::string ERASE;
+ static const std::string FLASH;
+ static const std::string GET_VAR;
+ static const std::string POWERDOWN;
+ static const std::string REBOOT;
+ static const std::string SET_ACTIVE;
+ static const std::string UPLOAD;
+ static const std::string VERIFY;
+ };
+
+ Transport* const transport;
+
+ private:
+ RetCode SendBuffer(int fd, size_t size);
+ RetCode SendBuffer(const std::vector<char>& buf);
+ RetCode SendBuffer(const void* buf, size_t size);
+
+ RetCode ReadBuffer(std::vector<char>& buf);
+ RetCode ReadBuffer(void* buf, size_t size);
+
+ int SparseWriteCallback(std::vector<char>& tpbuf, const char* data, size_t len);
+
+ std::string error_;
+ std::function<void(std::string&)> info_cb_;
+ bool disable_checks_;
+};
+
+} // namespace fastboot
diff --git a/fastboot/fastboot_test.cpp b/fastboot/fastboot_test.cpp
index 1681427..43201fa 100644
--- a/fastboot/fastboot_test.cpp
+++ b/fastboot/fastboot_test.cpp
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#include "fastboot.h"
+#include "engine.h"
#include <gtest/gtest.h>
TEST(FastBoot, ParseOsPatchLevel) {
- FastBoot fb;
+ FastBootTool fb;
boot_img_hdr_v1 hdr;
hdr = {};
@@ -34,7 +34,7 @@
}
TEST(FastBoot, ParseOsVersion) {
- FastBoot fb;
+ FastBootTool fb;
boot_img_hdr_v1 hdr;
hdr = {};
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 14dabaa..cc1714f 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -1,6 +1,5 @@
#include "fs.h"
-#include "fastboot.h"
#include <errno.h>
#include <fcntl.h>
diff --git a/fastboot/main.cpp b/fastboot/main.cpp
index f1c8afb..c3683f7 100644
--- a/fastboot/main.cpp
+++ b/fastboot/main.cpp
@@ -26,9 +26,9 @@
* SUCH DAMAGE.
*/
-#include "fastboot.h"
+#include "engine.h"
int main(int argc, char* argv[]) {
- FastBoot fb;
+ FastBootTool fb;
return fb.Main(argc, argv);
}
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
deleted file mode 100644
index e625095..0000000
--- a/fastboot/protocol.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#define round_down(a, b) \
- ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <algorithm>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <sparse/sparse.h>
-#include <utils/FileMap.h>
-
-#include "constants.h"
-#include "fastboot.h"
-#include "transport.h"
-
-static std::string g_error;
-
-using android::base::unique_fd;
-using android::base::WriteStringToFile;
-
-const std::string fb_get_error() {
- return g_error;
-}
-
-static int64_t check_response(Transport* transport, uint32_t size, char* response) {
- char status[FB_RESPONSE_SZ + 1];
-
- while (true) {
- int r = transport->Read(status, FB_RESPONSE_SZ);
- if (r < 0) {
- g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
- transport->Close();
- return -1;
- }
- status[r] = 0;
-
- if (static_cast<size_t>(r) < strlen(RESPONSE_OKAY)) {
- g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
- transport->Close();
- return -1;
- }
-
- if (!memcmp(status, RESPONSE_INFO, strlen(RESPONSE_INFO))) {
- verbose("received INFO \"%s\"", status + strlen(RESPONSE_INFO));
- fprintf(stderr, "(bootloader) %s\n", status + strlen(RESPONSE_INFO));
- continue;
- }
-
- if (!memcmp(status, RESPONSE_OKAY, strlen(RESPONSE_OKAY))) {
- verbose("received OKAY \"%s\"", status + strlen(RESPONSE_OKAY));
- if (response) {
- strcpy(response, status + strlen(RESPONSE_OKAY));
- }
- return 0;
- }
-
- if (!memcmp(status, RESPONSE_FAIL, strlen(RESPONSE_FAIL))) {
- verbose("received FAIL \"%s\"", status + strlen(RESPONSE_FAIL));
- if (static_cast<size_t>(r) > strlen(RESPONSE_FAIL)) {
- g_error = android::base::StringPrintf("remote: %s", status + strlen(RESPONSE_FAIL));
- } else {
- g_error = "remote failure";
- }
- return -1;
- }
-
- if (!memcmp(status, RESPONSE_DATA, strlen(RESPONSE_DATA)) && size > 0){
- verbose("received DATA %s", status + strlen(RESPONSE_DATA));
- uint32_t dsize = strtol(status + strlen(RESPONSE_DATA), 0, 16);
- if (dsize > size) {
- g_error = android::base::StringPrintf("data size too large (%d)", dsize);
- transport->Close();
- return -1;
- }
- return dsize;
- }
-
- verbose("received unknown status code \"%4.4s\"", status);
- g_error = "unknown status code";
- transport->Close();
- break;
- }
-
- return -1;
-}
-
-static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size,
- char* response) {
- if (cmd.size() > FB_COMMAND_SZ) {
- g_error = android::base::StringPrintf("command too large (%zu)", cmd.size());
- return -1;
- }
-
- if (response) {
- response[0] = 0;
- }
-
- verbose("sending command \"%s\"", cmd.c_str());
-
- if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
- g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
- transport->Close();
- return -1;
- }
-
- return check_response(transport, size, response);
-}
-
-static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) {
- verbose("sending data (%" PRIu32 " bytes)", size);
-
- int64_t r = transport->Write(data, size);
- if (r < 0) {
- g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno));
- transport->Close();
- return -1;
- }
- if (r != static_cast<int64_t>(size)) {
- g_error = "data write failure (short transfer)";
- transport->Close();
- return -1;
- }
- return r;
-}
-
-static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) {
- verbose("reading data (%" PRIu32 " bytes)", size);
-
- int64_t r = transport->Read(data, size);
- if (r < 0) {
- g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno));
- transport->Close();
- return -1;
- }
- if (r != (static_cast<int64_t>(size))) {
- g_error = "data read failure (short transfer)";
- transport->Close();
- return -1;
- }
- return r;
-}
-
-static int64_t _command_end(Transport* transport) {
- return check_response(transport, 0, 0) < 0 ? -1 : 0;
-}
-
-static int64_t _command_send(Transport* transport, const std::string& cmd, const void* data,
- uint32_t size, char* response) {
- if (size == 0) {
- return -1;
- }
-
- int64_t r = _command_start(transport, cmd, size, response);
- if (r < 0) {
- return -1;
- }
- r = _command_write_data(transport, data, size);
- if (r < 0) {
- return -1;
- }
-
- r = _command_end(transport);
- if (r < 0) {
- return -1;
- }
-
- return size;
-}
-
-static int64_t _command_send_fd(Transport* transport, const std::string& cmd, int fd, uint32_t size,
- char* response) {
- static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
- off64_t offset = 0;
- uint32_t remaining = size;
-
- if (_command_start(transport, cmd, size, response) < 0) {
- return -1;
- }
-
- while (remaining) {
- android::FileMap filemap;
- size_t len = std::min(remaining, MAX_MAP_SIZE);
-
- if (!filemap.create(NULL, fd, offset, len, true)) {
- return -1;
- }
-
- if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) {
- return -1;
- }
-
- remaining -= len;
- offset += len;
- }
-
- if (_command_end(transport) < 0) {
- return -1;
- }
-
- return size;
-}
-
-static int _command_send_no_data(Transport* transport, const std::string& cmd, char* response) {
- return _command_start(transport, cmd, 0, response);
-}
-
-int fb_command(Transport* transport, const std::string& cmd) {
- return _command_send_no_data(transport, cmd, 0);
-}
-
-int fb_command_response(Transport* transport, const std::string& cmd, char* response) {
- return _command_send_no_data(transport, cmd, response);
-}
-
-int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) {
- std::string cmd(android::base::StringPrintf(
- FB_CMD_DOWNLOAD ":" "%08x", size));
- return _command_send(transport, cmd.c_str(), data, size, 0) < 0 ? -1 : 0;
-}
-
-int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) {
- std::string cmd(android::base::StringPrintf(
- FB_CMD_DOWNLOAD ":" "%08x", size));
- return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0;
-}
-
-int64_t fb_upload_data(Transport* transport, const char* outfile) {
- // positive return value is the upload size sent by the device
- int64_t r = _command_start(transport, FB_CMD_UPLOAD,
- std::numeric_limits<int32_t>::max(), nullptr);
- if (r <= 0) {
- g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno));
- return r;
- }
-
- std::string data;
- data.resize(r);
- if ((r = _command_read_data(transport, &data[0], data.size())) == -1) {
- return r;
- }
-
- if (!WriteStringToFile(data, outfile, true)) {
- g_error = android::base::StringPrintf("write to '%s' failed", outfile);
- return -1;
- }
-
- return _command_end(transport);
-}
-
-static constexpr size_t TRANSPORT_BUF_SIZE = 1024;
-static char transport_buf[TRANSPORT_BUF_SIZE];
-static size_t transport_buf_len;
-
-static int fb_download_data_sparse_write(void* priv, const void* data, size_t len) {
- const char* ptr = static_cast<const char*>(data);
- if (transport_buf_len) {
- size_t to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
-
- memcpy(transport_buf + transport_buf_len, ptr, to_write);
- transport_buf_len += to_write;
- ptr += to_write;
- len -= to_write;
- }
-
- Transport* transport = static_cast<Transport*>(priv);
- if (transport_buf_len == TRANSPORT_BUF_SIZE) {
- int64_t r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
- if (r != static_cast<int64_t>(TRANSPORT_BUF_SIZE)) {
- return -1;
- }
- transport_buf_len = 0;
- }
-
- if (len > TRANSPORT_BUF_SIZE) {
- if (transport_buf_len > 0) {
- g_error = "internal error: transport_buf not empty";
- return -1;
- }
- size_t to_write = round_down(len, TRANSPORT_BUF_SIZE);
- int64_t r = _command_write_data(transport, ptr, to_write);
- if (r != static_cast<int64_t>(to_write)) {
- return -1;
- }
- ptr += to_write;
- len -= to_write;
- }
-
- if (len > 0) {
- if (len > TRANSPORT_BUF_SIZE) {
- g_error = "internal error: too much left for transport_buf";
- return -1;
- }
- memcpy(transport_buf, ptr, len);
- transport_buf_len = len;
- }
-
- return 0;
-}
-
-static int fb_download_data_sparse_flush(Transport* transport) {
- if (transport_buf_len > 0) {
- int64_t r = _command_write_data(transport, transport_buf, transport_buf_len);
- if (r != static_cast<int64_t>(transport_buf_len)) {
- return -1;
- }
- transport_buf_len = 0;
- }
- return 0;
-}
-
-int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
- int64_t size = sparse_file_len(s, true, false);
- if (size <= 0 || size > std::numeric_limits<uint32_t>::max()) {
- return -1;
- }
-
- std::string cmd(android::base::StringPrintf(
- FB_CMD_DOWNLOAD ":" "%08" PRIx64, size));
- int r = _command_start(transport, cmd, size, 0);
- if (r < 0) {
- return -1;
- }
-
- r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport);
- if (r < 0) {
- return -1;
- }
-
- r = fb_download_data_sparse_flush(transport);
- if (r < 0) {
- return -1;
- }
-
- return _command_end(transport);
-}
diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp
index cdab4f1..386dd30 100644
--- a/fastboot/usb_linux.cpp
+++ b/fastboot/usb_linux.cpp
@@ -47,8 +47,8 @@
#include <memory>
#include <thread>
-#include "fastboot.h"
#include "usb.h"
+#include "util.h"
using namespace std::chrono_literals;
diff --git a/fastboot/usb_windows.cpp b/fastboot/usb_windows.cpp
index 3dab5ac..0e5fba1 100644
--- a/fastboot/usb_windows.cpp
+++ b/fastboot/usb_windows.cpp
@@ -106,6 +106,7 @@
if (nullptr == ret->adb_interface) {
errno = GetLastError();
+ DBG("failed to open interface %S\n", interface_name);
return nullptr;
}
@@ -157,7 +158,7 @@
unsigned count = 0;
int ret;
- DBG("usb_write %d\n", len);
+ DBG("usb_write %zu\n", len);
if (nullptr != handle_) {
// Perform write
while(len > 0) {
@@ -195,7 +196,7 @@
unsigned long read = 0;
int ret;
- DBG("usb_read %d\n", len);
+ DBG("usb_read %zu\n", len);
if (nullptr != handle_) {
while (1) {
int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
@@ -269,19 +270,22 @@
return 0;
// Check vendor and product id first
- if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
- &device_desc)) {
+ if (!AdbGetUsbDeviceDescriptor(handle->adb_interface, &device_desc)) {
+ DBG("skipping device %x:%x\n", device_desc.idVendor, device_desc.idProduct);
return 0;
}
// Then check interface properties
- if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
- &interf_desc)) {
+ if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface, &interf_desc)) {
+ DBG("skipping device %x:%x, failed to find interface\n", device_desc.idVendor,
+ device_desc.idProduct);
return 0;
}
// Must have two endpoints
if (2 != interf_desc.bNumEndpoints) {
+ DBG("skipping device %x:%x, incorrect number of endpoints\n", device_desc.idVendor,
+ device_desc.idProduct);
return 0;
}
@@ -305,9 +309,13 @@
info.device_path[0] = 0;
if (callback(&info) == 0) {
+ DBG("skipping device %x:%x, not selected by callback\n", device_desc.idVendor,
+ device_desc.idProduct);
return 1;
}
+ DBG("found device %x:%x (%s)\n", device_desc.idVendor, device_desc.idProduct,
+ info.serial_number);
return 0;
}
@@ -338,6 +346,7 @@
}
*copy_name = '\0';
+ DBG("attempting to open interface %S\n", next_interface->device_name);
handle = do_usb_open(next_interface->device_name);
if (NULL != handle) {
// Lets see if this interface (device) belongs to us
diff --git a/fastboot/util.cpp b/fastboot/util.cpp
index 140270f..8f6e52a 100644
--- a/fastboot/util.cpp
+++ b/fastboot/util.cpp
@@ -33,7 +33,7 @@
#include <sys/time.h>
-#include "fastboot.h"
+#include "util.h"
static bool g_verbose = false;
diff --git a/fastboot/util.h b/fastboot/util.h
new file mode 100644
index 0000000..9033f93
--- /dev/null
+++ b/fastboot/util.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include <bootimg.h>
+
+/* util stuff */
+double now();
+char* xstrdup(const char*);
+void set_verbose();
+
+// These printf-like functions are implemented in terms of vsnprintf, so they
+// use the same attribute for compile-time format string checking.
+void die(const char* fmt, ...) __attribute__((__noreturn__))
+__attribute__((__format__(__printf__, 1, 2)));
+void verbose(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
diff --git a/init/devices.cpp b/init/devices.cpp
index ada1e28..ed4a739 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -31,7 +31,6 @@
#include <selinux/selinux.h>
#include "selinux.h"
-#include "ueventd.h"
#include "util.h"
#ifdef _INIT_INIT_H
diff --git a/init/util.cpp b/init/util.cpp
index 5f2b87d..7735717 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -37,12 +37,9 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <cutils/android_reboot.h>
#include <cutils/sockets.h>
#include <selinux/android.h>
-#include "reboot.h"
-
#if defined(__ANDROID__)
#include "selinux.h"
#else