Merge "trusty: tipc_test: Read output and test result from ta2ta_ipc_test"
diff --git a/.clang-format-2 b/.clang-format-2
index 41591ce..ede5d7e 100644
--- a/.clang-format-2
+++ b/.clang-format-2
@@ -7,4 +7,3 @@
PointerAlignment: Left
TabWidth: 2
UseTab: Never
-PenaltyExcessCharacter: 32
diff --git a/.clang-format-4 b/.clang-format-4
index 9127163..55773a2 100644
--- a/.clang-format-4
+++ b/.clang-format-4
@@ -9,4 +9,3 @@
PointerAlignment: Left
TabWidth: 4
UseTab: Never
-PenaltyExcessCharacter: 32
diff --git a/adb/Android.bp b/adb/Android.bp
index 97c9762..2a9a579 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -19,17 +19,13 @@
"-Wall",
"-Wextra",
"-Werror",
+ "-Wexit-time-destructors",
"-Wno-unused-parameter",
"-Wno-missing-field-initializers",
"-Wvla",
],
rtti: true,
- clang_cflags: [
- "-Wexit-time-destructors",
- "-Wthread-safety",
- ],
-
use_version_lib: true,
compile_multilib: "first",
@@ -85,6 +81,12 @@
"-luserenv",
],
},
+
+ not_windows: {
+ cflags: [
+ "-Wthread-safety",
+ ],
+ },
},
}
@@ -297,6 +299,10 @@
"libqemu_pipe",
"libbase",
],
+
+ export_include_dirs: [
+ "daemon/include",
+ ],
}
cc_binary {
diff --git a/adb/adb.bash b/adb/adb.bash
index d36bec3..b1b3957 100644
--- a/adb/adb.bash
+++ b/adb/adb.bash
@@ -16,11 +16,11 @@
#
_adb() {
- if ! type -t "$1" >/dev/null; then
+ if ! check_type "$1" >/dev/null; then
return
fi
- if type -t _init_completion >/dev/null; then
+ if check_type _init_completion >/dev/null; then
_init_completion || return
fi
@@ -435,7 +435,7 @@
fi
# Since we're probably doing file completion here, don't add a space after.
- if [[ $(type -t compopt) = "builtin" ]]; then
+ if [[ $(check_type compopt) == "builtin" ]]; then
compopt -o nospace
fi
@@ -451,7 +451,7 @@
xspec=$2
# Since we're probably doing file completion here, don't add a space after.
- if [[ $(type -t compopt) = "builtin" ]]; then
+ if [[ $(check_type compopt) == "builtin" ]]; then
compopt -o plusdirs
if [[ "${xspec}" == "" ]]; then
COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
@@ -492,7 +492,7 @@
}
-if [[ $(type -t compopt) = "builtin" ]]; then
+if [[ $(check_type compopt) == "builtin" ]]; then
complete -F _adb adb
else
complete -o nospace -F _adb adb
diff --git a/adb/adb.cpp b/adb/adb.cpp
index f8a54c6..19300f6 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);
}
@@ -415,7 +406,7 @@
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
asocket* s = find_local_socket(p->msg.arg1, 0);
if (s) {
- if(s->peer == 0) {
+ if(s->peer == nullptr) {
/* On first READY message, create the connection. */
s->peer = create_remote_socket(p->msg.arg0, t);
s->peer->peer = s;
@@ -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);
}
@@ -933,25 +924,6 @@
// This returns 1 on success, 0 on failure, and -1 to indicate this is not
// a forwarding-related request.
int handle_forward_request(const char* service, atransport* transport, int reply_fd) {
- if (!strcmp(service, "list-forward")) {
- // Create the list of forward redirections.
- std::string listeners = format_listeners();
-#if ADB_HOST
- SendOkay(reply_fd);
-#endif
- return SendProtocolString(reply_fd, listeners);
- }
-
- if (!strcmp(service, "killforward-all")) {
- remove_all_listeners();
-#if ADB_HOST
- /* On the host: 1st OKAY is connect, 2nd OKAY is status */
- SendOkay(reply_fd);
-#endif
- SendOkay(reply_fd);
- return 1;
- }
-
if (!strncmp(service, "forward:", 8) || !strncmp(service, "killforward:", 12)) {
// killforward:local
// forward:(norebind:)?local;remote
@@ -1171,7 +1143,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 +1152,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);
}
@@ -1214,10 +1186,30 @@
return SendOkay(reply_fd, response);
}
+ if (!strcmp(service, "list-forward")) {
+ // Create the list of forward redirections.
+ std::string listeners = format_listeners();
+#if ADB_HOST
+ SendOkay(reply_fd);
+#endif
+ return SendProtocolString(reply_fd, listeners);
+ }
+
+ if (!strcmp(service, "killforward-all")) {
+ remove_all_listeners();
+#if ADB_HOST
+ /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+ SendOkay(reply_fd);
+#endif
+ SendOkay(reply_fd);
+ return 1;
+ }
+
std::string error;
atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (!t) {
- return -1;
+ SendFail(reply_fd, error);
+ return 1;
}
int ret = handle_forward_request(service, t, reply_fd);
diff --git a/adb/adb.h b/adb/adb.h
index ede55da..7e9af9e 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -124,8 +124,6 @@
void print_packet(const char* label, apacket* p);
-// These use the system (v)fprintf, not the adb prefixed ones defined in sysdeps.h, so they
-// shouldn't be tagged with ADB_FORMAT_ARCHETYPE.
void fatal(const char* fmt, ...) __attribute__((noreturn, format(__printf__, 1, 2)));
void fatal_errno(const char* fmt, ...) __attribute__((noreturn, format(__printf__, 1, 2)));
@@ -158,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_io.cpp b/adb/adb_io.cpp
index 38e3116..6cc274b 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -49,7 +49,7 @@
}
buf[4] = 0;
- unsigned long len = strtoul(buf, 0, 16);
+ unsigned long len = strtoul(buf, nullptr, 16);
s->resize(len, '\0');
if (!ReadFdExactly(fd, &(*s)[0], len)) {
*error = perror_str("protocol fault (couldn't read status message)");
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/adb_utils.cpp b/adb/adb_utils.cpp
index b236fb3..0c3327f 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -79,22 +79,24 @@
}
std::string escape_arg(const std::string& s) {
- std::string result = s;
-
// Escape any ' in the string (before we single-quote the whole thing).
// The correct way to do this for the shell is to replace ' with '\'' --- that is,
// close the existing single-quoted string, escape a single single-quote, and start
// a new single-quoted string. Like the C preprocessor, the shell will concatenate
// these pieces into one string.
- for (size_t i = 0; i < s.size(); ++i) {
- if (s[i] == '\'') {
- result.insert(i, "'\\'");
- i += 2;
- }
+
+ std::string result;
+ result.push_back('\'');
+
+ size_t base = 0;
+ while (true) {
+ size_t found = s.find('\'', base);
+ result.append(s, base, found - base);
+ if (found == s.npos) break;
+ result.append("'\\''");
+ base = found + 1;
}
- // Prefix and suffix the whole string with '.
- result.insert(result.begin(), '\'');
result.push_back('\'');
return result;
}
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index e1b6287..341323f 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -82,30 +82,38 @@
#endif
TEST(adb_utils, escape_arg) {
- ASSERT_EQ(R"('')", escape_arg(""));
+ EXPECT_EQ(R"('')", escape_arg(""));
- ASSERT_EQ(R"('abc')", escape_arg("abc"));
+ EXPECT_EQ(R"('abc')", escape_arg("abc"));
- ASSERT_EQ(R"(' abc')", escape_arg(" abc"));
- ASSERT_EQ(R"(''\''abc')", escape_arg("'abc"));
- ASSERT_EQ(R"('"abc')", escape_arg("\"abc"));
- ASSERT_EQ(R"('\abc')", escape_arg("\\abc"));
- ASSERT_EQ(R"('(abc')", escape_arg("(abc"));
- ASSERT_EQ(R"(')abc')", escape_arg(")abc"));
+ auto wrap = [](const std::string& x) { return '\'' + x + '\''; };
+ const std::string q = R"('\'')";
+ EXPECT_EQ(wrap(q), escape_arg("'"));
+ EXPECT_EQ(wrap(q + q), escape_arg("''"));
+ EXPECT_EQ(wrap(q + "abc" + q), escape_arg("'abc'"));
+ EXPECT_EQ(wrap(q + "abc"), escape_arg("'abc"));
+ EXPECT_EQ(wrap("abc" + q), escape_arg("abc'"));
+ EXPECT_EQ(wrap("abc" + q + "def"), escape_arg("abc'def"));
+ EXPECT_EQ(wrap("a" + q + "b" + q + "c"), escape_arg("a'b'c"));
+ EXPECT_EQ(wrap("a" + q + "bcde" + q + "f"), escape_arg("a'bcde'f"));
- ASSERT_EQ(R"('abc abc')", escape_arg("abc abc"));
- ASSERT_EQ(R"('abc'\''abc')", escape_arg("abc'abc"));
- ASSERT_EQ(R"('abc"abc')", escape_arg("abc\"abc"));
- ASSERT_EQ(R"('abc\abc')", escape_arg("abc\\abc"));
- ASSERT_EQ(R"('abc(abc')", escape_arg("abc(abc"));
- ASSERT_EQ(R"('abc)abc')", escape_arg("abc)abc"));
+ EXPECT_EQ(R"(' abc')", escape_arg(" abc"));
+ EXPECT_EQ(R"('"abc')", escape_arg("\"abc"));
+ EXPECT_EQ(R"('\abc')", escape_arg("\\abc"));
+ EXPECT_EQ(R"('(abc')", escape_arg("(abc"));
+ EXPECT_EQ(R"(')abc')", escape_arg(")abc"));
- ASSERT_EQ(R"('abc ')", escape_arg("abc "));
- ASSERT_EQ(R"('abc'\''')", escape_arg("abc'"));
- ASSERT_EQ(R"('abc"')", escape_arg("abc\""));
- ASSERT_EQ(R"('abc\')", escape_arg("abc\\"));
- ASSERT_EQ(R"('abc(')", escape_arg("abc("));
- ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
+ EXPECT_EQ(R"('abc abc')", escape_arg("abc abc"));
+ EXPECT_EQ(R"('abc"abc')", escape_arg("abc\"abc"));
+ EXPECT_EQ(R"('abc\abc')", escape_arg("abc\\abc"));
+ EXPECT_EQ(R"('abc(abc')", escape_arg("abc(abc"));
+ EXPECT_EQ(R"('abc)abc')", escape_arg("abc)abc"));
+
+ EXPECT_EQ(R"('abc ')", escape_arg("abc "));
+ EXPECT_EQ(R"('abc"')", escape_arg("abc\""));
+ EXPECT_EQ(R"('abc\')", escape_arg("abc\\"));
+ EXPECT_EQ(R"('abc(')", escape_arg("abc("));
+ EXPECT_EQ(R"('abc)')", escape_arg("abc)"));
}
void test_mkdirs(const std::string& basepath) {
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index 849a6e7..1959258 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -46,7 +46,7 @@
#include "sysdeps/chrono.h"
static TransportType __adb_transport = kTransportAny;
-static const char* __adb_serial = NULL;
+static const char* __adb_serial = nullptr;
static TransportId __adb_transport_id = 0;
static const char* __adb_server_socket_spec;
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 0f4dd33..5fbef09 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -109,7 +109,7 @@
LOG(INFO) << "generate_key(" << file << ")...";
mode_t old_mask;
- FILE *f = NULL;
+ FILE *f = nullptr;
int ret = 0;
EVP_PKEY* pkey = EVP_PKEY_new();
@@ -121,7 +121,7 @@
}
BN_set_word(exponent, RSA_F4);
- RSA_generate_key_ex(rsa, 2048, exponent, NULL);
+ RSA_generate_key_ex(rsa, 2048, exponent, nullptr);
EVP_PKEY_set1_RSA(pkey, rsa);
old_mask = umask(077);
@@ -135,7 +135,7 @@
umask(old_mask);
- if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
+ if (!PEM_write_PrivateKey(f, pkey, nullptr, nullptr, 0, nullptr, nullptr)) {
D("Failed to write key");
goto out;
}
@@ -302,7 +302,7 @@
static std::string adb_auth_sign(RSA* key, const char* token, size_t token_size) {
if (token_size != TOKEN_SIZE) {
D("Unexpected token size %zd", token_size);
- return 0;
+ return nullptr;
}
std::string result;
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index e07dba7..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) {
@@ -885,7 +883,7 @@
return 0;
}
- int block = strtol(buf, NULL, 10);
+ int block = strtol(buf, nullptr, 10);
size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
if (offset >= static_cast<size_t>(sb.st_size)) {
@@ -968,7 +966,7 @@
//argv[2] and beyond become ppp_args[1] and beyond
ppp_args[i - 1] = argv[i];
}
- ppp_args[i-1] = NULL;
+ ppp_args[i-1] = nullptr;
// child side
@@ -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) {
@@ -1174,7 +1170,7 @@
argv[i++] = argv[j++];
}
argc -= 2;
- argv[argc] = NULL;
+ argv[argc] = nullptr;
}
}
@@ -1969,7 +1965,7 @@
char* end = strrchr(buf, ']');
if (start && end) {
*end = '\0';
- session_id = strtol(start + 1, NULL, 10);
+ session_id = strtol(start + 1, nullptr, 10);
}
}
if (session_id < 0) {
diff --git a/adb/client/commandline.h b/adb/client/commandline.h
index 3d10030..3aa03a7 100644
--- a/adb/client/commandline.h
+++ b/adb/client/commandline.h
@@ -83,6 +83,14 @@
DISALLOW_COPY_AND_ASSIGN(DefaultStandardStreamsCallback);
};
+class SilentStandardStreamsCallbackInterface : public StandardStreamsCallbackInterface {
+ public:
+ SilentStandardStreamsCallbackInterface() = default;
+ void OnStdout(const char*, int) override final {}
+ void OnStderr(const char*, int) override final {}
+ int Done(int status) override final { return status; }
+};
+
// Singleton.
extern DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK;
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 26f8d83..a438dbb 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -44,6 +44,8 @@
#include "sysdeps/errno.h"
#include "sysdeps/stat.h"
+#include "client/commandline.h"
+
#include <android-base/file.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
@@ -202,12 +204,11 @@
max = SYNC_DATA_MAX; // TODO: decide at runtime.
std::string error;
- FeatureSet features;
- if (!adb_get_feature_set(&features, &error)) {
+ if (!adb_get_feature_set(&features_, &error)) {
fd = -1;
Error("failed to get feature set: %s", error.c_str());
} else {
- have_stat_v2_ = CanUseFeature(features, kFeatureStat2);
+ have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
fd = adb_connect("sync:", &error);
if (fd < 0) {
Error("connect failed: %s", error.c_str());
@@ -232,6 +233,8 @@
line_printer_.KeepInfoLine();
}
+ const FeatureSet& Features() const { return features_; }
+
bool IsValid() { return fd >= 0; }
bool ReceivedError(const char* from, const char* to) {
@@ -510,8 +513,7 @@
return false;
}
-
- void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
+ void Printf(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
std::string s;
va_list ap;
@@ -522,7 +524,7 @@
line_printer_.Print(s, LinePrinter::INFO);
}
- void Println(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
+ void Println(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
std::string s;
va_list ap;
@@ -534,7 +536,7 @@
line_printer_.KeepInfoLine();
}
- void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
+ void Error(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
std::string s = "adb: error: ";
va_list ap;
@@ -545,7 +547,7 @@
line_printer_.Print(s, LinePrinter::ERROR);
}
- void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
+ void Warning(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
std::string s = "adb: warning: ";
va_list ap;
@@ -577,6 +579,7 @@
private:
bool expect_done_;
+ FeatureSet features_;
bool have_stat_v2_;
TransferLedger global_ledger_;
@@ -806,7 +809,7 @@
}
static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* file_list,
- const std::string& lpath,
+ std::vector<std::string>* directory_list, const std::string& lpath,
const std::string& rpath) {
std::vector<copyinfo> dirlist;
std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
@@ -849,21 +852,9 @@
// Close this directory and recurse.
dir.reset();
- // Add the current directory to the list if it was empty, to ensure that
- // it gets created.
- if (empty_dir) {
- // TODO(b/25566053): Make pushing empty directories work.
- // TODO(b/25457350): We don't preserve permissions on directories.
- sc.Warning("skipping empty directory '%s'", lpath.c_str());
- copyinfo ci(android::base::Dirname(lpath), android::base::Dirname(rpath),
- android::base::Basename(lpath), S_IFDIR);
- ci.skip = true;
- file_list->push_back(ci);
- return true;
- }
-
for (const copyinfo& ci : dirlist) {
- local_build_list(sc, file_list, ci.lpath, ci.rpath);
+ directory_list->push_back(ci.rpath);
+ local_build_list(sc, file_list, directory_list, ci.lpath, ci.rpath);
}
return true;
@@ -880,11 +871,54 @@
// Recursively build the list of files to copy.
std::vector<copyinfo> file_list;
+ std::vector<std::string> directory_list;
+
+ for (std::string dirpath = rpath; dirpath != "/"; dirpath = android::base::Dirname(dirpath)) {
+ directory_list.push_back(dirpath);
+ }
+ std::reverse(directory_list.begin(), directory_list.end());
+
int skipped = 0;
- if (!local_build_list(sc, &file_list, lpath, rpath)) {
+ if (!local_build_list(sc, &file_list, &directory_list, lpath, rpath)) {
return false;
}
+ // b/110953234:
+ // P shipped with a bug that causes directory creation as a side-effect of a push to fail.
+ // Work around this by explicitly doing a mkdir via shell.
+ //
+ // Devices that don't support shell_v2 are unhappy if we try to send a too-long packet to them,
+ // but they're not affected by this bug, so only apply the workaround if we have shell_v2.
+ //
+ // TODO(b/25457350): We don't preserve permissions on directories.
+ // TODO: Find all of the leaves and `mkdir -p` them instead?
+ if (CanUseFeature(sc.Features(), kFeatureShell2)) {
+ SilentStandardStreamsCallbackInterface cb;
+ std::string cmd = "mkdir";
+ for (const auto& dir : directory_list) {
+ std::string escaped_path = escape_arg(dir);
+ if (escaped_path.size() > 16384) {
+ // Somewhat arbitrarily limit that probably won't ever happen.
+ sc.Error("path too long: %s", escaped_path.c_str());
+ return false;
+ }
+
+ // The maximum should be 64kiB, but that's not including other stuff that gets tacked
+ // onto the command line, so let's be a bit conservative.
+ if (cmd.size() + escaped_path.size() > 32768) {
+ // Dispatch the command, ignoring failure (since the directory might already exist).
+ send_shell_command(cmd, false, &cb);
+ cmd = "mkdir";
+ }
+ cmd += " ";
+ cmd += escaped_path;
+ }
+
+ if (cmd != "mkdir") {
+ send_shell_command(cmd, false, &cb);
+ }
+ }
+
if (check_timestamps) {
for (const copyinfo& ci : file_list) {
if (!sc.SendLstat(ci.rpath.c_str())) {
diff --git a/adb/client/line_printer.cpp b/adb/client/line_printer.cpp
index 64d10b6..9758526 100644
--- a/adb/client/line_printer.cpp
+++ b/adb/client/line_printer.cpp
@@ -52,7 +52,7 @@
// MSDN says: "For some systems, [_IOLBF] provides line
// buffering. However, for Win32, the behavior is the same as _IOFBF
// - Full Buffering."
- setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stdout, nullptr, _IONBF, 0);
console_ = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
smart_terminal_ = GetConsoleScreenBufferInfo(console_, &csbi);
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 44ed3a2..de6c723 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -89,10 +89,10 @@
// unbuffer stdout and stderr just like if we were run at the console.
// This also keeps stderr unbuffered when it is redirected to adb.log.
if (is_daemon) {
- if (setvbuf(stdout, NULL, _IONBF, 0) == -1) {
+ if (setvbuf(stdout, nullptr, _IONBF, 0) == -1) {
fatal("cannot make stdout unbuffered: %s", strerror(errno));
}
- if (setvbuf(stderr, NULL, _IONBF, 0) == -1) {
+ if (setvbuf(stderr, nullptr, _IONBF, 0) == -1) {
fatal("cannot make stderr unbuffered: %s", strerror(errno));
}
}
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 46c3f58..10b6090 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -589,7 +589,7 @@
int rc = perform_usb_transfer(h, info, std::move(lock));
LOG(DEBUG) << "usb_write(" << len << ") = " << rc;
- return rc;
+ return info->transfer->actual_length;
}
int usb_read(usb_handle* h, void* d, int len) {
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index 1f376a4..869e858 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -128,7 +128,7 @@
if (!bus_dir) return;
dirent* de;
- while ((de = readdir(bus_dir.get())) != 0) {
+ while ((de = readdir(bus_dir.get())) != nullptr) {
if (contains_non_digit(de->d_name)) continue;
std::string bus_name = base + "/" + de->d_name;
@@ -418,11 +418,11 @@
if (h->zero_mask && !(len & h->zero_mask)) {
// If we need 0-markers and our transfer is an even multiple of the packet size,
// then send a zero marker.
- return usb_bulk_write(h, _data, 0);
+ return usb_bulk_write(h, _data, 0) == 0 ? n : -1;
}
D("-- usb_write --");
- return 0;
+ return n;
}
int usb_read(usb_handle *h, void *_data, int len)
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 8a95a19..49baf36 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -497,8 +497,8 @@
}
}
- if (0 == result)
- return 0;
+ if (!result)
+ return len;
LOG(ERROR) << "usb_write failed with status: " << std::hex << result;
return -1;
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index f529e8f..e928377 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -126,11 +126,11 @@
int usb_close(usb_handle* handle);
int known_device_locked(const wchar_t* dev_name) {
- if (NULL != dev_name) {
+ if (nullptr != dev_name) {
// Iterate through the list looking for the name match.
for (usb_handle* usb : handle_list) {
// In Windows names are not case sensetive!
- if ((NULL != usb->interface_name) && (0 == wcsicmp(usb->interface_name, dev_name))) {
+ if ((nullptr != usb->interface_name) && (0 == wcsicmp(usb->interface_name, dev_name))) {
return 1;
}
}
@@ -142,7 +142,7 @@
int known_device(const wchar_t* dev_name) {
int ret = 0;
- if (NULL != dev_name) {
+ if (nullptr != dev_name) {
std::lock_guard<std::mutex> lock(usb_lock);
ret = known_device_locked(dev_name);
}
@@ -151,7 +151,7 @@
}
int register_new_device(usb_handle* handle) {
- if (NULL == handle) return 0;
+ if (nullptr == handle) return 0;
std::lock_guard<std::mutex> lock(usb_lock);
@@ -209,7 +209,7 @@
// Get the HINSTANCE corresponding to the module that _power_window_proc
// is in (the main module).
- const HINSTANCE instance = GetModuleHandleW(NULL);
+ const HINSTANCE instance = GetModuleHandleW(nullptr);
if (!instance) {
// This is such a common API call that this should never fail.
fatal("GetModuleHandleW failed: %s",
@@ -228,14 +228,14 @@
}
if (!CreateWindowExW(WS_EX_NOACTIVATE, kPowerNotificationWindowClassName,
- L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0, NULL, NULL,
- instance, NULL)) {
+ L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0, nullptr, nullptr,
+ instance, nullptr)) {
fatal("CreateWindowExW failed: %s",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
}
MSG msg;
- while (GetMessageW(&msg, NULL, 0, 0)) {
+ while (GetMessageW(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
@@ -259,14 +259,14 @@
// Allocate our handle
usb_handle* ret = (usb_handle*)calloc(1, sizeof(usb_handle));
- if (NULL == ret) {
+ if (nullptr == ret) {
D("Could not allocate %u bytes for usb_handle: %s", sizeof(usb_handle), strerror(errno));
goto fail;
}
// Create interface.
ret->adb_interface = AdbCreateInterfaceByName(interface_name);
- if (NULL == ret->adb_interface) {
+ if (nullptr == ret->adb_interface) {
D("AdbCreateInterfaceByName failed: %s",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
goto fail;
@@ -275,7 +275,7 @@
// Open read pipe (endpoint)
ret->adb_read_pipe = AdbOpenDefaultBulkReadEndpoint(
ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite);
- if (NULL == ret->adb_read_pipe) {
+ if (nullptr == ret->adb_read_pipe) {
D("AdbOpenDefaultBulkReadEndpoint failed: %s",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
goto fail;
@@ -284,7 +284,7 @@
// Open write pipe (endpoint)
ret->adb_write_pipe = AdbOpenDefaultBulkWriteEndpoint(
ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite);
- if (NULL == ret->adb_write_pipe) {
+ if (nullptr == ret->adb_write_pipe) {
D("AdbOpenDefaultBulkWriteEndpoint failed: %s",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
goto fail;
@@ -292,7 +292,7 @@
// Save interface name
// First get expected name length
- AdbGetInterfaceName(ret->adb_interface, NULL, &name_len, false);
+ AdbGetInterfaceName(ret->adb_interface, nullptr, &name_len, false);
if (0 == name_len) {
D("AdbGetInterfaceName returned name length of zero: %s",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
@@ -300,7 +300,7 @@
}
ret->interface_name = (wchar_t*)malloc(name_len * sizeof(ret->interface_name[0]));
- if (NULL == ret->interface_name) {
+ if (nullptr == ret->interface_name) {
D("Could not allocate %lu characters for interface_name: %s", name_len, strerror(errno));
goto fail;
}
@@ -316,12 +316,12 @@
return ret;
fail:
- if (NULL != ret) {
+ if (nullptr != ret) {
usb_cleanup_handle(ret);
free(ret);
}
- return NULL;
+ return nullptr;
}
int usb_write(usb_handle* handle, const void* data, int len) {
@@ -330,7 +330,7 @@
int err = 0;
D("usb_write %d", len);
- if (NULL == handle) {
+ if (nullptr == handle) {
D("usb_write was passed NULL handle");
err = EINVAL;
goto fail;
@@ -365,12 +365,12 @@
}
}
- return 0;
+ return written;
fail:
// Any failure should cause us to kick the device instead of leaving it a
// zombie state with potential to hang.
- if (NULL != handle) {
+ if (nullptr != handle) {
D("Kicking device due to error in usb_write");
usb_kick(handle);
}
@@ -387,7 +387,7 @@
int orig_len = len;
D("usb_read %d", len);
- if (NULL == handle) {
+ if (nullptr == handle) {
D("usb_read was passed NULL handle");
err = EINVAL;
goto fail;
@@ -411,7 +411,7 @@
fail:
// Any failure should cause us to kick the device instead of leaving it a
// zombie state with potential to hang.
- if (NULL != handle) {
+ if (nullptr != handle) {
D("Kicking device due to error in usb_read");
usb_kick(handle);
}
@@ -431,19 +431,19 @@
void usb_cleanup_handle(usb_handle* handle) {
D("usb_cleanup_handle");
- if (NULL != handle) {
- if (NULL != handle->interface_name) free(handle->interface_name);
+ if (nullptr != handle) {
+ if (nullptr != handle->interface_name) free(handle->interface_name);
// AdbCloseHandle(pipe) will break any threads out of pending IO calls and
// wait until the pipe no longer uses the interface. Then we can
// AdbCloseHandle() the interface.
- if (NULL != handle->adb_write_pipe) _adb_close_handle(handle->adb_write_pipe);
- if (NULL != handle->adb_read_pipe) _adb_close_handle(handle->adb_read_pipe);
- if (NULL != handle->adb_interface) _adb_close_handle(handle->adb_interface);
+ if (nullptr != handle->adb_write_pipe) _adb_close_handle(handle->adb_write_pipe);
+ if (nullptr != handle->adb_read_pipe) _adb_close_handle(handle->adb_read_pipe);
+ if (nullptr != handle->adb_interface) _adb_close_handle(handle->adb_interface);
- handle->interface_name = NULL;
- handle->adb_write_pipe = NULL;
- handle->adb_read_pipe = NULL;
- handle->adb_interface = NULL;
+ handle->interface_name = nullptr;
+ handle->adb_write_pipe = nullptr;
+ handle->adb_read_pipe = nullptr;
+ handle->adb_interface = nullptr;
}
}
@@ -455,7 +455,7 @@
void usb_kick(usb_handle* handle) {
D("usb_kick");
- if (NULL != handle) {
+ if (nullptr != handle) {
std::lock_guard<std::mutex> lock(usb_lock);
usb_kick_locked(handle);
} else {
@@ -466,7 +466,7 @@
int usb_close(usb_handle* handle) {
D("usb_close");
- if (NULL != handle) {
+ if (nullptr != handle) {
// Remove handle from the list
{
std::lock_guard<std::mutex> lock(usb_lock);
@@ -487,7 +487,7 @@
}
int recognized_device(usb_handle* handle) {
- if (NULL == handle) return 0;
+ if (nullptr == handle) return 0;
// Check vendor and product id first
USB_DEVICE_DESCRIPTOR device_desc;
@@ -532,7 +532,7 @@
}
void find_devices() {
- usb_handle* handle = NULL;
+ usb_handle* handle = nullptr;
char entry_buffer[2048];
AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
unsigned long entry_buffer_size = sizeof(entry_buffer);
@@ -540,7 +540,7 @@
// Enumerate all present and active interfaces.
ADBAPIHANDLE enum_handle = AdbEnumInterfaces(usb_class_id, true, true, true);
- if (NULL == enum_handle) {
+ if (nullptr == enum_handle) {
D("AdbEnumInterfaces failed: %s",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
return;
@@ -551,7 +551,7 @@
if (!known_device(next_interface->device_name)) {
// This seems to be a new device. Open it!
handle = do_usb_open(next_interface->device_name);
- if (NULL != handle) {
+ if (nullptr != handle) {
// Lets see if this interface (device) belongs to us
if (recognized_device(handle)) {
D("adding a new device %ls", next_interface->device_name);
@@ -569,7 +569,7 @@
true)) {
// Lets make sure that we don't duplicate this device
if (register_new_device(handle)) {
- register_usb_transport(handle, serial_number, NULL, 1);
+ register_usb_transport(handle, serial_number, nullptr, 1);
} else {
D("register_new_device failed for %ls", next_interface->device_name);
usb_cleanup_handle(handle);
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index f0c3629..180df8f 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -100,7 +100,7 @@
static void usb_disconnected(void* unused, atransport* t) {
LOG(INFO) << "USB disconnect";
- usb_transport = NULL;
+ usb_transport = nullptr;
needs_retry = false;
}
@@ -200,7 +200,7 @@
return;
}
- listener_fde = fdevent_create(fd, adbd_auth_listener, NULL);
+ listener_fde = fdevent_create(fd, adbd_auth_listener, nullptr);
fdevent_add(listener_fde, FDE_READ);
}
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 1128993..0b71363 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -69,17 +69,23 @@
}
static bool secure_mkdirs(const std::string& path) {
- uid_t uid = -1;
- gid_t gid = -1;
- unsigned int mode = 0775;
- uint64_t capabilities = 0;
-
if (path[0] != '/') return false;
std::vector<std::string> path_components = android::base::Split(path, "/");
std::string partial_path;
for (const auto& path_component : path_components) {
- if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR;
+ uid_t uid = -1;
+ gid_t gid = -1;
+ unsigned int mode = 0775;
+ uint64_t capabilities = 0;
+
+ if (path_component.empty()) {
+ continue;
+ }
+
+ if (partial_path.empty() || partial_path.back() != OS_PATH_SEPARATOR) {
+ partial_path += OS_PATH_SEPARATOR;
+ }
partial_path += path_component;
if (should_use_fs_config(partial_path)) {
@@ -519,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 6c3a225..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;
@@ -75,7 +76,7 @@
adb_close(fds[0]);
adb_close(fds[1]);
const char* command = "screencap";
- const char *args[2] = {command, NULL};
+ const char *args[2] = {command, nullptr};
execvp(command, (char**)args);
exit(1);
}
@@ -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, NULL, 0));
-pipefail:
- adb_close(fd);
+ TEMP_FAILURE_RETRY(waitpid(pid, nullptr, 0));
}
diff --git a/init/init_first_stage.h b/adb/daemon/framebuffer_service.h
similarity index 67%
copy from init/init_first_stage.h
copy to adb/daemon/framebuffer_service.h
index c7a3867..d99c6fe 100644
--- a/init/init_first_stage.h
+++ b/adb/daemon/framebuffer_service.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,16 +14,11 @@
* limitations under the License.
*/
-#ifndef _INIT_FIRST_STAGE_H
-#define _INIT_FIRST_STAGE_H
+#ifndef _DAEMON_FRAMEBUFFER_SERVICE_H_
+#define _DAEMON_FRAMEBUFFER_SERVICE_H_
-namespace android {
-namespace init {
+#include <android-base/unique_fd.h>
-bool DoFirstStageMount();
-void SetInitAvbVersionInRecovery();
+void framebuffer_service(android::base::unique_fd fd);
-} // namespace init
-} // namespace android
-
-#endif
+#endif // _DAEMON_FRAMEBUFFER_SERVICE_H_
diff --git a/adb/daemon/usb.h b/adb/daemon/include/adbd/usb.h
similarity index 92%
rename from adb/daemon/usb.h
rename to adb/daemon/include/adbd/usb.h
index 15a7f65..7905d9d 100644
--- a/adb/daemon/usb.h
+++ b/adb/daemon/include/adbd/usb.h
@@ -19,6 +19,7 @@
#include <atomic>
#include <condition_variable>
#include <mutex>
+#include <vector>
#include <asyncio/AsyncIO.h>
@@ -54,5 +55,9 @@
// read and write threads.
struct aio_block read_aiob;
struct aio_block write_aiob;
+
+ bool reads_zero_packets;
+ size_t io_size;
};
+usb_handle *create_usb_handle(unsigned num_bufs, unsigned io_size);
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index 367695d..175e82e 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -264,7 +264,7 @@
iov.iov_base = &dummy;
iov.iov_len = 1;
- msg.msg_name = NULL;
+ msg.msg_name = nullptr;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
@@ -393,7 +393,7 @@
control->listen_socket = s;
control->fde = fdevent_create(s, jdwp_control_event, control);
- if (control->fde == NULL) {
+ if (control->fde == nullptr) {
D("could not create fdevent for jdwp control socket");
adb_close(s);
return -1;
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index 830b35d..1bb2fbb 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,7 +176,12 @@
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);
+ 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.
@@ -197,14 +215,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 +240,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 +251,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 +265,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 +283,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 0fcf89b..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 != NULL);
-
// 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/init/log.h b/adb/daemon/set_verity_enable_state_service.h
similarity index 62%
rename from init/log.h
rename to adb/daemon/set_verity_enable_state_service.h
index 5a4eba6..9f84f35 100644
--- a/init/log.h
+++ b/adb/daemon/set_verity_enable_state_service.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -14,19 +14,11 @@
* limitations under the License.
*/
-#ifndef _INIT_LOG_H_
-#define _INIT_LOG_H_
+#ifndef _DAEMON_SET_VERITY_ENABLED_STATE_SERVICE_H_
+#define _DAEMON_SET_VERITY_ENABLED_STATE_SERVICE_H_
-#include <sys/cdefs.h>
+#include <android-base/unique_fd.h>
-namespace android {
-namespace init {
+void set_verity_enabled_state_service(android::base::unique_fd fd, bool enable);
-void InitKernelLogging(char* argv[]);
-
-int selinux_klog_callback(int level, const char* fmt, ...) __printflike(2, 3);
-
-} // namespace init
-} // namespace android
-
-#endif
+#endif // _DAEMON_SET_VERITY_ENABLED_STATE_SERVICE_H_
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index c724b11..c79d6fc 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -41,7 +41,7 @@
#include <android-base/properties.h>
#include "adb.h"
-#include "daemon/usb.h"
+#include "adbd/usb.h"
#include "transport.h"
using namespace std::chrono_literals;
@@ -53,7 +53,7 @@
#define USB_FFS_BULK_SIZE 16384
// Number of buffers needed to fit MAX_PAYLOAD, with an extra for ZLPs.
-#define USB_FFS_NUM_BUFS ((MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1)
+#define USB_FFS_NUM_BUFS ((4 * MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1)
#define cpu_to_le16(x) htole16(x)
#define cpu_to_le32(x) htole32(x)
@@ -226,16 +226,16 @@
},
};
-static void aio_block_init(aio_block* aiob) {
- aiob->iocb.resize(USB_FFS_NUM_BUFS);
- aiob->iocbs.resize(USB_FFS_NUM_BUFS);
- aiob->events.resize(USB_FFS_NUM_BUFS);
+static void aio_block_init(aio_block* aiob, unsigned num_bufs) {
+ aiob->iocb.resize(num_bufs);
+ aiob->iocbs.resize(num_bufs);
+ aiob->events.resize(num_bufs);
aiob->num_submitted = 0;
- for (unsigned i = 0; i < USB_FFS_NUM_BUFS; i++) {
+ for (unsigned i = 0; i < num_bufs; i++) {
aiob->iocbs[i] = &aiob->iocb[i];
}
memset(&aiob->ctx, 0, sizeof(aiob->ctx));
- if (io_setup(USB_FFS_NUM_BUFS, &aiob->ctx)) {
+ if (io_setup(num_bufs, &aiob->ctx)) {
D("[ aio: got error on io_setup (%d) ]", errno);
}
}
@@ -250,7 +250,7 @@
}
}
-bool init_functionfs(struct usb_handle* h) {
+static bool init_functionfs(struct usb_handle* h) {
LOG(INFO) << "initializing functionfs";
ssize_t ret;
@@ -318,6 +318,7 @@
h->read_aiob.fd = h->bulk_out;
h->write_aiob.fd = h->bulk_in;
+ h->reads_zero_packets = true;
return true;
err:
@@ -336,9 +337,7 @@
return false;
}
-static void usb_ffs_open_thread(void* x) {
- struct usb_handle* usb = (struct usb_handle*)x;
-
+static void usb_ffs_open_thread(usb_handle *usb) {
adb_thread_setname("usb ffs open");
while (true) {
@@ -359,7 +358,7 @@
}
LOG(INFO) << "registering usb transport";
- register_usb_transport(usb, 0, 0, 1);
+ register_usb_transport(usb, nullptr, nullptr, 1);
}
// never gets here
@@ -370,6 +369,7 @@
D("about to write (fd=%d, len=%d)", h->bulk_in, len);
const char* buf = static_cast<const char*>(data);
+ int orig_len = len;
while (len > 0) {
int write_len = std::min(USB_FFS_BULK_SIZE, len);
int n = adb_write(h->bulk_in, buf, write_len);
@@ -382,13 +382,14 @@
}
D("[ done fd=%d ]", h->bulk_in);
- return 0;
+ return orig_len;
}
static int usb_ffs_read(usb_handle* h, void* data, int len) {
D("about to read (fd=%d, len=%d)", h->bulk_out, len);
char* buf = static_cast<char*>(data);
+ int orig_len = len;
while (len > 0) {
int read_len = std::min(USB_FFS_BULK_SIZE, len);
int n = adb_read(h->bulk_out, buf, read_len);
@@ -401,14 +402,14 @@
}
D("[ done fd=%d ]", h->bulk_out);
- return 0;
+ return orig_len;
}
static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) {
aio_block* aiob = read ? &h->read_aiob : &h->write_aiob;
bool zero_packet = false;
- int num_bufs = len / USB_FFS_BULK_SIZE + (len % USB_FFS_BULK_SIZE == 0 ? 0 : 1);
+ int num_bufs = len / h->io_size + (len % h->io_size == 0 ? 0 : 1);
const char* cur_data = reinterpret_cast<const char*>(data);
int packet_size = getMaxPacketSize(aiob->fd);
@@ -418,7 +419,7 @@
}
for (int i = 0; i < num_bufs; i++) {
- int buf_len = std::min(len, USB_FFS_BULK_SIZE);
+ int buf_len = std::min(len, static_cast<int>(h->io_size));
io_prep(&aiob->iocb[i], aiob->fd, cur_data, buf_len, 0, read);
len -= buf_len;
@@ -427,7 +428,7 @@
if (len == 0 && buf_len % packet_size == 0 && read) {
// adb does not expect the device to send a zero packet after data transfer,
// but the host *does* send a zero packet for the device to read.
- zero_packet = true;
+ zero_packet = h->reads_zero_packets;
}
}
if (zero_packet) {
@@ -449,6 +450,7 @@
if (num_bufs == 1 && aiob->events[0].res == -EINTR) {
continue;
}
+ int ret = 0;
for (int i = 0; i < num_bufs; i++) {
if (aiob->events[i].res < 0) {
errno = -aiob->events[i].res;
@@ -456,8 +458,9 @@
<< " total bufs " << num_bufs;
return -1;
}
+ ret += aiob->events[i].res;
}
- return 0;
+ return ret;
}
}
@@ -505,9 +508,7 @@
h->notify.notify_one();
}
-static void usb_ffs_init() {
- D("[ usb_init - using FunctionFS ]");
-
+usb_handle *create_usb_handle(unsigned num_bufs, unsigned io_size) {
usb_handle* h = new usb_handle();
if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
@@ -518,20 +519,21 @@
} else {
h->write = usb_ffs_aio_write;
h->read = usb_ffs_aio_read;
- aio_block_init(&h->read_aiob);
- aio_block_init(&h->write_aiob);
+ aio_block_init(&h->read_aiob, num_bufs);
+ aio_block_init(&h->write_aiob, num_bufs);
}
+ h->io_size = io_size;
h->kick = usb_ffs_kick;
h->close = usb_ffs_close;
-
- D("[ usb_init - starting thread ]");
- std::thread(usb_ffs_open_thread, h).detach();
+ return h;
}
void usb_init() {
+ D("[ usb_init - using FunctionFS ]");
dummy_fd = adb_open("/dev/null", O_WRONLY);
CHECK_NE(dummy_fd, -1);
- usb_ffs_init();
+
+ std::thread(usb_ffs_open_thread, create_usb_handle(USB_FFS_NUM_BUFS, USB_FFS_BULK_SIZE)).detach();
}
int usb_write(usb_handle* h, const void* data, int len) {
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 098a39d..dee87bd 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -149,7 +149,7 @@
void fdevent_destroy(fdevent* fde) {
check_main_thread();
- if (fde == 0) return;
+ if (fde == nullptr) return;
if (!(fde->state & FDE_CREATED)) {
LOG(FATAL) << "destroying fde not created by fdevent_create(): " << dump_fde(fde);
}
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 a757d90..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) {
@@ -352,7 +339,7 @@
while (true) {
bool is_ambiguous = false;
std::string error = "unknown error";
- const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
+ const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : nullptr;
atransport* t = acquire_one_transport(sinfo->transport_type, serial, sinfo->transport_id,
&is_ambiguous, &error);
if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
@@ -389,8 +376,8 @@
return;
}
- int console_port = strtol(pieces[0].c_str(), NULL, 0);
- int adb_port = strtol(pieces[1].c_str(), NULL, 0);
+ int console_port = strtol(pieces[0].c_str(), nullptr, 0);
+ int adb_port = strtol(pieces[1].c_str(), nullptr, 0);
if (console_port <= 0 || adb_port <= 0) {
*response = android::base::StringPrintf("Invalid port numbers: %s", port_spec.c_str());
return;
@@ -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,19 +465,20 @@
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 NULL;
+ return nullptr;
}
#endif /* ADB_HOST */
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index de3215d..69b5180 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -337,7 +337,7 @@
s->fd = fd;
s->enqueue = local_socket_enqueue;
s->ready = local_socket_ready;
- s->shutdown = NULL;
+ s->shutdown = nullptr;
s->close = local_socket_close;
install_local_socket(s);
@@ -383,7 +383,7 @@
s = host_service_to_socket(name, serial, transport_id);
- if (s != NULL) {
+ if (s != nullptr) {
D("LS(%d) bound to '%s'", s->id, name);
return s;
}
@@ -435,7 +435,7 @@
static void remote_socket_close(asocket* s) {
if (s->peer) {
- s->peer->peer = 0;
+ s->peer->peer = nullptr;
D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
s->peer->close(s->peer);
}
@@ -488,7 +488,7 @@
send the go-ahead message when they connect */
static void local_socket_ready_notify(asocket* s) {
s->ready = local_socket_ready;
- s->shutdown = NULL;
+ s->shutdown = nullptr;
s->close = local_socket_close;
SendOkay(s->fd);
s->ready(s);
@@ -499,7 +499,7 @@
connected (to avoid closing them without a status message) */
static void local_socket_close_notify(asocket* s) {
s->ready = local_socket_ready;
- s->shutdown = NULL;
+ s->shutdown = nullptr;
s->close = local_socket_close;
SendFail(s->fd, "closed");
s->close(s);
@@ -706,7 +706,7 @@
** and tear down here.
*/
s2 = create_host_service_socket(service, serial, transport_id);
- if (s2 == 0) {
+ if (s2 == nullptr) {
D("SS(%d): couldn't create host service '%s'", s->id, service);
SendFail(s->peer->fd, "unknown host service");
goto fail;
@@ -726,7 +726,7 @@
s->peer->close = local_socket_close;
s->peer->peer = s2;
s2->peer = s->peer;
- s->peer = 0;
+ s->peer = nullptr;
D("SS(%d): okay", s->id);
s->close(s);
@@ -764,12 +764,12 @@
s->peer->ready = local_socket_ready_notify;
s->peer->shutdown = nullptr;
s->peer->close = local_socket_close_notify;
- s->peer->peer = 0;
+ s->peer->peer = nullptr;
/* give him our transport and upref it */
s->peer->transport = s->transport;
connect_to_remote(s->peer, s->smart_socket_data.data() + 4);
- s->peer = 0;
+ s->peer = nullptr;
s->close(s);
return 1;
@@ -789,9 +789,9 @@
static void smart_socket_close(asocket* s) {
D("SS(%d): closed", s->id);
if (s->peer) {
- s->peer->peer = 0;
+ s->peer->peer = nullptr;
s->peer->close(s->peer);
- s->peer = 0;
+ s->peer = nullptr;
}
delete s;
}
@@ -801,7 +801,7 @@
asocket* s = new asocket();
s->enqueue = smart_socket_enqueue;
s->ready = smart_socket_ready;
- s->shutdown = NULL;
+ s->shutdown = nullptr;
s->close = smart_socket_close;
D("SS(%d)", s->id);
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 3be99f6..f2911e0 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -39,19 +39,6 @@
#include "sysdeps/network.h"
#include "sysdeps/stat.h"
-// Some printf-like functions are implemented in terms of
-// android::base::StringAppendV, so they should use the same attribute for
-// compile-time format string checking. On Windows, if the mingw version of
-// vsnprintf is used in StringAppendV, use `gnu_printf' which allows z in %zd
-// and PRIu64 (and related) to be recognized by the compile-time checking.
-#define ADB_FORMAT_ARCHETYPE __printf__
-#ifdef __USE_MINGW_ANSI_STDIO
-#if __USE_MINGW_ANSI_STDIO
-#undef ADB_FORMAT_ARCHETYPE
-#define ADB_FORMAT_ARCHETYPE gnu_printf
-#endif
-#endif
-
#ifdef _WIN32
// Clang-only nullability specifiers
@@ -212,14 +199,12 @@
extern int adb_utime(const char *, struct utimbuf *);
extern int adb_chmod(const char *, int);
-extern int adb_vfprintf(FILE *stream, const char *format, va_list ap)
- __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 0)));
-extern int adb_vprintf(const char *format, va_list ap)
- __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 1, 0)));
-extern int adb_fprintf(FILE *stream, const char *format, ...)
- __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3)));
-extern int adb_printf(const char *format, ...)
- __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 1, 2)));
+extern int adb_vfprintf(FILE* stream, const char* format, va_list ap)
+ __attribute__((__format__(__printf__, 2, 0)));
+extern int adb_vprintf(const char* format, va_list ap) __attribute__((__format__(__printf__, 1, 0)));
+extern int adb_fprintf(FILE* stream, const char* format, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
+extern int adb_printf(const char* format, ...) __attribute__((__format__(__printf__, 1, 2)));
extern int adb_fputs(const char* buf, FILE* stream);
extern int adb_fputc(int ch, FILE* stream);
@@ -329,7 +314,6 @@
#else /* !_WIN32 a.k.a. Unix */
#include <cutils/sockets.h>
-#include <cutils/threads.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
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/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index bfac342..c94d13f 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -158,7 +158,7 @@
D( "_fh_from_int: invalid fd %d passed to %s", fd + WIN32_FH_BASE,
func );
errno = EBADF;
- return NULL;
+ return nullptr;
}
f = &_win32_fhs[fd];
@@ -167,7 +167,7 @@
D( "_fh_from_int: invalid fd %d passed to %s", fd + WIN32_FH_BASE,
func );
errno = EBADF;
- return NULL;
+ return nullptr;
}
return f;
@@ -186,12 +186,12 @@
static FH
_fh_alloc( FHClass clazz )
{
- FH f = NULL;
+ FH f = nullptr;
std::lock_guard<std::mutex> lock(_win32_lock);
for (int i = _win32_fh_next; i < WIN32_MAX_FHS; ++i) {
- if (_win32_fhs[i].clazz == NULL) {
+ if (_win32_fhs[i].clazz == nullptr) {
f = &_win32_fhs[i];
_win32_fh_next = i + 1;
f->clazz = clazz;
@@ -226,7 +226,7 @@
f->name[0] = '\0';
f->eof = 0;
f->used = 0;
- f->clazz = NULL;
+ f->clazz = nullptr;
}
return 0;
}
@@ -269,7 +269,7 @@
static int _fh_file_read(FH f, void* buf, int len) {
DWORD read_bytes;
- if (!ReadFile(f->fh_handle, buf, (DWORD)len, &read_bytes, NULL)) {
+ if (!ReadFile(f->fh_handle, buf, (DWORD)len, &read_bytes, nullptr)) {
D("adb_read: could not read %d bytes from %s", len, f->name);
errno = EIO;
return -1;
@@ -282,7 +282,7 @@
static int _fh_file_write(FH f, const void* buf, int len) {
DWORD wrote_bytes;
- if (!WriteFile(f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL)) {
+ if (!WriteFile(f->fh_handle, buf, (DWORD)len, &wrote_bytes, nullptr)) {
D("adb_file_write: could not write %d bytes from %s", len, f->name);
errno = EIO;
return -1;
@@ -337,7 +337,7 @@
return -1;
}
- result = SetFilePointer(f->fh_handle, pos, NULL, method);
+ result = SetFilePointer(f->fh_handle, pos, nullptr, method);
if (result == INVALID_SET_FILE_POINTER) {
errno = EIO;
return -1;
@@ -387,7 +387,7 @@
return -1;
}
f->fh_handle =
- CreateFileW(path_wide.c_str(), desiredAccess, shareMode, NULL, OPEN_EXISTING, 0, NULL);
+ CreateFileW(path_wide.c_str(), desiredAccess, shareMode, nullptr, OPEN_EXISTING, 0, nullptr);
if (f->fh_handle == INVALID_HANDLE_VALUE) {
const DWORD err = GetLastError();
@@ -430,7 +430,7 @@
return -1;
}
f->fh_handle = CreateFileW(path_wide.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (f->fh_handle == INVALID_HANDLE_VALUE) {
const DWORD err = GetLastError();
@@ -461,7 +461,7 @@
int adb_read(int fd, void* buf, int len) {
FH f = _fh_from_int(fd, __func__);
- if (f == NULL) {
+ if (f == nullptr) {
errno = EBADF;
return -1;
}
@@ -472,7 +472,7 @@
int adb_write(int fd, const void* buf, int len) {
FH f = _fh_from_int(fd, __func__);
- if (f == NULL) {
+ if (f == nullptr) {
errno = EBADF;
return -1;
}
@@ -483,7 +483,7 @@
ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt) {
FH f = _fh_from_int(fd, __func__);
- if (f == NULL) {
+ if (f == nullptr) {
errno = EBADF;
return -1;
}
@@ -1700,7 +1700,7 @@
// The following emulation code should write the output sequence to
// either seqstr or to seqbuf and seqbuflen.
- const char* seqstr = NULL; // NULL terminated C-string
+ const char* seqstr = nullptr; // NULL terminated C-string
// Enough space for max sequence string below, plus modifiers and/or
// escape prefix.
char seqbuf[16];
@@ -1998,7 +1998,7 @@
// * seqstr is set (and strlen can be used to determine the length).
// * seqbuf and seqbuflen are set
// Fallback to ch from Windows.
- if (seqstr != NULL) {
+ if (seqstr != nullptr) {
out = seqstr;
outlen = strlen(seqstr);
} else if (seqbuflen > 0) {
@@ -2068,9 +2068,9 @@
}
void stdin_raw_restore() {
- if (_console_handle != NULL) {
+ if (_console_handle != nullptr) {
const HANDLE in = _console_handle;
- _console_handle = NULL; // clear state
+ _console_handle = nullptr; // clear state
if (!SetConsoleMode(in, _old_console_mode)) {
// This really should not fail.
@@ -2082,7 +2082,7 @@
// Called by 'adb shell' and 'adb exec-in' (via unix_read()) to read from stdin.
int unix_read_interruptible(int fd, void* buf, size_t len) {
- if ((fd == STDIN_FILENO) && (_console_handle != NULL)) {
+ if ((fd == STDIN_FILENO) && (_console_handle != nullptr)) {
// If it is a request to read from stdin, and stdin_raw_init() has been
// called, and it successfully configured the console, then read from
// the console using Win32 console APIs and partially emulate a unix
@@ -2442,7 +2442,7 @@
// Write UTF-16 to the console.
DWORD written = 0;
- if (!WriteConsoleW(console, utf16.c_str(), utf16.length(), &written, NULL)) {
+ if (!WriteConsoleW(console, utf16.c_str(), utf16.length(), &written, nullptr)) {
errno = EIO;
return -1;
}
@@ -2455,9 +2455,8 @@
}
// Function prototype because attributes cannot be placed on func definitions.
-static int _console_vfprintf(const HANDLE console, FILE* stream,
- const char *format, va_list ap)
- __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 3, 0)));
+static int _console_vfprintf(const HANDLE console, FILE* stream, const char* format, va_list ap)
+ __attribute__((__format__(__printf__, 3, 0)));
// Internal function to format a UTF-8 string and write it to a Win32 console.
// Returns -1 on error.
@@ -2487,7 +2486,7 @@
// If there is an associated Win32 console, write to it specially,
// otherwise defer to the regular C Runtime, passing it UTF-8.
- if (console != NULL) {
+ if (console != nullptr) {
return _console_vfprintf(console, stream, format, ap);
} else {
// If vfprintf is a macro, undefine it, so we can call the real
@@ -2578,7 +2577,7 @@
// If there is an associated Win32 console, write to it specially,
// otherwise defer to the regular C Runtime, passing it UTF-8.
- if (console != NULL) {
+ if (console != nullptr) {
return _console_fwrite(ptr, size, nmemb, stream, console);
} else {
// If fwrite is a macro, undefine it, so we can call the real
diff --git a/adb/test_device.py b/adb/test_device.py
index f995be2..4abe7a7 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -750,7 +750,6 @@
if host_dir is not None:
shutil.rmtree(host_dir)
- @unittest.expectedFailure # b/25566053
def test_push_empty(self):
"""Push a directory containing an empty directory to the device."""
self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
@@ -866,6 +865,21 @@
self.assertTrue('Permission denied' in output or
'Read-only file system' in output)
+ @requires_non_root
+ def test_push_directory_creation(self):
+ """Regression test for directory creation.
+
+ Bug: http://b/110953234
+ """
+ with tempfile.NamedTemporaryFile() as tmp_file:
+ tmp_file.write('\0' * 1024 * 1024)
+ tmp_file.flush()
+ remote_path = self.DEVICE_TEMP_DIR + '/test_push_directory_creation'
+ self.device.shell(['rm', '-rf', remote_path])
+
+ remote_path += '/filename'
+ self.device.push(local=tmp_file.name, remote=remote_path)
+
def _test_pull(self, remote_file, checksum):
tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
tmp_write.close()
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 7db9bf2..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 == NULL) {
+ 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();
}
}
@@ -467,7 +467,7 @@
D("device tracker %p removed", tracker);
if (peer) {
- peer->peer = NULL;
+ peer->peer = nullptr;
peer->close(peer);
}
device_tracker_remove(tracker);
@@ -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);
@@ -699,7 +693,7 @@
transport_registration_recv = s[1];
transport_registration_fde =
- fdevent_create(transport_registration_recv, transport_registration_func, 0);
+ fdevent_create(transport_registration_recv, transport_registration_func, nullptr);
fdevent_set(transport_registration_fde, FDE_READ);
}
@@ -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_local.cpp b/adb/transport_local.cpp
index 181d666..fa38238 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -490,7 +490,7 @@
std::make_unique<BlockingConnectionAdapter>(std::move(emulator_connection)));
std::lock_guard<std::mutex> lock(local_transports_lock);
atransport* existing_transport = find_emulator_transport_by_adb_port_locked(adb_port);
- if (existing_transport != NULL) {
+ if (existing_transport != nullptr) {
D("local transport for port %d already registered (%p)?", adb_port, existing_transport);
fail = -1;
} else if (local_transports.size() >= ADB_LOCAL_TRANSPORT_MAX) {
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/transport_usb.cpp b/adb/transport_usb.cpp
index 94b2e37..602970c 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -122,7 +122,7 @@
// On Android devices, we rely on the kernel to provide buffered read.
// So we can recover automatically from EOVERFLOW.
static int remote_read(apacket* p, usb_handle* usb) {
- if (usb_read(usb, &p->msg, sizeof(amessage))) {
+ if (usb_read(usb, &p->msg, sizeof(amessage)) != sizeof(amessage)) {
PLOG(ERROR) << "remote usb: read terminated (message)";
return -1;
}
@@ -134,7 +134,8 @@
}
p->payload.resize(p->msg.data_length);
- if (usb_read(usb, &p->payload[0], p->payload.size())) {
+ if (usb_read(usb, &p->payload[0], p->payload.size())
+ != static_cast<int>(p->payload.size())) {
PLOG(ERROR) << "remote usb: terminated (data)";
return -1;
}
@@ -154,14 +155,14 @@
}
bool UsbConnection::Write(apacket* packet) {
- unsigned size = packet->msg.data_length;
+ int size = packet->msg.data_length;
- if (usb_write(handle_, &packet->msg, sizeof(packet->msg)) != 0) {
+ if (usb_write(handle_, &packet->msg, sizeof(packet->msg)) != sizeof(packet->msg)) {
PLOG(ERROR) << "remote usb: 1 - write terminated";
return false;
}
- if (packet->msg.data_length != 0 && usb_write(handle_, packet->payload.data(), size) != 0) {
+ if (packet->msg.data_length != 0 && usb_write(handle_, packet->payload.data(), size) != size) {
PLOG(ERROR) << "remote usb: 2 - write terminated";
return false;
}
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/file.cpp b/base/file.cpp
index 2f697a1..d6fe753 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -199,17 +199,23 @@
bool RemoveFileIfExists(const std::string& path, std::string* err) {
struct stat st;
#if defined(_WIN32)
- //TODO: Windows version can't handle symbol link correctly.
+ // TODO: Windows version can't handle symbolic links correctly.
int result = stat(path.c_str(), &st);
bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
#else
int result = lstat(path.c_str(), &st);
bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
#endif
+ if (result == -1) {
+ if (errno == ENOENT || errno == ENOTDIR) return true;
+ if (err != nullptr) *err = strerror(errno);
+ return false;
+ }
+
if (result == 0) {
if (!file_type_removable) {
if (err != nullptr) {
- *err = "is not a regular or symbol link file";
+ *err = "is not a regular file or symbolic link";
}
return false;
}
diff --git a/base/file_test.cpp b/base/file_test.cpp
index 02b431d..6794652 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -26,6 +26,10 @@
#include "android-base/test_utils.h"
+#if !defined(_WIN32)
+#include <pwd.h>
+#endif
+
TEST(file, ReadFileToString_ENOENT) {
std::string s("hello");
errno = 0;
@@ -115,7 +119,7 @@
ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
}
-TEST(file, RemoveFileIfExist) {
+TEST(file, RemoveFileIfExists) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
close(tf.fd);
@@ -126,9 +130,43 @@
TemporaryDir td;
ASSERT_FALSE(android::base::RemoveFileIfExists(td.path));
ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
- ASSERT_EQ("is not a regular or symbol link file", err);
+ ASSERT_EQ("is not a regular file or symbolic link", err);
}
+TEST(file, RemoveFileIfExists_ENOTDIR) {
+ TemporaryFile tf;
+ close(tf.fd);
+ tf.fd = -1;
+ std::string err{"xxx"};
+ ASSERT_TRUE(android::base::RemoveFileIfExists(std::string{tf.path} + "/abc", &err));
+ ASSERT_EQ("xxx", err);
+}
+
+#if !defined(_WIN32)
+TEST(file, RemoveFileIfExists_EACCES) {
+ // EACCES -- one of the directories in the path has no search permission
+ // root can bypass permission restrictions, so drop root.
+ if (getuid() == 0) {
+ passwd* shell = getpwnam("shell");
+ setgid(shell->pw_gid);
+ setuid(shell->pw_uid);
+ }
+
+ TemporaryDir td;
+ TemporaryFile tf(td.path);
+ close(tf.fd);
+ tf.fd = -1;
+ std::string err{"xxx"};
+ // Remove dir's search permission.
+ ASSERT_TRUE(chmod(td.path, S_IRUSR | S_IWUSR) == 0);
+ ASSERT_FALSE(android::base::RemoveFileIfExists(tf.path, &err));
+ ASSERT_EQ("Permission denied", err);
+ // Set dir's search permission again.
+ ASSERT_TRUE(chmod(td.path, S_IRWXU) == 0);
+ ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err));
+}
+#endif
+
TEST(file, Readlink) {
#if !defined(_WIN32)
// Linux doesn't allow empty symbolic links.
diff --git a/base/include/android-base/chrono_utils.h b/base/include/android-base/chrono_utils.h
index c3396ee..11fcf71 100644
--- a/base/include/android-base/chrono_utils.h
+++ b/base/include/android-base/chrono_utils.h
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_CHRONO_UTILS_H
-#define ANDROID_BASE_CHRONO_UTILS_H
+#pragma once
#include <chrono>
#include <sstream>
-#if __cplusplus > 201103L // C++14
+#if __cplusplus > 201103L && !defined(__WIN32) // C++14
using namespace std::chrono_literals;
#endif
@@ -52,5 +51,3 @@
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_CHRONO_UTILS_H
diff --git a/base/include/android-base/endian.h b/base/include/android-base/endian.h
index 6eb677c..cbbd8c9 100644
--- a/base/include/android-base/endian.h
+++ b/base/include/android-base/endian.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_ENDIAN_H
-#define ANDROID_BASE_ENDIAN_H
+#pragma once
/* A cross-platform equivalent of bionic's <sys/endian.h>. */
@@ -86,5 +85,3 @@
#define le64toh(x) (x)
#endif
-
-#endif // ANDROID_BASE_ENDIAN_H
diff --git a/base/include/android-base/errors.h b/base/include/android-base/errors.h
index 04c299c..06f29fc 100644
--- a/base/include/android-base/errors.h
+++ b/base/include/android-base/errors.h
@@ -27,8 +27,7 @@
// special handling to get the error string. Refer to Microsoft documentation
// to determine which error code to check for each function.
-#ifndef ANDROID_BASE_ERRORS_H
-#define ANDROID_BASE_ERRORS_H
+#pragma once
#include <string>
@@ -42,5 +41,3 @@
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_ERRORS_H
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index 667d6fb..908690b 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_FILE_H
-#define ANDROID_BASE_FILE_H
+#pragma once
#include <sys/stat.h>
#include <sys/types.h>
@@ -78,5 +77,3 @@
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_FILE_H
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 05a12e7..aea6ce6 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_LOGGING_H
-#define ANDROID_BASE_LOGGING_H
+#pragma once
//
// Google-style C++ logging.
@@ -488,23 +487,14 @@
// Note: to print the pointer, use "<< static_cast<const void*>(string_pointer)" instead.
// Note: a not-recommended alternative is to let Clang ignore the warning by adding
// -Wno-user-defined-warnings to CPPFLAGS.
-#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
#define OSTREAM_STRING_POINTER_USAGE_WARNING \
__attribute__((diagnose_if(true, "Unexpected logging of string pointer", "warning")))
-#else
-#define OSTREAM_STRING_POINTER_USAGE_WARNING /* empty */
-#endif
inline std::ostream& operator<<(std::ostream& stream, const std::string* string_pointer)
OSTREAM_STRING_POINTER_USAGE_WARNING {
return stream << static_cast<const void*>(string_pointer);
}
-#ifdef __clang__
#pragma clang diagnostic pop
-#endif
-#undef OSTREAM_STRING_POINTER_USAGE_WARNING
} // namespace std
-
-#endif // ANDROID_BASE_LOGGING_H
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index fd6efb2..49cc0c9 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_MACROS_H
-#define ANDROID_BASE_MACROS_H
+#pragma once
#include <stddef.h> // for size_t
#include <unistd.h> // for TEMP_FAILURE_RETRY
@@ -171,17 +170,7 @@
//
// In either case this macro has no effect on runtime behavior and performance
// of code.
-#if defined(__clang__) && defined(__has_warning)
-#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT
-#endif
-#endif
-
-#ifndef FALLTHROUGH_INTENDED
-#define FALLTHROUGH_INTENDED \
- do { \
- } while (0)
-#endif
// Current ABI string
#if defined(__arm__)
@@ -197,5 +186,3 @@
#elif defined(__mips__) && defined(__LP64__)
#define ABI_STRING "mips64"
#endif
-
-#endif // ANDROID_BASE_MACROS_H
diff --git a/base/include/android-base/memory.h b/base/include/android-base/memory.h
index 9971226..0277a03 100644
--- a/base/include/android-base/memory.h
+++ b/base/include/android-base/memory.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_MEMORY_H
-#define ANDROID_BASE_MEMORY_H
+#pragma once
namespace android {
namespace base {
@@ -37,5 +36,3 @@
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_MEMORY_H
diff --git a/base/include/android-base/parsedouble.h b/base/include/android-base/parsedouble.h
index daa6902..c273c61 100644
--- a/base/include/android-base/parsedouble.h
+++ b/base/include/android-base/parsedouble.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_PARSEDOUBLE_H
-#define ANDROID_BASE_PARSEDOUBLE_H
+#pragma once
#include <errno.h>
#include <stdlib.h>
@@ -46,5 +45,3 @@
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_PARSEDOUBLE_H
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index 1b7cc5f..bb54c99 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_PARSEINT_H
-#define ANDROID_BASE_PARSEINT_H
+#pragma once
#include <errno.h>
#include <stdlib.h>
@@ -27,9 +26,9 @@
namespace android {
namespace base {
-// Parses the unsigned decimal integer in the string 's' and sets 'out' to
-// that value. Optionally allows the caller to define a 'max' beyond which
-// otherwise valid values will be rejected. Returns boolean success; 'out'
+// Parses the unsigned decimal or hexadecimal integer in the string 's' and sets
+// 'out' to that value. Optionally allows the caller to define a 'max' beyond
+// which otherwise valid values will be rejected. Returns boolean success; 'out'
// is untouched if parsing fails.
template <typename T>
bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
@@ -43,14 +42,14 @@
const char* suffixes = "bkmgtpe";
const char* suffix;
if (!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) return false;
-#if __clang__ // TODO: win32 still builds with GCC :-(
if (__builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) return false;
-#endif
}
if (max < result) {
return false;
}
- *out = static_cast<T>(result);
+ if (out != nullptr) {
+ *out = static_cast<T>(result);
+ }
return true;
}
@@ -72,8 +71,8 @@
return ParseByteCount(s.c_str(), out, max);
}
-// Parses the signed decimal integer in the string 's' and sets 'out' to
-// that value. Optionally allows the caller to define a 'min' and 'max
+// Parses the signed decimal or hexadecimal integer in the string 's' and sets
+// 'out' to that value. Optionally allows the caller to define a 'min' and 'max'
// beyond which otherwise valid values will be rejected. Returns boolean
// success; 'out' is untouched if parsing fails.
template <typename T>
@@ -90,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;
}
@@ -104,5 +105,3 @@
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_PARSEINT_H
diff --git a/base/include/android-base/parsenetaddress.h b/base/include/android-base/parsenetaddress.h
index b4ac025..47f8b5f 100644
--- a/base/include/android-base/parsenetaddress.h
+++ b/base/include/android-base/parsenetaddress.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_PARSENETADDRESS_H
-#define ANDROID_BASE_PARSENETADDRESS_H
+#pragma once
#include <string>
@@ -34,5 +33,3 @@
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_PARSENETADDRESS_H
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 3a05143..31e5273 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_PROPERTIES_H
-#define ANDROID_BASE_PROPERTIES_H
+#pragma once
#include <sys/cdefs.h>
@@ -73,5 +72,3 @@
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_PROPERTIES_H
diff --git a/base/include/android-base/scopeguard.h b/base/include/android-base/scopeguard.h
index c314e02..e6a9d10 100644
--- a/base/include/android-base/scopeguard.h
+++ b/base/include/android-base/scopeguard.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_SCOPEGUARD_H
-#define ANDROID_BASE_SCOPEGUARD_H
+#pragma once
#include <utility> // for std::move, std::forward
@@ -66,5 +65,3 @@
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_SCOPEGUARD_H
diff --git a/base/include/android-base/stringprintf.h b/base/include/android-base/stringprintf.h
index 1fd6297..93c56af 100644
--- a/base/include/android-base/stringprintf.h
+++ b/base/include/android-base/stringprintf.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_STRINGPRINTF_H
-#define ANDROID_BASE_STRINGPRINTF_H
+#pragma once
#include <stdarg.h>
#include <string>
@@ -24,33 +23,18 @@
namespace base {
// These printf-like functions are implemented in terms of vsnprintf, so they
-// use the same attribute for compile-time format string checking. On Windows,
-// if the mingw version of vsnprintf is used, use `gnu_printf' which allows z
-// in %zd and PRIu64 (and related) to be recognized by the compile-time
-// checking.
-#define ANDROID_BASE_FORMAT_ARCHETYPE __printf__
-#ifdef __USE_MINGW_ANSI_STDIO
-#if __USE_MINGW_ANSI_STDIO
-#undef ANDROID_BASE_FORMAT_ARCHETYPE
-#define ANDROID_BASE_FORMAT_ARCHETYPE gnu_printf
-#endif
-#endif
+// use the same attribute for compile-time format string checking.
// Returns a string corresponding to printf-like formatting of the arguments.
-std::string StringPrintf(const char* fmt, ...)
- __attribute__((__format__(ANDROID_BASE_FORMAT_ARCHETYPE, 1, 2)));
+std::string StringPrintf(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
// Appends a printf-like formatting of the arguments to 'dst'.
void StringAppendF(std::string* dst, const char* fmt, ...)
- __attribute__((__format__(ANDROID_BASE_FORMAT_ARCHETYPE, 2, 3)));
+ __attribute__((__format__(__printf__, 2, 3)));
// Appends a printf-like formatting of the arguments to 'dst'.
void StringAppendV(std::string* dst, const char* format, va_list ap)
- __attribute__((__format__(ANDROID_BASE_FORMAT_ARCHETYPE, 2, 0)));
-
-#undef ANDROID_BASE_FORMAT_ARCHETYPE
+ __attribute__((__format__(__printf__, 2, 0)));
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_STRINGPRINTF_H
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index 4d9fa34..9c35560 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_STRINGS_H
-#define ANDROID_BASE_STRINGS_H
+#pragma once
#include <sstream>
#include <string>
@@ -75,5 +74,3 @@
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_STRINGS_H
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index b29676f..9e2ea97 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_TEST_UTILS_H
-#define ANDROID_BASE_TEST_UTILS_H
+#pragma once
#include <regex>
#include <string>
@@ -114,5 +113,3 @@
ADD_FAILURE() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << (str); \
} \
} while (0)
-
-#endif // ANDROID_BASE_TEST_UTILS_H
diff --git a/base/include/android-base/thread_annotations.h b/base/include/android-base/thread_annotations.h
index 1307f0e..5c55e63 100644
--- a/base/include/android-base/thread_annotations.h
+++ b/base/include/android-base/thread_annotations.h
@@ -14,14 +14,9 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_THREAD_ANNOTATIONS_H
-#define ANDROID_BASE_THREAD_ANNOTATIONS_H
+#pragma once
-#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
-#else
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
-#endif
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#define CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
@@ -109,5 +104,3 @@
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
-
-#endif // ANDROID_BASE_THREAD_ANNOTATIONS_H
diff --git a/base/include/android-base/threads.h b/base/include/android-base/threads.h
index 85e65ba..dba1fc6 100644
--- a/base/include/android-base/threads.h
+++ b/base/include/android-base/threads.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_THREADS_H
-#define ANDROID_BASE_THREADS_H
+#pragma once
#include <stdint.h>
@@ -25,4 +24,7 @@
}
} // namespace android
+#if defined(__GLIBC__)
+// bionic has this Linux-specifix call, but glibc doesn't.
+extern "C" int tgkill(int tgid, int tid, int sig);
#endif
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 5d89271..c6936f1 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_UNIQUE_FD_H
-#define ANDROID_BASE_UNIQUE_FD_H
+#pragma once
#include <fcntl.h>
@@ -43,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
@@ -54,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&);
@@ -98,7 +157,8 @@
#if !defined(_WIN32)
// Inline functions, so that they can be used header-only.
-inline bool Pipe(unique_fd* read, unique_fd* write) {
+template <typename Closer>
+inline bool Pipe(unique_fd_impl<Closer>* read, unique_fd_impl<Closer>* write) {
int pipefd[2];
#if defined(__linux__)
@@ -122,7 +182,9 @@
return true;
}
-inline bool Socketpair(int domain, int type, int protocol, unique_fd* left, unique_fd* right) {
+template <typename Closer>
+inline bool Socketpair(int domain, int type, int protocol, unique_fd_impl<Closer>* left,
+ unique_fd_impl<Closer>* right) {
int sockfd[2];
if (socketpair(domain, type, protocol, sockfd) != 0) {
return false;
@@ -132,7 +194,8 @@
return true;
}
-inline bool Socketpair(int type, unique_fd* left, unique_fd* right) {
+template <typename Closer>
+inline bool Socketpair(int type, unique_fd_impl<Closer>* left, unique_fd_impl<Closer>* right) {
return Socketpair(AF_UNIX, type, 0, left, right);
}
@@ -143,12 +206,4 @@
template <typename T>
int close(const android::base::unique_fd_impl<T>&)
-#if defined(__clang__)
- __attribute__((__unavailable__(
-#else
- __attribute__((__error__(
-#endif
- "close called on unique_fd"
- )));
-
-#endif // ANDROID_BASE_UNIQUE_FD_H
+ __attribute__((__unavailable__("close called on unique_fd")));
diff --git a/base/include/android-base/utf8.h b/base/include/android-base/utf8.h
index c9cc1ab..4b91623 100755
--- a/base/include/android-base/utf8.h
+++ b/base/include/android-base/utf8.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BASE_UTF8_H
-#define ANDROID_BASE_UTF8_H
+#pragma once
#ifdef _WIN32
#include <string>
@@ -102,5 +101,3 @@
} // namespace utf8
} // namespace base
} // namespace android
-
-#endif // ANDROID_BASE_UTF8_H
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/threads.cpp b/base/threads.cpp
index a71382b..48f6197 100644
--- a/base/threads.cpp
+++ b/base/threads.cpp
@@ -46,3 +46,9 @@
} // namespace base
} // namespace android
+
+#if defined(__GLIBC__)
+int tgkill(int tgid, int tid, int sig) {
+ return syscall(__NR_tgkill, tgid, tid, sig);
+}
+#endif
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/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index ddd1caf..71d3ecb 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -24,6 +24,7 @@
NORMAL="${ESCAPE}[0m"
# Best guess to an average device's reboot time, refined as tests return
DURATION_DEFAULT=45
+STOP_ON_FAILURE=false
# Helper functions
@@ -50,11 +51,18 @@
fi
}
+[ "USAGE: get_property <prop>
+
+Returns the property value" ]
+get_property() {
+ adb shell getprop ${1} 2>&1 </dev/null
+}
+
[ "USAGE: isDebuggable
Returns: true if device is (likely) a debug build" ]
isDebuggable() {
- if inAdb && [ 1 -ne `adb shell getprop ro.debuggable` ]; then
+ if inAdb && [ 1 -ne `get_property ro.debuggable` ]; then
false
fi
}
@@ -93,7 +101,7 @@
return 1
fi
adb shell su root setprop persist.test.boot.reason "'${1}'" 2>/dev/null
- test_reason="`adb shell getprop persist.test.boot.reason 2>/dev/null`"
+ test_reason="`get_property persist.test.boot.reason`"
if [ X"${test_reason}" != X"${1}" ]; then
echo "ERROR: can not set persist.test.boot.reason to '${1}'." >&2
return 1
@@ -188,9 +196,9 @@
if [ 0 != ${counter} ]; then
adb wait-for-device </dev/null >/dev/null 2>/dev/null
fi
- if [ -n "`adb shell getprop sys.boot.reason </dev/null 2>/dev/null`" ]
+ if [ -n "`get_property sys.boot.reason`" ]
then
- vals=`adb shell getprop </dev/null 2>/dev/null |
+ vals=`get_property |
sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
then
@@ -223,15 +231,38 @@
rval="${2}"
shift 2
if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
- echo "ERROR: expected \"${lval}\" got \"${rval}\"" >&2
- if [ -n "${*}" ] ; then
- echo " ${*}" >&2
+ if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
+*}" ]; then
+ echo "ERROR: expected \"${lval}\"" >&2
+ echo " got \"${rval}\"" |
+ sed ': again
+ N
+ s/\(\n\)\([^ ]\)/\1 \2/
+ t again' >&2
+ if [ -n "${*}" ] ; then
+ echo " ${*}" >&2
+ fi
+ else
+ echo "ERROR: expected \"${lval}\" got \"${rval}\" ${*}" >&2
fi
return 1
fi
if [ -n "${*}" ] ; then
if [ X"${lval}" != X"${rval}" ]; then
- echo "INFO: ok \"${lval}\"(=\"${rval}\") ${*}" >&2
+ if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval%
+*}" ]; then
+ echo "INFO: ok \"${lval}\"" >&2
+ echo " = \"${rval}\"" |
+ sed ': again
+ N
+ s/\(\n\)\([^ ]\)/\1 \2/
+ t again' >&2
+ if [ -n "${*}" ] ; then
+ echo " ${*}" >&2
+ fi
+ else
+ echo "INFO: ok \"${lval}\" = \"${rval}\" ${*}" >&2
+ fi
else
echo "INFO: ok \"${lval}\" ${*}" >&2
fi
@@ -250,7 +281,7 @@
property="${1}"
value="${2}"
shift 2
- val=`adb shell getprop ${property} 2>&1`
+ val=`get_property ${property}`
EXPECT_EQ "${value}" "${val}" for Android property ${property}
local_ret=${?}
if [ 0 != ${local_ret} -a "ro.boot.bootreason" = "${property}" ]; then
@@ -317,6 +348,7 @@
init : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
init : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
init : Command 'exec - system log -- /system/bin/bootstat --record_time_since_factory_reset' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
+init : Command 'exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc
(/system/bin/bootstat --record_boot_complete)'...
(/system/bin/bootstat --record_boot_complete)' (pid${SPACE}
(/system/bin/bootstat --record_boot_reason)'...
@@ -392,6 +424,9 @@
echo "${GREEN}[ OK ]${NORMAL} ${TEST} ${*}"
else
echo "${RED}[ FAILED ]${NORMAL} ${TEST} ${*}"
+ if ${STOP_ON_FAILURE}; then
+ exit ${save_ret}
+ fi
fi
return ${save_ret}
}
@@ -462,7 +497,7 @@
NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
validate_property() {
- val="`adb shell getprop ${1} 2>&1`"
+ val=`get_property ${1}`
ret=`validate_reason "${val}"`
if [ "reboot" = "${ret}" ]; then
ret=`validate_reason "reboot,${val}"`
@@ -470,6 +505,17 @@
echo ${ret}
}
+[ "USAGE: check_boilerblate_properties
+
+Check for common property values" ]
+check_boilerplate_properties() {
+ EXPECT_PROPERTY persist.sys.boot.reason ""
+ save_ret=${?}
+ reason=`validate_property sys.boot.reason`
+ ( exit ${save_ret} ) # because one can not just do ?=${save_ret}
+ EXPECT_PROPERTY persist.sys.boot.reason.history "${reason},[1-9][0-9]*\(\|[^0-9].*\)"
+}
+
#
# Actual test frames
#
@@ -487,6 +533,7 @@
duration_test 1
wait_for_screen
retval=0
+ # sys.boot.reason is last for a reason
check_set="ro.boot.bootreason sys.boot.reason.last sys.boot.reason"
bootloader=""
# NB: this test could fail if performed _after_ optional_factory_reset test
@@ -498,12 +545,11 @@
check_set="ro.boot.bootreason sys.boot.reason"
bootloader="bootloader"
fi
- EXPECT_PROPERTY persist.sys.boot.reason ""
for prop in ${check_set}; do
reason=`validate_property ${prop}`
EXPECT_PROPERTY ${prop} ${reason} || retval=${?}
done
- # sys.boot.reason is last for a reason
+ check_boilerplate_properties || retval=${?}
report_bootstat_logs ${reason} ${bootloader}
return ${retval}
}
@@ -557,7 +603,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason "\(reboot,ota\|bootloader\)"
EXPECT_PROPERTY sys.boot.reason.last bootloader
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,ota bootloader
}
@@ -572,7 +618,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,ota
EXPECT_PROPERTY sys.boot.reason.last reboot,ota
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,ota
}
@@ -604,7 +650,7 @@
fi
EXPECT_PROPERTY sys.boot.reason ${reasons}
EXPECT_PROPERTY sys.boot.reason.last ${reason}
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs ${reason} ${bootloader_reason}
}
@@ -638,7 +684,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
EXPECT_PROPERTY sys.boot.reason.last "reboot,.*"
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,factory_reset reboot, reboot,adb \
"-bootstat: Failed to read /data/misc/bootstat/build_date: No such file or directory" \
"-bootstat: Failed to parse boot time record: /data/misc/bootstat/build_date"
@@ -670,7 +716,7 @@
( exit ${save_ret} ) # because one can not just do ?=${save_ret}
EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
EXPECT_PROPERTY sys.boot.reason.last ""
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,factory_reset bootloader \
"-bootstat: Failed to read /data/misc/bootstat/last_boot_time_utc: No such file or directory" \
"-bootstat: Failed to parse boot time record: /data/misc/bootstat/last_boot_time_utc" \
@@ -744,7 +790,7 @@
EXPECT_PROPERTY sys.boot.reason shutdown,battery
EXPECT_PROPERTY sys.boot.reason.last cold
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs shutdown,battery "-bootstat: Battery level at shutdown 2%"
exitPstore
}
@@ -766,7 +812,7 @@
wait_for_screen -n >&2
EXPECT_PROPERTY sys.boot.reason shutdown,battery
EXPECT_PROPERTY sys.boot.reason.last shutdown,battery
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs shutdown,battery
}
@@ -787,7 +833,7 @@
wait_for_screen -n >&2
EXPECT_PROPERTY sys.boot.reason shutdown,thermal,battery
EXPECT_PROPERTY sys.boot.reason.last shutdown,thermal,battery
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs shutdown,thermal,battery
}
@@ -824,7 +870,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs kernel_panic,sysrq
exitPstore
}
@@ -852,7 +898,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs kernel_panic,sysrq,test \
"-bootstat: Unknown boot reason: kernel_panic,sysrq,test"
exitPstore
@@ -883,7 +929,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs kernel_panic,hung
exitPstore
}
@@ -916,7 +962,7 @@
wait_for_screen -n >&2
EXPECT_PROPERTY sys.boot.reason shutdown,thermal
EXPECT_PROPERTY sys.boot.reason.last shutdown,thermal
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs shutdown,thermal
}
@@ -937,7 +983,7 @@
wait_for_screen -n >&2
EXPECT_PROPERTY sys.boot.reason shutdown,userrequested
EXPECT_PROPERTY sys.boot.reason.last shutdown,userrequested
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs shutdown,userrequested
}
@@ -954,7 +1000,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,shell
EXPECT_PROPERTY sys.boot.reason.last reboot,shell
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,shell
}
@@ -971,7 +1017,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,adb
EXPECT_PROPERTY sys.boot.reason.last reboot,adb
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,adb
}
@@ -1007,7 +1053,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
EXPECT_PROPERTY sys.boot.reason.last reboot,its_just_so_hard
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,its_just_so_hard
}
@@ -1057,7 +1103,7 @@
EXPECT_PROPERTY ro.boot.bootreason "${bootloader_expected}"
EXPECT_PROPERTY sys.boot.reason "${sys_expected}"
EXPECT_PROPERTY sys.boot.reason.last "${last_expected}"
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs "${sys_expected}"
}
@@ -1111,88 +1157,98 @@
shift 2
fi
-if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then
- echo "USAGE: ${0##*/} [-s SERIAL] [tests]"
- echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
- exit 0
-fi
+# Helpful for debugging, allows us to import the functions.
+if [ X"--macros" != X"${1}" ]; then
-# Check if all conditions for the script are sane
+ if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then
+ echo "USAGE: ${0##*/} [-s SERIAL] [tests]"
+ echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
+ exit 0
+ fi
-if [ -z "${ANDROID_SERIAL}" ]; then
- ndev=`(
- adb devices | grep -v 'List of devices attached'
- fastboot devices
- ) |
- grep -v "^[${SPACE}${TAB}]*\$" |
- wc -l`
- if [ ${ndev} -gt 1 ]; then
- echo "ERROR: no target device specified, ${ndev} connected" >&2
- echo "${RED}[ FAILED ]${NORMAL}"
- exit 1
+ if [ X"--stop" = X"${1}" ]; then
+ STOP_ON_FAILURE=true
+ shift
fi
- echo "WARNING: no target device specified" >&2
-fi
-ret=0
+ # Check if all conditions for the script are sane
-# Test Series
-if [ X"all" = X"${*}" ]; then
- # automagically pick up all test_<function>s.
- eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
- if [ X"nothing" = X"${1}" ]; then
- shift 1
- fi
-fi
-if [ -z "$*" ]; then
- # automagically pick up all test_<function>, except test_optional_<function>.
- eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null |
- grep -v '^optional_'`
- if [ -z "${2}" ]; then
- # Hard coded should shell fail to find them above (search/permission issues)
- eval set properties ota cold factory_reset hard battery unknown \
- kernel_panic kernel_panic_subreason kernel_panic_hung warm \
- thermal_shutdown userrequested_shutdown shell_reboot adb_reboot \
- Its_Just_So_Hard_reboot bootloader_normal bootloader_watchdog \
- bootloader_kernel_panic bootloader_oem_powerkey \
- bootloader_wdog_reset bootloader_wdog_reset bootloader_wdog_reset \
- bootloader_hard bootloader_recovery
- fi
- if [ X"nothing" = X"${1}" ]; then
- shift 1
- fi
-fi
-echo "INFO: selected test(s): ${@}" >&2
-echo
-# Prepare device
-setBootloaderBootReason 2>/dev/null
-# Start pouring through the tests.
-failures=
-successes=
-for t in "${@}"; do
- wrap_test ${t}
- retval=${?}
- if [ 0 = ${retval} ]; then
- if [ -z "${successes}" ]; then
- successes=${t}
- else
- successes="${successes} ${t}"
+ if [ -z "${ANDROID_SERIAL}" ]; then
+ ndev=`(
+ adb devices | grep -v 'List of devices attached'
+ fastboot devices
+ ) |
+ grep -v "^[${SPACE}${TAB}]*\$" |
+ wc -l`
+ if [ ${ndev} -gt 1 ]; then
+ echo "ERROR: no target device specified, ${ndev} connected" >&2
+ echo "${RED}[ FAILED ]${NORMAL}"
+ exit 1
fi
- else
- ret=${retval}
- if [ -z "${failures}" ]; then
- failures=${t}
- else
- failures="${failures} ${t}"
+ echo "WARNING: no target device specified" >&2
+ fi
+
+ ret=0
+
+ # Test Series
+ if [ X"all" = X"${*}" ]; then
+ # automagically pick up all test_<function>s.
+ eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
+ if [ X"nothing" = X"${1}" ]; then
+ shift 1
fi
fi
+ if [ -z "$*" ]; then
+ # automagically pick up all test_<function>, except test_optional_<function>.
+ eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null |
+ grep -v '^optional_'`
+ if [ -z "${2}" ]; then
+ # Hard coded should shell fail to find them (search/permission issues)
+ eval set properties ota cold factory_reset hard battery unknown \
+ kernel_panic kernel_panic_subreason kernel_panic_hung warm \
+ thermal_shutdown userrequested_shutdown shell_reboot adb_reboot \
+ Its_Just_So_Hard_reboot bootloader_normal bootloader_watchdog \
+ bootloader_kernel_panic bootloader_oem_powerkey \
+ bootloader_wdog_reset bootloader_cold bootloader_warm \
+ bootloader_hard bootloader_recovery
+ fi
+ if [ X"nothing" = X"${1}" ]; then
+ shift 1
+ fi
+ fi
+ echo "INFO: selected test(s): ${@}" >&2
echo
-done
+ # Prepare device
+ setBootloaderBootReason 2>/dev/null
+ # Start pouring through the tests.
+ failures=
+ successes=
+ for t in "${@}"; do
+ wrap_test ${t}
+ retval=${?}
+ if [ 0 = ${retval} ]; then
+ if [ -z "${successes}" ]; then
+ successes=${t}
+ else
+ successes="${successes} ${t}"
+ fi
+ else
+ ret=${retval}
+ if [ -z "${failures}" ]; then
+ failures=${t}
+ else
+ failures="${failures} ${t}"
+ fi
+ fi
+ echo
+ done
-if [ -n "${successes}" ]; then
- echo "${GREEN}[ PASSED ]${NORMAL} ${successes}"
+ if [ -n "${successes}" ]; then
+ echo "${GREEN}[ PASSED ]${NORMAL} ${successes}"
+ fi
+ if [ -n "${failures}" ]; then
+ echo "${RED}[ FAILED ]${NORMAL} ${failures}"
+ fi
+ exit ${ret}
+
fi
-if [ -n "${failures}" ]; then
- echo "${RED}[ FAILED ]${NORMAL} ${failures}"
-fi
-exit ${ret}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 7ec57ec..4d9f1ac 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -27,6 +27,7 @@
#include <cstddef>
#include <cstdio>
#include <ctime>
+#include <iterator>
#include <map>
#include <memory>
#include <regex>
@@ -123,12 +124,12 @@
return std::string(&temp[0], len);
}
-void SetProperty(const char* key, const std::string& val) {
- property_set(key, val.c_str());
+bool SetProperty(const char* key, const std::string& val) {
+ return property_set(key, val.c_str()) == 0;
}
-void SetProperty(const char* key, const char* val) {
- property_set(key, val);
+bool SetProperty(const char* key, const char* val) {
+ return property_set(key, val) == 0;
}
constexpr int32_t kEmptyBootReason = 0;
@@ -735,8 +736,49 @@
const char system_reboot_reason_property[] = "sys.boot.reason";
const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
const char last_last_reboot_reason_property[] = "sys.boot.reason.last";
+constexpr size_t history_reboot_reason_size = 4;
+const char history_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY ".history";
const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
+// Land system_boot_reason into system_reboot_reason_property.
+// Shift system_boot_reason into history_reboot_reason_property.
+void BootReasonAddToHistory(const std::string& system_boot_reason) {
+ if (system_boot_reason.empty()) return;
+ LOG(INFO) << "Canonical boot reason: " << system_boot_reason;
+ auto old_system_boot_reason = GetProperty(system_reboot_reason_property);
+ if (!SetProperty(system_reboot_reason_property, system_boot_reason)) {
+ SetProperty(system_reboot_reason_property, system_boot_reason.substr(0, PROPERTY_VALUE_MAX - 1));
+ }
+ auto reason_history = android::base::Split(GetProperty(history_reboot_reason_property), "\n");
+ static auto mark = time(nullptr);
+ auto mark_str = std::string(",") + std::to_string(mark);
+ auto marked_system_boot_reason = system_boot_reason + mark_str;
+ if (!reason_history.empty()) {
+ // delete any entries that we just wrote in a previous
+ // call and leveraging duplicate line handling
+ auto last = old_system_boot_reason + mark_str;
+ // trim the list to (history_reboot_reason_size - 1)
+ ssize_t max = history_reboot_reason_size;
+ for (auto it = reason_history.begin(); it != reason_history.end();) {
+ if (it->empty() || (last == *it) || (marked_system_boot_reason == *it) || (--max <= 0)) {
+ it = reason_history.erase(it);
+ } else {
+ last = *it;
+ ++it;
+ }
+ }
+ }
+ // insert at the front, concatenating mark (<epoch time>) detail to the value.
+ reason_history.insert(reason_history.begin(), marked_system_boot_reason);
+ // If the property string is too long ( > PROPERTY_VALUE_MAX)
+ // we get an error, so trim out last entry and try again.
+ while (!(SetProperty(history_reboot_reason_property, android::base::Join(reason_history, '\n')))) {
+ auto it = std::prev(reason_history.end());
+ if (it == reason_history.end()) break;
+ reason_history.erase(it);
+ }
+}
+
// Scrub, Sanitize, Standardize and Enhance the boot reason string supplied.
std::string BootReasonStrToReason(const std::string& boot_reason) {
std::string ret(GetProperty(system_reboot_reason_property));
@@ -795,6 +837,8 @@
{"!warm", "wdt_by_pass_pwk"}, // change flavour of blunt
{"!reboot", "^wdt$"}, // change flavour of blunt
{"reboot,tool", "tool_by_pass_pwk"},
+ {"!reboot,longkey", "reboot_longkey"},
+ {"!reboot,longkey", "kpdpwr"},
{"bootloader", ""},
};
@@ -930,13 +974,11 @@
if (!boot_event_store.GetBootEvent(kBuildDateKey, &record)) {
boot_complete_prefix = "factory_reset_" + boot_complete_prefix;
boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
- LOG(INFO) << "Canonical boot reason: reboot,factory_reset";
- SetProperty(system_reboot_reason_property, "reboot,factory_reset");
+ BootReasonAddToHistory("reboot,factory_reset");
} else if (build_date != record.second) {
boot_complete_prefix = "ota_" + boot_complete_prefix;
boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
- LOG(INFO) << "Canonical boot reason: reboot,ota";
- SetProperty(system_reboot_reason_property, "reboot,ota");
+ BootReasonAddToHistory("reboot,ota");
}
return boot_complete_prefix;
@@ -1034,7 +1076,7 @@
const std::string bootloader_boot_reason(GetProperty(bootloader_reboot_reason_property));
const std::string system_boot_reason(BootReasonStrToReason(bootloader_boot_reason));
// Record the scrubbed system_boot_reason to the property
- SetProperty(system_reboot_reason_property, system_boot_reason);
+ BootReasonAddToHistory(system_boot_reason);
// Shift last_reboot_reason_property to last_last_reboot_reason_property
std::string last_boot_reason(GetProperty(last_reboot_reason_property));
if (last_boot_reason.empty() || isKernelRebootReason(system_boot_reason)) {
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index f31337d..f0fe1d0 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -183,6 +183,8 @@
fprintf(stderr, " exit call exit(1)\n");
fprintf(stderr, "\n");
fprintf(stderr, " fortify fail a _FORTIFY_SOURCE check\n");
+ fprintf(stderr, " fdsan_file close a file descriptor that's owned by a FILE*\n");
+ fprintf(stderr, " fdsan_dir close a file descriptor that's owned by a DIR*\n");
fprintf(stderr, " seccomp fail a seccomp check\n");
#if defined(__arm__)
fprintf(stderr, " kuser_helper_version call kuser_helper_version\n");
@@ -236,39 +238,45 @@
// Actions.
if (!strcasecmp(arg, "SIGSEGV-non-null")) {
- sigsegv_non_null();
+ sigsegv_non_null();
} else if (!strcasecmp(arg, "smash-stack")) {
- volatile int len = 128;
- return smash_stack(&len);
+ volatile int len = 128;
+ return smash_stack(&len);
} else if (!strcasecmp(arg, "stack-overflow")) {
- overflow_stack(nullptr);
+ overflow_stack(nullptr);
} else if (!strcasecmp(arg, "nostack")) {
- crashnostack();
+ crashnostack();
} else if (!strcasecmp(arg, "exit")) {
- exit(1);
+ exit(1);
} else if (!strcasecmp(arg, "call-null")) {
return crash_null();
} else if (!strcasecmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
- return crash(42);
+ return crash(42);
} else if (!strcasecmp(arg, "abort")) {
- maybe_abort();
+ maybe_abort();
} else if (!strcasecmp(arg, "assert")) {
- __assert("some_file.c", 123, "false");
+ __assert("some_file.c", 123, "false");
} else if (!strcasecmp(arg, "assert2")) {
- __assert2("some_file.c", 123, "some_function", "false");
+ __assert2("some_file.c", 123, "some_function", "false");
} else if (!strcasecmp(arg, "fortify")) {
- char buf[10];
- __read_chk(-1, buf, 32, 10);
- while (true) pause();
+ char buf[10];
+ __read_chk(-1, buf, 32, 10);
+ while (true) pause();
+ } else if (!strcasecmp(arg, "fdsan_file")) {
+ FILE* f = fopen("/dev/null", "r");
+ close(fileno(f));
+ } else if (!strcasecmp(arg, "fdsan_dir")) {
+ DIR* d = opendir("/dev/");
+ close(dirfd(d));
} else if (!strcasecmp(arg, "LOG(FATAL)")) {
- LOG(FATAL) << "hello " << 123;
+ LOG(FATAL) << "hello " << 123;
} else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL")) {
- LOG_ALWAYS_FATAL("hello %s", "world");
+ LOG_ALWAYS_FATAL("hello %s", "world");
} else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL_IF")) {
- LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
+ LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
} else if (!strcasecmp(arg, "SIGFPE")) {
- raise(SIGFPE);
- return EXIT_SUCCESS;
+ raise(SIGFPE);
+ return EXIT_SUCCESS;
} else if (!strcasecmp(arg, "SIGILL")) {
#if defined(__aarch64__)
__asm__ volatile(".word 0\n");
@@ -280,28 +288,28 @@
#error
#endif
} else if (!strcasecmp(arg, "SIGTRAP")) {
- raise(SIGTRAP);
- return EXIT_SUCCESS;
+ raise(SIGTRAP);
+ return EXIT_SUCCESS;
} else if (!strcasecmp(arg, "fprintf-NULL")) {
- fprintf_null();
+ fprintf_null();
} else if (!strcasecmp(arg, "readdir-NULL")) {
- readdir_null();
+ readdir_null();
} else if (!strcasecmp(arg, "strlen-NULL")) {
- return strlen_null();
+ return strlen_null();
} else if (!strcasecmp(arg, "pthread_join-NULL")) {
- return pthread_join(0, nullptr);
+ return pthread_join(0, nullptr);
} else if (!strcasecmp(arg, "heap-usage")) {
- abuse_heap();
+ abuse_heap();
} else if (!strcasecmp(arg, "leak")) {
- leak();
+ leak();
} else if (!strcasecmp(arg, "SIGSEGV-unmapped")) {
- char* map = reinterpret_cast<char*>(mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS, -1, 0));
- munmap(map, sizeof(int));
- map[0] = '8';
+ char* map = reinterpret_cast<char*>(
+ mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
+ munmap(map, sizeof(int));
+ map[0] = '8';
} else if (!strcasecmp(arg, "seccomp")) {
- set_system_seccomp_filter();
- syscall(99999);
+ set_system_seccomp_filter();
+ syscall(99999);
#if defined(__arm__)
} else if (!strcasecmp(arg, "kuser_helper_version")) {
return __kuser_helper_version;
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index c07a34a..615fb46 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -59,7 +59,16 @@
#include "protocol.h"
using android::base::Pipe;
-using android::base::unique_fd;
+
+// We muck with our fds in a 'thread' that doesn't share the same fd table.
+// Close fds in that thread with a raw close syscall instead of going through libc.
+struct FdsanBypassCloser {
+ static void Close(int fd) {
+ syscall(__NR_close, fd);
+ }
+};
+
+using unique_fd = android::base::unique_fd_impl<FdsanBypassCloser>;
// see man(2) prctl, specifically the section about PR_GET_NAME
#define MAX_TASK_NAME_LEN (16)
@@ -299,7 +308,8 @@
debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg);
for (int i = 0; i < 1024; ++i) {
- close(i);
+ // Don't use close to avoid bionic's file descriptor ownership checks.
+ syscall(__NR_close, i);
}
int devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 433bb46..0b8a936 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -474,7 +474,7 @@
static void dump_log_file(log_t* log, pid_t pid, const char* filename, unsigned int tail) {
bool first = true;
- struct logger_list* logger_list;
+ logger_list* logger_list;
if (!log->should_retrieve_logcat) {
return;
@@ -488,11 +488,9 @@
return;
}
- struct log_msg log_entry;
-
while (true) {
+ log_msg log_entry;
ssize_t actual = android_logger_list_read(logger_list, &log_entry);
- struct logger_entry* entry;
if (actual < 0) {
if (actual == -EINTR) {
@@ -515,8 +513,6 @@
// high-frequency debug diagnostics should just be written to
// the tombstone file.
- entry = &log_entry.entry_v1;
-
if (first) {
_LOG(log, logtype::LOGS, "--------- %slog %s\n",
tail ? "tail end of " : "", filename);
@@ -527,19 +523,8 @@
//
// We want to display it in the same format as "logcat -v threadtime"
// (although in this case the pid is redundant).
- static const char* kPrioChars = "!.VDIWEFS";
- unsigned hdr_size = log_entry.entry.hdr_size;
- if (!hdr_size) {
- hdr_size = sizeof(log_entry.entry_v1);
- }
- if ((hdr_size < sizeof(log_entry.entry_v1)) ||
- (hdr_size > sizeof(log_entry.entry))) {
- continue;
- }
- char* msg = reinterpret_cast<char*>(log_entry.buf) + hdr_size;
-
char timeBuf[32];
- time_t sec = static_cast<time_t>(entry->sec);
+ time_t sec = static_cast<time_t>(log_entry.entry.sec);
struct tm tmBuf;
struct tm* ptm;
ptm = localtime_r(&sec, &tmBuf);
@@ -547,17 +532,23 @@
if (log_entry.id() == LOG_ID_EVENTS) {
if (!g_eventTagMap) {
- g_eventTagMap = android_openEventTagMap(NULL);
+ g_eventTagMap = android_openEventTagMap(nullptr);
}
AndroidLogEntry e;
char buf[512];
- android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
- _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8.*s: %s\n",
- timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
- 'I', (int)e.tagLen, e.tag, e.message);
+ if (android_log_processBinaryLogBuffer(&log_entry.entry_v1, &e, g_eventTagMap, buf,
+ sizeof(buf)) == 0) {
+ _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8.*s: %s\n", timeBuf,
+ log_entry.entry.nsec / 1000000, log_entry.entry.pid, log_entry.entry.tid, 'I',
+ (int)e.tagLen, e.tag, e.message);
+ }
continue;
}
+ char* msg = log_entry.msg();
+ if (msg == nullptr) {
+ continue;
+ }
unsigned char prio = msg[0];
char* tag = msg + 1;
msg = tag + strlen(tag) + 1;
@@ -568,20 +559,21 @@
*nl-- = '\0';
}
+ static const char* kPrioChars = "!.VDIWEFS";
char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
// Look for line breaks ('\n') and display each text line
// on a separate line, prefixed with the header, like logcat does.
do {
nl = strchr(msg, '\n');
- if (nl) {
+ if (nl != nullptr) {
*nl = '\0';
++nl;
}
- _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
- timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
- prioChar, tag, msg);
+ _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n", timeBuf,
+ log_entry.entry.nsec / 1000000, log_entry.entry.pid, log_entry.entry.tid, prioChar, tag,
+ msg);
} while ((msg = nl));
}
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 1f6f3c8..8bdc02f 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -287,9 +287,7 @@
case SIGFPE: return "SIGFPE";
case SIGILL: return "SIGILL";
case SIGSEGV: return "SIGSEGV";
-#if defined(SIGSTKFLT)
case SIGSTKFLT: return "SIGSTKFLT";
-#endif
case SIGSTOP: return "SIGSTOP";
case SIGSYS: return "SIGSYS";
case SIGTRAP: return "SIGTRAP";
@@ -311,8 +309,14 @@
case ILL_PRVREG: return "ILL_PRVREG";
case ILL_COPROC: return "ILL_COPROC";
case ILL_BADSTK: return "ILL_BADSTK";
+ case ILL_BADIADDR:
+ return "ILL_BADIADDR";
+ case __ILL_BREAK:
+ return "ILL_BREAK";
+ case __ILL_BNDMOD:
+ return "ILL_BNDMOD";
}
- static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
+ static_assert(NSIGILL == __ILL_BNDMOD, "missing ILL_* si_code");
break;
case SIGBUS:
switch (si->si_code) {
@@ -334,36 +338,44 @@
case FPE_FLTRES: return "FPE_FLTRES";
case FPE_FLTINV: return "FPE_FLTINV";
case FPE_FLTSUB: return "FPE_FLTSUB";
+ case __FPE_DECOVF:
+ return "FPE_DECOVF";
+ case __FPE_DECDIV:
+ return "FPE_DECDIV";
+ case __FPE_DECERR:
+ return "FPE_DECERR";
+ case __FPE_INVASC:
+ return "FPE_INVASC";
+ case __FPE_INVDEC:
+ return "FPE_INVDEC";
+ case FPE_FLTUNK:
+ return "FPE_FLTUNK";
+ case FPE_CONDTRAP:
+ return "FPE_CONDTRAP";
}
- static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
+ static_assert(NSIGFPE == FPE_CONDTRAP, "missing FPE_* si_code");
break;
case SIGSEGV:
switch (si->si_code) {
case SEGV_MAPERR: return "SEGV_MAPERR";
case SEGV_ACCERR: return "SEGV_ACCERR";
-#if defined(SEGV_BNDERR)
case SEGV_BNDERR: return "SEGV_BNDERR";
-#endif
-#if defined(SEGV_PKUERR)
case SEGV_PKUERR: return "SEGV_PKUERR";
-#endif
+ case SEGV_ACCADI:
+ return "SEGV_ACCADI";
+ case SEGV_ADIDERR:
+ return "SEGV_ADIDERR";
+ case SEGV_ADIPERR:
+ return "SEGV_ADIPERR";
}
-#if defined(SEGV_PKUERR)
- static_assert(NSIGSEGV == SEGV_PKUERR, "missing SEGV_* si_code");
-#elif defined(SEGV_BNDERR)
- static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code");
-#else
- static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
-#endif
+ static_assert(NSIGSEGV == SEGV_ADIPERR, "missing SEGV_* si_code");
break;
-#if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too.
case SIGSYS:
switch (si->si_code) {
case SYS_SECCOMP: return "SYS_SECCOMP";
}
static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
break;
-#endif
case SIGTRAP:
switch (si->si_code) {
case TRAP_BRKPT: return "TRAP_BRKPT";
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/constants.h b/fastboot/constants.h
new file mode 100644
index 0000000..5e7e955
--- /dev/null
+++ b/fastboot/constants.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#define FB_CMD_GETVAR "getvar"
+#define FB_CMD_DOWNLOAD "download"
+#define FB_CMD_UPLOAD "upload"
+#define FB_CMD_VERIFY "verify"
+#define FB_CMD_FLASH "flash"
+#define FB_CMD_ERASE "erase"
+#define FB_CMD_BOOT "boot"
+#define FB_CMD_SET_ACTIVE "set_active"
+#define FB_CMD_CONTINUE "continue"
+#define FB_CMD_REBOOT "reboot"
+#define FB_CMD_SHUTDOWN "shutdown"
+#define FB_CMD_REBOOT_BOOTLOADER "reboot-bootloader"
+#define FB_CMD_POWERDOWN "powerdown"
+
+#define RESPONSE_OKAY "OKAY"
+#define RESPONSE_FAIL "FAIL"
+#define RESPONSE_DATA "DATA"
+#define RESPONSE_INFO "INFO"
+
+#define FB_COMMAND_SZ 64
+#define FB_RESPONSE_SZ 64
+
+#define FB_VAR_VERSION "version"
+#define FB_VAR_VERSION_BOOTLOADER "version-bootloader"
+#define FB_VAR_VERSION_BASEBAND "version-baseband"
+#define FB_VAR_PRODUCT "product"
+#define FB_VAR_SERIALNO "serialno"
+#define FB_VAR_SECURE "secure"
+#define FB_VAR_UNLOCKED "unlocked"
+#define FB_VAR_CURRENT_SLOT "current-slot"
+#define FB_VAR_MAX_DOWNLOAD_SIZE "max-download-size"
+#define FB_VAR_HAS_SLOT "has-slot"
+#define FB_VAR_SLOT_COUNT "slot-count"
+#define FB_VAR_PARTITION_SIZE "partition-size"
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index f271d09..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>
@@ -42,6 +41,7 @@
#include <android-base/stringprintf.h>
+#include "constants.h"
#include "transport.h"
enum Op {
@@ -77,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 = "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) {
@@ -110,12 +113,12 @@
}
void fb_set_active(const std::string& slot) {
- Action& a = queue_action(OP_COMMAND, "set_active:" + slot);
+ Action& a = queue_action(OP_COMMAND, FB_CMD_SET_ACTIVE ":" + slot);
a.msg = "Setting current slot to '" + slot + "'";
}
void fb_queue_erase(const std::string& partition) {
- Action& a = queue_action(OP_COMMAND, "erase:" + partition);
+ Action& a = queue_action(OP_COMMAND, FB_CMD_ERASE ":" + partition);
a.msg = "Erasing '" + partition + "'";
}
@@ -125,7 +128,7 @@
a.size = sz;
a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024);
- Action& b = queue_action(OP_COMMAND, "flash:" + partition);
+ Action& b = queue_action(OP_COMMAND, FB_CMD_FLASH ":" + partition);
b.msg = "Writing '" + partition + "'";
}
@@ -135,7 +138,7 @@
a.size = sz;
a.msg = android::base::StringPrintf("Sending '%s' (%u KB)", partition.c_str(), sz / 1024);
- Action& b = queue_action(OP_COMMAND, "flash:" + partition);
+ Action& b = queue_action(OP_COMMAND, FB_CMD_FLASH ":" + partition);
b.msg = "Writing '" + partition + "'";
}
@@ -147,7 +150,7 @@
a.msg = android::base::StringPrintf("Sending sparse '%s' %zu/%zu (%u KB)", partition.c_str(),
current, total, sz / 1024);
- Action& b = queue_action(OP_COMMAND, "flash:" + partition);
+ Action& b = queue_action(OP_COMMAND, FB_CMD_FLASH ":" + partition);
b.msg = android::base::StringPrintf("Writing sparse '%s' %zu/%zu", partition.c_str(), current,
total);
}
@@ -223,7 +226,7 @@
void fb_queue_require(const std::string& product, const std::string& var, bool invert,
size_t nvalues, const char** values) {
- Action& a = queue_action(OP_QUERY, "getvar:" + var);
+ Action& a = queue_action(OP_QUERY, FB_CMD_GETVAR ":" + var);
a.product = product;
a.data = values;
a.size = nvalues;
@@ -243,7 +246,7 @@
}
void fb_queue_display(const std::string& label, const std::string& var) {
- Action& a = queue_action(OP_QUERY, "getvar:" + var);
+ Action& a = queue_action(OP_QUERY, FB_CMD_GETVAR ":" + var);
a.data = xstrdup(label.c_str());
a.func = cb_display;
}
@@ -258,7 +261,7 @@
}
void fb_queue_query_save(const std::string& var, char* dest, uint32_t dest_size) {
- Action& a = queue_action(OP_QUERY, "getvar:" + var);
+ Action& a = queue_action(OP_QUERY, FB_CMD_GETVAR ":" + var);
a.data = dest;
a.size = dest_size;
a.func = cb_save;
@@ -270,7 +273,7 @@
}
void fb_queue_reboot() {
- Action& a = queue_action(OP_COMMAND, "reboot");
+ Action& a = queue_action(OP_COMMAND, FB_CMD_REBOOT);
a.func = cb_do_nothing;
a.msg = "Rebooting";
}
@@ -309,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();
@@ -318,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 66%
rename from fastboot/fastboot.h
rename to fastboot/engine.h
index 2935eb5..74aaa6a 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/engine.h
@@ -34,24 +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 64
-#define FB_RESPONSE_SZ 64
+//#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,
@@ -69,35 +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. On Windows,
-// if the mingw version of vsnprintf is used, use `gnu_printf' which allows z
-// in %zd and PRIu64 (and related) to be recognized by the compile-time
-// checking.
-#define FASTBOOT_FORMAT_ARCHETYPE __printf__
-#ifdef __USE_MINGW_ANSI_STDIO
-#if __USE_MINGW_ANSI_STDIO
-#undef FASTBOOT_FORMAT_ARCHETYPE
-#define FASTBOOT_FORMAT_ARCHETYPE gnu_printf
-#endif
-#endif
-void die(const char* fmt, ...) __attribute__((__noreturn__))
-__attribute__((__format__(FASTBOOT_FORMAT_ARCHETYPE, 1, 2)));
-void verbose(const char* fmt, ...) __attribute__((__format__(FASTBOOT_FORMAT_ARCHETYPE, 1, 2)));
-#undef FASTBOOT_FORMAT_ARCHETYPE
-
/* 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.bash b/fastboot/fastboot.bash
index dca3b4e..cb1d354 100644
--- a/fastboot/fastboot.bash
+++ b/fastboot/fastboot.bash
@@ -16,11 +16,11 @@
#
_fastboot() {
- if ! type -t "$1" >/dev/null; then
+ if ! check_type "$1" >/dev/null; then
return
fi
- if type -t _init_completion >/dev/null; then
+ if check_type _init_completion >/dev/null; then
_init_completion || return
fi
@@ -135,7 +135,7 @@
xspec=$2
# Since we're probably doing file completion here, don't add a space after.
- if [[ $(type -t compopt) = "builtin" ]]; then
+ if [[ $(check_type compopt) == "builtin" ]]; then
compopt -o plusdirs
if [[ "${xspec}" == "" ]]; then
COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
@@ -175,7 +175,7 @@
fi
}
-if [[ $(type -t compopt) = "builtin" ]]; then
+if [[ $(check_type compopt) == "builtin" ]]; then
complete -F _fastboot fastboot
else
complete -o nospace -F _fastboot fastboot
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 fda6f5d..0000000
--- a/fastboot/protocol.cpp
+++ /dev/null
@@ -1,365 +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 "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 (r < 4) {
- g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
- transport->Close();
- return -1;
- }
-
- if (!memcmp(status, "INFO", 4)) {
- verbose("received INFO \"%s\"", status + 4);
- fprintf(stderr, "(bootloader) %s\n", status + 4);
- continue;
- }
-
- if (!memcmp(status, "OKAY", 4)) {
- verbose("received OKAY \"%s\"", status + 4);
- if (response) {
- strcpy(response, status + 4);
- }
- return 0;
- }
-
- if (!memcmp(status, "FAIL", 4)) {
- verbose("received FAIL \"%s\"", status + 4);
- if (r > 4) {
- g_error = android::base::StringPrintf("remote: %s", status + 4);
- } else {
- g_error = "remote failure";
- }
- return -1;
- }
-
- if (!memcmp(status, "DATA", 4) && size > 0){
- verbose("received DATA %s", status + 4);
- uint32_t dsize = strtol(status + 4, 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("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("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, "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("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/fs_mgr/Android.bp b/fs_mgr/Android.bp
index b0b4839..a3ce879 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -38,7 +38,6 @@
include_dirs: ["system/vold"],
srcs: [
"fs_mgr.cpp",
- "fs_mgr_dm_ioctl.cpp",
"fs_mgr_format.cpp",
"fs_mgr_verity.cpp",
"fs_mgr_avb.cpp",
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 9856126..b3df811 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -31,6 +31,7 @@
#include <time.h>
#include <unistd.h>
+#include <functional>
#include <memory>
#include <string>
#include <thread>
@@ -50,6 +51,7 @@
#include <ext4_utils/ext4_sb.h>
#include <ext4_utils/ext4_utils.h>
#include <ext4_utils/wipe.h>
+#include <libdm/dm.h>
#include <linux/fs.h>
#include <linux/loop.h>
#include <linux/magic.h>
@@ -59,7 +61,6 @@
#include "fs_mgr.h"
#include "fs_mgr_avb.h"
#include "fs_mgr_priv.h"
-#include "fs_mgr_priv_dm_ioctl.h"
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
#define KEY_IN_FOOTER "footer"
@@ -76,6 +77,8 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+using DeviceMapper = android::dm::DeviceMapper;
+
// record fs stat
enum FsStatFlags {
FS_STAT_IS_EXT4 = 0x0001,
@@ -802,14 +805,9 @@
return true;
}
- android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDONLY));
- if (dm_fd < 0) {
- PLOG(ERROR) << "open /dev/device-mapper failed";
- return false;
- }
- struct dm_ioctl io;
+ DeviceMapper& dm = DeviceMapper::Instance();
std::string device_name;
- if (!fs_mgr_dm_get_device_name(&io, rec->blk_device, dm_fd, &device_name)) {
+ if (!dm.GetDmDevicePathByName(rec->blk_device, &device_name)) {
return false;
}
free(rec->blk_device);
@@ -1359,7 +1357,7 @@
return true;
}
-bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback) {
+bool fs_mgr_update_verity_state(std::function<fs_mgr_verity_state_callback> callback) {
if (!callback) {
return false;
}
@@ -1369,12 +1367,6 @@
return false;
}
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC)));
- if (fd == -1) {
- PERROR << "Error opening device mapper";
- return false;
- }
-
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
fs_mgr_free_fstab);
if (!fstab) {
@@ -1382,8 +1374,8 @@
return false;
}
- alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
- struct dm_ioctl* io = (struct dm_ioctl*)buffer;
+ DeviceMapper& dm = DeviceMapper::Instance();
+
bool system_root = android::base::GetProperty("ro.build.system_root_image", "") == "true";
for (int i = 0; i < fstab->num_entries; i++) {
@@ -1399,20 +1391,20 @@
mount_point = basename(fstab->recs[i].mount_point);
}
- fs_mgr_dm_ioctl_init(io, DM_BUF_SIZE, mount_point);
+ const char* status = nullptr;
- const char* status;
- if (ioctl(fd, DM_TABLE_STATUS, io)) {
+ std::vector<DeviceMapper::TargetInfo> table;
+ if (!dm.GetTableStatus(mount_point, &table) || table.empty() || table[0].data.empty()) {
if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
status = "V";
} else {
PERROR << "Failed to query DM_TABLE_STATUS for " << mount_point.c_str();
continue;
}
+ } else {
+ status = table[0].data.c_str();
}
- status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
-
// To be consistent in vboot 1.0 and vboot 2.0 (AVB), change the mount_point
// back to 'system' for the callback. So it has property [partition.system.verified]
// instead of [partition.vroot.verified].
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 2020fa6..7c6093e 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -33,11 +33,11 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <libavb/libavb.h>
+#include <libdm/dm.h>
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_avb_ops.h"
-#include "fs_mgr_priv_dm_ioctl.h"
#include "fs_mgr_priv_sha.h"
static inline bool nibble_value(const char& c, uint8_t* value) {
@@ -218,9 +218,9 @@
// Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel.
// See the following link for more details:
// https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
-static std::string construct_verity_table(const AvbHashtreeDescriptor& hashtree_desc,
- const std::string& salt, const std::string& root_digest,
- const std::string& blk_device) {
+static bool construct_verity_table(const AvbHashtreeDescriptor& hashtree_desc,
+ const std::string& salt, const std::string& root_digest,
+ const std::string& blk_device, android::dm::DmTable* table) {
// Loads androidboot.veritymode from kernel cmdline.
std::string verity_mode;
if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) {
@@ -235,145 +235,56 @@
dm_verity_mode = "ignore_corruption";
} else if (verity_mode != "eio") { // Default dm_verity_mode is eio.
LERROR << "Unknown androidboot.veritymode: " << verity_mode;
- return "";
+ return false;
}
- // dm-verity construction parameters:
- // <version> <dev> <hash_dev>
- // <data_block_size> <hash_block_size>
- // <num_data_blocks> <hash_start_block>
- // <algorithm> <digest> <salt>
- // [<#opt_params> <opt_params>]
- std::ostringstream verity_table;
- verity_table << hashtree_desc.dm_verity_version << " " << blk_device << " " << blk_device << " "
- << hashtree_desc.data_block_size << " " << hashtree_desc.hash_block_size << " "
- << hashtree_desc.image_size / hashtree_desc.data_block_size << " "
- << hashtree_desc.tree_offset / hashtree_desc.hash_block_size << " "
- << hashtree_desc.hash_algorithm << " " << root_digest << " " << salt;
+ std::ostringstream hash_algorithm;
+ hash_algorithm << hashtree_desc.hash_algorithm;
- // Continued from the above optional parameters:
- // [<#opt_params> <opt_params>]
- int optional_argc = 0;
- std::ostringstream optional_args;
-
- // dm-verity optional parameters for FEC (forward error correction):
- // use_fec_from_device <fec_dev>
- // fec_roots <num>
- // fec_blocks <num>
- // fec_start <offset>
+ android::dm::DmTargetVerity target(0, hashtree_desc.image_size / 512,
+ hashtree_desc.dm_verity_version, blk_device, blk_device,
+ hashtree_desc.data_block_size, hashtree_desc.hash_block_size,
+ hashtree_desc.image_size / hashtree_desc.data_block_size,
+ hashtree_desc.tree_offset / hashtree_desc.hash_block_size,
+ hash_algorithm.str(), root_digest, salt);
if (hashtree_desc.fec_size > 0) {
- // Note that fec_blocks is the size that FEC covers, *NOT* the
- // size of the FEC data. Since we use FEC for everything up until
- // the FEC data, it's the same as the offset (fec_start).
- optional_argc += 8;
- // clang-format off
- optional_args << "use_fec_from_device " << blk_device
- << " fec_roots " << hashtree_desc.fec_num_roots
- << " fec_blocks " << hashtree_desc.fec_offset / hashtree_desc.data_block_size
- << " fec_start " << hashtree_desc.fec_offset / hashtree_desc.data_block_size
- << " ";
- // clang-format on
+ target.UseFec(blk_device, hashtree_desc.fec_num_roots,
+ hashtree_desc.fec_offset / hashtree_desc.data_block_size,
+ hashtree_desc.fec_offset / hashtree_desc.data_block_size);
}
-
if (!dm_verity_mode.empty()) {
- optional_argc += 1;
- optional_args << dm_verity_mode << " ";
+ target.SetVerityMode(dm_verity_mode);
}
-
// Always use ignore_zero_blocks.
- optional_argc += 1;
- optional_args << "ignore_zero_blocks";
+ target.IgnoreZeroBlocks();
- verity_table << " " << optional_argc << " " << optional_args.str();
- return verity_table.str();
-}
+ LINFO << "Built verity table: '" << target.GetParameterString() << "'";
-static bool load_verity_table(struct dm_ioctl* io, const std::string& dm_device_name, int fd,
- uint64_t image_size, const std::string& verity_table) {
- fs_mgr_dm_ioctl_init(io, DM_BUF_SIZE, dm_device_name);
-
- // The buffer consists of [dm_ioctl][dm_target_spec][verity_params].
- char* buffer = (char*)io;
-
- // Builds the dm_target_spec arguments.
- struct dm_target_spec* dm_target = (struct dm_target_spec*)&buffer[sizeof(struct dm_ioctl)];
- io->flags = DM_READONLY_FLAG;
- io->target_count = 1;
- dm_target->status = 0;
- dm_target->sector_start = 0;
- dm_target->length = image_size / 512;
- strcpy(dm_target->target_type, "verity");
-
- // Builds the verity params.
- char* verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
- size_t bufsize = DM_BUF_SIZE - (verity_params - buffer);
-
- LINFO << "Loading verity table: '" << verity_table << "'";
-
- // Copies verity_table to verity_params (including the terminating null byte).
- if (verity_table.size() > bufsize - 1) {
- LERROR << "Verity table size too large: " << verity_table.size()
- << " (max allowable size: " << bufsize - 1 << ")";
- return false;
- }
- memcpy(verity_params, verity_table.c_str(), verity_table.size() + 1);
-
- // Sets ext target boundary.
- verity_params += verity_table.size() + 1;
- verity_params = (char*)(((unsigned long)verity_params + 7) & ~7);
- dm_target->next = verity_params - buffer;
-
- // Sends the ioctl to load the verity table.
- if (ioctl(fd, DM_TABLE_LOAD, io)) {
- PERROR << "Error loading verity table";
- return false;
- }
-
- return true;
+ return table->AddTarget(std::make_unique<android::dm::DmTargetVerity>(target));
}
static bool hashtree_dm_verity_setup(struct fstab_rec* fstab_entry,
const AvbHashtreeDescriptor& hashtree_desc,
const std::string& salt, const std::string& root_digest,
bool wait_for_verity_dev) {
- // Gets the device mapper fd.
- android::base::unique_fd fd(open("/dev/device-mapper", O_RDWR));
- if (fd < 0) {
- PERROR << "Error opening device mapper";
+ android::dm::DmTable table;
+ if (!construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device, &table) ||
+ !table.valid()) {
+ LERROR << "Failed to construct verity table.";
return false;
}
+ table.set_readonly(true);
- // Creates the device.
- alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
- struct dm_ioctl* io = (struct dm_ioctl*)buffer;
const std::string mount_point(basename(fstab_entry->mount_point));
- if (!fs_mgr_dm_create_device(io, mount_point, fd)) {
+ android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
+ if (!dm.CreateDevice(mount_point, table)) {
LERROR << "Couldn't create verity device!";
return false;
}
- // Gets the name of the device file.
- std::string verity_blk_name;
- if (!fs_mgr_dm_get_device_name(io, mount_point, fd, &verity_blk_name)) {
- LERROR << "Couldn't get verity device number!";
- return false;
- }
-
- std::string verity_table =
- construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device);
- if (verity_table.empty()) {
- LERROR << "Failed to construct verity table.";
- return false;
- }
-
- // Loads the verity mapping table.
- if (!load_verity_table(io, mount_point, fd, hashtree_desc.image_size, verity_table)) {
- LERROR << "Couldn't load verity table!";
- return false;
- }
-
- // Activates the device.
- if (!fs_mgr_dm_resume_table(io, mount_point, fd)) {
+ std::string dev_path;
+ if (!dm.GetDmDevicePathByName(mount_point, &dev_path)) {
+ LERROR << "Couldn't get verity device path!";
return false;
}
@@ -382,10 +293,10 @@
// Updates fstab_rec->blk_device to verity device name.
free(fstab_entry->blk_device);
- fstab_entry->blk_device = strdup(verity_blk_name.c_str());
+ fstab_entry->blk_device = strdup(dev_path.c_str());
// Makes sure we've set everything up properly.
- if (wait_for_verity_dev && !fs_mgr_wait_for_file(verity_blk_name, 1s)) {
+ if (wait_for_verity_dev && !fs_mgr_wait_for_file(dev_path, 1s)) {
return false;
}
diff --git a/fs_mgr/fs_mgr_dm_ioctl.cpp b/fs_mgr/fs_mgr_dm_ioctl.cpp
deleted file mode 100644
index 3a7fae4..0000000
--- a/fs_mgr/fs_mgr_dm_ioctl.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2016 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 <errno.h>
-#include <string.h>
-
-#include <android-base/logging.h>
-#include <sys/ioctl.h>
-
-#include "fs_mgr_priv.h"
-#include "fs_mgr_priv_dm_ioctl.h"
-
-void fs_mgr_dm_ioctl_init(struct dm_ioctl* io, size_t size, const std::string& name) {
- memset(io, 0, size);
- io->data_size = size;
- io->data_start = sizeof(struct dm_ioctl);
- io->version[0] = 4;
- io->version[1] = 0;
- io->version[2] = 0;
- if (!name.empty()) {
- strlcpy(io->name, name.c_str(), sizeof(io->name));
- }
-}
-
-bool fs_mgr_dm_create_device(struct dm_ioctl* io, const std::string& name, int fd) {
- fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
- if (ioctl(fd, DM_DEV_CREATE, io)) {
- PERROR << "Error creating device mapping";
- return false;
- }
- return true;
-}
-
-bool fs_mgr_dm_destroy_device(struct dm_ioctl* io, const std::string& name, int fd) {
- fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
- if (ioctl(fd, DM_DEV_REMOVE, io)) {
- PERROR << "Error removing device mapping";
- return false;
- }
- return true;
-}
-
-bool fs_mgr_dm_get_device_name(struct dm_ioctl* io, const std::string& name, int fd,
- std::string* out_dev_name) {
- FS_MGR_CHECK(out_dev_name != nullptr);
-
- fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
- if (ioctl(fd, DM_DEV_STATUS, io)) {
- PERROR << "Error fetching device-mapper device number";
- return false;
- }
-
- int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
- *out_dev_name = "/dev/block/dm-" + std::to_string(dev_num);
-
- return true;
-}
-
-bool fs_mgr_dm_resume_table(struct dm_ioctl* io, const std::string& name, int fd) {
- fs_mgr_dm_ioctl_init(io, sizeof(*io), name);
- if (ioctl(fd, DM_DEV_SUSPEND, io)) {
- PERROR << "Error activating device table";
- return false;
- }
- return true;
-}
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index ed42d40..05e03e1 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -40,102 +40,62 @@
#include <liblp/reader.h>
#include "fs_mgr_priv.h"
-#include "fs_mgr_priv_dm_ioctl.h"
namespace android {
namespace fs_mgr {
-std::string LogicalPartitionExtent::Serialize() const {
- // Note: we need to include an explicit null-terminator.
- std::string argv =
- android::base::StringPrintf("%s %" PRIu64, block_device_.c_str(), first_sector_);
- argv.push_back(0);
+using DeviceMapper = android::dm::DeviceMapper;
+using DmTable = android::dm::DmTable;
+using DmTarget = android::dm::DmTarget;
+using DmTargetZero = android::dm::DmTargetZero;
+using DmTargetLinear = android::dm::DmTargetLinear;
- // The kernel expects each target to be aligned.
- size_t spec_bytes = sizeof(struct dm_target_spec) + argv.size();
- size_t padding = ((spec_bytes + 7) & ~7) - spec_bytes;
- for (size_t i = 0; i < padding; i++) {
- argv.push_back(0);
- }
-
- struct dm_target_spec spec;
- spec.sector_start = logical_sector_;
- spec.length = num_sectors_;
- spec.status = 0;
- strcpy(spec.target_type, "linear");
- spec.next = sizeof(struct dm_target_spec) + argv.size();
-
- return std::string((char*)&spec, sizeof(spec)) + argv;
-}
-
-static bool LoadDmTable(int dm_fd, const LogicalPartition& partition) {
- // Combine all dm_target_spec buffers together.
- std::string target_string;
- for (const auto& extent : partition.extents) {
- target_string += extent.Serialize();
- }
-
- // Allocate the ioctl buffer.
- size_t buffer_size = sizeof(struct dm_ioctl) + target_string.size();
- std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(buffer_size);
-
- // Initialize the ioctl buffer header, then copy our target specs in.
- struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
- fs_mgr_dm_ioctl_init(io, buffer_size, partition.name);
- io->target_count = partition.extents.size();
- if (partition.attributes & kPartitionReadonly) {
- io->flags |= DM_READONLY_FLAG;
- }
- memcpy(io + 1, target_string.c_str(), target_string.size());
-
- if (ioctl(dm_fd, DM_TABLE_LOAD, io)) {
- PERROR << "Failed ioctl() on DM_TABLE_LOAD, partition " << partition.name;
- return false;
- }
- return true;
-}
-
-static bool LoadTablesAndActivate(int dm_fd, const LogicalPartition& partition) {
- if (!LoadDmTable(dm_fd, partition)) {
- return false;
- }
-
- struct dm_ioctl io;
- return fs_mgr_dm_resume_table(&io, partition.name, dm_fd);
-}
-
-static bool CreateDmDeviceForPartition(int dm_fd, const LogicalPartition& partition) {
- struct dm_ioctl io;
- if (!fs_mgr_dm_create_device(&io, partition.name, dm_fd)) {
- return false;
- }
- if (!LoadTablesAndActivate(dm_fd, partition)) {
- // Remove the device rather than leave it in an inactive state.
- fs_mgr_dm_destroy_device(&io, partition.name, dm_fd);
- return false;
- }
-
- LINFO << "Created device-mapper device: " << partition.name;
- return true;
-}
-
-bool CreateLogicalPartitions(const LogicalPartitionTable& table) {
- android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDWR));
- if (dm_fd < 0) {
- PLOG(ERROR) << "failed to open /dev/device-mapper";
- return false;
- }
- for (const auto& partition : table.partitions) {
- if (!CreateDmDeviceForPartition(dm_fd, partition)) {
- LOG(ERROR) << "could not create dm-linear device for partition: " << partition.name;
+static bool CreateDmTable(const std::string& block_device, const LpMetadata& metadata,
+ const LpMetadataPartition& partition, DmTable* table) {
+ uint64_t sector = 0;
+ for (size_t i = 0; i < partition.num_extents; i++) {
+ const auto& extent = metadata.extents[partition.first_extent_index + i];
+ std::unique_ptr<DmTarget> target;
+ switch (extent.target_type) {
+ case LP_TARGET_TYPE_ZERO:
+ target = std::make_unique<DmTargetZero>(sector, extent.num_sectors);
+ break;
+ case LP_TARGET_TYPE_LINEAR:
+ target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, block_device,
+ extent.target_data);
+ break;
+ default:
+ LOG(ERROR) << "Unknown target type in metadata: " << extent.target_type;
+ return false;
+ }
+ if (!table->AddTarget(std::move(target))) {
return false;
}
+ sector += extent.num_sectors;
+ }
+ if (partition.attributes & LP_PARTITION_ATTR_READONLY) {
+ table->set_readonly(true);
}
return true;
}
-std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree() {
- return nullptr;
+static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
+ const LpMetadataPartition& partition, std::string* path) {
+ DeviceMapper& dm = DeviceMapper::Instance();
+
+ DmTable table;
+ if (!CreateDmTable(block_device, metadata, partition, &table)) {
+ return false;
+ }
+ std::string name = GetPartitionName(partition);
+ if (!dm.CreateDevice(name, table)) {
+ return false;
+ }
+ if (!dm.GetDmDevicePathByName(name, path)) {
+ return false;
+ }
+ LINFO << "Created logical partition " << name << " on device " << *path;
+ return true;
}
bool CreateLogicalPartitions(const std::string& block_device) {
@@ -145,22 +105,35 @@
LOG(ERROR) << "Could not read partition table.";
return true;
}
-
- LogicalPartitionTable table;
for (const auto& partition : metadata->partitions) {
- LogicalPartition new_partition;
- new_partition.name = GetPartitionName(partition);
- new_partition.attributes = partition.attributes;
- for (size_t i = 0; i < partition.num_extents; i++) {
- const auto& extent = metadata->extents[partition.first_extent_index + i];
- new_partition.extents.emplace_back(new_partition.num_sectors, extent.target_data,
- extent.num_sectors, block_device.c_str());
- new_partition.num_sectors += extent.num_sectors;
+ std::string path;
+ if (!CreateLogicalPartition(block_device, *metadata.get(), partition, &path)) {
+ LERROR << "Could not create logical partition: " << GetPartitionName(partition);
+ return false;
}
- table.partitions.push_back(new_partition);
}
+ return true;
+}
- return CreateLogicalPartitions(table);
+bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
+ const std::string& partition_name, std::string* path) {
+ auto metadata = ReadMetadata(block_device.c_str(), metadata_slot);
+ if (!metadata) {
+ LOG(ERROR) << "Could not read partition table.";
+ return true;
+ }
+ for (const auto& partition : metadata->partitions) {
+ if (GetPartitionName(partition) == partition_name) {
+ return CreateLogicalPartition(block_device, *metadata.get(), partition, path);
+ }
+ }
+ LERROR << "Could not find any partition with name: " << partition_name;
+ return false;
+}
+
+bool DestroyLogicalPartition(const std::string& name) {
+ DeviceMapper& dm = DeviceMapper::Instance();
+ return dm.DeleteDevice(name);
}
} // namespace fs_mgr
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index a14dba3..a5b3fe8 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -235,41 +235,46 @@
* If not found, the loop exits with fl[i].name being null.
*/
for (i = 0; fl[i].name; i++) {
- if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
+ auto name = fl[i].name;
+ auto len = strlen(name);
+ auto end = len;
+ if (name[end - 1] == '=') --end;
+ if (!strncmp(p, name, len) && (p[end] == name[end])) {
f |= fl[i].flag;
- if ((fl[i].flag == MF_CRYPT) && flag_vals) {
+ if (!flag_vals) break;
+ if (p[end] != '=') break;
+ char* arg = p + end + 1;
+ auto flag = fl[i].flag;
+ if (flag == MF_CRYPT) {
/* The encryptable flag is followed by an = and the
* location of the keys. Get it and return it.
*/
- flag_vals->key_loc = strdup(strchr(p, '=') + 1);
- } else if ((fl[i].flag == MF_VERIFY) && flag_vals) {
+ flag_vals->key_loc = strdup(arg);
+ } else if (flag == MF_VERIFY) {
/* If the verify flag is followed by an = and the
* location for the verity state, get it and return it.
*/
- char *start = strchr(p, '=');
- if (start) {
- flag_vals->verity_loc = strdup(start + 1);
- }
- } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
+ flag_vals->verity_loc = strdup(arg);
+ } else if (flag == MF_FORCECRYPT) {
/* The forceencrypt flag is followed by an = and the
* location of the keys. Get it and return it.
*/
- flag_vals->key_loc = strdup(strchr(p, '=') + 1);
- } else if ((fl[i].flag == MF_FORCEFDEORFBE) && flag_vals) {
+ flag_vals->key_loc = strdup(arg);
+ } else if (flag == MF_FORCEFDEORFBE) {
/* The forcefdeorfbe flag is followed by an = and the
* location of the keys. Get it and return it.
*/
- flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+ flag_vals->key_loc = strdup(arg);
flag_vals->file_contents_mode = EM_AES_256_XTS;
flag_vals->file_names_mode = EM_AES_256_CTS;
- } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
+ } else if (flag == MF_FILEENCRYPTION) {
/* The fileencryption flag is followed by an = and
* the mode of contents encryption, then optionally a
* : and the mode of filenames encryption (defaults
* to aes-256-cts). Get it and return it.
*/
- char *mode = strchr(p, '=') + 1;
- char *colon = strchr(mode, ':');
+ auto mode = arg;
+ auto colon = strchr(mode, ':');
if (colon) {
*colon = '\0';
}
@@ -283,33 +288,30 @@
} else {
flag_vals->file_names_mode = EM_AES_256_CTS;
}
- } else if ((fl[i].flag == MF_KEYDIRECTORY) && flag_vals) {
+ } else if (flag == MF_KEYDIRECTORY) {
/* The metadata flag is followed by an = and the
* directory for the keys. Get it and return it.
*/
- flag_vals->key_dir = strdup(strchr(p, '=') + 1);
- } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
+ flag_vals->key_dir = strdup(arg);
+ } else if (flag == MF_LENGTH) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
*/
- flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
- } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
+ flag_vals->part_length = strtoll(arg, NULL, 0);
+ } else if (flag == MF_VOLDMANAGED) {
/* The voldmanaged flag is followed by an = and the
* label, a colon and the partition number or the
* word "auto", e.g.
* voldmanaged=sdcard:3
* Get and return them.
*/
- char *label_start;
- char *label_end;
- char *part_start;
+ auto label_start = arg;
+ auto label_end = strchr(label_start, ':');
- label_start = strchr(p, '=') + 1;
- label_end = strchr(p, ':');
if (label_end) {
flag_vals->label = strndup(label_start,
(int) (label_end - label_start));
- part_start = strchr(p, ':') + 1;
+ auto part_start = label_end + 1;
if (!strcmp(part_start, "auto")) {
flag_vals->partnum = -1;
} else {
@@ -318,41 +320,41 @@
} else {
LERROR << "Warning: voldmanaged= flag malformed";
}
- } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
- flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
- } else if ((fl[i].flag == MF_MAX_COMP_STREAMS) && flag_vals) {
- flag_vals->max_comp_streams = strtoll(strchr(p, '=') + 1, NULL, 0);
- } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
- int is_percent = !!strrchr(p, '%');
- unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
+ } else if (flag == MF_SWAPPRIO) {
+ flag_vals->swap_prio = strtoll(arg, NULL, 0);
+ } else if (flag == MF_MAX_COMP_STREAMS) {
+ flag_vals->max_comp_streams = strtoll(arg, NULL, 0);
+ } else if (flag == MF_ZRAMSIZE) {
+ auto is_percent = !!strrchr(arg, '%');
+ auto val = strtoll(arg, NULL, 0);
if (is_percent)
flag_vals->zram_size = calculate_zram_size(val);
else
flag_vals->zram_size = val;
- } else if ((fl[i].flag == MF_RESERVEDSIZE) && flag_vals) {
+ } else if (flag == MF_RESERVEDSIZE) {
/* The reserved flag is followed by an = and the
* reserved size of the partition. Get it and return it.
*/
- flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
- } else if ((fl[i].flag == MF_ERASEBLKSIZE) && flag_vals) {
+ flag_vals->reserved_size = parse_size(arg);
+ } else if (flag == MF_ERASEBLKSIZE) {
/* The erase block size flag is followed by an = and the flash
* erase block size. Get it, check that it is a power of 2 and
* at least 4096, and return it.
*/
- unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
+ auto val = strtoul(arg, NULL, 0);
if (val >= 4096 && (val & (val - 1)) == 0)
flag_vals->erase_blk_size = val;
- } else if ((fl[i].flag == MF_LOGICALBLKSIZE) && flag_vals) {
+ } else if (flag == MF_LOGICALBLKSIZE) {
/* The logical block size flag is followed by an = and the flash
* logical block size. Get it, check that it is a power of 2 and
* at least 4096, and return it.
*/
- unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
+ auto val = strtoul(arg, NULL, 0);
if (val >= 4096 && (val & (val - 1)) == 0)
flag_vals->logical_blk_size = val;
- } else if ((fl[i].flag == MF_SYSFS) && flag_vals) {
+ } else if (flag == MF_SYSFS) {
/* The path to trigger device gc by idle-maint of vold. */
- flag_vals->sysfs_path = strdup(strchr(p, '=') + 1);
+ flag_vals->sysfs_path = strdup(arg);
}
break;
}
@@ -506,8 +508,7 @@
return false;
}
-static struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
-{
+static struct fstab* fs_mgr_read_fstab_file(FILE* fstab_file, bool proc_mounts) {
int cnt, entries;
ssize_t len;
size_t alloc_len = 0;
@@ -607,7 +608,10 @@
fstab->recs[cnt].fs_options = NULL;
}
- if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
+ if (proc_mounts) {
+ p += strlen(p);
+ } else if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing fs_mgr_options";
goto err;
}
@@ -739,7 +743,7 @@
return nullptr;
}
- fstab = fs_mgr_read_fstab_file(fstab_file);
+ fstab = fs_mgr_read_fstab_file(fstab_file, !strcmp("/proc/mounts", fstab_path));
if (!fstab) {
LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << fstab_path << "'";
}
@@ -767,7 +771,7 @@
return nullptr;
}
- struct fstab *fstab = fs_mgr_read_fstab_file(fstab_file.get());
+ struct fstab* fstab = fs_mgr_read_fstab_file(fstab_file.get(), false);
if (!fstab) {
LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
<< std::endl << fstab_buf;
diff --git a/fs_mgr/fs_mgr_priv_dm_ioctl.h b/fs_mgr/fs_mgr_priv_dm_ioctl.h
deleted file mode 100644
index 792475d..0000000
--- a/fs_mgr/fs_mgr_priv_dm_ioctl.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 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 __CORE_FS_MGR_PRIV_DM_IOCTL_H
-#define __CORE_FS_MGR_PRIV_DM_IOCTL_H
-
-#include <linux/dm-ioctl.h>
-#include <string>
-
-void fs_mgr_dm_ioctl_init(struct dm_ioctl* io, size_t size, const std::string& name);
-
-bool fs_mgr_dm_create_device(struct dm_ioctl* io, const std::string& name, int fd);
-
-bool fs_mgr_dm_destroy_device(struct dm_ioctl* io, const std::string& name, int fd);
-
-bool fs_mgr_dm_get_device_name(struct dm_ioctl* io, const std::string& name, int fd,
- std::string* out_dev_name);
-
-bool fs_mgr_dm_resume_table(struct dm_ioctl* io, const std::string& name, int fd);
-
-#endif /* __CORE_FS_MGR_PRIV_DM_IOCTL_H */
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index fe41f8a..5fb4ebb 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -35,6 +35,7 @@
#include <android-base/unique_fd.h>
#include <crypto_utils/android_pubkey.h>
#include <cutils/properties.h>
+#include <libdm/dm.h>
#include <logwrap/logwrap.h>
#include <openssl/obj_mac.h>
#include <openssl/rsa.h>
@@ -44,7 +45,6 @@
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
-#include "fs_mgr_priv_dm_ioctl.h"
#define VERITY_TABLE_RSA_KEY "/verity_key"
#define VERITY_TABLE_HASH_IDX 8
@@ -250,48 +250,27 @@
return true;
}
-static int load_verity_table(struct dm_ioctl *io, const std::string &name,
- uint64_t device_size, int fd,
- const struct verity_table_params *params, format_verity_table_func format)
-{
- char *verity_params;
- char *buffer = (char*) io;
- size_t bufsize;
+static int load_verity_table(android::dm::DeviceMapper& dm, const std::string& name,
+ uint64_t device_size, const struct verity_table_params* params,
+ format_verity_table_func format) {
+ android::dm::DmTable table;
+ table.set_readonly(true);
- fs_mgr_dm_ioctl_init(io, DM_BUF_SIZE, name);
-
- struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
-
- // set tgt arguments
- io->target_count = 1;
- io->flags = DM_READONLY_FLAG;
- tgt->status = 0;
- tgt->sector_start = 0;
- tgt->length = device_size / 512;
- strcpy(tgt->target_type, "verity");
-
- // build the verity params
- verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
- bufsize = DM_BUF_SIZE - (verity_params - buffer);
-
- if (!format(verity_params, bufsize, params)) {
+ char buffer[DM_BUF_SIZE];
+ if (!format(buffer, sizeof(buffer), params)) {
LERROR << "Failed to format verity parameters";
return -1;
}
- LINFO << "loading verity table: '" << verity_params << "'";
-
- // set next target boundary
- verity_params += strlen(verity_params) + 1;
- verity_params = (char*)(((uintptr_t)verity_params + 7) & ~7);
- tgt->next = verity_params - buffer;
-
- // send the ioctl to load the verity table
- if (ioctl(fd, DM_TABLE_LOAD, io)) {
- PERROR << "Error loading verity table";
+ android::dm::DmTargetVerityString target(0, device_size / 512, buffer);
+ if (!table.AddTarget(std::make_unique<decltype(target)>(target))) {
+ LERROR << "Failed to add verity target";
return -1;
}
-
+ if (!dm.CreateDevice(name, table)) {
+ LERROR << "Failed to create verity device \"" << name << "\"";
+ return -1;
+ }
return 0;
}
@@ -761,11 +740,11 @@
struct fec_verity_metadata verity;
struct verity_table_params params = { .table = NULL };
- alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
- struct dm_ioctl *io = (struct dm_ioctl *) buffer;
const std::string mount_point(basename(fstab->mount_point));
bool verified_at_boot = false;
+ android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
+
if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
FEC_DEFAULT_ROOTS) < 0) {
PERROR << "Failed to open '" << fstab->blk_device << "'";
@@ -798,24 +777,6 @@
params.ecc_dev = fstab->blk_device;
- // get the device mapper fd
- if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
- PERROR << "Error opening device mapper";
- goto out;
- }
-
- // create the device
- if (!fs_mgr_dm_create_device(io, mount_point, fd)) {
- LERROR << "Couldn't create verity device!";
- goto out;
- }
-
- // get the name of the device file
- if (!fs_mgr_dm_get_device_name(io, mount_point, fd, &verity_blk_name)) {
- LERROR << "Couldn't get verity device number!";
- goto out;
- }
-
if (load_verity_state(fstab, ¶ms.mode) < 0) {
/* if accessing or updating the state failed, switch to the default
* safe mode. This makes sure the device won't end up in an endless
@@ -861,8 +822,7 @@
fstab->fs_mgr_flags & MF_SLOTSELECT);
// load the verity mapping table
- if (load_verity_table(io, mount_point, verity.data_size, fd, ¶ms,
- format_verity_table) == 0) {
+ if (load_verity_table(dm, mount_point, verity.data_size, ¶ms, format_verity_table) == 0) {
goto loaded;
}
@@ -871,15 +831,14 @@
LINFO << "Disabling error correction for " << mount_point.c_str();
params.ecc.valid = false;
- if (load_verity_table(io, mount_point, verity.data_size, fd, ¶ms,
- format_verity_table) == 0) {
+ if (load_verity_table(dm, mount_point, verity.data_size, ¶ms, format_verity_table) == 0) {
goto loaded;
}
}
// try the legacy format for backwards compatibility
- if (load_verity_table(io, mount_point, verity.data_size, fd, ¶ms,
- format_legacy_verity_table) == 0) {
+ if (load_verity_table(dm, mount_point, verity.data_size, ¶ms, format_legacy_verity_table) ==
+ 0) {
goto loaded;
}
@@ -888,8 +847,8 @@
LINFO << "Falling back to EIO mode for " << mount_point.c_str();
params.mode = VERITY_MODE_EIO;
- if (load_verity_table(io, mount_point, verity.data_size, fd, ¶ms,
- format_legacy_verity_table) == 0) {
+ if (load_verity_table(dm, mount_point, verity.data_size, ¶ms,
+ format_legacy_verity_table) == 0) {
goto loaded;
}
}
@@ -898,9 +857,8 @@
goto out;
loaded:
-
- // activate the device
- if (!fs_mgr_dm_resume_table(io, mount_point, fd)) {
+ if (!dm.GetDmDevicePathByName(mount_point, &verity_blk_name)) {
+ LERROR << "Couldn't get verity device number!";
goto out;
}
@@ -923,7 +881,7 @@
if (!verified_at_boot) {
free(fstab->blk_device);
fstab->blk_device = strdup(verity_blk_name.c_str());
- } else if (!fs_mgr_dm_destroy_device(io, mount_point, fd)) {
+ } else if (!dm.DeleteDevice(mount_point)) {
LERROR << "Failed to remove verity device " << mount_point.c_str();
goto out;
}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index c1b2ed9..1049fb6 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -22,6 +22,8 @@
#include <stdbool.h>
#include <linux/dm-ioctl.h>
+#include <functional>
+
#include <fstab/fstab.h>
// Magic number at start of verity metadata
@@ -48,8 +50,8 @@
};
// Callback function for verity status
-typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
- const char *mount_point, int mode, int status);
+typedef void fs_mgr_verity_state_callback(struct fstab_rec* fstab, const char* mount_point,
+ int mode, int status);
#define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7
#define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6
@@ -73,7 +75,7 @@
struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
bool fs_mgr_load_verity_state(int* mode);
-bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
+bool fs_mgr_update_verity_state(std::function<fs_mgr_verity_state_callback> callback);
int fs_mgr_swapon_all(struct fstab *fstab);
bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index 9772c4b..cac475c 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -26,74 +26,28 @@
#define __CORE_FS_MGR_DM_LINEAR_H
#include <stdint.h>
+
#include <memory>
#include <string>
#include <vector>
+#include <libdm/dm.h>
+#include <liblp/metadata_format.h>
+
namespace android {
namespace fs_mgr {
-static const uint32_t kPartitionReadonly = 0x1;
-
-class LogicalPartitionExtent {
- public:
- LogicalPartitionExtent() : logical_sector_(0), first_sector_(0), num_sectors_(0) {}
- LogicalPartitionExtent(uint64_t logical_sector, uint64_t first_sector, uint64_t num_sectors,
- const std::string& block_device)
- : logical_sector_(logical_sector),
- first_sector_(first_sector),
- num_sectors_(num_sectors),
- block_device_(block_device) {}
-
- // Return a string containing the dm_target_spec buffer needed to use this
- // extent in a device-mapper table.
- std::string Serialize() const;
-
- const std::string& block_device() const { return block_device_; }
-
- private:
- // Logical sector this extent represents in the presented block device.
- // This is equal to the previous extent's logical sector plus the number
- // of sectors in that extent. The first extent always starts at 0.
- uint64_t logical_sector_;
- // First 512-byte sector of this extent, on the source block device.
- uint64_t first_sector_;
- // Number of 512-byte sectors.
- uint64_t num_sectors_;
- // Target block device.
- std::string block_device_;
-};
-
-struct LogicalPartition {
- LogicalPartition() : attributes(0), num_sectors(0) {}
-
- std::string name;
- uint32_t attributes;
- // Number of 512-byte sectors total.
- uint64_t num_sectors;
- // List of extents.
- std::vector<LogicalPartitionExtent> extents;
-};
-
-struct LogicalPartitionTable {
- // List of partitions in the partition table.
- std::vector<LogicalPartition> partitions;
-};
-
-// Load a dm-linear table from the device tree if one is available; otherwise,
-// return null.
-std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree();
-
-// Create device-mapper devices for the given partition table.
-//
-// On success, two devices nodes will be created for each partition, both
-// pointing to the same device:
-// /dev/block/dm-<N> where N is a sequential ID assigned by device-mapper.
-// /dev/block/dm-<name> where |name| is the partition name.
-//
-bool CreateLogicalPartitions(const LogicalPartitionTable& table);
bool CreateLogicalPartitions(const std::string& block_device);
+// Create a block device for a single logical partition, given metadata and
+// the partition name. On success, a path to the partition's block device is
+// returned.
+bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
+ const std::string& partition_name, std::string* path);
+
+// Destroy the block device for a logical partition, by name.
+bool DestroyLogicalPartition(const std::string& name);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index b96f4c1..ad3b6f4 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -272,6 +272,46 @@
return true;
}
+bool DeviceMapper::GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
+ char buffer[4096];
+ struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer);
+
+ InitIo(io, name);
+ io->data_size = sizeof(buffer);
+ io->data_start = sizeof(*io);
+ if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
+ PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
+ return false;
+ }
+ if (io->flags & DM_BUFFER_FULL_FLAG) {
+ PLOG(ERROR) << "DM_TABLE_STATUS result for " << name << " was too large";
+ return false;
+ }
+
+ uint32_t cursor = io->data_start;
+ uint32_t data_end = std::min(io->data_size, uint32_t(sizeof(buffer)));
+ for (uint32_t i = 0; i < io->target_count; i++) {
+ if (cursor + sizeof(struct dm_target_spec) > data_end) {
+ break;
+ }
+ // After each dm_target_spec is a status string. spec->next is an
+ // offset from |io->data_start|, and we clamp it to the size of our
+ // buffer.
+ struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(buffer + cursor);
+ uint32_t data_offset = cursor + sizeof(dm_target_spec);
+ uint32_t next_cursor = std::min(io->data_start + spec->next, data_end);
+
+ std::string data;
+ if (next_cursor > data_offset) {
+ // Note: we use c_str() to eliminate any extra trailing 0s.
+ data = std::string(buffer + data_offset, next_cursor - data_offset).c_str();
+ }
+ table->emplace_back(*spec, data);
+ cursor = next_cursor;
+ }
+ return true;
+}
+
// private methods of DeviceMapper
void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const {
CHECK(io != nullptr) << "nullptr passed to dm_ioctl initialization";
diff --git a/fs_mgr/libdm/dm_table.cpp b/fs_mgr/libdm/dm_table.cpp
index cb6f210..15c7ce1 100644
--- a/fs_mgr/libdm/dm_table.cpp
+++ b/fs_mgr/libdm/dm_table.cpp
@@ -23,6 +23,9 @@
namespace dm {
bool DmTable::AddTarget(std::unique_ptr<DmTarget>&& target) {
+ if (!target->Valid()) {
+ return false;
+ }
targets_.push_back(std::move(target));
return true;
}
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 5934416..20b26df 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -18,6 +18,7 @@
#include <android-base/logging.h>
#include <android-base/macros.h>
+#include <android-base/strings.h>
#include <libdm/dm.h>
@@ -55,5 +56,60 @@
return block_device_ + " " + std::to_string(physical_sector_);
}
+DmTargetVerity::DmTargetVerity(uint64_t start, uint64_t length, uint32_t version,
+ const std::string& block_device, const std::string& hash_device,
+ uint32_t data_block_size, uint32_t hash_block_size,
+ uint32_t num_data_blocks, uint32_t hash_start_block,
+ const std::string& hash_algorithm, const std::string& root_digest,
+ const std::string& salt)
+ : DmTarget(start, length), valid_(true) {
+ base_args_ = {
+ std::to_string(version),
+ block_device,
+ hash_device,
+ std::to_string(data_block_size),
+ std::to_string(hash_block_size),
+ std::to_string(num_data_blocks),
+ std::to_string(hash_start_block),
+ hash_algorithm,
+ root_digest,
+ salt,
+ };
+}
+
+void DmTargetVerity::UseFec(const std::string& device, uint32_t num_roots, uint32_t num_blocks,
+ uint32_t start) {
+ optional_args_.emplace_back("use_fec_from_device");
+ optional_args_.emplace_back(device);
+ optional_args_.emplace_back("fec_roots");
+ optional_args_.emplace_back(std::to_string(num_roots));
+ optional_args_.emplace_back("fec_blocks");
+ optional_args_.emplace_back(std::to_string(num_blocks));
+ optional_args_.emplace_back("fec_start");
+ optional_args_.emplace_back(std::to_string(start));
+}
+
+void DmTargetVerity::SetVerityMode(const std::string& mode) {
+ if (mode != "restart_on_corruption" && mode != "ignore_corruption") {
+ LOG(ERROR) << "Unknown verity mode: " << mode;
+ valid_ = false;
+ return;
+ }
+ optional_args_.emplace_back(mode);
+}
+
+void DmTargetVerity::IgnoreZeroBlocks() {
+ optional_args_.emplace_back("ignore_zero_blocks");
+}
+
+std::string DmTargetVerity::GetParameterString() const {
+ std::string base = android::base::Join(base_args_, " ");
+ if (optional_args_.empty()) {
+ return base;
+ }
+ std::string optional = android::base::Join(optional_args_, " ");
+ return base + " " + std::to_string(optional_args_.size()) + " " + optional;
+}
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 67dc958..cc61917 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -160,7 +160,43 @@
ASSERT_EQ(strncmp(sector, message2, sizeof(message2)), 0);
}
+ // Test GetTableStatus.
+ DeviceMapper& dm = DeviceMapper::Instance();
+ vector<DeviceMapper::TargetInfo> targets;
+ ASSERT_TRUE(dm.GetTableStatus(dev.name(), &targets));
+ ASSERT_EQ(targets.size(), 2);
+ EXPECT_EQ(strcmp(targets[0].spec.target_type, "linear"), 0);
+ EXPECT_TRUE(targets[0].data.empty());
+ EXPECT_EQ(targets[0].spec.sector_start, 0);
+ EXPECT_EQ(targets[0].spec.length, 1);
+ EXPECT_EQ(strcmp(targets[1].spec.target_type, "linear"), 0);
+ EXPECT_TRUE(targets[1].data.empty());
+ EXPECT_EQ(targets[1].spec.sector_start, 1);
+ EXPECT_EQ(targets[1].spec.length, 1);
+
// Normally the TestDevice destructor would delete this, but at least one
// test should ensure that device deletion works.
ASSERT_TRUE(dev.Destroy());
}
+
+TEST(libdm, DmVerityArgsAvb2) {
+ std::string device = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor_a";
+ std::string algorithm = "sha1";
+ std::string digest = "4be7e823b8c40f7bd5c8ccd5123f0722c5baca21";
+ std::string salt = "cc99f81ecb9484220a003b0719ee59dcf9be7e5d";
+
+ DmTargetVerity target(0, 10000, 1, device, device, 4096, 4096, 125961, 125961, algorithm,
+ digest, salt);
+ target.UseFec(device, 2, 126955, 126955);
+ target.SetVerityMode("restart_on_corruption");
+ target.IgnoreZeroBlocks();
+
+ // Verity table from a walleye build.
+ std::string expected =
+ "1 /dev/block/platform/soc/1da4000.ufshc/by-name/vendor_a "
+ "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor_a 4096 4096 125961 125961 sha1 "
+ "4be7e823b8c40f7bd5c8ccd5123f0722c5baca21 cc99f81ecb9484220a003b0719ee59dcf9be7e5d 10 "
+ "use_fec_from_device /dev/block/platform/soc/1da4000.ufshc/by-name/vendor_a fec_roots "
+ "2 fec_blocks 126955 fec_start 126955 restart_on_corruption ignore_zero_blocks";
+ EXPECT_EQ(target.GetParameterString(), expected);
+}
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 60bceed..e2bc729 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -26,6 +26,7 @@
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include <android-base/logging.h>
@@ -117,6 +118,18 @@
}
}
+ // Query the status of a table, given a device name. The output vector will
+ // contain one TargetInfo for each target in the table. If the device does
+ // not exist, or there were too many targets, the call will fail and return
+ // false.
+ struct TargetInfo {
+ struct dm_target_spec spec;
+ std::string data;
+ TargetInfo(const struct dm_target_spec& spec, const std::string& data)
+ : spec(spec), data(data) {}
+ };
+ bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table);
+
private:
// Maximum possible device mapper targets registered in the kernel.
// This is only used to read the list of targets from kernel so we allocate
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 31b6a70..d5974f4 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <string>
+#include <vector>
#include <android-base/logging.h>
@@ -69,6 +70,8 @@
// must implement this, for it to be used on a device.
std::string Serialize() const;
+ virtual bool Valid() const { return true; }
+
protected:
// Get the parameter string that is passed to the end of the dm_target_spec
// for this target type.
@@ -96,12 +99,51 @@
std::string name() const override { return "linear"; }
std::string GetParameterString() const override;
+ const std::string& block_device() const { return block_device_; }
private:
std::string block_device_;
uint64_t physical_sector_;
};
+class DmTargetVerity final : public DmTarget {
+ public:
+ DmTargetVerity(uint64_t start, uint64_t length, uint32_t version,
+ const std::string& block_device, const std::string& hash_device,
+ uint32_t data_block_size, uint32_t hash_block_size, uint32_t num_data_blocks,
+ uint32_t hash_start_block, const std::string& hash_algorithm,
+ const std::string& root_digest, const std::string& salt);
+
+ void UseFec(const std::string& device, uint32_t num_roots, uint32_t num_blocks, uint32_t start);
+ void SetVerityMode(const std::string& mode);
+ void IgnoreZeroBlocks();
+
+ std::string name() const override { return "verity"; }
+ std::string GetParameterString() const override;
+ bool Valid() const override { return valid_; }
+
+ private:
+ std::vector<std::string> base_args_;
+ std::vector<std::string> optional_args_;
+ bool valid_;
+};
+
+// This is the same as DmTargetVerity, but the table may be specified as a raw
+// string. This code exists only for fs_mgr_verity and should be avoided. Use
+// DmTargetVerity for new code instead.
+class DmTargetVerityString final : public DmTarget {
+ public:
+ DmTargetVerityString(uint64_t start, uint64_t length, const std::string& target_string)
+ : DmTarget(start, length), target_string_(target_string) {}
+
+ std::string name() const override { return "verity"; }
+ std::string GetParameterString() const override { return target_string_; }
+ bool Valid() const override { return true; }
+
+ private:
+ std::string target_string_;
+};
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index f7086a8..1434b21 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -24,6 +24,7 @@
],
srcs: [
"builder.cpp",
+ "images.cpp",
"reader.cpp",
"utility.cpp",
"writer.cpp",
@@ -33,6 +34,7 @@
"liblog",
"libcrypto",
"libcrypto_utils",
+ "libsparse",
],
whole_static_libs: [
"libext2_uuid",
@@ -46,12 +48,16 @@
cc_test {
name: "liblp_test",
defaults: ["fs_mgr_defaults"],
+ cppflags: [
+ "-Wno-unused-parameter",
+ ],
static_libs: [
"libbase",
"liblog",
"libcrypto",
"libcrypto_utils",
"liblp",
+ "libfs_mgr",
],
srcs: [
"builder_test.cpp",
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 0e4838c..9d710f9 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -16,22 +16,49 @@
#include "liblp/builder.h"
+#if defined(__linux__)
+#include <linux/fs.h>
+#endif
#include <string.h>
+#include <sys/ioctl.h>
#include <algorithm>
+#include <android-base/unique_fd.h>
#include <uuid/uuid.h>
-#include "liblp/metadata_format.h"
+#include "liblp/liblp.h"
+#include "reader.h"
#include "utility.h"
namespace android {
namespace fs_mgr {
-// Align a byte count up to the nearest 512-byte sector.
-template <typename T>
-static inline T AlignToSector(T value) {
- return (value + (LP_SECTOR_SIZE - 1)) & ~T(LP_SECTOR_SIZE - 1);
+bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
+#if defined(__linux__)
+ android::base::unique_fd fd(open(block_device.c_str(), O_RDONLY));
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "open '" << block_device << "' failed";
+ return false;
+ }
+ if (!GetDescriptorSize(fd, &device_info->size)) {
+ return false;
+ }
+ if (ioctl(fd, BLKIOMIN, &device_info->alignment) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
+ return false;
+ }
+ if (ioctl(fd, BLKALIGNOFF, &device_info->alignment_offset) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
+ return false;
+ }
+ return true;
+#else
+ (void)block_device;
+ (void)device_info;
+ LERROR << __PRETTY_FUNCTION__ << ": Not supported on this operating system.";
+ return false;
+#endif
}
void LinearExtent::AddTo(LpMetadata* out) const {
@@ -56,7 +83,7 @@
}
void Partition::ShrinkTo(uint64_t requested_size) {
- uint64_t aligned_size = AlignToSector(requested_size);
+ uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE);
if (size_ <= aligned_size) {
return;
}
@@ -82,11 +109,28 @@
DCHECK(size_ == requested_size);
}
-std::unique_ptr<MetadataBuilder> MetadataBuilder::New(uint64_t blockdevice_size,
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device,
+ uint32_t slot_number) {
+ std::unique_ptr<LpMetadata> metadata = ReadMetadata(block_device.c_str(), slot_number);
+ if (!metadata) {
+ return nullptr;
+ }
+ std::unique_ptr<MetadataBuilder> builder = New(*metadata.get());
+ if (!builder) {
+ return nullptr;
+ }
+ BlockDeviceInfo device_info;
+ if (fs_mgr::GetBlockDeviceInfo(block_device, &device_info)) {
+ builder->set_block_device_info(device_info);
+ }
+ return builder;
+}
+
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const BlockDeviceInfo& device_info,
uint32_t metadata_max_size,
uint32_t metadata_slot_count) {
std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
- if (!builder->Init(blockdevice_size, metadata_max_size, metadata_slot_count)) {
+ if (!builder->Init(device_info, metadata_max_size, metadata_slot_count)) {
return nullptr;
}
return builder;
@@ -135,10 +179,13 @@
}
}
}
+
+ device_info_.alignment = geometry_.alignment;
+ device_info_.alignment_offset = geometry_.alignment_offset;
return true;
}
-bool MetadataBuilder::Init(uint64_t blockdevice_size, uint32_t metadata_max_size,
+bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata_max_size,
uint32_t metadata_slot_count) {
if (metadata_max_size < sizeof(LpMetadataHeader)) {
LERROR << "Invalid metadata maximum size.";
@@ -150,7 +197,26 @@
}
// Align the metadata size up to the nearest sector.
- metadata_max_size = AlignToSector(metadata_max_size);
+ metadata_max_size = AlignTo(metadata_max_size, LP_SECTOR_SIZE);
+
+ // Check that device properties are sane.
+ device_info_ = device_info;
+ if (device_info_.size % LP_SECTOR_SIZE != 0) {
+ LERROR << "Block device size must be a multiple of 512.";
+ return false;
+ }
+ if (device_info_.alignment_offset % LP_SECTOR_SIZE != 0) {
+ LERROR << "Alignment offset is not sector-aligned.";
+ return false;
+ }
+ if (device_info_.alignment % LP_SECTOR_SIZE != 0) {
+ LERROR << "Partition alignment is not sector-aligned.";
+ return false;
+ }
+ if (device_info_.alignment_offset > device_info_.alignment) {
+ LERROR << "Partition alignment offset is greater than its alignment.";
+ return false;
+ }
// We reserve a geometry block (4KB) plus space for each copy of the
// maximum size of a metadata blob. Then, we double that space since
@@ -158,20 +224,37 @@
uint64_t reserved =
LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count);
uint64_t total_reserved = reserved * 2;
-
- if (blockdevice_size < total_reserved || blockdevice_size - total_reserved < LP_SECTOR_SIZE) {
+ if (device_info_.size < total_reserved) {
LERROR << "Attempting to create metadata on a block device that is too small.";
return false;
}
- // The last sector is inclusive. We subtract one to make sure that logical
- // partitions won't overlap with the same sector as the backup metadata,
- // which could happen if the block device was not aligned to LP_SECTOR_SIZE.
- geometry_.first_logical_sector = reserved / LP_SECTOR_SIZE;
- geometry_.last_logical_sector = ((blockdevice_size - reserved) / LP_SECTOR_SIZE) - 1;
+ // Compute the first free sector, factoring in alignment.
+ uint64_t free_area = AlignTo(reserved, device_info_.alignment, device_info_.alignment_offset);
+ uint64_t first_sector = free_area / LP_SECTOR_SIZE;
+
+ // Compute the last free sector, which is inclusive. We subtract 1 to make
+ // sure that logical partitions won't overlap with the same sector as the
+ // backup metadata, which could happen if the block device was not aligned
+ // to LP_SECTOR_SIZE.
+ uint64_t last_sector = ((device_info_.size - reserved) / LP_SECTOR_SIZE) - 1;
+
+ // If this check fails, it means either (1) we did not have free space to
+ // allocate a single sector, or (2) we did, but the alignment was high
+ // enough to bump the first sector out of range. Either way, we cannot
+ // continue.
+ if (first_sector > last_sector) {
+ LERROR << "Not enough space to allocate any partition tables.";
+ return false;
+ }
+
+ geometry_.first_logical_sector = first_sector;
+ geometry_.last_logical_sector = last_sector;
geometry_.metadata_max_size = metadata_max_size;
geometry_.metadata_slot_count = metadata_slot_count;
- DCHECK(geometry_.last_logical_sector >= geometry_.first_logical_sector);
+ geometry_.alignment = device_info_.alignment;
+ geometry_.alignment_offset = device_info_.alignment_offset;
+ geometry_.block_device_size = device_info_.size;
return true;
}
@@ -209,7 +292,7 @@
bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t requested_size) {
// Align the space needed up to the nearest sector.
- uint64_t aligned_size = AlignToSector(requested_size);
+ uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE);
if (partition->size() >= aligned_size) {
return true;
}
@@ -259,10 +342,16 @@
continue;
}
+ uint64_t aligned = AlignSector(previous.end);
+ if (aligned >= current.start) {
+ // After alignment, this extent is not usable.
+ continue;
+ }
+
// This gap is enough to hold the remainder of the space requested, so we
// can allocate what we need and return.
- if (current.start - previous.end >= sectors_needed) {
- auto extent = std::make_unique<LinearExtent>(sectors_needed, previous.end);
+ if (current.start - aligned >= sectors_needed) {
+ auto extent = std::make_unique<LinearExtent>(sectors_needed, aligned);
sectors_needed -= extent->num_sectors();
new_extents.push_back(std::move(extent));
break;
@@ -270,7 +359,7 @@
// This gap is not big enough to fit the remainder of the space requested,
// so consume the whole thing and keep looking for more.
- auto extent = std::make_unique<LinearExtent>(current.start - previous.end, previous.end);
+ auto extent = std::make_unique<LinearExtent>(current.start - aligned, aligned);
sectors_needed -= extent->num_sectors();
new_extents.push_back(std::move(extent));
}
@@ -286,8 +375,12 @@
}
DCHECK(first_sector <= geometry_.last_logical_sector);
+ // Note: After alignment, |first_sector| may be > the last usable sector.
+ first_sector = AlignSector(first_sector);
+
// Note: the last usable sector is inclusive.
- if (geometry_.last_logical_sector + 1 - first_sector < sectors_needed) {
+ if (first_sector > geometry_.last_logical_sector ||
+ geometry_.last_logical_sector + 1 - first_sector < sectors_needed) {
LERROR << "Not enough free space to expand partition: " << partition->name();
return false;
}
@@ -351,5 +444,26 @@
return (geometry_.last_logical_sector - geometry_.first_logical_sector + 1) * LP_SECTOR_SIZE;
}
+uint64_t MetadataBuilder::AlignSector(uint64_t sector) {
+ // Note: when reading alignment info from the Kernel, we don't assume it
+ // is aligned to the sector size, so we round up to the nearest sector.
+ uint64_t lba = sector * LP_SECTOR_SIZE;
+ uint64_t aligned = AlignTo(lba, device_info_.alignment, device_info_.alignment_offset);
+ return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
+}
+
+void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info) {
+ device_info_.size = device_info.size;
+
+ // The kernel does not guarantee these values are present, so we only
+ // replace existing values if the new values are non-zero.
+ if (device_info.alignment) {
+ device_info_.alignment = device_info.alignment;
+ }
+ if (device_info.alignment_offset) {
+ device_info_.alignment_offset = device_info.alignment_offset;
+ }
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 2983f0f..b610fd4 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -16,6 +16,8 @@
#include <gtest/gtest.h>
#include <liblp/builder.h>
+#include "fs_mgr.h"
+#include "utility.h"
using namespace std;
using namespace android::fs_mgr;
@@ -104,19 +106,9 @@
static const uint32_t kMetadataSize = 1024;
static const uint32_t kMetadataSlots = 2;
- // If the disk size is not aligned to 512 bytes, make sure it still leaves
- // space at the end for backup metadata, and that it doesn't overlap with
- // the space for logical partitions.
unique_ptr<MetadataBuilder> builder =
MetadataBuilder::New(kDiskSize, kMetadataSize, kMetadataSlots);
- unique_ptr<LpMetadata> exported = builder->Export();
- ASSERT_NE(exported, nullptr);
-
- static const size_t kMetadataSpace =
- (kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE;
- uint64_t space_at_end =
- kDiskSize - (exported->geometry.last_logical_sector + 1) * LP_SECTOR_SIZE;
- EXPECT_GE(space_at_end, kMetadataSpace);
+ ASSERT_EQ(builder, nullptr);
}
TEST(liblp, MetadataAlignment) {
@@ -127,6 +119,84 @@
EXPECT_EQ(exported->geometry.metadata_max_size, 1024);
}
+TEST(liblp, InternalAlignment) {
+ // Test the metadata fitting within alignment.
+ BlockDeviceInfo device_info(1024 * 1024, 768 * 1024, 0);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 2);
+ ASSERT_NE(builder, nullptr);
+ unique_ptr<LpMetadata> exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
+ EXPECT_EQ(exported->geometry.first_logical_sector, 1536);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 2035);
+
+ // Test a large alignment offset thrown in.
+ device_info.alignment_offset = 753664;
+ builder = MetadataBuilder::New(device_info, 1024, 2);
+ ASSERT_NE(builder, nullptr);
+ exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
+ EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 2035);
+
+ // Alignment offset without alignment doesn't mean anything.
+ device_info.alignment = 0;
+ builder = MetadataBuilder::New(device_info, 1024, 2);
+ ASSERT_EQ(builder, nullptr);
+
+ // Test a small alignment with an alignment offset.
+ device_info.alignment = 12 * 1024;
+ device_info.alignment_offset = 3 * 1024;
+ builder = MetadataBuilder::New(device_info, 16 * 1024, 2);
+ ASSERT_NE(builder, nullptr);
+ exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
+ EXPECT_EQ(exported->geometry.first_logical_sector, 78);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 1975);
+
+ // Test a small alignment with no alignment offset.
+ device_info.alignment = 11 * 1024;
+ builder = MetadataBuilder::New(device_info, 16 * 1024, 2);
+ ASSERT_NE(builder, nullptr);
+ exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
+ EXPECT_EQ(exported->geometry.first_logical_sector, 72);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 1975);
+}
+
+TEST(liblp, InternalPartitionAlignment) {
+ BlockDeviceInfo device_info(512 * 1024 * 1024, 768 * 1024, 753664);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 32 * 1024, 2);
+
+ Partition* a = builder->AddPartition("a", TEST_GUID, 0);
+ ASSERT_NE(a, nullptr);
+ Partition* b = builder->AddPartition("b", TEST_GUID2, 0);
+ ASSERT_NE(b, nullptr);
+
+ // Add a bunch of small extents to each, interleaving.
+ for (size_t i = 0; i < 10; i++) {
+ ASSERT_TRUE(builder->GrowPartition(a, a->size() + 4096));
+ ASSERT_TRUE(builder->GrowPartition(b, b->size() + 4096));
+ }
+ EXPECT_EQ(a->size(), 40960);
+ EXPECT_EQ(b->size(), 40960);
+
+ unique_ptr<LpMetadata> exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
+
+ // Check that each starting sector is aligned.
+ for (const auto& extent : exported->extents) {
+ ASSERT_EQ(extent.target_type, LP_TARGET_TYPE_LINEAR);
+ EXPECT_EQ(extent.num_sectors, 8);
+
+ uint64_t lba = extent.target_data * LP_SECTOR_SIZE;
+ uint64_t aligned_lba = AlignTo(lba, device_info.alignment, device_info.alignment_offset);
+ EXPECT_EQ(lba, aligned_lba);
+ }
+
+ // Sanity check one extent.
+ EXPECT_EQ(exported->extents.back().target_data, 30656);
+}
+
TEST(liblp, UseAllDiskSpace) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
EXPECT_EQ(builder->AllocatableSpace(), 1036288);
@@ -312,15 +382,72 @@
static const size_t kMetadataSize = 64 * 1024;
// No space to store metadata + geometry.
- unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize, kMetadataSize, 1);
+ BlockDeviceInfo device_info(kDiskSize, 0, 0);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
EXPECT_EQ(builder, nullptr);
// No space to store metadata + geometry + one free sector.
- builder = MetadataBuilder::New(kDiskSize + LP_METADATA_GEOMETRY_SIZE * 2, kMetadataSize, 1);
+ device_info.size += LP_METADATA_GEOMETRY_SIZE * 2;
+ builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
EXPECT_EQ(builder, nullptr);
// Space for metadata + geometry + one free sector.
- builder = MetadataBuilder::New(kDiskSize + LP_METADATA_GEOMETRY_SIZE * 2 + LP_SECTOR_SIZE,
- kMetadataSize, 1);
+ device_info.size += LP_SECTOR_SIZE;
+ builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
EXPECT_NE(builder, nullptr);
+
+ // Test with alignment.
+ device_info.alignment = 131072;
+ builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
+ EXPECT_EQ(builder, nullptr);
+
+ device_info.alignment = 0;
+ device_info.alignment_offset = 32768 - LP_SECTOR_SIZE;
+ builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
+ EXPECT_EQ(builder, nullptr);
+}
+
+TEST(liblp, block_device_info) {
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ ASSERT_NE(fstab, nullptr);
+
+ // This should read from the "super" partition once we have a well-defined
+ // way to access it.
+ struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), "/data");
+ ASSERT_NE(rec, nullptr);
+
+ BlockDeviceInfo device_info;
+ ASSERT_TRUE(GetBlockDeviceInfo(rec->blk_device, &device_info));
+
+ // Sanity check that the device doesn't give us some weird inefficient
+ // alignment.
+ ASSERT_EQ(device_info.alignment % LP_SECTOR_SIZE, 0);
+ ASSERT_EQ(device_info.alignment_offset % LP_SECTOR_SIZE, 0);
+ ASSERT_LE(device_info.alignment_offset, INT_MAX);
+
+ // Having an alignment offset > alignment doesn't really make sense.
+ ASSERT_LT(device_info.alignment_offset, device_info.alignment);
+}
+
+TEST(liblp, UpdateBlockDeviceInfo) {
+ BlockDeviceInfo device_info(1024 * 1024, 4096, 1024);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+ ASSERT_NE(builder, nullptr);
+
+ EXPECT_EQ(builder->block_device_info().size, device_info.size);
+ EXPECT_EQ(builder->block_device_info().alignment, device_info.alignment);
+ EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
+
+ device_info.alignment = 0;
+ device_info.alignment_offset = 2048;
+ builder->set_block_device_info(device_info);
+ EXPECT_EQ(builder->block_device_info().alignment, 4096);
+ EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
+
+ device_info.alignment = 8192;
+ device_info.alignment_offset = 0;
+ builder->set_block_device_info(device_info);
+ EXPECT_EQ(builder->block_device_info().alignment, 8192);
+ EXPECT_EQ(builder->block_device_info().alignment_offset, 2048);
}
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
new file mode 100644
index 0000000..a361a5d
--- /dev/null
+++ b/fs_mgr/liblp/images.cpp
@@ -0,0 +1,355 @@
+/*
+ * 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 "images.h"
+
+#include <limits.h>
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+#include <sparse/sparse.h>
+
+#include "reader.h"
+#include "utility.h"
+#include "writer.h"
+
+namespace android {
+namespace fs_mgr {
+
+std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
+ LpMetadataGeometry geometry;
+ if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
+ return nullptr;
+ }
+ if (SeekFile64(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << LP_METADATA_GEOMETRY_SIZE;
+ return nullptr;
+ }
+ std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd);
+ if (!metadata) {
+ return nullptr;
+ }
+ metadata->geometry = geometry;
+ return metadata;
+}
+
+std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
+ android::base::unique_fd fd(open(file, O_RDONLY));
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+ return nullptr;
+ }
+ return ReadFromImageFile(fd);
+}
+
+bool WriteToImageFile(int fd, const LpMetadata& input) {
+ std::string geometry = SerializeGeometry(input.geometry);
+ std::string metadata = SerializeMetadata(input);
+
+ std::string everything = geometry + metadata;
+
+ if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
+ PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed";
+ return false;
+ }
+ return true;
+}
+
+bool WriteToImageFile(const char* file, const LpMetadata& input) {
+ android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+ return false;
+ }
+ return WriteToImageFile(fd, input);
+}
+
+// We use an object to build the sparse file since it requires that data
+// pointers be held alive until the sparse file is destroyed. It's easier
+// to do this when the data pointers are all in one place.
+class SparseBuilder {
+ public:
+ SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images);
+
+ bool Build();
+ bool Export(const char* file);
+ bool IsValid() const { return file_ != nullptr; }
+
+ private:
+ bool AddData(const std::string& blob, uint64_t sector);
+ bool AddPartitionImage(const LpMetadataPartition& partition, const std::string& file);
+ int OpenImageFile(const std::string& file);
+ bool SectorToBlock(uint64_t sector, uint32_t* block);
+
+ const LpMetadata& metadata_;
+ const LpMetadataGeometry& geometry_;
+ uint32_t block_size_;
+ std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
+ std::string primary_blob_;
+ std::string backup_blob_;
+ std::map<std::string, std::string> images_;
+ std::vector<android::base::unique_fd> temp_fds_;
+};
+
+SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images)
+ : metadata_(metadata),
+ geometry_(metadata.geometry),
+ block_size_(block_size),
+ file_(sparse_file_new(block_size_, geometry_.block_device_size), sparse_file_destroy),
+ images_(images) {}
+
+bool SparseBuilder::Export(const char* file) {
+ android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
+ if (fd < 0) {
+ PERROR << "open failed: " << file;
+ return false;
+ }
+ // No gzip compression; sparseify; no checksum.
+ int ret = sparse_file_write(file_.get(), fd, false, true, false);
+ if (ret != 0) {
+ LERROR << "sparse_file_write failed (error code " << ret << ")";
+ return false;
+ }
+ return true;
+}
+
+bool SparseBuilder::AddData(const std::string& blob, uint64_t sector) {
+ uint32_t block;
+ if (!SectorToBlock(sector, &block)) {
+ return false;
+ }
+ void* data = const_cast<char*>(blob.data());
+ int ret = sparse_file_add_data(file_.get(), data, blob.size(), block);
+ if (ret != 0) {
+ LERROR << "sparse_file_add_data failed (error code " << ret << ")";
+ return false;
+ }
+ return true;
+}
+
+bool SparseBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
+ // The caller must ensure that the metadata has an alignment that is a
+ // multiple of the block size. liblp will take care of the rest, ensuring
+ // that all partitions are on an aligned boundary. Therefore all writes
+ // should be block-aligned, and if they are not, the table was misconfigured.
+ // Note that the default alignment is 1MiB, which is a multiple of the
+ // default block size (4096).
+ if ((sector * LP_SECTOR_SIZE) % block_size_ != 0) {
+ LERROR << "sector " << sector << " is not aligned to block size " << block_size_;
+ return false;
+ }
+ *block = (sector * LP_SECTOR_SIZE) / block_size_;
+ return true;
+}
+
+bool SparseBuilder::Build() {
+ std::string geometry_blob = SerializeGeometry(geometry_);
+ std::string metadata_blob = SerializeMetadata(metadata_);
+ metadata_blob.resize(geometry_.metadata_max_size);
+
+ std::string all_metadata;
+ for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
+ all_metadata += metadata_blob;
+ }
+
+ // Metadata immediately follows geometry, and we write the same metadata
+ // to all slots. Note that we don't bother trying to write skip chunks
+ // here since it's a small amount of data.
+ primary_blob_ = geometry_blob + all_metadata;
+ if (!AddData(primary_blob_, 0)) {
+ return false;
+ }
+
+ for (const auto& partition : metadata_.partitions) {
+ auto iter = images_.find(GetPartitionName(partition));
+ if (iter == images_.end()) {
+ continue;
+ }
+ if (!AddPartitionImage(partition, iter->second)) {
+ return false;
+ }
+ images_.erase(iter);
+ }
+
+ if (!images_.empty()) {
+ LERROR << "Partition image was specified but no partition was found.";
+ return false;
+ }
+
+ // The backup area contains all metadata slots, and then geometry. Similar
+ // to before we write the metadata to every slot.
+ int64_t backup_offset = GetBackupMetadataOffset(geometry_, 0);
+ uint64_t backups_start = geometry_.block_device_size + backup_offset;
+ uint64_t backup_sector = backups_start / LP_SECTOR_SIZE;
+
+ backup_blob_ = all_metadata + geometry_blob;
+ if (!AddData(backup_blob_, backup_sector)) {
+ return false;
+ }
+ return true;
+}
+
+static inline bool HasFillValue(uint32_t* buffer, size_t count) {
+ uint32_t fill_value = buffer[0];
+ for (size_t i = 1; i < count; i++) {
+ if (fill_value != buffer[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SparseBuilder::AddPartitionImage(const LpMetadataPartition& partition,
+ const std::string& file) {
+ if (partition.num_extents != 1) {
+ LERROR << "Partition for new tables should not have more than one extent: "
+ << GetPartitionName(partition);
+ return false;
+ }
+
+ const LpMetadataExtent& extent = metadata_.extents[partition.first_extent_index];
+ if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
+ LERROR << "Partition should only have linear extents: " << GetPartitionName(partition);
+ return false;
+ }
+
+ int fd = OpenImageFile(file);
+ if (fd < 0) {
+ LERROR << "Could not open image for partition: " << GetPartitionName(partition);
+ return false;
+ }
+
+ // Make sure the image does not exceed the partition size.
+ uint64_t file_length;
+ if (!GetDescriptorSize(fd, &file_length)) {
+ LERROR << "Could not compute image size";
+ return false;
+ }
+ if (file_length > extent.num_sectors * LP_SECTOR_SIZE) {
+ LERROR << "Image for partition '" << GetPartitionName(partition)
+ << "' is greater than its size";
+ return false;
+ }
+ if (SeekFile64(fd, 0, SEEK_SET)) {
+ PERROR << "lseek failed";
+ return false;
+ }
+
+ uint32_t output_block;
+ if (!SectorToBlock(extent.target_data, &output_block)) {
+ return false;
+ }
+
+ uint64_t pos = 0;
+ uint64_t remaining = file_length;
+ while (remaining) {
+ uint32_t buffer[block_size_ / sizeof(uint32_t)];
+ size_t read_size = remaining >= sizeof(buffer) ? sizeof(buffer) : size_t(remaining);
+ if (!android::base::ReadFully(fd, buffer, sizeof(buffer))) {
+ PERROR << "read failed";
+ return false;
+ }
+ if (read_size != sizeof(buffer) || !HasFillValue(buffer, read_size / sizeof(uint32_t))) {
+ int rv = sparse_file_add_fd(file_.get(), fd, pos, read_size, output_block);
+ if (rv) {
+ LERROR << "sparse_file_add_fd failed with code: " << rv;
+ return false;
+ }
+ } else {
+ int rv = sparse_file_add_fill(file_.get(), buffer[0], read_size, output_block);
+ if (rv) {
+ LERROR << "sparse_file_add_fill failed with code: " << rv;
+ return false;
+ }
+ }
+ pos += read_size;
+ remaining -= read_size;
+ output_block++;
+ }
+
+ return true;
+}
+
+int SparseBuilder::OpenImageFile(const std::string& file) {
+ android::base::unique_fd source_fd(open(file.c_str(), O_RDONLY));
+ if (source_fd < 0) {
+ PERROR << "open image file failed: " << file;
+ return -1;
+ }
+
+ std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> source(
+ sparse_file_import(source_fd, true, true), sparse_file_destroy);
+ if (!source) {
+ int fd = source_fd.get();
+ temp_fds_.push_back(std::move(source_fd));
+ return fd;
+ }
+
+ char temp_file[PATH_MAX];
+ snprintf(temp_file, sizeof(temp_file), "%s/imageXXXXXX", P_tmpdir);
+ android::base::unique_fd temp_fd(mkstemp(temp_file));
+ if (temp_fd < 0) {
+ PERROR << "mkstemp failed";
+ return -1;
+ }
+ if (unlink(temp_file) < 0) {
+ PERROR << "unlink failed";
+ return -1;
+ }
+
+ // We temporarily unsparse the file, rather than try to merge its chunks.
+ int rv = sparse_file_write(source.get(), temp_fd, false, false, false);
+ if (rv) {
+ LERROR << "sparse_file_write failed with code: " << rv;
+ return -1;
+ }
+ temp_fds_.push_back(std::move(temp_fd));
+ return temp_fds_.back().get();
+}
+
+bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images) {
+ if (block_size % LP_SECTOR_SIZE != 0) {
+ LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE;
+ return false;
+ }
+ if (metadata.geometry.block_device_size % block_size != 0) {
+ LERROR << "Device size must be a multiple of the block size, " << block_size;
+ return false;
+ }
+ uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
+ if (num_blocks >= UINT_MAX) {
+ // libsparse counts blocks in unsigned 32-bit integers, so we check to
+ // make sure we're not going to overflow.
+ LERROR << "Block device is too large to encode with libsparse.";
+ return false;
+ }
+
+ SparseBuilder builder(metadata, block_size, images);
+ if (!builder.IsValid()) {
+ LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size;
+ return false;
+ }
+ if (!builder.Build()) {
+ return false;
+ }
+ return builder.Export(file);
+}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/liblp/images.h b/fs_mgr/liblp/images.h
new file mode 100644
index 0000000..3a999b8
--- /dev/null
+++ b/fs_mgr/liblp/images.h
@@ -0,0 +1,29 @@
+/*
+ * 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 <liblp/liblp.h>
+
+namespace android {
+namespace fs_mgr {
+
+// Helper function to serialize geometry and metadata to a normal file, for
+// flashing or debugging.
+std::unique_ptr<LpMetadata> ReadFromImageFile(int fd);
+bool WriteToImageFile(const char* file, const LpMetadata& metadata);
+bool WriteToImageFile(int fd, const LpMetadata& metadata);
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 671a3bd..8bde313 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -23,13 +23,31 @@
#include <map>
#include <memory>
-#include "metadata_format.h"
+#include "liblp.h"
namespace android {
namespace fs_mgr {
class LinearExtent;
+// By default, partitions are aligned on a 1MiB boundary.
+static const uint32_t kDefaultPartitionAlignment = 1024 * 1024;
+
+struct BlockDeviceInfo {
+ BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0) {}
+ BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset)
+ : size(size), alignment(alignment), alignment_offset(alignment_offset) {}
+ // Size of the block device, in bytes.
+ uint64_t size;
+ // Optimal target alignment, in bytes. Partition extents will be aligned to
+ // this value by default. This value must be 0 or a multiple of 512.
+ uint32_t alignment;
+ // Alignment offset to parent device (if any), in bytes. The sector at
+ // |alignment_offset| on the target device is correctly aligned on its
+ // parent device. This value must be 0 or a multiple of 512.
+ uint32_t alignment_offset;
+};
+
// Abstraction around dm-targets that can be encoded into logical partition tables.
class Extent {
public:
@@ -107,14 +125,29 @@
// If the parameters would yield invalid metadata, nullptr is returned. This
// could happen if the block device size is too small to store the metadata
// and backup copies.
- static std::unique_ptr<MetadataBuilder> New(uint64_t blockdevice_size,
+ static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info,
uint32_t metadata_max_size,
uint32_t metadata_slot_count);
+ // Import an existing table for modification. This reads metadata off the
+ // given block device and imports it. It also adjusts alignment information
+ // based on run-time values in the operating system.
+ static std::unique_ptr<MetadataBuilder> New(const std::string& block_device,
+ uint32_t slot_number);
+
// Import an existing table for modification. If the table is not valid, for
// example it contains duplicate partition names, then nullptr is returned.
+ // This method is for testing or changing off-line tables.
static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata);
+ // Wrapper around New() with a BlockDeviceInfo that only specifies a device
+ // size. This is a convenience method for tests.
+ static std::unique_ptr<MetadataBuilder> New(uint64_t blockdev_size, uint32_t metadata_max_size,
+ uint32_t metadata_slot_count) {
+ BlockDeviceInfo device_info(blockdev_size, 0, 0);
+ return New(device_info, metadata_max_size, metadata_slot_count);
+ }
+
// Export metadata so it can be serialized to an image, to disk, or mounted
// via device-mapper.
std::unique_ptr<LpMetadata> Export();
@@ -156,16 +189,28 @@
// Amount of space that can be allocated to logical partitions.
uint64_t AllocatableSpace() const;
+ // Merge new block device information into previous values. Alignment values
+ // are only overwritten if the new values are non-zero.
+ void set_block_device_info(const BlockDeviceInfo& device_info);
+ const BlockDeviceInfo& block_device_info() const { return device_info_; }
+
private:
MetadataBuilder();
- bool Init(uint64_t blockdevice_size, uint32_t metadata_max_size, uint32_t metadata_slot_count);
+ bool Init(const BlockDeviceInfo& info, uint32_t metadata_max_size, uint32_t metadata_slot_count);
bool Init(const LpMetadata& metadata);
+ uint64_t AlignSector(uint64_t sector);
+
LpMetadataGeometry geometry_;
LpMetadataHeader header_;
std::vector<std::unique_ptr<Partition>> partitions_;
+ BlockDeviceInfo device_info_;
};
+// Read BlockDeviceInfo for a given block device. This always returns false
+// for non-Linux operating systems.
+bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
new file mode 100644
index 0000000..627aa8c
--- /dev/null
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -0,0 +1,78 @@
+//
+// 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 LIBLP_LIBLP_H
+#define LIBLP_LIBLP_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "metadata_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+// Helper structure for easily interpreting deserialized metadata, or
+// re-serializing metadata.
+struct LpMetadata {
+ LpMetadataGeometry geometry;
+ LpMetadataHeader header;
+ std::vector<LpMetadataPartition> partitions;
+ std::vector<LpMetadataExtent> extents;
+};
+
+// Place an initial partition table on the device. This will overwrite the
+// existing geometry, and should not be used for normal partition table
+// updates. False can be returned if the geometry is incompatible with the
+// block device or an I/O error occurs.
+bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata,
+ uint32_t slot_number);
+
+// Update the partition table for a given metadata slot number. False is
+// returned if an error occurs, which can include:
+// - Invalid slot number.
+// - I/O error.
+// - Corrupt or missing metadata geometry on disk.
+// - Incompatible geometry.
+bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata,
+ uint32_t slot_number);
+
+// Read logical partition metadata from its predetermined location on a block
+// device. If readback fails, we also attempt to load from a backup copy.
+std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number);
+
+// Read/Write logical partition metadata to an image file, for diagnostics or
+// flashing.
+bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images);
+bool WriteToImageFile(const char* file, const LpMetadata& metadata);
+std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
+
+// Helper to extract safe C++ strings from partition info.
+std::string GetPartitionName(const LpMetadataPartition& partition);
+std::string GetPartitionGuid(const LpMetadataPartition& partition);
+
+// Helper to return a slot number for a slot suffix.
+uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
+
+} // namespace fs_mgr
+} // namespace android
+
+#endif // LIBLP_LIBLP_H
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 8522435..e1323e1 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -67,7 +67,7 @@
* | Geometry Backup |
* +--------------------+
*/
-#define LP_METADATA_PARTITION_NAME "android"
+#define LP_METADATA_PARTITION_NAME "super"
/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
#define LP_SECTOR_SIZE 512
@@ -86,7 +86,9 @@
/* 8: SHA256 checksum of this struct, with this field set to 0. */
uint8_t checksum[32];
- /* 40: Maximum amount of space a single copy of the metadata can use. */
+ /* 40: Maximum amount of space a single copy of the metadata can use. This
+ * must be a multiple of LP_SECTOR_SIZE.
+ */
uint32_t metadata_max_size;
/* 44: Number of copies of the metadata to keep. For A/B devices, this
@@ -107,6 +109,33 @@
* backup geometry block at the very end.
*/
uint64_t last_logical_sector;
+
+ /* 64: Alignment for defining partitions or partition extents. For example,
+ * an alignment of 1MiB will require that all partitions have a size evenly
+ * divisible by 1MiB, and that the smallest unit the partition can grow by
+ * is 1MiB.
+ *
+ * Alignment is normally determined at runtime when growing or adding
+ * partitions. If for some reason the alignment cannot be determined, then
+ * this predefined alignment in the geometry is used instead. By default
+ * it is set to 1MiB.
+ */
+ uint32_t alignment;
+
+ /* 68: Alignment offset for "stacked" devices. For example, if the "super"
+ * partition itself is not aligned within the parent block device's
+ * partition table, then we adjust for this in deciding where to place
+ * |first_logical_sector|.
+ *
+ * Similar to |alignment|, this will be derived from the operating system.
+ * If it cannot be determined, it is assumed to be 0.
+ */
+ uint32_t alignment_offset;
+
+ /* 72: Block device size, as specified when the metadata was created. This
+ * can be used to verify the geometry against a target device.
+ */
+ uint64_t block_device_size;
} __attribute__((packed)) LpMetadataGeometry;
/* The logical partition metadata has a number of tables; they are described
@@ -240,28 +269,4 @@
} /* extern "C" */
#endif
-#ifdef __cplusplus
-namespace android {
-namespace fs_mgr {
-
-// Helper structure for easily interpreting deserialized metadata, or
-// re-serializing metadata.
-struct LpMetadata {
- LpMetadataGeometry geometry;
- LpMetadataHeader header;
- std::vector<LpMetadataPartition> partitions;
- std::vector<LpMetadataExtent> extents;
-};
-
-// Helper to extract safe C++ strings from partition info.
-std::string GetPartitionName(const LpMetadataPartition& partition);
-std::string GetPartitionGuid(const LpMetadataPartition& partition);
-
-// Helper to return a slot number for a slot suffix.
-uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
-
-} // namespace fs_mgr
-} // namespace android
-#endif
-
#endif /* LOGICAL_PARTITION_METADATA_FORMAT_H_ */
diff --git a/fs_mgr/liblp/include/liblp/reader.h b/fs_mgr/liblp/include/liblp/reader.h
deleted file mode 100644
index 982fe65..0000000
--- a/fs_mgr/liblp/include/liblp/reader.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 LIBLP_READER_H_
-#define LIBLP_READER_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "metadata_format.h"
-
-namespace android {
-namespace fs_mgr {
-
-// Read logical partition metadata from its predetermined location on a block
-// device. If readback fails, we also attempt to load from a backup copy.
-std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number);
-std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number);
-
-// Read and validate the logical partition geometry from a block device.
-bool ReadLogicalPartitionGeometry(const char* block_device, LpMetadataGeometry* geometry);
-bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
-
-// Read logical partition metadata from an image file that was created with
-// WriteToImageFile().
-std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
-std::unique_ptr<LpMetadata> ReadFromImageFile(int fd);
-
-} // namespace fs_mgr
-} // namespace android
-
-#endif /* LIBLP_READER_H_ */
diff --git a/fs_mgr/liblp/include/liblp/writer.h b/fs_mgr/liblp/include/liblp/writer.h
deleted file mode 100644
index efa409d..0000000
--- a/fs_mgr/liblp/include/liblp/writer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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 LIBLP_WRITER_H
-#define LIBLP_WRITER_H
-
-#include "metadata_format.h"
-
-namespace android {
-namespace fs_mgr {
-
-// When flashing the initial logical partition layout, we also write geometry
-// information at the start and end of the big physical partition. This helps
-// locate metadata and backup metadata in the case of corruption or a failed
-// update. For normal changes to the metadata, we never modify the geometry.
-enum class SyncMode {
- // Write geometry information.
- Flash,
- // Normal update of a single slot.
- Update
-};
-
-// Write the given partition table to the given block device, writing only
-// copies according to the given sync mode.
-//
-// This will perform some verification, such that the device has enough space
-// to store the metadata as well as all of its extents.
-//
-// The slot number indicates which metadata slot to use.
-bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode,
- uint32_t slot_number);
-bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode,
- uint32_t slot_number);
-
-// Helper function to serialize geometry and metadata to a normal file, for
-// flashing or debugging.
-bool WriteToImageFile(const char* file, const LpMetadata& metadata);
-bool WriteToImageFile(int fd, const LpMetadata& metadata);
-
-} // namespace fs_mgr
-} // namespace android
-
-#endif /* LIBLP_WRITER_H */
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 2595654..bbbedc7 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -23,10 +23,11 @@
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#include <liblp/builder.h>
-#include <liblp/reader.h>
-#include <liblp/writer.h>
+#include "images.h"
+#include "reader.h"
#include "utility.h"
+#include "writer.h"
using namespace std;
using namespace android::fs_mgr;
@@ -102,7 +103,7 @@
if (!exported) {
return {};
}
- if (!WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0)) {
+ if (!FlashPartitionTable(fd, *exported.get(), 0)) {
return {};
}
return fd;
@@ -131,7 +132,7 @@
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
- EXPECT_FALSE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0));
+ EXPECT_FALSE(FlashPartitionTable(fd, *exported.get(), 0));
}
// Test the basics of flashing a partition and reading it back.
@@ -146,7 +147,7 @@
// Export and flash.
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
- ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0));
+ ASSERT_TRUE(FlashPartitionTable(fd, *exported.get(), 0));
// Read back. Note that some fields are only filled in during
// serialization, so exported and imported will not be identical. For
@@ -195,7 +196,7 @@
// Change the name before writing to the next slot.
strncpy(imported->partitions[0].name, "vendor", sizeof(imported->partitions[0].name));
- ASSERT_TRUE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1));
// Read back the original slot, make sure it hasn't changed.
imported = ReadMetadata(fd, 0);
@@ -231,7 +232,7 @@
unique_ptr<LpMetadata> metadata = ReadMetadata(fd, 0);
ASSERT_NE(metadata, nullptr);
for (uint32_t i = 1; i < kMetadataSlots; i++) {
- ASSERT_TRUE(WritePartitionTable(fd, *metadata.get(), SyncMode::Update, i));
+ ASSERT_TRUE(UpdatePartitionTable(fd, *metadata.get(), i));
}
// Verify that we can't read unavailable slots.
@@ -246,25 +247,25 @@
unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
- ASSERT_TRUE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_TRUE(UpdatePartitionTable(fd, *imported.get(), 1));
imported->geometry.metadata_max_size += LP_SECTOR_SIZE;
- ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
imported->geometry.metadata_slot_count++;
- ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
imported->geometry.first_logical_sector++;
- ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
imported = ReadMetadata(fd, 0);
ASSERT_NE(imported, nullptr);
imported->geometry.last_logical_sector--;
- ASSERT_FALSE(WritePartitionTable(fd, *imported.get(), SyncMode::Update, 1));
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
}
// Test that changing one bit of metadata is enough to break the checksum.
@@ -353,8 +354,8 @@
ASSERT_GE(fd, 0);
// Check that we are able to write our table.
- ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Flash, 0));
- ASSERT_TRUE(WritePartitionTable(fd, *exported.get(), SyncMode::Update, 1));
+ ASSERT_TRUE(FlashPartitionTable(fd, *exported.get(), 0));
+ ASSERT_TRUE(UpdatePartitionTable(fd, *exported.get(), 1));
// Check that adding one more partition overflows the metadata allotment.
partition = builder->AddPartition("final", TEST_GUID, LP_PARTITION_ATTR_NONE);
@@ -364,7 +365,7 @@
ASSERT_NE(exported, nullptr);
// The new table should be too large to be written.
- ASSERT_FALSE(WritePartitionTable(fd, *exported.get(), SyncMode::Update, 1));
+ ASSERT_FALSE(UpdatePartitionTable(fd, *exported.get(), 1));
// Check that the first and last logical sectors weren't touched when we
// wrote this almost-full metadata.
@@ -393,3 +394,130 @@
unique_ptr<LpMetadata> imported = ReadFromImageFile(fd);
ASSERT_NE(imported, nullptr);
}
+
+class BadWriter {
+ public:
+ // When requested, write garbage instead of the requested bytes, then
+ // return false.
+ bool operator()(int fd, const std::string& blob) {
+ write_count_++;
+ if (write_count_ == fail_on_write_) {
+ std::unique_ptr<char[]> new_data = std::make_unique<char[]>(blob.size());
+ memset(new_data.get(), 0xe5, blob.size());
+ EXPECT_TRUE(android::base::WriteFully(fd, new_data.get(), blob.size()));
+ return false;
+ } else {
+ if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+ return false;
+ }
+ return fail_after_write_ != write_count_;
+ }
+ }
+ void Reset() {
+ fail_on_write_ = 0;
+ fail_after_write_ = 0;
+ write_count_ = 0;
+ }
+ void FailOnWrite(int number) {
+ Reset();
+ fail_on_write_ = number;
+ }
+ void FailAfterWrite(int number) {
+ Reset();
+ fail_after_write_ = number;
+ }
+
+ private:
+ int fail_on_write_ = 0;
+ int fail_after_write_ = 0;
+ int write_count_ = 0;
+};
+
+// Test that an interrupted flash operation on the "primary" copy of metadata
+// is not fatal.
+TEST(liblp, UpdatePrimaryMetadataFailure) {
+ unique_fd fd = CreateFlashedDisk();
+ ASSERT_GE(fd, 0);
+
+ BadWriter writer;
+
+ // Read and write it back.
+ writer.FailOnWrite(1);
+ unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+
+ // We should still be able to read the backup copy.
+ imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+
+ // Flash again, this time fail the backup copy. We should still be able
+ // to read the primary.
+ writer.FailOnWrite(3);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+ imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+}
+
+// Test that an interrupted flash operation on the "backup" copy of metadata
+// is not fatal.
+TEST(liblp, UpdateBackupMetadataFailure) {
+ unique_fd fd = CreateFlashedDisk();
+ ASSERT_GE(fd, 0);
+
+ BadWriter writer;
+
+ // Read and write it back.
+ writer.FailOnWrite(2);
+ unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+
+ // We should still be able to read the primary copy.
+ imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+
+ // Flash again, this time fail the primary copy. We should still be able
+ // to read the primary.
+ writer.FailOnWrite(2);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 0, writer));
+ imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+}
+
+// Test that an interrupted write *in between* writing metadata will read
+// the correct metadata copy. The primary is always considered newer than
+// the backup.
+TEST(liblp, UpdateMetadataCleanFailure) {
+ unique_fd fd = CreateFlashedDisk();
+ ASSERT_GE(fd, 0);
+
+ BadWriter writer;
+
+ // Change the name of the existing partition.
+ unique_ptr<LpMetadata> new_table = ReadMetadata(fd, 0);
+ ASSERT_NE(new_table, nullptr);
+ ASSERT_GE(new_table->partitions.size(), 1);
+ new_table->partitions[0].name[0]++;
+
+ // Flash it, but fail to write the backup copy.
+ writer.FailAfterWrite(2);
+ ASSERT_FALSE(UpdatePartitionTable(fd, *new_table.get(), 0, writer));
+
+ // When we read back, we should get the updated primary copy.
+ unique_ptr<LpMetadata> imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+ ASSERT_GE(new_table->partitions.size(), 1);
+ ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
+
+ // Flash again. After, the backup and primary copy should be coherent.
+ // Note that the sync step should have used the primary to sync, not
+ // the backup.
+ writer.Reset();
+ ASSERT_TRUE(UpdatePartitionTable(fd, *new_table.get(), 0, writer));
+
+ imported = ReadMetadata(fd, 0);
+ ASSERT_NE(imported, nullptr);
+ ASSERT_GE(new_table->partitions.size(), 1);
+ ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
+}
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 7938186..117da59 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "liblp/reader.h"
+#include "reader.h"
#include <stddef.h>
#include <stdlib.h>
@@ -41,11 +41,18 @@
LERROR << "Logical partition metadata has invalid geometry magic signature.";
return false;
}
+ // Reject if the struct size is larger than what we compiled. This is so we
+ // can compute a checksum with the |struct_size| field rather than using
+ // sizeof.
+ if (geometry->struct_size > sizeof(LpMetadataGeometry)) {
+ LERROR << "Logical partition metadata has unrecognized fields.";
+ return false;
+ }
// Recompute and check the CRC32.
{
LpMetadataGeometry temp = *geometry;
memset(&temp.checksum, 0, sizeof(temp.checksum));
- SHA256(&temp, sizeof(temp), temp.checksum);
+ SHA256(&temp, temp.struct_size, temp.checksum);
if (memcmp(temp.checksum, geometry->checksum, sizeof(temp.checksum)) != 0) {
LERROR << "Logical partition metadata has invalid geometry checksum.";
return false;
@@ -61,6 +68,10 @@
LERROR << "Logical partition metadata has invalid slot count.";
return false;
}
+ if (geometry->metadata_max_size % LP_SECTOR_SIZE != 0) {
+ LERROR << "Metadata max size is not sector-aligned.";
+ return false;
+ }
// Check that the metadata area and logical partition areas don't overlap.
int64_t end_of_metadata =
@@ -104,16 +115,6 @@
return ParseGeometry(buffer.get(), geometry);
}
-// Helper function to read geometry from a device without an open descriptor.
-bool ReadLogicalPartitionGeometry(const char* block_device, LpMetadataGeometry* geometry) {
- android::base::unique_fd fd(open(block_device, O_RDONLY));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
- return false;
- }
- return ReadLogicalPartitionGeometry(fd, geometry);
-}
-
static bool ValidateTableBounds(const LpMetadataHeader& header,
const LpMetadataTableDescriptor& table) {
if (table.offset > header.tables_size) {
@@ -168,11 +169,9 @@
return true;
}
-using ReadMetadataFn = std::function<bool(void* buffer, size_t num_bytes)>;
-
// Parse and validate all metadata at the current position in the given file
// descriptor.
-static std::unique_ptr<LpMetadata> ParseMetadata(int fd) {
+std::unique_ptr<LpMetadata> ParseMetadata(int fd) {
// First read and validate the header.
std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
if (!android::base::ReadFully(fd, &metadata->header, sizeof(metadata->header))) {
@@ -236,6 +235,26 @@
return metadata;
}
+std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
+ uint32_t slot_number) {
+ int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
+ if (SeekFile64(fd, offset, SEEK_SET) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
+ return nullptr;
+ }
+ return ParseMetadata(fd);
+}
+
+std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
+ uint32_t slot_number) {
+ int64_t offset = GetBackupMetadataOffset(geometry, slot_number);
+ if (SeekFile64(fd, offset, SEEK_END) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
+ return nullptr;
+ }
+ return ParseMetadata(fd);
+}
+
std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {
LpMetadataGeometry geometry;
if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
@@ -247,24 +266,11 @@
return nullptr;
}
- // First try the primary copy.
- int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
- if (SeekFile64(fd, offset, SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
- return nullptr;
- }
- std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd);
-
- // If the primary copy failed, try the backup copy.
+ // Read the priamry copy, and if that fails, try the backup.
+ std::unique_ptr<LpMetadata> metadata = ReadPrimaryMetadata(fd, geometry, slot_number);
if (!metadata) {
- offset = GetBackupMetadataOffset(geometry, slot_number);
- if (SeekFile64(fd, offset, SEEK_END) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
- return nullptr;
- }
- metadata = ParseMetadata(fd);
+ metadata = ReadBackupMetadata(fd, geometry, slot_number);
}
-
if (metadata) {
metadata->geometry = geometry;
}
@@ -280,32 +286,6 @@
return ReadMetadata(fd, slot_number);
}
-std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
- LpMetadataGeometry geometry;
- if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
- return nullptr;
- }
- if (SeekFile64(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << LP_METADATA_GEOMETRY_SIZE;
- return nullptr;
- }
- std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd);
- if (!metadata) {
- return nullptr;
- }
- metadata->geometry = geometry;
- return metadata;
-}
-
-std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
- android::base::unique_fd fd(open(file, O_RDONLY));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
- return nullptr;
- }
- return ReadFromImageFile(fd);
-}
-
static std::string NameFromFixedArray(const char* name, size_t buffer_size) {
// If the end of the buffer has a null character, it's safe to assume the
// buffer is null terminated. Otherwise, we cap the string to the input
diff --git a/fs_mgr/liblp/reader.h b/fs_mgr/liblp/reader.h
new file mode 100644
index 0000000..843b2f2
--- /dev/null
+++ b/fs_mgr/liblp/reader.h
@@ -0,0 +1,44 @@
+/*
+ * 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 LIBLP_READER_H_
+#define LIBLP_READER_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include <liblp/liblp.h>
+
+namespace android {
+namespace fs_mgr {
+
+std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number);
+
+// Helper functions for manually reading geometry and metadata.
+bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
+std::unique_ptr<LpMetadata> ParseMetadata(int fd);
+
+// These functions assume a valid geometry and slot number.
+std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
+ uint32_t slot_number);
+std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
+ uint32_t slot_number);
+
+} // namespace fs_mgr
+} // namespace android
+
+#endif /* LIBLP_READER_H_ */
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 5310cab..a590037 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -38,7 +38,8 @@
}
if (S_ISBLK(s.st_mode)) {
- return get_block_device_size(fd);
+ *size = get_block_device_size(fd);
+ return *size != 0;
}
int64_t result = SeekFile64(fd, 0, SEEK_END);
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 09ed314..4522275 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -50,6 +50,30 @@
// Compute a SHA256 hash.
void SHA256(const void* data, size_t length, uint8_t out[32]);
+// Align |base| such that it is evenly divisible by |alignment|, which does not
+// have to be a power of two.
+constexpr uint64_t AlignTo(uint64_t base, uint32_t alignment) {
+ if (!alignment) {
+ return base;
+ }
+ uint64_t remainder = base % alignment;
+ if (remainder == 0) {
+ return base;
+ }
+ return base + (alignment - remainder);
+}
+
+// Same as the above |AlignTo|, except that |base| is only aligned when added to
+// |alignment_offset|.
+constexpr uint64_t AlignTo(uint64_t base, uint32_t alignment, uint32_t alignment_offset) {
+ uint64_t aligned = AlignTo(base, alignment) + alignment_offset;
+ if (aligned - alignment >= base) {
+ // We overaligned (base < alignment_offset).
+ return aligned - alignment;
+ }
+ return aligned;
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 25e8a25..092dbf1 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-#include "utility.h"
#include <gtest/gtest.h>
+#include <liblp/liblp.h>
+
+#include "utility.h"
using namespace android;
using namespace android::fs_mgr;
@@ -29,8 +31,16 @@
}
TEST(liblp, GetMetadataOffset) {
- LpMetadataGeometry geometry = {
- LP_METADATA_GEOMETRY_MAGIC, sizeof(geometry), {0}, 16384, 4, 10000, 80000};
+ LpMetadataGeometry geometry = {LP_METADATA_GEOMETRY_MAGIC,
+ sizeof(geometry),
+ {0},
+ 16384,
+ 4,
+ 10000,
+ 80000,
+ 0,
+ 0,
+ 1024 * 1024};
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 4096);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 4096 + 16384);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 4096 + 16384 * 2);
@@ -41,3 +51,14 @@
EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), -4096 - 16384 * 3);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 0), -4096 - 16384 * 4);
}
+
+TEST(liblp, AlignTo) {
+ EXPECT_EQ(AlignTo(37, 0), 37);
+ EXPECT_EQ(AlignTo(1024, 1024), 1024);
+ EXPECT_EQ(AlignTo(555, 1024), 1024);
+ EXPECT_EQ(AlignTo(555, 1000), 1000);
+ EXPECT_EQ(AlignTo(0, 1024), 0);
+ EXPECT_EQ(AlignTo(54, 32, 30), 62);
+ EXPECT_EQ(AlignTo(32, 32, 30), 62);
+ EXPECT_EQ(AlignTo(17, 32, 30), 30);
+}
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 89cbabd..156319b 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "writer.h"
+
#include <inttypes.h>
#include <unistd.h>
@@ -22,18 +24,20 @@
#include <android-base/file.h>
#include <android-base/unique_fd.h>
-#include "liblp/reader.h"
-#include "liblp/writer.h"
+#include "reader.h"
#include "utility.h"
namespace android {
namespace fs_mgr {
-static std::string SerializeGeometry(const LpMetadataGeometry& input) {
+std::string SerializeGeometry(const LpMetadataGeometry& input) {
LpMetadataGeometry geometry = input;
memset(geometry.checksum, 0, sizeof(geometry.checksum));
SHA256(&geometry, sizeof(geometry), geometry.checksum);
- return std::string(reinterpret_cast<const char*>(&geometry), sizeof(geometry));
+
+ std::string blob(reinterpret_cast<const char*>(&geometry), sizeof(geometry));
+ blob.resize(LP_METADATA_GEOMETRY_SIZE);
+ return blob;
}
static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeometry& g2) {
@@ -43,7 +47,7 @@
g1.last_logical_sector == g2.last_logical_sector;
}
-static std::string SerializeMetadata(const LpMetadata& input) {
+std::string SerializeMetadata(const LpMetadata& input) {
LpMetadata metadata = input;
LpMetadataHeader& header = metadata.header;
@@ -73,8 +77,14 @@
// Perform sanity checks so we don't accidentally overwrite valid metadata
// with potentially invalid metadata, or random partition data with metadata.
-static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blockdevice_size,
- uint64_t metadata_size) {
+static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std::string* blob) {
+ uint64_t blockdevice_size;
+ if (!GetDescriptorSize(fd, &blockdevice_size)) {
+ return false;
+ }
+
+ *blob = SerializeMetadata(metadata);
+
const LpMetadataHeader& header = metadata.header;
const LpMetadataGeometry& geometry = metadata.geometry;
// Validate the usable sector range.
@@ -83,7 +93,7 @@
return false;
}
// Make sure we're writing within the space reserved.
- if (metadata_size > geometry.metadata_max_size) {
+ if (blob->size() > geometry.metadata_max_size) {
LERROR << "Logical partition metadata is too large.";
return false;
}
@@ -101,6 +111,11 @@
LERROR << "Not enough space to backup all logical partition metadata slots.";
return false;
}
+ if (blockdevice_size != metadata.geometry.block_device_size) {
+ LERROR << "Block device size " << blockdevice_size
+ << " does not match metadata requested size " << metadata.geometry.block_device_size;
+ return false;
+ }
// Make sure all partition entries reference valid extents.
for (const auto& partition : metadata.partitions) {
@@ -124,75 +139,24 @@
return true;
}
-bool WritePartitionTable(int fd, const LpMetadata& metadata, SyncMode sync_mode,
- uint32_t slot_number) {
- uint64_t size;
- if (!GetDescriptorSize(fd, &size)) {
- return false;
- }
-
- const LpMetadataGeometry& geometry = metadata.geometry;
- if (sync_mode != SyncMode::Flash) {
- // Verify that the old geometry is identical. If it's not, then we've
- // based this new metadata on invalid assumptions.
- LpMetadataGeometry old_geometry;
- if (!ReadLogicalPartitionGeometry(fd, &old_geometry)) {
- return false;
- }
- if (!CompareGeometry(geometry, old_geometry)) {
- LERROR << "Incompatible geometry in new logical partition metadata";
- return false;
- }
- }
-
- // Make sure we're writing to a valid metadata slot.
- if (slot_number >= geometry.metadata_slot_count) {
- LERROR << "Invalid logical partition metadata slot number.";
- return false;
- }
-
- // Before writing geometry and/or logical partition tables, perform some
- // basic checks that the geometry and tables are coherent, and will fit
- // on the given block device.
- std::string blob = SerializeMetadata(metadata);
- if (!ValidateGeometryAndMetadata(metadata, size, blob.size())) {
- return false;
- }
-
- // First write geometry if this is a flash operation. It gets written to
- // the first and last 4096-byte regions of the device.
- if (sync_mode == SyncMode::Flash) {
- std::string blob = SerializeGeometry(metadata.geometry);
- if (SeekFile64(fd, 0, SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0";
- return false;
- }
- if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
- PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
- return false;
- }
- if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE;
- return false;
- }
- if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
- PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
- return false;
- }
- }
-
- // Write the primary copy of the metadata.
+static bool WritePrimaryMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number,
+ const std::string& blob,
+ const std::function<bool(int, const std::string&)>& writer) {
int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << primary_offset;
return false;
}
- if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+ if (!writer(fd, blob)) {
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
return false;
}
+ return true;
+}
- // Write the backup copy of the metadata.
+static bool WriteBackupMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number,
+ const std::string& blob,
+ const std::function<bool(int, const std::string&)>& writer) {
int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number);
int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_END);
if (abs_offset == (int64_t)-1) {
@@ -204,44 +168,157 @@
<< " is within logical partition bounds, sector " << geometry.last_logical_sector;
return false;
}
- if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+ if (!writer(fd, blob)) {
PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
return false;
}
return true;
}
-bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode,
- uint32_t slot_number) {
- android::base::unique_fd fd(open(block_device, O_RDWR | O_SYNC));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+static bool WriteMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number,
+ const std::string& blob,
+ const std::function<bool(int, const std::string&)>& writer) {
+ // Make sure we're writing to a valid metadata slot.
+ if (slot_number >= geometry.metadata_slot_count) {
+ LERROR << "Invalid logical partition metadata slot number.";
return false;
}
- return WritePartitionTable(fd, metadata, sync_mode, slot_number);
-}
-
-bool WriteToImageFile(int fd, const LpMetadata& input) {
- std::string geometry = SerializeGeometry(input.geometry);
- std::string padding(LP_METADATA_GEOMETRY_SIZE - geometry.size(), '\0');
- std::string metadata = SerializeMetadata(input);
-
- std::string everything = geometry + padding + metadata;
-
- if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
- PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed";
+ if (!WritePrimaryMetadata(fd, geometry, slot_number, blob, writer)) {
+ return false;
+ }
+ if (!WriteBackupMetadata(fd, geometry, slot_number, blob, writer)) {
return false;
}
return true;
}
-bool WriteToImageFile(const char* file, const LpMetadata& input) {
- android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
- if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+static bool DefaultWriter(int fd, const std::string& blob) {
+ return android::base::WriteFully(fd, blob.data(), blob.size());
+}
+
+bool FlashPartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) {
+ // Before writing geometry and/or logical partition tables, perform some
+ // basic checks that the geometry and tables are coherent, and will fit
+ // on the given block device.
+ std::string metadata_blob;
+ if (!ValidateAndSerializeMetadata(fd, metadata, &metadata_blob)) {
return false;
}
- return WriteToImageFile(fd, input);
+
+ // Write geometry to the first and last 4096 bytes of the device.
+ std::string blob = SerializeGeometry(metadata.geometry);
+ if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0";
+ return false;
+ }
+ if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+ PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
+ return false;
+ }
+ if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE;
+ return false;
+ }
+ if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+ PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
+ return false;
+ }
+
+ // Write metadata to the correct slot, now that geometry is in place.
+ return WriteMetadata(fd, metadata.geometry, slot_number, metadata_blob, DefaultWriter);
+}
+
+static bool CompareMetadata(const LpMetadata& a, const LpMetadata& b) {
+ return !memcmp(a.header.header_checksum, b.header.header_checksum,
+ sizeof(a.header.header_checksum));
+}
+
+bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number,
+ const std::function<bool(int, const std::string&)>& writer) {
+ // Before writing geometry and/or logical partition tables, perform some
+ // basic checks that the geometry and tables are coherent, and will fit
+ // on the given block device.
+ std::string blob;
+ if (!ValidateAndSerializeMetadata(fd, metadata, &blob)) {
+ return false;
+ }
+
+ // Verify that the old geometry is identical. If it's not, then we might be
+ // writing a table that was built for a different device, so we must reject
+ // it.
+ const LpMetadataGeometry& geometry = metadata.geometry;
+ LpMetadataGeometry old_geometry;
+ if (!ReadLogicalPartitionGeometry(fd, &old_geometry)) {
+ return false;
+ }
+ if (!CompareGeometry(geometry, old_geometry)) {
+ LERROR << "Incompatible geometry in new logical partition metadata";
+ return false;
+ }
+
+ // Validate the slot number now, before we call Read*Metadata.
+ if (slot_number >= geometry.metadata_slot_count) {
+ LERROR << "Invalid logical partition metadata slot number.";
+ return false;
+ }
+
+ // Try to read both existing copies of the metadata, if any.
+ std::unique_ptr<LpMetadata> primary = ReadPrimaryMetadata(fd, geometry, slot_number);
+ std::unique_ptr<LpMetadata> backup = ReadBackupMetadata(fd, geometry, slot_number);
+
+ if (primary && (!backup || !CompareMetadata(*primary.get(), *backup.get()))) {
+ // If the backup copy does not match the primary copy, we first
+ // synchronize the backup copy. This guarantees that a partial write
+ // still leaves one copy intact.
+ std::string old_blob;
+ if (!ValidateAndSerializeMetadata(fd, *primary.get(), &old_blob)) {
+ LERROR << "Error serializing primary metadata to repair corrupted backup";
+ return false;
+ }
+ if (!WriteBackupMetadata(fd, geometry, slot_number, old_blob, writer)) {
+ LERROR << "Error writing primary metadata to repair corrupted backup";
+ return false;
+ }
+ } else if (backup && !primary) {
+ // The backup copy is coherent, and the primary is not. Sync it for
+ // safety.
+ std::string old_blob;
+ if (!ValidateAndSerializeMetadata(fd, *backup.get(), &old_blob)) {
+ LERROR << "Error serializing primary metadata to repair corrupted backup";
+ return false;
+ }
+ if (!WritePrimaryMetadata(fd, geometry, slot_number, old_blob, writer)) {
+ LERROR << "Error writing primary metadata to repair corrupted backup";
+ return false;
+ }
+ }
+
+ // Both copies should now be in sync, so we can continue the update.
+ return WriteMetadata(fd, geometry, slot_number, blob, writer);
+}
+
+bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata,
+ uint32_t slot_number) {
+ android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+ return false;
+ }
+ return FlashPartitionTable(fd, metadata, slot_number);
+}
+
+bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& metadata,
+ uint32_t slot_number) {
+ android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
+ if (fd < 0) {
+ PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+ return false;
+ }
+ return UpdatePartitionTable(fd, metadata, slot_number);
+}
+
+bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number) {
+ return UpdatePartitionTable(fd, metadata, slot_number, DefaultWriter);
}
} // namespace fs_mgr
diff --git a/fs_mgr/liblp/writer.h b/fs_mgr/liblp/writer.h
new file mode 100644
index 0000000..adbbebf
--- /dev/null
+++ b/fs_mgr/liblp/writer.h
@@ -0,0 +1,42 @@
+/*
+ * 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 LIBLP_WRITER_H
+#define LIBLP_WRITER_H
+
+#include <functional>
+#include <string>
+
+#include <liblp/liblp.h>
+
+namespace android {
+namespace fs_mgr {
+
+std::string SerializeGeometry(const LpMetadataGeometry& input);
+std::string SerializeMetadata(const LpMetadata& input);
+
+// These variants are for testing only. The path-based functions should be used
+// for actual operation, so that open() is called with the correct flags.
+bool FlashPartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number);
+bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number);
+
+bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_number,
+ const std::function<bool(int, const std::string&)>& writer);
+
+} // namespace fs_mgr
+} // namespace android
+
+#endif /* LIBLP_WRITER_H */
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 2e76752..8b1c55a 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -14,13 +14,18 @@
* limitations under the License.
*/
+#include <linux/fs.h>
+#include <mntent.h>
+
#include <algorithm>
#include <iterator>
+#include <set>
#include <string>
#include <utility>
#include <vector>
#include <android-base/strings.h>
+#include <fstab/fstab.h>
#include <gtest/gtest.h>
#include "../fs_mgr_priv_boot_config.h"
@@ -129,3 +134,70 @@
EXPECT_FALSE(fs_mgr_get_boot_config_from_kernel(cmdline, "nospace", &content));
EXPECT_TRUE(content.empty()) << content;
}
+
+TEST(fs_mgr, fs_mgr_read_fstab_file_proc_mounts) {
+ auto fstab = fs_mgr_read_fstab("/proc/mounts");
+ ASSERT_NE(fstab, nullptr);
+
+ std::unique_ptr<std::FILE, int (*)(std::FILE*)> mounts(setmntent("/proc/mounts", "r"),
+ endmntent);
+ ASSERT_NE(mounts, nullptr);
+
+ mntent* mentry;
+ int i = 0;
+ while ((mentry = getmntent(mounts.get())) != nullptr) {
+ ASSERT_LT(i, fstab->num_entries);
+ auto fsrec = &fstab->recs[i];
+
+ std::string mnt_fsname(mentry->mnt_fsname ?: "nullptr");
+ std::string blk_device(fsrec->blk_device ?: "nullptr");
+ EXPECT_EQ(mnt_fsname, blk_device);
+
+ std::string mnt_dir(mentry->mnt_dir ?: "nullptr");
+ std::string mount_point(fsrec->mount_point ?: "nullptr");
+ EXPECT_EQ(mnt_dir, mount_point);
+
+ std::string mnt_type(mentry->mnt_type ?: "nullptr");
+ std::string fs_type(fsrec->fs_type ?: "nullptr");
+ EXPECT_EQ(mnt_type, fs_type);
+
+ std::set<std::string> mnt_opts;
+ for (auto& s : android::base::Split(mentry->mnt_opts ?: "nullptr", ",")) {
+ mnt_opts.emplace(s);
+ }
+ std::set<std::string> fs_options;
+ for (auto& s : android::base::Split(fsrec->fs_options ?: "nullptr", ",")) {
+ fs_options.emplace(s);
+ }
+ // matches private content in fs_mgr_fstab.c
+ static struct flag_list {
+ const char* name;
+ unsigned int flag;
+ } mount_flags[] = {
+ {"noatime", MS_NOATIME},
+ {"noexec", MS_NOEXEC},
+ {"nosuid", MS_NOSUID},
+ {"nodev", MS_NODEV},
+ {"nodiratime", MS_NODIRATIME},
+ {"ro", MS_RDONLY},
+ {"rw", 0},
+ {"remount", MS_REMOUNT},
+ {"bind", MS_BIND},
+ {"rec", MS_REC},
+ {"unbindable", MS_UNBINDABLE},
+ {"private", MS_PRIVATE},
+ {"slave", MS_SLAVE},
+ {"shared", MS_SHARED},
+ {"defaults", 0},
+ {0, 0},
+ };
+ for (auto f = 0; mount_flags[f].name; ++f) {
+ if (mount_flags[f].flag & fsrec->flags) {
+ fs_options.emplace(mount_flags[f].name);
+ }
+ }
+ if (!(fsrec->flags & MS_RDONLY)) fs_options.emplace("rw");
+ EXPECT_EQ(mnt_opts, fs_options);
+ ++i;
+ }
+}
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 9d48b8c..5e11c84 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -50,6 +50,7 @@
std::cerr << " delete <dm-name>" << std::endl;
std::cerr << " list <devices | targets>" << std::endl;
std::cerr << " getpath <dm-name>" << std::endl;
+ std::cerr << " table <dm-name>" << std::endl;
std::cerr << " help" << std::endl;
std::cerr << std::endl;
std::cerr << "Target syntax:" << std::endl;
@@ -258,6 +259,31 @@
return 0;
}
+static int TableCmdHandler(int argc, char** argv) {
+ if (argc != 1) {
+ std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
+ return -EINVAL;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ std::vector<DeviceMapper::TargetInfo> table;
+ if (!dm.GetTableStatus(argv[0], &table)) {
+ std::cerr << "Could not query table status of device \"" << argv[0] << "\"." << std::endl;
+ return -EINVAL;
+ }
+ std::cout << "Targets in the device-mapper table for " << argv[0] << ":" << std::endl;
+ for (const auto& target : table) {
+ std::cout << target.spec.sector_start << "-"
+ << (target.spec.sector_start + target.spec.length) << ": "
+ << target.spec.target_type;
+ if (!target.data.empty()) {
+ std::cout << ", " << target.data;
+ }
+ std::cout << std::endl;
+ }
+ return 0;
+}
+
static std::map<std::string, std::function<int(int, char**)>> cmdmap = {
// clang-format off
{"create", DmCreateCmdHandler},
@@ -265,6 +291,7 @@
{"list", DmListCmdHandler},
{"help", HelpCmdHandler},
{"getpath", GetPathCmdHandler},
+ {"table", TableCmdHandler},
// clang-format on
};
diff --git a/gatekeeperd/OWNERS b/gatekeeperd/OWNERS
new file mode 100644
index 0000000..9c99c6e
--- /dev/null
+++ b/gatekeeperd/OWNERS
@@ -0,0 +1,2 @@
+swillden@google.com
+jdanis@google.com
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 61c8804..abb387c 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -234,11 +234,13 @@
virtual int verify(uint32_t uid,
const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
const uint8_t *provided_password, uint32_t provided_password_length, bool *request_reenroll) {
- uint8_t *auth_token;
+ uint8_t *auth_token = nullptr;
uint32_t auth_token_length;
- return verifyChallenge(uid, 0, enrolled_password_handle, enrolled_password_handle_length,
+ int ret = verifyChallenge(uid, 0, enrolled_password_handle, enrolled_password_handle_length,
provided_password, provided_password_length,
&auth_token, &auth_token_length, request_reenroll);
+ delete [] auth_token;
+ return ret;
}
virtual int verifyChallenge(uint32_t uid, uint64_t challenge,
diff --git a/healthd/Android.bp b/healthd/Android.bp
index 56f5148..7269b62 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -5,3 +5,16 @@
header_libs: ["libbatteryservice_headers"],
export_header_lib_headers: ["libbatteryservice_headers"],
}
+
+cc_library_static {
+ name: "libbatterymonitor",
+ srcs: ["BatteryMonitor.cpp"],
+ vendor_available: true,
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "libutils",
+ "libbase",
+ ],
+ header_libs: ["libhealthd_headers"],
+ export_header_lib_headers: ["libhealthd_headers"],
+}
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 6c8fecf..1244903 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -3,14 +3,6 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := BatteryMonitor.cpp
-LOCAL_MODULE := libbatterymonitor
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libutils libbase libbinder
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
healthd_mode_android.cpp \
BatteryPropertiesRegistrar.cpp
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 194e667..97435c7 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -18,7 +18,6 @@
#define HEALTHD_BATTERYMONITOR_H
#include <batteryservice/BatteryService.h>
-#include <binder/IInterface.h>
#include <utils/String8.h>
#include <utils/Vector.h>
diff --git a/init/Android.bp b/init/Android.bp
index cf7637f..c02b8d1 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -104,11 +104,10 @@
"devices.cpp",
"epoll.cpp",
"firmware_handler.cpp",
+ "first_stage_mount.cpp",
"import_parser.cpp",
"init.cpp",
- "init_first_stage.cpp",
"keychords.cpp",
- "log.cpp",
"parser.cpp",
"persistent_properties.cpp",
"persistent_properties.proto",
@@ -179,6 +178,8 @@
"rlimit_parser_test.cpp",
"service_test.cpp",
"subcontext_test.cpp",
+ "tokenizer_test.cpp",
+ "ueventd_parser_test.cpp",
"ueventd_test.cpp",
"util_test.cpp",
],
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
index 8a4b518..1481162 100644
--- a/init/action_parser.cpp
+++ b/init/action_parser.cpp
@@ -60,7 +60,7 @@
prop_name.erase(equal_pos);
if (!IsActionableProperty(subcontext, prop_name)) {
- return Error() << "unexported property tigger found: " << prop_name;
+ return Error() << "unexported property trigger found: " << prop_name;
}
if (auto [it, inserted] = property_triggers->emplace(prop_name, prop_value); !inserted) {
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/devices.h b/init/devices.h
index f9035da..0be660f 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -35,6 +35,8 @@
class Permissions {
public:
+ friend void TestPermissions(const Permissions& expected, const Permissions& test);
+
Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid);
bool Match(const std::string& path) const;
@@ -57,6 +59,8 @@
class SysfsPermissions : public Permissions {
public:
+ friend void TestSysfsPermissions(const SysfsPermissions& expected, const SysfsPermissions& test);
+
SysfsPermissions(const std::string& name, const std::string& attribute, mode_t perm, uid_t uid,
gid_t gid)
: Permissions(name, perm, uid, gid), attribute_(attribute) {}
@@ -71,16 +75,24 @@
class Subsystem {
public:
friend class SubsystemParser;
+ friend void TestSubsystems(const Subsystem& expected, const Subsystem& test);
+
+ enum DevnameSource {
+ DEVNAME_UEVENT_DEVNAME,
+ DEVNAME_UEVENT_DEVPATH,
+ };
Subsystem() {}
- Subsystem(std::string name) : name_(std::move(name)) {}
+ Subsystem(const std::string& name) : name_(name) {}
+ Subsystem(const std::string& name, DevnameSource source, const std::string& dir_name)
+ : name_(name), devname_source_(source), dir_name_(dir_name) {}
// Returns the full path for a uevent of a device that is a member of this subsystem,
// according to the rules parsed from ueventd.rc
std::string ParseDevPath(const Uevent& uevent) const {
- std::string devname = devname_source_ == DevnameSource::DEVNAME_UEVENT_DEVNAME
- ? uevent.device_name
- : android::base::Basename(uevent.path);
+ std::string devname = devname_source_ == DEVNAME_UEVENT_DEVNAME
+ ? uevent.device_name
+ : android::base::Basename(uevent.path);
return dir_name_ + "/" + devname;
}
@@ -88,14 +100,9 @@
bool operator==(const std::string& string_name) const { return name_ == string_name; }
private:
- enum class DevnameSource {
- DEVNAME_UEVENT_DEVNAME,
- DEVNAME_UEVENT_DEVPATH,
- };
-
std::string name_;
+ DevnameSource devname_source_ = DEVNAME_UEVENT_DEVNAME;
std::string dir_name_ = "/dev";
- DevnameSource devname_source_;
};
class DeviceHandler {
@@ -106,7 +113,6 @@
DeviceHandler(std::vector<Permissions> dev_permissions,
std::vector<SysfsPermissions> sysfs_permissions, std::vector<Subsystem> subsystems,
std::set<std::string> boot_devices, bool skip_restorecon);
- ~DeviceHandler(){};
void HandleDeviceEvent(const Uevent& uevent);
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index 8c8d9f2..28bda34 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -21,7 +21,6 @@
#include <sys/wait.h>
#include <unistd.h>
-#include <string>
#include <thread>
#include <android-base/chrono_utils.h>
@@ -36,6 +35,8 @@
namespace android {
namespace init {
+std::vector<std::string> firmware_directories;
+
static void LoadFirmware(const Uevent& uevent, const std::string& root, int fw_fd, size_t fw_size,
int loading_fd, int data_fd) {
// Start transfer.
@@ -78,12 +79,9 @@
return;
}
- static const char* firmware_dirs[] = {"/etc/firmware/", "/odm/firmware/",
- "/vendor/firmware/", "/firmware/image/"};
-
try_loading_again:
- for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
- std::string file = firmware_dirs[i] + uevent.firmware;
+ for (const auto& firmware_directory : firmware_directories) {
+ std::string file = firmware_directory + uevent.firmware;
unique_fd fw_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
struct stat sb;
if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
diff --git a/init/firmware_handler.h b/init/firmware_handler.h
index e456ac4..6081511 100644
--- a/init/firmware_handler.h
+++ b/init/firmware_handler.h
@@ -17,11 +17,16 @@
#ifndef _INIT_FIRMWARE_HANDLER_H
#define _INIT_FIRMWARE_HANDLER_H
+#include <string>
+#include <vector>
+
#include "uevent.h"
namespace android {
namespace init {
+extern std::vector<std::string> firmware_directories;
+
void HandleFirmwareEvent(const Uevent& uevent);
} // namespace init
diff --git a/init/init_first_stage.cpp b/init/first_stage_mount.cpp
similarity index 92%
rename from init/init_first_stage.cpp
rename to init/first_stage_mount.cpp
index 2bc9f3a..8ded873 100644
--- a/init/init_first_stage.cpp
+++ b/init/first_stage_mount.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "init_first_stage.h"
+#include "first_stage_mount.h"
#include <stdlib.h>
#include <unistd.h>
@@ -40,7 +40,6 @@
#include "util.h"
using android::base::Timer;
-using android::fs_mgr::LogicalPartitionTable;
namespace android {
namespace init {
@@ -75,7 +74,6 @@
bool need_dm_verity_;
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
- std::unique_ptr<LogicalPartitionTable> dm_linear_table_;
std::string lp_metadata_partition_;
std::vector<fstab_rec*> mount_fstab_recs_;
std::set<std::string> required_devices_partition_names_;
@@ -127,11 +125,12 @@
if (checked) {
return enabled;
}
- import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
- if (key == "androidboot.logical_partitions" && value == "1") {
- enabled = true;
- }
- });
+ import_kernel_cmdline(false,
+ [](const std::string& key, const std::string& value, bool in_qemu) {
+ if (key == "androidboot.logical_partitions" && value == "1") {
+ enabled = true;
+ }
+ });
checked = true;
return enabled;
}
@@ -150,14 +149,10 @@
LOG(INFO) << "Failed to read fstab from device tree";
}
- if (IsDmLinearEnabled()) {
- dm_linear_table_ = android::fs_mgr::LoadPartitionsFromDeviceTree();
- }
-
auto boot_devices = fs_mgr_get_boot_devices();
- device_handler_ =
- std::make_unique<DeviceHandler>(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
- std::vector<Subsystem>{}, std::move(boot_devices), false);
+ device_handler_ = std::make_unique<DeviceHandler>(
+ std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
+ std::move(boot_devices), false);
}
std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
@@ -195,15 +190,6 @@
}
required_devices_partition_names_.emplace(LP_METADATA_PARTITION_NAME);
-
- if (dm_linear_table_) {
- for (const auto& partition : dm_linear_table_->partitions) {
- for (const auto& extent : partition.extents) {
- const std::string& partition_name = android::base::Basename(extent.block_device());
- required_devices_partition_names_.emplace(partition_name);
- }
- }
- }
return true;
}
@@ -272,11 +258,6 @@
<< LP_METADATA_PARTITION_NAME;
return false;
}
- if (dm_linear_table_) {
- if (!android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get())) {
- return false;
- }
- }
return android::fs_mgr::CreateLogicalPartitions(lp_metadata_partition_);
}
@@ -456,12 +437,19 @@
bool FirstStageMountVBootV2::GetDmVerityDevices() {
need_dm_verity_ = false;
+ std::set<std::string> logical_partitions;
+
// fstab_rec->blk_device has A/B suffix.
for (auto fstab_rec : mount_fstab_recs_) {
if (fs_mgr_is_avb(fstab_rec)) {
need_dm_verity_ = true;
}
- required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+ if (fs_mgr_is_logical(fstab_rec)) {
+ // Don't try to find logical partitions via uevent regeneration.
+ logical_partitions.emplace(basename(fstab_rec->blk_device));
+ } else {
+ required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+ }
}
// libavb verifies AVB metadata on all verified partitions at once.
@@ -476,11 +464,15 @@
std::vector<std::string> partitions = android::base::Split(device_tree_vbmeta_parts_, ",");
std::string ab_suffix = fs_mgr_get_slot_suffix();
for (const auto& partition : partitions) {
+ std::string partition_name = partition + ab_suffix;
+ if (logical_partitions.count(partition_name)) {
+ continue;
+ }
// required_devices_partition_names_ is of type std::set so it's not an issue
// to emplace a partition twice. e.g., /vendor might be in both places:
// - device_tree_vbmeta_parts_ = "vbmeta,boot,system,vendor"
// - mount_fstab_recs_: /vendor_a
- required_devices_partition_names_.emplace(partition + ab_suffix);
+ required_devices_partition_names_.emplace(partition_name);
}
}
return true;
@@ -493,7 +485,7 @@
// as it finds them, so this must happen first.
if (!uevent.partition_name.empty() &&
required_devices_partition_names_.find(uevent.partition_name) !=
- required_devices_partition_names_.end()) {
+ required_devices_partition_names_.end()) {
// GetBlockDeviceSymlinks() will return three symlinks at most, depending on
// the content of uevent. by-name symlink will be at [0] if uevent->partition_name
// is not empty. e.g.,
@@ -501,7 +493,7 @@
// - /dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1
std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
if (!links.empty()) {
- auto[it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
+ auto [it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
if (!inserted) {
LOG(ERROR) << "Partition '" << uevent.partition_name
<< "' already existed in the by-name symlink map with a value of '"
@@ -517,7 +509,7 @@
if (fs_mgr_is_avb(fstab_rec)) {
if (!InitAvbHandle()) return false;
SetUpAvbHashtreeResult hashtree_result =
- avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
+ avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
switch (hashtree_result) {
case SetUpAvbHashtreeResult::kDisabled:
return true; // Returns true to mount the partition.
@@ -594,7 +586,7 @@
}
FsManagerAvbUniquePtr avb_handle =
- FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
+ FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
if (!avb_handle) {
PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
return;
diff --git a/init/init_first_stage.h b/init/first_stage_mount.h
similarity index 91%
rename from init/init_first_stage.h
rename to init/first_stage_mount.h
index c7a3867..21d87fd 100644
--- a/init/init_first_stage.h
+++ b/init/first_stage_mount.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _INIT_FIRST_STAGE_H
-#define _INIT_FIRST_STAGE_H
+#pragma once
namespace android {
namespace init {
@@ -25,5 +24,3 @@
} // namespace init
} // namespace android
-
-#endif
diff --git a/init/init.cpp b/init/init.cpp
index 77c4fc4..6569871 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -48,10 +48,9 @@
#include "action_parser.h"
#include "epoll.h"
+#include "first_stage_mount.h"
#include "import_parser.h"
-#include "init_first_stage.h"
#include "keychords.h"
-#include "log.h"
#include "property_service.h"
#include "reboot.h"
#include "security.h"
@@ -582,6 +581,34 @@
}
}
+static void InitAborter(const char* abort_message) {
+ // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
+ // simply abort instead of trying to reboot the system.
+ if (getpid() != 1) {
+ android::base::DefaultAborter(abort_message);
+ return;
+ }
+
+ RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+}
+
+static void InitKernelLogging(char* argv[]) {
+ // Make stdin/stdout/stderr all point to /dev/null.
+ int fd = open("/sys/fs/selinux/null", O_RDWR);
+ if (fd == -1) {
+ int saved_errno = errno;
+ android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
+ errno = saved_errno;
+ PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
+ }
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ if (fd > 2) close(fd);
+
+ android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
+}
+
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
@@ -592,7 +619,7 @@
}
if (argc > 1 && !strcmp(argv[1], "subcontext")) {
- InitKernelLogging(argv);
+ android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap function_map;
return SubcontextMain(argc, argv, &function_map);
}
@@ -647,6 +674,9 @@
// /mnt/vendor is used to mount vendor-specific partitions that can not be
// part of the vendor partition, e.g. because they are mounted read-write.
CHECKCALL(mkdir("/mnt/vendor", 0755));
+ // /mnt/product is used to mount product-specific partitions that can not be
+ // part of the product partition, e.g. because they are mounted read-write.
+ CHECKCALL(mkdir("/mnt/product", 0755));
#undef CHECKCALL
diff --git a/init/log.cpp b/init/log.cpp
deleted file mode 100644
index 6198fc2..0000000
--- a/init/log.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2015 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 "log.h"
-
-#include <fcntl.h>
-#include <linux/audit.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-#include <cutils/android_reboot.h>
-#include <selinux/selinux.h>
-
-#include "reboot.h"
-
-namespace android {
-namespace init {
-
-static void InitAborter(const char* abort_message) {
- // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to
- // simply abort instead of trying to reboot the system.
- if (getpid() != 1) {
- android::base::DefaultAborter(abort_message);
- return;
- }
-
- // DoReboot() does a lot to try to shutdown the system cleanly. If something happens to call
- // LOG(FATAL) in the shutdown path, we want to catch this and immediately use the syscall to
- // reboot instead of recursing here.
- static bool has_aborted = false;
- if (!has_aborted) {
- has_aborted = true;
- // Do not queue "shutdown" trigger since we want to shutdown immediately and it's not likely
- // that we can even run the ActionQueue at this point.
- DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
- } else {
- RebootSystem(ANDROID_RB_RESTART2, "bootloader");
- }
-}
-
-void InitKernelLogging(char* argv[]) {
- // Make stdin/stdout/stderr all point to /dev/null.
- int fd = open("/sys/fs/selinux/null", O_RDWR);
- if (fd == -1) {
- int saved_errno = errno;
- android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
- errno = saved_errno;
- PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
- }
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- if (fd > 2) close(fd);
-
- android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);
-}
-
-int selinux_klog_callback(int type, const char *fmt, ...) {
- android::base::LogSeverity severity = android::base::ERROR;
- if (type == SELINUX_WARNING) {
- severity = android::base::WARNING;
- } else if (type == SELINUX_INFO) {
- severity = android::base::INFO;
- }
- char buf[1024];
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
- android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
- return 0;
-}
-
-} // namespace init
-} // namespace android
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 0ba5c4a..94f206e 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -59,7 +59,6 @@
#include <android-base/unique_fd.h>
#include <selinux/android.h>
-#include "log.h"
#include "util.h"
using android::base::ParseInt;
@@ -448,10 +447,26 @@
selinux_android_restorecon("/sbin/sload.f2fs", 0);
}
+int SelinuxKlogCallback(int type, const char* fmt, ...) {
+ android::base::LogSeverity severity = android::base::ERROR;
+ if (type == SELINUX_WARNING) {
+ severity = android::base::WARNING;
+ } else if (type == SELINUX_INFO) {
+ severity = android::base::INFO;
+ }
+ char buf[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
+ return 0;
+}
+
// This function sets up SELinux logging to be written to kmsg, to match init's logging.
void SelinuxSetupKernelLogging() {
selinux_callback cb;
- cb.func_log = selinux_klog_callback;
+ cb.func_log = SelinuxKlogCallback;
selinux_set_callback(SELINUX_CB_LOG, cb);
}
diff --git a/init/service.cpp b/init/service.cpp
index 95b37ab..4c2747e 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -130,7 +130,7 @@
if (umount2("/sys", MNT_DETACH) == -1) {
return ErrnoError() << "Could not umount(/sys)";
}
- if (mount("", "/sys", "sys", kSafeFlags, "") == -1) {
+ if (mount("", "/sys", "sysfs", kSafeFlags, "") == -1) {
return ErrnoError() << "Could not mount(/sys)";
}
}
diff --git a/init/tokenizer.cpp b/init/tokenizer.cpp
index f8d9b6b..bb143f1 100644
--- a/init/tokenizer.cpp
+++ b/init/tokenizer.cpp
@@ -85,15 +85,19 @@
goto textdone;
case 'n':
*s++ = '\n';
+ x++;
break;
case 'r':
*s++ = '\r';
+ x++;
break;
case 't':
*s++ = '\t';
+ x++;
break;
case '\\':
*s++ = '\\';
+ x++;
break;
case '\r':
/* \ <cr> <lf> -> line continuation */
@@ -101,6 +105,7 @@
x++;
continue;
}
+ x++;
case '\n':
/* \ <lf> -> line continuation */
state->line++;
diff --git a/init/tokenizer_test.cpp b/init/tokenizer_test.cpp
new file mode 100644
index 0000000..acfc7c7
--- /dev/null
+++ b/init/tokenizer_test.cpp
@@ -0,0 +1,163 @@
+//
+// 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 "tokenizer.h"
+
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace init {
+
+namespace {
+
+void RunTest(const std::string& data, const std::vector<std::vector<std::string>>& expected_tokens) {
+ auto data_copy = std::string{data};
+ data_copy.push_back('\n'); // TODO: fix tokenizer
+ data_copy.push_back('\0');
+
+ parse_state state;
+ state.line = 0;
+ state.ptr = data_copy.data();
+ state.nexttoken = 0;
+
+ std::vector<std::string> current_line;
+ std::vector<std::vector<std::string>> tokens;
+
+ while (true) {
+ switch (next_token(&state)) {
+ case T_EOF:
+ EXPECT_EQ(expected_tokens, tokens) << data;
+ return;
+ case T_NEWLINE:
+ tokens.emplace_back(std::move(current_line));
+ break;
+ case T_TEXT:
+ current_line.emplace_back(state.text);
+ break;
+ }
+ }
+}
+
+} // namespace
+
+TEST(tokenizer, null) {
+ RunTest("", {{}});
+}
+
+TEST(tokenizer, simple_oneline) {
+ RunTest("one two\tthree\rfour", {{"one", "two", "three", "four"}});
+}
+
+TEST(tokenizer, simple_multiline) {
+ RunTest("1 2 3\n4 5 6\n7 8 9", {{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}});
+}
+
+TEST(tokenizer, preceding_space) {
+ // Preceding spaces are ignored.
+ RunTest(" 1 2 3\n\t\t\t\t4 5 6\n\r\r\r\r7 8 9",
+ {{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}});
+}
+
+TEST(tokenizer, comments) {
+ // Entirely commented lines still produce a T_NEWLINE token for tracking line count.
+ RunTest("1 2 3\n#4 5 6\n7 8 9", {{"1", "2", "3"}, {}, {"7", "8", "9"}});
+
+ RunTest("#1 2 3\n4 5 6\n7 8 9", {{}, {"4", "5", "6"}, {"7", "8", "9"}});
+
+ RunTest("1 2 3\n4 5 6\n#7 8 9", {{"1", "2", "3"}, {"4", "5", "6"}, {}});
+
+ RunTest("1 2 #3\n4 #5 6\n#7 8 9", {{"1", "2"}, {"4"}, {}});
+}
+
+TEST(tokenizer, control_chars) {
+ // Literal \n, \r, \t, and \\ produce the control characters \n, \r, \t, and \\ respectively.
+ // Literal \? produces ? for all other character '?'
+
+ RunTest(R"(1 token\ntoken 2)", {{"1", "token\ntoken", "2"}});
+ RunTest(R"(1 token\rtoken 2)", {{"1", "token\rtoken", "2"}});
+ RunTest(R"(1 token\ttoken 2)", {{"1", "token\ttoken", "2"}});
+ RunTest(R"(1 token\\token 2)", {{"1", "token\\token", "2"}});
+ RunTest(R"(1 token\btoken 2)", {{"1", "tokenbtoken", "2"}});
+
+ RunTest(R"(1 token\n 2)", {{"1", "token\n", "2"}});
+ RunTest(R"(1 token\r 2)", {{"1", "token\r", "2"}});
+ RunTest(R"(1 token\t 2)", {{"1", "token\t", "2"}});
+ RunTest(R"(1 token\\ 2)", {{"1", "token\\", "2"}});
+ RunTest(R"(1 token\b 2)", {{"1", "tokenb", "2"}});
+
+ RunTest(R"(1 \ntoken 2)", {{"1", "\ntoken", "2"}});
+ RunTest(R"(1 \rtoken 2)", {{"1", "\rtoken", "2"}});
+ RunTest(R"(1 \ttoken 2)", {{"1", "\ttoken", "2"}});
+ RunTest(R"(1 \\token 2)", {{"1", "\\token", "2"}});
+ RunTest(R"(1 \btoken 2)", {{"1", "btoken", "2"}});
+
+ RunTest(R"(1 \n 2)", {{"1", "\n", "2"}});
+ RunTest(R"(1 \r 2)", {{"1", "\r", "2"}});
+ RunTest(R"(1 \t 2)", {{"1", "\t", "2"}});
+ RunTest(R"(1 \\ 2)", {{"1", "\\", "2"}});
+ RunTest(R"(1 \b 2)", {{"1", "b", "2"}});
+}
+
+TEST(tokenizer, cr_lf) {
+ // \ before \n, \r, or \r\n is interpreted as a line continuation
+ // Extra whitespace on the next line is eaten, except \r unlike in the above tests.
+
+ RunTest("lf\\\ncont", {{"lfcont"}});
+ RunTest("lf\\\n \t\t\t\tcont", {{"lfcont"}});
+
+ RunTest("crlf\\\r\ncont", {{"crlfcont"}});
+ RunTest("crlf\\\r\n \t\t\t\tcont", {{"crlfcont"}});
+
+ RunTest("cr\\\rcont", {{"crcont"}});
+
+ RunTest("lfspace \\\ncont", {{"lfspace", "cont"}});
+ RunTest("lfspace \\\n \t\t\t\tcont", {{"lfspace", "cont"}});
+
+ RunTest("crlfspace \\\r\ncont", {{"crlfspace", "cont"}});
+ RunTest("crlfspace \\\r\n \t\t\t\tcont", {{"crlfspace", "cont"}});
+
+ RunTest("crspace \\\rcont", {{"crspace", "cont"}});
+}
+
+TEST(tokenizer, quoted) {
+ RunTest("\"quoted simple string\"", {{"quoted simple string"}});
+
+ // Unterminated quotes just return T_EOF without any T_NEWLINE.
+ RunTest("\"unterminated quoted string", {});
+
+ RunTest("\"1 2 3\"\n \"unterminated quoted string", {{"1 2 3"}});
+
+ // Escaping quotes is not allowed and are treated as an unterminated quoted string.
+ RunTest("\"quoted escaped quote\\\"\"", {});
+ RunTest("\"quoted escaped\\\" quote\"", {});
+ RunTest("\"\\\"quoted escaped quote\"", {});
+
+ RunTest("\"quoted control characters \\n \\r \\t \\\\ \\b \\\r \\\n \r \n\"",
+ {{"quoted control characters \\n \\r \\t \\\\ \\b \\\r \\\n \r \n"}});
+
+ RunTest("\"quoted simple string\" \"second quoted string\"",
+ {{"quoted simple string", "second quoted string"}});
+
+ RunTest("\"# comment quoted string\"", {{"# comment quoted string"}});
+
+ RunTest("\"Adjacent \"\"quoted strings\"", {{"Adjacent quoted strings"}});
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index a284203..cd45a3f 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -36,7 +36,6 @@
#include "devices.h"
#include "firmware_handler.h"
-#include "log.h"
#include "selinux.h"
#include "uevent_listener.h"
#include "ueventd_parser.h"
@@ -215,39 +214,6 @@
LOG(INFO) << "Coldboot took " << cold_boot_timer.duration().count() / 1000.0f << " seconds";
}
-DeviceHandler CreateDeviceHandler() {
- Parser parser;
-
- std::vector<Subsystem> subsystems;
- parser.AddSectionParser("subsystem", std::make_unique<SubsystemParser>(&subsystems));
-
- using namespace std::placeholders;
- std::vector<SysfsPermissions> sysfs_permissions;
- std::vector<Permissions> dev_permissions;
- parser.AddSingleLineParser("/sys/",
- std::bind(ParsePermissionsLine, _1, &sysfs_permissions, nullptr));
- parser.AddSingleLineParser("/dev/",
- std::bind(ParsePermissionsLine, _1, nullptr, &dev_permissions));
-
- parser.ParseConfig("/ueventd.rc");
- parser.ParseConfig("/vendor/ueventd.rc");
- parser.ParseConfig("/odm/ueventd.rc");
-
- /*
- * keep the current product name base configuration so
- * we remain backwards compatible and allow it to override
- * everything
- * TODO: cleanup platform ueventd.rc to remove vendor specific
- * device node entries (b/34968103)
- */
- std::string hardware = android::base::GetProperty("ro.hardware", "");
- parser.ParseConfig("/ueventd." + hardware + ".rc");
-
- auto boot_devices = fs_mgr_get_boot_devices();
- return DeviceHandler(std::move(dev_permissions), std::move(sysfs_permissions),
- std::move(subsystems), std::move(boot_devices), true);
-}
-
int ueventd_main(int argc, char** argv) {
/*
* init sets the umask to 077 for forked processes. We need to
@@ -256,16 +222,34 @@
*/
umask(000);
- InitKernelLogging(argv);
+ android::base::InitLogging(argv, &android::base::KernelLogger);
LOG(INFO) << "ueventd started!";
SelinuxSetupKernelLogging();
SelabelInitialize();
- DeviceHandler device_handler = CreateDeviceHandler();
+ DeviceHandler device_handler;
UeventListener uevent_listener;
+ {
+ // Keep the current product name base configuration so we remain backwards compatible and
+ // allow it to override everything.
+ // TODO: cleanup platform ueventd.rc to remove vendor specific device node entries (b/34968103)
+ auto hardware = android::base::GetProperty("ro.hardware", "");
+
+ auto ueventd_configuration =
+ ParseConfig({"/ueventd.rc", "/vendor/ueventd.rc", "/odm/ueventd.rc",
+ "/ueventd." + hardware + ".rc"});
+
+ device_handler = DeviceHandler{std::move(ueventd_configuration.dev_permissions),
+ std::move(ueventd_configuration.sysfs_permissions),
+ std::move(ueventd_configuration.subsystems),
+ fs_mgr_get_boot_devices(), true};
+
+ firmware_directories = ueventd_configuration.firmware_directories;
+ }
+
if (access(COLDBOOT_DONE, F_OK) != 0) {
ColdBoot cold_boot(uevent_listener, device_handler);
cold_boot.Run();
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index f74c878..54b0d16 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -20,6 +20,7 @@
#include <pwd.h>
#include "keyword_map.h"
+#include "parser.h"
namespace android {
namespace init {
@@ -72,6 +73,33 @@
return Success();
}
+Result<Success> ParseFirmwareDirectoriesLine(std::vector<std::string>&& args,
+ std::vector<std::string>* firmware_directories) {
+ if (args.size() < 2) {
+ return Error() << "firmware_directories must have at least 1 entry";
+ }
+
+ std::move(std::next(args.begin()), args.end(), std::back_inserter(*firmware_directories));
+
+ return Success();
+}
+
+class SubsystemParser : public SectionParser {
+ public:
+ SubsystemParser(std::vector<Subsystem>* subsystems) : subsystems_(subsystems) {}
+ Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
+ int line) override;
+ Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
+ Result<Success> EndSection() override;
+
+ private:
+ Result<Success> ParseDevName(std::vector<std::string>&& args);
+ Result<Success> ParseDirName(std::vector<std::string>&& args);
+
+ Subsystem subsystem_;
+ std::vector<Subsystem>* subsystems_;
+};
+
Result<Success> SubsystemParser::ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) {
if (args.size() != 2) {
@@ -89,11 +117,11 @@
Result<Success> SubsystemParser::ParseDevName(std::vector<std::string>&& args) {
if (args[1] == "uevent_devname") {
- subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVNAME;
+ subsystem_.devname_source_ = Subsystem::DEVNAME_UEVENT_DEVNAME;
return Success();
}
if (args[1] == "uevent_devpath") {
- subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVPATH;
+ subsystem_.devname_source_ = Subsystem::DEVNAME_UEVENT_DEVPATH;
return Success();
}
@@ -138,5 +166,29 @@
return Success();
}
+UeventdConfiguration ParseConfig(const std::vector<std::string>& configs) {
+ Parser parser;
+ UeventdConfiguration ueventd_configuration;
+
+ parser.AddSectionParser("subsystem",
+ std::make_unique<SubsystemParser>(&ueventd_configuration.subsystems));
+
+ using namespace std::placeholders;
+ parser.AddSingleLineParser(
+ "/sys/",
+ std::bind(ParsePermissionsLine, _1, &ueventd_configuration.sysfs_permissions, nullptr));
+ parser.AddSingleLineParser("/dev/", std::bind(ParsePermissionsLine, _1, nullptr,
+ &ueventd_configuration.dev_permissions));
+ parser.AddSingleLineParser("firmware_directories",
+ std::bind(ParseFirmwareDirectoriesLine, _1,
+ &ueventd_configuration.firmware_directories));
+
+ for (const auto& config : configs) {
+ parser.ParseConfig(config);
+ }
+
+ return ueventd_configuration;
+}
+
} // namespace init
} // namespace android
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 83684f3..343d58b 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -21,30 +21,18 @@
#include <vector>
#include "devices.h"
-#include "parser.h"
namespace android {
namespace init {
-class SubsystemParser : public SectionParser {
- public:
- SubsystemParser(std::vector<Subsystem>* subsystems) : subsystems_(subsystems) {}
- Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
- int line) override;
- Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
- Result<Success> EndSection() override;
-
- private:
- Result<Success> ParseDevName(std::vector<std::string>&& args);
- Result<Success> ParseDirName(std::vector<std::string>&& args);
-
- Subsystem subsystem_;
- std::vector<Subsystem>* subsystems_;
+struct UeventdConfiguration {
+ std::vector<Subsystem> subsystems;
+ std::vector<SysfsPermissions> sysfs_permissions;
+ std::vector<Permissions> dev_permissions;
+ std::vector<std::string> firmware_directories;
};
-Result<Success> ParsePermissionsLine(std::vector<std::string>&& args,
- std::vector<SysfsPermissions>* out_sysfs_permissions,
- std::vector<Permissions>* out_dev_permissions);
+UeventdConfiguration ParseConfig(const std::vector<std::string>& configs);
} // namespace init
} // namespace android
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
new file mode 100644
index 0000000..31208b9
--- /dev/null
+++ b/init/ueventd_parser_test.cpp
@@ -0,0 +1,224 @@
+/*
+ * 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 "ueventd_parser.h"
+
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+namespace init {
+
+void TestSubsystems(const Subsystem& expected, const Subsystem& test) {
+ EXPECT_EQ(expected.name_, test.name_);
+ EXPECT_EQ(expected.devname_source_, test.devname_source_) << expected.name_;
+ EXPECT_EQ(expected.dir_name_, test.dir_name_) << expected.name_;
+}
+
+void TestPermissions(const Permissions& expected, const Permissions& test) {
+ EXPECT_EQ(expected.name_, test.name_);
+ EXPECT_EQ(expected.perm_, test.perm_) << expected.name_;
+ EXPECT_EQ(expected.uid_, test.uid_) << expected.name_;
+ EXPECT_EQ(expected.gid_, test.gid_) << expected.name_;
+ EXPECT_EQ(expected.prefix_, test.prefix_) << expected.name_;
+ EXPECT_EQ(expected.wildcard_, test.wildcard_) << expected.name_;
+}
+
+void TestSysfsPermissions(const SysfsPermissions& expected, const SysfsPermissions& test) {
+ TestPermissions(expected, test);
+ EXPECT_EQ(expected.attribute_, test.attribute_);
+}
+
+template <typename T, typename F>
+void TestVector(const T& expected, const T& test, F function) {
+ ASSERT_EQ(expected.size(), test.size());
+ auto expected_it = expected.begin();
+ auto test_it = test.begin();
+
+ for (; expected_it != expected.end(); ++expected_it, ++test_it) {
+ function(*expected_it, *test_it);
+ }
+}
+
+void TestUeventdFile(const std::string& content, const UeventdConfiguration& expected) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ ASSERT_TRUE(android::base::WriteStringToFd(content, tf.fd));
+
+ auto result = ParseConfig({tf.path});
+
+ TestVector(expected.subsystems, result.subsystems, TestSubsystems);
+ TestVector(expected.sysfs_permissions, result.sysfs_permissions, TestSysfsPermissions);
+ TestVector(expected.dev_permissions, result.dev_permissions, TestPermissions);
+ EXPECT_EQ(expected.firmware_directories, result.firmware_directories);
+}
+
+TEST(ueventd_parser, EmptyFile) {
+ TestUeventdFile("", {});
+}
+
+TEST(ueventd_parser, Subsystems) {
+ auto ueventd_file = R"(
+subsystem test_devname
+ devname uevent_devname
+
+subsystem test_devpath_no_dirname
+ devname uevent_devpath
+
+subsystem test_devname2
+ devname uevent_devname
+
+subsystem test_devpath_dirname
+ devname uevent_devpath
+ dirname /dev/graphics
+)";
+
+ auto subsystems = std::vector<Subsystem>{
+ {"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
+ {"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"},
+ {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
+ {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}};
+
+ TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}});
+}
+
+TEST(ueventd_parser, Permissions) {
+ auto ueventd_file = R"(
+/dev/rtc0 0640 system system
+/dev/graphics/* 0660 root graphics
+/dev/*/test 0660 root system
+
+/sys/devices/platform/trusty.* trusty_version 0440 root log
+/sys/devices/virtual/input/input enable 0660 root input
+/sys/devices/virtual/*/input poll_delay 0660 root input
+)";
+
+ auto permissions = std::vector<Permissions>{
+ {"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM},
+ {"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS},
+ {"/dev/*/test", 0660, AID_ROOT, AID_SYSTEM},
+ };
+
+ auto sysfs_permissions = std::vector<SysfsPermissions>{
+ {"/sys/devices/platform/trusty.*", "trusty_version", 0440, AID_ROOT, AID_LOG},
+ {"/sys/devices/virtual/input/input", "enable", 0660, AID_ROOT, AID_INPUT},
+ {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT},
+ };
+
+ TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}});
+}
+
+TEST(ueventd_parser, FirmwareDirectories) {
+ auto ueventd_file = R"(
+firmware_directories /first/ /second /third
+firmware_directories /more
+)";
+
+ auto firmware_directories = std::vector<std::string>{
+ "/first/",
+ "/second",
+ "/third",
+ "/more",
+ };
+
+ TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories});
+}
+
+TEST(ueventd_parser, AllTogether) {
+ auto ueventd_file = R"(
+
+/dev/rtc0 0640 system system
+firmware_directories /first/ /second /third
+/sys/devices/platform/trusty.* trusty_version 0440 root log
+
+subsystem test_devname
+ devname uevent_devname
+
+/dev/graphics/* 0660 root graphics
+
+subsystem test_devpath_no_dirname
+ devname uevent_devpath
+
+/sys/devices/virtual/input/input enable 0660 root input
+
+## this is a comment
+
+subsystem test_devname2
+## another comment
+ devname uevent_devname
+
+subsystem test_devpath_dirname
+ devname uevent_devpath
+ dirname /dev/graphics
+
+/dev/*/test 0660 root system
+/sys/devices/virtual/*/input poll_delay 0660 root input
+firmware_directories /more
+
+#ending comment
+)";
+
+ auto subsystems = std::vector<Subsystem>{
+ {"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
+ {"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"},
+ {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
+ {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}};
+
+ auto permissions = std::vector<Permissions>{
+ {"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM},
+ {"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS},
+ {"/dev/*/test", 0660, AID_ROOT, AID_SYSTEM},
+ };
+
+ auto sysfs_permissions = std::vector<SysfsPermissions>{
+ {"/sys/devices/platform/trusty.*", "trusty_version", 0440, AID_ROOT, AID_LOG},
+ {"/sys/devices/virtual/input/input", "enable", 0660, AID_ROOT, AID_INPUT},
+ {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT},
+ };
+
+ auto firmware_directories = std::vector<std::string>{
+ "/first/",
+ "/second",
+ "/third",
+ "/more",
+ };
+
+ TestUeventdFile(ueventd_file,
+ {subsystems, sysfs_permissions, permissions, firmware_directories});
+}
+
+// All of these lines are ill-formed, so test that there is 0 output.
+TEST(ueventd_parser, ParseErrors) {
+ auto ueventd_file = R"(
+
+/dev/rtc0 badmode baduidbad system
+/dev/rtc0 0640 baduidbad system
+/dev/rtc0 0640 system baduidbad
+firmware_directories #no directory listed
+/sys/devices/platform/trusty.* trusty_version badmode root log
+/sys/devices/platform/trusty.* trusty_version 0440 baduidbad log
+/sys/devices/platform/trusty.* trusty_version 0440 root baduidbad
+
+subsystem #no name
+
+)";
+
+ TestUeventdFile(ueventd_file, {});
+}
+
+} // namespace init
+} // namespace android
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
diff --git a/init/watchdogd.cpp b/init/watchdogd.cpp
index e0164b4..e03a2c3 100644
--- a/init/watchdogd.cpp
+++ b/init/watchdogd.cpp
@@ -23,8 +23,6 @@
#include <android-base/logging.h>
-#include "log.h"
-
#ifdef _INIT_INIT_H
#error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
#endif
@@ -35,7 +33,7 @@
namespace init {
int watchdogd_main(int argc, char **argv) {
- InitKernelLogging(argv);
+ android::base::InitLogging(argv, &android::base::KernelLogger);
int interval = 10;
if (argc >= 2) interval = atoi(argv[1]);
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index b4bf35f..a10e636 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -42,7 +42,6 @@
"Backtrace.cpp",
"BacktraceCurrent.cpp",
"BacktracePtrace.cpp",
- "thread_utils.c",
"ThreadEntry.cpp",
"UnwindStack.cpp",
"UnwindStackMap.cpp",
@@ -94,7 +93,6 @@
],
static_libs: [
- "libcutils",
"libprocinfo",
],
@@ -145,7 +143,6 @@
"backtrace_offline_test.cpp",
"backtrace_test.cpp",
"GetPss.cpp",
- "thread_utils.c",
],
cflags: [
@@ -159,7 +156,6 @@
"libbacktrace",
"libdexfile",
"libbase",
- "libcutils",
"liblog",
"libunwindstack",
],
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 6445a7c..6bec63c 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -23,6 +23,7 @@
#include <string>
#include <android-base/stringprintf.h>
+#include <android-base/threads.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
@@ -31,7 +32,6 @@
#include "BacktraceLog.h"
#include "UnwindStack.h"
-#include "thread_utils.h"
using android::base::StringPrintf;
@@ -124,7 +124,7 @@
if (pid == BACKTRACE_CURRENT_PROCESS) {
pid = getpid();
if (tid == BACKTRACE_CURRENT_THREAD) {
- tid = gettid();
+ tid = android::base::GetThreadId();
}
} else if (tid == BACKTRACE_CURRENT_THREAD) {
tid = pid;
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index f6f4423..39cb995 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -28,13 +28,13 @@
#include <string>
+#include <android-base/threads.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include "BacktraceAsyncSafeLog.h"
#include "BacktraceCurrent.h"
#include "ThreadEntry.h"
-#include "thread_utils.h"
bool BacktraceCurrent::ReadWord(uint64_t ptr, word_t* out_value) {
if (!VerifyReadWordArgs(ptr, out_value)) {
@@ -76,7 +76,7 @@
return UnwindFromContext(num_ignore_frames, ucontext);
}
- if (Tid() != gettid()) {
+ if (Tid() != android::base::GetThreadId()) {
return UnwindThread(num_ignore_frames);
}
@@ -114,16 +114,17 @@
static void SignalLogOnly(int, siginfo_t*, void*) {
ErrnoRestorer restore;
- BACK_ASYNC_SAFE_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(), gettid(),
- THREAD_SIGNAL);
+ BACK_ASYNC_SAFE_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(),
+ static_cast<int>(android::base::GetThreadId()), THREAD_SIGNAL);
}
static void SignalHandler(int, siginfo_t*, void* sigcontext) {
ErrnoRestorer restore;
- ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
+ ThreadEntry* entry = ThreadEntry::Get(getpid(), android::base::GetThreadId(), false);
if (!entry) {
- BACK_ASYNC_SAFE_LOGE("pid %d, tid %d entry not found", getpid(), gettid());
+ BACK_ASYNC_SAFE_LOGE("pid %d, tid %d entry not found", getpid(),
+ static_cast<int>(android::base::GetThreadId()));
return;
}
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 399721d..6a967f7 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -32,8 +32,6 @@
#include <procinfo/process_map.h>
#endif
-#include "thread_utils.h"
-
using android::base::StringPrintf;
std::string backtrace_map_t::Name() const {
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index bf6b16f..9da457d 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -28,7 +28,6 @@
#include "BacktraceLog.h"
#include "BacktracePtrace.h"
-#include "thread_utils.h"
#if !defined(__APPLE__)
static bool PtraceRead(pid_t tid, uint64_t addr, word_t* out_value) {
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index e087b2e..4e7f761 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -23,10 +23,6 @@
#include <set>
#include <string>
-#if !defined(__ANDROID__)
-#include <cutils/threads.h>
-#endif
-
#include <backtrace/Backtrace.h>
#include <demangle.h>
#include <unwindstack/Elf.h>
diff --git a/libbacktrace/backtrace_benchmarks.cpp b/libbacktrace/backtrace_benchmarks.cpp
index a23e3b4..099ac60 100644
--- a/libbacktrace/backtrace_benchmarks.cpp
+++ b/libbacktrace/backtrace_benchmarks.cpp
@@ -27,6 +27,7 @@
#include <string>
#include <android-base/file.h>
+#include <android-base/threads.h>
#include <benchmark/benchmark.h>
@@ -154,7 +155,7 @@
static void CreateBacktrace(benchmark::State& state, BacktraceMap* map, BacktraceCreateFn fn) {
while (state.KeepRunning()) {
- std::unique_ptr<Backtrace> backtrace(fn(getpid(), gettid(), map));
+ std::unique_ptr<Backtrace> backtrace(fn(getpid(), android::base::GetThreadId(), map));
backtrace->Unwind(0);
}
}
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 9877f29..7d1027e 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -31,9 +31,9 @@
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/threads.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
-#include <cutils/threads.h>
#include <gtest/gtest.h>
@@ -99,7 +99,7 @@
static void* OfflineThreadFunc(void* arg) {
OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
- fn_arg->tid = gettid();
+ fn_arg->tid = android::base::GetThreadId();
test_get_context_and_wait(&fn_arg->ucontext, &fn_arg->exit_flag);
return nullptr;
}
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index f78a31f..06a32c7 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -47,16 +47,15 @@
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
+#include <android-base/threads.h>
#include <android-base/unique_fd.h>
#include <cutils/atomic.h>
-#include <cutils/threads.h>
#include <gtest/gtest.h>
// For the THREAD_SIGNAL definition.
#include "BacktraceCurrent.h"
#include "backtrace_testlib.h"
-#include "thread_utils.h"
// Number of microseconds per milliseconds.
#define US_PER_MSEC 1000
@@ -525,7 +524,7 @@
}
void VerifyLevelThread(void*) {
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), android::base::GetThreadId()));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
VERIFY_NO_ERROR(backtrace->GetError().error_code);
@@ -538,7 +537,7 @@
}
static void VerifyMaxThread(void*) {
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), android::base::GetThreadId()));
ASSERT_TRUE(backtrace.get() != nullptr);
ASSERT_TRUE(backtrace->Unwind(0));
ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
@@ -553,7 +552,7 @@
static void* ThreadLevelRun(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data);
- thread->tid = gettid();
+ thread->tid = android::base::GetThreadId();
EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
return nullptr;
}
@@ -644,7 +643,7 @@
static void* ThreadMaxRun(void* data) {
thread_t* thread = reinterpret_cast<thread_t*>(data);
- thread->tid = gettid();
+ thread->tid = android::base::GetThreadId();
EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
return nullptr;
}
@@ -994,7 +993,7 @@
static void* ThreadReadTest(void* data) {
thread_t* thread_data = reinterpret_cast<thread_t*>(data);
- thread_data->tid = gettid();
+ thread_data->tid = android::base::GetThreadId();
// Create two map pages.
// Mark the second page as not-readable.
@@ -1816,7 +1815,8 @@
static void TestFrameSkipNumbering(create_func_t create_func, map_create_func_t map_create_func) {
std::unique_ptr<BacktraceMap> map(map_create_func(getpid(), false));
- std::unique_ptr<Backtrace> backtrace(create_func(getpid(), gettid(), map.get()));
+ std::unique_ptr<Backtrace> backtrace(
+ create_func(getpid(), android::base::GetThreadId(), map.get()));
backtrace->Unwind(1);
ASSERT_NE(0U, backtrace->NumFrames());
ASSERT_EQ(0U, backtrace->GetFrame(0)->num);
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 735a2f3..10e790b 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -122,7 +122,7 @@
// Tracing a thread in a different process is not supported.
// If map is NULL, then create the map and manage it internally.
// If map is not NULL, the map is still owned by the caller.
- static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
+ static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = nullptr);
// Create an offline Backtrace object that can be used to do an unwind without a process
// that is still running. By default, information is only cached in the map
@@ -145,7 +145,7 @@
virtual ~Backtrace();
// Get the current stack trace and store in the backtrace_ structure.
- virtual bool Unwind(size_t num_ignore_frames, void* context = NULL) = 0;
+ virtual bool Unwind(size_t num_ignore_frames, void* context = nullptr) = 0;
static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
@@ -160,7 +160,7 @@
// If the string is empty, then no valid function name was found,
// or the pc is not in any valid map.
virtual std::string GetFunctionName(uint64_t pc, uint64_t* offset,
- const backtrace_map_t* map = NULL);
+ const backtrace_map_t* map = nullptr);
// Fill in the map data associated with the given pc.
virtual void FillInMap(uint64_t pc, backtrace_map_t* map);
@@ -185,7 +185,7 @@
const backtrace_frame_data_t* GetFrame(size_t frame_num) {
if (frame_num >= frames_.size()) {
- return NULL;
+ return nullptr;
}
return &frames_[frame_num];
}
diff --git a/libbacktrace/thread_utils.c b/libbacktrace/thread_utils.c
deleted file mode 100644
index e75f56e..0000000
--- a/libbacktrace/thread_utils.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2013 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 "thread_utils.h"
-
-#if !defined(__BIONIC__)
-
-// glibc doesn't implement or export tgkill.
-#include <unistd.h>
-#include <sys/syscall.h>
-
-int tgkill(int tgid, int tid, int sig) {
- return syscall(__NR_tgkill, tgid, tid, sig);
-}
-
-#endif
diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h
deleted file mode 100644
index 9590657..0000000
--- a/libbacktrace/thread_utils.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2013 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 _LIBBACKTRACE_THREAD_UTILS_H
-#define _LIBBACKTRACE_THREAD_UTILS_H
-
-#include <unistd.h>
-
-#if !defined(__ANDROID__)
-#include <cutils/threads.h>
-#endif
-
-__BEGIN_DECLS
-
-int tgkill(int tgid, int tid, int sig);
-
-__END_DECLS
-
-#endif /* _LIBBACKTRACE_THREAD_UTILS_H */
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index cdbb65f..37afb98 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -20,6 +20,7 @@
libcutils_nonwindows_sources = [
"android_get_control_file.cpp",
"fs.cpp",
+ "hashmap.cpp",
"multiuser.cpp",
"socket_inaddr_any_server_unix.cpp",
"socket_local_client_unix.cpp",
@@ -61,11 +62,9 @@
"config_utils.cpp",
"fs_config.cpp",
"canned_fs_config.cpp",
- "hashmap.cpp",
"iosched_policy.cpp",
"load_file.cpp",
"native_handle.cpp",
- "open_memstream.c",
"record_stream.cpp",
"sched_policy.cpp",
"sockets.cpp",
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index 15ace0e..0cc4fc0 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -90,7 +90,7 @@
dev_t rdev;
struct stat st;
- if (TEMP_FAILURE_RETRY(fstat(fd, &st)) < 0) {
+ if (fstat(fd, &st) < 0) {
return -1;
}
@@ -135,6 +135,12 @@
return -1;
}
+static int __ashmem_check_failure(int fd, int result)
+{
+ if (result == -1 && errno == ENOTTY) __ashmem_is_ashmem(fd, 1);
+ return result;
+}
+
int ashmem_valid(int fd)
{
return __ashmem_is_ashmem(fd, 0) >= 0;
@@ -182,12 +188,7 @@
int ashmem_set_prot_region(int fd, int prot)
{
- int ret = __ashmem_is_ashmem(fd, 1);
- if (ret < 0) {
- return ret;
- }
-
- return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot));
+ return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot)));
}
int ashmem_pin_region(int fd, size_t offset, size_t len)
@@ -195,12 +196,7 @@
// TODO: should LP64 reject too-large offset/len?
ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
- int ret = __ashmem_is_ashmem(fd, 1);
- if (ret < 0) {
- return ret;
- }
-
- return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_PIN, &pin));
+ return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_PIN, &pin)));
}
int ashmem_unpin_region(int fd, size_t offset, size_t len)
@@ -208,20 +204,10 @@
// TODO: should LP64 reject too-large offset/len?
ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
- int ret = __ashmem_is_ashmem(fd, 1);
- if (ret < 0) {
- return ret;
- }
-
- return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_UNPIN, &pin));
+ return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_UNPIN, &pin)));
}
int ashmem_get_size_region(int fd)
{
- int ret = __ashmem_is_ashmem(fd, 1);
- if (ret < 0) {
- return ret;
- }
-
- return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL));
+ return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)));
}
diff --git a/libcutils/hashmap.cpp b/libcutils/hashmap.cpp
index 10e3b25..57d6006 100644
--- a/libcutils/hashmap.cpp
+++ b/libcutils/hashmap.cpp
@@ -18,7 +18,7 @@
#include <assert.h>
#include <errno.h>
-#include <cutils/threads.h>
+#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@@ -36,7 +36,7 @@
size_t bucketCount;
int (*hash)(void* key);
bool (*equals)(void* keyA, void* keyB);
- mutex_t lock;
+ pthread_mutex_t lock;
size_t size;
};
@@ -44,18 +44,18 @@
int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) {
assert(hash != NULL);
assert(equals != NULL);
-
+
Hashmap* map = static_cast<Hashmap*>(malloc(sizeof(Hashmap)));
if (map == NULL) {
return NULL;
}
-
+
// 0.75 load factor.
size_t minimumBucketCount = initialCapacity * 4 / 3;
map->bucketCount = 1;
while (map->bucketCount <= minimumBucketCount) {
// Bucket count must be power of 2.
- map->bucketCount <<= 1;
+ map->bucketCount <<= 1;
}
map->buckets = static_cast<Entry**>(calloc(map->bucketCount, sizeof(Entry*)));
@@ -63,14 +63,14 @@
free(map);
return NULL;
}
-
+
map->size = 0;
map->hash = hash;
map->equals = equals;
-
- mutex_init(&map->lock);
-
+
+ pthread_mutex_init(&map->lock, nullptr);
+
return map;
}
@@ -89,12 +89,8 @@
h ^= (((unsigned int) h) >> 14);
h += (h << 4);
h ^= (((unsigned int) h) >> 10);
-
- return h;
-}
-size_t hashmapSize(Hashmap* map) {
- return map->size;
+ return h;
}
static inline size_t calculateIndex(size_t bucketCount, int hash) {
@@ -111,7 +107,7 @@
// Abort expansion.
return;
}
-
+
// Move over existing entries.
size_t i;
for (i = 0; i < map->bucketCount; i++) {
@@ -133,11 +129,11 @@
}
void hashmapLock(Hashmap* map) {
- mutex_lock(&map->lock);
+ pthread_mutex_lock(&map->lock);
}
void hashmapUnlock(Hashmap* map) {
- mutex_unlock(&map->lock);
+ pthread_mutex_unlock(&map->lock);
}
void hashmapFree(Hashmap* map) {
@@ -151,7 +147,7 @@
}
}
free(map->buckets);
- mutex_destroy(&map->lock);
+ pthread_mutex_destroy(&map->lock);
free(map);
}
@@ -240,54 +236,6 @@
return NULL;
}
-bool hashmapContainsKey(Hashmap* map, void* key) {
- int hash = hashKey(map, key);
- size_t index = calculateIndex(map->bucketCount, hash);
-
- Entry* entry = map->buckets[index];
- while (entry != NULL) {
- if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
- return true;
- }
- entry = entry->next;
- }
-
- return false;
-}
-
-void* hashmapMemoize(Hashmap* map, void* key,
- void* (*initialValue)(void* key, void* context), void* context) {
- int hash = hashKey(map, key);
- size_t index = calculateIndex(map->bucketCount, hash);
-
- Entry** p = &(map->buckets[index]);
- while (true) {
- Entry* current = *p;
-
- // Add a new entry.
- if (current == NULL) {
- *p = createEntry(key, hash, NULL);
- if (*p == NULL) {
- errno = ENOMEM;
- return NULL;
- }
- void* value = initialValue(key, context);
- (*p)->value = value;
- map->size++;
- expandIfNecessary(map);
- return value;
- }
-
- // Return existing value.
- if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
- return current->value;
- }
-
- // Move to next entry.
- p = ¤t->next;
- }
-}
-
void* hashmapRemove(Hashmap* map, void* key) {
int hash = hashKey(map, key);
size_t index = calculateIndex(map->bucketCount, hash);
@@ -310,9 +258,8 @@
return NULL;
}
-void hashmapForEach(Hashmap* map,
- bool (*callback)(void* key, void* value, void* context),
- void* context) {
+void hashmapForEach(Hashmap* map, bool (*callback)(void* key, void* value, void* context),
+ void* context) {
size_t i;
for (i = 0; i < map->bucketCount; i++) {
Entry* entry = map->buckets[i];
@@ -325,34 +272,3 @@
}
}
}
-
-size_t hashmapCurrentCapacity(Hashmap* map) {
- size_t bucketCount = map->bucketCount;
- return bucketCount * 3 / 4;
-}
-
-size_t hashmapCountCollisions(Hashmap* map) {
- size_t collisions = 0;
- size_t i;
- for (i = 0; i < map->bucketCount; i++) {
- Entry* entry = map->buckets[i];
- while (entry != NULL) {
- if (entry->next != NULL) {
- collisions++;
- }
- entry = entry->next;
- }
- }
- return collisions;
-}
-
-int hashmapIntHash(void* key) {
- // Return the key value itself.
- return *((int*) key);
-}
-
-bool hashmapIntEquals(void* keyA, void* keyB) {
- int a = *((int*) keyA);
- int b = *((int*) keyB);
- return a == b;
-}
diff --git a/libcutils/include/cutils/hashmap.h b/libcutils/include/cutils/hashmap.h
index 5cb344c..9cfd669 100644
--- a/libcutils/include/cutils/hashmap.h
+++ b/libcutils/include/cutils/hashmap.h
@@ -16,6 +16,9 @@
/**
* Hash map.
+ *
+ * Use std::map or std::unordered_map instead.
+ * https://en.cppreference.com/w/cpp/container
*/
#ifndef __HASHMAP_H
@@ -68,38 +71,17 @@
void* hashmapGet(Hashmap* map, void* key);
/**
- * Returns true if the map contains an entry for the given key.
- */
-bool hashmapContainsKey(Hashmap* map, void* key);
-
-/**
- * Gets the value for a key. If a value is not found, this function gets a
- * value and creates an entry using the given callback.
- *
- * If memory allocation fails, the callback is not called, this function
- * returns NULL, and errno is set to ENOMEM.
- */
-void* hashmapMemoize(Hashmap* map, void* key,
- void* (*initialValue)(void* key, void* context), void* context);
-
-/**
* Removes an entry from the map. Returns the removed value or NULL if no
* entry was present.
*/
void* hashmapRemove(Hashmap* map, void* key);
/**
- * Gets the number of entries in this map.
- */
-size_t hashmapSize(Hashmap* map);
-
-/**
* Invokes the given callback on each entry in the map. Stops iterating if
* the callback returns false.
*/
-void hashmapForEach(Hashmap* map,
- bool (*callback)(void* key, void* value, void* context),
- void* context);
+void hashmapForEach(Hashmap* map, bool (*callback)(void* key, void* value, void* context),
+ void* context);
/**
* Concurrency support.
@@ -115,36 +97,8 @@
*/
void hashmapUnlock(Hashmap* map);
-/**
- * Key utilities.
- */
-
-/**
- * Hashes int keys. 'key' is a pointer to int.
- */
-int hashmapIntHash(void* key);
-
-/**
- * Compares two int keys for equality.
- */
-bool hashmapIntEquals(void* keyA, void* keyB);
-
-/**
- * For debugging.
- */
-
-/**
- * Gets current capacity.
- */
-size_t hashmapCurrentCapacity(Hashmap* map);
-
-/**
- * Counts the number of entry collisions.
- */
-size_t hashmapCountCollisions(Hashmap* map);
-
#ifdef __cplusplus
}
#endif
-#endif /* __HASHMAP_H */
+#endif /* __HASHMAP_H */
diff --git a/libcutils/include/cutils/open_memstream.h b/libcutils/include/cutils/open_memstream.h
deleted file mode 100644
index c1a81eb..0000000
--- a/libcutils/include/cutils/open_memstream.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2010 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 __CUTILS_OPEN_MEMSTREAM_H__
-#define __CUTILS_OPEN_MEMSTREAM_H__
-
-#include <stdio.h>
-
-#if defined(__APPLE__)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-FILE* open_memstream(char** bufp, size_t* sizep);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __APPLE__ */
-
-#endif /*__CUTILS_OPEN_MEMSTREAM_H__*/
diff --git a/libcutils/include/cutils/threads.h b/libcutils/include/cutils/threads.h
index 5727494..ba4846e 100644
--- a/libcutils/include/cutils/threads.h
+++ b/libcutils/include/cutils/threads.h
@@ -29,16 +29,16 @@
extern "C" {
#endif
-/***********************************************************************/
-/***********************************************************************/
-/***** *****/
-/***** local thread storage *****/
-/***** *****/
-/***********************************************************************/
-/***********************************************************************/
+//
+// Deprecated: use android::base::GetThreadId instead, which doesn't truncate on Mac/Windows.
+//
extern pid_t gettid();
+//
+// Deprecated: use `_Thread_local` in C or `thread_local` in C++.
+//
+
#if !defined(_WIN32)
typedef struct {
@@ -70,77 +70,6 @@
void* value,
thread_store_destruct_t destroy);
-/***********************************************************************/
-/***********************************************************************/
-/***** *****/
-/***** mutexes *****/
-/***** *****/
-/***********************************************************************/
-/***********************************************************************/
-
-#if !defined(_WIN32)
-
-typedef pthread_mutex_t mutex_t;
-
-#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
-
-static __inline__ void mutex_lock(mutex_t* lock)
-{
- pthread_mutex_lock(lock);
-}
-static __inline__ void mutex_unlock(mutex_t* lock)
-{
- pthread_mutex_unlock(lock);
-}
-static __inline__ int mutex_init(mutex_t* lock)
-{
- return pthread_mutex_init(lock, NULL);
-}
-static __inline__ void mutex_destroy(mutex_t* lock)
-{
- pthread_mutex_destroy(lock);
-}
-
-#else // !defined(_WIN32)
-
-typedef struct {
- int init;
- CRITICAL_SECTION lock[1];
-} mutex_t;
-
-#define MUTEX_INITIALIZER { 0, {{ NULL, 0, 0, NULL, NULL, 0 }} }
-
-static __inline__ void mutex_lock(mutex_t* lock)
-{
- if (!lock->init) {
- lock->init = 1;
- InitializeCriticalSection( lock->lock );
- lock->init = 2;
- } else while (lock->init != 2)
- Sleep(10);
-
- EnterCriticalSection(lock->lock);
-}
-
-static __inline__ void mutex_unlock(mutex_t* lock)
-{
- LeaveCriticalSection(lock->lock);
-}
-static __inline__ int mutex_init(mutex_t* lock)
-{
- InitializeCriticalSection(lock->lock);
- lock->init = 2;
- return 0;
-}
-static __inline__ void mutex_destroy(mutex_t* lock)
-{
- if (lock->init) {
- lock->init = 0;
- DeleteCriticalSection(lock->lock);
- }
-}
-#endif // !defined(_WIN32)
-
#ifdef __cplusplus
}
#endif
diff --git a/libcutils/include_vndk/cutils/open_memstream.h b/libcutils/include_vndk/cutils/open_memstream.h
deleted file mode 120000
index c894084..0000000
--- a/libcutils/include_vndk/cutils/open_memstream.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/open_memstream.h
\ No newline at end of file
diff --git a/libcutils/open_memstream.c b/libcutils/open_memstream.c
deleted file mode 100644
index 9183266..0000000
--- a/libcutils/open_memstream.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#if defined(__APPLE__)
-
-/*
- * Implementation of the POSIX open_memstream() function, which Linux has
- * but BSD lacks.
- *
- * Summary:
- * - Works like a file-backed FILE* opened with fopen(name, "w"), but the
- * backing is a chunk of memory rather than a file.
- * - The buffer expands as you write more data. Seeking past the end
- * of the file and then writing to it zero-fills the gap.
- * - The values at "*bufp" and "*sizep" should be considered read-only,
- * and are only valid immediately after an fflush() or fclose().
- * - A '\0' is maintained just past the end of the file. This is not included
- * in "*sizep". (The behavior w.r.t. fseek() is not clearly defined.
- * The spec says the null byte is written when a write() advances EOF,
- * but it looks like glibc ensures the null byte is always found at EOF,
- * even if you just seeked backwards. The example on the opengroup.org
- * page suggests that this is the expected behavior. The null must be
- * present after a no-op fflush(), which we can't see, so we have to save
- * and restore it. Annoying, but allows file truncation.)
- * - After fclose(), the caller must eventually free(*bufp).
- *
- * This is built out of funopen(), which BSD has but Linux lacks. There is
- * no flush() operator, so we need to keep the user pointers up to date
- * after each operation.
- *
- * I don't think Windows has any of the above, but we don't need to use
- * them there, so we just supply a stub.
- */
-#include <cutils/open_memstream.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-#if 0
-# define DBUG(x) printf x
-#else
-# define DBUG(x) ((void)0)
-#endif
-
-/*
- * Definition of a seekable, write-only memory stream.
- */
-typedef struct {
- char** bufp; /* pointer to buffer pointer */
- size_t* sizep; /* pointer to eof */
-
- size_t allocSize; /* size of buffer */
- size_t eof; /* furthest point we've written to */
- size_t offset; /* current write offset */
- char saved; /* required by NUL handling */
-} MemStream;
-
-#define kInitialSize 1024
-
-/*
- * Ensure that we have enough storage to write "size" bytes at the
- * current offset. We also have to take into account the extra '\0'
- * that we maintain just past EOF.
- *
- * Returns 0 on success.
- */
-static int ensureCapacity(MemStream* stream, int writeSize)
-{
- DBUG(("+++ ensureCap off=%d size=%d\n", stream->offset, writeSize));
-
- size_t neededSize = stream->offset + writeSize + 1;
- if (neededSize <= stream->allocSize)
- return 0;
-
- size_t newSize;
-
- if (stream->allocSize == 0) {
- newSize = kInitialSize;
- } else {
- newSize = stream->allocSize;
- newSize += newSize / 2; /* expand by 3/2 */
- }
-
- if (newSize < neededSize)
- newSize = neededSize;
- DBUG(("+++ realloc %p->%p to size=%d\n",
- stream->bufp, *stream->bufp, newSize));
- char* newBuf = (char*) realloc(*stream->bufp, newSize);
- if (newBuf == NULL)
- return -1;
-
- *stream->bufp = newBuf;
- stream->allocSize = newSize;
- return 0;
-}
-
-/*
- * Write data to a memstream, expanding the buffer if necessary.
- *
- * If we previously seeked beyond EOF, zero-fill the gap.
- *
- * Returns the number of bytes written.
- */
-static int write_memstream(void* cookie, const char* buf, int size)
-{
- MemStream* stream = (MemStream*) cookie;
-
- if (ensureCapacity(stream, size) < 0)
- return -1;
-
- /* seeked past EOF earlier? */
- if (stream->eof < stream->offset) {
- DBUG(("+++ zero-fill gap from %d to %d\n",
- stream->eof, stream->offset-1));
- memset(*stream->bufp + stream->eof, '\0',
- stream->offset - stream->eof);
- }
-
- /* copy data, advance write pointer */
- memcpy(*stream->bufp + stream->offset, buf, size);
- stream->offset += size;
-
- if (stream->offset > stream->eof) {
- /* EOF has advanced, update it and append null byte */
- DBUG(("+++ EOF advanced to %d, appending nul\n", stream->offset));
- assert(stream->offset < stream->allocSize);
- stream->eof = stream->offset;
- } else {
- /* within previously-written area; save char we're about to stomp */
- DBUG(("+++ within written area, saving '%c' at %d\n",
- *(*stream->bufp + stream->offset), stream->offset));
- stream->saved = *(*stream->bufp + stream->offset);
- }
- *(*stream->bufp + stream->offset) = '\0';
- *stream->sizep = stream->offset;
-
- return size;
-}
-
-/*
- * Seek within a memstream.
- *
- * Returns the new offset, or -1 on failure.
- */
-static fpos_t seek_memstream(void* cookie, fpos_t offset, int whence)
-{
- MemStream* stream = (MemStream*) cookie;
- off_t newPosn = (off_t) offset;
-
- if (whence == SEEK_CUR) {
- newPosn += stream->offset;
- } else if (whence == SEEK_END) {
- newPosn += stream->eof;
- }
-
- if (newPosn < 0 || ((fpos_t)((size_t) newPosn)) != newPosn) {
- /* bad offset - negative or huge */
- DBUG(("+++ bogus seek offset %ld\n", (long) newPosn));
- errno = EINVAL;
- return (fpos_t) -1;
- }
-
- if (stream->offset < stream->eof) {
- /*
- * We were pointing to an area we'd already written to, which means
- * we stomped on a character and must now restore it.
- */
- DBUG(("+++ restoring char '%c' at %d\n",
- stream->saved, stream->offset));
- *(*stream->bufp + stream->offset) = stream->saved;
- }
-
- stream->offset = (size_t) newPosn;
-
- if (stream->offset < stream->eof) {
- /*
- * We're seeked backward into the stream. Preserve the character
- * at EOF and stomp it with a NUL.
- */
- stream->saved = *(*stream->bufp + stream->offset);
- *(*stream->bufp + stream->offset) = '\0';
- *stream->sizep = stream->offset;
- } else {
- /*
- * We're positioned at, or possibly beyond, the EOF. We want to
- * publish the current EOF, not the current position.
- */
- *stream->sizep = stream->eof;
- }
-
- return newPosn;
-}
-
-/*
- * Close the memstream. We free everything but the data buffer.
- */
-static int close_memstream(void* cookie)
-{
- free(cookie);
- return 0;
-}
-
-/*
- * Prepare a memstream.
- */
-FILE* open_memstream(char** bufp, size_t* sizep)
-{
- FILE* fp;
- MemStream* stream;
-
- if (bufp == NULL || sizep == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- stream = (MemStream*) calloc(1, sizeof(MemStream));
- if (stream == NULL)
- return NULL;
-
- fp = funopen(stream,
- NULL, write_memstream, seek_memstream, close_memstream);
- if (fp == NULL) {
- free(stream);
- return NULL;
- }
-
- *sizep = 0;
- *bufp = NULL;
- stream->bufp = bufp;
- stream->sizep = sizep;
-
- return fp;
-}
-
-
-
-
-#if 0
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * Simple regression test.
- *
- * To test on desktop Linux with valgrind, it's possible to make a simple
- * change to open_memstream() to use fopencookie instead:
- *
- * cookie_io_functions_t iofuncs =
- * { NULL, write_memstream, seek_memstream, close_memstream };
- * fp = fopencookie(stream, "w", iofuncs);
- *
- * (Some tweaks to seek_memstream are also required, as that takes a
- * pointer to an offset rather than an offset, and returns 0 or -1.)
- */
-int testMemStream(void)
-{
- FILE *stream;
- char *buf;
- size_t len;
- off_t eob;
-
- printf("Test1\n");
-
- /* std example */
- stream = open_memstream(&buf, &len);
- fprintf(stream, "hello my world");
- fflush(stream);
- printf("buf=%s, len=%zu\n", buf, len);
- eob = ftello(stream);
- fseeko(stream, 0, SEEK_SET);
- fprintf(stream, "good-bye");
- fseeko(stream, eob, SEEK_SET);
- fclose(stream);
- printf("buf=%s, len=%zu\n", buf, len);
- free(buf);
-
- printf("Test2\n");
-
- /* std example without final seek-to-end */
- stream = open_memstream(&buf, &len);
- fprintf(stream, "hello my world");
- fflush(stream);
- printf("buf=%s, len=%zu\n", buf, len);
- eob = ftello(stream);
- fseeko(stream, 0, SEEK_SET);
- fprintf(stream, "good-bye");
- //fseeko(stream, eob, SEEK_SET);
- fclose(stream);
- printf("buf=%s, len=%zu\n", buf, len);
- free(buf);
-
- printf("Test3\n");
-
- /* fancy example; should expand buffer with writes */
- static const int kCmpLen = 1024 + 128;
- char* cmp = malloc(kCmpLen);
- memset(cmp, 0, 1024);
- memset(cmp+1024, 0xff, kCmpLen-1024);
- sprintf(cmp, "This-is-a-tes1234");
- sprintf(cmp + 1022, "abcdef");
-
- stream = open_memstream (&buf, &len);
- setvbuf(stream, NULL, _IONBF, 0); /* note: crashes in glibc with this */
- fprintf(stream, "This-is-a-test");
- fseek(stream, -1, SEEK_CUR); /* broken in glibc; can use {13,SEEK_SET} */
- fprintf(stream, "1234");
- fseek(stream, 1022, SEEK_SET);
- fputc('a', stream);
- fputc('b', stream);
- fputc('c', stream);
- fputc('d', stream);
- fputc('e', stream);
- fputc('f', stream);
- fflush(stream);
-
- if (memcmp(buf, cmp, len+1) != 0) {
- printf("mismatch\n");
- } else {
- printf("match\n");
- }
-
- printf("Test4\n");
- stream = open_memstream (&buf, &len);
- fseek(stream, 5000, SEEK_SET);
- fseek(stream, 4096, SEEK_SET);
- fseek(stream, -1, SEEK_SET); /* should have no effect */
- fputc('x', stream);
- if (ftell(stream) == 4097)
- printf("good\n");
- else
- printf("BAD: offset is %ld\n", ftell(stream));
-
- printf("DONE\n");
-
- return 0;
-}
-
-/* expected output:
-Test1
-buf=hello my world, len=14
-buf=good-bye world, len=14
-Test2
-buf=hello my world, len=14
-buf=good-bye, len=8
-Test3
-match
-Test4
-good
-DONE
-*/
-
-#endif
-
-#endif /* __APPLE__ */
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index 2849aa8..0cb8a4d 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -32,10 +32,6 @@
#include "android_get_control_env.h"
-#ifndef TEMP_FAILURE_RETRY
-#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
-#endif
-
#if defined(__ANDROID__)
/* For the socket trust (credentials) check */
#include <private/android_filesystem_config.h>
@@ -102,15 +98,15 @@
// Compare to UNIX domain socket name, must match!
struct sockaddr_un addr;
socklen_t addrlen = sizeof(addr);
- int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
+ int ret = getsockname(fd, (struct sockaddr*)&addr, &addrlen);
if (ret < 0) return -1;
- char *path = NULL;
- if (asprintf(&path, ANDROID_SOCKET_DIR "/%s", name) < 0) return -1;
- if (!path) return -1;
- int cmp = strcmp(addr.sun_path, path);
- free(path);
- if (cmp != 0) return -1;
- // It is what we think it is
- return fd;
+ constexpr char prefix[] = ANDROID_SOCKET_DIR "/";
+ constexpr size_t prefix_size = sizeof(prefix) - sizeof('\0');
+ if ((strncmp(addr.sun_path, prefix, prefix_size) == 0) &&
+ (strcmp(addr.sun_path + prefix_size, name) == 0)) {
+ // It is what we think it is
+ return fd;
+ }
+ return -1;
}
diff --git a/libcutils/str_parms.cpp b/libcutils/str_parms.cpp
index f5a52a7..d818c51 100644
--- a/libcutils/str_parms.cpp
+++ b/libcutils/str_parms.cpp
@@ -354,12 +354,8 @@
char *str_parms_to_str(struct str_parms *str_parms)
{
char *str = NULL;
-
- if (hashmapSize(str_parms->map) > 0)
- hashmapForEach(str_parms->map, combine_strings, &str);
- else
- str = strdup("");
- return str;
+ hashmapForEach(str_parms->map, combine_strings, &str);
+ return (str != NULL) ? str : strdup("");
}
static bool dump_entry(void* key, void* value, void* /*context*/) {
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 52cbe8b..ee9220d 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -115,16 +115,8 @@
*/
int __android_log_print(int prio, const char* tag, const char* fmt, ...)
#if defined(__GNUC__)
-#ifdef __USE_MINGW_ANSI_STDIO
-#if __USE_MINGW_ANSI_STDIO
- __attribute__((__format__(gnu_printf, 3, 4)))
-#else
__attribute__((__format__(printf, 3, 4)))
#endif
-#else
- __attribute__((__format__(printf, 3, 4)))
-#endif
-#endif
;
/**
@@ -133,16 +125,8 @@
*/
int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap)
#if defined(__GNUC__)
-#ifdef __USE_MINGW_ANSI_STDIO
-#if __USE_MINGW_ANSI_STDIO
- __attribute__((__format__(gnu_printf, 3, 0)))
-#else
__attribute__((__format__(printf, 3, 0)))
#endif
-#else
- __attribute__((__format__(printf, 3, 0)))
-#endif
-#endif
;
/**
@@ -164,16 +148,8 @@
...)
#if defined(__GNUC__)
__attribute__((__noreturn__))
-#ifdef __USE_MINGW_ANSI_STDIO
-#if __USE_MINGW_ANSI_STDIO
- __attribute__((__format__(gnu_printf, 3, 4)))
-#else
__attribute__((__format__(printf, 3, 4)))
#endif
-#else
- __attribute__((__format__(printf, 3, 4)))
-#endif
-#endif
;
#ifndef log_id_t_defined
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index 21fc7cc..1314330 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -40,6 +40,19 @@
#endif
#endif
+/*
+ * Use __VA_ARGS__ if running a static analyzer,
+ * to avoid warnings of unused variables in __VA_ARGS__.
+ * __FAKE_USE_VA_ARGS is undefined at link time,
+ * so don't link with __clang_analyzer__ defined.
+ */
+#ifdef __clang_analyzer__
+extern void __fake_use_va_args(int, ...);
+#define __FAKE_USE_VA_ARGS(...) __fake_use_va_args(0, ##__VA_ARGS__)
+#else
+#define __FAKE_USE_VA_ARGS(...) ((void)(0))
+#endif
+
/* --------------------------------------------------------------------- */
/*
@@ -112,7 +125,7 @@
#define LOG_ALWAYS_FATAL_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)android_printAssert(#cond, LOG_TAG, ##__VA_ARGS__)) \
- : (void)0)
+ : __FAKE_USE_VA_ARGS(__VA_ARGS__))
#endif
#ifndef LOG_ALWAYS_FATAL
@@ -128,10 +141,10 @@
#if LOG_NDEBUG
#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) ((void)0)
+#define LOG_FATAL_IF(cond, ...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
#endif
#ifndef LOG_FATAL
-#define LOG_FATAL(...) ((void)0)
+#define LOG_FATAL(...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
#endif
#else
@@ -175,11 +188,12 @@
#ifndef ALOGV
#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#if LOG_NDEBUG
-#define ALOGV(...) \
- do { \
- if (false) { \
- __ALOGV(__VA_ARGS__); \
- } \
+#define ALOGV(...) \
+ do { \
+ __FAKE_USE_VA_ARGS(__VA_ARGS__); \
+ if (false) { \
+ __ALOGV(__VA_ARGS__); \
+ } \
} while (false)
#else
#define ALOGV(...) __ALOGV(__VA_ARGS__)
@@ -188,11 +202,11 @@
#ifndef ALOGV_IF
#if LOG_NDEBUG
-#define ALOGV_IF(cond, ...) ((void)0)
+#define ALOGV_IF(cond, ...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
#else
#define ALOGV_IF(cond, ...) \
((__predict_false(cond)) ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
- : (void)0)
+ : __FAKE_USE_VA_ARGS(__VA_ARGS__))
#endif
#endif
@@ -206,7 +220,7 @@
#ifndef ALOGD_IF
#define ALOGD_IF(cond, ...) \
((__predict_false(cond)) ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
- : (void)0)
+ : __FAKE_USE_VA_ARGS(__VA_ARGS__))
#endif
/*
@@ -219,7 +233,7 @@
#ifndef ALOGI_IF
#define ALOGI_IF(cond, ...) \
((__predict_false(cond)) ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
- : (void)0)
+ : __FAKE_USE_VA_ARGS(__VA_ARGS__))
#endif
/*
@@ -232,7 +246,7 @@
#ifndef ALOGW_IF
#define ALOGW_IF(cond, ...) \
((__predict_false(cond)) ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
- : (void)0)
+ : __FAKE_USE_VA_ARGS(__VA_ARGS__))
#endif
/*
@@ -245,7 +259,7 @@
#ifndef ALOGE_IF
#define ALOGE_IF(cond, ...) \
((__predict_false(cond)) ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
- : (void)0)
+ : __FAKE_USE_VA_ARGS(__VA_ARGS__))
#endif
/* --------------------------------------------------------------------- */
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index d118563..93b9d4e 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -184,7 +184,7 @@
hdr_size = sizeof(entry_v1);
}
if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
- return NULL;
+ return nullptr;
}
return reinterpret_cast<char*>(buf) + hdr_size;
}
diff --git a/liblog/include/private/android_logger.h b/liblog/include/private/android_logger.h
index 965de37..b927b46 100644
--- a/liblog/include/private/android_logger.h
+++ b/liblog/include/private/android_logger.h
@@ -173,7 +173,7 @@
#if defined(_USING_LIBCXX)
operator std::string() {
if (ret) return std::string("");
- const char* cp = NULL;
+ const char* cp = nullptr;
ssize_t len = android_log_write_list_buffer(ctx, &cp);
if (len < 0) ret = len;
if (!cp || (len <= 0)) return std::string("");
diff --git a/libmemunreachable/tests/ThreadCapture_test.cpp b/libmemunreachable/tests/ThreadCapture_test.cpp
index 4fbf729..933d65a 100644
--- a/libmemunreachable/tests/ThreadCapture_test.cpp
+++ b/libmemunreachable/tests/ThreadCapture_test.cpp
@@ -32,6 +32,8 @@
#include "ScopedDisableMalloc.h"
#include "ScopedPipe.h"
+#include <android-base/threads.h>
+
using namespace std::chrono_literals;
namespace android {
@@ -260,7 +262,7 @@
ThreadCapture thread_capture(ret, heap);
thread_capture.InjectTestFunc([&](pid_t tid) {
- syscall(SYS_tgkill, ret, tid, SIGKILL);
+ tgkill(ret, tid, SIGKILL);
usleep(10000);
});
auto list_tids = allocator::vector<pid_t>(heap);
@@ -319,7 +321,7 @@
ThreadCapture thread_capture(child, heap);
thread_capture.InjectTestFunc([&](pid_t tid) {
- syscall(SYS_tgkill, child, tid, sig);
+ tgkill(child, tid, sig);
usleep(10000);
});
auto list_tids = allocator::vector<pid_t>(heap);
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index 3563fc1..19a1783 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -53,8 +53,21 @@
#if defined(__ANDROID__)
// Look up linker namespace by class_loader. Returns nullptr if
// there is no namespace associated with the class_loader.
+// TODO(b/79940628): move users to FindNativeLoaderNamespaceByClassLoader and remove this function.
__attribute__((visibility("default")))
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
+// That version works with native bridge namespaces, but requires use of OpenNativeLibrary.
+class NativeLoaderNamespace;
+__attribute__((visibility("default")))
+NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(
+ JNIEnv* env, jobject class_loader);
+// Load library. Unlinke OpenNativeLibrary above couldn't create namespace on demand, but does
+// not require access to JNIEnv either.
+__attribute__((visibility("default")))
+void* OpenNativeLibrary(NativeLoaderNamespace* ns,
+ const char* path,
+ bool* needs_native_bridge,
+ std::string* error_msg);
#endif
__attribute__((visibility("default")))
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 7fef106..67c1c10 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -29,6 +29,7 @@
#include "nativebridge/native_bridge.h"
#include <algorithm>
+#include <list>
#include <memory>
#include <mutex>
#include <string>
@@ -150,15 +151,14 @@
public:
LibraryNamespaces() : initialized_(false) { }
- bool Create(JNIEnv* env,
- uint32_t target_sdk_version,
- jobject class_loader,
- bool is_shared,
- bool is_for_vendor,
- jstring java_library_path,
- jstring java_permitted_path,
- NativeLoaderNamespace* ns,
- std::string* error_msg) {
+ NativeLoaderNamespace* Create(JNIEnv* env,
+ uint32_t target_sdk_version,
+ jobject class_loader,
+ bool is_shared,
+ bool is_for_vendor,
+ jstring java_library_path,
+ jstring java_permitted_path,
+ std::string* error_msg) {
std::string library_path; // empty string by default.
if (java_library_path != nullptr) {
@@ -182,10 +182,10 @@
}
if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
- return false;
+ return nullptr;
}
- bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
+ bool found = FindNamespaceByClassLoader(env, class_loader);
LOG_ALWAYS_FATAL_IF(found,
"There is already a namespace associated with this classloader");
@@ -199,13 +199,12 @@
namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
}
- NativeLoaderNamespace parent_ns;
- bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
+ NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
bool is_native_bridge = false;
- if (found_parent_namespace) {
- is_native_bridge = !parent_ns.is_android_namespace();
+ if (parent_ns != nullptr) {
+ is_native_bridge = !parent_ns->is_android_namespace();
} else if (!library_path.empty()) {
is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
}
@@ -251,15 +250,17 @@
NativeLoaderNamespace native_loader_ns;
if (!is_native_bridge) {
+ android_namespace_t* android_parent_ns =
+ parent_ns == nullptr ? nullptr : parent_ns->get_android_ns();
android_namespace_t* ns = android_create_namespace(namespace_name,
nullptr,
library_path.c_str(),
namespace_type,
permitted_path.c_str(),
- parent_ns.get_android_ns());
+ android_parent_ns);
if (ns == nullptr) {
*error_msg = dlerror();
- return false;
+ return nullptr;
}
// Note that when vendor_ns is not configured this function will return nullptr
@@ -269,49 +270,50 @@
if (!android_link_namespaces(ns, nullptr, system_exposed_libraries.c_str())) {
*error_msg = dlerror();
- return false;
+ return nullptr;
}
if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) {
// vendor apks are allowed to use VNDK-SP libraries.
if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) {
*error_msg = dlerror();
- return false;
+ return nullptr;
}
}
if (!vendor_public_libraries_.empty()) {
if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
*error_msg = dlerror();
- return false;
+ return nullptr;
}
}
native_loader_ns = NativeLoaderNamespace(ns);
} else {
+ native_bridge_namespace_t* native_bridge_parent_namespace =
+ parent_ns == nullptr ? nullptr : parent_ns->get_native_bridge_ns();
native_bridge_namespace_t* ns = NativeBridgeCreateNamespace(namespace_name,
nullptr,
library_path.c_str(),
namespace_type,
permitted_path.c_str(),
- parent_ns.get_native_bridge_ns());
-
+ native_bridge_parent_namespace);
if (ns == nullptr) {
*error_msg = NativeBridgeGetError();
- return false;
+ return nullptr;
}
native_bridge_namespace_t* vendor_ns = NativeBridgeGetVendorNamespace();
if (!NativeBridgeLinkNamespaces(ns, nullptr, system_exposed_libraries.c_str())) {
*error_msg = NativeBridgeGetError();
- return false;
+ return nullptr;
}
if (!vendor_public_libraries_.empty()) {
if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
*error_msg = NativeBridgeGetError();
- return false;
+ return nullptr;
}
}
@@ -320,24 +322,19 @@
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
- *ns = native_loader_ns;
- return true;
+ return &(namespaces_.back().second);
}
- bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
+ NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
[&](const std::pair<jweak, NativeLoaderNamespace>& value) {
return env->IsSameObject(value.first, class_loader);
});
if (it != namespaces_.end()) {
- if (ns != nullptr) {
- *ns = it->second;
- }
-
- return true;
+ return &it->second;
}
- return false;
+ return nullptr;
}
void Initialize() {
@@ -557,24 +554,23 @@
return env->CallObjectMethod(class_loader, get_parent);
}
- bool FindParentNamespaceByClassLoader(JNIEnv* env,
- jobject class_loader,
- NativeLoaderNamespace* ns) {
+ NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
jobject parent_class_loader = GetParentClassLoader(env, class_loader);
while (parent_class_loader != nullptr) {
- if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
- return true;
+ NativeLoaderNamespace* ns;
+ if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
+ return ns;
}
parent_class_loader = GetParentClassLoader(env, parent_class_loader);
}
- return false;
+ return nullptr;
}
bool initialized_;
- std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
+ std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
std::string system_public_libraries_;
std::string vendor_public_libraries_;
std::string oem_public_libraries_;
@@ -614,7 +610,6 @@
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
std::string error_msg;
- NativeLoaderNamespace ns;
bool success = g_namespaces->Create(env,
target_sdk_version,
class_loader,
@@ -622,8 +617,7 @@
is_for_vendor,
library_path,
permitted_path,
- &ns,
- &error_msg);
+ &error_msg) != nullptr;
if (!success) {
return env->NewStringUTF(error_msg.c_str());
}
@@ -649,43 +643,24 @@
}
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- NativeLoaderNamespace ns;
+ NativeLoaderNamespace* ns;
- if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
+ if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) {
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
- if (!g_namespaces->Create(env,
- target_sdk_version,
- class_loader,
- false /* is_shared */,
- false /* is_for_vendor */,
- library_path,
- nullptr,
- &ns,
- error_msg)) {
+ if ((ns = g_namespaces->Create(env,
+ target_sdk_version,
+ class_loader,
+ false /* is_shared */,
+ false /* is_for_vendor */,
+ library_path,
+ nullptr,
+ error_msg)) == nullptr) {
return nullptr;
}
}
- if (ns.is_android_namespace()) {
- android_dlextinfo extinfo;
- extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
- extinfo.library_namespace = ns.get_android_ns();
-
- void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
- if (handle == nullptr) {
- *error_msg = dlerror();
- }
- *needs_native_bridge = false;
- return handle;
- } else {
- void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
- if (handle == nullptr) {
- *error_msg = NativeBridgeGetError();
- }
- *needs_native_bridge = true;
- return handle;
- }
+ return OpenNativeLibrary(ns, path, needs_native_bridge, error_msg);
#else
UNUSED(env, target_sdk_version, class_loader);
@@ -741,18 +716,45 @@
}
#if defined(__ANDROID__)
+void* OpenNativeLibrary(NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge,
+ std::string* error_msg) {
+ if (ns->is_android_namespace()) {
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns->get_android_ns();
+
+ void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
+ if (handle == nullptr) {
+ *error_msg = dlerror();
+ }
+ *needs_native_bridge = false;
+ return handle;
+ } else {
+ void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns->get_native_bridge_ns());
+ if (handle == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ }
+ *needs_native_bridge = true;
+ return handle;
+ }
+}
+
// native_bridge_namespaces are not supported for callers of this function.
// This function will return nullptr in the case when application is running
// on native bridge.
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
- NativeLoaderNamespace ns;
- if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
- return ns.is_android_namespace() ? ns.get_android_ns() : nullptr;
+ NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+ if (ns != nullptr) {
+ return ns->is_android_namespace() ? ns->get_android_ns() : nullptr;
}
return nullptr;
}
+NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ std::lock_guard<std::mutex> guard(g_namespaces_mutex);
+ return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+}
#endif
}; // android namespace
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index b0bc497..c38279d 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -2,6 +2,7 @@
srcs: ["processgroup.cpp"],
name: "libprocessgroup",
host_supported: true,
+ recovery_available: true,
shared_libs: ["libbase"],
export_include_dirs: ["include"],
cflags: [
diff --git a/libprocinfo/include/procinfo/process.h b/libprocinfo/include/procinfo/process.h
index db56fc1..9278e18 100644
--- a/libprocinfo/include/procinfo/process.h
+++ b/libprocinfo/include/procinfo/process.h
@@ -56,23 +56,25 @@
};
// Parse the contents of /proc/<tid>/status into |process_info|.
-bool GetProcessInfo(pid_t tid, ProcessInfo* process_info);
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error = nullptr);
// Parse the contents of <fd>/status into |process_info|.
// |fd| should be an fd pointing at a /proc/<pid> directory.
-bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info);
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, std::string* error = nullptr);
// Fetch the list of threads from a given process's /proc/<pid> directory.
// |fd| should be an fd pointing at a /proc/<pid> directory.
template <typename Collection>
-auto GetProcessTidsFromProcPidFd(int fd, Collection* out) ->
+auto GetProcessTidsFromProcPidFd(int fd, Collection* out, std::string* error = nullptr) ->
typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
out->clear();
int task_fd = openat(fd, "task", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
std::unique_ptr<DIR, int (*)(DIR*)> dir(fdopendir(task_fd), closedir);
if (!dir) {
- PLOG(ERROR) << "failed to open task directory";
+ if (error != nullptr) {
+ *error = "failed to open task directory";
+ }
return false;
}
@@ -81,7 +83,9 @@
if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) {
pid_t tid;
if (!android::base::ParseInt(dent->d_name, &tid, 1, std::numeric_limits<pid_t>::max())) {
- LOG(ERROR) << "failed to parse task id: " << dent->d_name;
+ if (error != nullptr) {
+ *error = std::string("failed to parse task id: ") + dent->d_name;
+ }
return false;
}
@@ -93,21 +97,25 @@
}
template <typename Collection>
-auto GetProcessTids(pid_t pid, Collection* out) ->
+auto GetProcessTids(pid_t pid, Collection* out, std::string* error = nullptr) ->
typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
char task_path[PATH_MAX];
if (snprintf(task_path, PATH_MAX, "/proc/%d", pid) >= PATH_MAX) {
- LOG(ERROR) << "task path overflow (pid = " << pid << ")";
+ if (error != nullptr) {
+ *error = "task path overflow (pid = " + std::to_string(pid) + ")";
+ }
return false;
}
android::base::unique_fd fd(open(task_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
if (fd == -1) {
- PLOG(ERROR) << "failed to open " << task_path;
+ if (error != nullptr) {
+ *error = std::string("failed to open ") + task_path;
+ }
return false;
}
- return GetProcessTidsFromProcPidFd(fd.get(), out);
+ return GetProcessTidsFromProcPidFd(fd.get(), out, error);
}
#endif
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
index 6e5be6e..9194cf3 100644
--- a/libprocinfo/process.cpp
+++ b/libprocinfo/process.cpp
@@ -31,17 +31,19 @@
namespace android {
namespace procinfo {
-bool GetProcessInfo(pid_t tid, ProcessInfo* process_info) {
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error) {
char path[PATH_MAX];
snprintf(path, sizeof(path), "/proc/%d", tid);
unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY));
if (dirfd == -1) {
- PLOG(ERROR) << "failed to open " << path;
+ if (error != nullptr) {
+ *error = std::string("failed to open ") + path;
+ }
return false;
}
- return GetProcessInfoFromProcPidFd(dirfd.get(), process_info);
+ return GetProcessInfoFromProcPidFd(dirfd.get(), process_info, error);
}
static ProcessState parse_state(const char* state) {
@@ -62,17 +64,21 @@
}
}
-bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
+bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, std::string* error) {
int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
if (status_fd == -1) {
- PLOG(ERROR) << "failed to open status fd in GetProcessInfoFromProcPidFd";
+ if (error != nullptr) {
+ *error = "failed to open status fd in GetProcessInfoFromProcPidFd";
+ }
return false;
}
std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose);
if (!fp) {
- PLOG(ERROR) << "failed to open status file in GetProcessInfoFromProcPidFd";
+ if (error != nullptr) {
+ *error = "failed to open status file in GetProcessInfoFromProcPidFd";
+ }
close(status_fd);
return false;
}
diff --git a/libsparse/backed_block.cpp b/libsparse/backed_block.cpp
index 7f5632e..f3d8022 100644
--- a/libsparse/backed_block.cpp
+++ b/libsparse/backed_block.cpp
@@ -133,7 +133,7 @@
struct backed_block* start, struct backed_block* end) {
struct backed_block* bb;
- if (start == NULL) {
+ if (start == nullptr) {
start = from->data_blocks;
}
@@ -142,12 +142,12 @@
;
}
- if (start == NULL || end == NULL) {
+ if (start == nullptr || end == nullptr) {
return;
}
- from->last_used = NULL;
- to->last_used = NULL;
+ from->last_used = nullptr;
+ to->last_used = nullptr;
if (from->data_blocks == start) {
from->data_blocks = end->next;
} else {
@@ -161,7 +161,7 @@
if (!to->data_blocks) {
to->data_blocks = start;
- end->next = NULL;
+ end->next = nullptr;
} else {
for (bb = to->data_blocks; bb; bb = bb->next) {
if (!bb->next || bb->next->block > start->block) {
@@ -230,7 +230,7 @@
static int queue_bb(struct backed_block_list* bbl, struct backed_block* new_bb) {
struct backed_block* bb;
- if (bbl->data_blocks == NULL) {
+ if (bbl->data_blocks == nullptr) {
bbl->data_blocks = new_bb;
return 0;
}
@@ -253,7 +253,7 @@
for (; bb->next && bb->next->block < new_bb->block; bb = bb->next)
;
- if (bb->next == NULL) {
+ if (bb->next == nullptr) {
bb->next = new_bb;
} else {
new_bb->next = bb->next;
@@ -273,7 +273,7 @@
int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
- if (bb == NULL) {
+ if (bb == nullptr) {
return -ENOMEM;
}
@@ -281,7 +281,7 @@
bb->len = len;
bb->type = BACKED_BLOCK_FILL;
bb->fill.val = fill_val;
- bb->next = NULL;
+ bb->next = nullptr;
return queue_bb(bbl, bb);
}
@@ -290,7 +290,7 @@
int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
- if (bb == NULL) {
+ if (bb == nullptr) {
return -ENOMEM;
}
@@ -298,7 +298,7 @@
bb->len = len;
bb->type = BACKED_BLOCK_DATA;
bb->data.data = data;
- bb->next = NULL;
+ bb->next = nullptr;
return queue_bb(bbl, bb);
}
@@ -307,7 +307,7 @@
int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
unsigned int len, unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
- if (bb == NULL) {
+ if (bb == nullptr) {
return -ENOMEM;
}
@@ -316,7 +316,7 @@
bb->type = BACKED_BLOCK_FILE;
bb->file.filename = strdup(filename);
bb->file.offset = offset;
- bb->next = NULL;
+ bb->next = nullptr;
return queue_bb(bbl, bb);
}
@@ -325,7 +325,7 @@
int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
- if (bb == NULL) {
+ if (bb == nullptr) {
return -ENOMEM;
}
@@ -334,7 +334,7 @@
bb->type = BACKED_BLOCK_FD;
bb->fd.fd = fd;
bb->fd.offset = offset;
- bb->next = NULL;
+ bb->next = nullptr;
return queue_bb(bbl, bb);
}
@@ -350,7 +350,7 @@
}
new_bb = reinterpret_cast<backed_block*>(malloc(sizeof(struct backed_block)));
- if (new_bb == NULL) {
+ if (new_bb == nullptr) {
return -ENOMEM;
}
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 3d5fb0c..5865786 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -210,6 +210,37 @@
int (*write)(void *priv, const void *data, size_t len), void *priv);
/**
+ * sparse_file_callback_typed - call a callback for blocks based on type
+ *
+ * @s - sparse file cookie
+ * @sparse - write in the Android sparse file format
+ * @data_write - function to call for data blocks. must not be null
+ * @fd_write - function to call for fd blocks
+ * @fill_write - function to call for fill blocks
+ * @skip_write - function to call for skip blocks
+ * @priv - value that will be passed as the first argument to each write
+ *
+ * Writes a sparse file by calling callback functions. If sparse is true, the
+ * file will be written in the Android sparse file format, and fill and skip blocks
+ * along with metadata will be written with data_write. If sparse is false, the file
+ * will be expanded into normal format and fill and skip blocks will be written with
+ * the given callbacks.
+ * If a callback function is provided, the library will not unroll data into a buffer,
+ * and will instead pass it directly to the caller for custom implementation. If a
+ * callback is not provided, that type of block will be converted into a void* and
+ * written with data_write. If no callbacks other than data are provided, the behavior
+ * is the same as sparse_file_callback(). The callback should return negative on error,
+ * 0 on success.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_callback_typed(struct sparse_file* s, bool sparse,
+ int (*data_write)(void* priv, const void* data, size_t len),
+ int (*fd_write)(void* priv, int fd, size_t len),
+ int (*fill_write)(void* priv, uint32_t fill_val, size_t len),
+ int (*skip_write)(void* priv, int64_t len), void* priv);
+
+/**
* sparse_file_foreach_chunk - call a callback for data blocks in sparse file
*
* @s - sparse file cookie
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index 5388e77..8a21dab 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -29,6 +29,8 @@
#include <unistd.h>
#include <zlib.h>
+#include <algorithm>
+
#include "defs.h"
#include "output_file.h"
#include "sparse_crc32.h"
@@ -48,13 +50,6 @@
#define off64_t off_t
#endif
-#define min(a, b) \
- ({ \
- typeof(a) _a = (a); \
- typeof(b) _b = (b); \
- (_a < _b) ? _a : _b; \
- })
-
#define SPARSE_HEADER_MAJOR_VER 1
#define SPARSE_HEADER_MINOR_VER 0
#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
@@ -67,11 +62,14 @@
int (*skip)(struct output_file*, int64_t);
int (*pad)(struct output_file*, int64_t);
int (*write)(struct output_file*, void*, size_t);
+ int (*write_fd)(struct output_file*, int, size_t);
+ int (*write_fill)(struct output_file*, uint32_t, size_t);
void (*close)(struct output_file*);
};
struct sparse_file_ops {
int (*write_data_chunk)(struct output_file* out, unsigned int len, void* data);
+ int (*write_fd_chunk)(struct output_file* out, unsigned int len, int fd);
int (*write_fill_chunk)(struct output_file* out, unsigned int len, uint32_t fill_val);
int (*write_skip_chunk)(struct output_file* out, int64_t len);
int (*write_end_chunk)(struct output_file* out);
@@ -108,11 +106,96 @@
struct output_file_callback {
struct output_file out;
void* priv;
- int (*write)(void* priv, const void* buf, size_t len);
+ int (*data_write)(void* priv, const void* data, size_t len);
+ int (*fd_write)(void* priv, int fd, size_t len);
+ int (*fill_write)(void* priv, uint32_t fill_val, size_t len);
+ int (*skip_write)(void* priv, off64_t len);
};
#define to_output_file_callback(_o) container_of((_o), struct output_file_callback, out)
+union handle_data {
+ void* data_ptr;
+ int fd;
+};
+
+static int default_file_write_fd(struct output_file* out, int fd, size_t len) {
+ int ret;
+ int64_t aligned_offset;
+ int aligned_diff;
+ uint64_t buffer_size;
+ char* ptr;
+ int64_t offset = lseek64(fd, 0, SEEK_CUR);
+
+ if (offset < 0) {
+ return -errno;
+ }
+
+ aligned_offset = offset & ~(4096 - 1);
+ aligned_diff = offset - aligned_offset;
+ buffer_size = (uint64_t)len + (uint64_t)aligned_diff;
+
+#ifndef _WIN32
+ if (buffer_size > SIZE_MAX) {
+ return -E2BIG;
+ }
+ char* data =
+ reinterpret_cast<char*>(mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
+ if (data == MAP_FAILED) {
+ return -errno;
+ }
+ ptr = data + aligned_diff;
+#else
+ char* data = reinterpret_cast<char*>(malloc(len));
+ if (!data) {
+ return -errno;
+ }
+ ret = read_all(fd, data, len);
+ if (ret < 0) {
+ free(data);
+ return -errno;
+ }
+ ptr = data;
+#endif
+
+ ret = out->ops->write(out, ptr, len);
+
+ if (out->use_crc) {
+ out->crc32 = sparse_crc32(out->crc32, ptr, len);
+ }
+
+#ifndef _WIN32
+ munmap(data, buffer_size);
+#else
+ free(data);
+#endif
+
+ return ret;
+}
+
+static int default_file_write_fill(struct output_file* out, uint32_t fill_val, size_t len) {
+ int ret;
+ unsigned int i;
+ unsigned int write_len;
+
+ /* Initialize fill_buf with the fill_val */
+ for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
+ out->fill_buf[i] = fill_val;
+ }
+
+ while (len) {
+ write_len = std::min(len, static_cast<size_t>(out->block_size));
+ ret = out->ops->write(out, out->fill_buf, write_len);
+ if (ret < 0) {
+ return ret;
+ }
+
+ len -= write_len;
+ }
+
+ return 0;
+}
+
static int file_open(struct output_file* out, int fd) {
struct output_file_normal* outn = to_output_file_normal(out);
@@ -176,6 +259,8 @@
.skip = file_skip,
.pad = file_pad,
.write = file_write,
+ .write_fd = default_file_write_fd,
+ .write_fill = default_file_write_fill,
.close = file_close,
};
@@ -231,9 +316,9 @@
struct output_file_gz* outgz = to_output_file_gz(out);
while (len > 0) {
- ret = gzwrite(outgz->gz_fd, data, min(len, (unsigned int)INT_MAX));
+ ret = gzwrite(outgz->gz_fd, data, std::min(len, static_cast<size_t>(INT_MAX)));
if (ret == 0) {
- error("gzwrite %s", gzerror(outgz->gz_fd, NULL));
+ error("gzwrite %s", gzerror(outgz->gz_fd, nullptr));
return -1;
}
len -= ret;
@@ -255,6 +340,8 @@
.skip = gz_file_skip,
.pad = gz_file_pad,
.write = gz_file_write,
+ .write_fd = default_file_write_fd,
+ .write_fill = default_file_write_fill,
.close = gz_file_close,
};
@@ -267,9 +354,13 @@
int to_write;
int ret;
+ if (outc->skip_write) {
+ return outc->skip_write(outc->priv, off);
+ }
+
while (off > 0) {
- to_write = min(off, (int64_t)INT_MAX);
- ret = outc->write(outc->priv, NULL, to_write);
+ to_write = std::min(off, static_cast<int64_t>(INT_MAX));
+ ret = outc->data_write(outc->priv, nullptr, to_write);
if (ret < 0) {
return ret;
}
@@ -285,8 +376,23 @@
static int callback_file_write(struct output_file* out, void* data, size_t len) {
struct output_file_callback* outc = to_output_file_callback(out);
+ return outc->data_write(outc->priv, data, len);
+}
- return outc->write(outc->priv, data, len);
+static int callback_file_write_fd(struct output_file* out, int fd, size_t len) {
+ struct output_file_callback* outc = to_output_file_callback(out);
+ if (outc->fd_write) {
+ return outc->fd_write(outc->priv, fd, len);
+ }
+ return default_file_write_fd(out, fd, len);
+}
+
+static int callback_file_write_fill(struct output_file* out, uint32_t fill_val, size_t len) {
+ struct output_file_callback* outc = to_output_file_callback(out);
+ if (outc->fill_write) {
+ return outc->fill_write(outc->priv, fill_val, len);
+ }
+ return default_file_write_fill(out, fill_val, len);
}
static void callback_file_close(struct output_file* out) {
@@ -300,6 +406,8 @@
.skip = callback_file_skip,
.pad = callback_file_pad,
.write = callback_file_write,
+ .write_fd = callback_file_write_fd,
+ .write_fill = callback_file_write_fill,
.close = callback_file_close,
};
@@ -376,7 +484,8 @@
return 0;
}
-static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data) {
+static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int len,
+ handle_data data, bool is_fd) {
chunk_header_t chunk_header;
int rnd_up_len, zero_len;
int ret;
@@ -393,7 +502,16 @@
ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
if (ret < 0) return -1;
- ret = out->ops->write(out, data, len);
+
+ if (is_fd) {
+ // CRC is handled by write_fd
+ ret = out->ops->write_fd(out, data.fd, len);
+ } else {
+ ret = out->ops->write(out, data.data_ptr, len);
+ if (out->use_crc) {
+ out->crc32 = sparse_crc32(out->crc32, data.data_ptr, len);
+ }
+ }
if (ret < 0) return -1;
if (zero_len) {
ret = out->ops->write(out, out->zero_buf, zero_len);
@@ -401,7 +519,6 @@
}
if (out->use_crc) {
- out->crc32 = sparse_crc32(out->crc32, data, len);
if (zero_len) out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len);
}
@@ -411,6 +528,16 @@
return 0;
}
+static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data_ptr) {
+ handle_data data = {data_ptr};
+ return write_sparse_data_chunk_variant(out, len, data, false /* isFd */);
+}
+
+static int write_sparse_fd_chunk(struct output_file* out, unsigned int len, int fd) {
+ handle_data data = {.fd = fd};
+ return write_sparse_data_chunk_variant(out, len, data, true /* isFd */);
+}
+
int write_sparse_end_chunk(struct output_file* out) {
chunk_header_t chunk_header;
int ret;
@@ -438,16 +565,22 @@
static struct sparse_file_ops sparse_file_ops = {
.write_data_chunk = write_sparse_data_chunk,
+ .write_fd_chunk = write_sparse_fd_chunk,
.write_fill_chunk = write_sparse_fill_chunk,
.write_skip_chunk = write_sparse_skip_chunk,
.write_end_chunk = write_sparse_end_chunk,
};
-static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data) {
+static int write_normal_data_chunk_variant(struct output_file* out, unsigned int len,
+ handle_data data, bool isFd) {
int ret;
unsigned int rnd_up_len = ALIGN(len, out->block_size);
- ret = out->ops->write(out, data, len);
+ if (isFd) {
+ ret = out->ops->write_fd(out, data.fd, len);
+ } else {
+ ret = out->ops->write(out, data.data_ptr, len);
+ }
if (ret < 0) {
return ret;
}
@@ -459,27 +592,18 @@
return ret;
}
+static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data_ptr) {
+ handle_data data = {data_ptr};
+ return write_normal_data_chunk_variant(out, len, data, false /* isFd */);
+}
+
+static int write_normal_fd_chunk(struct output_file* out, unsigned int len, int fd) {
+ handle_data data = {.fd = fd};
+ return write_normal_data_chunk_variant(out, len, data, true /* isFd */);
+}
+
static int write_normal_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
- int ret;
- unsigned int i;
- unsigned int write_len;
-
- /* Initialize fill_buf with the fill_val */
- for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
- out->fill_buf[i] = fill_val;
- }
-
- while (len) {
- write_len = min(len, out->block_size);
- ret = out->ops->write(out, out->fill_buf, write_len);
- if (ret < 0) {
- return ret;
- }
-
- len -= write_len;
- }
-
- return 0;
+ return out->ops->write_fill(out, fill_val, len);
}
static int write_normal_skip_chunk(struct output_file* out, int64_t len) {
@@ -492,6 +616,7 @@
static struct sparse_file_ops normal_file_ops = {
.write_data_chunk = write_normal_data_chunk,
+ .write_fd_chunk = write_normal_fd_chunk,
.write_fill_chunk = write_normal_fill_chunk,
.write_skip_chunk = write_normal_skip_chunk,
.write_end_chunk = write_normal_end_chunk,
@@ -568,7 +693,7 @@
reinterpret_cast<struct output_file_gz*>(calloc(1, sizeof(struct output_file_gz)));
if (!outgz) {
error_errno("malloc struct outgz");
- return NULL;
+ return nullptr;
}
outgz->out.ops = &gz_file_ops;
@@ -581,7 +706,7 @@
reinterpret_cast<struct output_file_normal*>(calloc(1, sizeof(struct output_file_normal)));
if (!outn) {
error_errno("malloc struct outn");
- return NULL;
+ return nullptr;
}
outn->out.ops = &file_ops;
@@ -589,27 +714,38 @@
return &outn->out;
}
-struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
- unsigned int block_size, int64_t len, int gz __unused,
- int sparse, int chunks, int crc) {
+struct output_file* output_file_open_callback(int (*data_write)(void*, const void*, size_t),
+ int (*fd_write)(void*, int, size_t),
+ int (*fill_write)(void*, uint32_t, size_t),
+ int (*skip_write)(void*, off64_t), void* priv,
+ unsigned int block_size, int64_t len, int sparse,
+ int chunks, int crc) {
int ret;
struct output_file_callback* outc;
+ if (!data_write || (crc && (fd_write || fill_write))) {
+ errno = EINVAL;
+ return nullptr;
+ }
+
outc =
reinterpret_cast<struct output_file_callback*>(calloc(1, sizeof(struct output_file_callback)));
if (!outc) {
error_errno("malloc struct outc");
- return NULL;
+ return nullptr;
}
outc->out.ops = &callback_file_ops;
outc->priv = priv;
- outc->write = write;
+ outc->data_write = data_write;
+ outc->fd_write = fd_write;
+ outc->fill_write = fill_write;
+ outc->skip_write = skip_write;
ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc);
if (ret < 0) {
free(outc);
- return NULL;
+ return nullptr;
}
return &outc->out;
@@ -626,7 +762,7 @@
out = output_file_new_normal();
}
if (!out) {
- return NULL;
+ return nullptr;
}
out->ops->open(out, fd);
@@ -634,7 +770,7 @@
ret = output_file_init(out, block_size, len, sparse, chunks, crc);
if (ret < 0) {
free(out);
- return NULL;
+ return nullptr;
}
return out;
@@ -651,52 +787,8 @@
}
int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) {
- int ret;
- int64_t aligned_offset;
- int aligned_diff;
- uint64_t buffer_size;
- char* ptr;
-
- aligned_offset = offset & ~(4096 - 1);
- aligned_diff = offset - aligned_offset;
- buffer_size = (uint64_t)len + (uint64_t)aligned_diff;
-
-#ifndef _WIN32
- if (buffer_size > SIZE_MAX) return -E2BIG;
- char* data =
- reinterpret_cast<char*>(mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset));
- if (data == MAP_FAILED) {
- return -errno;
- }
- ptr = data + aligned_diff;
-#else
- off64_t pos;
- char* data = reinterpret_cast<char*>(malloc(len));
- if (!data) {
- return -errno;
- }
- pos = lseek64(fd, offset, SEEK_SET);
- if (pos < 0) {
- free(data);
- return -errno;
- }
- ret = read_all(fd, data, len);
- if (ret < 0) {
- free(data);
- return ret;
- }
- ptr = data;
-#endif
-
- ret = out->sparse_ops->write_data_chunk(out, len, ptr);
-
-#ifndef _WIN32
- munmap(data, buffer_size);
-#else
- free(data);
-#endif
-
- return ret;
+ lseek64(fd, offset, SEEK_SET);
+ return out->sparse_ops->write_fd_chunk(out, len, fd);
}
/* Write a contiguous region of data blocks from a file */
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index 278430b..114582e 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -22,14 +22,18 @@
#endif
#include <sparse/sparse.h>
+#include <sys/types.h>
struct output_file;
struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t len, int gz,
int sparse, int chunks, int crc);
-struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
- unsigned int block_size, int64_t len, int gz,
- int sparse, int chunks, int crc);
+struct output_file* output_file_open_callback(int (*data_write)(void*, const void*, size_t),
+ int (*fd_write)(void*, int, size_t),
+ int (*fill_write)(void*, uint32_t, size_t),
+ int (*skip_write)(void*, off64_t), void* priv,
+ unsigned int block_size, int64_t len, int sparse,
+ int chunks, int crc);
int write_data_chunk(struct output_file* out, unsigned int len, void* data);
int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val);
int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset);
diff --git a/libsparse/simg2simg.cpp b/libsparse/simg2simg.cpp
index 7e65701..a2c296e 100644
--- a/libsparse/simg2simg.cpp
+++ b/libsparse/simg2simg.cpp
@@ -66,7 +66,7 @@
exit(-1);
}
- files = sparse_file_resparse(s, max_size, NULL, 0);
+ files = sparse_file_resparse(s, max_size, nullptr, 0);
if (files < 0) {
fprintf(stderr, "Failed to resparse\n");
exit(-1);
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index 6ff97b6..f5ca907 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -30,13 +30,13 @@
struct sparse_file* sparse_file_new(unsigned int block_size, int64_t len) {
struct sparse_file* s = reinterpret_cast<sparse_file*>(calloc(sizeof(struct sparse_file), 1));
if (!s) {
- return NULL;
+ return nullptr;
}
s->backed_block_list = backed_block_list_new(block_size);
if (!s->backed_block_list) {
free(s);
- return NULL;
+ return nullptr;
}
s->block_size = block_size;
@@ -160,7 +160,30 @@
struct output_file* out;
chunks = sparse_count_chunks(s);
- out = output_file_open_callback(write, priv, s->block_size, s->len, false, sparse, chunks, crc);
+ out = output_file_open_callback(write, nullptr, nullptr, nullptr, priv, s->block_size, s->len,
+ sparse, chunks, crc);
+
+ if (!out) return -ENOMEM;
+
+ ret = write_all_blocks(s, out);
+
+ output_file_close(out);
+
+ return ret;
+}
+
+int sparse_file_callback_typed(struct sparse_file* s, bool sparse,
+ int (*data_write)(void* priv, const void* data, size_t len),
+ int (*fd_write)(void* priv, int fd, size_t len),
+ int (*fill_write)(void* priv, uint32_t fill_val, size_t len),
+ int (*skip_write)(void* priv, int64_t len), void* priv) {
+ int ret;
+ int chunks;
+ struct output_file* out;
+
+ chunks = sparse_count_chunks(s);
+ out = output_file_open_callback(data_write, fd_write, fill_write, skip_write, priv, s->block_size,
+ s->len, sparse, chunks, false);
if (!out) return -ENOMEM;
@@ -198,8 +221,8 @@
chk.write = write;
chk.block = chk.nr_blocks = 0;
chunks = sparse_count_chunks(s);
- out = output_file_open_callback(foreach_chunk_write, &chk, s->block_size, s->len, false, sparse,
- chunks, crc);
+ out = output_file_open_callback(foreach_chunk_write, nullptr, nullptr, nullptr, &chk,
+ s->block_size, s->len, sparse, chunks, crc);
if (!out) return -ENOMEM;
@@ -227,8 +250,8 @@
int64_t count = 0;
struct output_file* out;
- out = output_file_open_callback(out_counter_write, &count, s->block_size, s->len, false, sparse,
- chunks, crc);
+ out = output_file_open_callback(out_counter_write, nullptr, nullptr, nullptr, &count,
+ s->block_size, s->len, sparse, chunks, crc);
if (!out) {
return -1;
}
@@ -252,7 +275,7 @@
unsigned int len) {
int64_t count = 0;
struct output_file* out_counter;
- struct backed_block* last_bb = NULL;
+ struct backed_block* last_bb = nullptr;
struct backed_block* bb;
struct backed_block* start;
unsigned int last_block = 0;
@@ -267,10 +290,10 @@
len -= overhead;
start = backed_block_iter_new(from->backed_block_list);
- out_counter = output_file_open_callback(out_counter_write, &count, to->block_size, to->len, false,
- true, 0, false);
+ out_counter = output_file_open_callback(out_counter_write, nullptr, nullptr, nullptr, &count,
+ to->block_size, to->len, true, 0, false);
if (!out_counter) {
- return NULL;
+ return nullptr;
}
for (bb = start; bb; bb = backed_block_iter_next(bb)) {
@@ -281,7 +304,7 @@
/* will call out_counter_write to update count */
ret = sparse_file_write_block(out_counter, bb);
if (ret) {
- bb = NULL;
+ bb = nullptr;
goto out;
}
if (file_len + count > len) {
@@ -330,13 +353,13 @@
if (c < out_s_count) {
out_s[c] = s;
} else {
- backed_block_list_move(s->backed_block_list, tmp->backed_block_list, NULL, NULL);
+ backed_block_list_move(s->backed_block_list, tmp->backed_block_list, nullptr, nullptr);
sparse_file_destroy(s);
}
c++;
} while (bb);
- backed_block_list_move(tmp->backed_block_list, in_s->backed_block_list, NULL, NULL);
+ backed_block_list_move(tmp->backed_block_list, in_s->backed_block_list, nullptr, nullptr);
sparse_file_destroy(tmp);
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index 56e2c9a..c4c1823 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -276,7 +276,7 @@
return ret;
}
- if (crc32 != NULL && file_crc32 != *crc32) {
+ if (crc32 != nullptr && file_crc32 != *crc32) {
return -EINVAL;
}
@@ -339,7 +339,7 @@
sparse_header_t sparse_header;
chunk_header_t chunk_header;
uint32_t crc32 = 0;
- uint32_t* crc_ptr = 0;
+ uint32_t* crc_ptr = nullptr;
unsigned int cur_block = 0;
if (!copybuf) {
@@ -489,39 +489,39 @@
ret = source->ReadValue(&sparse_header, sizeof(sparse_header));
if (ret < 0) {
verbose_error(verbose, ret, "header");
- return NULL;
+ return nullptr;
}
if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
verbose_error(verbose, -EINVAL, "header magic");
- return NULL;
+ return nullptr;
}
if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
verbose_error(verbose, -EINVAL, "header major version");
- return NULL;
+ return nullptr;
}
if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
- return NULL;
+ return nullptr;
}
if (sparse_header.chunk_hdr_sz < sizeof(chunk_header_t)) {
- return NULL;
+ return nullptr;
}
len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
s = sparse_file_new(sparse_header.blk_sz, len);
if (!s) {
- verbose_error(verbose, -EINVAL, NULL);
- return NULL;
+ verbose_error(verbose, -EINVAL, nullptr);
+ return nullptr;
}
ret = source->SetOffset(0);
if (ret < 0) {
verbose_error(verbose, ret, "seeking");
sparse_file_destroy(s);
- return NULL;
+ return nullptr;
}
s->verbose = verbose;
@@ -529,7 +529,7 @@
ret = sparse_file_read_sparse(s, source, crc);
if (ret < 0) {
sparse_file_destroy(s);
- return NULL;
+ return nullptr;
}
return s;
@@ -557,20 +557,20 @@
len = lseek64(fd, 0, SEEK_END);
if (len < 0) {
- return NULL;
+ return nullptr;
}
lseek64(fd, 0, SEEK_SET);
s = sparse_file_new(4096, len);
if (!s) {
- return NULL;
+ return nullptr;
}
ret = sparse_file_read_normal(s, fd);
if (ret < 0) {
sparse_file_destroy(s);
- return NULL;
+ return nullptr;
}
return s;
diff --git a/libsync/include/ndk/sync.h b/libsync/include/ndk/sync.h
index 49f01e1..ba7d8c4 100644
--- a/libsync/include/ndk/sync.h
+++ b/libsync/include/ndk/sync.h
@@ -27,11 +27,14 @@
#define ANDROID_SYNC_H
#include <stdint.h>
+#include <sys/cdefs.h>
#include <linux/sync_file.h>
__BEGIN_DECLS
+#if __ANDROID_API__ >= 26
+
/* Fences indicate the status of an asynchronous task. They are initially
* in unsignaled state (0), and make a one-time transition to either signaled
* (1) or error (< 0) state. A sync file is a collection of one or more fences;
@@ -88,6 +91,8 @@
/** Free a struct sync_file_info structure */
void sync_file_info_free(struct sync_file_info* info) __INTRODUCED_IN(26);
+#endif /* __ANDROID_API__ >= 26 */
+
__END_DECLS
#endif /* ANDROID_SYNC_H */
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 87e2684..835e226 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -42,7 +42,7 @@
FrameworkListener::FrameworkListener(int sock) :
SocketListener(sock, true) {
- init(NULL, false);
+ init(nullptr, false);
}
void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
@@ -154,7 +154,7 @@
if (!haveCmdNum) {
char *endptr;
int cmdNum = (int)strtol(tmp, &endptr, 0);
- if (endptr == NULL || *endptr != '\0') {
+ if (endptr == nullptr || *endptr != '\0') {
cli->sendMsg(500, "Invalid sequence number", false);
goto out;
}
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 35a3063..24ea7aa 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -45,8 +45,8 @@
NetlinkEvent::NetlinkEvent() {
mAction = Action::kUnknown;
memset(mParams, 0, sizeof(mParams));
- mPath = NULL;
- mSubsystem = NULL;
+ mPath = nullptr;
+ mSubsystem = nullptr;
}
NetlinkEvent::~NetlinkEvent() {
@@ -89,7 +89,7 @@
NL_EVENT_RTM_NAME(LOCAL_QLOG_NL_EVENT);
NL_EVENT_RTM_NAME(LOCAL_NFLOG_PACKET);
default:
- return NULL;
+ return nullptr;
}
#undef NL_EVENT_RTM_NAME
}
@@ -158,7 +158,7 @@
*/
bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
- struct ifa_cacheinfo *cacheinfo = NULL;
+ struct ifa_cacheinfo *cacheinfo = nullptr;
char addrstr[INET6_ADDRSTRLEN] = "";
char ifname[IFNAMSIZ] = "";
@@ -239,12 +239,13 @@
asprintf(&mParams[1], "INTERFACE=%s", ifname);
asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
+ asprintf(&mParams[4], "IFINDEX=%u", ifaddr->ifa_index);
if (cacheinfo) {
- asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
- asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
- asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
- asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
+ asprintf(&mParams[5], "PREFERRED=%u", cacheinfo->ifa_prefered);
+ asprintf(&mParams[6], "VALID=%u", cacheinfo->ifa_valid);
+ asprintf(&mParams[7], "CSTAMP=%u", cacheinfo->cstamp);
+ asprintf(&mParams[8], "TSTAMP=%u", cacheinfo->tstamp);
}
return true;
@@ -285,7 +286,7 @@
bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) {
int uid = -1;
int len = 0;
- char* raw = NULL;
+ char* raw = nullptr;
struct nlattr* uid_attr = findNlAttr(nh, sizeof(struct genlmsghdr), NFULA_UID);
if (uid_attr) {
@@ -583,7 +584,7 @@
(prefixlen == 0 || !memcmp(str, prefix, prefixlen))) {
return str + prefixlen;
} else {
- return NULL;
+ return nullptr;
}
}
@@ -624,16 +625,16 @@
first = 0;
} else {
const char* a;
- if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
+ if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != nullptr) {
if (!strcmp(a, "add"))
mAction = Action::kAdd;
else if (!strcmp(a, "remove"))
mAction = Action::kRemove;
else if (!strcmp(a, "change"))
mAction = Action::kChange;
- } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
+ } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != nullptr) {
mSeq = atoi(a);
- } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
+ } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != nullptr) {
mSubsystem = strdup(a);
} else if (param_idx < NL_PARAMS_MAX) {
mParams[param_idx++] = strdup(s);
@@ -655,14 +656,14 @@
const char *NetlinkEvent::findParam(const char *paramName) {
size_t len = strlen(paramName);
- for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
+ for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != nullptr; ++i) {
const char *ptr = mParams[i] + len;
if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
return ++ptr;
}
SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName);
- return NULL;
+ return nullptr;
}
nlattr* NetlinkEvent::findNlAttr(const nlmsghdr* nh, size_t hdrlen, uint16_t attr) {
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 971f908..0625db7 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -42,8 +42,8 @@
mSocket = socket;
mSocketOwned = owned;
mUseCmdNum = useCmdNum;
- pthread_mutex_init(&mWriteMutex, NULL);
- pthread_mutex_init(&mRefCountMutex, NULL);
+ pthread_mutex_init(&mWriteMutex, nullptr);
+ pthread_mutex_init(&mRefCountMutex, nullptr);
mPid = -1;
mUid = -1;
mGid = -1;
@@ -135,9 +135,9 @@
const char *end = arg + len;
char *oldresult;
- if(result == NULL) {
+ if(result == nullptr) {
SLOGW("malloc error (%s)", strerror(errno));
- return NULL;
+ return nullptr;
}
*(current++) = '"';
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 3f8f3db..0c8a688 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -39,7 +39,7 @@
}
SocketListener::SocketListener(int socketFd, bool listen) {
- init(NULL, socketFd, listen, false);
+ init(nullptr, socketFd, listen, false);
}
SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
@@ -51,7 +51,7 @@
mSocketName = socketName;
mSock = socketFd;
mUseCmdNum = useCmdNum;
- pthread_mutex_init(&mClientsLock, NULL);
+ pthread_mutex_init(&mClientsLock, nullptr);
mClients = new SocketClientCollection();
}
@@ -102,7 +102,7 @@
return -1;
}
- if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
+ if (pthread_create(&mThread, nullptr, SocketListener::threadStart, this)) {
SLOGE("pthread_create (%s)", strerror(errno));
return -1;
}
@@ -147,8 +147,8 @@
SocketListener *me = reinterpret_cast<SocketListener *>(obj);
me->runListener();
- pthread_exit(NULL);
- return NULL;
+ pthread_exit(nullptr);
+ return nullptr;
}
void SocketListener::runListener() {
@@ -183,7 +183,7 @@
}
pthread_mutex_unlock(&mClientsLock);
SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);
- if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
+ if ((rc = select(max + 1, &read_fds, nullptr, nullptr, nullptr)) < 0) {
if (errno == EINTR)
continue;
SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);
diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h
index 635cefd..388ab0a 100644
--- a/libunwindstack/DwarfDebugFrame.h
+++ b/libunwindstack/DwarfDebugFrame.h
@@ -26,9 +26,9 @@
namespace unwindstack {
template <typename AddressType>
-class DwarfDebugFrame : public DwarfSectionImpl<AddressType> {
+class DwarfDebugFrame : public DwarfSectionImplNoHdr<AddressType> {
public:
- DwarfDebugFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {
+ DwarfDebugFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {
this->cie32_value_ = static_cast<uint32_t>(-1);
this->cie64_value_ = static_cast<uint64_t>(-1);
}
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index 7a41e45..df441fb 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -25,9 +25,9 @@
namespace unwindstack {
template <typename AddressType>
-class DwarfEhFrame : public DwarfSectionImpl<AddressType> {
+class DwarfEhFrame : public DwarfSectionImplNoHdr<AddressType> {
public:
- DwarfEhFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
+ DwarfEhFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {}
virtual ~DwarfEhFrame() = default;
uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
index fd6a457..668527a 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ b/libunwindstack/DwarfEhFrameWithHdr.cpp
@@ -39,6 +39,7 @@
memory_.clear_text_offset();
memory_.set_data_offset(offset);
memory_.set_cur_offset(offset);
+ pc_offset_ = offset;
// Read the first four bytes all at once.
uint8_t data[4];
@@ -88,12 +89,22 @@
}
template <typename AddressType>
-const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromIndex(size_t index) {
- const FdeInfo* info = GetFdeInfoFromIndex(index);
- if (info == nullptr) {
+const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
+ uint64_t fde_offset;
+ if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
return nullptr;
}
- return this->GetFdeFromOffset(info->offset);
+ const DwarfFde* fde = this->GetFdeFromOffset(fde_offset);
+ if (fde == nullptr) {
+ return nullptr;
+ }
+
+ // Guaranteed pc >= pc_start, need to check pc in the fde range.
+ if (pc < fde->pc_end) {
+ return fde;
+ }
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
+ return nullptr;
}
template <typename AddressType>
@@ -241,6 +252,21 @@
}
}
+template <typename AddressType>
+void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
+ for (size_t i = 0; i < fde_count_; i++) {
+ const FdeInfo* info = GetFdeInfoFromIndex(i);
+ if (info == nullptr) {
+ break;
+ }
+ const DwarfFde* fde = this->GetFdeFromOffset(info->offset);
+ if (fde == nullptr) {
+ break;
+ }
+ fdes->push_back(fde);
+ }
+}
+
// Explicitly instantiate DwarfEhFrameWithHdr
template class DwarfEhFrameWithHdr<uint32_t>;
template class DwarfEhFrameWithHdr<uint64_t>;
diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h
index d16dd10..e3e9ca8 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.h
+++ b/libunwindstack/DwarfEhFrameWithHdr.h
@@ -21,7 +21,7 @@
#include <unordered_map>
-#include "DwarfEhFrame.h"
+#include <unwindstack/DwarfSection.h>
namespace unwindstack {
@@ -29,12 +29,12 @@
class Memory;
template <typename AddressType>
-class DwarfEhFrameWithHdr : public DwarfEhFrame<AddressType> {
+class DwarfEhFrameWithHdr : public DwarfSectionImpl<AddressType> {
public:
// Add these so that the protected members of DwarfSectionImpl
// can be accessed without needing a this->.
using DwarfSectionImpl<AddressType>::memory_;
- using DwarfSectionImpl<AddressType>::fde_count_;
+ using DwarfSectionImpl<AddressType>::pc_offset_;
using DwarfSectionImpl<AddressType>::entries_offset_;
using DwarfSectionImpl<AddressType>::entries_end_;
using DwarfSectionImpl<AddressType>::last_error_;
@@ -45,14 +45,27 @@
uint64_t offset;
};
- DwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrame<AddressType>(memory) {}
+ DwarfEhFrameWithHdr(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
virtual ~DwarfEhFrameWithHdr() = default;
+ uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
+ return this->memory_.cur_offset() - pointer - 4;
+ }
+
+ uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
+ return this->memory_.cur_offset() - pointer - 8;
+ }
+
+ uint64_t AdjustPcFromFde(uint64_t pc) override {
+ // The eh_frame uses relative pcs.
+ return pc + this->memory_.cur_offset() - 4;
+ }
+
bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
- bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
+ const DwarfFde* GetFdeFromPc(uint64_t pc) override;
- const DwarfFde* GetFdeFromIndex(size_t index) override;
+ bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset);
const FdeInfo* GetFdeInfoFromIndex(size_t index);
@@ -60,6 +73,8 @@
bool GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset, uint64_t total_entries);
+ void GetFdes(std::vector<const DwarfFde*>* fdes) override;
+
protected:
uint8_t version_;
uint8_t ptr_encoding_;
@@ -71,6 +86,7 @@
uint64_t entries_data_offset_;
uint64_t cur_entries_offset_ = 0;
+ uint64_t fde_count_;
std::unordered_map<uint64_t, FdeInfo> fde_info_;
};
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index eb83949..6061f61 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -36,24 +36,6 @@
DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}
-const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
- uint64_t fde_offset;
- if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
- return nullptr;
- }
- const DwarfFde* fde = GetFdeFromOffset(fde_offset);
- if (fde == nullptr) {
- return nullptr;
- }
-
- // Guaranteed pc >= pc_start, need to check pc in the fde range.
- if (pc < fde->pc_end) {
- return fde;
- }
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return nullptr;
-}
-
bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
// Lookup the pc in the cache.
auto it = loc_regs_.upper_bound(pc);
@@ -81,6 +63,314 @@
}
template <typename AddressType>
+const DwarfCie* DwarfSectionImpl<AddressType>::GetCieFromOffset(uint64_t offset) {
+ auto cie_entry = cie_entries_.find(offset);
+ if (cie_entry != cie_entries_.end()) {
+ return &cie_entry->second;
+ }
+ DwarfCie* cie = &cie_entries_[offset];
+ memory_.set_cur_offset(offset);
+ if (!FillInCieHeader(cie) || !FillInCie(cie)) {
+ // Erase the cached entry.
+ cie_entries_.erase(offset);
+ return nullptr;
+ }
+ return cie;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInCieHeader(DwarfCie* cie) {
+ cie->lsda_encoding = DW_EH_PE_omit;
+ uint32_t length32;
+ if (!memory_.ReadBytes(&length32, sizeof(length32))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ if (length32 == static_cast<uint32_t>(-1)) {
+ // 64 bit Cie
+ uint64_t length64;
+ if (!memory_.ReadBytes(&length64, sizeof(length64))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ cie->cfa_instructions_end = memory_.cur_offset() + length64;
+ cie->fde_address_encoding = DW_EH_PE_sdata8;
+
+ uint64_t cie_id;
+ if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ if (cie_id != cie64_value_) {
+ // This is not a Cie, something has gone horribly wrong.
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+ } else {
+ // 32 bit Cie
+ cie->cfa_instructions_end = memory_.cur_offset() + length32;
+ cie->fde_address_encoding = DW_EH_PE_sdata4;
+
+ uint32_t cie_id;
+ if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ if (cie_id != cie32_value_) {
+ // This is not a Cie, something has gone horribly wrong.
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+ }
+ return true;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
+ if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (cie->version != 1 && cie->version != 3 && cie->version != 4) {
+ // Unrecognized version.
+ last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
+ return false;
+ }
+
+ // Read the augmentation string.
+ char aug_value;
+ do {
+ if (!memory_.ReadBytes(&aug_value, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ cie->augmentation_string.push_back(aug_value);
+ } while (aug_value != '\0');
+
+ if (cie->version == 4) {
+ // Skip the Address Size field since we only use it for validation.
+ memory_.set_cur_offset(memory_.cur_offset() + 1);
+
+ // Segment Size
+ if (!memory_.ReadBytes(&cie->segment_size, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ }
+
+ // Code Alignment Factor
+ if (!memory_.ReadULEB128(&cie->code_alignment_factor)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ // Data Alignment Factor
+ if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (cie->version == 1) {
+ // Return Address is a single byte.
+ uint8_t return_address_register;
+ if (!memory_.ReadBytes(&return_address_register, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ cie->return_address_register = return_address_register;
+ } else if (!memory_.ReadULEB128(&cie->return_address_register)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (cie->augmentation_string[0] != 'z') {
+ cie->cfa_instructions_offset = memory_.cur_offset();
+ return true;
+ }
+
+ uint64_t aug_length;
+ if (!memory_.ReadULEB128(&aug_length)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ cie->cfa_instructions_offset = memory_.cur_offset() + aug_length;
+
+ for (size_t i = 1; i < cie->augmentation_string.size(); i++) {
+ switch (cie->augmentation_string[i]) {
+ case 'L':
+ if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ break;
+ case 'P': {
+ uint8_t encoding;
+ if (!memory_.ReadBytes(&encoding, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ memory_.set_pc_offset(pc_offset_);
+ if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ } break;
+ case 'R':
+ if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+template <typename AddressType>
+const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset) {
+ auto fde_entry = fde_entries_.find(offset);
+ if (fde_entry != fde_entries_.end()) {
+ return &fde_entry->second;
+ }
+ DwarfFde* fde = &fde_entries_[offset];
+ memory_.set_cur_offset(offset);
+ if (!FillInFdeHeader(fde) || !FillInFde(fde)) {
+ fde_entries_.erase(offset);
+ return nullptr;
+ }
+ return fde;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInFdeHeader(DwarfFde* fde) {
+ uint32_t length32;
+ if (!memory_.ReadBytes(&length32, sizeof(length32))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (length32 == static_cast<uint32_t>(-1)) {
+ // 64 bit Fde.
+ uint64_t length64;
+ if (!memory_.ReadBytes(&length64, sizeof(length64))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ fde->cfa_instructions_end = memory_.cur_offset() + length64;
+
+ uint64_t value64;
+ if (!memory_.ReadBytes(&value64, sizeof(value64))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ if (value64 == cie64_value_) {
+ // This is a Cie, this means something has gone wrong.
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+
+ // Get the Cie pointer, which is necessary to properly read the rest of
+ // of the Fde information.
+ fde->cie_offset = GetCieOffsetFromFde64(value64);
+ } else {
+ // 32 bit Fde.
+ fde->cfa_instructions_end = memory_.cur_offset() + length32;
+
+ uint32_t value32;
+ if (!memory_.ReadBytes(&value32, sizeof(value32))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ if (value32 == cie32_value_) {
+ // This is a Cie, this means something has gone wrong.
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+
+ // Get the Cie pointer, which is necessary to properly read the rest of
+ // of the Fde information.
+ fde->cie_offset = GetCieOffsetFromFde32(value32);
+ }
+ return true;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
+ uint64_t cur_offset = memory_.cur_offset();
+
+ const DwarfCie* cie = GetCieFromOffset(fde->cie_offset);
+ if (cie == nullptr) {
+ return false;
+ }
+ fde->cie = cie;
+
+ if (cie->segment_size != 0) {
+ // Skip over the segment selector for now.
+ cur_offset += cie->segment_size;
+ }
+ memory_.set_cur_offset(cur_offset);
+
+ // The load bias only applies to the start.
+ memory_.set_pc_offset(load_bias_);
+ bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start);
+ fde->pc_start = AdjustPcFromFde(fde->pc_start);
+
+ memory_.set_pc_offset(0);
+ if (!valid || !memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_end)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ fde->pc_end += fde->pc_start;
+
+ if (cie->augmentation_string.size() > 0 && cie->augmentation_string[0] == 'z') {
+ // Augmentation Size
+ uint64_t aug_length;
+ if (!memory_.ReadULEB128(&aug_length)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ uint64_t cur_offset = memory_.cur_offset();
+
+ memory_.set_pc_offset(pc_offset_);
+ if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ // Set our position to after all of the augmentation data.
+ memory_.set_cur_offset(cur_offset + aug_length);
+ }
+ fde->cfa_instructions_offset = memory_.cur_offset();
+
+ return true;
+}
+
+template <typename AddressType>
bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, Memory* regular_memory,
AddressType* value,
RegsInfo<AddressType>* regs_info,
@@ -260,307 +550,6 @@
}
template <typename AddressType>
-const DwarfCie* DwarfSectionImpl<AddressType>::GetCie(uint64_t offset) {
- auto cie_entry = cie_entries_.find(offset);
- if (cie_entry != cie_entries_.end()) {
- return &cie_entry->second;
- }
- DwarfCie* cie = &cie_entries_[offset];
- memory_.set_cur_offset(offset);
- if (!FillInCie(cie)) {
- // Erase the cached entry.
- cie_entries_.erase(offset);
- return nullptr;
- }
- return cie;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
- uint32_t length32;
- if (!memory_.ReadBytes(&length32, sizeof(length32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- // Set the default for the lsda encoding.
- cie->lsda_encoding = DW_EH_PE_omit;
-
- if (length32 == static_cast<uint32_t>(-1)) {
- // 64 bit Cie
- uint64_t length64;
- if (!memory_.ReadBytes(&length64, sizeof(length64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- cie->cfa_instructions_end = memory_.cur_offset() + length64;
- cie->fde_address_encoding = DW_EH_PE_sdata8;
-
- uint64_t cie_id;
- if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (cie_id != cie64_value_) {
- // This is not a Cie, something has gone horribly wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- } else {
- // 32 bit Cie
- cie->cfa_instructions_end = memory_.cur_offset() + length32;
- cie->fde_address_encoding = DW_EH_PE_sdata4;
-
- uint32_t cie_id;
- if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (cie_id != cie32_value_) {
- // This is not a Cie, something has gone horribly wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- }
-
- if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (cie->version != 1 && cie->version != 3 && cie->version != 4) {
- // Unrecognized version.
- last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
- return false;
- }
-
- // Read the augmentation string.
- char aug_value;
- do {
- if (!memory_.ReadBytes(&aug_value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- cie->augmentation_string.push_back(aug_value);
- } while (aug_value != '\0');
-
- if (cie->version == 4) {
- // Skip the Address Size field since we only use it for validation.
- memory_.set_cur_offset(memory_.cur_offset() + 1);
-
- // Segment Size
- if (!memory_.ReadBytes(&cie->segment_size, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- }
-
- // Code Alignment Factor
- if (!memory_.ReadULEB128(&cie->code_alignment_factor)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- // Data Alignment Factor
- if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (cie->version == 1) {
- // Return Address is a single byte.
- uint8_t return_address_register;
- if (!memory_.ReadBytes(&return_address_register, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- cie->return_address_register = return_address_register;
- } else if (!memory_.ReadULEB128(&cie->return_address_register)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (cie->augmentation_string[0] != 'z') {
- cie->cfa_instructions_offset = memory_.cur_offset();
- return true;
- }
-
- uint64_t aug_length;
- if (!memory_.ReadULEB128(&aug_length)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- cie->cfa_instructions_offset = memory_.cur_offset() + aug_length;
-
- for (size_t i = 1; i < cie->augmentation_string.size(); i++) {
- switch (cie->augmentation_string[i]) {
- case 'L':
- if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- break;
- case 'P': {
- uint8_t encoding;
- if (!memory_.ReadBytes(&encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- memory_.set_pc_offset(pc_offset_);
- if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } break;
- case 'R':
- if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- break;
- }
- }
- return true;
-}
-
-template <typename AddressType>
-const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset) {
- auto fde_entry = fde_entries_.find(offset);
- if (fde_entry != fde_entries_.end()) {
- return &fde_entry->second;
- }
- DwarfFde* fde = &fde_entries_[offset];
- memory_.set_cur_offset(offset);
- if (!FillInFde(fde)) {
- fde_entries_.erase(offset);
- return nullptr;
- }
- return fde;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
- uint32_t length32;
- if (!memory_.ReadBytes(&length32, sizeof(length32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (length32 == static_cast<uint32_t>(-1)) {
- // 64 bit Fde.
- uint64_t length64;
- if (!memory_.ReadBytes(&length64, sizeof(length64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- fde->cfa_instructions_end = memory_.cur_offset() + length64;
-
- uint64_t value64;
- if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (value64 == cie64_value_) {
- // This is a Cie, this means something has gone wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Get the Cie pointer, which is necessary to properly read the rest of
- // of the Fde information.
- fde->cie_offset = GetCieOffsetFromFde64(value64);
- } else {
- // 32 bit Fde.
- fde->cfa_instructions_end = memory_.cur_offset() + length32;
-
- uint32_t value32;
- if (!memory_.ReadBytes(&value32, sizeof(value32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (value32 == cie32_value_) {
- // This is a Cie, this means something has gone wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Get the Cie pointer, which is necessary to properly read the rest of
- // of the Fde information.
- fde->cie_offset = GetCieOffsetFromFde32(value32);
- }
- uint64_t cur_offset = memory_.cur_offset();
-
- const DwarfCie* cie = GetCie(fde->cie_offset);
- if (cie == nullptr) {
- return false;
- }
- fde->cie = cie;
-
- if (cie->segment_size != 0) {
- // Skip over the segment selector for now.
- cur_offset += cie->segment_size;
- }
- memory_.set_cur_offset(cur_offset);
-
- // The load bias only applies to the start.
- memory_.set_pc_offset(load_bias_);
- bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start);
- fde->pc_start = AdjustPcFromFde(fde->pc_start);
-
- memory_.set_pc_offset(0);
- if (!valid || !memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_end)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- fde->pc_end += fde->pc_start;
-
- if (cie->augmentation_string.size() > 0 && cie->augmentation_string[0] == 'z') {
- // Augmentation Size
- uint64_t aug_length;
- if (!memory_.ReadULEB128(&aug_length)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- uint64_t cur_offset = memory_.cur_offset();
-
- memory_.set_pc_offset(pc_offset_);
- if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- // Set our position to after all of the augmentation data.
- memory_.set_cur_offset(cur_offset + aug_length);
- }
- fde->cfa_instructions_offset = memory_.cur_offset();
-
- return true;
-}
-
-template <typename AddressType>
bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde,
dwarf_loc_regs_t* loc_regs) {
DwarfCfa<AddressType> cfa(&memory_, fde);
@@ -601,9 +590,10 @@
}
template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
+bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
load_bias_ = load_bias;
entries_offset_ = offset;
+ next_entries_offset_ = offset;
entries_end_ = offset + size;
memory_.clear_func_offset();
@@ -612,298 +602,213 @@
memory_.set_data_offset(offset);
pc_offset_ = offset;
- return CreateSortedFdeList();
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::GetCieInfo(uint8_t* segment_size, uint8_t* encoding) {
- uint8_t version;
- if (!memory_.ReadBytes(&version, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- // Read the augmentation string.
- std::vector<char> aug_string;
- char aug_value;
- bool get_encoding = false;
- do {
- if (!memory_.ReadBytes(&aug_value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (aug_value == 'R') {
- get_encoding = true;
- }
- aug_string.push_back(aug_value);
- } while (aug_value != '\0');
-
- if (version == 4) {
- // Skip the Address Size field.
- memory_.set_cur_offset(memory_.cur_offset() + 1);
-
- // Read the segment size.
- if (!memory_.ReadBytes(segment_size, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } else {
- *segment_size = 0;
- }
-
- if (aug_string[0] != 'z' || !get_encoding) {
- // No encoding
- return true;
- }
-
- // Skip code alignment factor
- uint8_t value;
- do {
- if (!memory_.ReadBytes(&value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } while (value & 0x80);
-
- // Skip data alignment factor
- do {
- if (!memory_.ReadBytes(&value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } while (value & 0x80);
-
- if (version == 1) {
- // Skip return address register.
- memory_.set_cur_offset(memory_.cur_offset() + 1);
- } else {
- // Skip return address register.
- do {
- if (!memory_.ReadBytes(&value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } while (value & 0x80);
- }
-
- // Skip the augmentation length.
- do {
- if (!memory_.ReadBytes(&value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } while (value & 0x80);
-
- for (size_t i = 1; i < aug_string.size(); i++) {
- if (aug_string[i] == 'R') {
- if (!memory_.ReadBytes(encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- // Got the encoding, that's all we are looking for.
- return true;
- } else if (aug_string[i] == 'L') {
- memory_.set_cur_offset(memory_.cur_offset() + 1);
- } else if (aug_string[i] == 'P') {
- uint8_t encoding;
- if (!memory_.ReadBytes(&encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- uint64_t value;
- memory_.set_pc_offset(pc_offset_);
- if (!memory_.template ReadEncodedValue<AddressType>(encoding, &value)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- }
- }
-
- // It should be impossible to get here.
- abort();
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::AddFdeInfo(uint64_t entry_offset, uint8_t segment_size,
- uint8_t encoding) {
- if (segment_size != 0) {
- memory_.set_cur_offset(memory_.cur_offset() + 1);
- }
-
- uint64_t start;
- memory_.set_pc_offset(load_bias_);
- bool valid = memory_.template ReadEncodedValue<AddressType>(encoding, &start);
- start = AdjustPcFromFde(start);
-
- uint64_t length;
- memory_.set_pc_offset(0);
- if (!valid || !memory_.template ReadEncodedValue<AddressType>(encoding, &length)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (length != 0) {
- fdes_.emplace_back(entry_offset, start, length);
- }
-
return true;
}
+// Create a cached version of the fde information such that it is a std::map
+// that is indexed by end pc and contains a pair that represents the start pc
+// followed by the fde object. The fde pointers are owned by fde_entries_
+// and not by the map object.
+// It is possible for an fde to be represented by multiple entries in
+// the map. This can happen if the the start pc and end pc overlap already
+// existing entries. For example, if there is already an entry of 0x400, 0x200,
+// and an fde has a start pc of 0x100 and end pc of 0x500, two new entries
+// will be added: 0x200, 0x100 and 0x500, 0x400.
template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::CreateSortedFdeList() {
- memory_.set_cur_offset(entries_offset_);
+void DwarfSectionImplNoHdr<AddressType>::InsertFde(const DwarfFde* fde) {
+ uint64_t start = fde->pc_start;
+ uint64_t end = fde->pc_end;
+ auto it = fdes_.upper_bound(start);
+ bool add_element = false;
+ while (it != fdes_.end() && start < end) {
+ if (add_element) {
+ add_element = false;
+ if (end < it->second.first) {
+ if (it->first == end) {
+ return;
+ }
+ fdes_[end] = std::make_pair(start, fde);
+ return;
+ }
+ if (start != it->second.first) {
+ fdes_[it->second.first] = std::make_pair(start, fde);
+ }
+ }
+ if (start < it->first) {
+ if (end < it->second.first) {
+ if (it->first != end) {
+ fdes_[end] = std::make_pair(start, fde);
+ }
+ return;
+ }
+ add_element = true;
+ }
+ start = it->first;
+ ++it;
+ }
+ if (start < end) {
+ fdes_[end] = std::make_pair(start, fde);
+ }
+}
- // Loop through all of the entries and read just enough to create
- // a sorted list of pcs.
- // This code assumes that first comes the cie, then the fdes that
- // it applies to.
- uint64_t cie_offset = 0;
- uint8_t address_encoding;
- uint8_t segment_size;
- while (memory_.cur_offset() < entries_end_) {
- uint64_t cur_entry_offset = memory_.cur_offset();
+template <typename AddressType>
+bool DwarfSectionImplNoHdr<AddressType>::GetNextCieOrFde(DwarfFde** fde_entry) {
+ uint64_t start_offset = next_entries_offset_;
- // Figure out the entry length and type.
- uint32_t value32;
+ memory_.set_cur_offset(next_entries_offset_);
+ uint32_t value32;
+ if (!memory_.ReadBytes(&value32, sizeof(value32))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ uint64_t cie_offset;
+ uint8_t cie_fde_encoding;
+ bool entry_is_cie = false;
+ if (value32 == static_cast<uint32_t>(-1)) {
+ // 64 bit entry.
+ uint64_t value64;
+ if (!memory_.ReadBytes(&value64, sizeof(value64))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ next_entries_offset_ = memory_.cur_offset() + value64;
+ // Read the Cie Id of a Cie or the pointer of the Fde.
+ if (!memory_.ReadBytes(&value64, sizeof(value64))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (value64 == cie64_value_) {
+ entry_is_cie = true;
+ cie_fde_encoding = DW_EH_PE_sdata8;
+ } else {
+ cie_offset = this->GetCieOffsetFromFde64(value64);
+ }
+ } else {
+ next_entries_offset_ = memory_.cur_offset() + value32;
+
+ // 32 bit Cie
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
return false;
}
- uint64_t next_entry_offset;
- if (value32 == static_cast<uint32_t>(-1)) {
- uint64_t value64;
- if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- next_entry_offset = memory_.cur_offset() + value64;
-
- // Read the Cie Id of a Cie or the pointer of the Fde.
- if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (value64 == cie64_value_) {
- // Cie 64 bit
- address_encoding = DW_EH_PE_sdata8;
- if (!GetCieInfo(&segment_size, &address_encoding)) {
- return false;
- }
- cie_offset = cur_entry_offset;
- } else {
- uint64_t last_cie_offset = GetCieOffsetFromFde64(value64);
- if (last_cie_offset != cie_offset) {
- // This means that this Fde is not following the Cie.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Fde 64 bit
- if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
- return false;
- }
- }
+ if (value32 == cie32_value_) {
+ entry_is_cie = true;
+ cie_fde_encoding = DW_EH_PE_sdata4;
} else {
- next_entry_offset = memory_.cur_offset() + value32;
-
- // Read the Cie Id of a Cie or the pointer of the Fde.
- if (!memory_.ReadBytes(&value32, sizeof(value32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (value32 == cie32_value_) {
- // Cie 32 bit
- address_encoding = DW_EH_PE_sdata4;
- if (!GetCieInfo(&segment_size, &address_encoding)) {
- return false;
- }
- cie_offset = cur_entry_offset;
- } else {
- uint64_t last_cie_offset = GetCieOffsetFromFde32(value32);
- if (last_cie_offset != cie_offset) {
- // This means that this Fde is not following the Cie.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Fde 32 bit
- if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
- return false;
- }
- }
+ cie_offset = this->GetCieOffsetFromFde32(value32);
}
-
- if (next_entry_offset < memory_.cur_offset()) {
- // Simply consider the processing done in this case.
- break;
- }
- memory_.set_cur_offset(next_entry_offset);
}
- // Sort the entries.
- std::sort(fdes_.begin(), fdes_.end(), [](const FdeInfo& a, const FdeInfo& b) {
- if (a.start == b.start) return a.end < b.end;
- return a.start < b.start;
- });
+ if (entry_is_cie) {
+ DwarfCie* cie = &cie_entries_[start_offset];
+ cie->lsda_encoding = DW_EH_PE_omit;
+ cie->cfa_instructions_end = next_entries_offset_;
+ cie->fde_address_encoding = cie_fde_encoding;
- fde_count_ = fdes_.size();
+ if (!this->FillInCie(cie)) {
+ cie_entries_.erase(start_offset);
+ return false;
+ }
+ *fde_entry = nullptr;
+ } else {
+ DwarfFde* fde = &fde_entries_[start_offset];
+ fde->cfa_instructions_end = next_entries_offset_;
+ fde->cie_offset = cie_offset;
+ if (!this->FillInFde(fde)) {
+ fde_entries_.erase(start_offset);
+ return false;
+ }
+ *fde_entry = fde;
+ }
return true;
}
template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
- if (fde_count_ == 0) {
- return false;
- }
-
- size_t first = 0;
- size_t last = fde_count_;
- while (first < last) {
- size_t current = (first + last) / 2;
- const FdeInfo* info = &fdes_[current];
- if (pc >= info->start && pc < info->end) {
- *fde_offset = info->offset;
- return true;
- }
-
- if (pc < info->start) {
- last = current;
+void DwarfSectionImplNoHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
+ // Loop through the already cached entries.
+ uint64_t entry_offset = entries_offset_;
+ while (entry_offset < next_entries_offset_) {
+ auto cie_it = cie_entries_.find(entry_offset);
+ if (cie_it != cie_entries_.end()) {
+ entry_offset = cie_it->second.cfa_instructions_end;
} else {
- first = current + 1;
+ auto fde_it = fde_entries_.find(entry_offset);
+ if (fde_it == fde_entries_.end()) {
+ // No fde or cie at this entry, should not be possible.
+ return;
+ }
+ entry_offset = fde_it->second.cfa_instructions_end;
+ fdes->push_back(&fde_it->second);
}
}
- return false;
+
+ while (next_entries_offset_ < entries_end_) {
+ DwarfFde* fde;
+ if (!GetNextCieOrFde(&fde)) {
+ break;
+ }
+ if (fde != nullptr) {
+ InsertFde(fde);
+ fdes->push_back(fde);
+ }
+
+ if (next_entries_offset_ < memory_.cur_offset()) {
+ // Simply consider the processing done in this case.
+ break;
+ }
+ }
}
template <typename AddressType>
-const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromIndex(size_t index) {
- if (index >= fdes_.size()) {
- return nullptr;
+const DwarfFde* DwarfSectionImplNoHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
+ // Search in the list of fdes we already have.
+ auto it = fdes_.upper_bound(pc);
+ if (it != fdes_.end()) {
+ if (pc >= it->second.first) {
+ return it->second.second;
+ }
}
- return this->GetFdeFromOffset(fdes_[index].offset);
+
+ // The section might have overlapping pcs in fdes, so it is necessary
+ // to do a linear search of the fdes by pc. As fdes are read, a cached
+ // search map is created.
+ while (next_entries_offset_ < entries_end_) {
+ DwarfFde* fde;
+ if (!GetNextCieOrFde(&fde)) {
+ return nullptr;
+ }
+ if (fde != nullptr) {
+ InsertFde(fde);
+ if (pc >= fde->pc_start && pc < fde->pc_end) {
+ return fde;
+ }
+ }
+
+ if (next_entries_offset_ < memory_.cur_offset()) {
+ // Simply consider the processing done in this case.
+ break;
+ }
+ }
+ return nullptr;
}
// Explicitly instantiate DwarfSectionImpl
template class DwarfSectionImpl<uint32_t>;
template class DwarfSectionImpl<uint64_t>;
+// Explicitly instantiate DwarfSectionImplNoHdr
+template class DwarfSectionImplNoHdr<uint32_t>;
+template class DwarfSectionImplNoHdr<uint64_t>;
+
// Explicitly instantiate DwarfDebugFrame
template class DwarfDebugFrame<uint32_t>;
template class DwarfDebugFrame<uint64_t>;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 915cddb..2c00456 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -204,49 +204,19 @@
uint64_t offset = ehdr.e_phoff;
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
PhdrType phdr;
- if (!memory_->ReadField(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
+ if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address =
- offset + reinterpret_cast<uintptr_t>(&phdr.p_type) - reinterpret_cast<uintptr_t>(&phdr);
+ last_error_.address = offset;
return false;
}
- if (HandleType(offset, phdr.p_type)) {
- continue;
- }
-
switch (phdr.p_type) {
case PT_LOAD:
{
- // Get the flags first, if this isn't an executable header, ignore it.
- if (!memory_->ReadField(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_flags) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
if ((phdr.p_flags & PF_X) == 0) {
continue;
}
- if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_vaddr) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
- if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
- if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
static_cast<size_t>(phdr.p_memsz)};
if (phdr.p_offset == 0) {
@@ -256,46 +226,20 @@
}
case PT_GNU_EH_FRAME:
- if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
// This is really the pointer to the .eh_frame_hdr section.
eh_frame_hdr_offset_ = phdr.p_offset;
- if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
eh_frame_hdr_size_ = phdr.p_memsz;
break;
case PT_DYNAMIC:
- if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_offset) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
dynamic_offset_ = phdr.p_offset;
- if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_vaddr) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
dynamic_vaddr_ = phdr.p_vaddr;
- if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset + reinterpret_cast<uintptr_t>(&phdr.p_memsz) -
- reinterpret_cast<uintptr_t>(&phdr);
- return false;
- }
dynamic_size_ = phdr.p_memsz;
break;
+
+ default:
+ HandleUnknownType(phdr.p_type, phdr.p_offset, phdr.p_filesz);
+ break;
}
}
return true;
@@ -313,8 +257,7 @@
ShdrType shdr;
if (ehdr.e_shstrndx < ehdr.e_shnum) {
uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
- if (memory_->ReadField(sh_offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
- memory_->ReadField(sh_offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
+ if (memory_->ReadFully(sh_offset, &shdr, sizeof(shdr))) {
sec_offset = shdr.sh_offset;
sec_size = shdr.sh_size;
}
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index a3244e8..3dd5d54 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -87,23 +87,17 @@
#define PT_ARM_EXIDX 0x70000001
#endif
-bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type) {
+void ElfInterfaceArm::HandleUnknownType(uint32_t type, uint64_t ph_offset, uint64_t ph_filesz) {
if (type != PT_ARM_EXIDX) {
- return false;
- }
-
- Elf32_Phdr phdr;
- if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
- return true;
+ return;
}
// The offset already takes into account the load bias.
- start_offset_ = phdr.p_offset;
+ start_offset_ = ph_offset;
// Always use filesz instead of memsz. In most cases they are the same,
// but some shared libraries wind up setting one correctly and not the other.
- total_entries_ = phdr.p_filesz / 8;
- return true;
+ total_entries_ = ph_filesz / 8;
}
bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index 3bee9cf..4c3a0c3 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -70,7 +70,7 @@
bool FindEntry(uint32_t pc, uint64_t* entry_offset);
- bool HandleType(uint64_t offset, uint32_t type) override;
+ void HandleUnknownType(uint32_t type, uint64_t ph_offset, uint64_t ph_filesz) override;
bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 847f382..e9942de 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -43,7 +43,12 @@
class iterator : public std::iterator<std::bidirectional_iterator_tag, DwarfFde*> {
public:
- iterator(DwarfSection* section, size_t index) : section_(section), index_(index) {}
+ iterator(DwarfSection* section, size_t index) : index_(index) {
+ section->GetFdes(&fdes_);
+ if (index_ == static_cast<size_t>(-1)) {
+ index_ = fdes_.size();
+ }
+ }
iterator& operator++() {
index_++;
@@ -65,15 +70,18 @@
bool operator==(const iterator& rhs) { return this->index_ == rhs.index_; }
bool operator!=(const iterator& rhs) { return this->index_ != rhs.index_; }
- const DwarfFde* operator*() { return section_->GetFdeFromIndex(index_); }
+ const DwarfFde* operator*() {
+ if (index_ > fdes_.size()) return nullptr;
+ return fdes_[index_];
+ }
private:
- DwarfSection* section_ = nullptr;
+ std::vector<const DwarfFde*> fdes_;
size_t index_ = 0;
};
iterator begin() { return iterator(this, 0); }
- iterator end() { return iterator(this, fde_count_); }
+ iterator end() { return iterator(this, static_cast<size_t>(-1)); }
DwarfErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
@@ -82,15 +90,11 @@
virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*) = 0;
- virtual bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) = 0;
-
virtual bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) = 0;
- virtual const DwarfFde* GetFdeFromIndex(size_t index) = 0;
+ virtual void GetFdes(std::vector<const DwarfFde*>* fdes) = 0;
- const DwarfFde* GetFdeFromPc(uint64_t pc);
-
- virtual const DwarfFde* GetFdeFromOffset(uint64_t fde_offset) = 0;
+ virtual const DwarfFde* GetFdeFromPc(uint64_t pc) = 0;
virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) = 0;
@@ -109,7 +113,6 @@
uint32_t cie32_value_ = 0;
uint64_t cie64_value_ = 0;
- uint64_t fde_count_ = 0;
std::unordered_map<uint64_t, DwarfFde> fde_entries_;
std::unordered_map<uint64_t, DwarfCie> cie_entries_;
std::unordered_map<uint64_t, dwarf_loc_regs_t> cie_loc_regs_;
@@ -119,55 +122,73 @@
template <typename AddressType>
class DwarfSectionImpl : public DwarfSection {
public:
- struct FdeInfo {
- FdeInfo(uint64_t offset, uint64_t start, uint64_t length)
- : offset(offset), start(start), end(start + length) {}
-
- uint64_t offset;
- AddressType start;
- AddressType end;
- };
-
DwarfSectionImpl(Memory* memory) : DwarfSection(memory) {}
virtual ~DwarfSectionImpl() = default;
- bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
+ const DwarfCie* GetCieFromOffset(uint64_t offset);
- bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
-
- const DwarfFde* GetFdeFromIndex(size_t index) override;
+ const DwarfFde* GetFdeFromOffset(uint64_t offset);
bool EvalRegister(const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr, void* info);
bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
Regs* regs, bool* finished) override;
- const DwarfCie* GetCie(uint64_t offset);
- bool FillInCie(DwarfCie* cie);
-
- const DwarfFde* GetFdeFromOffset(uint64_t offset) override;
- bool FillInFde(DwarfFde* fde);
-
bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) override;
bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) override;
protected:
+ bool FillInCieHeader(DwarfCie* cie);
+
+ bool FillInCie(DwarfCie* cie);
+
+ bool FillInFdeHeader(DwarfFde* fde);
+
+ bool FillInFde(DwarfFde* fde);
+
bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
RegsInfo<AddressType>* regs_info, bool* is_dex_pc);
- bool GetCieInfo(uint8_t* segment_size, uint8_t* encoding);
-
- bool AddFdeInfo(uint64_t entry_offset, uint8_t segment_size, uint8_t encoding);
-
- bool CreateSortedFdeList();
-
uint64_t load_bias_ = 0;
+ uint64_t entries_offset_ = 0;
+ uint64_t entries_end_ = 0;
uint64_t pc_offset_ = 0;
+};
- std::vector<FdeInfo> fdes_;
- uint64_t entries_offset_;
- uint64_t entries_end_;
+template <typename AddressType>
+class DwarfSectionImplNoHdr : public DwarfSectionImpl<AddressType> {
+ public:
+ // Add these so that the protected members of DwarfSectionImpl
+ // can be accessed without needing a this->.
+ using DwarfSectionImpl<AddressType>::memory_;
+ using DwarfSectionImpl<AddressType>::pc_offset_;
+ using DwarfSectionImpl<AddressType>::entries_offset_;
+ using DwarfSectionImpl<AddressType>::entries_end_;
+ using DwarfSectionImpl<AddressType>::last_error_;
+ using DwarfSectionImpl<AddressType>::load_bias_;
+ using DwarfSectionImpl<AddressType>::cie_entries_;
+ using DwarfSectionImpl<AddressType>::fde_entries_;
+ using DwarfSectionImpl<AddressType>::cie32_value_;
+ using DwarfSectionImpl<AddressType>::cie64_value_;
+
+ DwarfSectionImplNoHdr(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
+ virtual ~DwarfSectionImplNoHdr() = default;
+
+ bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
+
+ const DwarfFde* GetFdeFromPc(uint64_t pc) override;
+
+ void GetFdes(std::vector<const DwarfFde*>* fdes) override;
+
+ protected:
+ bool GetNextCieOrFde(DwarfFde** fde_entry);
+
+ void InsertFde(const DwarfFde* fde);
+
+ uint64_t next_entries_offset_ = 0;
+
+ std::map<uint64_t, std::pair<uint64_t, const DwarfFde*>> fdes_;
};
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 0c588da..5c1210d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -118,7 +118,7 @@
template <typename SymType>
bool GetGlobalVariableWithTemplate(const std::string& name, uint64_t* memory_address);
- virtual bool HandleType(uint64_t, uint32_t) { return false; }
+ virtual void HandleUnknownType(uint32_t, uint64_t, uint64_t) {}
template <typename EhdrType>
static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index c0c07f4..dee5e98 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -41,18 +41,6 @@
bool ReadFully(uint64_t addr, void* dst, size_t size);
- inline bool ReadField(uint64_t addr, void* start, void* field, size_t size) {
- if (reinterpret_cast<uintptr_t>(field) < reinterpret_cast<uintptr_t>(start)) {
- return false;
- }
- uint64_t offset = reinterpret_cast<uintptr_t>(field) - reinterpret_cast<uintptr_t>(start);
- if (__builtin_add_overflow(addr, offset, &offset)) {
- return false;
- }
- // The read will check if offset + size overflows.
- return ReadFully(offset, field, size);
- }
-
inline bool Read32(uint64_t addr, uint32_t* dst) {
return ReadFully(addr, dst, sizeof(uint32_t));
}
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 3a52044..d620934 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -16,7 +16,8 @@
#include <stdint.h>
-#include <gmock/gmock.h>
+#include <vector>
+
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
@@ -30,480 +31,377 @@
namespace unwindstack {
template <typename TypeParam>
-class MockDwarfDebugFrame : public DwarfDebugFrame<TypeParam> {
- public:
- MockDwarfDebugFrame(Memory* memory) : DwarfDebugFrame<TypeParam>(memory) {}
- ~MockDwarfDebugFrame() = default;
-
- void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
- void TestSetOffset(uint64_t offset) { this->entries_offset_ = offset; }
- void TestSetEndOffset(uint64_t offset) { this->entries_end_ = offset; }
- void TestPushFdeInfo(const typename DwarfDebugFrame<TypeParam>::FdeInfo& info) {
- this->fdes_.push_back(info);
- }
-
- uint64_t TestGetFdeCount() { return this->fde_count_; }
- uint8_t TestGetOffset() { return this->offset_; }
- uint8_t TestGetEndOffset() { return this->end_offset_; }
- void TestGetFdeInfo(size_t index, typename DwarfDebugFrame<TypeParam>::FdeInfo* info) {
- *info = this->fdes_[index];
- }
-};
-
-template <typename TypeParam>
class DwarfDebugFrameTest : public ::testing::Test {
protected:
void SetUp() override {
memory_.Clear();
- debug_frame_ = new MockDwarfDebugFrame<TypeParam>(&memory_);
+ debug_frame_ = new DwarfDebugFrame<TypeParam>(&memory_);
ResetLogs();
}
void TearDown() override { delete debug_frame_; }
MemoryFake memory_;
- MockDwarfDebugFrame<TypeParam>* debug_frame_ = nullptr;
+ DwarfDebugFrame<TypeParam>* debug_frame_ = nullptr;
};
TYPED_TEST_CASE_P(DwarfDebugFrameTest);
// NOTE: All test class variables need to be referenced as this->.
-TYPED_TEST_P(DwarfDebugFrameTest, Init32) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, '\0');
+static void SetCie32(MemoryFake* memory, uint64_t offset, uint32_t length,
+ std::vector<uint8_t> data) {
+ memory->SetData32(offset, length);
+ offset += 4;
+ // Indicates this is a cie.
+ memory->SetData32(offset, 0xffffffff);
+ offset += 4;
+ memory->SetMemory(offset, data);
+}
+
+static void SetCie64(MemoryFake* memory, uint64_t offset, uint64_t length,
+ std::vector<uint8_t> data) {
+ memory->SetData32(offset, 0xffffffff);
+ offset += 4;
+ memory->SetData64(offset, length);
+ offset += 8;
+ // Indicates this is a cie.
+ memory->SetData64(offset, 0xffffffffffffffffUL);
+ offset += 8;
+ memory->SetMemory(offset, data);
+}
+
+static void SetFde32(MemoryFake* memory, uint64_t offset, uint32_t length, uint64_t cie_offset,
+ uint32_t pc_start, uint32_t pc_length, uint64_t segment_length = 0,
+ std::vector<uint8_t>* data = nullptr) {
+ memory->SetData32(offset, length);
+ offset += 4;
+ memory->SetData32(offset, cie_offset);
+ offset += 4 + segment_length;
+ memory->SetData32(offset, pc_start);
+ offset += 4;
+ memory->SetData32(offset, pc_length);
+ if (data != nullptr) {
+ offset += 4;
+ memory->SetMemory(offset, *data);
+ }
+}
+
+static void SetFde64(MemoryFake* memory, uint64_t offset, uint64_t length, uint64_t cie_offset,
+ uint64_t pc_start, uint64_t pc_length, uint64_t segment_length = 0,
+ std::vector<uint8_t>* data = nullptr) {
+ memory->SetData32(offset, 0xffffffff);
+ offset += 4;
+ memory->SetData64(offset, length);
+ offset += 8;
+ memory->SetData64(offset, cie_offset);
+ offset += 8 + segment_length;
+ memory->SetData64(offset, pc_start);
+ offset += 8;
+ memory->SetData64(offset, pc_length);
+ if (data != nullptr) {
+ offset += 8;
+ memory->SetMemory(offset, *data);
+ }
+}
+
+static void SetFourFdes32(MemoryFake* memory) {
+ SetCie32(memory, 0x5000, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
// FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
-
- this->memory_.SetData32(0x5200, 0xfc);
- this->memory_.SetData32(0x5204, 0);
- this->memory_.SetData32(0x5208, 0x2500);
- this->memory_.SetData32(0x520c, 0x300);
+ SetFde32(memory, 0x5100, 0xfc, 0, 0x1500, 0x200);
+ SetFde32(memory, 0x5200, 0xfc, 0, 0x2500, 0x300);
// CIE 32 information.
- this->memory_.SetData32(0x5300, 0xfc);
- this->memory_.SetData32(0x5304, 0xffffffff);
- this->memory_.SetData8(0x5308, 1);
- this->memory_.SetData8(0x5309, '\0');
+ SetCie32(memory, 0x5300, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
// FDE 32 information.
- this->memory_.SetData32(0x5400, 0xfc);
- this->memory_.SetData32(0x5404, 0x300);
- this->memory_.SetData32(0x5408, 0x3500);
- this->memory_.SetData32(0x540c, 0x400);
+ SetFde32(memory, 0x5400, 0xfc, 0x300, 0x3500, 0x400);
+ SetFde32(memory, 0x5500, 0xfc, 0x300, 0x4500, 0x500);
+}
- this->memory_.SetData32(0x5500, 0xfc);
- this->memory_.SetData32(0x5504, 0x300);
- this->memory_.SetData32(0x5508, 0x4500);
- this->memory_.SetData32(0x550c, 0x500);
-
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32) {
+ SetFourFdes32(&this->memory_);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(4U, this->debug_frame_->TestGetFdeCount());
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
- this->debug_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x1500U, info.start);
- EXPECT_EQ(0x1700U, info.end);
+ ASSERT_EQ(4U, fdes.size());
- this->debug_frame_->TestGetFdeInfo(1, &info);
- EXPECT_EQ(0x5200U, info.offset);
- EXPECT_EQ(0x2500U, info.start);
- EXPECT_EQ(0x2800U, info.end);
+ EXPECT_EQ(0x5000U, fdes[0]->cie_offset);
+ EXPECT_EQ(0x5110U, fdes[0]->cfa_instructions_offset);
+ EXPECT_EQ(0x5200U, fdes[0]->cfa_instructions_end);
+ EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+ EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+ EXPECT_EQ(0U, fdes[0]->lsda_address);
+ EXPECT_TRUE(fdes[0]->cie != nullptr);
- this->debug_frame_->TestGetFdeInfo(2, &info);
- EXPECT_EQ(0x5400U, info.offset);
- EXPECT_EQ(0x3500U, info.start);
- EXPECT_EQ(0x3900U, info.end);
+ EXPECT_EQ(0x5000U, fdes[1]->cie_offset);
+ EXPECT_EQ(0x5210U, fdes[1]->cfa_instructions_offset);
+ EXPECT_EQ(0x5300U, fdes[1]->cfa_instructions_end);
+ EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+ EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+ EXPECT_EQ(0U, fdes[1]->lsda_address);
+ EXPECT_TRUE(fdes[1]->cie != nullptr);
- this->debug_frame_->TestGetFdeInfo(3, &info);
- EXPECT_EQ(0x5500U, info.offset);
- EXPECT_EQ(0x4500U, info.start);
- EXPECT_EQ(0x4a00U, info.end);
+ EXPECT_EQ(0x5300U, fdes[2]->cie_offset);
+ EXPECT_EQ(0x5410U, fdes[2]->cfa_instructions_offset);
+ EXPECT_EQ(0x5500U, fdes[2]->cfa_instructions_end);
+ EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+ EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+ EXPECT_EQ(0U, fdes[2]->lsda_address);
+ EXPECT_TRUE(fdes[2]->cie != nullptr);
+
+ EXPECT_EQ(0x5300U, fdes[3]->cie_offset);
+ EXPECT_EQ(0x5510U, fdes[3]->cfa_instructions_offset);
+ EXPECT_EQ(0x5600U, fdes[3]->cfa_instructions_end);
+ EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+ EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
+ EXPECT_EQ(0U, fdes[3]->lsda_address);
+ EXPECT_TRUE(fdes[3]->cie != nullptr);
}
-TYPED_TEST_P(DwarfDebugFrameTest, Init32_fde_not_following_cie) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, '\0');
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x1000);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
-
- ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init32_do_not_fail_on_bad_next_entry) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, '\0');
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
-
- this->memory_.SetData32(0x5200, 0xfc);
- this->memory_.SetData32(0x5204, 0);
- this->memory_.SetData32(0x5208, 0x2500);
- this->memory_.SetData32(0x520c, 0x300);
-
- // CIE 32 information.
- this->memory_.SetData32(0x5300, 0);
- this->memory_.SetData32(0x5304, 0xffffffff);
- this->memory_.SetData8(0x5308, 1);
- this->memory_.SetData8(0x5309, '\0');
-
- // FDE 32 information.
- this->memory_.SetData32(0x5400, 0xfc);
- this->memory_.SetData32(0x5404, 0x300);
- this->memory_.SetData32(0x5408, 0x3500);
- this->memory_.SetData32(0x540c, 0x400);
-
- this->memory_.SetData32(0x5500, 0xfc);
- this->memory_.SetData32(0x5504, 0x300);
- this->memory_.SetData32(0x5508, 0x4500);
- this->memory_.SetData32(0x550c, 0x500);
-
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32_after_GetFdeFromPc) {
+ SetFourFdes32(&this->memory_);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x3600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x3500U, fde->pc_start);
+ EXPECT_EQ(0x3900U, fde->pc_end);
+
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
+ ASSERT_EQ(4U, fdes.size());
+
+ // Verify that they got added in the correct order.
+ EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+ EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+ EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+ EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+ EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+ EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+ EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+ EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
}
-TYPED_TEST_P(DwarfDebugFrameTest, Init64) {
- // CIE 64 information.
- this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xf4);
- this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x5014, 1);
- this->memory_.SetData8(0x5015, '\0');
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32_not_in_section) {
+ SetFourFdes32(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
- // FDE 64 information.
- this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xf4);
- this->memory_.SetData64(0x510c, 0);
- this->memory_.SetData64(0x5114, 0x1500);
- this->memory_.SetData64(0x511c, 0x200);
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
- this->memory_.SetData32(0x5200, 0xffffffff);
- this->memory_.SetData64(0x5204, 0xf4);
- this->memory_.SetData64(0x520c, 0);
- this->memory_.SetData64(0x5214, 0x2500);
- this->memory_.SetData64(0x521c, 0x300);
+ ASSERT_EQ(3U, fdes.size());
+}
- // CIE 64 information.
- this->memory_.SetData32(0x5300, 0xffffffff);
- this->memory_.SetData64(0x5304, 0xf4);
- this->memory_.SetData64(0x530c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x5314, 1);
- this->memory_.SetData8(0x5315, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5400, 0xffffffff);
- this->memory_.SetData64(0x5404, 0xf4);
- this->memory_.SetData64(0x540c, 0x300);
- this->memory_.SetData64(0x5414, 0x3500);
- this->memory_.SetData64(0x541c, 0x400);
-
- this->memory_.SetData32(0x5500, 0xffffffff);
- this->memory_.SetData64(0x5504, 0xf4);
- this->memory_.SetData64(0x550c, 0x300);
- this->memory_.SetData64(0x5514, 0x4500);
- this->memory_.SetData64(0x551c, 0x500);
-
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32) {
+ SetFourFdes32(&this->memory_);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(4U, this->debug_frame_->TestGetFdeCount());
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x1600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x1500U, fde->pc_start);
- this->debug_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x1500U, info.start);
- EXPECT_EQ(0x1700U, info.end);
-
- this->debug_frame_->TestGetFdeInfo(1, &info);
- EXPECT_EQ(0x5200U, info.offset);
- EXPECT_EQ(0x2500U, info.start);
- EXPECT_EQ(0x2800U, info.end);
-
- this->debug_frame_->TestGetFdeInfo(2, &info);
- EXPECT_EQ(0x5400U, info.offset);
- EXPECT_EQ(0x3500U, info.start);
- EXPECT_EQ(0x3900U, info.end);
-
- this->debug_frame_->TestGetFdeInfo(3, &info);
- EXPECT_EQ(0x5500U, info.offset);
- EXPECT_EQ(0x4500U, info.start);
- EXPECT_EQ(0x4a00U, info.end);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init64_fde_not_following_cie) {
- // CIE 64 information.
- this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xf4);
- this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x5014, 1);
- this->memory_.SetData8(0x5015, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xf4);
- this->memory_.SetData64(0x510c, 0x1000);
- this->memory_.SetData64(0x5114, 0x1500);
- this->memory_.SetData64(0x511c, 0x200);
-
- ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init64_do_not_fail_on_bad_next_entry) {
- // CIE 64 information.
- this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xf4);
- this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x5014, 1);
- this->memory_.SetData8(0x5015, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xf4);
- this->memory_.SetData64(0x510c, 0);
- this->memory_.SetData64(0x5114, 0x1500);
- this->memory_.SetData64(0x511c, 0x200);
-
- this->memory_.SetData32(0x5200, 0xffffffff);
- this->memory_.SetData64(0x5204, 0xf4);
- this->memory_.SetData64(0x520c, 0);
- this->memory_.SetData64(0x5214, 0x2500);
- this->memory_.SetData64(0x521c, 0x300);
-
- // CIE 64 information.
- this->memory_.SetData32(0x5300, 0xffffffff);
- this->memory_.SetData64(0x5304, 0);
- this->memory_.SetData64(0x530c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x5314, 1);
- this->memory_.SetData8(0x5315, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5400, 0xffffffff);
- this->memory_.SetData64(0x5404, 0xf4);
- this->memory_.SetData64(0x540c, 0x300);
- this->memory_.SetData64(0x5414, 0x3500);
- this->memory_.SetData64(0x541c, 0x400);
-
- this->memory_.SetData32(0x5500, 0xffffffff);
- this->memory_.SetData64(0x5504, 0xf4);
- this->memory_.SetData64(0x550c, 0x300);
- this->memory_.SetData64(0x5514, 0x4500);
- this->memory_.SetData64(0x551c, 0x500);
-
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init_non_zero_load_bias) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, 'z');
- this->memory_.SetData8(0x500a, 'R');
- this->memory_.SetData8(0x500b, '\0');
- this->memory_.SetData8(0x500c, 0);
- this->memory_.SetData8(0x500d, 0);
- this->memory_.SetData8(0x500e, 0);
- this->memory_.SetData8(0x500f, 0);
- this->memory_.SetData8(0x5010, 0x1b);
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
- this->memory_.SetData8(0x5110, 0);
- this->memory_.SetData8(0x5111, 0);
-
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0x1000));
- ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
-
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
-
- this->debug_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x2500U, info.start);
- EXPECT_EQ(0x2700U, info.end);
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x2504);
+ fde = this->debug_frame_->GetFdeFromPc(0x2600);
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x2500U, fde->pc_start);
- EXPECT_EQ(0x2700U, fde->pc_end);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x3600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x3500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x4500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0);
+ ASSERT_TRUE(fde == nullptr);
}
-TYPED_TEST_P(DwarfDebugFrameTest, Init_version1) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 1);
- // Augment string.
- this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'R', 'P', 'L', '\0'});
- // Code alignment factor.
- this->memory_.SetMemory(0x500e, std::vector<uint8_t>{0x80, 0x00});
- // Data alignment factor.
- this->memory_.SetMemory(0x5010, std::vector<uint8_t>{0x81, 0x80, 0x80, 0x00});
- // Return address register
- this->memory_.SetData8(0x5014, 0x84);
- // Augmentation length
- this->memory_.SetMemory(0x5015, std::vector<uint8_t>{0x84, 0x00});
- // R data.
- this->memory_.SetData8(0x5017, DW_EH_PE_pcrel | DW_EH_PE_udata2);
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32_reverse) {
+ SetFourFdes32(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0);
- this->memory_.SetData16(0x5108, 0x1500);
- this->memory_.SetData16(0x510a, 0x200);
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x4500U, fde->pc_start);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0));
- ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
+ fde = this->debug_frame_->GetFdeFromPc(0x3600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x3500U, fde->pc_start);
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
- this->debug_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x1500U, info.start);
- EXPECT_EQ(0x1700U, info.end);
+ fde = this->debug_frame_->GetFdeFromPc(0x2600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x2500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x1600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x1500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0);
+ ASSERT_TRUE(fde == nullptr);
}
-TYPED_TEST_P(DwarfDebugFrameTest, Init_version4) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 4);
- // Augment string.
- this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'L', 'P', 'R', '\0'});
- // Address size.
- this->memory_.SetData8(0x500e, 4);
- // Segment size.
- this->memory_.SetData8(0x500f, 0);
- // Code alignment factor.
- this->memory_.SetMemory(0x5010, std::vector<uint8_t>{0x80, 0x00});
- // Data alignment factor.
- this->memory_.SetMemory(0x5012, std::vector<uint8_t>{0x81, 0x80, 0x80, 0x00});
- // Return address register
- this->memory_.SetMemory(0x5016, std::vector<uint8_t>{0x85, 0x10});
- // Augmentation length
- this->memory_.SetMemory(0x5018, std::vector<uint8_t>{0x84, 0x00});
- // L data.
- this->memory_.SetData8(0x501a, 0x10);
- // P data.
- this->memory_.SetData8(0x501b, DW_EH_PE_udata4);
- this->memory_.SetData32(0x501c, 0x100);
- // R data.
- this->memory_.SetData8(0x5020, DW_EH_PE_pcrel | DW_EH_PE_udata2);
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32_not_in_section) {
+ SetFourFdes32(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0);
- this->memory_.SetData16(0x5108, 0x1500);
- this->memory_.SetData16(0x510a, 0x200);
-
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0));
- ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
-
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
- this->debug_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x1500U, info.start);
- EXPECT_EQ(0x1700U, info.end);
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde == nullptr);
}
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeOffsetFromPc) {
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
- for (size_t i = 0; i < 9; i++) {
- info.start = 0x1000 * (i + 1);
- info.end = 0x1000 * (i + 2) - 0x10;
- info.offset = 0x5000 + i * 0x20;
- this->debug_frame_->TestPushFdeInfo(info);
- }
+static void SetFourFdes64(MemoryFake* memory) {
+ // CIE 64 information.
+ SetCie64(memory, 0x5000, 0xf4, std::vector<uint8_t>{1, '\0', 0, 0, 1});
- this->debug_frame_->TestSetFdeCount(0);
- uint64_t fde_offset;
- ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ // FDE 64 information.
+ SetFde64(memory, 0x5100, 0xf4, 0, 0x1500, 0x200);
+ SetFde64(memory, 0x5200, 0xf4, 0, 0x2500, 0x300);
- this->debug_frame_->TestSetFdeCount(9);
- ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- // Odd number of elements.
- for (size_t i = 0; i < 9; i++) {
- TypeParam pc = 0x1000 * (i + 1);
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index "
- << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
- << "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- }
+ // CIE 64 information.
+ SetCie64(memory, 0x5300, 0xf4, std::vector<uint8_t>{1, '\0', 0, 0, 1});
- // Even number of elements.
- this->debug_frame_->TestSetFdeCount(10);
- info.start = 0xa000;
- info.end = 0xaff0;
- info.offset = 0x5120;
- this->debug_frame_->TestPushFdeInfo(info);
+ // FDE 64 information.
+ SetFde64(memory, 0x5400, 0xf4, 0x300, 0x3500, 0x400);
+ SetFde64(memory, 0x5500, 0xf4, 0x300, 0x4500, 0x500);
+}
- for (size_t i = 0; i < 10; i++) {
- TypeParam pc = 0x1000 * (i + 1);
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index "
- << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
- << "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- }
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
+
+ ASSERT_EQ(4U, fdes.size());
+
+ EXPECT_EQ(0x5000U, fdes[0]->cie_offset);
+ EXPECT_EQ(0x5124U, fdes[0]->cfa_instructions_offset);
+ EXPECT_EQ(0x5200U, fdes[0]->cfa_instructions_end);
+ EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+ EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+ EXPECT_EQ(0U, fdes[0]->lsda_address);
+ EXPECT_TRUE(fdes[0]->cie != nullptr);
+
+ EXPECT_EQ(0x5000U, fdes[1]->cie_offset);
+ EXPECT_EQ(0x5224U, fdes[1]->cfa_instructions_offset);
+ EXPECT_EQ(0x5300U, fdes[1]->cfa_instructions_end);
+ EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+ EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+ EXPECT_EQ(0U, fdes[1]->lsda_address);
+ EXPECT_TRUE(fdes[1]->cie != nullptr);
+
+ EXPECT_EQ(0x5300U, fdes[2]->cie_offset);
+ EXPECT_EQ(0x5424U, fdes[2]->cfa_instructions_offset);
+ EXPECT_EQ(0x5500U, fdes[2]->cfa_instructions_end);
+ EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+ EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+ EXPECT_EQ(0U, fdes[2]->lsda_address);
+ EXPECT_TRUE(fdes[2]->cie != nullptr);
+
+ EXPECT_EQ(0x5300U, fdes[3]->cie_offset);
+ EXPECT_EQ(0x5524U, fdes[3]->cfa_instructions_offset);
+ EXPECT_EQ(0x5600U, fdes[3]->cfa_instructions_end);
+ EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+ EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
+ EXPECT_EQ(0U, fdes[3]->lsda_address);
+ EXPECT_TRUE(fdes[3]->cie != nullptr);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64_after_GetFdeFromPc) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x2600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x2500U, fde->pc_start);
+ EXPECT_EQ(0x2800U, fde->pc_end);
+
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
+ ASSERT_EQ(4U, fdes.size());
+
+ // Verify that they got added in the correct order.
+ EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+ EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+ EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+ EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+ EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+ EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+ EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+ EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64_not_in_section) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
+
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
+
+ ASSERT_EQ(3U, fdes.size());
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x1600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x1500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x2600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x2500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x3600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x3500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x4500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0);
+ ASSERT_TRUE(fde == nullptr);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64_reverse) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x4500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x3600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x3500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x2600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x2500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x1600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x1500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0);
+ ASSERT_TRUE(fde == nullptr);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64_not_in_section) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde == nullptr);
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde32) {
- this->debug_frame_->TestSetOffset(0x4000);
-
- // CIE 32 information.
- this->memory_.SetData32(0xf000, 0x100);
- this->memory_.SetData32(0xf004, 0xffffffff);
- this->memory_.SetData8(0xf008, 0x1);
- this->memory_.SetData8(0xf009, '\0');
- this->memory_.SetData8(0xf00a, 4);
- this->memory_.SetData8(0xf00b, 8);
- this->memory_.SetData8(0xf00c, 0x20);
-
- // FDE 32 information.
- this->memory_.SetData32(0x14000, 0x20);
- this->memory_.SetData32(0x14004, 0xb000);
- this->memory_.SetData32(0x14008, 0x9000);
- this->memory_.SetData32(0x1400c, 0x100);
+ SetCie32(&this->memory_, 0xf000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ SetFde32(&this->memory_, 0x14000, 0x20, 0xf000, 0x9000, 0x100);
const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x14000);
ASSERT_TRUE(fde != nullptr);
@@ -530,24 +428,8 @@
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde64) {
- this->debug_frame_->TestSetOffset(0x2000);
-
- // CIE 64 information.
- this->memory_.SetData32(0x6000, 0xffffffff);
- this->memory_.SetData64(0x6004, 0x100);
- this->memory_.SetData64(0x600c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x6014, 0x1);
- this->memory_.SetData8(0x6015, '\0');
- this->memory_.SetData8(0x6016, 4);
- this->memory_.SetData8(0x6017, 8);
- this->memory_.SetData8(0x6018, 0x20);
-
- // FDE 64 information.
- this->memory_.SetData32(0x8000, 0xffffffff);
- this->memory_.SetData64(0x8004, 0x200);
- this->memory_.SetData64(0x800c, 0x4000);
- this->memory_.SetData64(0x8014, 0x5000);
- this->memory_.SetData64(0x801c, 0x300);
+ SetCie64(&this->memory_, 0x6000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ SetFde64(&this->memory_, 0x8000, 0x200, 0x6000, 0x5000, 0x300);
const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x8000);
ASSERT_TRUE(fde != nullptr);
@@ -573,11 +455,357 @@
EXPECT_EQ(0x20U, fde->cie->return_address_register);
}
-REGISTER_TYPED_TEST_CASE_P(DwarfDebugFrameTest, Init32, Init32_fde_not_following_cie,
- Init32_do_not_fail_on_bad_next_entry, Init64,
- Init64_do_not_fail_on_bad_next_entry, Init64_fde_not_following_cie,
- Init_non_zero_load_bias, Init_version1, Init_version4,
- GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
+static void VerifyCieVersion(const DwarfCie* cie, uint8_t version, uint8_t segment_size,
+ uint8_t fde_encoding, uint64_t return_address, uint64_t start_offset,
+ uint64_t end_offset) {
+ EXPECT_EQ(version, cie->version);
+ EXPECT_EQ(fde_encoding, cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
+ EXPECT_EQ(segment_size, cie->segment_size);
+ EXPECT_EQ(1U, cie->augmentation_string.size());
+ EXPECT_EQ('\0', cie->augmentation_string[0]);
+ EXPECT_EQ(0U, cie->personality_handler);
+ EXPECT_EQ(4U, cie->code_alignment_factor);
+ EXPECT_EQ(8, cie->data_alignment_factor);
+ EXPECT_EQ(return_address, cie->return_address_register);
+ EXPECT_EQ(0x5000U + start_offset, cie->cfa_instructions_offset);
+ EXPECT_EQ(0x5000U + end_offset, cie->cfa_instructions_end);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_cie_cached) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
+
+ std::vector<uint8_t> zero(0x100, 0);
+ this->memory_.SetMemory(0x5000, zero);
+ cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_cie_cached) {
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
+
+ std::vector<uint8_t> zero(0x100, 0);
+ this->memory_.SetMemory(0x5000, zero);
+ cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version1) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version1) {
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version3) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{3, '\0', 4, 8, 0x81, 3});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 3, 0, DW_EH_PE_sdata4, 0x181, 0xe, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version3) {
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{3, '\0', 4, 8, 0x81, 3});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 3, 0, DW_EH_PE_sdata8, 0x181, 0x1a, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version4) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 0, 10, 4, 8, 0x81, 3});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata4, 0x181, 0x10, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version4) {
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 0, 10, 4, 8, 0x81, 3});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata8, 0x181, 0x1c, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset_version_invalid) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{0, '\0', 1, 2, 3, 4, 5, 6, 7});
+ ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x5000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+ SetCie64(&this->memory_, 0x6000, 0x100, std::vector<uint8_t>{0, '\0', 1, 2, 3, 4, 5, 6, 7});
+ ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x6000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+
+ SetCie32(&this->memory_, 0x7000, 0x100, std::vector<uint8_t>{5, '\0', 1, 2, 3, 4, 5, 6, 7});
+ ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x7000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+ SetCie64(&this->memory_, 0x8000, 0x100, std::vector<uint8_t>{5, '\0', 1, 2, 3, 4, 5, 6, 7});
+ ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x8000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+}
+
+static void VerifyCieAugment(const DwarfCie* cie, uint64_t inst_offset, uint64_t inst_end) {
+ EXPECT_EQ(1U, cie->version);
+ EXPECT_EQ(DW_EH_PE_udata2, cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_textrel | DW_EH_PE_udata2, cie->lsda_encoding);
+ EXPECT_EQ(0U, cie->segment_size);
+ EXPECT_EQ(5U, cie->augmentation_string.size());
+ EXPECT_EQ('z', cie->augmentation_string[0]);
+ EXPECT_EQ('L', cie->augmentation_string[1]);
+ EXPECT_EQ('P', cie->augmentation_string[2]);
+ EXPECT_EQ('R', cie->augmentation_string[3]);
+ EXPECT_EQ('\0', cie->augmentation_string[4]);
+ EXPECT_EQ(0x12345678U, cie->personality_handler);
+ EXPECT_EQ(4U, cie->code_alignment_factor);
+ EXPECT_EQ(8, cie->data_alignment_factor);
+ EXPECT_EQ(0x10U, cie->return_address_register);
+ EXPECT_EQ(inst_offset, cie->cfa_instructions_offset);
+ EXPECT_EQ(inst_end, cie->cfa_instructions_end);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_augment) {
+ SetCie32(&this->memory_, 0x5000, 0x100,
+ std::vector<uint8_t>{/* version */ 1,
+ /* augment string */ 'z', 'L', 'P', 'R', '\0',
+ /* code alignment factor */ 4,
+ /* data alignment factor */ 8,
+ /* return address register */ 0x10,
+ /* augment length */ 0xf,
+ /* L data */ DW_EH_PE_textrel | DW_EH_PE_udata2,
+ /* P data */ DW_EH_PE_udata4, 0x78, 0x56, 0x34, 0x12,
+ /* R data */ DW_EH_PE_udata2});
+
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieAugment(cie, 0x5021, 0x5104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_augment) {
+ SetCie64(&this->memory_, 0x5000, 0x100,
+ std::vector<uint8_t>{/* version */ 1,
+ /* augment string */ 'z', 'L', 'P', 'R', '\0',
+ /* code alignment factor */ 4,
+ /* data alignment factor */ 8,
+ /* return address register */ 0x10,
+ /* augment length */ 0xf,
+ /* L data */ DW_EH_PE_textrel | DW_EH_PE_udata2,
+ /* P data */ DW_EH_PE_udata4, 0x78, 0x56, 0x34, 0x12,
+ /* R data */ DW_EH_PE_udata2});
+
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieAugment(cie, 0x502d, 0x510c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset32_augment) {
+ SetCie32(&this->memory_, 0x5000, 0xfc,
+ std::vector<uint8_t>{/* version */ 4,
+ /* augment string */ 'z', '\0',
+ /* address size */ 8,
+ /* segment size */ 0x10,
+ /* code alignment factor */ 16,
+ /* data alignment factor */ 32,
+ /* return address register */ 10,
+ /* augment length */ 0x0});
+
+ std::vector<uint8_t> data{/* augment length */ 0x80, 0x3};
+ SetFde32(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0x10, &data);
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+ ASSERT_TRUE(fde != nullptr);
+ ASSERT_TRUE(fde->cie != nullptr);
+ EXPECT_EQ(4U, fde->cie->version);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x53a2U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x5504U, fde->cfa_instructions_end);
+ EXPECT_EQ(0x4300U, fde->pc_start);
+ EXPECT_EQ(0x4600U, fde->pc_end);
+ EXPECT_EQ(0U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset64_augment) {
+ SetCie64(&this->memory_, 0x5000, 0xfc,
+ std::vector<uint8_t>{/* version */ 4,
+ /* augment string */ 'z', '\0',
+ /* address size */ 8,
+ /* segment size */ 0x10,
+ /* code alignment factor */ 16,
+ /* data alignment factor */ 32,
+ /* return address register */ 10,
+ /* augment length */ 0x0});
+
+ std::vector<uint8_t> data{/* augment length */ 0x80, 0x3};
+ SetFde64(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0x10, &data);
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+ ASSERT_TRUE(fde != nullptr);
+ ASSERT_TRUE(fde->cie != nullptr);
+ EXPECT_EQ(4U, fde->cie->version);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x53b6U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x550cU, fde->cfa_instructions_end);
+ EXPECT_EQ(0x4300U, fde->pc_start);
+ EXPECT_EQ(0x4600U, fde->pc_end);
+ EXPECT_EQ(0U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset32_lsda_address) {
+ SetCie32(&this->memory_, 0x5000, 0xfc,
+ std::vector<uint8_t>{/* version */ 1,
+ /* augment string */ 'z', 'L', '\0',
+ /* address size */ 8,
+ /* code alignment factor */ 16,
+ /* data alignment factor */ 32,
+ /* return address register */ 10,
+ /* augment length */ 0x2,
+ /* L data */ DW_EH_PE_udata2});
+
+ std::vector<uint8_t> data{/* augment length */ 0x80, 0x3,
+ /* lsda address */ 0x20, 0x45};
+ SetFde32(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0, &data);
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+ ASSERT_TRUE(fde != nullptr);
+ ASSERT_TRUE(fde->cie != nullptr);
+ EXPECT_EQ(1U, fde->cie->version);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x5392U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x5504U, fde->cfa_instructions_end);
+ EXPECT_EQ(0x4300U, fde->pc_start);
+ EXPECT_EQ(0x4600U, fde->pc_end);
+ EXPECT_EQ(0x4520U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset64_lsda_address) {
+ SetCie64(&this->memory_, 0x5000, 0xfc,
+ std::vector<uint8_t>{/* version */ 1,
+ /* augment string */ 'z', 'L', '\0',
+ /* address size */ 8,
+ /* code alignment factor */ 16,
+ /* data alignment factor */ 32,
+ /* return address register */ 10,
+ /* augment length */ 0x2,
+ /* L data */ DW_EH_PE_udata2});
+
+ std::vector<uint8_t> data{/* augment length */ 0x80, 0x3,
+ /* lsda address */ 0x20, 0x45};
+ SetFde64(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0, &data);
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+ ASSERT_TRUE(fde != nullptr);
+ ASSERT_TRUE(fde->cie != nullptr);
+ EXPECT_EQ(1U, fde->cie->version);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x53a6U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x550cU, fde->cfa_instructions_end);
+ EXPECT_EQ(0x4300U, fde->pc_start);
+ EXPECT_EQ(0x4600U, fde->pc_end);
+ EXPECT_EQ(0x4520U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc_interleaved) {
+ SetCie32(&this->memory_, 0x5000, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
+
+ // FDE 0 (0x100 - 0x200)
+ SetFde32(&this->memory_, 0x5100, 0xfc, 0, 0x100, 0x100);
+ // FDE 1 (0x300 - 0x500)
+ SetFde32(&this->memory_, 0x5200, 0xfc, 0, 0x300, 0x200);
+ // FDE 2 (0x700 - 0x800)
+ SetFde32(&this->memory_, 0x5300, 0xfc, 0, 0x700, 0x100);
+ // FDE 3 (0xa00 - 0xb00)
+ SetFde32(&this->memory_, 0x5400, 0xfc, 0, 0xa00, 0x100);
+ // FDE 4 (0x100 - 0xb00)
+ SetFde32(&this->memory_, 0x5500, 0xfc, 0, 0x150, 0xa00);
+ // FDE 5 (0x0 - 0x50)
+ SetFde32(&this->memory_, 0x5600, 0xfc, 0, 0, 0x50);
+
+ this->debug_frame_->Init(0x5000, 0x700, 0);
+
+ // Force reading all entries so no entries are found.
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0xfffff);
+ ASSERT_TRUE(fde == nullptr);
+
+ // 0x0 - 0x50 FDE 5
+ fde = this->debug_frame_->GetFdeFromPc(0x10);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0U, fde->pc_start);
+ EXPECT_EQ(0x50U, fde->pc_end);
+
+ // 0x100 - 0x200 FDE 0
+ fde = this->debug_frame_->GetFdeFromPc(0x170);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x100U, fde->pc_start);
+ EXPECT_EQ(0x200U, fde->pc_end);
+
+ // 0x200 - 0x300 FDE 4
+ fde = this->debug_frame_->GetFdeFromPc(0x210);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x150U, fde->pc_start);
+ EXPECT_EQ(0xb50U, fde->pc_end);
+
+ // 0x300 - 0x500 FDE 1
+ fde = this->debug_frame_->GetFdeFromPc(0x310);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x300U, fde->pc_start);
+ EXPECT_EQ(0x500U, fde->pc_end);
+
+ // 0x700 - 0x800 FDE 2
+ fde = this->debug_frame_->GetFdeFromPc(0x790);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x700U, fde->pc_start);
+ EXPECT_EQ(0x800U, fde->pc_end);
+
+ // 0x800 - 0x900 FDE 4
+ fde = this->debug_frame_->GetFdeFromPc(0x850);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x150U, fde->pc_start);
+ EXPECT_EQ(0xb50U, fde->pc_end);
+
+ // 0xa00 - 0xb00 FDE 3
+ fde = this->debug_frame_->GetFdeFromPc(0xa35);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0xa00U, fde->pc_start);
+ EXPECT_EQ(0xb00U, fde->pc_end);
+
+ // 0xb00 - 0xb50 FDE 4
+ fde = this->debug_frame_->GetFdeFromPc(0xb20);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x150U, fde->pc_start);
+ EXPECT_EQ(0xb50U, fde->pc_end);
+}
+
+REGISTER_TYPED_TEST_CASE_P(
+ DwarfDebugFrameTest, GetFdes32, GetFdes32_after_GetFdeFromPc, GetFdes32_not_in_section,
+ GetFdeFromPc32, GetFdeFromPc32_reverse, GetFdeFromPc32_not_in_section, GetFdes64,
+ GetFdes64_after_GetFdeFromPc, GetFdes64_not_in_section, GetFdeFromPc64, GetFdeFromPc64_reverse,
+ GetFdeFromPc64_not_in_section, GetCieFde32, GetCieFde64, GetCieFromOffset32_cie_cached,
+ GetCieFromOffset64_cie_cached, GetCieFromOffset32_version1, GetCieFromOffset64_version1,
+ GetCieFromOffset32_version3, GetCieFromOffset64_version3, GetCieFromOffset32_version4,
+ GetCieFromOffset64_version4, GetCieFromOffset_version_invalid, GetCieFromOffset32_augment,
+ GetCieFromOffset64_augment, GetFdeFromOffset32_augment, GetFdeFromOffset64_augment,
+ GetFdeFromOffset32_lsda_address, GetFdeFromOffset64_lsda_address, GetFdeFromPc_interleaved);
typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index e8d53e6..9cac6e8 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -16,7 +16,6 @@
#include <stdint.h>
-#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
@@ -30,50 +29,32 @@
namespace unwindstack {
template <typename TypeParam>
-class MockDwarfEhFrame : public DwarfEhFrame<TypeParam> {
- public:
- MockDwarfEhFrame(Memory* memory) : DwarfEhFrame<TypeParam>(memory) {}
- ~MockDwarfEhFrame() = default;
-
- void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
- void TestSetOffset(uint64_t offset) { this->entries_offset_ = offset; }
- void TestSetEndOffset(uint64_t offset) { this->entries_end_ = offset; }
- void TestPushFdeInfo(const typename DwarfEhFrame<TypeParam>::FdeInfo& info) {
- this->fdes_.push_back(info);
- }
-
- uint64_t TestGetFdeCount() { return this->fde_count_; }
- uint8_t TestGetOffset() { return this->offset_; }
- uint8_t TestGetEndOffset() { return this->end_offset_; }
- void TestGetFdeInfo(size_t index, typename DwarfEhFrame<TypeParam>::FdeInfo* info) {
- *info = this->fdes_[index];
- }
-};
-
-template <typename TypeParam>
class DwarfEhFrameTest : public ::testing::Test {
protected:
void SetUp() override {
memory_.Clear();
- eh_frame_ = new MockDwarfEhFrame<TypeParam>(&memory_);
+ eh_frame_ = new DwarfEhFrame<TypeParam>(&memory_);
ResetLogs();
}
void TearDown() override { delete eh_frame_; }
MemoryFake memory_;
- MockDwarfEhFrame<TypeParam>* eh_frame_ = nullptr;
+ DwarfEhFrame<TypeParam>* eh_frame_ = nullptr;
};
TYPED_TEST_CASE_P(DwarfEhFrameTest);
// NOTE: All test class variables need to be referenced as this->.
-TYPED_TEST_P(DwarfEhFrameTest, Init32) {
+// Only verify different cie/fde format. All other DwarfSection corner
+// cases are tested in DwarfDebugFrameTest.cpp.
+
+TYPED_TEST_P(DwarfEhFrameTest, GetFdeCieFromOffset32) {
// CIE 32 information.
this->memory_.SetData32(0x5000, 0xfc);
+ // Indicates this is a cie for eh_frame.
this->memory_.SetData32(0x5004, 0);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, '\0');
+ this->memory_.SetMemory(0x5008, std::vector<uint8_t>{1, '\0', 16, 32, 1});
// FDE 32 information.
this->memory_.SetData32(0x5100, 0xfc);
@@ -81,415 +62,70 @@
this->memory_.SetData32(0x5108, 0x1500);
this->memory_.SetData32(0x510c, 0x200);
- this->memory_.SetData32(0x5200, 0xfc);
- this->memory_.SetData32(0x5204, 0x204);
- this->memory_.SetData32(0x5208, 0x2500);
- this->memory_.SetData32(0x520c, 0x300);
+ const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x5100);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x5110U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x5200U, fde->cfa_instructions_end);
+ EXPECT_EQ(0x6608U, fde->pc_start);
+ EXPECT_EQ(0x6808U, fde->pc_end);
+ EXPECT_EQ(0U, fde->lsda_address);
- // CIE 32 information.
- this->memory_.SetData32(0x5300, 0xfc);
- this->memory_.SetData32(0x5304, 0);
- this->memory_.SetData8(0x5308, 1);
- this->memory_.SetData8(0x5309, '\0');
-
- // FDE 32 information.
- this->memory_.SetData32(0x5400, 0xfc);
- this->memory_.SetData32(0x5404, 0x104);
- this->memory_.SetData32(0x5408, 0x3500);
- this->memory_.SetData32(0x540c, 0x400);
-
- this->memory_.SetData32(0x5500, 0xfc);
- this->memory_.SetData32(0x5504, 0x204);
- this->memory_.SetData32(0x5508, 0x4500);
- this->memory_.SetData32(0x550c, 0x500);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(4U, this->eh_frame_->TestGetFdeCount());
-
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
-
- this->eh_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x6608U, info.start);
- EXPECT_EQ(0x6808U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(1, &info);
- EXPECT_EQ(0x5200U, info.offset);
- EXPECT_EQ(0x7708U, info.start);
- EXPECT_EQ(0x7a08U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(2, &info);
- EXPECT_EQ(0x5400U, info.offset);
- EXPECT_EQ(0x8908U, info.start);
- EXPECT_EQ(0x8d08U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(3, &info);
- EXPECT_EQ(0x5500U, info.offset);
- EXPECT_EQ(0x9a08U, info.start);
- EXPECT_EQ(0x9f08U, info.end);
+ const DwarfCie* cie = fde->cie;
+ ASSERT_TRUE(cie != nullptr);
+ EXPECT_EQ(1U, cie->version);
+ EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
+ EXPECT_EQ(0U, cie->segment_size);
+ EXPECT_EQ('\0', cie->augmentation_string[0]);
+ EXPECT_EQ(0U, cie->personality_handler);
+ EXPECT_EQ(0x500dU, cie->cfa_instructions_offset);
+ EXPECT_EQ(0x5100U, cie->cfa_instructions_end);
+ EXPECT_EQ(16U, cie->code_alignment_factor);
+ EXPECT_EQ(32U, cie->data_alignment_factor);
+ EXPECT_EQ(1U, cie->return_address_register);
}
-TYPED_TEST_P(DwarfEhFrameTest, Init32_fde_not_following_cie) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, '\0');
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x1000);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
-
- ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init64) {
+TYPED_TEST_P(DwarfEhFrameTest, GetFdeCieFromOffset64) {
// CIE 64 information.
this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xf4);
+ this->memory_.SetData64(0x5004, 0xfc);
+ // Indicates this is a cie for eh_frame.
this->memory_.SetData64(0x500c, 0);
- this->memory_.SetData8(0x5014, 1);
- this->memory_.SetData8(0x5015, '\0');
+ this->memory_.SetMemory(0x5014, std::vector<uint8_t>{1, '\0', 16, 32, 1});
// FDE 64 information.
this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xf4);
+ this->memory_.SetData64(0x5104, 0xfc);
this->memory_.SetData64(0x510c, 0x10c);
this->memory_.SetData64(0x5114, 0x1500);
this->memory_.SetData64(0x511c, 0x200);
- this->memory_.SetData32(0x5200, 0xffffffff);
- this->memory_.SetData64(0x5204, 0xf4);
- this->memory_.SetData64(0x520c, 0x20c);
- this->memory_.SetData64(0x5214, 0x2500);
- this->memory_.SetData64(0x521c, 0x300);
-
- // CIE 64 information.
- this->memory_.SetData32(0x5300, 0xffffffff);
- this->memory_.SetData64(0x5304, 0xf4);
- this->memory_.SetData64(0x530c, 0);
- this->memory_.SetData8(0x5314, 1);
- this->memory_.SetData8(0x5315, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5400, 0xffffffff);
- this->memory_.SetData64(0x5404, 0xf4);
- this->memory_.SetData64(0x540c, 0x10c);
- this->memory_.SetData64(0x5414, 0x3500);
- this->memory_.SetData64(0x541c, 0x400);
-
- this->memory_.SetData32(0x5500, 0xffffffff);
- this->memory_.SetData64(0x5504, 0xf4);
- this->memory_.SetData64(0x550c, 0x20c);
- this->memory_.SetData64(0x5514, 0x4500);
- this->memory_.SetData64(0x551c, 0x500);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(4U, this->eh_frame_->TestGetFdeCount());
-
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
-
- this->eh_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x6618U, info.start);
- EXPECT_EQ(0x6818U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(1, &info);
- EXPECT_EQ(0x5200U, info.offset);
- EXPECT_EQ(0x7718U, info.start);
- EXPECT_EQ(0x7a18U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(2, &info);
- EXPECT_EQ(0x5400U, info.offset);
- EXPECT_EQ(0x8918U, info.start);
- EXPECT_EQ(0x8d18U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(3, &info);
- EXPECT_EQ(0x5500U, info.offset);
- EXPECT_EQ(0x9a18U, info.start);
- EXPECT_EQ(0x9f18U, info.end);
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init64_fde_not_following_cie) {
- // CIE 64 information.
- this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xf4);
- this->memory_.SetData64(0x500c, 0);
- this->memory_.SetData8(0x5014, 1);
- this->memory_.SetData8(0x5015, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xf4);
- this->memory_.SetData64(0x510c, 0x1000);
- this->memory_.SetData64(0x5114, 0x1500);
- this->memory_.SetData64(0x511c, 0x200);
-
- ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init_non_zero_load_bias) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, 'z');
- this->memory_.SetData8(0x500a, 'R');
- this->memory_.SetData8(0x500b, '\0');
- this->memory_.SetData8(0x500c, 0);
- this->memory_.SetData8(0x500d, 0);
- this->memory_.SetData8(0x500e, 0);
- this->memory_.SetData8(0x500f, 0);
- this->memory_.SetData8(0x5010, 0x1b);
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x104);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
- this->memory_.SetData8(0x5110, 0);
- this->memory_.SetData8(0x5111, 0);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200, 0x2000));
- ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
-
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
-
- this->eh_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x8608U, info.start);
- EXPECT_EQ(0x8808U, info.end);
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x8700);
+ const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x5100);
ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x8608U, fde->pc_start);
- EXPECT_EQ(0x8808U, fde->pc_end);
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init_version1) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0);
- this->memory_.SetData8(0x5008, 1);
- // Augment string.
- this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'R', 'P', 'L', '\0'});
- // Code alignment factor.
- this->memory_.SetMemory(0x500e, std::vector<uint8_t>{0x80, 0x00});
- // Data alignment factor.
- this->memory_.SetMemory(0x5010, std::vector<uint8_t>{0x81, 0x80, 0x80, 0x00});
- // Return address register
- this->memory_.SetData8(0x5014, 0x84);
- // Augmentation length
- this->memory_.SetMemory(0x5015, std::vector<uint8_t>{0x84, 0x00});
- // R data.
- this->memory_.SetData8(0x5017, DW_EH_PE_pcrel | DW_EH_PE_udata2);
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x104);
- this->memory_.SetData16(0x5108, 0x1500);
- this->memory_.SetData16(0x510a, 0x200);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200, 0));
- ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
-
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
- this->eh_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x6606U, info.start);
- EXPECT_EQ(0x6806U, info.end);
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init_version4) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0);
- this->memory_.SetData8(0x5008, 4);
- // Augment string.
- this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'L', 'P', 'R', '\0'});
- // Address size.
- this->memory_.SetData8(0x500e, 4);
- // Segment size.
- this->memory_.SetData8(0x500f, 0);
- // Code alignment factor.
- this->memory_.SetMemory(0x5010, std::vector<uint8_t>{0x80, 0x00});
- // Data alignment factor.
- this->memory_.SetMemory(0x5012, std::vector<uint8_t>{0x81, 0x80, 0x80, 0x00});
- // Return address register
- this->memory_.SetMemory(0x5016, std::vector<uint8_t>{0x85, 0x10});
- // Augmentation length
- this->memory_.SetMemory(0x5018, std::vector<uint8_t>{0x84, 0x00});
- // L data.
- this->memory_.SetData8(0x501a, 0x10);
- // P data.
- this->memory_.SetData8(0x501b, DW_EH_PE_udata4);
- this->memory_.SetData32(0x501c, 0x100);
- // R data.
- this->memory_.SetData8(0x5020, DW_EH_PE_pcrel | DW_EH_PE_udata2);
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x104);
- this->memory_.SetData16(0x5108, 0x1500);
- this->memory_.SetData16(0x510a, 0x200);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200, 0));
- ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
-
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
- this->eh_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x6606U, info.start);
- EXPECT_EQ(0x6806U, info.end);
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc) {
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
- for (size_t i = 0; i < 9; i++) {
- info.start = 0x1000 * (i + 1);
- info.end = 0x1000 * (i + 2) - 0x10;
- info.offset = 0x5000 + i * 0x20;
- this->eh_frame_->TestPushFdeInfo(info);
- }
-
- this->eh_frame_->TestSetFdeCount(0);
- uint64_t fde_offset;
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
-
- this->eh_frame_->TestSetFdeCount(9);
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
- // Odd number of elements.
- for (size_t i = 0; i < 9; i++) {
- TypeParam pc = 0x1000 * (i + 1);
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
- << "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
- }
-
- // Even number of elements.
- this->eh_frame_->TestSetFdeCount(10);
- info.start = 0xa000;
- info.end = 0xaff0;
- info.offset = 0x5120;
- this->eh_frame_->TestPushFdeInfo(info);
-
- for (size_t i = 0; i < 10; i++) {
- TypeParam pc = 0x1000 * (i + 1);
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
- << "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
- }
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, GetCieFde32) {
- this->eh_frame_->TestSetOffset(0x4000);
-
- // CIE 32 information.
- this->memory_.SetData32(0xf000, 0x100);
- this->memory_.SetData32(0xf004, 0);
- this->memory_.SetData8(0xf008, 0x1);
- this->memory_.SetData8(0xf009, '\0');
- this->memory_.SetData8(0xf00a, 4);
- this->memory_.SetData8(0xf00b, 8);
- this->memory_.SetData8(0xf00c, 0x20);
-
- // FDE 32 information.
- this->memory_.SetData32(0x14000, 0x20);
- this->memory_.SetData32(0x14004, 0x5004);
- this->memory_.SetData32(0x14008, 0x9000);
- this->memory_.SetData32(0x1400c, 0x100);
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x14000);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
- EXPECT_EQ(0x1d008U, fde->pc_start);
- EXPECT_EQ(0x1d108U, fde->pc_end);
- EXPECT_EQ(0xf000U, fde->cie_offset);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x5124U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x5208U, fde->cfa_instructions_end);
+ EXPECT_EQ(0x6618U, fde->pc_start);
+ EXPECT_EQ(0x6818U, fde->pc_end);
EXPECT_EQ(0U, fde->lsda_address);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, fde->cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
- EXPECT_EQ(0U, fde->cie->segment_size);
- EXPECT_EQ(1U, fde->cie->augmentation_string.size());
- EXPECT_EQ('\0', fde->cie->augmentation_string[0]);
- EXPECT_EQ(0U, fde->cie->personality_handler);
- EXPECT_EQ(0xf00dU, fde->cie->cfa_instructions_offset);
- EXPECT_EQ(0xf104U, fde->cie->cfa_instructions_end);
- EXPECT_EQ(4U, fde->cie->code_alignment_factor);
- EXPECT_EQ(8, fde->cie->data_alignment_factor);
- EXPECT_EQ(0x20U, fde->cie->return_address_register);
+ const DwarfCie* cie = fde->cie;
+ ASSERT_TRUE(cie != nullptr);
+ EXPECT_EQ(1U, cie->version);
+ EXPECT_EQ(DW_EH_PE_sdata8, cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
+ EXPECT_EQ(0U, cie->segment_size);
+ EXPECT_EQ('\0', cie->augmentation_string[0]);
+ EXPECT_EQ(0U, cie->personality_handler);
+ EXPECT_EQ(0x5019U, cie->cfa_instructions_offset);
+ EXPECT_EQ(0x5108U, cie->cfa_instructions_end);
+ EXPECT_EQ(16U, cie->code_alignment_factor);
+ EXPECT_EQ(32U, cie->data_alignment_factor);
+ EXPECT_EQ(1U, cie->return_address_register);
}
-TYPED_TEST_P(DwarfEhFrameTest, GetCieFde64) {
- this->eh_frame_->TestSetOffset(0x2000);
-
- // CIE 64 information.
- this->memory_.SetData32(0x6000, 0xffffffff);
- this->memory_.SetData64(0x6004, 0x100);
- this->memory_.SetData64(0x600c, 0);
- this->memory_.SetData8(0x6014, 0x1);
- this->memory_.SetData8(0x6015, '\0');
- this->memory_.SetData8(0x6016, 4);
- this->memory_.SetData8(0x6017, 8);
- this->memory_.SetData8(0x6018, 0x20);
-
- // FDE 64 information.
- this->memory_.SetData32(0x8000, 0xffffffff);
- this->memory_.SetData64(0x8004, 0x200);
- this->memory_.SetData64(0x800c, 0x200c);
- this->memory_.SetData64(0x8014, 0x5000);
- this->memory_.SetData64(0x801c, 0x300);
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x8000);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
- EXPECT_EQ(0xd018U, fde->pc_start);
- EXPECT_EQ(0xd318U, fde->pc_end);
- EXPECT_EQ(0x6000U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_sdata8, fde->cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
- EXPECT_EQ(0U, fde->cie->segment_size);
- EXPECT_EQ(1U, fde->cie->augmentation_string.size());
- EXPECT_EQ('\0', fde->cie->augmentation_string[0]);
- EXPECT_EQ(0U, fde->cie->personality_handler);
- EXPECT_EQ(0x6019U, fde->cie->cfa_instructions_offset);
- EXPECT_EQ(0x610cU, fde->cie->cfa_instructions_end);
- EXPECT_EQ(4U, fde->cie->code_alignment_factor);
- EXPECT_EQ(8, fde->cie->data_alignment_factor);
- EXPECT_EQ(0x20U, fde->cie->return_address_register);
-}
-
-REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameTest, Init32, Init32_fde_not_following_cie, Init64,
- Init64_fde_not_following_cie, Init_non_zero_load_bias, Init_version1,
- Init_version4, GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
+REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameTest, GetFdeCieFromOffset32, GetFdeCieFromOffset64);
typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameTest, DwarfEhFrameTestTypes);
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 19c7b98..910ae36 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -30,10 +30,10 @@
namespace unwindstack {
template <typename TypeParam>
-class MockDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr<TypeParam> {
+class TestDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr<TypeParam> {
public:
- MockDwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrameWithHdr<TypeParam>(memory) {}
- ~MockDwarfEhFrameWithHdr() = default;
+ TestDwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrameWithHdr<TypeParam>(memory) {}
+ ~TestDwarfEhFrameWithHdr() = default;
void TestSetTableEncoding(uint8_t encoding) { this->table_encoding_ = encoding; }
void TestSetEntriesOffset(uint64_t offset) { this->entries_offset_ = offset; }
@@ -64,14 +64,14 @@
protected:
void SetUp() override {
memory_.Clear();
- eh_frame_ = new MockDwarfEhFrameWithHdr<TypeParam>(&memory_);
+ eh_frame_ = new TestDwarfEhFrameWithHdr<TypeParam>(&memory_);
ResetLogs();
}
void TearDown() override { delete eh_frame_; }
MemoryFake memory_;
- MockDwarfEhFrameWithHdr<TypeParam>* eh_frame_ = nullptr;
+ TestDwarfEhFrameWithHdr<TypeParam>* eh_frame_ = nullptr;
};
TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest);
@@ -121,23 +121,14 @@
// CIE 32 information.
this->memory_.SetData32(0x1300, 0xfc);
this->memory_.SetData32(0x1304, 0);
- this->memory_.SetData8(0x1308, 1);
- this->memory_.SetData8(0x1309, 'z');
- this->memory_.SetData8(0x130a, 'R');
- this->memory_.SetData8(0x130b, '\0');
- this->memory_.SetData8(0x130c, 0);
- this->memory_.SetData8(0x130d, 0);
- this->memory_.SetData8(0x130e, 0);
- this->memory_.SetData8(0x130f, 0);
- this->memory_.SetData8(0x1310, 0x1b);
+ this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
// FDE 32 information.
this->memory_.SetData32(0x1400, 0xfc);
this->memory_.SetData32(0x1404, 0x104);
this->memory_.SetData32(0x1408, 0x10f8);
this->memory_.SetData32(0x140c, 0x200);
- this->memory_.SetData8(0x1410, 0);
- this->memory_.SetData8(0x1411, 0);
+ this->memory_.SetData16(0x1410, 0);
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0x2000));
EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
@@ -157,6 +148,68 @@
EXPECT_EQ(0x4700U, fde->pc_end);
}
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdes) {
+ this->memory_.SetMemory(
+ 0x1000, std::vector<uint8_t>{1, DW_EH_PE_udata2, DW_EH_PE_udata4, DW_EH_PE_sdata4});
+ this->memory_.SetData16(0x1004, 0x500);
+ this->memory_.SetData32(0x1006, 4);
+
+ // Header information.
+ this->memory_.SetData32(0x100a, 0x4600);
+ this->memory_.SetData32(0x100e, 0x1500);
+ this->memory_.SetData32(0x1012, 0x5500);
+ this->memory_.SetData32(0x1016, 0x1400);
+ this->memory_.SetData32(0x101a, 0x6800);
+ this->memory_.SetData32(0x101e, 0x1700);
+ this->memory_.SetData32(0x1022, 0x7700);
+ this->memory_.SetData32(0x1026, 0x1600);
+
+ // CIE 32 information.
+ this->memory_.SetData32(0x1300, 0xfc);
+ this->memory_.SetData32(0x1304, 0);
+ this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, '\0', 0, 0, 0});
+
+ // FDE 32 information.
+ // pc 0x5500 - 0x5700
+ this->memory_.SetData32(0x1400, 0xfc);
+ this->memory_.SetData32(0x1404, 0x104);
+ this->memory_.SetData32(0x1408, 0x40f8);
+ this->memory_.SetData32(0x140c, 0x200);
+
+ // pc 0x4600 - 0x4800
+ this->memory_.SetData32(0x1500, 0xfc);
+ this->memory_.SetData32(0x1504, 0x204);
+ this->memory_.SetData32(0x1508, 0x30f8);
+ this->memory_.SetData32(0x150c, 0x200);
+
+ // pc 0x7700 - 0x7900
+ this->memory_.SetData32(0x1600, 0xfc);
+ this->memory_.SetData32(0x1604, 0x304);
+ this->memory_.SetData32(0x1608, 0x60f8);
+ this->memory_.SetData32(0x160c, 0x200);
+
+ // pc 0x6800 - 0x6a00
+ this->memory_.SetData32(0x1700, 0xfc);
+ this->memory_.SetData32(0x1704, 0x404);
+ this->memory_.SetData32(0x1708, 0x50f8);
+ this->memory_.SetData32(0x170c, 0x200);
+
+ ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
+
+ std::vector<const DwarfFde*> fdes;
+ this->eh_frame_->GetFdes(&fdes);
+ ASSERT_EQ(4U, fdes.size());
+
+ EXPECT_EQ(0x4600U, fdes[0]->pc_start);
+ EXPECT_EQ(0x4800U, fdes[0]->pc_end);
+ EXPECT_EQ(0x5500U, fdes[1]->pc_start);
+ EXPECT_EQ(0x5700U, fdes[1]->pc_end);
+ EXPECT_EQ(0x6800U, fdes[2]->pc_start);
+ EXPECT_EQ(0x6a00U, fdes[2]->pc_end);
+ EXPECT_EQ(0x7700U, fdes[3]->pc_start);
+ EXPECT_EQ(0x7900U, fdes[3]->pc_end);
+}
+
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
this->eh_frame_->TestSetTableEntrySize(0x10);
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
@@ -388,11 +441,7 @@
// CIE 32 information.
this->memory_.SetData32(0xf000, 0x100);
this->memory_.SetData32(0xf004, 0);
- this->memory_.SetData8(0xf008, 0x1);
- this->memory_.SetData8(0xf009, '\0');
- this->memory_.SetData8(0xf00a, 4);
- this->memory_.SetData8(0xf00b, 8);
- this->memory_.SetData8(0xf00c, 0x20);
+ this->memory_.SetMemory(0xf008, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
// FDE 32 information.
this->memory_.SetData32(0x14000, 0x20);
@@ -429,11 +478,7 @@
this->memory_.SetData32(0x6000, 0xffffffff);
this->memory_.SetData64(0x6004, 0x100);
this->memory_.SetData64(0x600c, 0);
- this->memory_.SetData8(0x6014, 0x1);
- this->memory_.SetData8(0x6015, '\0');
- this->memory_.SetData8(0x6016, 4);
- this->memory_.SetData8(0x6017, 8);
- this->memory_.SetData8(0x6018, 0x20);
+ this->memory_.SetMemory(0x6014, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
// FDE 64 information.
this->memory_.SetData32(0x8000, 0xffffffff);
@@ -478,7 +523,7 @@
ASSERT_EQ(nullptr, this->eh_frame_->GetFdeFromPc(0x800));
}
-REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias,
+REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias, GetFdes,
GetFdeInfoFromIndex_expect_cache_fail, GetFdeInfoFromIndex_read_pcrel,
GetFdeInfoFromIndex_read_datarel, GetFdeInfoFromIndex_cached,
GetFdeOffsetBinary_verify, GetFdeOffsetBinary_index_fail,
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index 414f2f2..46f555a 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -16,7 +16,6 @@
#include <stdint.h>
-#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
@@ -31,42 +30,27 @@
namespace unwindstack {
template <typename TypeParam>
-class MockDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
+class TestDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
public:
- MockDwarfSectionImpl(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
- virtual ~MockDwarfSectionImpl() = default;
+ TestDwarfSectionImpl(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
+ virtual ~TestDwarfSectionImpl() = default;
- MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
+ bool Init(uint64_t, uint64_t, uint64_t) override { return false; }
- MOCK_METHOD2(GetFdeOffsetFromPc, bool(uint64_t, uint64_t*));
+ void GetFdes(std::vector<const DwarfFde*>*) override {}
- MOCK_METHOD1(GetFdeFromIndex, const DwarfFde*(size_t));
+ const DwarfFde* GetFdeFromPc(uint64_t) override { return nullptr; }
- MOCK_METHOD1(GetCieOffsetFromFde32, uint64_t(uint32_t));
+ uint64_t GetCieOffsetFromFde32(uint32_t) { return 0; }
- MOCK_METHOD1(GetCieOffsetFromFde64, uint64_t(uint64_t));
+ uint64_t GetCieOffsetFromFde64(uint64_t) { return 0; }
- MOCK_METHOD1(AdjustPcFromFde, uint64_t(uint64_t));
-
- void TestSetCie32Value(uint32_t value32) { this->cie32_value_ = value32; }
-
- void TestSetCie64Value(uint64_t value64) { this->cie64_value_ = value64; }
-
- void TestSetCachedCieEntry(uint64_t offset, const DwarfCie& cie) {
- this->cie_entries_[offset] = cie;
- }
- void TestClearCachedCieEntry() { this->cie_entries_.clear(); }
-
- void TestSetCachedFdeEntry(uint64_t offset, const DwarfFde& fde) {
- this->fde_entries_[offset] = fde;
- }
- void TestClearCachedFdeEntry() { this->fde_entries_.clear(); }
+ uint64_t AdjustPcFromFde(uint64_t) override { return 0; }
void TestSetCachedCieLocRegs(uint64_t offset, const dwarf_loc_regs_t& loc_regs) {
this->cie_loc_regs_[offset] = loc_regs;
}
void TestClearCachedCieLocRegs() { this->cie_loc_regs_.clear(); }
-
void TestClearError() { this->last_error_.code = DWARF_ERROR_NONE; }
};
@@ -75,21 +59,41 @@
protected:
void SetUp() override {
memory_.Clear();
- section_ = new MockDwarfSectionImpl<TypeParam>(&memory_);
+ section_ = new TestDwarfSectionImpl<TypeParam>(&memory_);
ResetLogs();
- section_->TestSetCie32Value(static_cast<uint32_t>(-1));
- section_->TestSetCie64Value(static_cast<uint64_t>(-1));
}
void TearDown() override { delete section_; }
MemoryFake memory_;
- MockDwarfSectionImpl<TypeParam>* section_ = nullptr;
+ TestDwarfSectionImpl<TypeParam>* section_ = nullptr;
};
TYPED_TEST_CASE_P(DwarfSectionImplTest);
// NOTE: All test class variables need to be referenced as this->.
+TYPED_TEST_P(DwarfSectionImplTest, GetCieFromOffset_fail_should_not_cache) {
+ ASSERT_TRUE(this->section_->GetCieFromOffset(0x4000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+
+ this->section_->TestClearError();
+ ASSERT_TRUE(this->section_->GetCieFromOffset(0x4000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) {
+ ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+
+ this->section_->TestClearError();
+ ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+}
+
TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_eval_fail) {
DwarfCie cie{.version = 3, .return_address_register = 5};
RegsImplFake<TypeParam> regs(10);
@@ -487,334 +491,6 @@
EXPECT_EQ(0x80000000U, regs.pc());
}
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_fail_should_not_cache) {
- ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_32_version_check) {
- this->memory_.SetData32(0x5000, 0x100);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 0x1);
- this->memory_.SetData8(0x5009, '\0');
- this->memory_.SetData8(0x500a, 4);
- this->memory_.SetData8(0x500b, 8);
- this->memory_.SetData8(0x500c, 0x20);
-
- const DwarfCie* cie = this->section_->GetCie(0x5000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x500dU, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x20U, cie->return_address_register);
- EXPECT_EQ(DWARF_ERROR_NONE, this->section_->LastErrorCode());
-
- this->section_->TestClearCachedCieEntry();
- // Set version to 0, 2, 5 and verify we fail.
- this->memory_.SetData8(0x5008, 0x0);
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
-
- this->memory_.SetData8(0x5008, 0x2);
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
-
- this->memory_.SetData8(0x5008, 0x5);
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_negative_data_alignment_factor) {
- this->memory_.SetData32(0x5000, 0x100);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 0x1);
- this->memory_.SetData8(0x5009, '\0');
- this->memory_.SetData8(0x500a, 4);
- this->memory_.SetMemory(0x500b, std::vector<uint8_t>{0xfc, 0xff, 0xff, 0xff, 0x7f});
- this->memory_.SetData8(0x5010, 0x20);
-
- const DwarfCie* cie = this->section_->GetCie(0x5000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x5011U, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(-4, cie->data_alignment_factor);
- EXPECT_EQ(0x20U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_64_no_augment) {
- this->memory_.SetData32(0x8000, 0xffffffff);
- this->memory_.SetData64(0x8004, 0x200);
- this->memory_.SetData64(0x800c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x8014, 0x1);
- this->memory_.SetData8(0x8015, '\0');
- this->memory_.SetData8(0x8016, 4);
- this->memory_.SetData8(0x8017, 8);
- this->memory_.SetData8(0x8018, 0x20);
-
- const DwarfCie* cie = this->section_->GetCie(0x8000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata8, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x8019U, cie->cfa_instructions_offset);
- EXPECT_EQ(0x820cU, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x20U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_augment) {
- this->memory_.SetData32(0x5000, 0x100);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 0x1);
- this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'L', 'P', 'R', '\0'});
- this->memory_.SetData8(0x500e, 4);
- this->memory_.SetData8(0x500f, 8);
- this->memory_.SetData8(0x5010, 0x10);
- // Augment length.
- this->memory_.SetData8(0x5011, 0xf);
- // L data.
- this->memory_.SetData8(0x5012, DW_EH_PE_textrel | DW_EH_PE_udata2);
- // P data.
- this->memory_.SetData8(0x5013, DW_EH_PE_udata4);
- this->memory_.SetData32(0x5014, 0x12345678);
- // R data.
- this->memory_.SetData8(0x5018, DW_EH_PE_udata2);
-
- const DwarfCie* cie = this->section_->GetCie(0x5000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_udata2, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_textrel | DW_EH_PE_udata2, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(5U, cie->augmentation_string.size());
- EXPECT_EQ('z', cie->augmentation_string[0]);
- EXPECT_EQ('L', cie->augmentation_string[1]);
- EXPECT_EQ('P', cie->augmentation_string[2]);
- EXPECT_EQ('R', cie->augmentation_string[3]);
- EXPECT_EQ('\0', cie->augmentation_string[4]);
- EXPECT_EQ(0x12345678U, cie->personality_handler);
- EXPECT_EQ(0x5021U, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x10U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_version_3) {
- this->memory_.SetData32(0x5000, 0x100);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 0x3);
- this->memory_.SetData8(0x5009, '\0');
- this->memory_.SetData8(0x500a, 4);
- this->memory_.SetData8(0x500b, 8);
- this->memory_.SetMemory(0x500c, std::vector<uint8_t>{0x81, 0x03});
-
- const DwarfCie* cie = this->section_->GetCie(0x5000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(3U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x500eU, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x181U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_version_4) {
- this->memory_.SetData32(0x5000, 0x100);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 0x4);
- this->memory_.SetData8(0x5009, '\0');
- this->memory_.SetData8(0x500a, 4);
- this->memory_.SetData8(0x500b, 0x13);
- this->memory_.SetData8(0x500c, 4);
- this->memory_.SetData8(0x500d, 8);
- this->memory_.SetMemory(0x500e, std::vector<uint8_t>{0x81, 0x03});
-
- const DwarfCie* cie = this->section_->GetCie(0x5000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(4U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0x13U, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x5010U, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x181U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) {
- ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment) {
- this->memory_.SetData32(0x4000, 0x20);
- this->memory_.SetData32(0x4004, 0x8000);
- this->memory_.SetData32(0x4008, 0x5000);
- this->memory_.SetData32(0x400c, 0x100);
-
- EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
- DwarfCie cie{};
- cie.fde_address_encoding = DW_EH_PE_udata4;
- this->section_->TestSetCachedCieEntry(0x8000, cie);
- EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
- const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(0x4010U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x4024U, fde->cfa_instructions_end);
- EXPECT_EQ(0x5000U, fde->pc_start);
- EXPECT_EQ(0x5100U, fde->pc_end);
- EXPECT_EQ(0x8000U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment_non_zero_segment_size) {
- this->memory_.SetData32(0x4000, 0x30);
- this->memory_.SetData32(0x4004, 0x8000);
- this->memory_.SetData32(0x4018, 0x5000);
- this->memory_.SetData32(0x401c, 0x100);
-
- EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
- DwarfCie cie{};
- cie.fde_address_encoding = DW_EH_PE_udata4;
- cie.segment_size = 0x10;
- this->section_->TestSetCachedCieEntry(0x8000, cie);
- EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
- const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(0x4020U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x4034U, fde->cfa_instructions_end);
- EXPECT_EQ(0x5000U, fde->pc_start);
- EXPECT_EQ(0x5100U, fde->pc_end);
- EXPECT_EQ(0x8000U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_augment) {
- this->memory_.SetData32(0x4000, 0x100);
- this->memory_.SetData32(0x4004, 0x8000);
- this->memory_.SetData32(0x4008, 0x5000);
- this->memory_.SetData32(0x400c, 0x100);
- this->memory_.SetMemory(0x4010, std::vector<uint8_t>{0x82, 0x01});
- this->memory_.SetData16(0x4012, 0x1234);
-
- EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
- DwarfCie cie{};
- cie.fde_address_encoding = DW_EH_PE_udata4;
- cie.augmentation_string.push_back('z');
- cie.lsda_encoding = DW_EH_PE_udata2;
- this->section_->TestSetCachedCieEntry(0x8000, cie);
- EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
- const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(0x4094U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x4104U, fde->cfa_instructions_end);
- EXPECT_EQ(0x5000U, fde->pc_start);
- EXPECT_EQ(0x5100U, fde->pc_end);
- EXPECT_EQ(0x8000U, fde->cie_offset);
- EXPECT_EQ(0x1234U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_64_no_augment) {
- this->memory_.SetData32(0x4000, 0xffffffff);
- this->memory_.SetData64(0x4004, 0x100);
- this->memory_.SetData64(0x400c, 0x12345678);
- this->memory_.SetData32(0x4014, 0x5000);
- this->memory_.SetData32(0x4018, 0x100);
-
- EXPECT_CALL(*this->section_, GetCieOffsetFromFde64(0x12345678))
- .WillOnce(::testing::Return(0x12345678));
- DwarfCie cie{};
- cie.fde_address_encoding = DW_EH_PE_udata4;
- this->section_->TestSetCachedCieEntry(0x12345678, cie);
- EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
- const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(0x401cU, fde->cfa_instructions_offset);
- EXPECT_EQ(0x410cU, fde->cfa_instructions_end);
- EXPECT_EQ(0x5000U, fde->pc_start);
- EXPECT_EQ(0x5100U, fde->pc_end);
- EXPECT_EQ(0x12345678U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_cached) {
- DwarfCie cie{};
- cie.fde_address_encoding = DW_EH_PE_udata4;
- cie.augmentation_string.push_back('z');
- cie.lsda_encoding = DW_EH_PE_udata2;
-
- DwarfFde fde_cached{};
- fde_cached.cfa_instructions_offset = 0x1000;
- fde_cached.cfa_instructions_end = 0x1100;
- fde_cached.pc_start = 0x9000;
- fde_cached.pc_end = 0x9400;
- fde_cached.cie_offset = 0x30000;
- fde_cached.cie = &cie;
- this->section_->TestSetCachedFdeEntry(0x6000, fde_cached);
-
- const DwarfFde* fde = this->section_->GetFdeFromOffset(0x6000);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_EQ(&cie, fde->cie);
- EXPECT_EQ(0x1000U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x1100U, fde->cfa_instructions_end);
- EXPECT_EQ(0x9000U, fde->pc_start);
- EXPECT_EQ(0x9400U, fde->pc_end);
- EXPECT_EQ(0x30000U, fde->cie_offset);
-}
-
TYPED_TEST_P(DwarfSectionImplTest, GetCfaLocationInfo_cie_not_cached) {
DwarfCie cie{};
cie.cfa_instructions_offset = 0x3000;
@@ -895,18 +571,16 @@
ASSERT_EQ("", GetFakeLogBuf());
}
-REGISTER_TYPED_TEST_CASE_P(
- DwarfSectionImplTest, Eval_cfa_expr_eval_fail, Eval_cfa_expr_no_stack,
- Eval_cfa_expr_is_register, Eval_cfa_expr, Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa,
- Eval_cfa_bad, Eval_cfa_register_prev, Eval_cfa_register_from_value, Eval_double_indirection,
- Eval_register_reference_chain, Eval_dex_pc, Eval_invalid_register, Eval_different_reg_locations,
- Eval_return_address_undefined, Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc,
- Eval_reg_expr, Eval_reg_val_expr, GetCie_fail_should_not_cache, GetCie_32_version_check,
- GetCie_negative_data_alignment_factor, GetCie_64_no_augment, GetCie_augment, GetCie_version_3,
- GetCie_version_4, GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
- GetFdeFromOffset_32_no_augment_non_zero_segment_size, GetFdeFromOffset_32_augment,
- GetFdeFromOffset_64_no_augment, GetFdeFromOffset_cached, GetCfaLocationInfo_cie_not_cached,
- GetCfaLocationInfo_cie_cached, Log);
+REGISTER_TYPED_TEST_CASE_P(DwarfSectionImplTest, GetCieFromOffset_fail_should_not_cache,
+ GetFdeFromOffset_fail_should_not_cache, Eval_cfa_expr_eval_fail,
+ Eval_cfa_expr_no_stack, Eval_cfa_expr_is_register, Eval_cfa_expr,
+ Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa, Eval_cfa_bad,
+ Eval_cfa_register_prev, Eval_cfa_register_from_value,
+ Eval_double_indirection, Eval_register_reference_chain, Eval_dex_pc,
+ Eval_invalid_register, Eval_different_reg_locations,
+ Eval_return_address_undefined, Eval_pc_zero, Eval_return_address,
+ Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
+ GetCfaLocationInfo_cie_not_cached, GetCfaLocationInfo_cie_cached, Log);
typedef ::testing::Types<uint32_t, uint64_t> DwarfSectionImplTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfSectionImplTest, DwarfSectionImplTestTypes);
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp
index 2c6c879..d754fcc 100644
--- a/libunwindstack/tests/DwarfSectionTest.cpp
+++ b/libunwindstack/tests/DwarfSectionTest.cpp
@@ -30,24 +30,18 @@
MockDwarfSection(Memory* memory) : DwarfSection(memory) {}
virtual ~MockDwarfSection() = default;
- MOCK_METHOD3(Log, bool(uint8_t, uint64_t, const DwarfFde*));
+ MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
MOCK_METHOD5(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*));
+ MOCK_METHOD3(Log, bool(uint8_t, uint64_t, const DwarfFde*));
+
+ MOCK_METHOD1(GetFdes, void(std::vector<const DwarfFde*>*));
+
+ MOCK_METHOD1(GetFdeFromPc, const DwarfFde*(uint64_t));
+
MOCK_METHOD3(GetCfaLocationInfo, bool(uint64_t, const DwarfFde*, dwarf_loc_regs_t*));
- MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
-
- MOCK_METHOD2(GetFdeOffsetFromPc, bool(uint64_t, uint64_t*));
-
- MOCK_METHOD1(GetFdeFromOffset, const DwarfFde*(uint64_t));
-
- MOCK_METHOD1(GetFdeFromIndex, const DwarfFde*(size_t));
-
- MOCK_METHOD1(IsCie32, bool(uint32_t));
-
- MOCK_METHOD1(IsCie64, bool(uint64_t));
-
MOCK_METHOD1(GetCieOffsetFromFde32, uint64_t(uint32_t));
MOCK_METHOD1(GetCieOffsetFromFde64, uint64_t(uint64_t));
@@ -57,112 +51,60 @@
class DwarfSectionTest : public ::testing::Test {
protected:
+ void SetUp() override { section_.reset(new MockDwarfSection(&memory_)); }
+
MemoryFake memory_;
+ std::unique_ptr<MockDwarfSection> section_;
};
-TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_fail_from_pc) {
- MockDwarfSection mock_section(&memory_);
-
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(false));
-
- // Verify nullptr when GetFdeOffsetFromPc fails.
- ASSERT_TRUE(mock_section.GetFdeFromPc(0x1000) == nullptr);
-}
-
-TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_fail_fde_pc_end) {
- MockDwarfSection mock_section(&memory_);
-
- DwarfFde fde{};
- fde.pc_end = 0x500;
-
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
- // Verify nullptr when GetFdeOffsetFromPc fails.
- ASSERT_TRUE(mock_section.GetFdeFromPc(0x1000) == nullptr);
-}
-
-TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_pass) {
- MockDwarfSection mock_section(&memory_);
-
- DwarfFde fde{};
- fde.pc_end = 0x2000;
-
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
- // Verify nullptr when GetFdeOffsetFromPc fails.
- ASSERT_EQ(&fde, mock_section.GetFdeFromPc(0x1000));
-}
-
TEST_F(DwarfSectionTest, Step_fail_fde) {
- MockDwarfSection mock_section(&memory_);
-
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(false));
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(nullptr));
bool finished;
- ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
+ ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
}
TEST_F(DwarfSectionTest, Step_fail_cie_null) {
- MockDwarfSection mock_section(&memory_);
-
DwarfFde fde{};
fde.pc_end = 0x2000;
fde.cie = nullptr;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
bool finished;
- ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
+ ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
}
TEST_F(DwarfSectionTest, Step_fail_cfa_location) {
- MockDwarfSection mock_section(&memory_);
-
DwarfCie cie{};
DwarfFde fde{};
fde.pc_end = 0x2000;
fde.cie = &cie;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
- EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
+ EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
.WillOnce(::testing::Return(false));
bool finished;
- ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
+ ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
}
TEST_F(DwarfSectionTest, Step_pass) {
- MockDwarfSection mock_section(&memory_);
-
DwarfCie cie{};
DwarfFde fde{};
fde.pc_end = 0x2000;
fde.cie = &cie;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
- EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
+ EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
.WillOnce(::testing::Return(true));
MemoryFake process;
- EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+ EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
.WillOnce(::testing::Return(true));
bool finished;
- ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
}
static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde,
@@ -173,64 +115,53 @@
}
TEST_F(DwarfSectionTest, Step_cache) {
- MockDwarfSection mock_section(&memory_);
-
DwarfCie cie{};
DwarfFde fde{};
fde.pc_start = 0x500;
fde.pc_end = 0x2000;
fde.cie = &cie;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
- EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
+ EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
.WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
MemoryFake process;
- EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+ EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
.WillRepeatedly(::testing::Return(true));
bool finished;
- ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
- ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
- ASSERT_TRUE(mock_section.Step(0x1500, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x1500, nullptr, &process, &finished));
}
TEST_F(DwarfSectionTest, Step_cache_not_in_pc) {
- MockDwarfSection mock_section(&memory_);
-
DwarfCie cie{};
DwarfFde fde0{};
fde0.pc_start = 0x1000;
fde0.pc_end = 0x2000;
fde0.cie = &cie;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde0));
- EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde0, ::testing::_))
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde0));
+ EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde0, ::testing::_))
.WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
MemoryFake process;
- EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+ EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
.WillRepeatedly(::testing::Return(true));
bool finished;
- ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
DwarfFde fde1{};
fde1.pc_start = 0x500;
fde1.pc_end = 0x800;
fde1.cie = &cie;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x600, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde1));
- EXPECT_CALL(mock_section, GetCfaLocationInfo(0x600, &fde1, ::testing::_))
+ EXPECT_CALL(*section_, GetFdeFromPc(0x600)).WillOnce(::testing::Return(&fde1));
+ EXPECT_CALL(*section_, GetCfaLocationInfo(0x600, &fde1, ::testing::_))
.WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
- ASSERT_TRUE(mock_section.Step(0x600, nullptr, &process, &finished));
- ASSERT_TRUE(mock_section.Step(0x700, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x600, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x700, nullptr, &process, &finished));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index a8bb4aa..43c6a97 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -242,44 +242,21 @@
ASSERT_EQ(0xa020U, entries[4]);
}
-TEST_F(ElfInterfaceArmTest, HandleType_not_arm_exidx) {
+TEST_F(ElfInterfaceArmTest, HandleUnknownType_arm_exidx) {
ElfInterfaceArmFake interface(&memory_);
- ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME));
- ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK));
-}
-
-TEST_F(ElfInterfaceArmTest, HandleType_arm_exidx) {
- ElfInterfaceArmFake interface(&memory_);
-
- Elf32_Phdr phdr = {};
interface.FakeSetStartOffset(0x1000);
interface.FakeSetTotalEntries(100);
- phdr.p_offset = 0x2000;
- phdr.p_filesz = 0xa00;
- // Verify that if reads fail, we don't set the values but still get true.
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ // Verify that if the type is not the one we want, we don't set the values.
+ interface.HandleUnknownType(0x70000000, 0x2000, 320);
ASSERT_EQ(0x1000U, interface.start_offset());
ASSERT_EQ(100U, interface.total_entries());
// Everything is correct and present.
- memory_.SetMemory(0x1000, &phdr, sizeof(phdr));
- ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+ interface.HandleUnknownType(0x70000001, 0x2000, 320);
ASSERT_EQ(0x2000U, interface.start_offset());
- ASSERT_EQ(320U, interface.total_entries());
+ ASSERT_EQ(40U, interface.total_entries());
}
TEST_F(ElfInterfaceArmTest, StepExidx) {
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index 487d39c..aa6df84 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -656,8 +656,7 @@
memory_.SetData32(0x5000, 0xfc);
memory_.SetData32(0x5004, 0xffffffff);
- memory_.SetData8(0x5008, 1);
- memory_.SetData8(0x5009, '\0');
+ memory_.SetMemory(0x5008, std::vector<uint8_t>{1, '\0', 4, 8, 2});
memory_.SetData32(0x5100, 0xfc);
memory_.SetData32(0x5104, 0);
@@ -678,56 +677,6 @@
InitHeadersDebugFrame<ElfInterface64Fake>();
}
-template <typename ElfType>
-void ElfInterfaceTest::InitHeadersEhFrameFail() {
- ElfType elf(&memory_);
-
- elf.FakeSetEhFrameOffset(0x1000);
- elf.FakeSetEhFrameSize(0x100);
- elf.FakeSetDebugFrameOffset(0);
- elf.FakeSetDebugFrameSize(0);
-
- elf.InitHeaders(0);
-
- EXPECT_TRUE(elf.eh_frame() == nullptr);
- EXPECT_EQ(0U, elf.eh_frame_offset());
- EXPECT_EQ(static_cast<uint64_t>(-1), elf.eh_frame_size());
- EXPECT_TRUE(elf.debug_frame() == nullptr);
-}
-
-TEST_F(ElfInterfaceTest, init_headers_eh_frame32_fail) {
- InitHeadersEhFrameFail<ElfInterface32Fake>();
-}
-
-TEST_F(ElfInterfaceTest, init_headers_eh_frame64_fail) {
- InitHeadersEhFrameFail<ElfInterface64Fake>();
-}
-
-template <typename ElfType>
-void ElfInterfaceTest::InitHeadersDebugFrameFail() {
- ElfType elf(&memory_);
-
- elf.FakeSetEhFrameOffset(0);
- elf.FakeSetEhFrameSize(0);
- elf.FakeSetDebugFrameOffset(0x1000);
- elf.FakeSetDebugFrameSize(0x100);
-
- elf.InitHeaders(0);
-
- EXPECT_TRUE(elf.eh_frame() == nullptr);
- EXPECT_TRUE(elf.debug_frame() == nullptr);
- EXPECT_EQ(0U, elf.debug_frame_offset());
- EXPECT_EQ(static_cast<uint64_t>(-1), elf.debug_frame_size());
-}
-
-TEST_F(ElfInterfaceTest, init_headers_debug_frame32_fail) {
- InitHeadersDebugFrameFail<ElfInterface32Fake>();
-}
-
-TEST_F(ElfInterfaceTest, init_headers_debug_frame64_fail) {
- InitHeadersDebugFrameFail<ElfInterface64Fake>();
-}
-
template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void ElfInterfaceTest::InitSectionHeadersMalformed() {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -1024,11 +973,7 @@
// CIE 32.
memory_.SetData32(0x600, 0xfc);
memory_.SetData32(0x604, 0xffffffff);
- memory_.SetData8(0x608, 1);
- memory_.SetData8(0x609, '\0');
- memory_.SetData8(0x60a, 0x4);
- memory_.SetData8(0x60b, 0x4);
- memory_.SetData8(0x60c, 0x1);
+ memory_.SetMemory(0x608, std::vector<uint8_t>{1, '\0', 4, 4, 1});
// FDE 32.
memory_.SetData32(0x700, 0xfc);
@@ -1085,11 +1030,7 @@
// CIE 32.
memory_.SetData32(0x600, 0xfc);
memory_.SetData32(0x604, 0);
- memory_.SetData8(0x608, 1);
- memory_.SetData8(0x609, '\0');
- memory_.SetData8(0x60a, 0x4);
- memory_.SetData8(0x60b, 0x4);
- memory_.SetData8(0x60c, 0x1);
+ memory_.SetMemory(0x608, std::vector<uint8_t>{1, '\0', 4, 4, 1});
// FDE 32.
memory_.SetData32(0x700, 0xfc);
diff --git a/libunwindstack/tests/MemoryTest.cpp b/libunwindstack/tests/MemoryTest.cpp
index 4a9ed9f..3655984 100644
--- a/libunwindstack/tests/MemoryTest.cpp
+++ b/libunwindstack/tests/MemoryTest.cpp
@@ -51,40 +51,6 @@
uint64_t four;
};
-TEST(MemoryTest, read_field) {
- MemoryFakeAlwaysReadZero memory;
-
- FakeStruct data;
- memset(&data, 0xff, sizeof(data));
- ASSERT_TRUE(memory.ReadField(0, &data, &data.one, sizeof(data.one)));
- ASSERT_EQ(0, data.one);
-
- memset(&data, 0xff, sizeof(data));
- ASSERT_TRUE(memory.ReadField(0, &data, &data.two, sizeof(data.two)));
- ASSERT_FALSE(data.two);
-
- memset(&data, 0xff, sizeof(data));
- ASSERT_TRUE(memory.ReadField(0, &data, &data.three, sizeof(data.three)));
- ASSERT_EQ(0U, data.three);
-
- memset(&data, 0xff, sizeof(data));
- ASSERT_TRUE(memory.ReadField(0, &data, &data.four, sizeof(data.four)));
- ASSERT_EQ(0U, data.four);
-}
-
-TEST(MemoryTest, read_field_fails) {
- MemoryFakeAlwaysReadZero memory;
-
- FakeStruct data;
- memset(&data, 0xff, sizeof(data));
-
- ASSERT_FALSE(memory.ReadField(UINT64_MAX, &data, &data.three, sizeof(data.three)));
-
- // Field and start reversed, should fail.
- ASSERT_FALSE(memory.ReadField(100, &data.two, &data, sizeof(data.two)));
- ASSERT_FALSE(memory.ReadField(0, &data.two, &data, sizeof(data.two)));
-}
-
TEST(MemoryTest, read_string) {
std::string name("string_in_memory");
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 83695bb..ea992c7 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -32,6 +32,7 @@
#include <vector>
#include <android-base/stringprintf.h>
+#include <android-base/threads.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
@@ -231,8 +232,7 @@
usleep(1000);
}
ASSERT_NE(0, tid.load());
- // Portable tgkill method.
- ASSERT_EQ(0, syscall(__NR_tgkill, getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
+ ASSERT_EQ(0, tgkill(getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
// Wait for context data.
void* ucontext;
diff --git a/libutils/Android.bp b/libutils/Android.bp
index bbfa9d8..d635e65 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -155,6 +155,7 @@
],
},
linux: {
+ shared_libs: ["libbase"],
srcs: [
"Looper.cpp",
],
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 3c4d81c..583c6b9 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -48,10 +48,10 @@
// Constructor. Create an empty object.
FileMap::FileMap(void)
- : mFileName(NULL),
- mBasePtr(NULL),
+ : mFileName(nullptr),
+ mBasePtr(nullptr),
mBaseLength(0),
- mDataPtr(NULL),
+ mDataPtr(nullptr),
mDataLength(0)
#if defined(__MINGW32__)
,
@@ -69,9 +69,9 @@
, mFileHandle(other.mFileHandle), mFileMapping(other.mFileMapping)
#endif
{
- other.mFileName = NULL;
- other.mBasePtr = NULL;
- other.mDataPtr = NULL;
+ other.mFileName = nullptr;
+ other.mBasePtr = nullptr;
+ other.mDataPtr = nullptr;
#if defined(__MINGW32__)
other.mFileHandle = INVALID_HANDLE_VALUE;
other.mFileMapping = NULL;
@@ -86,9 +86,9 @@
mDataOffset = other.mDataOffset;
mDataPtr = other.mDataPtr;
mDataLength = other.mDataLength;
- other.mFileName = NULL;
- other.mBasePtr = NULL;
- other.mDataPtr = NULL;
+ other.mFileName = nullptr;
+ other.mBasePtr = nullptr;
+ other.mDataPtr = nullptr;
#if defined(__MINGW32__)
mFileHandle = other.mFileHandle;
mFileMapping = other.mFileMapping;
@@ -101,7 +101,7 @@
// Destructor.
FileMap::~FileMap(void)
{
- if (mFileName != NULL) {
+ if (mFileName != nullptr) {
free(mFileName);
}
#if defined(__MINGW32__)
@@ -196,7 +196,7 @@
if (!readOnly)
prot |= PROT_WRITE;
- ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
+ ptr = mmap(nullptr, adjLength, prot, flags, fd, adjOffset);
if (ptr == MAP_FAILED) {
ALOGE("mmap(%lld,%zu) failed: %s\n",
(long long)adjOffset, adjLength, strerror(errno));
@@ -205,7 +205,7 @@
mBasePtr = ptr;
#endif // !defined(__MINGW32__)
- mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
+ mFileName = origFileName != nullptr ? strdup(origFileName) : nullptr;
mBaseLength = adjLength;
mDataOffset = offset;
mDataPtr = (char*) mBasePtr + adjust;
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 6c57b2e..102fdf0 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -29,7 +29,7 @@
void WeakMessageHandler::handleMessage(const Message& message) {
sp<MessageHandler> handler = mHandler.promote();
- if (handler != NULL) {
+ if (handler != nullptr) {
handler->handleMessage(message);
}
}
@@ -60,24 +60,22 @@
static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
static pthread_key_t gTLSKey = 0;
-Looper::Looper(bool allowNonCallbacks) :
- mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
- mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
- mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
- mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
- LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",
- strerror(errno));
+Looper::Looper(bool allowNonCallbacks)
+ : mAllowNonCallbacks(allowNonCallbacks),
+ mSendingMessage(false),
+ mPolling(false),
+ mEpollRebuildRequired(false),
+ mNextRequestSeq(0),
+ mResponseIndex(0),
+ mNextMessageUptime(LLONG_MAX) {
+ mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
+ LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));
AutoMutex _l(mLock);
rebuildEpollLocked();
}
Looper::~Looper() {
- close(mWakeEventFd);
- mWakeEventFd = -1;
- if (mEpollFd >= 0) {
- close(mEpollFd);
- }
}
void Looper::initTLSKey() {
@@ -87,7 +85,7 @@
void Looper::threadDestructor(void *st) {
Looper* const self = static_cast<Looper*>(st);
- if (self != NULL) {
+ if (self != nullptr) {
self->decStrong((void*)threadDestructor);
}
}
@@ -95,13 +93,13 @@
void Looper::setForThread(const sp<Looper>& looper) {
sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
- if (looper != NULL) {
+ if (looper != nullptr) {
looper->incStrong((void*)threadDestructor);
}
pthread_setspecific(gTLSKey, looper.get());
- if (old != NULL) {
+ if (old != nullptr) {
old->decStrong((void*)threadDestructor);
}
}
@@ -116,7 +114,7 @@
sp<Looper> Looper::prepare(int opts) {
bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
sp<Looper> looper = Looper::getForThread();
- if (looper == NULL) {
+ if (looper == nullptr) {
looper = new Looper(allowNonCallbacks);
Looper::setForThread(looper);
}
@@ -137,18 +135,18 @@
#if DEBUG_CALLBACKS
ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
#endif
- close(mEpollFd);
+ mEpollFd.reset();
}
// Allocate the new epoll instance and register the wake pipe.
- mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+ mEpollFd.reset(epoll_create(EPOLL_SIZE_HINT));
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
- eventItem.data.fd = mWakeEventFd;
- int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
+ eventItem.data.fd = mWakeEventFd.get();
+ int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
strerror(errno));
@@ -157,7 +155,7 @@
struct epoll_event eventItem;
request.initEventItem(&eventItem);
- int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
+ int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
if (epollResult < 0) {
ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
request.fd, strerror(errno));
@@ -190,9 +188,9 @@
"fd=%d, events=0x%x, data=%p",
this, ident, fd, events, data);
#endif
- if (outFd != NULL) *outFd = fd;
- if (outEvents != NULL) *outEvents = events;
- if (outData != NULL) *outData = data;
+ if (outFd != nullptr) *outFd = fd;
+ if (outEvents != nullptr) *outEvents = events;
+ if (outData != nullptr) *outData = data;
return ident;
}
}
@@ -201,9 +199,9 @@
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
- if (outFd != NULL) *outFd = 0;
- if (outEvents != NULL) *outEvents = 0;
- if (outData != NULL) *outData = NULL;
+ if (outFd != nullptr) *outFd = 0;
+ if (outEvents != nullptr) *outEvents = 0;
+ if (outData != nullptr) *outData = nullptr;
return result;
}
@@ -239,7 +237,7 @@
mPolling = true;
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
- int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
+ int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
// No longer idling.
mPolling = false;
@@ -281,7 +279,7 @@
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
- if (fd == mWakeEventFd) {
+ if (fd == mWakeEventFd.get()) {
if (epollEvents & EPOLLIN) {
awoken();
} else {
@@ -401,11 +399,11 @@
#endif
uint64_t inc = 1;
- ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
+ ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
- LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s",
- mWakeEventFd, strerror(errno));
+ LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s", mWakeEventFd.get(),
+ strerror(errno));
}
}
}
@@ -416,7 +414,7 @@
#endif
uint64_t counter;
- TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
+ TEMP_FAILURE_RETRY(read(mWakeEventFd.get(), &counter, sizeof(uint64_t)));
}
void Looper::pushResponse(int events, const Request& request) {
@@ -427,7 +425,7 @@
}
int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
- return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
+ return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : nullptr, data);
}
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
@@ -467,14 +465,14 @@
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
- int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+ int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
if (epollResult < 0) {
ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
return -1;
}
mRequests.add(fd, request);
} else {
- int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
+ int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_MOD, fd, &eventItem);
if (epollResult < 0) {
if (errno == ENOENT) {
// Tolerate ENOENT because it means that an older file descriptor was
@@ -495,7 +493,7 @@
"being recycled, falling back on EPOLL_CTL_ADD: %s",
this, strerror(errno));
#endif
- epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+ epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
if (epollResult < 0) {
ALOGE("Error modifying or adding epoll events for fd %d: %s",
fd, strerror(errno));
@@ -542,7 +540,7 @@
// updating the epoll set so that we avoid accidentally leaking callbacks.
mRequests.removeItemsAt(requestIndex);
- int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
+ int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_DEL, fd, nullptr);
if (epollResult < 0) {
if (seq != -1 && (errno == EBADF || errno == ENOENT)) {
// Tolerate EBADF or ENOENT when the sequence number is known because it
diff --git a/libutils/NativeHandle.cpp b/libutils/NativeHandle.cpp
index 97d06b8..d437a9f 100644
--- a/libutils/NativeHandle.cpp
+++ b/libutils/NativeHandle.cpp
@@ -20,7 +20,7 @@
namespace android {
sp<NativeHandle> NativeHandle::create(native_handle_t* handle, bool ownsHandle) {
- return handle ? new NativeHandle(handle, ownsHandle) : NULL;
+ return handle ? new NativeHandle(handle, ownsHandle) : nullptr;
}
NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle)
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
index cbf042e..c9ae210 100644
--- a/libutils/Printer.cpp
+++ b/libutils/Printer.cpp
@@ -73,7 +73,7 @@
}
void LogPrinter::printLine(const char* string) {
- if (string == NULL) {
+ if (string == nullptr) {
ALOGW("%s: NULL string passed in", __FUNCTION__);
return;
}
@@ -107,7 +107,7 @@
}
void FdPrinter::printLine(const char* string) {
- if (string == NULL) {
+ if (string == nullptr) {
ALOGW("%s: NULL string passed in", __FUNCTION__);
return;
} else if (mFd < 0) {
@@ -127,16 +127,16 @@
mTarget(target),
mPrefix(prefix ?: "") {
- if (target == NULL) {
+ if (target == nullptr) {
ALOGW("%s: Target string was NULL", __FUNCTION__);
}
}
void String8Printer::printLine(const char* string) {
- if (string == NULL) {
+ if (string == nullptr) {
ALOGW("%s: NULL string passed in", __FUNCTION__);
return;
- } else if (mTarget == NULL) {
+ } else if (mTarget == nullptr) {
ALOGW("%s: Target string was NULL", __FUNCTION__);
return;
}
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
index b8fb6dc..f054de9 100644
--- a/libutils/ProcessCallStack.cpp
+++ b/libutils/ProcessCallStack.cpp
@@ -42,14 +42,14 @@
static const char* PATH_SELF_TASK = "/proc/self/task";
static void dumpProcessHeader(Printer& printer, pid_t pid, const char* timeStr) {
- if (timeStr == NULL) {
+ if (timeStr == nullptr) {
ALOGW("%s: timeStr was NULL", __FUNCTION__);
return;
}
char path[PATH_MAX];
char procNameBuf[MAX_PROC_PATH];
- char* procName = NULL;
+ char* procName = nullptr;
FILE* fp;
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
@@ -76,7 +76,7 @@
static String8 getThreadName(pid_t tid) {
char path[PATH_MAX];
- char* procName = NULL;
+ char* procName = nullptr;
char procNameBuf[MAX_PROC_PATH];
FILE* fp;
@@ -88,7 +88,7 @@
ALOGE("%s: Failed to open %s", __FUNCTION__, path);
}
- if (procName == NULL) {
+ if (procName == nullptr) {
// Reading /proc/self/task/%d/comm failed due to a race
return String8::format("[err-unknown-tid-%d]", tid);
}
@@ -128,7 +128,7 @@
void ProcessCallStack::update() {
std::unique_ptr<DIR, decltype(&closedir)> dp(opendir(PATH_SELF_TASK), closedir);
- if (dp == NULL) {
+ if (dp == nullptr) {
ALOGE("%s: Failed to update the process's call stacks: %s",
__FUNCTION__, strerror(errno));
return;
@@ -140,7 +140,7 @@
// Get current time.
{
- time_t t = time(NULL);
+ time_t t = time(nullptr);
struct tm tm;
localtime_r(&t, &tm);
@@ -152,7 +152,7 @@
* - Read every file in directory => get every tid
*/
dirent* ep;
- while ((ep = readdir(dp.get())) != NULL) {
+ while ((ep = readdir(dp.get())) != nullptr) {
pid_t tid = -1;
sscanf(ep->d_name, "%d", &tid);
diff --git a/libutils/PropertyMap.cpp b/libutils/PropertyMap.cpp
index 4bcdd0f..b8c065d 100644
--- a/libutils/PropertyMap.cpp
+++ b/libutils/PropertyMap.cpp
@@ -112,7 +112,7 @@
}
status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
- *outMap = NULL;
+ *outMap = nullptr;
Tokenizer* tokenizer;
status_t status = Tokenizer::open(filename, &tokenizer);
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 8bccb0f..9074850 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -712,7 +712,7 @@
delete mRefs;
}
// For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
- const_cast<weakref_impl*&>(mRefs) = NULL;
+ const_cast<weakref_impl*&>(mRefs) = nullptr;
}
void RefBase::extendObjectLifetime(int32_t mode)
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index bad98b2..7910c6e 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -75,7 +75,7 @@
"Invalid buffer size %zu", newSize);
buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
- if (buf != NULL) {
+ if (buf != nullptr) {
buf->mSize = newSize;
return buf;
}
@@ -94,7 +94,7 @@
if (onlyOwner()) {
return const_cast<SharedBuffer*>(this);
}
- return 0;
+ return nullptr;
}
SharedBuffer* SharedBuffer::reset(size_t new_size) const
diff --git a/libutils/SharedBuffer.h b/libutils/SharedBuffer.h
index 81cadff..fdf13a9 100644
--- a/libutils/SharedBuffer.h
+++ b/libutils/SharedBuffer.h
@@ -124,11 +124,11 @@
}
SharedBuffer* SharedBuffer::bufferFromData(void* data) {
- return data ? static_cast<SharedBuffer *>(data)-1 : 0;
+ return data ? static_cast<SharedBuffer *>(data)-1 : nullptr;
}
const SharedBuffer* SharedBuffer::bufferFromData(const void* data) {
- return data ? static_cast<const SharedBuffer *>(data)-1 : 0;
+ return data ? static_cast<const SharedBuffer *>(data)-1 : nullptr;
}
size_t SharedBuffer::sizeFromData(const void* data) {
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 84d53dd..f820b8b 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -74,7 +74,7 @@
}
String16::String16(StaticLinkage)
- : mString(0)
+ : mString(nullptr)
{
// this constructor is used when we can't rely on the static-initializers
// having run. In this case we always allocate an empty string. It's less
@@ -336,7 +336,7 @@
{
const size_t N = size();
const char16_t* str = string();
- char16_t* edit = NULL;
+ char16_t* edit = nullptr;
for (size_t i=0; i<N; i++) {
const char16_t v = str[i];
if (v >= 'A' && v <= 'Z') {
@@ -358,7 +358,7 @@
{
const size_t N = size();
const char16_t* str = string();
- char16_t* edit = NULL;
+ char16_t* edit = nullptr;
for (size_t i=0; i<N; i++) {
if (str[i] == replaceThis) {
if (!edit) {
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 580e870..8d318f7 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -58,7 +58,7 @@
{
if (len > 0) {
if (len == SIZE_MAX) {
- return NULL;
+ return nullptr;
}
SharedBuffer* buf = SharedBuffer::alloc(len+1);
ALOG_ASSERT(buf, "Unable to allocate shared buffer");
@@ -68,7 +68,7 @@
str[len] = 0;
return str;
}
- return NULL;
+ return nullptr;
}
return getEmptyString();
@@ -126,7 +126,7 @@
}
String8::String8(StaticLinkage)
- : mString(0)
+ : mString(nullptr)
{
// this constructor is used when we can't rely on the static-initializers
// having run. In this case we always allocate an empty string. It's less
@@ -147,7 +147,7 @@
String8::String8(const char* o)
: mString(allocFromUTF8(o, strlen(o)))
{
- if (mString == NULL) {
+ if (mString == nullptr) {
mString = getEmptyString();
}
}
@@ -155,7 +155,7 @@
String8::String8(const char* o, size_t len)
: mString(allocFromUTF8(o, len))
{
- if (mString == NULL) {
+ if (mString == nullptr) {
mString = getEmptyString();
}
}
@@ -319,7 +319,7 @@
* second vsnprintf access undefined args.
*/
va_copy(tmp_args, args);
- n = vsnprintf(NULL, 0, fmt, tmp_args);
+ n = vsnprintf(nullptr, 0, fmt, tmp_args);
va_end(tmp_args);
if (n != 0) {
@@ -360,7 +360,7 @@
mString = str;
return str;
}
- return NULL;
+ return nullptr;
}
void String8::unlockBuffer()
@@ -512,7 +512,7 @@
const char*const buf = mString;
cp = strrchr(buf, OS_PATH_SEPARATOR);
- if (cp == NULL)
+ if (cp == nullptr)
return String8(*this);
else
return String8(cp+1);
@@ -524,7 +524,7 @@
const char*const str = mString;
cp = strrchr(str, OS_PATH_SEPARATOR);
- if (cp == NULL)
+ if (cp == nullptr)
return String8("");
else
return String8(str, cp - str);
@@ -543,7 +543,7 @@
cp = strchr(buf, OS_PATH_SEPARATOR);
}
- if (cp == NULL) {
+ if (cp == nullptr) {
String8 res = buf != str ? String8(buf) : *this;
if (outRemains) *outRemains = String8("");
return res;
@@ -567,15 +567,15 @@
// only look at the filename
lastSlash = strrchr(str, OS_PATH_SEPARATOR);
- if (lastSlash == NULL)
+ if (lastSlash == nullptr)
lastSlash = str;
else
lastSlash++;
// find the last dot
lastDot = strrchr(lastSlash, '.');
- if (lastDot == NULL)
- return NULL;
+ if (lastDot == nullptr)
+ return nullptr;
// looks good, ship it
return const_cast<char*>(lastDot);
@@ -586,7 +586,7 @@
char* ext;
ext = find_extension();
- if (ext != NULL)
+ if (ext != nullptr)
return String8(ext);
else
return String8("");
@@ -598,7 +598,7 @@
const char* const str = mString;
ext = find_extension();
- if (ext == NULL)
+ if (ext == nullptr)
return String8(*this);
else
return String8(str, ext - str);
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 7d7f0e2..43ec6c1 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -163,7 +163,7 @@
// Note that *threadID is directly available to the parent only, as it is
// assigned after the child starts. Use memory barrier / lock if the child
// or other threads also need access.
- if (threadId != NULL) {
+ if (threadId != nullptr) {
*threadId = (android_thread_id_t)thread; // XXX: this is not portable
}
return 1;
@@ -768,7 +768,7 @@
strong.clear();
// And immediately, re-acquire a strong reference for the next loop
strong = weak.promote();
- } while(strong != 0);
+ } while(strong != nullptr);
return 0;
}
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index b2df9a5..c3641ef 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -45,7 +45,7 @@
// is windows.
struct timeval t;
t.tv_sec = t.tv_usec = 0;
- gettimeofday(&t, NULL);
+ gettimeofday(&t, nullptr);
return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
}
#endif
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
index b68a2cf..f73d699 100644
--- a/libutils/Tokenizer.cpp
+++ b/libutils/Tokenizer.cpp
@@ -28,7 +28,7 @@
namespace android {
static inline bool isDelimiter(char ch, const char* delimiters) {
- return strchr(delimiters, ch) != NULL;
+ return strchr(delimiters, ch) != nullptr;
}
Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer,
@@ -46,7 +46,7 @@
}
status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) {
- *outTokenizer = NULL;
+ *outTokenizer = nullptr;
int result = NO_ERROR;
int fd = ::open(filename.string(), O_RDONLY);
@@ -64,12 +64,12 @@
FileMap* fileMap = new FileMap();
bool ownBuffer = false;
char* buffer;
- if (fileMap->create(NULL, fd, 0, length, true)) {
+ if (fileMap->create(nullptr, fd, 0, length, true)) {
fileMap->advise(FileMap::SEQUENTIAL);
buffer = static_cast<char*>(fileMap->getDataPtr());
} else {
delete fileMap;
- fileMap = NULL;
+ fileMap = nullptr;
// Fall back to reading into a buffer since we can't mmap files in sysfs.
// The length we obtained from stat is wrong too (it will always be 4096)
@@ -81,7 +81,7 @@
result = -errno;
ALOGE("Error reading file '%s': %s", filename.string(), strerror(errno));
delete[] buffer;
- buffer = NULL;
+ buffer = nullptr;
} else {
length = size_t(nrd);
}
@@ -98,7 +98,7 @@
status_t Tokenizer::fromContents(const String8& filename,
const char* contents, Tokenizer** outTokenizer) {
- *outTokenizer = new Tokenizer(filename, NULL,
+ *outTokenizer = new Tokenizer(filename, nullptr,
const_cast<char*>(contents), false, strlen(contents));
return OK;
}
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 1086831..e00fb81 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -159,7 +159,7 @@
return -1;
}
size_t dummy_index;
- if (next_index == NULL) {
+ if (next_index == nullptr) {
next_index = &dummy_index;
}
size_t num_read;
@@ -173,7 +173,7 @@
ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len)
{
- if (src == NULL || src_len == 0) {
+ if (src == nullptr || src_len == 0) {
return -1;
}
@@ -195,7 +195,7 @@
void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len)
{
- if (src == NULL || src_len == 0 || dst == NULL) {
+ if (src == nullptr || src_len == 0 || dst == nullptr) {
return;
}
@@ -363,7 +363,7 @@
void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len)
{
- if (src == NULL || src_len == 0 || dst == NULL) {
+ if (src == nullptr || src_len == 0 || dst == nullptr) {
return;
}
@@ -440,7 +440,7 @@
ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
{
- if (src == NULL || src_len == 0) {
+ if (src == nullptr || src_len == 0) {
return -1;
}
@@ -490,7 +490,7 @@
size_t utf8_to_utf32_length(const char *src, size_t src_len)
{
- if (src == NULL || src_len == 0) {
+ if (src == nullptr || src_len == 0) {
return 0;
}
size_t ret = 0;
@@ -515,7 +515,7 @@
void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst)
{
- if (src == NULL || src_len == 0 || dst == NULL) {
+ if (src == nullptr || src_len == 0 || dst == nullptr) {
return;
}
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index ef3277f..00a904d 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -44,7 +44,7 @@
// ----------------------------------------------------------------------------
VectorImpl::VectorImpl(size_t itemSize, uint32_t flags)
- : mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize)
+ : mStorage(nullptr), mCount(0), mFlags(flags), mItemSize(itemSize)
{
}
@@ -77,7 +77,7 @@
mCount = rhs.mCount;
SharedBuffer::bufferFromData(mStorage)->acquire();
} else {
- mStorage = 0;
+ mStorage = nullptr;
mCount = 0;
}
}
@@ -89,14 +89,14 @@
if (mStorage) {
const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
SharedBuffer* editable = sb->attemptEdit();
- if (editable == 0) {
+ if (editable == nullptr) {
// If we're here, we're not the only owner of the buffer.
// We must make a copy of it.
editable = SharedBuffer::alloc(sb->size());
// Fail instead of returning a pointer to storage that's not
// editable. Otherwise we'd be editing the contents of a buffer
// for which we're not the only owner, which is undefined behaviour.
- LOG_ALWAYS_FATAL_IF(editable == NULL);
+ LOG_ALWAYS_FATAL_IF(editable == nullptr);
_do_copy(editable->data(), mStorage, mCount);
release_storage();
mStorage = editable->data();
@@ -141,7 +141,7 @@
ssize_t VectorImpl::insertAt(size_t index, size_t numItems)
{
- return insertAt(0, index, numItems);
+ return insertAt(nullptr, index, numItems);
}
ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems)
@@ -177,7 +177,7 @@
const ssize_t count = size();
if (count > 1) {
void* array = const_cast<void*>(arrayImpl());
- void* temp = 0;
+ void* temp = nullptr;
ssize_t i = 1;
while (i < count) {
void* item = reinterpret_cast<char*>(array) + mItemSize*(i);
@@ -205,7 +205,7 @@
_do_copy(next, curr, 1);
next = curr;
--j;
- curr = NULL;
+ curr = nullptr;
if (j >= 0) {
curr = reinterpret_cast<char*>(array) + mItemSize*(j);
}
@@ -233,7 +233,7 @@
void VectorImpl::push()
{
- push(0);
+ push(nullptr);
}
void VectorImpl::push(const void* item)
@@ -243,7 +243,7 @@
ssize_t VectorImpl::add()
{
- return add(0);
+ return add(nullptr);
}
ssize_t VectorImpl::add(const void* item)
@@ -253,7 +253,7 @@
ssize_t VectorImpl::replaceAt(size_t index)
{
- return replaceAt(0, index);
+ return replaceAt(nullptr, index);
}
ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
@@ -267,10 +267,10 @@
void* item = editItemLocation(index);
if (item != prototype) {
- if (item == 0)
+ if (item == nullptr)
return NO_MEMORY;
_do_destroy(item, 1);
- if (prototype == 0) {
+ if (prototype == nullptr) {
_do_construct(item, 1);
} else {
_do_copy(item, prototype, 1);
@@ -294,7 +294,7 @@
void VectorImpl::finish_vector()
{
release_storage();
- mStorage = 0;
+ mStorage = nullptr;
mCount = 0;
}
@@ -315,7 +315,7 @@
return reinterpret_cast<char*>(buffer) + index*mItemSize;
}
}
- return 0;
+ return nullptr;
}
const void* VectorImpl::itemLocation(size_t index) const
@@ -330,7 +330,7 @@
return reinterpret_cast<const char*>(buffer) + index*mItemSize;
}
}
- return 0;
+ return nullptr;
}
ssize_t VectorImpl::setCapacity(size_t new_capacity)
@@ -418,7 +418,7 @@
if (sb) {
mStorage = sb->data();
} else {
- return NULL;
+ return nullptr;
}
} else {
SharedBuffer* sb = SharedBuffer::alloc(new_alloc_size);
@@ -435,7 +435,7 @@
release_storage();
mStorage = const_cast<void*>(array);
} else {
- return NULL;
+ return nullptr;
}
}
} else {
diff --git a/libutils/include/utils/AndroidThreads.h b/libutils/include/utils/AndroidThreads.h
index dab888d..a8d7851 100644
--- a/libutils/include/utils/AndroidThreads.h
+++ b/libutils/include/utils/AndroidThreads.h
@@ -106,7 +106,7 @@
const char* threadName = "android:unnamed_thread",
int32_t threadPriority = PRIORITY_DEFAULT,
size_t threadStackSize = 0,
- thread_id_t *threadId = 0)
+ thread_id_t *threadId = nullptr)
{
return androidCreateThreadEtc(entryFunction, userData, threadName,
threadPriority, threadStackSize, threadId) ? true : false;
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 9622142..0c1b875 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -49,13 +49,13 @@
// Dump a stack trace to the log using the supplied logtag.
void log(const char* logtag,
android_LogPriority priority = ANDROID_LOG_DEBUG,
- const char* prefix = 0) const;
+ const char* prefix = nullptr) const;
// Dump a stack trace to the specified file descriptor.
- void dump(int fd, int indent = 0, const char* prefix = 0) const;
+ void dump(int fd, int indent = 0, const char* prefix = nullptr) const;
// Return a string (possibly very long) containing the complete stack trace.
- String8 toString(const char* prefix = 0) const;
+ String8 toString(const char* prefix = nullptr) const;
// Dump a serialized representation of the stack trace to the specified printer.
void print(Printer& printer) const;
diff --git a/libutils/include/utils/Condition.h b/libutils/include/utils/Condition.h
index c8da67c..540ed82 100644
--- a/libutils/include/utils/Condition.h
+++ b/libutils/include/utils/Condition.h
@@ -124,7 +124,7 @@
#else // __APPLE__
// Apple doesn't support POSIX clocks.
struct timeval t;
- gettimeofday(&t, NULL);
+ gettimeofday(&t, nullptr);
ts.tv_sec = t.tv_sec;
ts.tv_nsec = t.tv_usec*1000;
#endif
diff --git a/libutils/include/utils/Looper.h b/libutils/include/utils/Looper.h
index a62e67f..c439c5c 100644
--- a/libutils/include/utils/Looper.h
+++ b/libutils/include/utils/Looper.h
@@ -24,6 +24,8 @@
#include <sys/epoll.h>
+#include <android-base/unique_fd.h>
+
namespace android {
/*
@@ -262,7 +264,7 @@
*/
int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
inline int pollOnce(int timeoutMillis) {
- return pollOnce(timeoutMillis, NULL, NULL, NULL);
+ return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);
}
/**
@@ -272,7 +274,7 @@
*/
int pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
inline int pollAll(int timeoutMillis) {
- return pollAll(timeoutMillis, NULL, NULL, NULL);
+ return pollAll(timeoutMillis, nullptr, nullptr, nullptr);
}
/**
@@ -447,7 +449,7 @@
const bool mAllowNonCallbacks; // immutable
- int mWakeEventFd; // immutable
+ android::base::unique_fd mWakeEventFd; // immutable
Mutex mLock;
Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
@@ -457,7 +459,7 @@
// any use of it is racy anyway.
volatile bool mPolling;
- int mEpollFd; // guarded by mLock but only modified on the looper thread
+ android::base::unique_fd mEpollFd; // guarded by mLock but only modified on the looper thread
bool mEpollRebuildRequired; // guarded by mLock
// Locked list of file descriptor monitoring requests.
diff --git a/libutils/include/utils/LruCache.h b/libutils/include/utils/LruCache.h
index 89dccd6..36775d0 100644
--- a/libutils/include/utils/LruCache.h
+++ b/libutils/include/utils/LruCache.h
@@ -71,7 +71,7 @@
Entry* parent;
Entry* child;
- Entry(TKey _key, TValue _value) : key(_key), value(_value), parent(NULL), child(NULL) {
+ Entry(TKey _key, TValue _value) : key(_key), value(_value), parent(nullptr), child(nullptr) {
}
const TKey& getKey() const final { return key; }
};
@@ -162,9 +162,9 @@
template <typename TKey, typename TValue>
LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity)
: mSet(new LruCacheSet())
- , mListener(NULL)
- , mOldest(NULL)
- , mYoungest(NULL)
+ , mListener(nullptr)
+ , mOldest(nullptr)
+ , mYoungest(nullptr)
, mMaxCapacity(maxCapacity)
, mNullValue(0) {
mSet->max_load_factor(1.0);
@@ -236,7 +236,7 @@
template <typename TKey, typename TValue>
bool LruCache<TKey, TValue>::removeOldest() {
- if (mOldest != NULL) {
+ if (mOldest != nullptr) {
return remove(mOldest->key);
// TODO: should probably abort if false
}
@@ -254,12 +254,12 @@
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::clear() {
if (mListener) {
- for (Entry* p = mOldest; p != NULL; p = p->child) {
+ for (Entry* p = mOldest; p != nullptr; p = p->child) {
(*mListener)(p->key, p->value);
}
}
- mYoungest = NULL;
- mOldest = NULL;
+ mYoungest = nullptr;
+ mOldest = nullptr;
for (auto entry : *mSet.get()) {
delete entry;
}
@@ -268,7 +268,7 @@
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::attachToCache(Entry& entry) {
- if (mYoungest == NULL) {
+ if (mYoungest == nullptr) {
mYoungest = mOldest = &entry;
} else {
entry.parent = mYoungest;
@@ -279,19 +279,19 @@
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::detachFromCache(Entry& entry) {
- if (entry.parent != NULL) {
+ if (entry.parent != nullptr) {
entry.parent->child = entry.child;
} else {
mOldest = entry.child;
}
- if (entry.child != NULL) {
+ if (entry.child != nullptr) {
entry.child->parent = entry.parent;
} else {
mYoungest = entry.parent;
}
- entry.parent = NULL;
- entry.child = NULL;
+ entry.parent = nullptr;
+ entry.child = nullptr;
}
}
diff --git a/libutils/include/utils/Mutex.h b/libutils/include/utils/Mutex.h
index 1228df4..29c2e8c 100644
--- a/libutils/include/utils/Mutex.h
+++ b/libutils/include/utils/Mutex.h
@@ -100,7 +100,7 @@
Mutex();
explicit Mutex(const char* name);
- explicit Mutex(int type, const char* name = NULL);
+ explicit Mutex(int type, const char* name = nullptr);
~Mutex();
// lock or unlock the mutex
@@ -160,10 +160,10 @@
#if !defined(_WIN32)
inline Mutex::Mutex() {
- pthread_mutex_init(&mMutex, NULL);
+ pthread_mutex_init(&mMutex, nullptr);
}
inline Mutex::Mutex(__attribute__((unused)) const char* name) {
- pthread_mutex_init(&mMutex, NULL);
+ pthread_mutex_init(&mMutex, nullptr);
}
inline Mutex::Mutex(int type, __attribute__((unused)) const char* name) {
if (type == SHARED) {
@@ -173,7 +173,7 @@
pthread_mutex_init(&mMutex, &attr);
pthread_mutexattr_destroy(&attr);
} else {
- pthread_mutex_init(&mMutex, NULL);
+ pthread_mutex_init(&mMutex, nullptr);
}
}
inline Mutex::~Mutex() {
diff --git a/libutils/include/utils/Printer.h b/libutils/include/utils/Printer.h
index a6f6928..7465927 100644
--- a/libutils/include/utils/Printer.h
+++ b/libutils/include/utils/Printer.h
@@ -45,7 +45,7 @@
// (Note that the default ALOG behavior is to ignore blank lines)
LogPrinter(const char* logtag,
android_LogPriority priority = ANDROID_LOG_DEBUG,
- const char* prefix = 0,
+ const char* prefix = nullptr,
bool ignoreBlankLines = false);
// Print the specified line to logcat. No \n at the end is necessary.
@@ -66,7 +66,7 @@
// Create a printer using the specified file descriptor.
// - Each line will be prefixed with 'indent' number of blank spaces.
// - In addition, each line will be prefixed with the 'prefix' string.
- FdPrinter(int fd, unsigned int indent = 0, const char* prefix = 0);
+ FdPrinter(int fd, unsigned int indent = 0, const char* prefix = nullptr);
// Print the specified line to the file descriptor. \n is appended automatically.
virtual void printLine(const char* string);
@@ -90,7 +90,7 @@
// Create a printer using the specified String8 as the target.
// - In addition, each line will be prefixed with the 'prefix' string.
// - target's memory lifetime must be a superset of this String8Printer.
- String8Printer(String8* target, const char* prefix = 0);
+ String8Printer(String8* target, const char* prefix = nullptr);
// Append the specified line to the String8. \n is appended automatically.
virtual void printLine(const char* string);
diff --git a/libutils/include/utils/ProcessCallStack.h b/libutils/include/utils/ProcessCallStack.h
index b5f2edc..7e06086 100644
--- a/libutils/include/utils/ProcessCallStack.h
+++ b/libutils/include/utils/ProcessCallStack.h
@@ -43,13 +43,13 @@
// Print all stack traces to the log using the supplied logtag.
void log(const char* logtag, android_LogPriority priority = ANDROID_LOG_DEBUG,
- const char* prefix = 0) const;
+ const char* prefix = nullptr) const;
// Dump all stack traces to the specified file descriptor.
- void dump(int fd, int indent = 0, const char* prefix = 0) const;
+ void dump(int fd, int indent = 0, const char* prefix = nullptr) const;
// Return a string (possibly very long) containing all the stack traces.
- String8 toString(const char* prefix = 0) const;
+ String8 toString(const char* prefix = nullptr) const;
// Dump a serialized representation of all the stack traces to the specified printer.
void print(Printer& printer) const;
diff --git a/libutils/include/utils/RWLock.h b/libutils/include/utils/RWLock.h
index 7d43e69..64e370e 100644
--- a/libutils/include/utils/RWLock.h
+++ b/libutils/include/utils/RWLock.h
@@ -48,7 +48,7 @@
RWLock();
explicit RWLock(const char* name);
- explicit RWLock(int type, const char* name = NULL);
+ explicit RWLock(int type, const char* name = nullptr);
~RWLock();
status_t readLock();
@@ -82,10 +82,10 @@
};
inline RWLock::RWLock() {
- pthread_rwlock_init(&mRWLock, NULL);
+ pthread_rwlock_init(&mRWLock, nullptr);
}
inline RWLock::RWLock(__attribute__((unused)) const char* name) {
- pthread_rwlock_init(&mRWLock, NULL);
+ pthread_rwlock_init(&mRWLock, nullptr);
}
inline RWLock::RWLock(int type, __attribute__((unused)) const char* name) {
if (type == SHARED) {
@@ -95,7 +95,7 @@
pthread_rwlock_init(&mRWLock, &attr);
pthread_rwlockattr_destroy(&attr);
} else {
- pthread_rwlock_init(&mRWLock, NULL);
+ pthread_rwlock_init(&mRWLock, nullptr);
}
}
inline RWLock::~RWLock() {
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index e817ee4..1780cf2 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -354,7 +354,7 @@
public:
typedef typename RefBase::weakref_type weakref_type;
- inline wp() : m_ptr(0) { }
+ inline wp() : m_ptr(nullptr) { }
wp(T* other); // NOLINT(implicit)
wp(const wp<T>& other);
@@ -505,7 +505,7 @@
wp<T>& wp<T>::operator = (T* other)
{
weakref_type* newRefs =
- other ? other->createWeak(this) : 0;
+ other ? other->createWeak(this) : nullptr;
if (m_ptr) m_refs->decWeak(this);
m_ptr = other;
m_refs = newRefs;
@@ -528,7 +528,7 @@
wp<T>& wp<T>::operator = (const sp<T>& other)
{
weakref_type* newRefs =
- other != NULL ? other->createWeak(this) : 0;
+ other != nullptr ? other->createWeak(this) : nullptr;
T* otherPtr(other.m_ptr);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
@@ -563,7 +563,7 @@
wp<T>& wp<T>::operator = (const sp<U>& other)
{
weakref_type* newRefs =
- other != NULL ? other->createWeak(this) : 0;
+ other != nullptr ? other->createWeak(this) : 0;
U* otherPtr(other.m_ptr);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
diff --git a/libutils/include/utils/Singleton.h b/libutils/include/utils/Singleton.h
index 2dd5a47..44d8ad7 100644
--- a/libutils/include/utils/Singleton.h
+++ b/libutils/include/utils/Singleton.h
@@ -51,7 +51,7 @@
static TYPE& getInstance() {
Mutex::Autolock _l(sLock);
TYPE* instance = sInstance;
- if (instance == 0) {
+ if (instance == nullptr) {
instance = new TYPE();
sInstance = instance;
}
@@ -60,7 +60,7 @@
static bool hasInstance() {
Mutex::Autolock _l(sLock);
- return sInstance != 0;
+ return sInstance != nullptr;
}
protected:
@@ -90,7 +90,7 @@
#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \
template<> ::android::Mutex \
(::android::Singleton< TYPE >::sLock)(::android::Mutex::PRIVATE); \
- template<> TYPE* ::android::Singleton< TYPE >::sInstance(0); /* NOLINT */ \
+ template<> TYPE* ::android::Singleton< TYPE >::sInstance(nullptr); /* NOLINT */ \
template class ::android::Singleton< TYPE >;
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 94ac32f..c8f584e 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -187,7 +187,7 @@
* "/tmp" --> "tmp" (remain = "")
* "bar.c" --> "bar.c" (remain = "")
*/
- String8 walkPath(String8* outRemains = NULL) const;
+ String8 walkPath(String8* outRemains = nullptr) const;
/*
* Return the filename extension. This is the last '.' and any number
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 9cd278f1..360fce5 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -52,7 +52,7 @@
template<typename T>
class sp {
public:
- inline sp() : m_ptr(0) { }
+ inline sp() : m_ptr(nullptr) { }
sp(T* other); // NOLINT(implicit)
sp(const sp<T>& other);
@@ -230,7 +230,7 @@
void sp<T>::clear() {
if (m_ptr) {
m_ptr->decStrong(this);
- m_ptr = 0;
+ m_ptr = nullptr;
}
}
diff --git a/libutils/include/utils/VectorImpl.h b/libutils/include/utils/VectorImpl.h
index 55d5d98..41b9f33 100644
--- a/libutils/include/utils/VectorImpl.h
+++ b/libutils/include/utils/VectorImpl.h
@@ -157,7 +157,7 @@
virtual int do_compare(const void* lhs, const void* rhs) const = 0;
private:
- ssize_t _indexOrderOf(const void* item, size_t* order = 0) const;
+ ssize_t _indexOrderOf(const void* item, size_t* order = nullptr) const;
// these are made private, because they can't be used on a SortedVector
// (they don't have an implementation either)
diff --git a/libutils/misc.cpp b/libutils/misc.cpp
index f074341..f77e189 100644
--- a/libutils/misc.cpp
+++ b/libutils/misc.cpp
@@ -41,13 +41,13 @@
#if !defined(_WIN32)
static pthread_mutex_t gSyspropMutex = PTHREAD_MUTEX_INITIALIZER;
-static Vector<sysprop_change_callback_info>* gSyspropList = NULL;
+static Vector<sysprop_change_callback_info>* gSyspropList = nullptr;
#endif
#if !defined(_WIN32)
void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
pthread_mutex_lock(&gSyspropMutex);
- if (gSyspropList == NULL) {
+ if (gSyspropList == nullptr) {
gSyspropList = new Vector<sysprop_change_callback_info>();
}
sysprop_change_callback_info info;
@@ -103,7 +103,7 @@
#if !defined(_WIN32)
pthread_mutex_lock(&gSyspropMutex);
Vector<sysprop_change_callback_info> listeners;
- if (gSyspropList != NULL) {
+ if (gSyspropList != nullptr) {
listeners = *gSyspropList;
}
pthread_mutex_unlock(&gSyspropMutex);
diff --git a/libutils/tests/Looper_test.cpp b/libutils/tests/Looper_test.cpp
index 8ebcfaf..2282ced 100644
--- a/libutils/tests/Looper_test.cpp
+++ b/libutils/tests/Looper_test.cpp
@@ -339,7 +339,7 @@
Pipe pipe;
pipe.writeSignal();
- mLooper->addFd(pipe.receiveFd, expectedIdent, Looper::EVENT_INPUT, NULL, expectedData);
+ mLooper->addFd(pipe.receiveFd, expectedIdent, Looper::EVENT_INPUT, nullptr, expectedData);
StopWatch stopWatch("pollOnce");
int fd;
@@ -364,7 +364,7 @@
TEST_F(LooperTest, AddFd_WhenCallbackAdded_ReturnsOne) {
Pipe pipe;
- int result = mLooper->addFd(pipe.receiveFd, 0, Looper::EVENT_INPUT, NULL, NULL);
+ int result = mLooper->addFd(pipe.receiveFd, 0, Looper::EVENT_INPUT, nullptr, nullptr);
EXPECT_EQ(1, result)
<< "addFd should return 1 because FD was added";
@@ -372,7 +372,7 @@
TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) {
Pipe pipe;
- int result = mLooper->addFd(pipe.receiveFd, -1, Looper::EVENT_INPUT, NULL, NULL);
+ int result = mLooper->addFd(pipe.receiveFd, -1, Looper::EVENT_INPUT, nullptr, nullptr);
EXPECT_EQ(-1, result)
<< "addFd should return -1 because arguments were invalid";
@@ -381,7 +381,7 @@
TEST_F(LooperTest, AddFd_WhenNoCallbackAndAllowNonCallbacksIsFalse_ReturnsError) {
Pipe pipe;
sp<Looper> looper = new Looper(false /*allowNonCallbacks*/);
- int result = looper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
+ int result = looper->addFd(pipe.receiveFd, 0, 0, nullptr, nullptr);
EXPECT_EQ(-1, result)
<< "addFd should return -1 because arguments were invalid";
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index 4e885bb..c4d917b 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -110,7 +110,7 @@
class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
public:
- EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
+ EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(nullptr) { }
~EntryRemovedCallback() {}
void operator()(SimpleKey& k, StringValue& v) {
callbackCount += 1;
@@ -153,7 +153,7 @@
TEST_F(LruCacheTest, Empty) {
LruCache<SimpleKey, StringValue> cache(100);
- EXPECT_EQ(NULL, cache.get(0));
+ EXPECT_EQ(nullptr, cache.get(0));
EXPECT_EQ(0u, cache.size());
}
@@ -175,7 +175,7 @@
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
- EXPECT_EQ(NULL, cache.get(1));
+ EXPECT_EQ(nullptr, cache.get(1));
EXPECT_STREQ("two", cache.get(2));
EXPECT_STREQ("three", cache.get(3));
EXPECT_EQ(2u, cache.size());
@@ -188,7 +188,7 @@
cache.put(2, "two");
cache.put(3, "three");
cache.removeOldest();
- EXPECT_EQ(NULL, cache.get(1));
+ EXPECT_EQ(nullptr, cache.get(1));
EXPECT_STREQ("two", cache.get(2));
EXPECT_STREQ("three", cache.get(3));
EXPECT_EQ(2u, cache.size());
@@ -203,7 +203,7 @@
EXPECT_STREQ("one", cache.get(1));
cache.removeOldest();
EXPECT_STREQ("one", cache.get(1));
- EXPECT_EQ(NULL, cache.get(2));
+ EXPECT_EQ(nullptr, cache.get(2));
EXPECT_STREQ("three", cache.get(3));
EXPECT_EQ(2u, cache.size());
}
@@ -230,7 +230,7 @@
int index = random() % kNumKeys;
uint32_t key = hash_int(index);
const char *val = cache.get(key);
- if (val != NULL) {
+ if (val != nullptr) {
EXPECT_EQ(strings[index], val);
hitCount++;
} else {
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index e074a92..5336c40 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -98,7 +98,7 @@
// Checks that the size calculation (not the capacity calculation) doesn't
// overflow : the size here will be (1 + SIZE_MAX).
- EXPECT_DEATH(vector.insertArrayAt(NULL, 0, SIZE_MAX), "new_size overflow");
+ EXPECT_DEATH(vector.insertArrayAt(nullptr, 0, SIZE_MAX), "new_size overflow");
}
TEST_F(VectorTest, _grow_OverflowCapacityDoubling) {
@@ -106,14 +106,14 @@
// This should fail because the calculated capacity will overflow even though
// the size of the vector doesn't.
- EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX - 1)), "new_capacity overflow");
+ EXPECT_DEATH(vector.insertArrayAt(nullptr, 0, (SIZE_MAX - 1)), "new_capacity overflow");
}
TEST_F(VectorTest, _grow_OverflowBufferAlloc) {
Vector<int> vector;
// This should fail because the capacity * sizeof(int) overflows, even
// though the capacity itself doesn't.
- EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX / 2)), "new_alloc_size overflow");
+ EXPECT_DEATH(vector.insertArrayAt(nullptr, 0, (SIZE_MAX / 2)), "new_alloc_size overflow");
}
TEST_F(VectorTest, editArray_Shared) {
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 5e5e7af..9536fc7 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -33,6 +33,10 @@
#include <memory>
#include <vector>
+#if defined(__BIONIC__)
+#include <android/fdsan.h>
+#endif
+
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h> // TEMP_FAILURE_RETRY may or may not be in unistd
@@ -165,6 +169,44 @@
return 0;
}
+ZipArchive::ZipArchive(const int fd, bool assume_ownership)
+ : mapped_zip(fd),
+ close_file(assume_ownership),
+ directory_offset(0),
+ central_directory(),
+ directory_map(new android::FileMap()),
+ num_entries(0),
+ hash_table_size(0),
+ hash_table(nullptr) {
+#if defined(__BIONIC__)
+ if (assume_ownership) {
+ android_fdsan_exchange_owner_tag(fd, 0, reinterpret_cast<uint64_t>(this));
+ }
+#endif
+}
+
+ZipArchive::ZipArchive(void* address, size_t length)
+ : mapped_zip(address, length),
+ close_file(false),
+ directory_offset(0),
+ central_directory(),
+ directory_map(new android::FileMap()),
+ num_entries(0),
+ hash_table_size(0),
+ hash_table(nullptr) {}
+
+ZipArchive::~ZipArchive() {
+ if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
+#if defined(__BIONIC__)
+ android_fdsan_close_with_tag(mapped_zip.GetFileDescriptor(), reinterpret_cast<uint64_t>(this));
+#else
+ close(mapped_zip.GetFileDescriptor());
+#endif
+ }
+
+ free(hash_table);
+}
+
static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
off64_t file_length, off64_t read_amount, uint8_t* scan_buffer) {
const off64_t search_start = file_length - read_amount;
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 18e0229..0a73300 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -156,33 +156,9 @@
uint32_t hash_table_size;
ZipString* hash_table;
- ZipArchive(const int fd, bool assume_ownership)
- : mapped_zip(fd),
- close_file(assume_ownership),
- directory_offset(0),
- central_directory(),
- directory_map(new android::FileMap()),
- num_entries(0),
- hash_table_size(0),
- hash_table(nullptr) {}
-
- ZipArchive(void* address, size_t length)
- : mapped_zip(address, length),
- close_file(false),
- directory_offset(0),
- central_directory(),
- directory_map(new android::FileMap()),
- num_entries(0),
- hash_table_size(0),
- hash_table(nullptr) {}
-
- ~ZipArchive() {
- if (close_file && mapped_zip.GetFileDescriptor() >= 0) {
- close(mapped_zip.GetFileDescriptor());
- }
-
- free(hash_table);
- }
+ ZipArchive(const int fd, bool assume_ownership);
+ ZipArchive(void* address, size_t length);
+ ~ZipArchive();
bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
size_t cd_size);
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 1cfef34..c2487d6 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -332,7 +332,7 @@
data->fd = -1;
return -1;
}
- ALOG_ASSERT((size_t)size < buf_size - 1, data->filename " too large");
+ ALOG_ASSERT((size_t)size < buf_size - 1, "%s too large", data->filename);
buf[size] = 0;
return 0;
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 750761f..da8d2d4 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -113,6 +113,9 @@
# graphics timestamp
# 60100 - 60199 reserved for surfaceflinger
+# audio
+# 61000 - 61199 reserved for audioserver
+
# 0 for screen off, 1 for screen on, 2 for key-guard done
70000 screen_toggled (screen_state|1|5)
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 06c0ab5..7a843d8 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -288,9 +288,9 @@
uid = AID_ROOT;
}
- const char* name = NULL;
- const char* format = NULL;
- const char* id = NULL;
+ const char* name = nullptr;
+ const char* format = nullptr;
+ const char* id = nullptr;
for (int i = 1; i < argc; ++i) {
static const char _name[] = "name=";
if (!strncmp(argv[i], _name, strlen(_name))) {
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
old mode 100755
new mode 100644
index 70ecbe0..658e079
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -36,7 +36,7 @@
// reference counts are used to ensure that individual
// LogTimeEntry lifetime is managed when not protected.
void FlushCommand::runSocketCommand(SocketClient* client) {
- LogTimeEntry* entry = NULL;
+ LogTimeEntry* entry = nullptr;
LastLogTimes& times = mReader.logbuf().mTimes;
LogTimeEntry::wrlock();
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
old mode 100755
new mode 100644
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
old mode 100755
new mode 100644
index 27cd9a8..4ea7877
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -171,13 +171,13 @@
}
int LogAudit::logPrint(const char* fmt, ...) {
- if (fmt == NULL) {
+ if (fmt == nullptr) {
return -EINVAL;
}
va_list args;
- char* str = NULL;
+ char* str = nullptr;
va_start(args, fmt);
int rc = vasprintf(&str, fmt, args);
va_end(args);
@@ -228,7 +228,7 @@
static char* last_str;
static bool last_info;
- if (last_str != NULL) {
+ if (last_str != nullptr) {
static const char avc[] = "): avc: ";
char* avcl = strstr(last_str, avc);
bool skip = false;
@@ -265,10 +265,10 @@
writev(fdDmesg, iov, arraysize(iov));
free(last_str);
- last_str = NULL;
+ last_str = nullptr;
}
}
- if (last_str == NULL) {
+ if (last_str == nullptr) {
count = 0;
last_str = strdup(str);
last_info = info;
@@ -357,7 +357,7 @@
static const char comm_str[] = " comm=\"";
const char* comm = strstr(str, comm_str);
const char* estr = str + strlen(str);
- const char* commfree = NULL;
+ const char* commfree = nullptr;
if (comm) {
estr = comm;
comm += sizeof(comm_str) - 1;
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index f20ac45..2d627b9 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -91,7 +91,7 @@
// caller must own and free character string
char* android::tidToName(pid_t tid) {
- char* retval = NULL;
+ char* retval = nullptr;
char buffer[256];
snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
int fd = open(buffer, O_RDONLY);
@@ -114,7 +114,7 @@
char* name = android::pidToName(tid);
if (!retval) {
retval = name;
- name = NULL;
+ name = nullptr;
}
// check if comm is truncated, see if cmdline has full representation
@@ -162,15 +162,15 @@
if (!strncmp(name + 1, commName + 1, len)) {
if (commName[len + 1] == '\0') {
free(const_cast<char*>(commName));
- commName = NULL;
+ commName = nullptr;
} else {
free(const_cast<char*>(name));
- name = NULL;
+ name = nullptr;
}
}
}
if (name) {
- char* buf = NULL;
+ char* buf = nullptr;
asprintf(&buf, "(%s)", name);
if (buf) {
free(const_cast<char*>(name));
@@ -178,7 +178,7 @@
}
}
if (commName) {
- char* buf = NULL;
+ char* buf = nullptr;
asprintf(&buf, " %s", commName);
if (buf) {
free(const_cast<char*>(commName));
@@ -187,7 +187,7 @@
}
// identical to below to calculate the buffer size required
const char* type = lastSame ? "identical" : "expire";
- size_t len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
+ size_t len = snprintf(nullptr, 0, format_uid, mUid, name ? name : "",
commName ? commName : "", type, getDropped(),
(getDropped() > 1) ? "s" : "");
@@ -247,7 +247,7 @@
iovec[0].iov_base = &entry;
iovec[0].iov_len = entry.hdr_size;
- char* buffer = NULL;
+ char* buffer = nullptr;
if (mDropped) {
entry.len = populateDroppedMessage(buffer, parent, lastSame);
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index 6d7c0a5..8bff9da 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -44,9 +44,9 @@
char* ptr;
static const char ws[] = " \n";
- for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(NULL, ws, &ptr)) {
+ for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(nullptr, ws, &ptr)) {
errno = 0;
- gid_t Gid = strtol(buf, NULL, 10);
+ gid_t Gid = strtol(buf, nullptr, 10);
if (errno != 0) {
return false;
}
@@ -98,7 +98,7 @@
continue;
}
- char* line = NULL;
+ char* line = nullptr;
size_t len = 0;
while (getline(&line, &len, file) > 0) {
static const char groups_string[] = "Groups:\t";
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
old mode 100755
new mode 100644
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
old mode 100755
new mode 100644
index fc51dcf..e568ddc
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -50,7 +50,7 @@
alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
struct msghdr hdr = {
- NULL, 0, &iov, 1, control, sizeof(control), 0,
+ nullptr, 0, &iov, 1, control, sizeof(control), 0,
};
int socket = cli->getSocket();
@@ -66,10 +66,10 @@
buffer[n] = 0;
- struct ucred* cred = NULL;
+ struct ucred* cred = nullptr;
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
- while (cmsg != NULL) {
+ while (cmsg != nullptr) {
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS) {
cred = (struct ucred*)CMSG_DATA(cmsg);
@@ -79,7 +79,7 @@
}
struct ucred fake_cred;
- if (cred == NULL) {
+ if (cred == nullptr) {
cred = &fake_cred;
cred->pid = 0;
cred->uid = DEFAULT_OVERFLOWUID;
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
old mode 100755
new mode 100644
diff --git a/logd/LogReader.h b/logd/LogReader.h
old mode 100755
new mode 100644
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index af59ddc..cefacf7 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -56,7 +56,7 @@
// caller must own and free character string
char* pidToName(pid_t pid) {
- char* retval = NULL;
+ char* retval = nullptr;
if (pid == 0) { // special case from auditd/klogd for kernel
retval = strdup("logd");
} else {
@@ -286,7 +286,7 @@
name = strdup(nameTmp);
} else if (fastcmp<strcmp>(name, nameTmp)) {
free(const_cast<char*>(name));
- name = NULL;
+ name = nullptr;
break;
}
}
@@ -872,7 +872,7 @@
pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
const char* name = writablePidTable.add(pid)->second.getName();
if (!name) {
- return NULL;
+ return nullptr;
}
return strdup(name);
}
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index ff7e762..1ab9dd1 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -91,7 +91,7 @@
fd = TEMP_FAILURE_RETRY(open(
filename, O_WRONLY | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
if (fd >= 0) {
- time_t now = time(NULL);
+ time_t now = time(nullptr);
struct tm tm;
localtime_r(&now, &tm);
char timebuf[20];
@@ -208,7 +208,7 @@
} else if (lineStart) {
if (*cp == '#') {
/* comment; just scan to end */
- lineStart = NULL;
+ lineStart = nullptr;
} else if (isdigit(*cp)) {
unsigned long Tag = strtoul(cp, &cp, 10);
if (warn && (Tag > emptyTag)) {
@@ -235,7 +235,7 @@
if (hasAlpha &&
((cp >= endp) || (*cp == '#') || isspace(*cp))) {
if (Tag > emptyTag) {
- if (*cp != '\n') lineStart = NULL;
+ if (*cp != '\n') lineStart = nullptr;
continue;
}
while ((cp < endp) && (*cp != '\n') && isspace(*cp))
@@ -245,14 +245,14 @@
while ((cp < endp) && (*cp != '\n')) {
if (*cp == '#') {
uid = sniffUid(cp, endp);
- lineStart = NULL;
+ lineStart = nullptr;
break;
}
++cp;
}
while ((cp > format) && isspace(cp[-1])) {
--cp;
- lineStart = NULL;
+ lineStart = nullptr;
}
std::string Format(format, cp - format);
@@ -263,7 +263,7 @@
android::prdebug("tag name invalid %.*s",
(int)(cp - name + 1), name);
}
- lineStart = NULL;
+ lineStart = nullptr;
}
} else if (!isspace(*cp)) {
break;
@@ -364,7 +364,7 @@
android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
it = tag2name.find(tag);
- if ((it == tag2name.end()) || (it->second.length() == 0)) return NULL;
+ if ((it == tag2name.end()) || (it->second.length() == 0)) return nullptr;
return it->second.c_str();
}
@@ -383,7 +383,7 @@
const char* android::tagToName(uint32_t tag) {
LogTags* me = logtags;
- if (!me) return NULL;
+ if (!me) return nullptr;
me->WritePmsgEventLogTags(tag);
return me->tagToName(tag);
}
@@ -412,7 +412,7 @@
android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
iform = tag2format.find(tag);
- if (iform == tag2format.end()) return NULL;
+ if (iform == tag2format.end()) return nullptr;
return iform->second.c_str();
}
@@ -441,7 +441,7 @@
bool& unique) {
key2tag_const_iterator ik;
- bool write = format != NULL;
+ bool write = format != nullptr;
unique = write;
if (!write) {
@@ -679,7 +679,7 @@
// are in readonly mode.
uint32_t LogTags::nameToTag(uid_t uid, const char* name, const char* format) {
std::string Name = std::string(name);
- bool write = format != NULL;
+ bool write = format != nullptr;
bool updateUid = uid != AID_ROOT;
bool updateFormat = format && *format;
bool unique;
@@ -848,7 +848,7 @@
if (!list) {
// switch to read entry only if format == "*"
- if (format && (format[0] == '*') && !format[1]) format = NULL;
+ if (format && (format[0] == '*') && !format[1]) format = nullptr;
// WAI: for null format, only works for a single entry, we can have
// multiple entries, one for each format, so we find first entry
diff --git a/logd/LogTags.h b/logd/LogTags.h
index 203318d..e4d165a 100644
--- a/logd/LogTags.h
+++ b/logd/LogTags.h
@@ -87,14 +87,14 @@
bool RebuildFileEventLogTags(const char* filename, bool warn = true);
void AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
- const std::string& Format, const char* source = NULL,
+ const std::string& Format, const char* source = nullptr,
bool warn = false);
void WriteDynamicEventLogTags(uint32_t tag, uid_t uid);
void WriteDebugEventLogTags(uint32_t tag, uid_t uid);
// push tag details to persistent storage
void WritePersistEventLogTags(uint32_t tag, uid_t uid = AID_ROOT,
- const char* source = NULL);
+ const char* source = nullptr);
static const uint32_t emptyTag = uint32_t(-1);
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
old mode 100755
new mode 100644
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
old mode 100755
new mode 100644
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 4b8b080..9d762dc 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -51,7 +51,7 @@
}
PruneList::PruneList() {
- init(NULL);
+ init(nullptr);
}
PruneList::~PruneList() {
@@ -79,7 +79,7 @@
// default here means take ro.logd.filter, persist.logd.filter then
// internal default in that order.
if (str && !strcmp(str, _default)) {
- str = NULL;
+ str = nullptr;
}
static const char _disable[] = "disable";
if (str && !strcmp(str, _disable)) {
diff --git a/mkbootimg/Android.bp b/mkbootimg/Android.bp
index b494346..576a677 100644
--- a/mkbootimg/Android.bp
+++ b/mkbootimg/Android.bp
@@ -9,6 +9,7 @@
cc_library_headers {
name: "bootimg_headers",
vendor_available: true,
+ recovery_available: true,
export_include_dirs: ["include/bootimg"],
host_supported: true,
target: {
diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp
index 3c4bdc3..51c1226 100644
--- a/property_service/libpropertyinfoserializer/Android.bp
+++ b/property_service/libpropertyinfoserializer/Android.bp
@@ -17,6 +17,7 @@
cc_library_static {
name: "libpropertyinfoserializer",
defaults: ["propertyinfoserializer_defaults"],
+ recovery_available: true,
srcs: [
"property_info_file.cpp",
"property_info_serializer.cpp",
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 197047d..d3f038e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -227,6 +227,8 @@
# pstore/ramoops previous console log
mount pstore pstore /sys/fs/pstore nodev noexec nosuid
+ chown system log /sys/fs/pstore
+ chmod 0550 /sys/fs/pstore
chown system log /sys/fs/pstore/console-ramoops
chmod 0440 /sys/fs/pstore/console-ramoops
chown system log /sys/fs/pstore/console-ramoops-0
@@ -316,8 +318,8 @@
start vndservicemanager
# Once everything is setup, no need to modify /.
- # The bind+ro combination avoids modifying any other mount flags.
- mount rootfs rootfs / remount bind ro
+ # The bind+remount combination allows this to work in containers.
+ mount rootfs rootfs / remount bind ro nodev
# Mount shared so changes propagate into child namespaces
mount rootfs rootfs / shared rec
# Mount default storage into root namespace
@@ -716,6 +718,9 @@
on property:security.perf_harden=0
write /proc/sys/kernel/perf_event_paranoid 1
+ write /proc/sys/kernel/perf_event_max_sample_rate ${debug.perf_event_max_sample_rate:-100000}
+ write /proc/sys/kernel/perf_cpu_time_max_percent ${debug.perf_cpu_time_max_percent:-25}
+ write /proc/sys/kernel/perf_event_mlock_kb ${debug.perf_event_mlock_kb:-516}
on property:security.perf_harden=1
write /proc/sys/kernel/perf_event_paranoid 3
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index b03d83b..2f85dec 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -1,3 +1,5 @@
+firmware_directories /etc/firmware/ /odm/firmware/ /vendor/firmware/ /firmware/image/
+
subsystem adf
devname uevent_devname
diff --git a/run-as/Android.bp b/run-as/Android.bp
new file mode 100644
index 0000000..840a43c
--- /dev/null
+++ b/run-as/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "run-as",
+ srcs: [
+ "run-as.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libselinux",
+ "libpackagelistparser",
+ "libminijail",
+ ],
+}
diff --git a/run-as/Android.mk b/run-as/Android.mk
deleted file mode 100644
index 7111fbe..0000000
--- a/run-as/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_MODULE := run-as
-LOCAL_SHARED_LIBRARIES := libselinux libpackagelistparser libminijail
-LOCAL_SRC_FILES := run-as.cpp
-include $(BUILD_EXECUTABLE)
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
index b27cfad..d005ecf 100644
--- a/run-as/run-as.cpp
+++ b/run-as/run-as.cpp
@@ -28,6 +28,7 @@
#include <libminijail.h>
#include <scoped_minijail.h>
+#include <android-base/properties.h>
#include <packagelistparser/packagelistparser.h>
#include <private/android_filesystem_config.h>
#include <selinux/android.h>
@@ -40,6 +41,7 @@
// The 'run-as' binary is installed with CAP_SETUID and CAP_SETGID file
// capabilities, but will check the following:
//
+// - that the ro.boot.disable_runas property is not set
// - that it is invoked from the 'shell' or 'root' user (abort otherwise)
// - that '<package-name>' is the name of an installed and debuggable package
// - that the package's data directory is well-formed
@@ -139,6 +141,12 @@
error(1, 0, "only 'shell' or 'root' users can run this program");
}
+ // Some devices can disable running run-as, such as Chrome OS when running in
+ // non-developer mode.
+ if (android::base::GetBoolProperty("ro.boot.disable_runas", false)) {
+ error(1, 0, "run-as is disabled from the kernel commandline");
+ }
+
char* pkgname = argv[1];
int cmd_argv_offset = 2;
diff --git a/trusty/OWNERS b/trusty/OWNERS
index 357b4f4..e807d71 100644
--- a/trusty/OWNERS
+++ b/trusty/OWNERS
@@ -1,3 +1,7 @@
-bohr@google.com
-swillden@google.com
+arve@google.com
dkrahn@google.com
+drewry@google.com
+gmar@google.com
+ncbray@google.com
+rpere@google.com
+swillden@google.com