fs_mgr_avb: allow top-level vbmeta struct to be in 'boot' partition
am: 1aa6eaf821
Change-Id: Icc0435ac3b026cc2f302ee61ff15a27e2c08feba
diff --git a/.clang-format-2 b/.clang-format-2
index aab4665..41591ce 100644
--- a/.clang-format-2
+++ b/.clang-format-2
@@ -1,4 +1,5 @@
BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
diff --git a/.clang-format-4 b/.clang-format-4
index 1497447..ae4a451 100644
--- a/.clang-format-4
+++ b/.clang-format-4
@@ -1,5 +1,6 @@
BasedOnStyle: Google
AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index f195b4e..f95a855 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -268,10 +268,6 @@
#undef accept
#define accept ___xxx_accept
-int adb_getsockname(int fd, struct sockaddr* sockaddr, socklen_t* optlen);
-#undef getsockname
-#define getsockname(...) ___xxx_getsockname(__VA__ARGS__)
-
// Returns the local port number of a bound socket, or -1 on failure.
int adb_socket_get_local_port(int fd);
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index f997e6b..5873b2b 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -984,7 +984,7 @@
return -1;
}
- int result = (getsockname)(fh->fh_socket, sockaddr, optlen);
+ int result = getsockname(fh->fh_socket, sockaddr, optlen);
if (result == SOCKET_ERROR) {
const DWORD err = WSAGetLastError();
D("adb_getsockname: setsockopt on fd %d failed: %s\n", fd,
@@ -1042,11 +1042,6 @@
int local_port = -1;
std::string error;
- struct sockaddr_storage peer_addr = {};
- struct sockaddr_storage client_addr = {};
- socklen_t peer_socklen = sizeof(peer_addr);
- socklen_t client_socklen = sizeof(client_addr);
-
server = network_loopback_server(0, SOCK_STREAM, &error);
if (server < 0) {
D("adb_socketpair: failed to create server: %s", error.c_str());
@@ -1066,32 +1061,12 @@
goto fail;
}
- // Make sure that the peer that connected to us and the client are the same.
- accepted = adb_socket_accept(server, reinterpret_cast<sockaddr*>(&peer_addr), &peer_socklen);
+ accepted = adb_socket_accept(server, nullptr, nullptr);
if (accepted < 0) {
D("adb_socketpair: failed to accept: %s", strerror(errno));
goto fail;
}
-
- if (adb_getsockname(client, reinterpret_cast<sockaddr*>(&client_addr), &client_socklen) != 0) {
- D("adb_socketpair: failed to getpeername: %s", strerror(errno));
- goto fail;
- }
-
- if (peer_socklen != client_socklen) {
- D("adb_socketpair: client and peer sockaddrs have different lengths");
- errno = EIO;
- goto fail;
- }
-
- if (memcmp(&peer_addr, &client_addr, peer_socklen) != 0) {
- D("adb_socketpair: client and peer sockaddrs don't match");
- errno = EIO;
- goto fail;
- }
-
adb_close(server);
-
sv[0] = client;
sv[1] = accepted;
return 0;
diff --git a/base/Android.bp b/base/Android.bp
index 7b1dc8e..121da42 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -42,24 +42,36 @@
srcs: [
"errors_unix.cpp",
"properties.cpp",
+ "chrono_utils.cpp",
],
cppflags: ["-Wexit-time-destructors"],
sanitize: {
misc_undefined: ["integer"],
},
+
},
darwin: {
- srcs: ["errors_unix.cpp"],
+ srcs: [
+ "chrono_utils.cpp",
+ "errors_unix.cpp",
+ ],
cppflags: ["-Wexit-time-destructors"],
},
linux_bionic: {
- srcs: ["errors_unix.cpp"],
+ srcs: [
+ "chrono_utils.cpp",
+ "errors_unix.cpp",
+ ],
cppflags: ["-Wexit-time-destructors"],
enabled: true,
},
linux: {
- srcs: ["errors_unix.cpp"],
+ srcs: [
+ "chrono_utils.cpp",
+ "errors_unix.cpp",
+ ],
cppflags: ["-Wexit-time-destructors"],
+ host_ldlibs: ["-lrt"],
},
windows: {
srcs: [
@@ -92,11 +104,18 @@
],
target: {
android: {
- srcs: ["properties_test.cpp"],
+ srcs: [
+ "chrono_utils_test.cpp",
+ "properties_test.cpp"
+ ],
sanitize: {
misc_undefined: ["integer"],
},
},
+ linux: {
+ srcs: ["chrono_utils_test.cpp"],
+ host_ldlibs: ["-lrt"],
+ },
windows: {
srcs: ["utf8_test.cpp"],
enabled: true,
diff --git a/base/chrono_utils.cpp b/base/chrono_utils.cpp
new file mode 100644
index 0000000..5eedf3b
--- /dev/null
+++ b/base/chrono_utils.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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/chrono_utils.h"
+
+#include <time.h>
+
+namespace android {
+namespace base {
+
+boot_clock::time_point boot_clock::now() {
+#ifdef __ANDROID__
+ timespec ts;
+ clock_gettime(CLOCK_BOOTTIME, &ts);
+ return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
+ std::chrono::nanoseconds(ts.tv_nsec));
+#else
+ // Darwin does not support clock_gettime.
+ return boot_clock::time_point();
+#endif // __ANDROID__
+}
+
+} // namespace base
+} // namespace android
diff --git a/base/chrono_utils_test.cpp b/base/chrono_utils_test.cpp
new file mode 100644
index 0000000..057132d
--- /dev/null
+++ b/base/chrono_utils_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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/chrono_utils.h"
+
+#include <time.h>
+
+#include <chrono>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace base {
+
+std::chrono::seconds GetBootTimeSeconds() {
+ struct timespec now;
+ clock_gettime(CLOCK_BOOTTIME, &now);
+
+ auto now_tp = boot_clock::time_point(std::chrono::seconds(now.tv_sec) +
+ std::chrono::nanoseconds(now.tv_nsec));
+ return std::chrono::duration_cast<std::chrono::seconds>(now_tp.time_since_epoch());
+}
+
+// Tests (at least) the seconds accuracy of the boot_clock::now() method.
+TEST(ChronoUtilsTest, BootClockNowSeconds) {
+ auto now = GetBootTimeSeconds();
+ auto boot_seconds =
+ std::chrono::duration_cast<std::chrono::seconds>(boot_clock::now().time_since_epoch());
+ EXPECT_EQ(now, boot_seconds);
+}
+
+} // namespace base
+} // namespace android
\ No newline at end of file
diff --git a/base/include/android-base/chrono_utils.h b/base/include/android-base/chrono_utils.h
new file mode 100644
index 0000000..0086425
--- /dev/null
+++ b/base/include/android-base/chrono_utils.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_BASE_CHRONO_UTILS_H
+#define ANDROID_BASE_CHRONO_UTILS_H
+
+#include <chrono>
+
+namespace android {
+namespace base {
+
+// A std::chrono clock based on CLOCK_BOOTTIME.
+class boot_clock {
+ public:
+ typedef std::chrono::nanoseconds duration;
+ typedef std::chrono::time_point<boot_clock, duration> time_point;
+
+ static time_point now();
+};
+
+} // namespace base
+} // namespace android
+
+#endif // ANDROID_BASE_CHRONO_UTILS_H
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 4de5e57..041586c 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -62,15 +62,14 @@
// Waits for the system property `key` to have the value `expected_value`.
// Times out after `relative_timeout`.
// Returns true on success, false on timeout.
-bool WaitForProperty(const std::string& key,
- const std::string& expected_value,
- std::chrono::milliseconds relative_timeout);
+bool WaitForProperty(const std::string& key, const std::string& expected_value,
+ std::chrono::milliseconds relative_timeout = std::chrono::milliseconds::max());
// Waits for the system property `key` to be created.
// Times out after `relative_timeout`.
// Returns true on success, false on timeout.
-bool WaitForPropertyCreation(const std::string& key,
- std::chrono::milliseconds relative_timeout);
+bool WaitForPropertyCreation(const std::string& key, std::chrono::milliseconds relative_timeout =
+ std::chrono::milliseconds::max());
} // namespace base
} // namespace android
diff --git a/base/properties.cpp b/base/properties.cpp
index 32c0128..816bca0 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -101,22 +101,24 @@
}
// TODO: chrono_utils?
-static void DurationToTimeSpec(timespec& ts, std::chrono::nanoseconds d) {
+static void DurationToTimeSpec(timespec& ts, const std::chrono::milliseconds d) {
auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
ts.tv_sec = s.count();
ts.tv_nsec = ns.count();
}
+// TODO: boot_clock?
using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
-static void UpdateTimeSpec(timespec& ts,
- const AbsTime& timeout) {
+static void UpdateTimeSpec(timespec& ts, std::chrono::milliseconds relative_timeout,
+ const AbsTime& start_time) {
auto now = std::chrono::steady_clock::now();
- auto remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
- if (remaining_timeout < 0ns) {
+ auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+ if (time_elapsed >= relative_timeout) {
ts = { 0, 0 };
} else {
+ auto remaining_timeout = relative_timeout - time_elapsed;
DurationToTimeSpec(ts, remaining_timeout);
}
}
@@ -127,11 +129,7 @@
// Returns nullptr on timeout.
static const prop_info* WaitForPropertyCreation(const std::string& key,
const std::chrono::milliseconds& relative_timeout,
- AbsTime& absolute_timeout) {
- // TODO: boot_clock?
- auto now = std::chrono::steady_clock::now();
- absolute_timeout = now + relative_timeout;
-
+ const AbsTime& start_time) {
// Find the property's prop_info*.
const prop_info* pi;
unsigned global_serial = 0;
@@ -139,17 +137,16 @@
// The property doesn't even exist yet.
// Wait for a global change and then look again.
timespec ts;
- UpdateTimeSpec(ts, absolute_timeout);
+ UpdateTimeSpec(ts, relative_timeout, start_time);
if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr;
}
return pi;
}
-bool WaitForProperty(const std::string& key,
- const std::string& expected_value,
+bool WaitForProperty(const std::string& key, const std::string& expected_value,
std::chrono::milliseconds relative_timeout) {
- AbsTime absolute_timeout;
- const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, absolute_timeout);
+ auto start_time = std::chrono::steady_clock::now();
+ const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, start_time);
if (pi == nullptr) return false;
WaitForPropertyData data;
@@ -162,7 +159,7 @@
if (data.done) return true;
// It didn't, so wait for the property to change before checking again.
- UpdateTimeSpec(ts, absolute_timeout);
+ UpdateTimeSpec(ts, relative_timeout, start_time);
uint32_t unused;
if (!__system_property_wait(pi, data.last_read_serial, &unused, &ts)) return false;
}
@@ -170,8 +167,8 @@
bool WaitForPropertyCreation(const std::string& key,
std::chrono::milliseconds relative_timeout) {
- AbsTime absolute_timeout;
- return (WaitForPropertyCreation(key, relative_timeout, absolute_timeout) != nullptr);
+ auto start_time = std::chrono::steady_clock::now();
+ return (WaitForPropertyCreation(key, relative_timeout, start_time) != nullptr);
}
} // namespace base
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index 1bbe482..de5f3dc 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -151,6 +151,38 @@
ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
}
+TEST(properties, WaitForProperty_MaxTimeout) {
+ std::atomic<bool> flag{false};
+ std::thread thread([&]() {
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+ while (!flag) std::this_thread::yield();
+ std::this_thread::sleep_for(500ms);
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+ });
+
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
+ flag = true;
+ // Test that this does not immediately return false due to overflow issues with the timeout.
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b"));
+ thread.join();
+}
+
+TEST(properties, WaitForProperty_NegativeTimeout) {
+ std::atomic<bool> flag{false};
+ std::thread thread([&]() {
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+ while (!flag) std::this_thread::yield();
+ std::this_thread::sleep_for(500ms);
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+ });
+
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
+ flag = true;
+ // Assert that this immediately returns with a negative timeout
+ ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", -100ms));
+ thread.join();
+}
+
TEST(properties, WaitForPropertyCreation) {
std::thread thread([&]() {
std::this_thread::sleep_for(100ms);
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index f744ad1..95c9af5 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -16,7 +16,6 @@
bootstat_lib_src_files = [
"boot_event_record_store.cpp",
- "uptime_parser.cpp",
]
cc_defaults {
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index 2648594..99d9405 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -20,13 +20,16 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <utime.h>
+
+#include <chrono>
#include <cstdlib>
#include <string>
#include <utility>
+
+#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
-#include "uptime_parser.h"
namespace {
@@ -55,7 +58,9 @@
}
void BootEventRecordStore::AddBootEvent(const std::string& event) {
- AddBootEventWithValue(event, bootstat::ParseUptime());
+ auto uptime = std::chrono::duration_cast<std::chrono::seconds>(
+ android::base::boot_clock::now().time_since_epoch());
+ AddBootEventWithValue(event, uptime.count());
}
// The implementation of AddBootEventValue makes use of the mtime file
diff --git a/bootstat/boot_event_record_store_test.cpp b/bootstat/boot_event_record_store_test.cpp
index 90f6513..d98169b 100644
--- a/bootstat/boot_event_record_store_test.cpp
+++ b/bootstat/boot_event_record_store_test.cpp
@@ -21,15 +21,18 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
+
+#include <chrono>
#include <cstdint>
#include <cstdlib>
+
+#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/test_utils.h>
#include <android-base/unique_fd.h>
-#include <gtest/gtest.h>
#include <gmock/gmock.h>
-#include "uptime_parser.h"
+#include <gtest/gtest.h>
using testing::UnorderedElementsAreArray;
@@ -89,6 +92,13 @@
rmdir(path.c_str());
}
+// Returns the time in seconds since boot.
+time_t GetUptimeSeconds() {
+ return std::chrono::duration_cast<std::chrono::seconds>(
+ android::base::boot_clock::now().time_since_epoch())
+ .count();
+}
+
class BootEventRecordStoreTest : public ::testing::Test {
public:
BootEventRecordStoreTest() {
@@ -126,7 +136,7 @@
BootEventRecordStore store;
store.SetStorePath(GetStorePathForTesting());
- time_t uptime = bootstat::ParseUptime();
+ time_t uptime = GetUptimeSeconds();
ASSERT_NE(-1, uptime);
store.AddBootEvent("cenozoic");
@@ -141,7 +151,7 @@
BootEventRecordStore store;
store.SetStorePath(GetStorePathForTesting());
- time_t uptime = bootstat::ParseUptime();
+ time_t uptime = GetUptimeSeconds();
ASSERT_NE(-1, uptime);
store.AddBootEvent("cretaceous");
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index a4cc5f2..6f25d96 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -21,6 +21,7 @@
#include <getopt.h>
#include <unistd.h>
+#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdio>
@@ -30,15 +31,15 @@
#include <string>
#include <vector>
-#include <android/log.h>
+#include <android-base/chrono_utils.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
+#include <android/log.h>
#include <cutils/properties.h>
#include <metricslogger/metrics_logger.h>
#include "boot_event_record_store.h"
-#include "uptime_parser.h"
namespace {
@@ -255,7 +256,8 @@
BootEventRecordStore boot_event_store;
BootEventRecordStore::BootEventRecord record;
- time_t uptime = bootstat::ParseUptime();
+ auto uptime = std::chrono::duration_cast<std::chrono::seconds>(
+ android::base::boot_clock::now().time_since_epoch());
time_t current_time_utc = time(nullptr);
if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
@@ -282,22 +284,21 @@
// Log the amount of time elapsed until the device is decrypted, which
// includes the variable amount of time the user takes to enter the
// decryption password.
- boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime);
+ boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime.count());
// Subtract the decryption time to normalize the boot cycle timing.
- time_t boot_complete = uptime - record.second;
+ std::chrono::seconds boot_complete = std::chrono::seconds(uptime.count() - record.second);
boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt",
- boot_complete);
-
+ boot_complete.count());
} else {
- boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
- uptime);
+ boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
+ uptime.count());
}
// Record the total time from device startup to boot complete, regardless of
// encryption state.
- boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime);
+ boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime.count());
RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init");
RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.selinux");
diff --git a/bootstat/uptime_parser.cpp b/bootstat/uptime_parser.cpp
deleted file mode 100644
index 7c2034c..0000000
--- a/bootstat/uptime_parser.cpp
+++ /dev/null
@@ -1,38 +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 "uptime_parser.h"
-
-#include <time.h>
-#include <cstdlib>
-#include <string>
-#include <android-base/file.h>
-#include <android-base/logging.h>
-
-namespace bootstat {
-
-time_t ParseUptime() {
- std::string uptime_str;
- if (!android::base::ReadFileToString("/proc/uptime", &uptime_str)) {
- PLOG(ERROR) << "Failed to read /proc/uptime";
- return -1;
- }
-
- // Cast intentionally rounds down.
- return static_cast<time_t>(strtod(uptime_str.c_str(), NULL));
-}
-
-} // namespace bootstat
\ No newline at end of file
diff --git a/bootstat/uptime_parser.h b/bootstat/uptime_parser.h
deleted file mode 100644
index 756ae9b..0000000
--- a/bootstat/uptime_parser.h
+++ /dev/null
@@ -1,29 +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 UPTIME_PARSER_H_
-#define UPTIME_PARSER_H_
-
-#include <time.h>
-
-namespace bootstat {
-
-// Returns the number of seconds the system has been on since reboot.
-time_t ParseUptime();
-
-} // namespace bootstat
-
-#endif // UPTIME_PARSER_H_
\ No newline at end of file
diff --git a/demangle/demangle.cpp b/demangle/demangle.cpp
index be4d2dd..66e5e58 100644
--- a/demangle/demangle.cpp
+++ b/demangle/demangle.cpp
@@ -20,22 +20,25 @@
#include <string.h>
#include <unistd.h>
+#include <cctype>
#include <string>
#include <demangle.h>
extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
-void usage(const char* prog_name) {
- printf("Usage: %s [-c] <NAME_TO_DEMANGLE>\n", prog_name);
- printf(" -c\n");
- printf(" Compare the results of __cxa_demangle against the current\n");
- printf(" demangler.\n");
+static void Usage(const char* prog_name) {
+ printf("usage: %s [-c] [NAME_TO_DEMANGLE...]\n", prog_name);
+ printf("\n");
+ printf("Demangles C++ mangled names if supplied on the command-line, or found\n");
+ printf("reading from stdin otherwise.\n");
+ printf("\n");
+ printf("-c\tCompare against __cxa_demangle\n");
+ printf("\n");
}
-std::string DemangleWithCxa(const char* name) {
+static std::string DemangleWithCxa(const char* name) {
const char* cxa_demangle = __cxa_demangle(name, nullptr, nullptr, nullptr);
-
if (cxa_demangle == nullptr) {
return name;
}
@@ -54,6 +57,49 @@
return demangled_str;
}
+static void Compare(const char* name, const std::string& demangled_name) {
+ std::string cxa_demangled_name(DemangleWithCxa(name));
+ if (cxa_demangled_name != demangled_name) {
+ printf("\nMismatch!\n");
+ printf("\tmangled name: %s\n", name);
+ printf("\tour demangle: %s\n", demangled_name.c_str());
+ printf("\tcxa demangle: %s\n", cxa_demangled_name.c_str());
+ exit(1);
+ }
+}
+
+static int Filter(bool compare) {
+ char* line = nullptr;
+ size_t line_length = 0;
+
+ while ((getline(&line, &line_length, stdin)) != -1) {
+ char* p = line;
+ char* name;
+ while ((name = strstr(p, "_Z")) != nullptr) {
+ // Output anything before the identifier.
+ *name = 0;
+ printf("%s", p);
+ *name = '_';
+
+ // Extract the identifier.
+ p = name;
+ while (*p && (std::isalnum(*p) || *p == '_' || *p == '.' || *p == '$')) ++p;
+
+ // Demangle and output.
+ std::string identifier(name, p);
+ std::string demangled_name = demangle(identifier.c_str());
+ printf("%s", demangled_name.c_str());
+
+ if (compare) Compare(identifier.c_str(), demangled_name);
+ }
+ // Output anything after the last identifier.
+ printf("%s", p);
+ }
+
+ free(line);
+ return 0;
+}
+
int main(int argc, char** argv) {
#ifdef __BIONIC__
const char* prog_name = getprogname();
@@ -67,31 +113,21 @@
if (opt_char == 'c') {
compare = true;
} else {
- usage(prog_name);
+ Usage(prog_name);
return 1;
}
}
- if (optind >= argc || argc - optind != 1) {
- printf("Must supply a single argument.\n\n");
- usage(prog_name);
- return 1;
- }
- const char* name = argv[optind];
- std::string demangled_name = demangle(name);
+ // With no arguments, act as a filter.
+ if (optind == argc) return Filter(compare);
- printf("%s\n", demangled_name.c_str());
+ // Otherwise demangle each argument.
+ while (optind < argc) {
+ const char* name = argv[optind++];
+ std::string demangled_name = demangle(name);
+ printf("%s\n", demangled_name.c_str());
- if (compare) {
- std::string cxa_demangle_str(DemangleWithCxa(name));
-
- if (cxa_demangle_str != demangled_name) {
- printf("Mismatch\n");
- printf("cxa demangle: %s\n", cxa_demangle_str.c_str());
- return 1;
- } else {
- printf("Match\n");
- }
+ if (compare) Compare(name, demangled_name);
}
return 0;
}
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index 2c14c9b..8e49663 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -39,7 +39,28 @@
#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
-static struct fstab* fs_mgr_fstab = nullptr;
+static std::string fstab_by_name_prefix;
+
+static std::string extract_by_name_prefix(struct fstab* fstab) {
+ // In AVB, we can assume that there's an entry for the /misc mount
+ // point in the fstab file and use that to get the device file for
+ // the misc partition. The device needs not to have an actual /misc
+ // partition. Then returns the prefix by removing the trailing "misc":
+ //
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/
+
+ struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
+ if (fstab_entry == nullptr) {
+ LERROR << "/misc mount point not found in fstab";
+ return "";
+ }
+
+ std::string full_path(fstab_entry->blk_device);
+ size_t end_slash = full_path.find_last_of("/");
+
+ return full_path.substr(0, end_slash + 1);
+}
static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* partition,
int64_t offset, size_t num_bytes, void* buffer,
@@ -49,30 +70,14 @@
// for partitions having 'slotselect' optin in fstab file, but it
// won't be appended to the mount point.
//
- // In AVB, we can assume that there's an entry for the /misc mount
- // point and use that to get the device file for the misc partition.
- // From there we'll assume that a by-name scheme is used
- // so we can just replace the trailing "misc" by the given
- // |partition|, e.g.
+ // Appends |partition| to the fstab_by_name_prefix, which is obtained
+ // by removing the trailing "misc" from the device file of /misc mount
+ // point. e.g.,
//
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
- struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fs_mgr_fstab, "/misc");
-
- if (fstab_entry == nullptr) {
- LERROR << "/misc mount point not found in fstab";
- return AVB_IO_RESULT_ERROR_IO;
- }
-
- std::string partition_name(partition);
- std::string path(fstab_entry->blk_device);
- // Replaces the last field of device file if it's not misc.
- if (!android::base::StartsWith(partition_name, "misc")) {
- size_t end_slash = path.find_last_of("/");
- std::string by_name_prefix(path.substr(0, end_slash + 1));
- path = by_name_prefix + partition_name;
- }
+ std::string path = fstab_by_name_prefix + partition;
// Ensures the device path (a symlink created by init) is ready to
// access. fs_mgr_test_access() will test a few iterations if the
@@ -168,8 +173,8 @@
AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab) {
AvbOps* ops;
- // Assigns the fstab to the static variable for later use.
- fs_mgr_fstab = fstab;
+ fstab_by_name_prefix = extract_by_name_prefix(fstab);
+ if (fstab_by_name_prefix.empty()) return nullptr;
ops = (AvbOps*)calloc(1, sizeof(AvbOps));
if (ops == nullptr) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 70b10e0..a9a0df7 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -671,17 +671,6 @@
return fstab;
}
-/* combines fstab entries passed in from device tree with
- * the ones found from fstab_path
- */
-struct fstab *fs_mgr_read_fstab_with_dt(const char *fstab_path)
-{
- struct fstab *fstab_dt = fs_mgr_read_fstab_dt();
- struct fstab *fstab = fs_mgr_read_fstab(fstab_path);
-
- return in_place_merge(fstab_dt, fstab);
-}
-
/*
* tries to load default fstab.<hardware> file from /odm/etc, /vendor/etc
* or /. loads the first one found and also combines fstab entries passed
@@ -704,7 +693,12 @@
LWARNING << __FUNCTION__ << "(): failed to find device hardware name";
}
- return fs_mgr_read_fstab_with_dt(default_fstab.c_str());
+ // combines fstab entries passed in from device tree with
+ // the ones found from default_fstab file
+ struct fstab *fstab_dt = fs_mgr_read_fstab_dt();
+ struct fstab *fstab = fs_mgr_read_fstab(default_fstab.c_str());
+
+ return in_place_merge(fstab_dt, fstab);
}
void fs_mgr_free_fstab(struct fstab *fstab)
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index e5f2699..2fd5f65 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -89,7 +89,6 @@
struct fstab *fs_mgr_read_fstab_default();
struct fstab *fs_mgr_read_fstab_dt();
struct fstab *fs_mgr_read_fstab(const char *fstab_path);
-struct fstab *fs_mgr_read_fstab_with_dt(const char *fstab_path);
void fs_mgr_free_fstab(struct fstab *fstab);
#define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 64a2d82..75b3c61 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -919,8 +919,14 @@
if (!is_file_crypto()) {
return 0;
}
- return e4crypt_create_device_key(args[1].c_str(),
- do_installkeys_ensure_dir_exists);
+ auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
+ if (do_installkeys_ensure_dir_exists(unencrypted_dir.c_str())) {
+ PLOG(ERROR) << "Failed to create " << unencrypted_dir;
+ return -1;
+ }
+ std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
+ "enablefilecrypto"};
+ return do_exec(exec_args);
}
static int do_init_user0(const std::vector<std::string>& args) {
diff --git a/init/init.cpp b/init/init.cpp
index a1d9f1b..3884ae9 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -40,6 +40,7 @@
#include <selinux/label.h>
#include <selinux/android.h>
+#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -69,6 +70,7 @@
#include "util.h"
#include "watchdogd.h"
+using android::base::boot_clock;
using android::base::GetProperty;
using android::base::StringPrintf;
diff --git a/init/service.cpp b/init/service.cpp
index 3db34db..e89de9a 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -32,6 +32,7 @@
#include <selinux/selinux.h>
+#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
@@ -48,6 +49,7 @@
#include "property_service.h"
#include "util.h"
+using android::base::boot_clock;
using android::base::ParseInt;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
diff --git a/init/service.h b/init/service.h
index f08a03f..d84ce02 100644
--- a/init/service.h
+++ b/init/service.h
@@ -26,6 +26,8 @@
#include <string>
#include <vector>
+#include <android-base/chrono_utils.h>
+
#include "action.h"
#include "capabilities.h"
#include "descriptors.h"
@@ -144,8 +146,8 @@
unsigned flags_;
pid_t pid_;
- boot_clock::time_point time_started_; // time of last start
- boot_clock::time_point time_crashed_; // first crash within inspection window
+ android::base::boot_clock::time_point time_started_; // time of last start
+ android::base::boot_clock::time_point time_crashed_; // first crash within inspection window
int crash_count_; // number of times crashed within window
uid_t uid_;
diff --git a/init/util.cpp b/init/util.cpp
index 73d97ed..3f8f244 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -52,6 +52,8 @@
#include "reboot.h"
#include "util.h"
+using android::base::boot_clock;
+
static unsigned int do_decode_uid(const char *s)
{
unsigned int v;
@@ -198,13 +200,6 @@
return success;
}
-boot_clock::time_point boot_clock::now() {
- timespec ts;
- clock_gettime(CLOCK_BOOTTIME, &ts);
- return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
- std::chrono::nanoseconds(ts.tv_nsec));
-}
-
int mkdir_recursive(const char *pathname, mode_t mode)
{
char buf[128];
diff --git a/init/util.h b/init/util.h
index 81c64d7..23509d3 100644
--- a/init/util.h
+++ b/init/util.h
@@ -25,8 +25,11 @@
#include <ostream>
#include <string>
+#include <android-base/chrono_utils.h>
+
#define COLDBOOT_DONE "/dev/.coldboot_done"
+using android::base::boot_clock;
using namespace std::chrono_literals;
int create_socket(const char *name, int type, mode_t perm,
@@ -35,32 +38,22 @@
bool read_file(const char* path, std::string* content);
bool write_file(const char* path, const char* content);
-// A std::chrono clock based on CLOCK_BOOTTIME.
-class boot_clock {
- public:
- typedef std::chrono::nanoseconds duration;
- typedef std::chrono::time_point<boot_clock, duration> time_point;
- static constexpr bool is_steady = true;
-
- static time_point now();
-};
-
class Timer {
- public:
- Timer() : start_(boot_clock::now()) {
- }
+ public:
+ Timer() : start_(boot_clock::now()) {}
- double duration_s() const {
- typedef std::chrono::duration<double> double_duration;
- return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
- }
+ double duration_s() const {
+ typedef std::chrono::duration<double> double_duration;
+ return std::chrono::duration_cast<double_duration>(boot_clock::now() - start_).count();
+ }
- int64_t duration_ms() const {
- return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_).count();
- }
+ int64_t duration_ms() const {
+ return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_)
+ .count();
+ }
- private:
- boot_clock::time_point start_;
+ private:
+ android::base::boot_clock::time_point start_;
};
std::ostream& operator<<(std::ostream& os, const Timer& t);
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.c
index e0e6a34..96ca566 100644
--- a/libcutils/canned_fs_config.c
+++ b/libcutils/canned_fs_config.c
@@ -17,6 +17,7 @@
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -41,7 +42,7 @@
}
int load_canned_fs_config(const char* fn) {
- char line[PATH_MAX + 200];
+ char buf[PATH_MAX + 200];
FILE* f;
f = fopen(fn, "r");
@@ -50,17 +51,21 @@
return -1;
}
- while (fgets(line, sizeof(line), f)) {
+ while (fgets(buf, sizeof(buf), f)) {
Path* p;
char* token;
+ char* line = buf;
+ bool rootdir;
while (canned_used >= canned_alloc) {
canned_alloc = (canned_alloc+1) * 2;
canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
}
p = canned_data + canned_used;
- p->path = strdup(strtok(line, " "));
- p->uid = atoi(strtok(NULL, " "));
+ if (line[0] == '/') line++;
+ rootdir = line[0] == ' ';
+ p->path = strdup(rootdir ? "" : strtok(line, " "));
+ p->uid = atoi(strtok(rootdir ? line : NULL, " "));
p->gid = atoi(strtok(NULL, " "));
p->mode = strtol(strtok(NULL, " "), NULL, 8); // mode is in octal
p->capabilities = 0;
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 0037f15..3eeb9dc 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -130,6 +130,7 @@
#define AID_MEDIA_OBB 1059 /* GID for OBB files on internal media storage */
#define AID_ESE 1060 /* embedded secure element (eSE) subsystem */
#define AID_OTA_UPDATE 1061 /* resource tracking UID for OTA updates */
+#define AID_DISK_RESERVED 1062 /* GID that has access to reserved disk space */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 718d76b..c663a5d 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -69,6 +69,7 @@
cc_test {
name: "libcutils_test_static",
+ test_suites: ["device-tests"],
defaults: ["libcutils_test_default"],
static_libs: ["libc"] + test_libraries,
stl: "libc++_static",
diff --git a/libcutils/tests/AndroidTest.xml b/libcutils/tests/AndroidTest.xml
new file mode 100644
index 0000000..c945f4d
--- /dev/null
+++ b/libcutils/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for libcutils_test_static">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libcutils_test_static->/data/local/tmp/libcutils_test_static" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="libcutils_test_static" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/libnativebridge/.clang-format b/libnativebridge/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libnativebridge/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libnativeloader/.clang-format b/libnativeloader/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libnativeloader/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index ece623b..dabeac1 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -47,6 +47,7 @@
srcs: [
"ArmExidx.cpp",
+ "DwarfMemory.cpp",
"Elf.cpp",
"ElfInterface.cpp",
"ElfInterfaceArm.cpp",
@@ -87,6 +88,7 @@
srcs: [
"tests/ArmExidxDecodeTest.cpp",
"tests/ArmExidxExtractTest.cpp",
+ "tests/DwarfMemoryTest.cpp",
"tests/ElfInterfaceArmTest.cpp",
"tests/ElfInterfaceTest.cpp",
"tests/ElfTest.cpp",
diff --git a/libunwindstack/DwarfEncoding.h b/libunwindstack/DwarfEncoding.h
new file mode 100644
index 0000000..0ff3b8c
--- /dev/null
+++ b/libunwindstack/DwarfEncoding.h
@@ -0,0 +1,47 @@
+/*
+ * 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 _LIBUNWINDSTACK_DWARF_ENCODING_H
+#define _LIBUNWINDSTACK_DWARF_ENCODING_H
+
+#include <stdint.h>
+
+enum DwarfEncoding : uint8_t {
+ DW_EH_PE_omit = 0xff,
+
+ DW_EH_PE_absptr = 0x00,
+ DW_EH_PE_uleb128 = 0x01,
+ DW_EH_PE_udata2 = 0x02,
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_udata8 = 0x04,
+ DW_EH_PE_sleb128 = 0x09,
+ DW_EH_PE_sdata2 = 0x0a,
+ DW_EH_PE_sdata4 = 0x0b,
+ DW_EH_PE_sdata8 = 0x0c,
+
+ DW_EH_PE_pcrel = 0x10,
+ DW_EH_PE_textrel = 0x20,
+ DW_EH_PE_datarel = 0x30,
+ DW_EH_PE_funcrel = 0x40,
+ DW_EH_PE_aligned = 0x50,
+
+ // The following are special values used to encode CFA and OP operands.
+ DW_EH_PE_udata1 = 0x0d,
+ DW_EH_PE_sdata1 = 0x0e,
+ DW_EH_PE_block = 0x0f,
+};
+
+#endif // _LIBUNWINDSTACK_DWARF_ENCODING_H
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
new file mode 100644
index 0000000..11806ea
--- /dev/null
+++ b/libunwindstack/DwarfMemory.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2017 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 <assert.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "DwarfEncoding.h"
+#include "DwarfMemory.h"
+#include "Memory.h"
+
+bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
+ if (!memory_->Read(cur_offset_, dst, num_bytes)) {
+ return false;
+ }
+ cur_offset_ += num_bytes;
+ return true;
+}
+
+template <typename SignedType>
+bool DwarfMemory::ReadSigned(uint64_t* value) {
+ SignedType signed_value;
+ if (!ReadBytes(&signed_value, sizeof(SignedType))) {
+ return false;
+ }
+ *value = static_cast<int64_t>(signed_value);
+ return true;
+}
+
+bool DwarfMemory::ReadULEB128(uint64_t* value) {
+ uint64_t cur_value = 0;
+ uint64_t shift = 0;
+ uint8_t byte;
+ do {
+ if (!ReadBytes(&byte, 1)) {
+ return false;
+ }
+ cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
+ shift += 7;
+ } while (byte & 0x80);
+ *value = cur_value;
+ return true;
+}
+
+bool DwarfMemory::ReadSLEB128(int64_t* value) {
+ uint64_t cur_value = 0;
+ uint64_t shift = 0;
+ uint8_t byte;
+ do {
+ if (!ReadBytes(&byte, 1)) {
+ return false;
+ }
+ cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
+ shift += 7;
+ } while (byte & 0x80);
+ if (byte & 0x40) {
+ // Negative value, need to sign extend.
+ cur_value |= static_cast<uint64_t>(-1) << shift;
+ }
+ *value = static_cast<int64_t>(cur_value);
+ return true;
+}
+
+template <typename AddressType>
+size_t DwarfMemory::GetEncodedSize(uint8_t encoding) {
+ switch (encoding & 0x0f) {
+ case DW_EH_PE_absptr:
+ return sizeof(AddressType);
+ case DW_EH_PE_udata1:
+ case DW_EH_PE_sdata1:
+ return 1;
+ case DW_EH_PE_udata2:
+ case DW_EH_PE_sdata2:
+ return 2;
+ case DW_EH_PE_udata4:
+ case DW_EH_PE_sdata4:
+ return 4;
+ case DW_EH_PE_udata8:
+ case DW_EH_PE_sdata8:
+ return 8;
+ case DW_EH_PE_uleb128:
+ case DW_EH_PE_sleb128:
+ default:
+ return 0;
+ }
+}
+
+bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) {
+ assert((encoding & 0x0f) == 0);
+ assert(encoding != DW_EH_PE_aligned);
+
+ // Handle the encoding.
+ switch (encoding) {
+ case DW_EH_PE_absptr:
+ // Nothing to do.
+ break;
+ case DW_EH_PE_pcrel:
+ if (pc_offset_ == static_cast<uint64_t>(-1)) {
+ // Unsupported encoding.
+ return false;
+ }
+ *value += pc_offset_;
+ break;
+ case DW_EH_PE_textrel:
+ if (text_offset_ == static_cast<uint64_t>(-1)) {
+ // Unsupported encoding.
+ return false;
+ }
+ *value += text_offset_;
+ break;
+ case DW_EH_PE_datarel:
+ if (data_offset_ == static_cast<uint64_t>(-1)) {
+ // Unsupported encoding.
+ return false;
+ }
+ *value += data_offset_;
+ break;
+ case DW_EH_PE_funcrel:
+ if (func_offset_ == static_cast<uint64_t>(-1)) {
+ // Unsupported encoding.
+ return false;
+ }
+ *value += func_offset_;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+template <typename AddressType>
+bool DwarfMemory::ReadEncodedValue(uint8_t encoding, uint64_t* value) {
+ if (encoding == DW_EH_PE_omit) {
+ *value = 0;
+ return true;
+ } else if (encoding == DW_EH_PE_aligned) {
+ if (__builtin_add_overflow(cur_offset_, sizeof(AddressType) - 1, &cur_offset_)) {
+ return false;
+ }
+ cur_offset_ &= -sizeof(AddressType);
+
+ if (sizeof(AddressType) != sizeof(uint64_t)) {
+ *value = 0;
+ }
+ return ReadBytes(value, sizeof(AddressType));
+ }
+
+ // Get the data.
+ switch (encoding & 0x0f) {
+ case DW_EH_PE_absptr:
+ if (sizeof(AddressType) != sizeof(uint64_t)) {
+ *value = 0;
+ }
+ if (!ReadBytes(value, sizeof(AddressType))) {
+ return false;
+ }
+ break;
+ case DW_EH_PE_uleb128:
+ if (!ReadULEB128(value)) {
+ return false;
+ }
+ break;
+ case DW_EH_PE_sleb128:
+ int64_t signed_value;
+ if (!ReadSLEB128(&signed_value)) {
+ return false;
+ }
+ *value = static_cast<uint64_t>(signed_value);
+ break;
+ case DW_EH_PE_udata1: {
+ uint8_t value8;
+ if (!ReadBytes(&value8, 1)) {
+ return false;
+ }
+ *value = value8;
+ } break;
+ case DW_EH_PE_sdata1:
+ if (!ReadSigned<int8_t>(value)) {
+ return false;
+ }
+ break;
+ case DW_EH_PE_udata2: {
+ uint16_t value16;
+ if (!ReadBytes(&value16, 2)) {
+ return false;
+ }
+ *value = value16;
+ } break;
+ case DW_EH_PE_sdata2:
+ if (!ReadSigned<int16_t>(value)) {
+ return false;
+ }
+ break;
+ case DW_EH_PE_udata4: {
+ uint32_t value32;
+ if (!ReadBytes(&value32, 4)) {
+ return false;
+ }
+ *value = value32;
+ } break;
+ case DW_EH_PE_sdata4:
+ if (!ReadSigned<int32_t>(value)) {
+ return false;
+ }
+ break;
+ case DW_EH_PE_udata8:
+ if (!ReadBytes(value, sizeof(uint64_t))) {
+ return false;
+ }
+ break;
+ case DW_EH_PE_sdata8:
+ if (!ReadSigned<int64_t>(value)) {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return AdjustEncodedValue(encoding & 0xf0, value);
+}
+
+// Instantiate all of the needed template functions.
+template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*);
+template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*);
+template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*);
+template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*);
+
+template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t);
+template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t);
+
+template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
+template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
diff --git a/libunwindstack/DwarfMemory.h b/libunwindstack/DwarfMemory.h
new file mode 100644
index 0000000..a304dd9
--- /dev/null
+++ b/libunwindstack/DwarfMemory.h
@@ -0,0 +1,72 @@
+/*
+ * 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 _LIBUNWINDSTACK_DWARF_MEMORY_H
+#define _LIBUNWINDSTACK_DWARF_MEMORY_H
+
+#include <stdint.h>
+
+// Forward declarations.
+class Memory;
+
+class DwarfMemory {
+ public:
+ DwarfMemory(Memory* memory) : memory_(memory) {}
+ virtual ~DwarfMemory() = default;
+
+ bool ReadBytes(void* dst, size_t num_bytes);
+
+ template <typename SignedType>
+ bool ReadSigned(uint64_t* value);
+
+ bool ReadULEB128(uint64_t* value);
+
+ bool ReadSLEB128(int64_t* value);
+
+ template <typename AddressType>
+ size_t GetEncodedSize(uint8_t encoding);
+
+ bool AdjustEncodedValue(uint8_t encoding, uint64_t* value);
+
+ template <typename AddressType>
+ bool ReadEncodedValue(uint8_t encoding, uint64_t* value);
+
+ uint64_t cur_offset() { return cur_offset_; }
+ void set_cur_offset(uint64_t cur_offset) { cur_offset_ = cur_offset; }
+
+ void set_pc_offset(uint64_t offset) { pc_offset_ = offset; }
+ void clear_pc_offset() { pc_offset_ = static_cast<uint64_t>(-1); }
+
+ void set_data_offset(uint64_t offset) { data_offset_ = offset; }
+ void clear_data_offset() { data_offset_ = static_cast<uint64_t>(-1); }
+
+ void set_func_offset(uint64_t offset) { func_offset_ = offset; }
+ void clear_func_offset() { func_offset_ = static_cast<uint64_t>(-1); }
+
+ void set_text_offset(uint64_t offset) { text_offset_ = offset; }
+ void clear_text_offset() { text_offset_ = static_cast<uint64_t>(-1); }
+
+ private:
+ Memory* memory_;
+ uint64_t cur_offset_ = 0;
+
+ uint64_t pc_offset_ = static_cast<uint64_t>(-1);
+ uint64_t data_offset_ = static_cast<uint64_t>(-1);
+ uint64_t func_offset_ = static_cast<uint64_t>(-1);
+ uint64_t text_offset_ = static_cast<uint64_t>(-1);
+};
+
+#endif // _LIBUNWINDSTACK_DWARF_MEMORY_H
diff --git a/libunwindstack/tests/DwarfMemoryTest.cpp b/libunwindstack/tests/DwarfMemoryTest.cpp
new file mode 100644
index 0000000..4877f36
--- /dev/null
+++ b/libunwindstack/tests/DwarfMemoryTest.cpp
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2017 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 <stdint.h>
+
+#include <ios>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "DwarfMemory.h"
+
+#include "MemoryFake.h"
+
+class DwarfMemoryTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ memory_.Clear();
+ dwarf_mem_.reset(new DwarfMemory(&memory_));
+ }
+
+ template <typename AddressType>
+ void GetEncodedSizeTest(uint8_t value, size_t expected);
+ template <typename AddressType>
+ void ReadEncodedValue_omit();
+ template <typename AddressType>
+ void ReadEncodedValue_leb128();
+ template <typename AddressType>
+ void ReadEncodedValue_data1();
+ template <typename AddressType>
+ void ReadEncodedValue_data2();
+ template <typename AddressType>
+ void ReadEncodedValue_data4();
+ template <typename AddressType>
+ void ReadEncodedValue_data8();
+ template <typename AddressType>
+ void ReadEncodedValue_non_zero_adjust();
+ template <typename AddressType>
+ void ReadEncodedValue_overflow();
+
+ MemoryFake memory_;
+ std::unique_ptr<DwarfMemory> dwarf_mem_;
+};
+
+TEST_F(DwarfMemoryTest, ReadBytes) {
+ memory_.SetMemory(0, std::vector<uint8_t>{0x10, 0x18, 0xff, 0xfe});
+
+ uint8_t byte;
+ ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
+ ASSERT_EQ(0x10U, byte);
+ ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
+ ASSERT_EQ(0x18U, byte);
+ ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
+ ASSERT_EQ(0xffU, byte);
+ ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
+ ASSERT_EQ(0xfeU, byte);
+ ASSERT_EQ(4U, dwarf_mem_->cur_offset());
+
+ dwarf_mem_->set_cur_offset(2);
+ ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
+ ASSERT_EQ(0xffU, byte);
+ ASSERT_EQ(3U, dwarf_mem_->cur_offset());
+}
+
+TEST_F(DwarfMemoryTest, ReadSigned_check) {
+ uint64_t value;
+
+ // Signed 8 byte reads.
+ memory_.SetData8(0, static_cast<uint8_t>(-10));
+ memory_.SetData8(1, 200);
+ ASSERT_TRUE(dwarf_mem_->ReadSigned<int8_t>(&value));
+ ASSERT_EQ(static_cast<int8_t>(-10), static_cast<int8_t>(value));
+ ASSERT_TRUE(dwarf_mem_->ReadSigned<int8_t>(&value));
+ ASSERT_EQ(static_cast<int8_t>(200), static_cast<int8_t>(value));
+
+ // Signed 16 byte reads.
+ memory_.SetData16(0x10, static_cast<uint16_t>(-1000));
+ memory_.SetData16(0x12, 50100);
+ dwarf_mem_->set_cur_offset(0x10);
+ ASSERT_TRUE(dwarf_mem_->ReadSigned<int16_t>(&value));
+ ASSERT_EQ(static_cast<int16_t>(-1000), static_cast<int16_t>(value));
+ ASSERT_TRUE(dwarf_mem_->ReadSigned<int16_t>(&value));
+ ASSERT_EQ(static_cast<int16_t>(50100), static_cast<int16_t>(value));
+
+ // Signed 32 byte reads.
+ memory_.SetData32(0x100, static_cast<uint32_t>(-1000000000));
+ memory_.SetData32(0x104, 3000000000);
+ dwarf_mem_->set_cur_offset(0x100);
+ ASSERT_TRUE(dwarf_mem_->ReadSigned<int32_t>(&value));
+ ASSERT_EQ(static_cast<int32_t>(-1000000000), static_cast<int32_t>(value));
+ ASSERT_TRUE(dwarf_mem_->ReadSigned<int32_t>(&value));
+ ASSERT_EQ(static_cast<int32_t>(3000000000), static_cast<int32_t>(value));
+
+ // Signed 64 byte reads.
+ memory_.SetData64(0x200, static_cast<uint64_t>(-2000000000000LL));
+ memory_.SetData64(0x208, 5000000000000LL);
+ dwarf_mem_->set_cur_offset(0x200);
+ ASSERT_TRUE(dwarf_mem_->ReadSigned<int64_t>(&value));
+ ASSERT_EQ(static_cast<int64_t>(-2000000000000), static_cast<int64_t>(value));
+ ASSERT_TRUE(dwarf_mem_->ReadSigned<int64_t>(&value));
+ ASSERT_EQ(static_cast<int64_t>(5000000000000), static_cast<int64_t>(value));
+}
+
+TEST_F(DwarfMemoryTest, ReadULEB128) {
+ memory_.SetMemory(0, std::vector<uint8_t>{0x01, 0x80, 0x24, 0xff, 0xc3, 0xff, 0x7f});
+
+ uint64_t value;
+ ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
+ ASSERT_EQ(1U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(1U, value);
+
+ ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
+ ASSERT_EQ(3U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0x1200U, value);
+
+ ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
+ ASSERT_EQ(7U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0xfffe1ffU, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadSLEB128) {
+ memory_.SetMemory(0, std::vector<uint8_t>{0x06, 0x40, 0x82, 0x34, 0x89, 0x64, 0xf9, 0xc3, 0x8f,
+ 0x2f, 0xbf, 0xc3, 0xf7, 0x5f});
+
+ int64_t value;
+ ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+ ASSERT_EQ(1U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(6U, value);
+
+ ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+ ASSERT_EQ(2U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0xffffffffffffffc0ULL, static_cast<uint64_t>(value));
+
+ ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+ ASSERT_EQ(4U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0x1a02U, value);
+
+ ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+ ASSERT_EQ(6U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0xfffffffffffff209ULL, static_cast<uint64_t>(value));
+
+ ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+ ASSERT_EQ(10U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0x5e3e1f9U, value);
+
+ ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
+ ASSERT_EQ(14U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0xfffffffffbfde1bfULL, static_cast<uint64_t>(value));
+}
+
+template <typename AddressType>
+void DwarfMemoryTest::GetEncodedSizeTest(uint8_t value, size_t expected) {
+ for (size_t i = 0; i < 16; i++) {
+ uint8_t encoding = (i << 4) | value;
+ ASSERT_EQ(expected, dwarf_mem_->GetEncodedSize<AddressType>(encoding))
+ << "encoding 0x" << std::hex << static_cast<uint32_t>(encoding) << " test value 0x"
+ << static_cast<size_t>(value);
+ }
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_absptr_uint32_t) {
+ GetEncodedSizeTest<uint32_t>(0, sizeof(uint32_t));
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_absptr_uint64_t) {
+ GetEncodedSizeTest<uint64_t>(0, sizeof(uint64_t));
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_data1) {
+ // udata1
+ GetEncodedSizeTest<uint32_t>(0x0d, 1);
+ GetEncodedSizeTest<uint64_t>(0x0d, 1);
+
+ // sdata1
+ GetEncodedSizeTest<uint32_t>(0x0e, 1);
+ GetEncodedSizeTest<uint64_t>(0x0e, 1);
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_data2) {
+ // udata2
+ GetEncodedSizeTest<uint32_t>(0x02, 2);
+ GetEncodedSizeTest<uint64_t>(0x02, 2);
+
+ // sdata2
+ GetEncodedSizeTest<uint32_t>(0x0a, 2);
+ GetEncodedSizeTest<uint64_t>(0x0a, 2);
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_data4) {
+ // udata4
+ GetEncodedSizeTest<uint32_t>(0x03, 4);
+ GetEncodedSizeTest<uint64_t>(0x03, 4);
+
+ // sdata4
+ GetEncodedSizeTest<uint32_t>(0x0b, 4);
+ GetEncodedSizeTest<uint64_t>(0x0b, 4);
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_data8) {
+ // udata8
+ GetEncodedSizeTest<uint32_t>(0x04, 8);
+ GetEncodedSizeTest<uint64_t>(0x04, 8);
+
+ // sdata8
+ GetEncodedSizeTest<uint32_t>(0x0c, 8);
+ GetEncodedSizeTest<uint64_t>(0x0c, 8);
+}
+
+TEST_F(DwarfMemoryTest, GetEncodedSize_unknown) {
+ GetEncodedSizeTest<uint32_t>(0x01, 0);
+ GetEncodedSizeTest<uint64_t>(0x01, 0);
+
+ GetEncodedSizeTest<uint32_t>(0x09, 0);
+ GetEncodedSizeTest<uint64_t>(0x09, 0);
+
+ GetEncodedSizeTest<uint32_t>(0x0f, 0);
+ GetEncodedSizeTest<uint64_t>(0x0f, 0);
+}
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_omit() {
+ uint64_t value = 123;
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0xff, &value));
+ ASSERT_EQ(0U, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_omit_uint32_t) { ReadEncodedValue_omit<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_omit_uint64_t) { ReadEncodedValue_omit<uint64_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_absptr_uint32_t) {
+ uint64_t value = 100;
+ ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x00, &value));
+
+ memory_.SetData32(0, 0x12345678);
+
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x00, &value));
+ ASSERT_EQ(4U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0x12345678U, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_absptr_uint64_t) {
+ uint64_t value = 100;
+ ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x00, &value));
+
+ memory_.SetData64(0, 0x12345678f1f2f3f4ULL);
+
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x00, &value));
+ ASSERT_EQ(8U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0x12345678f1f2f3f4ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_aligned_uint32_t) {
+ uint64_t value = 100;
+ dwarf_mem_->set_cur_offset(1);
+ ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x50, &value));
+
+ memory_.SetData32(4, 0x12345678);
+
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x50, &value));
+ ASSERT_EQ(8U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0x12345678U, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_aligned_uint64_t) {
+ uint64_t value = 100;
+ dwarf_mem_->set_cur_offset(1);
+ ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x50, &value));
+
+ memory_.SetData64(8, 0x12345678f1f2f3f4ULL);
+
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x50, &value));
+ ASSERT_EQ(16U, dwarf_mem_->cur_offset());
+ ASSERT_EQ(0x12345678f1f2f3f4ULL, value);
+}
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_leb128() {
+ memory_.SetMemory(0, std::vector<uint8_t>{0x80, 0x42});
+
+ uint64_t value = 100;
+ // uleb128
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x01, &value));
+ ASSERT_EQ(0x2100U, value);
+
+ dwarf_mem_->set_cur_offset(0);
+ // sleb128
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x09, &value));
+ ASSERT_EQ(0xffffffffffffe100ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint32_t) { ReadEncodedValue_leb128<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint64_t) { ReadEncodedValue_leb128<uint64_t>(); }
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_data1() {
+ memory_.SetData8(0, 0xe0);
+
+ uint64_t value = 0;
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0d, &value));
+ ASSERT_EQ(0xe0U, value);
+
+ dwarf_mem_->set_cur_offset(0);
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0e, &value));
+ ASSERT_EQ(0xffffffffffffffe0ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint32_t) { ReadEncodedValue_data1<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint64_t) { ReadEncodedValue_data1<uint64_t>(); }
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_data2() {
+ memory_.SetData16(0, 0xe000);
+
+ uint64_t value = 0;
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x02, &value));
+ ASSERT_EQ(0xe000U, value);
+
+ dwarf_mem_->set_cur_offset(0);
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0a, &value));
+ ASSERT_EQ(0xffffffffffffe000ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint32_t) { ReadEncodedValue_data2<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint64_t) { ReadEncodedValue_data2<uint64_t>(); }
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_data4() {
+ memory_.SetData32(0, 0xe0000000);
+
+ uint64_t value = 0;
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x03, &value));
+ ASSERT_EQ(0xe0000000U, value);
+
+ dwarf_mem_->set_cur_offset(0);
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0b, &value));
+ ASSERT_EQ(0xffffffffe0000000ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint32_t) { ReadEncodedValue_data4<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint64_t) { ReadEncodedValue_data4<uint64_t>(); }
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_data8() {
+ memory_.SetData64(0, 0xe000000000000000ULL);
+
+ uint64_t value = 0;
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x04, &value));
+ ASSERT_EQ(0xe000000000000000ULL, value);
+
+ dwarf_mem_->set_cur_offset(0);
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0c, &value));
+ ASSERT_EQ(0xe000000000000000ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint32_t) { ReadEncodedValue_data8<uint32_t>(); }
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint64_t) { ReadEncodedValue_data8<uint64_t>(); }
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_non_zero_adjust() {
+ memory_.SetData64(0, 0xe000000000000000ULL);
+
+ uint64_t value = 0;
+ dwarf_mem_->set_pc_offset(0x2000);
+ ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x14, &value));
+ ASSERT_EQ(0xe000000000002000ULL, value);
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_non_zero_adjust_uint32_t) {
+ ReadEncodedValue_non_zero_adjust<uint32_t>();
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_non_zero_adjust_uint64_t) {
+ ReadEncodedValue_non_zero_adjust<uint64_t>();
+}
+
+template <typename AddressType>
+void DwarfMemoryTest::ReadEncodedValue_overflow() {
+ memory_.SetData64(0, 0);
+
+ uint64_t value = 0;
+ dwarf_mem_->set_cur_offset(UINT64_MAX);
+ ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<AddressType>(0x50, &value));
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_overflow_uint32_t) {
+ ReadEncodedValue_overflow<uint32_t>();
+}
+
+TEST_F(DwarfMemoryTest, ReadEncodedValue_overflow_uint64_t) {
+ ReadEncodedValue_overflow<uint64_t>();
+}
+
+TEST_F(DwarfMemoryTest, AdjustEncodedValue_absptr) {
+ uint64_t value = 0x1234;
+ ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x00, &value));
+ ASSERT_EQ(0x1234U, value);
+}
+
+TEST_F(DwarfMemoryTest, AdjustEncodedValue_pcrel) {
+ uint64_t value = 0x1234;
+ ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
+
+ dwarf_mem_->set_pc_offset(0x2000);
+ ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
+ ASSERT_EQ(0x3234U, value);
+
+ dwarf_mem_->set_pc_offset(static_cast<uint64_t>(-4));
+ value = 0x1234;
+ ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
+ ASSERT_EQ(0x1230U, value);
+}
+
+TEST_F(DwarfMemoryTest, AdjustEncodedValue_textrel) {
+ uint64_t value = 0x8234;
+ ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
+
+ dwarf_mem_->set_text_offset(0x1000);
+ ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
+ ASSERT_EQ(0x9234U, value);
+
+ dwarf_mem_->set_text_offset(static_cast<uint64_t>(-16));
+ value = 0x8234;
+ ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
+ ASSERT_EQ(0x8224U, value);
+}
+
+TEST_F(DwarfMemoryTest, AdjustEncodedValue_datarel) {
+ uint64_t value = 0xb234;
+ ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
+
+ dwarf_mem_->set_data_offset(0x1200);
+ ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
+ ASSERT_EQ(0xc434U, value);
+
+ dwarf_mem_->set_data_offset(static_cast<uint64_t>(-256));
+ value = 0xb234;
+ ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
+ ASSERT_EQ(0xb134U, value);
+}
+
+TEST_F(DwarfMemoryTest, AdjustEncodedValue_funcrel) {
+ uint64_t value = 0x15234;
+ ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
+
+ dwarf_mem_->set_func_offset(0x60000);
+ ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
+ ASSERT_EQ(0x75234U, value);
+
+ dwarf_mem_->set_func_offset(static_cast<uint64_t>(-4096));
+ value = 0x15234;
+ ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
+ ASSERT_EQ(0x14234U, value);
+}
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 81356fe..04a620c 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -235,7 +235,9 @@
}
iovec[1].iov_len = entry.len;
- log_time retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mRealTime;
+ log_time retval = reader->sendDatav(iovec, 1 + (entry.len != 0))
+ ? FLUSH_ERROR
+ : mRealTime;
if (buffer) free(buffer);
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
index 381df5a..8fcd17f 100644
--- a/tzdatacheck/tzdatacheck.cpp
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -30,6 +30,19 @@
#include "android-base/logging.h"
+// The name of the directory that holds a staged time zone update distro. If this exists it should
+// replace the one in CURRENT_DIR_NAME.
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* STAGED_DIR_NAME = "/staged";
+
+// The name of the directory that holds the (optional) installed time zone update distro.
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* CURRENT_DIR_NAME = "/current";
+
+// The name of a file in the staged dir that indicates the staged operation is an "uninstall".
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* UNINSTALL_TOMBSTONE_FILE_NAME = "/STAGED_UNINSTALL_TOMBSTONE";
+
// The name of the file containing the distro version information.
// See also libcore.tzdata.shared2.TimeZoneDistro / libcore.tzdata.shared2.DistroVersion.
static const char* DISTRO_VERSION_FILENAME = "/distro_version";
@@ -75,7 +88,6 @@
static const char TZ_DATA_HEADER_PREFIX[] = "tzdata";
static const size_t TZ_DATA_HEADER_PREFIX_LEN = sizeof(TZ_DATA_HEADER_PREFIX) - 1; // exclude \0
-
static void usage() {
std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
"\n"
@@ -184,7 +196,7 @@
return 0;
}
-enum PathStatus { ERR, NONE, IS_DIR, NOT_DIR };
+enum PathStatus { ERR, NONE, IS_DIR, IS_REG, UNKNOWN };
static PathStatus checkPath(const std::string& path) {
struct stat buf;
@@ -195,7 +207,31 @@
}
return NONE;
}
- return S_ISDIR(buf.st_mode) ? IS_DIR : NOT_DIR;
+ return S_ISDIR(buf.st_mode) ? IS_DIR : S_ISREG(buf.st_mode) ? IS_REG : UNKNOWN;
+}
+
+/*
+ * Deletes fileToDelete and returns true if it is successful. If fileToDelete is not a file or
+ * cannot be accessed this method returns false.
+ */
+static bool deleteFile(const std::string& fileToDelete) {
+ // Check whether the file exists.
+ PathStatus pathStatus = checkPath(fileToDelete);
+ if (pathStatus == NONE) {
+ LOG(INFO) << "Path " << fileToDelete << " does not exist";
+ return true;
+ }
+ if (pathStatus != IS_REG) {
+ LOG(WARNING) << "Path " << fileToDelete << " failed to stat() or is not a file.";
+ return false;
+ }
+
+ // Attempt the deletion.
+ int rc = unlink(fileToDelete.c_str());
+ if (rc != 0) {
+ PLOG(WARNING) << "unlink() failed for " << fileToDelete;
+ }
+ return rc == 0;
}
/*
@@ -260,8 +296,7 @@
std::string dataUpdatesDirName(dataZoneInfoDir);
dataUpdatesDirName += "/updates";
LOG(INFO) << "Removing: " << dataUpdatesDirName;
- bool deleted = deleteDir(dataUpdatesDirName);
- if (!deleted) {
+ if (!deleteDir(dataUpdatesDirName)) {
LOG(WARNING) << "Deletion of install metadata " << dataUpdatesDirName
<< " was not successful";
}
@@ -270,14 +305,151 @@
/*
* Deletes the timezone update distro directory.
*/
-static void deleteUpdateDistroDir(std::string& distroDirName) {
+static void deleteUpdateDistroDir(const std::string& distroDirName) {
LOG(INFO) << "Removing: " << distroDirName;
- bool deleted = deleteDir(distroDirName);
- if (!deleted) {
+ if (!deleteDir(distroDirName)) {
LOG(WARNING) << "Deletion of distro dir " << distroDirName << " was not successful";
}
}
+static void handleStagedUninstall(const std::string& dataStagedDirName,
+ const std::string& dataCurrentDirName,
+ const PathStatus dataCurrentDirStatus) {
+ LOG(INFO) << "Staged operation is an uninstall.";
+
+ // Delete the current install directory.
+ switch (dataCurrentDirStatus) {
+ case NONE:
+ // This is unexpected: No uninstall should be staged if there is nothing to
+ // uninstall. Carry on anyway.
+ LOG(WARNING) << "No current install to delete.";
+ break;
+ case IS_DIR:
+ // This is normal. Delete the current install dir.
+ if (!deleteDir(dataCurrentDirName)) {
+ LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+ << " was not successful";
+ // If this happens we don't know whether we were able to delete or not. We don't
+ // delete the staged operation so it will be retried next boot unless overridden.
+ return;
+ }
+ break;
+ case IS_REG:
+ default:
+ // This is unexpected: We can try to delete the unexpected file and carry on.
+ LOG(WARNING) << "Current distro dir " << dataCurrentDirName
+ << " is not actually a directory. Attempting deletion.";
+ if (!deleteFile(dataCurrentDirName)) {
+ LOG(WARNING) << "Could not delete " << dataCurrentDirName;
+ return;
+ }
+ break;
+ }
+
+ // Delete the staged uninstall dir.
+ if (!deleteDir(dataStagedDirName)) {
+ LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+ << " was not successful";
+ // If this happens we don't know whether we were able to delete the staged operation
+ // or not.
+ return;
+ }
+ LOG(INFO) << "Staged uninstall complete.";
+}
+
+static void handleStagedInstall(const std::string& dataStagedDirName,
+ const std::string& dataCurrentDirName,
+ const PathStatus dataCurrentDirStatus) {
+ LOG(INFO) << "Staged operation is an install.";
+
+ switch (dataCurrentDirStatus) {
+ case NONE:
+ // This is expected: This is the first install.
+ LOG(INFO) << "No current install to replace.";
+ break;
+ case IS_DIR:
+ // This is expected: We are replacing an existing install.
+ // Delete the current dir so we can replace it.
+ if (!deleteDir(dataCurrentDirName)) {
+ LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+ << " was not successful";
+ // If this happens, we cannot proceed.
+ return;
+ }
+ break;
+ case IS_REG:
+ default:
+ // This is unexpected: We can try to delete the unexpected file and carry on.
+ LOG(WARNING) << "Current distro dir " << dataCurrentDirName
+ << " is not actually a directory. Attempting deletion.";
+ if (!deleteFile(dataCurrentDirName)) {
+ LOG(WARNING) << "Could not delete " << dataCurrentDirName;
+ return;
+ }
+ break;
+ }
+
+ // Move the staged dir so it is the new current dir, completing the install.
+ LOG(INFO) << "Moving " << dataStagedDirName << " to " << dataCurrentDirName;
+ int rc = rename(dataStagedDirName.c_str(), dataCurrentDirName.c_str());
+ if (rc == -1) {
+ PLOG(WARNING) << "Unable to rename directory from " << dataStagedDirName << " to "
+ << &dataCurrentDirName[0];
+ return;
+ }
+
+ LOG(INFO) << "Staged install complete.";
+}
+/*
+ * Process a staged operation if there is one.
+ */
+static void processStagedOperation(const std::string& dataStagedDirName,
+ const std::string& dataCurrentDirName) {
+ PathStatus dataStagedDirStatus = checkPath(dataStagedDirName);
+
+ // Exit early for the common case.
+ if (dataStagedDirStatus == NONE) {
+ LOG(DEBUG) << "No staged time zone operation.";
+ return;
+ }
+
+ // Check known directory names are in a good starting state.
+ if (dataStagedDirStatus != IS_DIR) {
+ LOG(WARNING) << "Staged distro dir " << dataStagedDirName
+ << " could not be accessed or is not a directory."
+ << " stagedDirStatus=" << dataStagedDirStatus;
+ return;
+ }
+
+ // dataStagedDirStatus == IS_DIR.
+
+ // Work out whether there is anything currently installed.
+ PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
+ if (dataCurrentDirStatus == ERR) {
+ LOG(WARNING) << "Current install dir " << dataCurrentDirName << " could not be accessed"
+ << " dataCurrentDirStatus=" << dataCurrentDirStatus;
+ return;
+ }
+
+ // We must perform the staged operation.
+
+ // Check to see if the staged directory contains an uninstall or an install operation.
+ std::string uninstallTombStoneFile(dataStagedDirName);
+ uninstallTombStoneFile += UNINSTALL_TOMBSTONE_FILE_NAME;
+ int uninstallTombStoneFileStatus = checkPath(uninstallTombStoneFile);
+ if (uninstallTombStoneFileStatus != IS_REG && uninstallTombStoneFileStatus != NONE) {
+ // Error case.
+ LOG(WARNING) << "Unable to determine if the staged operation is an uninstall.";
+ return;
+ }
+ if (uninstallTombStoneFileStatus == IS_REG) {
+ handleStagedUninstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
+ } else {
+ // uninstallTombStoneFileStatus == NONE meaning this is a staged install.
+ handleStagedInstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
+ }
+}
+
/*
* After a platform update it is likely that timezone data found on the system partition will be
* newer than the version found in the data partition. This tool detects this case and removes the
@@ -300,15 +472,25 @@
const char* systemZoneInfoDir = argv[1];
const char* dataZoneInfoDir = argv[2];
- // Check the distro directory exists. If it does not, exit quickly: nothing to do.
+ std::string dataStagedDirName(dataZoneInfoDir);
+ dataStagedDirName += STAGED_DIR_NAME;
+
std::string dataCurrentDirName(dataZoneInfoDir);
- dataCurrentDirName += "/current";
- int dataCurrentDirStatus = checkPath(dataCurrentDirName);
+ dataCurrentDirName += CURRENT_DIR_NAME;
+
+ // Check for an process any staged operation.
+ // If the staged operation could not be handled we still have to validate the current installed
+ // directory so we do not check for errors and do not quit early.
+ processStagedOperation(dataStagedDirName, dataCurrentDirName);
+
+ // Check the distro directory exists. If it does not, exit quickly: nothing to do.
+ PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
if (dataCurrentDirStatus == NONE) {
LOG(INFO) << "timezone distro dir " << dataCurrentDirName
<< " does not exist. No action required.";
return 0;
}
+
// If the distro directory path is not a directory or we can't stat() the path, exit with a
// warning: either there's a problem accessing storage or the world is not as it should be;
// nothing to do.