Merge "ueventd: don't double fork firmware handlers"
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index bb26e70..b236fb3 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -157,7 +157,12 @@
}
std::string dump_hex(const void* data, size_t byte_count) {
- byte_count = std::min(byte_count, size_t(16));
+ size_t truncate_len = 16;
+ bool truncated = false;
+ if (byte_count > truncate_len) {
+ byte_count = truncate_len;
+ truncated = true;
+ }
const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
@@ -172,6 +177,10 @@
line.push_back(isprint(ch) ? ch : '.');
}
+ if (truncated) {
+ line += " [truncated]";
+ }
+
return line;
}
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 47094b8..2f46920 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -192,7 +192,7 @@
#if defined(_WIN32) || !ADB_HOST
return false;
#else
- static bool disable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "0") == 0;
- return !disable;
+ static bool enable = getenv("ADB_LIBUSB") && strcmp(getenv("ADB_LIBUSB"), "1") == 0;
+ return enable;
#endif
}
diff --git a/base/include/android-base/utf8.h b/base/include/android-base/utf8.h
index 2d5a6f6..c9cc1ab 100755
--- a/base/include/android-base/utf8.h
+++ b/base/include/android-base/utf8.h
@@ -22,6 +22,8 @@
#else
// Bring in prototypes for standard APIs so that we can import them into the utf8 namespace.
#include <fcntl.h> // open
+#include <stdio.h> // fopen
+#include <sys/stat.h> // mkdir
#include <unistd.h> // unlink
#endif
@@ -53,6 +55,19 @@
// Convert a UTF-8 std::string (including any embedded NULL characters) to
// UTF-16. Returns whether the conversion was done successfully.
bool UTF8ToWide(const std::string& utf8, std::wstring* utf16);
+
+// Convert a file system path, represented as a NULL-terminated string of
+// UTF-8 characters, to a UTF-16 string representing the same file system
+// path using the Windows extended-lengh path representation.
+//
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#MAXPATH:
+// ```The Windows API has many functions that also have Unicode versions to
+// permit an extended-length path for a maximum total path length of 32,767
+// characters. To specify an extended-length path, use the "\\?\" prefix.
+// For example, "\\?\D:\very long path".```
+//
+// Returns whether the conversion was done successfully.
+bool UTF8PathToWindowsLongPath(const char* utf8, std::wstring* utf16);
#endif
// The functions in the utf8 namespace take UTF-8 strings. For Windows, these
@@ -73,9 +88,13 @@
namespace utf8 {
#ifdef _WIN32
+FILE* fopen(const char* name, const char* mode);
+int mkdir(const char* name, mode_t mode);
int open(const char* name, int flags, ...);
int unlink(const char* name);
#else
+using ::fopen;
+using ::mkdir;
using ::open;
using ::unlink;
#endif
diff --git a/base/utf8.cpp b/base/utf8.cpp
index 3cca700..5984fb0 100644
--- a/base/utf8.cpp
+++ b/base/utf8.cpp
@@ -19,7 +19,9 @@
#include "android-base/utf8.h"
#include <fcntl.h>
+#include <stdio.h>
+#include <algorithm>
#include <string>
#include "android-base/logging.h"
@@ -153,12 +155,58 @@
return UTF8ToWide(utf8.c_str(), utf8.length(), utf16);
}
+static bool isDriveLetter(wchar_t c) {
+ return (c >= L'a' && c <= L'z') || (c >= L'A' && c <= L'Z');
+}
+
+bool UTF8PathToWindowsLongPath(const char* utf8, std::wstring* utf16) {
+ if (!UTF8ToWide(utf8, utf16)) {
+ return false;
+ }
+ // Note: Although most Win32 File I/O API are limited to MAX_PATH (260
+ // characters), the CreateDirectory API is limited to 248 characters.
+ if (utf16->length() >= 248) {
+ // If path is of the form "x:\" or "x:/"
+ if (isDriveLetter((*utf16)[0]) && (*utf16)[1] == L':' &&
+ ((*utf16)[2] == L'\\' || (*utf16)[2] == L'/')) {
+ // Append long path prefix, and make sure there are no unix-style
+ // separators to ensure a fully compliant Win32 long path string.
+ utf16->insert(0, LR"(\\?\)");
+ std::replace(utf16->begin(), utf16->end(), L'/', L'\\');
+ }
+ }
+ return true;
+}
+
// Versions of standard library APIs that support UTF-8 strings.
namespace utf8 {
+FILE* fopen(const char* name, const char* mode) {
+ std::wstring name_utf16;
+ if (!UTF8PathToWindowsLongPath(name, &name_utf16)) {
+ return nullptr;
+ }
+
+ std::wstring mode_utf16;
+ if (!UTF8ToWide(mode, &mode_utf16)) {
+ return nullptr;
+ }
+
+ return _wfopen(name_utf16.c_str(), mode_utf16.c_str());
+}
+
+int mkdir(const char* name, mode_t mode) {
+ std::wstring name_utf16;
+ if (!UTF8PathToWindowsLongPath(name, &name_utf16)) {
+ return -1;
+ }
+
+ return _wmkdir(name_utf16.c_str());
+}
+
int open(const char* name, int flags, ...) {
std::wstring name_utf16;
- if (!UTF8ToWide(name, &name_utf16)) {
+ if (!UTF8PathToWindowsLongPath(name, &name_utf16)) {
return -1;
}
@@ -175,7 +223,7 @@
int unlink(const char* name) {
std::wstring name_utf16;
- if (!UTF8ToWide(name, &name_utf16)) {
+ if (!UTF8PathToWindowsLongPath(name, &name_utf16)) {
return -1;
}
diff --git a/base/utf8_test.cpp b/base/utf8_test.cpp
index ae8fc8c..fcb25c3 100644
--- a/base/utf8_test.cpp
+++ b/base/utf8_test.cpp
@@ -18,7 +18,12 @@
#include <gtest/gtest.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
#include "android-base/macros.h"
+#include "android-base/test_utils.h"
+#include "android-base/unique_fd.h"
namespace android {
namespace base {
@@ -408,5 +413,76 @@
EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null));
}
+TEST(UTF8PathToWindowsLongPathTest, DontAddPrefixIfShorterThanMaxPath) {
+ std::string utf8 = "c:\\mypath\\myfile.txt";
+
+ std::wstring wide;
+ EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide));
+
+ EXPECT_EQ(std::string::npos, wide.find(LR"(\\?\)"));
+}
+
+TEST(UTF8PathToWindowsLongPathTest, AddPrefixIfLongerThanMaxPath) {
+ std::string utf8 = "c:\\mypath";
+ while (utf8.length() < 300 /* MAX_PATH is 260 */) {
+ utf8 += "\\mypathsegment";
+ }
+
+ std::wstring wide;
+ EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide));
+
+ EXPECT_EQ(0U, wide.find(LR"(\\?\)"));
+ EXPECT_EQ(std::string::npos, wide.find(L"/"));
+}
+
+TEST(UTF8PathToWindowsLongPathTest, AddPrefixAndFixSeparatorsIfLongerThanMaxPath) {
+ std::string utf8 = "c:/mypath";
+ while (utf8.length() < 300 /* MAX_PATH is 260 */) {
+ utf8 += "/mypathsegment";
+ }
+
+ std::wstring wide;
+ EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide));
+
+ EXPECT_EQ(0U, wide.find(LR"(\\?\)"));
+ EXPECT_EQ(std::string::npos, wide.find(L"/"));
+}
+
+namespace utf8 {
+
+TEST(Utf8FilesTest, CanCreateOpenAndDeleteFileWithLongPath) {
+ TemporaryDir td;
+
+ // Create long directory path
+ std::string utf8 = td.path;
+ while (utf8.length() < 300 /* MAX_PATH is 260 */) {
+ utf8 += "\\mypathsegment";
+ EXPECT_EQ(0, mkdir(utf8.c_str(), 0));
+ }
+
+ // Create file
+ utf8 += "\\test-file.bin";
+ int flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
+ int mode = 0666;
+ android::base::unique_fd fd(open(utf8.c_str(), flags, mode));
+ EXPECT_NE(-1, fd.get());
+
+ // Close file
+ fd.reset();
+ EXPECT_EQ(-1, fd.get());
+
+ // Open file with fopen
+ FILE* file = fopen(utf8.c_str(), "rb");
+ EXPECT_NE(nullptr, file);
+
+ if (file) {
+ fclose(file);
+ }
+
+ // Delete file
+ EXPECT_EQ(0, unlink(utf8.c_str()));
+}
+
+} // namespace utf8
} // namespace base
} // namespace android
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 5565cfd..f86aaa0 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -274,7 +274,7 @@
"libbase",
"libdebuggerd_client",
"liblog",
- "libselinux",
+ "libprocinfo",
],
local_include_dirs: ["include"],
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 6298ace..b016e23 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -27,7 +27,7 @@
#include <android-base/parseint.h>
#include <android-base/unique_fd.h>
#include <debuggerd/client.h>
-#include <selinux/selinux.h>
+#include <procinfo/process.h>
#include "util.h"
using android::base::unique_fd;
@@ -66,6 +66,24 @@
usage(1);
}
+ if (getuid() != 0) {
+ errx(1, "root is required");
+ }
+
+ // Check to see if the process exists and that we can actually send a signal to it.
+ android::procinfo::ProcessInfo proc_info;
+ if (!android::procinfo::GetProcessInfo(pid, &proc_info)) {
+ err(1, "failed to fetch info for process %d", pid);
+ }
+
+ if (proc_info.state == android::procinfo::kProcessStateZombie) {
+ errx(1, "process %d is a zombie", pid);
+ }
+
+ if (kill(pid, 0) != 0) {
+ err(1, "cannot send signal to process %d", pid);
+ }
+
unique_fd piperead, pipewrite;
if (!Pipe(&piperead, &pipewrite)) {
err(1, "failed to create pipe");
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 7685476..93c7fb5 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -32,6 +32,7 @@
#include <event2/thread.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
@@ -43,6 +44,7 @@
#include "intercept_manager.h"
+using android::base::GetIntProperty;
using android::base::StringPrintf;
using android::base::unique_fd;
@@ -53,7 +55,19 @@
kCrashStatusQueued,
};
-struct Crash;
+// Ownership of Crash is a bit messy.
+// It's either owned by an active event that must have a timeout, or owned by
+// queued_requests, in the case that multiple crashes come in at the same time.
+struct Crash {
+ ~Crash() { event_free(crash_event); }
+
+ unique_fd crash_fd;
+ pid_t crash_pid;
+ event* crash_event = nullptr;
+ std::string crash_path;
+
+ DebuggerdDumpType crash_type;
+};
class CrashQueue {
public:
@@ -77,6 +91,24 @@
find_oldest_artifact();
}
+ static CrashQueue* for_crash(const Crash* crash) {
+ return (crash->crash_type == kDebuggerdJavaBacktrace) ? for_anrs() : for_tombstones();
+ }
+
+ static CrashQueue* for_tombstones() {
+ static CrashQueue queue("/data/tombstones", "tombstone_" /* file_name_prefix */,
+ GetIntProperty("tombstoned.max_tombstone_count", 10),
+ 1 /* max_concurrent_dumps */);
+ return &queue;
+ }
+
+ static CrashQueue* for_anrs() {
+ static CrashQueue queue("/data/anr", "trace_" /* file_name_prefix */,
+ GetIntProperty("tombstoned.max_anr_count", 64),
+ 4 /* max_concurrent_dumps */);
+ return &queue;
+ }
+
std::pair<unique_fd, std::string> get_output() {
unique_fd result;
std::string file_name = StringPrintf("%s%02d", file_name_prefix_.c_str(), next_artifact_);
@@ -118,9 +150,6 @@
void on_crash_completed() { --num_concurrent_dumps_; }
- static CrashQueue* const tombstone;
- static CrashQueue* const java_trace;
-
private:
void find_oldest_artifact() {
size_t oldest_tombstone = 0;
@@ -167,37 +196,6 @@
// Whether java trace dumps are produced via tombstoned.
static constexpr bool kJavaTraceDumpsEnabled = true;
-/* static */ CrashQueue* const CrashQueue::tombstone =
- new CrashQueue("/data/tombstones", "tombstone_" /* file_name_prefix */, 10 /* max_artifacts */,
- 1 /* max_concurrent_dumps */);
-
-/* static */ CrashQueue* const CrashQueue::java_trace =
- (kJavaTraceDumpsEnabled ? new CrashQueue("/data/anr", "trace_" /* file_name_prefix */,
- 64 /* max_artifacts */, 4 /* max_concurrent_dumps */)
- : nullptr);
-
-// Ownership of Crash is a bit messy.
-// It's either owned by an active event that must have a timeout, or owned by
-// queued_requests, in the case that multiple crashes come in at the same time.
-struct Crash {
- ~Crash() { event_free(crash_event); }
-
- unique_fd crash_fd;
- pid_t crash_pid;
- event* crash_event = nullptr;
- std::string crash_path;
-
- DebuggerdDumpType crash_type;
-};
-
-static CrashQueue* get_crash_queue(const Crash* crash) {
- if (crash->crash_type == kDebuggerdJavaBacktrace) {
- return CrashQueue::java_trace;
- }
-
- return CrashQueue::tombstone;
-}
-
// Forward declare the callbacks so they can be placed in a sensible order.
static void crash_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int, void*);
static void crash_request_cb(evutil_socket_t sockfd, short ev, void* arg);
@@ -206,7 +204,7 @@
static void perform_request(Crash* crash) {
unique_fd output_fd;
if (!intercept_manager->GetIntercept(crash->crash_pid, crash->crash_type, &output_fd)) {
- std::tie(output_fd, crash->crash_path) = get_crash_queue(crash)->get_output();
+ std::tie(output_fd, crash->crash_path) = CrashQueue::for_crash(crash)->get_output();
}
TombstonedCrashPacket response = {
@@ -229,7 +227,7 @@
event_add(crash->crash_event, &timeout);
}
- get_crash_queue(crash)->on_crash_started();
+ CrashQueue::for_crash(crash)->on_crash_started();
return;
fail:
@@ -305,7 +303,7 @@
LOG(INFO) << "received crash request for pid " << crash->crash_pid;
- if (get_crash_queue(crash)->maybe_enqueue_crash(crash)) {
+ if (CrashQueue::for_crash(crash)->maybe_enqueue_crash(crash)) {
LOG(INFO) << "enqueueing crash request for pid " << crash->crash_pid;
} else {
perform_request(crash);
@@ -322,7 +320,7 @@
Crash* crash = static_cast<Crash*>(arg);
TombstonedCrashPacket request = {};
- get_crash_queue(crash)->on_crash_completed();
+ CrashQueue::for_crash(crash)->on_crash_completed();
if ((ev & EV_READ) == 0) {
goto fail;
@@ -356,7 +354,7 @@
}
fail:
- CrashQueue* queue = get_crash_queue(crash);
+ CrashQueue* queue = CrashQueue::for_crash(crash);
delete crash;
// If there's something queued up, let them proceed.
@@ -392,7 +390,7 @@
intercept_manager = new InterceptManager(base, intercept_socket);
evconnlistener* tombstone_listener = evconnlistener_new(
- base, crash_accept_cb, CrashQueue::tombstone, -1, LEV_OPT_CLOSE_ON_FREE, crash_socket);
+ base, crash_accept_cb, CrashQueue::for_tombstones(), -1, LEV_OPT_CLOSE_ON_FREE, crash_socket);
if (!tombstone_listener) {
LOG(FATAL) << "failed to create evconnlistener for tombstones.";
}
@@ -405,7 +403,7 @@
evutil_make_socket_nonblocking(java_trace_socket);
evconnlistener* java_trace_listener = evconnlistener_new(
- base, crash_accept_cb, CrashQueue::java_trace, -1, LEV_OPT_CLOSE_ON_FREE, java_trace_socket);
+ base, crash_accept_cb, CrashQueue::for_anrs(), -1, LEV_OPT_CLOSE_ON_FREE, java_trace_socket);
if (!java_trace_listener) {
LOG(FATAL) << "failed to create evconnlistener for java traces.";
}
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 0af6159..608917a 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -21,18 +21,6 @@
},
local_include_dirs: ["include/"],
cppflags: ["-Werror"],
- static_libs: [
- "liblogwrap",
- "libfec",
- "libfec_rs",
- "libbase",
- "libcrypto_utils",
- "libcrypto",
- "libext4_utils",
- "libsquashfs_utils",
- "libselinux",
- "libavb",
- ],
}
cc_library_static {
@@ -44,12 +32,28 @@
"fs_mgr.cpp",
"fs_mgr_dm_ioctl.cpp",
"fs_mgr_format.cpp",
- "fs_mgr_fstab.cpp",
- "fs_mgr_slotselect.cpp",
"fs_mgr_verity.cpp",
"fs_mgr_avb.cpp",
"fs_mgr_avb_ops.cpp",
- "fs_mgr_boot_config.cpp",
+ ],
+ static_libs: [
+ "liblogwrap",
+ "libfec",
+ "libfec_rs",
+ "libbase",
+ "libcrypto_utils",
+ "libcrypto",
+ "libext4_utils",
+ "libsquashfs_utils",
+ "libselinux",
+ "libavb",
+ "libfstab",
+ ],
+ export_static_lib_headers: [
+ "libfstab",
+ ],
+ whole_static_libs: [
+ "libfstab",
],
product_variables: {
debuggable: {
@@ -60,3 +64,16 @@
},
},
}
+
+cc_library_static {
+ name: "libfstab",
+ vendor_available: true,
+ defaults: ["fs_mgr_defaults"],
+ srcs: [
+ "fs_mgr_fstab.cpp",
+ "fs_mgr_boot_config.cpp",
+ "fs_mgr_slotselect.cpp",
+ ],
+ export_include_dirs: ["include_fstab"],
+ header_libs: ["libbase_headers"],
+}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 8c19a81..340cd1e 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -457,6 +457,16 @@
return rc;
}
+// Orange state means the device is unlocked, see the following link for details.
+// https://source.android.com/security/verifiedboot/verified-boot#device_state
+bool fs_mgr_is_device_unlocked() {
+ std::string verified_boot_state;
+ if (fs_mgr_get_boot_config("verifiedbootstate", &verified_boot_state)) {
+ return verified_boot_state == "orange";
+ }
+ return false;
+}
+
/*
* __mount(): wrapper around the mount() system call which also
* sets the underlying block device to read-only if the mount is read-only.
@@ -476,10 +486,11 @@
if ((info.st_mode & S_IFMT) == S_IFLNK)
unlink(target);
mkdir(target, 0755);
+ errno = 0;
ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
save_errno = errno;
- LINFO << __FUNCTION__ << "(source=" << source << ",target="
- << target << ",type=" << rec->fs_type << ")=" << ret;
+ PINFO << __FUNCTION__ << "(source=" << source << ",target=" << target
+ << ",type=" << rec->fs_type << ")=" << ret;
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
fs_mgr_set_blk_ro(source);
}
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 2c99aa7..e939dbe 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -473,16 +473,6 @@
return true;
}
-// Orange state means the device is unlocked, see the following link for details.
-// https://source.android.com/security/verifiedboot/verified-boot#device_state
-static inline bool IsDeviceUnlocked() {
- std::string verified_boot_state;
- if (fs_mgr_get_boot_config("verifiedbootstate", &verified_boot_state)) {
- return verified_boot_state == "orange";
- }
- return false;
-}
-
FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const fstab& fstab) {
FsManagerAvbOps avb_ops(fstab);
return DoOpen(&avb_ops);
@@ -498,7 +488,7 @@
}
FsManagerAvbUniquePtr FsManagerAvbHandle::DoOpen(FsManagerAvbOps* avb_ops) {
- bool is_device_unlocked = IsDeviceUnlocked();
+ bool is_device_unlocked = fs_mgr_is_device_unlocked();
FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
if (!avb_handle) {
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index c985462..5035c87 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -113,6 +113,7 @@
int fs_mgr_set_blk_ro(const char *blockdev);
int fs_mgr_test_access(const char *device);
bool fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool fs_mgr_is_device_unlocked();
bool is_dt_compatible();
bool is_device_secure();
int load_verity_state(struct fstab_rec* fstab, int* mode);
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 1d832b3..f997323 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -348,10 +348,13 @@
static int was_verity_restart()
{
- static const char *files[] = {
+ static const char* files[] = {
+ // clang-format off
+ "/sys/fs/pstore/console-ramoops-0",
"/sys/fs/pstore/console-ramoops",
"/proc/last_kmsg",
NULL
+ // clang-format on
};
int i;
@@ -779,8 +782,8 @@
if (fec_verity_get_metadata(f, &verity) < 0) {
PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
// Allow verity disabled when the device is unlocked without metadata
- if ("0" == android::base::GetProperty("ro.boot.flash.locked", "")) {
- retval = FS_MGR_SETUP_VERITY_DISABLED;
+ if (fs_mgr_is_device_unlocked()) {
+ retval = FS_MGR_SETUP_VERITY_SKIPPED;
LWARNING << "Allow invalid metadata when the device is unlocked";
}
goto out;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 047fd54..3d3faf3 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -22,11 +22,7 @@
#include <stdbool.h>
#include <linux/dm-ioctl.h>
-// C++ only headers
-// TODO: move this into separate header files under include/fs_mgr/*.h
-#ifdef __cplusplus
-#include <string>
-#endif
+#include <fstab/fstab.h>
// Magic number at start of verity metadata
#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
@@ -53,47 +49,10 @@
MOUNT_MODE_LATE = 2
};
-/*
- * The entries must be kept in the same order as they were seen in the fstab.
- * Unless explicitly requested, a lookup on mount point should always
- * return the 1st one.
- */
-struct fstab {
- int num_entries;
- struct fstab_rec *recs;
- char *fstab_filename;
-};
-
-struct fstab_rec {
- char *blk_device;
- char *mount_point;
- char *fs_type;
- unsigned long flags;
- char *fs_options;
- int fs_mgr_flags;
- char *key_loc;
- char *verity_loc;
- long long length;
- char *label;
- int partnum;
- int swap_prio;
- int max_comp_streams;
- unsigned int zram_size;
- uint64_t reserved_size;
- unsigned int file_encryption_mode;
- unsigned int erase_blk_size;
- unsigned int logical_blk_size;
-};
-
// Callback function for verity status
typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
const char *mount_point, int mode, int status);
-struct fstab *fs_mgr_read_fstab_default();
-struct fstab *fs_mgr_read_fstab_dt();
-struct fstab *fs_mgr_read_fstab(const char *fstab_path);
-void fs_mgr_free_fstab(struct fstab *fstab);
-
#define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 3
@@ -116,26 +75,6 @@
char *real_blk_device, int size);
bool fs_mgr_load_verity_state(int* mode);
bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
-int fs_mgr_add_entry(struct fstab *fstab,
- const char *mount_point, const char *fs_type,
- const char *blk_device);
-struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path);
-int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab);
-int fs_mgr_is_nonremovable(const struct fstab_rec *fstab);
-int fs_mgr_is_verified(const struct fstab_rec *fstab);
-int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab);
-int fs_mgr_is_avb(const struct fstab_rec *fstab);
-int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
-int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
-const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab);
-int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab);
-int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
-int fs_mgr_is_notrim(struct fstab_rec *fstab);
-int fs_mgr_is_formattable(struct fstab_rec *fstab);
-int fs_mgr_is_slotselect(struct fstab_rec *fstab);
-int fs_mgr_is_nofail(struct fstab_rec *fstab);
-int fs_mgr_is_latemount(struct fstab_rec *fstab);
-int fs_mgr_is_quota(struct fstab_rec *fstab);
int fs_mgr_swapon_all(struct fstab *fstab);
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
@@ -148,10 +87,4 @@
__END_DECLS
-// C++ only functions
-// TODO: move this into separate header files under include/fs_mgr/*.h
-#ifdef __cplusplus
-std::string fs_mgr_get_slot_suffix();
-#endif
-
#endif /* __CORE_FS_MGR_H */
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
new file mode 100644
index 0000000..3ea4e03
--- /dev/null
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2012 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_TAB_H
+#define __CORE_FS_TAB_H
+
+#include <linux/dm-ioctl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+// C++ only headers
+// TODO: move this into separate header files under include/fs_mgr/*.h
+#ifdef __cplusplus
+#include <string>
+#endif
+
+__BEGIN_DECLS
+
+/*
+ * The entries must be kept in the same order as they were seen in the fstab.
+ * Unless explicitly requested, a lookup on mount point should always
+ * return the 1st one.
+ */
+struct fstab {
+ int num_entries;
+ struct fstab_rec* recs;
+ char* fstab_filename;
+};
+
+struct fstab_rec {
+ char* blk_device;
+ char* mount_point;
+ char* fs_type;
+ unsigned long flags;
+ char* fs_options;
+ int fs_mgr_flags;
+ char* key_loc;
+ char* verity_loc;
+ long long length;
+ char* label;
+ int partnum;
+ int swap_prio;
+ int max_comp_streams;
+ unsigned int zram_size;
+ uint64_t reserved_size;
+ unsigned int file_encryption_mode;
+ unsigned int erase_blk_size;
+ unsigned int logical_blk_size;
+};
+
+struct fstab* fs_mgr_read_fstab_default();
+struct fstab* fs_mgr_read_fstab_dt();
+struct fstab* fs_mgr_read_fstab(const char* fstab_path);
+void fs_mgr_free_fstab(struct fstab* fstab);
+
+int fs_mgr_add_entry(struct fstab* fstab, const char* mount_point, const char* fs_type,
+ const char* blk_device);
+struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const char* path);
+int fs_mgr_is_voldmanaged(const struct fstab_rec* fstab);
+int fs_mgr_is_nonremovable(const struct fstab_rec* fstab);
+int fs_mgr_is_verified(const struct fstab_rec* fstab);
+int fs_mgr_is_verifyatboot(const struct fstab_rec* fstab);
+int fs_mgr_is_avb(const struct fstab_rec* fstab);
+int fs_mgr_is_encryptable(const struct fstab_rec* fstab);
+int fs_mgr_is_file_encrypted(const struct fstab_rec* fstab);
+const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec* fstab);
+int fs_mgr_is_convertible_to_fbe(const struct fstab_rec* fstab);
+int fs_mgr_is_noemulatedsd(const struct fstab_rec* fstab);
+int fs_mgr_is_notrim(struct fstab_rec* fstab);
+int fs_mgr_is_formattable(struct fstab_rec* fstab);
+int fs_mgr_is_slotselect(struct fstab_rec* fstab);
+int fs_mgr_is_nofail(struct fstab_rec* fstab);
+int fs_mgr_is_latemount(struct fstab_rec* fstab);
+int fs_mgr_is_quota(struct fstab_rec* fstab);
+
+__END_DECLS
+
+// C++ only functions
+// TODO: move this into separate header files under include/fs_mgr/*.h
+#ifdef __cplusplus
+std::string fs_mgr_get_slot_suffix();
+#endif
+
+#endif /* __CORE_FS_TAB_H */
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
index 523e1f1..e51a06d 100644
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ b/healthd/BatteryPropertiesRegistrar.cpp
@@ -36,9 +36,19 @@
}
void BatteryPropertiesRegistrar::notifyListeners(const struct BatteryProperties& props) {
- Mutex::Autolock _l(mRegistrationLock);
- for (size_t i = 0; i < mListeners.size(); i++) {
- mListeners[i]->batteryPropertiesChanged(props);
+ Vector<sp<IBatteryPropertiesListener> > listenersCopy;
+
+ // Binder currently may service an incoming oneway transaction whenever an
+ // outbound oneway call is made (if there is already a pending incoming
+ // oneway call waiting). This is considered a bug and may change in the
+ // future. For now, avoid recursive mutex lock while making outbound
+ // calls by making a local copy of the current list of listeners.
+ {
+ Mutex::Autolock _l(mRegistrationLock);
+ listenersCopy = mListeners;
+ }
+ for (size_t i = 0; i < listenersCopy.size(); i++) {
+ listenersCopy[i]->batteryPropertiesChanged(props);
}
}
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 91774c6..d7d1454 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -33,6 +33,7 @@
#include <functional>
#include <android-base/file.h>
+#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <sys/socket.h>
@@ -76,8 +77,6 @@
#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
-#define LAST_KMSG_PATH "/proc/last_kmsg"
-#define LAST_KMSG_PSTORE_PATH "/sys/fs/pstore/console-ramoops"
#define LAST_KMSG_MAX_SZ (32 * 1024)
#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
@@ -217,14 +216,21 @@
LOGW("\n");
LOGW("*************** LAST KMSG ***************\n");
LOGW("\n");
- buf = (char *)load_file(LAST_KMSG_PSTORE_PATH, &sz);
+ const char* kmsg[] = {
+ // clang-format off
+ "/sys/fs/pstore/console-ramoops-0",
+ "/sys/fs/pstore/console-ramoops",
+ "/proc/last_kmsg",
+ // clang-format on
+ };
+ for (size_t i = 0; i < arraysize(kmsg); ++i) {
+ buf = (char*)load_file(kmsg[i], &sz);
+ if (buf && sz) break;
+ }
if (!buf || !sz) {
- buf = (char *)load_file(LAST_KMSG_PATH, &sz);
- if (!buf || !sz) {
- LOGW("last_kmsg not found. Cold reset?\n");
- goto out;
- }
+ LOGW("last_kmsg not found. Cold reset?\n");
+ goto out;
}
len = min(sz, LAST_KMSG_MAX_SZ);
diff --git a/include/ziparchive b/include/ziparchive
new file mode 120000
index 0000000..d8fa424
--- /dev/null
+++ b/include/ziparchive
@@ -0,0 +1 @@
+../libziparchive/include/ziparchive
\ No newline at end of file
diff --git a/init/README.md b/init/README.md
index 72b6c6b..422fdad 100644
--- a/init/README.md
+++ b/init/README.md
@@ -260,6 +260,14 @@
> Sets the child's /proc/self/oom\_score\_adj to the specified value,
which must range from -1000 to 1000.
+`shutdown <shutdown_behavior>`
+> Set shutdown behavior of the service process. When this is not specified,
+ the service is killed during shutdown process by using SIGTERM and SIGKILL.
+ The service with shutdown_behavior of "critical" is not killed during shutdown
+ until shutdown times out. When shutdown times out, even services tagged with
+ "shutdown critical" will be killed. When the service tagged with "shutdown critical"
+ is not running when shut down starts, it will be started.
+
Triggers
--------
diff --git a/init/action.cpp b/init/action.cpp
index 6900391..4a3ab48 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -326,6 +326,13 @@
}
}
+void ActionManager::ClearQueue() {
+ // We are shutting down so don't claim the oneshot builtin actions back
+ current_executing_actions_ = {};
+ event_queue_ = {};
+ current_command_ = 0;
+}
+
bool ActionParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line, std::string* err) {
std::vector<std::string> triggers(args.begin() + 1, args.end());
diff --git a/init/action.h b/init/action.h
index 5cb50a7..ad15f3f 100644
--- a/init/action.h
+++ b/init/action.h
@@ -104,6 +104,7 @@
void ExecuteOneCommand();
bool HasMoreCommands() const;
void DumpState() const;
+ void ClearQueue();
private:
ActionManager(ActionManager const&) = delete;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 00ffbc3..75a8f19 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -119,7 +119,7 @@
LOG(ERROR) << "failed to set bootloader message: " << err;
return -1;
}
- DoReboot(ANDROID_RB_RESTART2, "reboot", "recovery", false);
+ property_set("sys.powerctl", "reboot,recovery");
return 0;
}
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
index 53832a4..642a364 100644
--- a/init/capabilities.cpp
+++ b/init/capabilities.cpp
@@ -107,17 +107,15 @@
}
static bool SetProcCaps(const CapSet& to_keep, bool add_setpcap) {
- cap_t caps = cap_init();
- auto deleter = [](cap_t* p) { cap_free(*p); };
- std::unique_ptr<cap_t, decltype(deleter)> ptr_caps(&caps, deleter);
+ ScopedCaps caps(cap_init());
- cap_clear(caps);
+ cap_clear(caps.get());
cap_value_t value[1];
for (size_t cap = 0; cap < to_keep.size(); ++cap) {
if (to_keep.test(cap)) {
value[0] = cap;
- if (cap_set_flag(caps, CAP_INHERITABLE, arraysize(value), value, CAP_SET) != 0 ||
- cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0) {
+ if (cap_set_flag(caps.get(), CAP_INHERITABLE, arraysize(value), value, CAP_SET) != 0 ||
+ cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0) {
PLOG(ERROR) << "cap_set_flag(INHERITABLE|PERMITTED, " << cap << ") failed";
return false;
}
@@ -126,14 +124,14 @@
if (add_setpcap) {
value[0] = CAP_SETPCAP;
- if (cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0 ||
- cap_set_flag(caps, CAP_EFFECTIVE, arraysize(value), value, CAP_SET) != 0) {
+ if (cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0 ||
+ cap_set_flag(caps.get(), CAP_EFFECTIVE, arraysize(value), value, CAP_SET) != 0) {
PLOG(ERROR) << "cap_set_flag(PERMITTED|EFFECTIVE, " << CAP_SETPCAP << ") failed";
return false;
}
}
- if (cap_set_proc(caps) != 0) {
+ if (cap_set_proc(caps.get()) != 0) {
PLOG(ERROR) << "cap_set_proc(" << to_keep.to_ulong() << ") failed";
return false;
}
diff --git a/init/capabilities.h b/init/capabilities.h
index ef507a6..ede85c3 100644
--- a/init/capabilities.h
+++ b/init/capabilities.h
@@ -15,15 +15,21 @@
#ifndef _INIT_CAPABILITIES_H
#define _INIT_CAPABILITIES_H
-#include <linux/capability.h>
+#include <sys/capability.h>
#include <bitset>
#include <string>
+#include <type_traits>
namespace android {
namespace init {
+struct CapDeleter {
+ void operator()(cap_t caps) const { cap_free(caps); }
+};
+
using CapSet = std::bitset<CAP_LAST_CAP + 1>;
+using ScopedCaps = std::unique_ptr<std::remove_pointer<cap_t>::type, CapDeleter>;
int LookupCap(const std::string& cap_name);
bool CapAmbientSupported();
diff --git a/init/devices.cpp b/init/devices.cpp
index 215d2ea..13cf991 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -219,7 +219,7 @@
return {0600, 0, 0};
}
-void DeviceHandler::MakeDevice(const std::string& path, int block, int major, int minor,
+void DeviceHandler::MakeDevice(const std::string& path, bool block, int major, int minor,
const std::vector<std::string>& links) const {
auto[mode, uid, gid] = GetDevicePermissions(path, links);
mode |= (block ? S_IFBLK : S_IFCHR);
@@ -279,45 +279,6 @@
}
}
-std::vector<std::string> DeviceHandler::GetCharacterDeviceSymlinks(const Uevent& uevent) const {
- std::string parent_device;
- if (!FindPlatformDevice(uevent.path, &parent_device)) return {};
-
- // skip path to the parent driver
- std::string path = uevent.path.substr(parent_device.length());
-
- if (!StartsWith(path, "/usb")) return {};
-
- // skip root hub name and device. use device interface
- // skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
- // then extract what comes between the 3rd and 4th slash
- // e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
-
- std::string::size_type start = 0;
- start = path.find('/', start + 1);
- if (start == std::string::npos) return {};
-
- start = path.find('/', start + 1);
- if (start == std::string::npos) return {};
-
- auto end = path.find('/', start + 1);
- if (end == std::string::npos) return {};
-
- start++; // Skip the first '/'
-
- auto length = end - start;
- if (length == 0) return {};
-
- auto name_string = path.substr(start, length);
-
- std::vector<std::string> links;
- links.emplace_back("/dev/usb/" + uevent.subsystem + name_string);
-
- mkdir("/dev/usb", 0755);
-
- return links;
-}
-
// replaces any unacceptable characters with '_', the
// length of the resulting string is equal to the input string
void SanitizePartitionName(std::string* string) {
@@ -385,7 +346,7 @@
return links;
}
-void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, int block,
+void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, bool block,
int major, int minor, const std::vector<std::string>& links) const {
if (action == "add") {
MakeDevice(devpath, block, major, minor, links);
@@ -411,31 +372,26 @@
}
}
-void DeviceHandler::HandleBlockDeviceEvent(const Uevent& uevent) const {
- // if it's not a /dev device, nothing to do
- if (uevent.major < 0 || uevent.minor < 0) return;
-
- const char* base = "/dev/block/";
- make_dir(base, 0755, sehandle_);
-
- std::string name = Basename(uevent.path);
- std::string devpath = base + name;
-
- std::vector<std::string> links;
- if (StartsWith(uevent.path, "/devices")) {
- links = GetBlockDeviceSymlinks(uevent);
+void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
+ if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
+ FixupSysPermissions(uevent.path, uevent.subsystem);
}
- HandleDevice(uevent.action, devpath, 1, uevent.major, uevent.minor, links);
-}
-
-void DeviceHandler::HandleGenericDeviceEvent(const Uevent& uevent) const {
// if it's not a /dev device, nothing to do
if (uevent.major < 0 || uevent.minor < 0) return;
std::string devpath;
+ std::vector<std::string> links;
+ bool block = false;
- if (StartsWith(uevent.subsystem, "usb")) {
+ if (uevent.subsystem == "block") {
+ block = true;
+ devpath = "/dev/block/" + Basename(uevent.path);
+
+ if (StartsWith(uevent.path, "/devices")) {
+ links = GetBlockDeviceSymlinks(uevent);
+ }
+ } else if (StartsWith(uevent.subsystem, "usb")) {
if (uevent.subsystem == "usb") {
if (!uevent.device_name.empty()) {
devpath = "/dev/" + uevent.device_name;
@@ -461,21 +417,7 @@
mkdir_recursive(Dirname(devpath), 0755, sehandle_);
- auto links = GetCharacterDeviceSymlinks(uevent);
-
- HandleDevice(uevent.action, devpath, 0, uevent.major, uevent.minor, links);
-}
-
-void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
- if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
- FixupSysPermissions(uevent.path, uevent.subsystem);
- }
-
- if (uevent.subsystem == "block") {
- HandleBlockDeviceEvent(uevent);
- } else {
- HandleGenericDeviceEvent(uevent);
- }
+ HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
}
DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
diff --git a/init/devices.h b/init/devices.h
index 5105ad7..c64f5fb 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -115,16 +115,12 @@
bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
const std::string& path, const std::vector<std::string>& links) const;
- void MakeDevice(const std::string& path, int block, int major, int minor,
+ void MakeDevice(const std::string& path, bool block, int major, int minor,
const std::vector<std::string>& links) const;
- std::vector<std::string> GetCharacterDeviceSymlinks(const Uevent& uevent) const;
- void HandleDevice(const std::string& action, const std::string& devpath, int block, int major,
+ void HandleDevice(const std::string& action, const std::string& devpath, bool block, int major,
int minor, const std::vector<std::string>& links) const;
void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
- void HandleBlockDeviceEvent(const Uevent& uevent) const;
- void HandleGenericDeviceEvent(const Uevent& uevent) const;
-
std::vector<Permissions> dev_permissions_;
std::vector<SysfsPermissions> sysfs_permissions_;
std::vector<Subsystem> subsystems_;
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index 57d8e0f..ac4ab9b 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -30,7 +30,7 @@
class DeviceHandlerTester {
public:
void TestGetSymlinks(const std::string& platform_device, const Uevent& uevent,
- const std::vector<std::string> expected_links, bool block) {
+ const std::vector<std::string> expected_links) {
TemporaryDir fake_sys_root;
device_handler_.sysfs_mount_point_ = fake_sys_root.path;
@@ -44,11 +44,7 @@
mkdir_recursive(android::base::Dirname(fake_sys_root.path + uevent.path), 0777, nullptr);
std::vector<std::string> result;
- if (block) {
- result = device_handler_.GetBlockDeviceSymlinks(uevent);
- } else {
- result = device_handler_.GetCharacterDeviceSymlinks(uevent);
- }
+ result = device_handler_.GetBlockDeviceSymlinks(uevent);
auto expected_size = expected_links.size();
ASSERT_EQ(expected_size, result.size());
@@ -64,95 +60,6 @@
DeviceHandler device_handler_;
};
-TEST(device_handler, get_character_device_symlinks_success) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/usb/usb_device/name/tty2-1:1.0",
- .subsystem = "tty",
- };
- std::vector<std::string> expected_result{"/dev/usb/ttyname"};
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_pdev_match) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/device/name/tty2-1:1.0", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_nothing_after_platform_device) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_usb_found) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/bad/bad/", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_roothub) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/usb/", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_usb_device) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/usb/usb_device/", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_final_slash) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/usb/usb_device/name", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
-TEST(device_handler, get_character_device_symlinks_no_final_name) {
- const char* platform_device = "/devices/platform/some_device_name";
- Uevent uevent = {
- .path = "/devices/platform/some_device_name/usb/usb_device//", .subsystem = "tty",
- };
- std::vector<std::string> expected_result;
-
- DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, false);
-}
-
TEST(device_handler, get_block_device_symlinks_success_platform) {
// These are actual paths from bullhead
const char* platform_device = "/devices/soc.0/f9824900.sdhci";
@@ -164,7 +71,7 @@
std::vector<std::string> expected_result{"/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0"};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_success_platform_with_partition) {
@@ -182,7 +89,7 @@
};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_success_platform_with_partition_only_num) {
@@ -198,7 +105,7 @@
};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_success_platform_with_partition_only_name) {
@@ -214,7 +121,7 @@
};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_success_pci) {
@@ -225,7 +132,7 @@
std::vector<std::string> expected_result{"/dev/block/pci/pci0000:00/0000:00:1f.2/mmcblk0"};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_pci_bad_format) {
@@ -236,7 +143,7 @@
std::vector<std::string> expected_result{};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_success_vbd) {
@@ -247,7 +154,7 @@
std::vector<std::string> expected_result{"/dev/block/vbd/1234/mmcblk0"};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_vbd_bad_format) {
@@ -258,7 +165,7 @@
std::vector<std::string> expected_result{};
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, get_block_device_symlinks_no_matches) {
@@ -271,7 +178,7 @@
std::vector<std::string> expected_result;
DeviceHandlerTester device_handler_tester_;
- device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result, true);
+ device_handler_tester_.TestGetSymlinks(platform_device, uevent, expected_result);
}
TEST(device_handler, sanitize_null) {
diff --git a/init/init.cpp b/init/init.cpp
index 0562dad..d23e1a3 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -94,6 +94,7 @@
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
static std::string wait_prop_name;
static std::string wait_prop_value;
+static bool shutting_down;
void DumpState() {
ServiceManager::GetInstance().DumpState();
@@ -158,21 +159,31 @@
return true;
}
+void ResetWaitForProp() {
+ wait_prop_name.clear();
+ wait_prop_value.clear();
+ waiting_for_prop.reset();
+}
+
void property_changed(const std::string& name, const std::string& value) {
// If the property is sys.powerctl, we bypass the event queue and immediately handle it.
// This is to ensure that init will always and immediately shutdown/reboot, regardless of
// if there are other pending events to process or if init is waiting on an exec service or
// waiting on a property.
- if (name == "sys.powerctl") HandlePowerctlMessage(value);
+ // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
+ // commands to be executed.
+ if (name == "sys.powerctl") {
+ if (HandlePowerctlMessage(value)) {
+ shutting_down = true;
+ }
+ }
if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
if (waiting_for_prop) {
if (wait_prop_name == name && wait_prop_value == value) {
- wait_prop_name.clear();
- wait_prop_value.clear();
LOG(INFO) << "Wait for property took " << *waiting_for_prop;
- waiting_for_prop.reset();
+ ResetWaitForProp();
}
}
}
@@ -1135,7 +1146,7 @@
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || sm.IsWaitingForExec())) {
- restart_processes();
+ if (!shutting_down) restart_processes();
// If there's a process that needs restarting, wake up in time for that.
if (process_needs_restart_at != 0) {
diff --git a/init/init.h b/init/init.h
index 479b771..aaab523 100644
--- a/init/init.h
+++ b/init/init.h
@@ -44,6 +44,8 @@
void DumpState();
+void ResetWaitForProp();
+
} // namespace init
} // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index df7912f..38d603a 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -20,7 +20,7 @@
#include <fcntl.h>
#include <linux/fs.h>
#include <mntent.h>
-#include <selinux/selinux.h>
+#include <sys/capability.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
@@ -48,6 +48,8 @@
#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
+#include "capabilities.h"
+#include "init.h"
#include "property_service.h"
#include "service.h"
@@ -162,9 +164,38 @@
LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration_ms()) << ":" << stat;
}
+// Determines whether the system is capable of rebooting. This is conservative,
+// so if any of the attempts to determine this fail, it will still return true.
+static bool IsRebootCapable() {
+ if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
+ PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
+ return true;
+ }
+
+ ScopedCaps caps(cap_get_proc());
+ if (!caps) {
+ PLOG(WARNING) << "cap_get_proc() failed";
+ return true;
+ }
+
+ cap_flag_value_t value = CAP_SET;
+ if (cap_get_flag(caps.get(), CAP_SYS_BOOT, CAP_EFFECTIVE, &value) != 0) {
+ PLOG(WARNING) << "cap_get_flag(CAP_SYS_BOOT, EFFECTIVE) failed";
+ return true;
+ }
+ return value == CAP_SET;
+}
+
static void __attribute__((noreturn))
RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
LOG(INFO) << "Reboot ending, jumping to kernel";
+
+ if (!IsRebootCapable()) {
+ // On systems where init does not have the capability of rebooting the
+ // device, just exit cleanly.
+ exit(0);
+ }
+
switch (cmd) {
case ANDROID_RB_POWEROFF:
reboot(RB_POWER_OFF);
@@ -334,13 +365,15 @@
// keep debugging tools until non critical ones are all gone.
const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
- const std::set<std::string> to_starts{"watchdogd", "vold", "ueventd"};
+ const std::set<std::string> to_starts{"watchdogd"};
ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
if (kill_after_apps.count(s->name())) {
s->SetShutdownCritical();
} else if (to_starts.count(s->name())) {
s->Start();
s->SetShutdownCritical();
+ } else if (s->IsShutdownCritical()) {
+ s->Start(); // start shutdown critical service if not started
}
});
@@ -460,6 +493,9 @@
}
} else if (command == "thermal-shutdown") { // no additional parameter allowed
cmd = ANDROID_RB_THERMOFF;
+ // Do not queue "shutdown" trigger since we want to shutdown immediately
+ DoReboot(cmd, command, reboot_target, run_fsck);
+ return true;
} else {
command_invalid = true;
}
@@ -468,7 +504,26 @@
return false;
}
- DoReboot(cmd, command, reboot_target, run_fsck);
+ LOG(INFO) << "Clear action queue and start shutdown trigger";
+ ActionManager::GetInstance().ClearQueue();
+ // Queue shutdown trigger first
+ ActionManager::GetInstance().QueueEventTrigger("shutdown");
+ // Queue built-in shutdown_done
+ auto shutdown_handler = [cmd, command, reboot_target,
+ run_fsck](const std::vector<std::string>&) {
+ DoReboot(cmd, command, reboot_target, run_fsck);
+ return 0;
+ };
+ ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
+
+ // Skip wait for prop if it is in progress
+ ResetWaitForProp();
+
+ // Skip wait for exec if it is in progress
+ if (ServiceManager::GetInstance().IsWaitingForExec()) {
+ ServiceManager::GetInstance().ClearExecWait();
+ }
+
return true;
}
diff --git a/init/service.cpp b/init/service.cpp
index f9a452b..6b36526 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -34,6 +34,7 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <processgroup/processgroup.h>
@@ -47,6 +48,7 @@
using android::base::boot_clock;
using android::base::GetProperty;
using android::base::Join;
+using android::base::make_scope_guard;
using android::base::ParseInt;
using android::base::StartsWith;
using android::base::StringPrintf;
@@ -235,8 +237,15 @@
void Service::SetProcessAttributes() {
// Keep capabilites on uid change.
if (capabilities_.any() && uid_) {
- if (prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS | SECBIT_KEEP_CAPS_LOCKED) != 0) {
- PLOG(FATAL) << "prtcl(PR_SET_KEEPCAPS) failed for " << name_;
+ // If Android is running in a container, some securebits might already
+ // be locked, so don't change those.
+ int64_t securebits = prctl(PR_GET_SECUREBITS);
+ if (securebits == -1) {
+ PLOG(FATAL) << "prctl(PR_GET_SECUREBITS) failed for " << name_;
+ }
+ securebits |= SECBIT_KEEP_CAPS | SECBIT_KEEP_CAPS_LOCKED;
+ if (prctl(PR_SET_SECUREBITS, securebits) != 0) {
+ PLOG(FATAL) << "prctl(PR_SET_SECUREBITS) failed for " << name_;
}
}
@@ -492,6 +501,14 @@
return true;
}
+bool Service::ParseShutdown(const std::vector<std::string>& args, std::string* err) {
+ if (args[1] == "critical") {
+ flags_ |= SVC_SHUTDOWN_CRITICAL;
+ return true;
+ }
+ return false;
+}
+
template <typename T>
bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
@@ -595,6 +612,7 @@
{"namespace", {1, 2, &Service::ParseNamespace}},
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
+ {"shutdown", {1, 1, &Service::ParseShutdown}},
{"socket", {3, 6, &Service::ParseSocket}},
{"file", {2, 2, &Service::ParseFile}},
{"user", {1, 1, &Service::ParseUser}},
@@ -1081,14 +1099,24 @@
}
bool ServiceManager::ReapOneProcess() {
- int status;
- pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
- if (pid == 0) {
+ siginfo_t siginfo = {};
+ // This returns a zombie pid or informs us that there are no zombies left to be reaped.
+ // It does NOT reap the pid; that is done below.
+ if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) {
+ PLOG(ERROR) << "waitid failed";
return false;
- } else if (pid == -1) {
- PLOG(ERROR) << "waitpid failed";
- return false;
- } else if (PropertyChildReap(pid)) {
+ }
+
+ auto pid = siginfo.si_pid;
+ if (pid == 0) return false;
+
+ // At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
+ // whenever the function returns from this point forward.
+ // We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we
+ // want the pid to remain valid throughout that (and potentially future) usages.
+ auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });
+
+ if (PropertyChildReap(pid)) {
return true;
}
@@ -1105,14 +1133,11 @@
name = StringPrintf("Untracked pid %d", pid);
}
+ auto status = siginfo.si_status;
if (WIFEXITED(status)) {
LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
} else if (WIFSIGNALED(status)) {
LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
- } else if (WIFSTOPPED(status)) {
- LOG(INFO) << name << " stopped by signal " << WSTOPSIG(status) << wait_string;
- } else {
- LOG(INFO) << name << " state changed" << wait_string;
}
if (!svc) {
@@ -1136,6 +1161,15 @@
}
}
+void ServiceManager::ClearExecWait() {
+ // Clear EXEC flag if there is one pending
+ // And clear the wait flag
+ for (const auto& s : services_) {
+ s->UnSetExec();
+ }
+ exec_waiter_.reset();
+}
+
bool ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line, std::string* err) {
if (args.size() < 3) {
diff --git a/init/service.h b/init/service.h
index 3c7dc74..40b4745 100644
--- a/init/service.h
+++ b/init/service.h
@@ -89,6 +89,7 @@
void DumpState() const;
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
+ void UnSetExec() { flags_ &= ~SVC_EXEC; }
const std::string& name() const { return name_; }
const std::set<std::string>& classnames() const { return classnames_; }
@@ -137,6 +138,7 @@
bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
+ bool ParseShutdown(const std::vector<std::string>& args, std::string* err);
bool ParseSocket(const std::vector<std::string>& args, std::string* err);
bool ParseFile(const std::vector<std::string>& args, std::string* err);
bool ParseUser(const std::vector<std::string>& args, std::string* err);
@@ -186,7 +188,7 @@
};
class ServiceManager {
-public:
+ public:
static ServiceManager& GetInstance();
// Exposed for testing
@@ -208,8 +210,9 @@
void ReapAnyOutstandingChildren();
void RemoveService(const Service& svc);
void DumpState() const;
+ void ClearExecWait();
-private:
+ private:
// Cleans up a child process that exited.
// Returns true iff a children was cleaned up.
bool ReapOneProcess();
diff --git a/init/util.cpp b/init/util.cpp
index 4b1894f..479179e 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -370,6 +370,7 @@
void panic() {
LOG(ERROR) << "panic: rebooting to bootloader";
+ // Do not queue "shutdown" trigger since we want to shutdown immediately
DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false);
}
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index a643a29..e02aaf2 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -161,6 +161,7 @@
shared_libs = [
"libbase",
"libunwind",
+ "libziparchive",
],
}
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 919b65b..13c4abf 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -266,14 +266,27 @@
return false;
}
+static inline bool prefix_cmp(bool partial, const char* prefix, size_t len, const char* path,
+ size_t plen) {
+ return ((partial && plen >= len) || (plen == len)) && !strncmp(prefix, path, len);
+}
+
// alias prefixes of "<partition>/<stuff>" to "system/<partition>/<stuff>" or
// "system/<partition>/<stuff>" to "<partition>/<stuff>"
-static bool prefix_cmp(const char* prefix, const char* path, size_t len) {
- if (!strncmp(prefix, path, len)) return true;
+static bool fs_config_cmp(bool partial, const char* prefix, size_t len, const char* path,
+ size_t plen) {
+ // If name ends in * then allow partial matches.
+ if (!partial && prefix[len - 1] == '*') {
+ len--;
+ partial = true;
+ }
+
+ if (prefix_cmp(partial, prefix, len, path, plen)) return true;
static const char system[] = "system/";
if (!strncmp(path, system, strlen(system))) {
path += strlen(system);
+ plen -= strlen(system);
} else if (len <= strlen(system)) {
return false;
} else if (strncmp(prefix, system, strlen(system))) {
@@ -282,25 +295,11 @@
prefix += strlen(system);
len -= strlen(system);
}
- return is_partition(prefix, len) && !strncmp(prefix, path, len);
+ return is_partition(prefix, len) && prefix_cmp(partial, prefix, len, path, plen);
}
-
-static bool fs_config_cmp(bool dir, const char* prefix, size_t len, const char* path, size_t plen) {
- if (dir) {
- if (plen < len) {
- return false;
- }
- } else {
- // If name ends in * then allow partial matches.
- if (prefix[len - 1] == '*') {
- return prefix_cmp(prefix, path, len - 1);
- }
- if (plen != len) {
- return false;
- }
- }
- return prefix_cmp(prefix, path, len);
-}
+#ifndef __ANDROID_VNDK__
+auto __for_testing_only__fs_config_cmp = fs_config_cmp;
+#endif
void fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid,
unsigned* mode, uint64_t* capabilities) {
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index 4c303e6..f733e90 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -28,13 +28,6 @@
#define UNUSED __attribute__((__unused__))
-#ifndef SLOGE
-#define SLOGE ALOGE
-#endif
-#ifndef SLOGW
-#define SLOGW ALOGW
-#endif
-
/* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
* Call this any place a SchedPolicy is used as an input parameter.
* Returns the possibly re-mapped policy.
@@ -123,11 +116,8 @@
on where init.rc mounts cpuset. That's why we'd better require this
configuration be set if CONFIG_CPUSETS is set.
- With runtime check using the following function, build time
- variables like ENABLE_CPUSETS (used in Android.mk) or cpusets (used
- in Android.bp) are not needed.
+ In older releases, this was controlled by build-time configuration.
*/
-
bool cpusets_enabled() {
static bool enabled = (access("/dev/cpuset/tasks", F_OK) == 0);
@@ -139,12 +129,8 @@
CONFIG_CGROUP_SCHEDTUNE that's in Android common Linux kernel and Linaro
Stable Kernel (LSK), but not in mainline Linux as of v4.9.
- With runtime check using the following function, build time
- variables like ENABLE_SCHEDBOOST (used in Android.mk) or schedboost
- (used in Android.bp) are not needed.
-
+ In older releases, this was controlled by build-time configuration.
*/
-
bool schedboost_enabled() {
static bool enabled = (access("/dev/stune/tasks", F_OK) == 0);
diff --git a/libcutils/tests/fs_config.cpp b/libcutils/tests/fs_config.cpp
index a62cd51..391adb6 100644
--- a/libcutils/tests/fs_config.cpp
+++ b/libcutils/tests/fs_config.cpp
@@ -29,12 +29,39 @@
extern const fs_path_config* __for_testing_only__android_dirs;
extern const fs_path_config* __for_testing_only__android_files;
+extern bool (*__for_testing_only__fs_config_cmp)(bool, const char*, size_t, const char*, size_t);
// Maximum entries in system/core/libcutils/fs_config.cpp:android_* before we
// hit a nullptr termination, before we declare the list is just too big or
// could be missing the nullptr.
static constexpr size_t max_idx = 4096;
+static const struct fs_config_cmp_test {
+ bool dir;
+ const char* prefix;
+ const char* path;
+ bool match;
+} fs_config_cmp_tests[] = {
+ // clang-format off
+ { true, "system/lib", "system/lib/hw", true },
+ { true, "vendor/lib", "system/vendor/lib/hw", true },
+ { true, "system/vendor/lib", "vendor/lib/hw", true },
+ { true, "system/vendor/lib", "system/vendor/lib/hw", true },
+ { false, "vendor/bin/wifi", "system/vendor/bin/w", false },
+ { false, "vendor/bin/wifi", "system/vendor/bin/wifi", true },
+ { false, "vendor/bin/wifi", "system/vendor/bin/wifi2", false },
+ { false, "system/vendor/bin/wifi", "system/vendor/bin/wifi", true, },
+ { false, "odm/bin/wifi", "system/odm/bin/wifi", true },
+ { false, "oem/bin/wifi", "system/oem/bin/wifi", true },
+ { false, "data/bin/wifi", "system/data/bin/wifi", false },
+ { false, "system/bin/*", "system/bin/wifi", true },
+ { false, "vendor/bin/*", "system/vendor/bin/wifi", true },
+ { false, "system/bin/*", "system/bin", false },
+ { false, "system/vendor/bin/*", "vendor/bin/wifi", true },
+ { false, NULL, NULL, false },
+ // clang-format on
+};
+
static bool check_unique(std::vector<const char*>& paths, const std::string& config_name,
const std::string& prefix) {
bool retval = false;
@@ -106,6 +133,22 @@
return check_unique(paths_tmp, config, prefix) || retval;
}
+static bool check_fs_config_cmp(const fs_config_cmp_test* tests) {
+ bool match, retval = false;
+ for (size_t idx = 0; tests[idx].prefix; ++idx) {
+ match = __for_testing_only__fs_config_cmp(tests[idx].dir, tests[idx].prefix,
+ strlen(tests[idx].prefix), tests[idx].path,
+ strlen(tests[idx].path));
+ if (match != tests[idx].match) {
+ GTEST_LOG_(ERROR) << tests[idx].path << (match ? " matched " : " didn't match ")
+ << tests[idx].prefix;
+ retval = true;
+ break;
+ }
+ }
+ return retval;
+}
+
#define endof(pointer, field) (offsetof(typeof(*(pointer)), field) + sizeof((pointer)->field))
static bool check_unique(const std::string& config, const std::string& prefix) {
@@ -199,3 +242,7 @@
TEST(fs_config, odm_files_alias) {
check_two(__for_testing_only__android_files, "files", "odm/");
}
+
+TEST(fs_config, system_alias) {
+ EXPECT_FALSE(check_fs_config_cmp(fs_config_cmp_tests));
+}
diff --git a/liblog/include_vndk/log/log.h b/liblog/include_vndk/log/log.h
index 01623df..a79beec 100644
--- a/liblog/include_vndk/log/log.h
+++ b/liblog/include_vndk/log/log.h
@@ -9,6 +9,7 @@
#include <log/log_radio.h>
#include <log/log_read.h>
#include <log/log_safetynet.h>
+#include <log/log_system.h>
#include <log/log_time.h>
/*
diff --git a/liblog/include_vndk/log/log_system.h b/liblog/include_vndk/log/log_system.h
new file mode 120000
index 0000000..d0d3904
--- /dev/null
+++ b/liblog/include_vndk/log/log_system.h
@@ -0,0 +1 @@
+../../include/log/log_system.h
\ No newline at end of file
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index f62f368..ff53fad 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -37,7 +37,7 @@
template <class F>
void install(int signal, F&& f) {
- if (signal != -1) MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed");
+ if (signal_ != -1) MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed");
handler_ = SignalFn(std::allocator_arg, allocator_,
[=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index f5d4e1c..9b8248e 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -43,9 +43,6 @@
using namespace std::chrono_literals;
-// Uncomment line below use memory cgroups for keeping track of (forked) PIDs
-// #define USE_MEMCG 1
-
#define MEM_CGROUP_PATH "/dev/memcg/apps"
#define MEM_CGROUP_TASKS "/dev/memcg/apps/tasks"
#define ACCT_CGROUP_PATH "/acct"
@@ -91,7 +88,6 @@
};
static const char* getCgroupRootPath() {
-#ifdef USE_MEMCG
static const char* cgroup_root_path = NULL;
std::call_once(init_path_flag, [&]() {
// Check if mem cgroup is mounted, only then check for write-access to avoid
@@ -100,9 +96,6 @@
ACCT_CGROUP_PATH : MEM_CGROUP_PATH;
});
return cgroup_root_path;
-#else
- return ACCT_CGROUP_PATH;
-#endif
}
static int convertUidToPath(char *path, size_t size, uid_t uid)
diff --git a/libprocinfo/include/procinfo/process.h b/libprocinfo/include/procinfo/process.h
index fb140ff..db56fc1 100644
--- a/libprocinfo/include/procinfo/process.h
+++ b/libprocinfo/include/procinfo/process.h
@@ -35,8 +35,18 @@
#if defined(__linux__)
+enum ProcessState {
+ kProcessStateUnknown,
+ kProcessStateRunning,
+ kProcessStateSleeping,
+ kProcessStateUninterruptibleWait,
+ kProcessStateStopped,
+ kProcessStateZombie,
+};
+
struct ProcessInfo {
std::string name;
+ ProcessState state;
pid_t tid;
pid_t pid;
pid_t ppid;
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
index c513e16..6e5be6e 100644
--- a/libprocinfo/process.cpp
+++ b/libprocinfo/process.cpp
@@ -44,6 +44,24 @@
return GetProcessInfoFromProcPidFd(dirfd.get(), process_info);
}
+static ProcessState parse_state(const char* state) {
+ switch (*state) {
+ case 'R':
+ return kProcessStateRunning;
+ case 'S':
+ return kProcessStateSleeping;
+ case 'D':
+ return kProcessStateUninterruptibleWait;
+ case 'T':
+ return kProcessStateStopped;
+ case 'Z':
+ return kProcessStateZombie;
+ default:
+ LOG(ERROR) << "unknown process state: " << *state;
+ return kProcessStateUnknown;
+ }
+}
+
bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
@@ -60,7 +78,7 @@
}
int field_bitmap = 0;
- static constexpr int finished_bitmap = 127;
+ static constexpr int finished_bitmap = 255;
char* line = nullptr;
size_t len = 0;
@@ -98,6 +116,9 @@
} else if (header == "Gid:") {
process_info->gid = atoi(tab + 1);
field_bitmap |= 64;
+ } else if (header == "State:") {
+ process_info->state = parse_state(tab + 1);
+ field_bitmap |= 128;
}
}
diff --git a/libprocinfo/process_test.cpp b/libprocinfo/process_test.cpp
index 5ffd236..9da9278 100644
--- a/libprocinfo/process_test.cpp
+++ b/libprocinfo/process_test.cpp
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <chrono>
#include <set>
#include <thread>
#include <vector>
@@ -29,6 +30,8 @@
#include <android-base/stringprintf.h>
+using namespace std::chrono_literals;
+
#if !defined(__BIONIC__)
#include <syscall.h>
static pid_t gettid() {
@@ -82,3 +85,34 @@
}
}).join();
}
+
+TEST(process_info, process_state) {
+ int pipefd[2];
+ ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
+ pid_t forkpid = fork();
+
+ ASSERT_NE(-1, forkpid);
+ if (forkpid == 0) {
+ close(pipefd[1]);
+ char buf;
+ TEMP_FAILURE_RETRY(read(pipefd[0], &buf, 1));
+ _exit(0);
+ }
+
+ // Give the child some time to get to the read.
+ std::this_thread::sleep_for(100ms);
+
+ android::procinfo::ProcessInfo procinfo;
+ ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
+ ASSERT_EQ(android::procinfo::kProcessStateSleeping, procinfo.state);
+
+ ASSERT_EQ(0, kill(forkpid, SIGKILL));
+
+ // Give the kernel some time to kill the child.
+ std::this_thread::sleep_for(100ms);
+
+ ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
+ ASSERT_EQ(android::procinfo::kProcessStateZombie, procinfo.state);
+
+ ASSERT_EQ(forkpid, waitpid(forkpid, nullptr, 0));
+}
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index d7e949b..8776db7 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -57,16 +57,17 @@
"ElfInterface.cpp",
"ElfInterfaceArm.cpp",
"Log.cpp",
- "Regs.cpp",
"MapInfo.cpp",
"Maps.cpp",
"Memory.cpp",
+ "Regs.cpp",
"Symbols.cpp",
],
shared_libs: [
"libbase",
"liblog",
+ "liblzma",
],
}
@@ -75,17 +76,6 @@
defaults: ["libunwindstack_common"],
}
-cc_library {
- name: "libunwindstack_debug",
- defaults: ["libunwindstack_common"],
-
- cflags: [
- "-UNDEBUG",
- "-O0",
- "-g",
- ],
-}
-
//-------------------------------------------------------------------------
// Unit Tests
//-------------------------------------------------------------------------
@@ -128,6 +118,7 @@
shared_libs: [
"libbase",
"liblog",
+ "liblzma",
],
static_libs: [
@@ -151,15 +142,10 @@
shared_libs: [
"libunwindstack",
],
-}
-// These unit tests run against the static debug library.
-cc_test {
- name: "libunwindstack_test_debug",
- defaults: ["libunwindstack_test_common"],
-
- static_libs: [
- "libunwindstack_debug",
+ data: [
+ "tests/elf32.xz",
+ "tests/elf64.xz",
],
}
@@ -173,6 +159,7 @@
shared_libs: [
"libunwindstack",
"libbase",
+ "liblzma",
],
static_libs: [
@@ -190,3 +177,25 @@
"unwind_info.cpp",
],
}
+
+// Generates the elf data for use in the tests for .gnu_debugdata frames.
+// Once these files are generated, use the xz command to compress the data.
+cc_binary_host {
+ name: "gen_gnudebugdata",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ srcs: [
+ "tests/GenGnuDebugdata.cpp",
+ ],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
index 12adf57..5c7caca 100644
--- a/libunwindstack/ArmExidx.cpp
+++ b/libunwindstack/ArmExidx.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <assert.h>
#include <stdint.h>
#include <deque>
@@ -23,6 +22,7 @@
#include <android-base/stringprintf.h>
#include "ArmExidx.h"
+#include "Check.h"
#include "Log.h"
#include "Machine.h"
#include "Memory.h"
@@ -173,7 +173,7 @@
}
inline bool ArmExidx::DecodePrefix_10_00(uint8_t byte) {
- assert((byte >> 4) == 0x8);
+ CHECK((byte >> 4) == 0x8);
uint16_t registers = (byte & 0xf) << 8;
if (!GetByte(&byte)) {
@@ -232,7 +232,7 @@
}
inline bool ArmExidx::DecodePrefix_10_01(uint8_t byte) {
- assert((byte >> 4) == 0x9);
+ CHECK((byte >> 4) == 0x9);
uint8_t bits = byte & 0xf;
if (bits == 13 || bits == 15) {
@@ -258,7 +258,7 @@
}
inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {
- assert((byte >> 4) == 0xa);
+ CHECK((byte >> 4) == 0xa);
// 10100nnn: Pop r4-r[4+nnn]
// 10101nnn: Pop r4-r[4+nnn], r14
@@ -419,7 +419,7 @@
}
inline bool ArmExidx::DecodePrefix_10_11_1nnn(uint8_t byte) {
- assert((byte & ~0x07) == 0xb8);
+ CHECK((byte & ~0x07) == 0xb8);
// 10111nnn: Pop VFP double-precision registers D[8]-D[8+nnn] by FSTMFDX
if (log_) {
@@ -439,7 +439,7 @@
}
inline bool ArmExidx::DecodePrefix_10(uint8_t byte) {
- assert((byte >> 6) == 0x2);
+ CHECK((byte >> 6) == 0x2);
switch ((byte >> 4) & 0x3) {
case 0:
@@ -469,7 +469,7 @@
}
inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
- assert((byte & ~0x07) == 0xc0);
+ CHECK((byte & ~0x07) == 0xc0);
uint8_t bits = byte & 0x7;
if (bits == 6) {
@@ -550,7 +550,7 @@
}
inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
- assert((byte & ~0x07) == 0xc8);
+ CHECK((byte & ~0x07) == 0xc8);
uint8_t bits = byte & 0x7;
if (bits == 0) {
@@ -605,7 +605,7 @@
}
inline bool ArmExidx::DecodePrefix_11_010(uint8_t byte) {
- assert((byte & ~0x07) == 0xd0);
+ CHECK((byte & ~0x07) == 0xd0);
// 11010nnn: Pop VFP double precision registers D[8]-D[8+nnn] by VPUSH
if (log_) {
@@ -624,7 +624,7 @@
}
inline bool ArmExidx::DecodePrefix_11(uint8_t byte) {
- assert((byte >> 6) == 0x3);
+ CHECK((byte >> 6) == 0x3);
switch ((byte >> 3) & 0x7) {
case 0:
diff --git a/libunwindstack/Check.h b/libunwindstack/Check.h
new file mode 100644
index 0000000..e0c48c7
--- /dev/null
+++ b/libunwindstack/Check.h
@@ -0,0 +1,30 @@
+/*
+ * 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 _LIBUNWINDSTACK_ERROR_H
+#define _LIBUNWINDSTACK_ERROR_H
+
+#include <stdlib.h>
+
+#include "Log.h"
+
+#define CHECK(assertion) \
+ if (__builtin_expect(!(assertion), false)) { \
+ log(0, "%s:%d: %s\n", __FILE__, __LINE__, #assertion); \
+ abort(); \
+ }
+
+#endif // _LIBUNWINDSTACK_ERROR_H
diff --git a/libunwindstack/DwarfEhFrame.cpp b/libunwindstack/DwarfEhFrame.cpp
index 045fb36..937b6bd 100644
--- a/libunwindstack/DwarfEhFrame.cpp
+++ b/libunwindstack/DwarfEhFrame.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#include <assert.h>
#include <stdint.h>
+#include "Check.h"
#include "DwarfEhFrame.h"
#include "DwarfMemory.h"
#include "DwarfSection.h"
@@ -105,8 +105,8 @@
template <typename AddressType>
bool DwarfEhFrame<AddressType>::GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset,
uint64_t total_entries) {
- assert(fde_count_ > 0);
- assert(total_entries <= fde_count_);
+ CHECK(fde_count_ > 0);
+ CHECK(total_entries <= fde_count_);
size_t first = 0;
size_t last = total_entries;
@@ -133,7 +133,7 @@
template <typename AddressType>
bool DwarfEhFrame<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset) {
- assert(fde_count_ != 0);
+ CHECK(fde_count_ != 0);
last_error_ = DWARF_ERROR_NONE;
// We can do a binary search if the pc is in the range of the elements
// that have already been cached.
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
index 11806ea..a984fc6 100644
--- a/libunwindstack/DwarfMemory.cpp
+++ b/libunwindstack/DwarfMemory.cpp
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include <assert.h>
#include <stdint.h>
#include <string>
+#include "Check.h"
#include "DwarfEncoding.h"
#include "DwarfMemory.h"
#include "Memory.h"
@@ -100,8 +100,8 @@
}
bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) {
- assert((encoding & 0x0f) == 0);
- assert(encoding != DW_EH_PE_aligned);
+ CHECK((encoding & 0x0f) == 0);
+ CHECK(encoding != DW_EH_PE_aligned);
// Handle the encoding.
switch (encoding) {
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 272b5f0..ad1447a 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -49,6 +49,28 @@
return valid_;
}
+// It is expensive to initialize the .gnu_debugdata section. Provide a method
+// to initialize this data separately.
+void Elf::InitGnuDebugdata() {
+ if (!valid_ || interface_->gnu_debugdata_offset() == 0) {
+ return;
+ }
+
+ gnu_debugdata_memory_.reset(interface_->CreateGnuDebugdataMemory());
+ gnu_debugdata_interface_.reset(CreateInterfaceFromMemory(gnu_debugdata_memory_.get()));
+ ElfInterface* gnu = gnu_debugdata_interface_.get();
+ if (gnu == nullptr) {
+ return;
+ }
+ if (gnu->Init()) {
+ gnu->InitHeaders();
+ } else {
+ // Free all of the memory associated with the gnu_debugdata section.
+ gnu_debugdata_memory_.reset(nullptr);
+ gnu_debugdata_interface_.reset(nullptr);
+ }
+}
+
bool Elf::IsValidElf(Memory* memory) {
if (memory == nullptr) {
return false;
diff --git a/libunwindstack/Elf.h b/libunwindstack/Elf.h
index f9db541..cff9dc4 100644
--- a/libunwindstack/Elf.h
+++ b/libunwindstack/Elf.h
@@ -46,11 +46,15 @@
}
bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
- return valid_ && interface_->GetFunctionName(addr, name, func_offset);
+ return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
+ (gnu_debugdata_interface_ &&
+ gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
}
bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
- return valid_ && interface_->Step(rel_pc, regs, process_memory);
+ return valid_ && (interface_->Step(rel_pc, regs, process_memory) ||
+ (gnu_debugdata_interface_ &&
+ gnu_debugdata_interface_->Step(rel_pc, regs, process_memory)));
}
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
@@ -65,6 +69,8 @@
ElfInterface* interface() { return interface_.get(); }
+ ElfInterface* gnu_debugdata_interface() { return gnu_debugdata_interface_.get(); }
+
static bool IsValidElf(Memory* memory);
protected:
@@ -73,6 +79,9 @@
std::unique_ptr<Memory> memory_;
uint32_t machine_type_;
uint8_t class_type_;
+
+ std::unique_ptr<Memory> gnu_debugdata_memory_;
+ std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
};
#endif // _LIBUNWINDSTACK_ELF_H
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 3a7f7cb..7d38ee0 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -20,6 +20,10 @@
#include <memory>
#include <string>
+#include <7zCrc.h>
+#include <Xz.h>
+#include <XzCrc64.h>
+
#include "DwarfDebugFrame.h"
#include "DwarfEhFrame.h"
#include "DwarfSection.h"
@@ -35,6 +39,60 @@
}
}
+Memory* ElfInterface::CreateGnuDebugdataMemory() {
+ if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
+ return nullptr;
+ }
+
+ // TODO: Only call these initialization functions once.
+ CrcGenerateTable();
+ Crc64GenerateTable();
+
+ std::vector<uint8_t> src(gnu_debugdata_size_);
+ if (!memory_->Read(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
+ gnu_debugdata_offset_ = 0;
+ gnu_debugdata_size_ = static_cast<uint64_t>(-1);
+ return nullptr;
+ }
+
+ ISzAlloc alloc;
+ CXzUnpacker state;
+ alloc.Alloc = [](void*, size_t size) { return malloc(size); };
+ alloc.Free = [](void*, void* ptr) { return free(ptr); };
+
+ XzUnpacker_Construct(&state, &alloc);
+
+ std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
+ int return_val;
+ size_t src_offset = 0;
+ size_t dst_offset = 0;
+ ECoderStatus status;
+ dst->Resize(5 * gnu_debugdata_size_);
+ do {
+ size_t src_remaining = src.size() - src_offset;
+ size_t dst_remaining = dst->Size() - dst_offset;
+ if (dst_remaining < 2 * gnu_debugdata_size_) {
+ dst->Resize(dst->Size() + 2 * gnu_debugdata_size_);
+ dst_remaining += 2 * gnu_debugdata_size_;
+ }
+ return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
+ &src_remaining, CODER_FINISH_ANY, &status);
+ src_offset += src_remaining;
+ dst_offset += dst_remaining;
+ } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
+ XzUnpacker_Free(&state);
+ if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) {
+ gnu_debugdata_offset_ = 0;
+ gnu_debugdata_size_ = static_cast<uint64_t>(-1);
+ return nullptr;
+ }
+
+ // Shrink back down to the exact size.
+ dst->Resize(dst_offset);
+
+ return dst.release();
+}
+
template <typename AddressType>
void ElfInterface::InitHeadersWithTemplate() {
if (eh_frame_offset_ != 0) {
diff --git a/libunwindstack/Memory.h b/libunwindstack/Memory.h
index f9f6d56..e353cab 100644
--- a/libunwindstack/Memory.h
+++ b/libunwindstack/Memory.h
@@ -17,7 +17,6 @@
#ifndef _LIBUNWINDSTACK_MEMORY_H
#define _LIBUNWINDSTACK_MEMORY_H
-#include <assert.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
@@ -25,6 +24,8 @@
#include <string>
#include <vector>
+#include "Check.h"
+
class Memory {
public:
Memory() = default;
@@ -130,7 +131,7 @@
public:
MemoryRange(Memory* memory, uint64_t begin, uint64_t end)
: memory_(memory), begin_(begin), length_(end - begin) {
- assert(end > begin);
+ CHECK(end > begin);
}
virtual ~MemoryRange() { delete memory_; }
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index e7d10b2..da22b07 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <assert.h>
#include <elf.h>
#include <stdint.h>
#include <sys/ptrace.h>
@@ -22,6 +21,7 @@
#include <vector>
+#include "Check.h"
#include "Elf.h"
#include "ElfInterface.h"
#include "Machine.h"
@@ -43,7 +43,7 @@
bool RegsImpl<AddressType>::GetReturnAddressFromDefault(Memory* memory, uint64_t* value) {
switch (return_loc_.type) {
case LOCATION_REGISTER:
- assert(return_loc_.value < total_regs_);
+ CHECK(return_loc_.value < total_regs_);
*value = regs_[return_loc_.value];
return true;
case LOCATION_SP_OFFSET:
diff --git a/libunwindstack/Symbols.cpp b/libunwindstack/Symbols.cpp
index 86c1233..edc2187 100644
--- a/libunwindstack/Symbols.cpp
+++ b/libunwindstack/Symbols.cpp
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#include <assert.h>
#include <elf.h>
#include <stdint.h>
#include <string>
+#include "Check.h"
#include "Memory.h"
#include "Symbols.h"
@@ -58,7 +58,7 @@
if (symbols_.size() != 0) {
const Info* info = GetInfoFromCache(addr);
if (info) {
- assert(addr >= info->start_offset && addr <= info->end_offset);
+ CHECK(addr >= info->start_offset && addr <= info->end_offset);
*func_offset = addr - info->start_offset;
return elf_memory->ReadString(info->str_offset, name, str_end_ - info->str_offset);
}
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 25fec8e..22cade2 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -15,6 +15,10 @@
*/
#include <elf.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <gtest/gtest.h>
@@ -26,10 +30,6 @@
#define PT_ARM_EXIDX 0x70000001
#endif
-#if !defined(EM_AARCH64)
-#define EM_AARCH64 183
-#endif
-
class ElfTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -43,17 +43,18 @@
ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
+
+ ehdr->e_type = ET_DYN;
+ ehdr->e_version = EV_CURRENT;
}
- void InitElf32(uint32_t type) {
+ void InitElf32(uint32_t machine) {
Elf32_Ehdr ehdr;
InitEhdr<Elf32_Ehdr>(&ehdr);
ehdr.e_ident[EI_CLASS] = ELFCLASS32;
- ehdr.e_type = ET_DYN;
- ehdr.e_machine = type;
- ehdr.e_version = EV_CURRENT;
+ ehdr.e_machine = machine;
ehdr.e_entry = 0;
ehdr.e_phoff = 0x100;
ehdr.e_shoff = 0;
@@ -64,7 +65,7 @@
ehdr.e_shentsize = sizeof(Elf32_Shdr);
ehdr.e_shnum = 0;
ehdr.e_shstrndx = 0;
- if (type == EM_ARM) {
+ if (machine == EM_ARM) {
ehdr.e_flags = 0x5000200;
ehdr.e_phnum = 2;
}
@@ -82,7 +83,7 @@
phdr.p_align = 0x1000;
memory_->SetMemory(0x100, &phdr, sizeof(phdr));
- if (type == EM_ARM) {
+ if (machine == EM_ARM) {
memset(&phdr, 0, sizeof(phdr));
phdr.p_type = PT_ARM_EXIDX;
phdr.p_offset = 0x30000;
@@ -96,15 +97,13 @@
}
}
- void InitElf64(uint32_t type) {
+ void InitElf64(uint32_t machine) {
Elf64_Ehdr ehdr;
InitEhdr<Elf64_Ehdr>(&ehdr);
ehdr.e_ident[EI_CLASS] = ELFCLASS64;
- ehdr.e_type = ET_DYN;
- ehdr.e_machine = type;
- ehdr.e_version = EV_CURRENT;
+ ehdr.e_machine = machine;
ehdr.e_entry = 0;
ehdr.e_phoff = 0x100;
ehdr.e_shoff = 0;
@@ -130,6 +129,12 @@
memory_->SetMemory(0x100, &phdr, sizeof(phdr));
}
+ template <typename Ehdr, typename Shdr>
+ void GnuDebugdataInitFail(Ehdr* ehdr);
+
+ template <typename Ehdr, typename Shdr>
+ void GnuDebugdataInit(Ehdr* ehdr);
+
MemoryFake* memory_;
};
@@ -208,3 +213,154 @@
ASSERT_EQ(ELFCLASS64, elf.class_type());
ASSERT_TRUE(elf.interface() != nullptr);
}
+
+template <typename Ehdr, typename Shdr>
+void ElfTest::GnuDebugdataInitFail(Ehdr* ehdr) {
+ Elf elf(memory_);
+
+ uint64_t offset = 0x2000;
+
+ ehdr->e_shoff = offset;
+ ehdr->e_shnum = 3;
+ ehdr->e_shentsize = sizeof(Shdr);
+ ehdr->e_shstrndx = 2;
+ memory_->SetMemory(0, ehdr, sizeof(*ehdr));
+
+ Shdr shdr;
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_NULL;
+ memory_->SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr->e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_name = 0x100;
+ shdr.sh_addr = 0x5000;
+ shdr.sh_offset = 0x5000;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = 0x800;
+ memory_->SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr->e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_name = 0x200000;
+ shdr.sh_offset = 0xf000;
+ shdr.sh_size = 0x1000;
+ memory_->SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr->e_shentsize;
+
+ memory_->SetMemory(0xf100, ".gnu_debugdata", sizeof(".gnu_debugdata"));
+
+ ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.interface() != nullptr);
+ ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+ EXPECT_EQ(0x5000U, elf.interface()->gnu_debugdata_offset());
+ EXPECT_EQ(0x800U, elf.interface()->gnu_debugdata_size());
+
+ elf.InitGnuDebugdata();
+}
+
+TEST_F(ElfTest, gnu_debugdata_init_fail32) {
+ Elf32_Ehdr ehdr;
+ InitEhdr<Elf32_Ehdr>(&ehdr);
+ ehdr.e_ident[EI_CLASS] = ELFCLASS32;
+ ehdr.e_machine = EM_ARM;
+
+ GnuDebugdataInitFail<Elf32_Ehdr, Elf32_Shdr>(&ehdr);
+}
+
+TEST_F(ElfTest, gnu_debugdata_init_fail64) {
+ Elf64_Ehdr ehdr;
+ InitEhdr<Elf64_Ehdr>(&ehdr);
+ ehdr.e_ident[EI_CLASS] = ELFCLASS64;
+ ehdr.e_machine = EM_AARCH64;
+
+ GnuDebugdataInitFail<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
+}
+
+template <typename Ehdr, typename Shdr>
+void ElfTest::GnuDebugdataInit(Ehdr* ehdr) {
+ Elf elf(memory_);
+
+ uint64_t offset = 0x2000;
+
+ ehdr->e_shoff = offset;
+ ehdr->e_shnum = 3;
+ ehdr->e_shentsize = sizeof(Shdr);
+ ehdr->e_shstrndx = 2;
+ memory_->SetMemory(0, ehdr, sizeof(*ehdr));
+
+ Shdr shdr;
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_NULL;
+ memory_->SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr->e_shentsize;
+
+ uint64_t gnu_offset = offset;
+ offset += ehdr->e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_name = 0x200000;
+ shdr.sh_offset = 0xf000;
+ shdr.sh_size = 0x1000;
+ memory_->SetMemory(offset, &shdr, sizeof(shdr));
+ offset += ehdr->e_shentsize;
+
+ memory_->SetMemory(0xf100, ".gnu_debugdata", sizeof(".gnu_debugdata"));
+
+ // Read in the compressed elf data and put it in our fake memory.
+ std::string name("tests/");
+ if (sizeof(Ehdr) == sizeof(Elf32_Ehdr)) {
+ name += "elf32.xz";
+ } else {
+ name += "elf64.xz";
+ }
+ int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY));
+ ASSERT_NE(-1, fd) << "Cannot open " + name;
+ // Assumes the file is less than 1024 bytes.
+ std::vector<uint8_t> buf(1024);
+ ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size()));
+ ASSERT_GT(bytes, 0);
+ // Make sure the file isn't too big.
+ ASSERT_NE(static_cast<size_t>(bytes), buf.size())
+ << "File " + name + " is too big, increase buffer size.";
+ close(fd);
+ buf.resize(bytes);
+ memory_->SetMemory(0x5000, buf);
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_name = 0x100;
+ shdr.sh_addr = 0x5000;
+ shdr.sh_offset = 0x5000;
+ shdr.sh_size = bytes;
+ memory_->SetMemory(gnu_offset, &shdr, sizeof(shdr));
+
+ ASSERT_TRUE(elf.Init());
+ ASSERT_TRUE(elf.interface() != nullptr);
+ ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+ EXPECT_EQ(0x5000U, elf.interface()->gnu_debugdata_offset());
+
+ elf.InitGnuDebugdata();
+ ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
+}
+
+TEST_F(ElfTest, gnu_debugdata_init32) {
+ Elf32_Ehdr ehdr;
+ InitEhdr<Elf32_Ehdr>(&ehdr);
+ ehdr.e_ident[EI_CLASS] = ELFCLASS32;
+ ehdr.e_machine = EM_ARM;
+
+ GnuDebugdataInit<Elf32_Ehdr, Elf32_Shdr>(&ehdr);
+}
+
+TEST_F(ElfTest, gnu_debugdata_init64) {
+ Elf64_Ehdr ehdr;
+ InitEhdr<Elf64_Ehdr>(&ehdr);
+ ehdr.e_ident[EI_CLASS] = ELFCLASS64;
+ ehdr.e_machine = EM_AARCH64;
+
+ GnuDebugdataInit<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
+}
diff --git a/libunwindstack/tests/GenGnuDebugdata.cpp b/libunwindstack/tests/GenGnuDebugdata.cpp
new file mode 100644
index 0000000..2644582
--- /dev/null
+++ b/libunwindstack/tests/GenGnuDebugdata.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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 <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#if !defined(EM_AARCH64)
+#define EM_AARCH64 183
+#endif
+
+template <typename Ehdr>
+void InitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine) {
+ memset(ehdr, 0, sizeof(Ehdr));
+ memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
+ ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+ ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+ ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
+ ehdr->e_ident[EI_CLASS] = elf_class;
+ ehdr->e_type = ET_DYN;
+ ehdr->e_machine = machine;
+ ehdr->e_version = EV_CURRENT;
+ ehdr->e_ehsize = sizeof(Ehdr);
+}
+
+template <typename Ehdr, typename Shdr>
+void GenElf(Ehdr* ehdr, int fd) {
+ uint64_t offset = sizeof(Ehdr);
+ ehdr->e_shoff = offset;
+ ehdr->e_shnum = 3;
+ ehdr->e_shentsize = sizeof(Shdr);
+ ehdr->e_shstrndx = 2;
+ TEMP_FAILURE_RETRY(write(fd, ehdr, sizeof(Ehdr)));
+
+ Shdr shdr;
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_name = 0;
+ shdr.sh_type = SHT_NULL;
+ TEMP_FAILURE_RETRY(write(fd, &shdr, sizeof(Shdr)));
+ offset += ehdr->e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_name = 11;
+ shdr.sh_addr = 0x5000;
+ shdr.sh_offset = 0x5000;
+ shdr.sh_entsize = 0x100;
+ shdr.sh_size = 0x800;
+ TEMP_FAILURE_RETRY(write(fd, &shdr, sizeof(Shdr)));
+ offset += ehdr->e_shentsize;
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_name = 1;
+ shdr.sh_offset = 0x200;
+ shdr.sh_size = 24;
+ TEMP_FAILURE_RETRY(write(fd, &shdr, sizeof(Shdr)));
+
+ // Write out the name entries information.
+ lseek(fd, 0x200, SEEK_SET);
+ std::string name;
+ TEMP_FAILURE_RETRY(write(fd, name.data(), name.size() + 1));
+ name = ".shstrtab";
+ TEMP_FAILURE_RETRY(write(fd, name.data(), name.size() + 1));
+ name = ".debug_frame";
+ TEMP_FAILURE_RETRY(write(fd, name.data(), name.size() + 1));
+}
+
+int main() {
+ int elf32_fd = TEMP_FAILURE_RETRY(open("elf32", O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
+ if (elf32_fd == -1) {
+ printf("Failed to create elf32: %s\n", strerror(errno));
+ return 1;
+ }
+
+ int elf64_fd = TEMP_FAILURE_RETRY(open("elf64", O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
+ if (elf64_fd == -1) {
+ printf("Failed to create elf64: %s\n", strerror(errno));
+ return 1;
+ }
+
+ Elf32_Ehdr ehdr32;
+ InitEhdr<Elf32_Ehdr>(&ehdr32, ELFCLASS32, EM_ARM);
+ GenElf<Elf32_Ehdr, Elf32_Shdr>(&ehdr32, elf32_fd);
+ close(elf32_fd);
+
+ Elf64_Ehdr ehdr64;
+ InitEhdr<Elf64_Ehdr>(&ehdr64, ELFCLASS64, EM_AARCH64);
+ GenElf<Elf64_Ehdr, Elf64_Shdr>(&ehdr64, elf64_fd);
+ close(elf64_fd);
+}
diff --git a/libunwindstack/tests/elf32.xz b/libunwindstack/tests/elf32.xz
new file mode 100644
index 0000000..f25d433
--- /dev/null
+++ b/libunwindstack/tests/elf32.xz
Binary files differ
diff --git a/libunwindstack/tests/elf64.xz b/libunwindstack/tests/elf64.xz
new file mode 100644
index 0000000..eb1618e
--- /dev/null
+++ b/libunwindstack/tests/elf64.xz
Binary files differ
diff --git a/libunwindstack/unwind_info.cpp b/libunwindstack/unwind_info.cpp
index 6f158b0..da1522b 100644
--- a/libunwindstack/unwind_info.cpp
+++ b/libunwindstack/unwind_info.cpp
@@ -26,6 +26,8 @@
#include <unistd.h>
#include "ArmExidx.h"
+#include "DwarfSection.h"
+#include "DwarfStructs.h"
#include "Elf.h"
#include "ElfInterface.h"
#include "ElfInterfaceArm.h"
@@ -46,12 +48,14 @@
std::string name;
printf(" PC 0x%" PRIx64, addr + load_bias);
uint64_t func_offset;
- if (interface->GetFunctionName(addr + load_bias + 1, &name, &func_offset) && !name.empty()) {
+ uint64_t pc = addr + load_bias;
+ // This might be a thumb function, so set the low bit.
+ if (interface->GetFunctionName(pc | 1, &name, &func_offset) && !name.empty()) {
printf(" <%s>", name.c_str());
}
printf("\n");
uint64_t entry;
- if (!interface->FindEntry(addr + load_bias, &entry)) {
+ if (!interface->FindEntry(pc, &entry)) {
printf(" Cannot find entry for address.\n");
continue;
}
@@ -75,6 +79,27 @@
printf("\n");
}
+void DumpDwarfSection(ElfInterface* interface, DwarfSection* section, uint64_t load_bias) {
+ for (const DwarfFde* fde : *section) {
+ // Sometimes there are entries that have empty length, skip those since
+ // they don't contain any interesting information.
+ if (fde->pc_start == fde->pc_end) {
+ continue;
+ }
+ printf("\n PC 0x%" PRIx64, fde->pc_start + load_bias);
+ std::string name;
+ uint64_t func_offset;
+ if (interface->GetFunctionName(fde->pc_start + load_bias, &name, &func_offset) &&
+ !name.empty()) {
+ printf(" <%s>", name.c_str());
+ }
+ printf("\n");
+ if (!section->Log(2, UINT64_MAX, load_bias, fde)) {
+ printf("Failed to process cfa information for entry at 0x%" PRIx64 "\n", fde->pc_start);
+ }
+ }
+}
+
int main(int argc, char** argv) {
if (argc != 2) {
printf("Need to pass the name of an elf file to the program.\n");
@@ -117,5 +142,38 @@
printf("\n");
}
+ if (interface->eh_frame() != nullptr) {
+ printf("eh_frame information:\n");
+ DumpDwarfSection(interface, interface->eh_frame(), interface->load_bias());
+ printf("\n");
+ } else {
+ printf("\nno eh_frame information\n");
+ }
+
+ if (interface->debug_frame() != nullptr) {
+ printf("\ndebug_frame information:\n");
+ DumpDwarfSection(interface, interface->debug_frame(), interface->load_bias());
+ printf("\n");
+ } else {
+ printf("\nno debug_frame information\n");
+ }
+
+ // If there is a gnu_debugdata interface, dump the information for that.
+ ElfInterface* gnu_debugdata_interface = elf.gnu_debugdata_interface();
+ if (gnu_debugdata_interface != nullptr) {
+ if (gnu_debugdata_interface->eh_frame() != nullptr) {
+ printf("\ngnu_debugdata (eh_frame):\n");
+ DumpDwarfSection(gnu_debugdata_interface, gnu_debugdata_interface->eh_frame(), 0);
+ printf("\n");
+ }
+ if (gnu_debugdata_interface->debug_frame() != nullptr) {
+ printf("\ngnu_debugdata (debug_frame):\n");
+ DumpDwarfSection(gnu_debugdata_interface, gnu_debugdata_interface->debug_frame(), 0);
+ printf("\n");
+ }
+ } else {
+ printf("\nno valid gnu_debugdata information\n");
+ }
+
return 0;
}
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 1084d59..84a9a2f 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -65,6 +65,7 @@
"liblog",
"libbase",
],
+ export_include_dirs: ["include"],
target: {
android: {
shared_libs: [
diff --git a/libziparchive/entry_name_utils-inl.h b/libziparchive/entry_name_utils-inl.h
index ddbc286..5fc2fb4 100644
--- a/libziparchive/entry_name_utils-inl.h
+++ b/libziparchive/entry_name_utils-inl.h
@@ -55,5 +55,4 @@
return true;
}
-
#endif // LIBZIPARCHIVE_ENTRY_NAME_UTILS_INL_H_
diff --git a/libziparchive/entry_name_utils_test.cc b/libziparchive/entry_name_utils_test.cc
index 20715bb..d83d854 100644
--- a/libziparchive/entry_name_utils_test.cc
+++ b/libziparchive/entry_name_utils_test.cc
@@ -20,44 +20,43 @@
TEST(entry_name_utils, NullChars) {
// 'A', 'R', '\0', 'S', 'E'
- const uint8_t zeroes[] = { 0x41, 0x52, 0x00, 0x53, 0x45 };
+ const uint8_t zeroes[] = {0x41, 0x52, 0x00, 0x53, 0x45};
ASSERT_FALSE(IsValidEntryName(zeroes, sizeof(zeroes)));
- const uint8_t zeroes_continuation_chars[] = { 0xc2, 0xa1, 0xc2, 0x00 };
- ASSERT_FALSE(IsValidEntryName(zeroes_continuation_chars,
- sizeof(zeroes_continuation_chars)));
+ const uint8_t zeroes_continuation_chars[] = {0xc2, 0xa1, 0xc2, 0x00};
+ ASSERT_FALSE(IsValidEntryName(zeroes_continuation_chars, sizeof(zeroes_continuation_chars)));
}
TEST(entry_name_utils, InvalidSequence) {
// 0xfe is an invalid start byte
- const uint8_t invalid[] = { 0x41, 0xfe };
+ const uint8_t invalid[] = {0x41, 0xfe};
ASSERT_FALSE(IsValidEntryName(invalid, sizeof(invalid)));
// 0x91 is an invalid start byte (it's a valid continuation byte).
- const uint8_t invalid2[] = { 0x41, 0x91 };
+ const uint8_t invalid2[] = {0x41, 0x91};
ASSERT_FALSE(IsValidEntryName(invalid2, sizeof(invalid2)));
}
TEST(entry_name_utils, TruncatedContinuation) {
// Malayalam script with truncated bytes. There should be 2 bytes
// after 0xe0
- const uint8_t truncated[] = { 0xe0, 0xb4, 0x85, 0xe0, 0xb4 };
+ const uint8_t truncated[] = {0xe0, 0xb4, 0x85, 0xe0, 0xb4};
ASSERT_FALSE(IsValidEntryName(truncated, sizeof(truncated)));
// 0xc2 is the start of a 2 byte sequence that we've subsequently
// dropped.
- const uint8_t truncated2[] = { 0xc2, 0xc2, 0xa1 };
+ const uint8_t truncated2[] = {0xc2, 0xc2, 0xa1};
ASSERT_FALSE(IsValidEntryName(truncated2, sizeof(truncated2)));
}
TEST(entry_name_utils, BadContinuation) {
// 0x41 is an invalid continuation char, since it's MSBs
// aren't "10..." (are 01).
- const uint8_t bad[] = { 0xc2, 0xa1, 0xc2, 0x41 };
+ const uint8_t bad[] = {0xc2, 0xa1, 0xc2, 0x41};
ASSERT_FALSE(IsValidEntryName(bad, sizeof(bad)));
// 0x41 is an invalid continuation char, since it's MSBs
// aren't "10..." (are 11).
- const uint8_t bad2[] = { 0xc2, 0xa1, 0xc2, 0xfe };
+ const uint8_t bad2[] = {0xc2, 0xa1, 0xc2, 0xfe};
ASSERT_FALSE(IsValidEntryName(bad2, sizeof(bad2)));
}
diff --git a/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
similarity index 90%
rename from include/ziparchive/zip_archive.h
rename to libziparchive/include/ziparchive/zip_archive.h
index ece8693..73ae68d 100644
--- a/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -28,8 +28,8 @@
/* Zip compression methods we support */
enum {
- kCompressStored = 0, // no compression
- kCompressDeflated = 8, // standard deflate
+ kCompressStored = 0, // no compression
+ kCompressDeflated = 8, // standard deflate
};
struct ZipString {
@@ -44,19 +44,17 @@
explicit ZipString(const char* entry_name);
bool operator==(const ZipString& rhs) const {
- return name && (name_length == rhs.name_length) &&
- (memcmp(name, rhs.name, name_length) == 0);
+ return name && (name_length == rhs.name_length) && (memcmp(name, rhs.name, name_length) == 0);
}
bool StartsWith(const ZipString& prefix) const {
return name && (name_length >= prefix.name_length) &&
- (memcmp(name, prefix.name, prefix.name_length) == 0);
+ (memcmp(name, prefix.name, prefix.name_length) == 0);
}
bool EndsWith(const ZipString& suffix) const {
return name && (name_length >= suffix.name_length) &&
- (memcmp(name + name_length - suffix.name_length, suffix.name,
- suffix.name_length) == 0);
+ (memcmp(name + name_length - suffix.name_length, suffix.name, suffix.name_length) == 0);
}
};
@@ -134,11 +132,11 @@
*
* Returns 0 on success, and negative values on failure.
*/
-int32_t OpenArchiveFd(const int fd, const char* debugFileName,
- ZipArchiveHandle *handle, bool assume_ownership = true);
+int32_t OpenArchiveFd(const int fd, const char* debugFileName, ZipArchiveHandle* handle,
+ bool assume_ownership = true);
int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debugFileName,
- ZipArchiveHandle *handle);
+ ZipArchiveHandle* handle);
/*
* Close archive, releasing resources associated with it. This will
* unmap the central directory of the zipfile and free all internal
@@ -164,8 +162,7 @@
* On non-Windows platforms this method does not modify internal state and
* can be called concurrently.
*/
-int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName,
- ZipEntry* data);
+int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, ZipEntry* data);
/*
* Start iterating over all entries of a zip file. The order of iteration
@@ -180,8 +177,7 @@
*
* Returns 0 on success and negative values on failure.
*/
-int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
- const ZipString* optional_prefix,
+int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const ZipString* optional_prefix,
const ZipString* optional_suffix);
/*
@@ -217,8 +213,7 @@
*
* Returns 0 on success and negative values on failure.
*/
-int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry,
- uint8_t* begin, uint32_t size);
+int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size);
int GetFileDescriptor(const ZipArchiveHandle handle);
@@ -230,9 +225,9 @@
/*
* Stream the uncompressed data through the supplied function,
* passing cookie to it each time it gets called.
-*/
+ */
int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
- ProcessZipEntryFunction func, void* cookie);
+ ProcessZipEntryFunction func, void* cookie);
#endif
#endif // LIBZIPARCHIVE_ZIPARCHIVE_H_
diff --git a/include/ziparchive/zip_archive_stream_entry.h b/libziparchive/include/ziparchive/zip_archive_stream_entry.h
similarity index 100%
rename from include/ziparchive/zip_archive_stream_entry.h
rename to libziparchive/include/ziparchive/zip_archive_stream_entry.h
diff --git a/include/ziparchive/zip_writer.h b/libziparchive/include/ziparchive/zip_writer.h
similarity index 96%
rename from include/ziparchive/zip_writer.h
rename to libziparchive/include/ziparchive/zip_writer.h
index 08ead48..c350a27 100644
--- a/include/ziparchive/zip_writer.h
+++ b/libziparchive/include/ziparchive/zip_writer.h
@@ -19,7 +19,6 @@
#include <cstdio>
#include <ctime>
-#include <zlib.h>
#include <memory>
#include <string>
@@ -28,6 +27,9 @@
#include "android-base/macros.h"
#include "utils/Compat.h"
+struct z_stream_s;
+typedef struct z_stream_s z_stream;
+
/**
* Writes a Zip file via a stateful interface.
*
@@ -50,7 +52,7 @@
* fclose(file);
*/
class ZipWriter {
-public:
+ public:
enum {
/**
* Flag to compress the zip entry using deflate.
@@ -120,8 +122,7 @@
/**
* Same as StartAlignedEntry(const char*, size_t), but sets a last modified time for the entry.
*/
- int32_t StartAlignedEntryWithTime(const char* path, size_t flags, time_t time,
- uint32_t alignment);
+ int32_t StartAlignedEntryWithTime(const char* path, size_t flags, time_t time, uint32_t alignment);
/**
* Writes bytes to the zip file for the previously started zip entry.
@@ -156,7 +157,7 @@
*/
int32_t Finish();
-private:
+ private:
DISALLOW_COPY_AND_ASSIGN(ZipWriter);
int32_t HandleError(int32_t error_code);
@@ -179,7 +180,7 @@
std::vector<FileEntry> files_;
FileEntry current_file_entry_;
- std::unique_ptr<z_stream, void(*)(z_stream*)> z_stream_;
+ std::unique_ptr<z_stream, void (*)(z_stream*)> z_stream_;
std::vector<uint8_t> buffer_;
};
diff --git a/libziparchive/testdata/bad_filename.zip b/libziparchive/testdata/bad_filename.zip
new file mode 100644
index 0000000..294eaf5
--- /dev/null
+++ b/libziparchive/testdata/bad_filename.zip
Binary files differ
diff --git a/libziparchive/testdata/crash.apk b/libziparchive/testdata/crash.apk
new file mode 100644
index 0000000..d6dd52d
--- /dev/null
+++ b/libziparchive/testdata/crash.apk
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index efe1096..17c268b 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -115,8 +115,7 @@
* Convert a ZipEntry to a hash table index, verifying that it's in a
* valid range.
*/
-static int64_t EntryToIndex(const ZipString* hash_table,
- const uint32_t hash_table_size,
+static int64_t EntryToIndex(const ZipString* hash_table, const uint32_t hash_table_size,
const ZipString& name) {
const uint32_t hash = ComputeHash(name);
@@ -137,7 +136,7 @@
/*
* Add a new entry to the hash table.
*/
-static int32_t AddToHash(ZipString *hash_table, const uint64_t hash_table_size,
+static int32_t AddToHash(ZipString* hash_table, const uint64_t hash_table_size,
const ZipString& name) {
const uint64_t hash = ComputeHash(name);
uint32_t ent = hash & (hash_table_size - 1);
@@ -161,13 +160,12 @@
}
static int32_t MapCentralDirectory0(const char* debug_file_name, ZipArchive* archive,
- off64_t file_length, off64_t read_amount,
- uint8_t* scan_buffer) {
+ off64_t file_length, off64_t read_amount, uint8_t* scan_buffer) {
const off64_t search_start = file_length - read_amount;
- if(!archive->mapped_zip.ReadAtOffset(scan_buffer, read_amount, search_start)) {
- ALOGE("Zip: read %" PRId64 " from offset %" PRId64 " failed",
- static_cast<int64_t>(read_amount), static_cast<int64_t>(search_start));
+ if (!archive->mapped_zip.ReadAtOffset(scan_buffer, read_amount, search_start)) {
+ ALOGE("Zip: read %" PRId64 " from offset %" PRId64 " failed", static_cast<int64_t>(read_amount),
+ static_cast<int64_t>(search_start));
return kIoError;
}
@@ -198,8 +196,7 @@
* Verify that there's no trailing space at the end of the central directory
* and its comment.
*/
- const off64_t calculated_length = eocd_offset + sizeof(EocdRecord)
- + eocd->comment_length;
+ const off64_t calculated_length = eocd_offset + sizeof(EocdRecord) + eocd->comment_length;
if (calculated_length != file_length) {
ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory",
static_cast<int64_t>(file_length - calculated_length));
@@ -212,7 +209,7 @@
*/
if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) {
ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
- eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
+ eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
#if defined(__ANDROID__)
if (eocd->cd_start_offset + eocd->cd_size <= eocd_offset) {
android_errorWriteLog(0x534e4554, "31251826");
@@ -225,8 +222,8 @@
return kEmptyArchive;
}
- ALOGV("+++ num_entries=%" PRIu32 " dir_size=%" PRIu32 " dir_offset=%" PRIu32,
- eocd->num_records, eocd->cd_size, eocd->cd_start_offset);
+ ALOGV("+++ num_entries=%" PRIu32 " dir_size=%" PRIu32 " dir_offset=%" PRIu32, eocd->num_records,
+ eocd->cd_size, eocd->cd_start_offset);
/*
* It all looks good. Create a mapping for the CD, and set the fields
@@ -255,7 +252,6 @@
* num_entries
*/
static int32_t MapCentralDirectory(const char* debug_file_name, ZipArchive* archive) {
-
// Test file length. We use lseek64 to make sure the file
// is small enough to be a zip file (Its size must be less than
// 0xffffffff bytes).
@@ -292,8 +288,8 @@
}
std::vector<uint8_t> scan_buffer(read_amount);
- int32_t result = MapCentralDirectory0(debug_file_name, archive, file_length, read_amount,
- scan_buffer.data());
+ int32_t result =
+ MapCentralDirectory0(debug_file_name, archive, file_length, read_amount, scan_buffer.data());
return result;
}
@@ -314,8 +310,13 @@
* least one unused entry to avoid an infinite loop during creation.
*/
archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
- archive->hash_table = reinterpret_cast<ZipString*>(calloc(archive->hash_table_size,
- sizeof(ZipString)));
+ archive->hash_table =
+ reinterpret_cast<ZipString*>(calloc(archive->hash_table_size, sizeof(ZipString)));
+ if (archive->hash_table == nullptr) {
+ ALOGW("Zip: unable to allocate the %u-entry hash_table, entry size: %zu",
+ archive->hash_table_size, sizeof(ZipString));
+ return -1;
+ }
/*
* Walk through the central directory, adding entries to the hash
@@ -324,22 +325,24 @@
const uint8_t* const cd_end = cd_ptr + cd_length;
const uint8_t* ptr = cd_ptr;
for (uint16_t i = 0; i < num_entries; i++) {
- const CentralDirectoryRecord* cdr =
- reinterpret_cast<const CentralDirectoryRecord*>(ptr);
- if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
- ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
+ if (ptr > cd_end - sizeof(CentralDirectoryRecord)) {
+ ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
+#if defined(__ANDROID__)
+ android_errorWriteLog(0x534e4554, "36392138");
+#endif
return -1;
}
- if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
- ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
+ const CentralDirectoryRecord* cdr = reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+ if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
+ ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
return -1;
}
const off64_t local_header_offset = cdr->local_file_header_offset;
if (local_header_offset >= archive->directory_offset) {
ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
- static_cast<int64_t>(local_header_offset), i);
+ static_cast<int64_t>(local_header_offset), i);
return -1;
}
@@ -348,6 +351,13 @@
const uint16_t comment_length = cdr->comment_length;
const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
+ if (file_name + file_name_length > cd_end) {
+ ALOGW(
+ "Zip: file name boundary exceeds the central directory range, file_name_length: "
+ "%" PRIx16 ", cd_length: %zu",
+ file_name_length, cd_length);
+ return -1;
+ }
/* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
if (!IsValidEntryName(file_name, file_name_length)) {
return -1;
@@ -357,8 +367,7 @@
ZipString entry_name;
entry_name.name = file_name;
entry_name.name_length = file_name_length;
- const int add_result = AddToHash(archive->hash_table,
- archive->hash_table_size, entry_name);
+ const int add_result = AddToHash(archive->hash_table, archive->hash_table_size, entry_name);
if (add_result != 0) {
ALOGW("Zip: Error adding entry to hash table %d", add_result);
return add_result;
@@ -366,8 +375,7 @@
ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
- ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
- ptr - cd_ptr, cd_length, i);
+ ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16, ptr - cd_ptr, cd_length, i);
return -1;
}
}
@@ -376,8 +384,7 @@
return 0;
}
-static int32_t OpenArchiveInternal(ZipArchive* archive,
- const char* debug_file_name) {
+static int32_t OpenArchiveInternal(ZipArchive* archive, const char* debug_file_name) {
int32_t result = -1;
if ((result = MapCentralDirectory(debug_file_name, archive)) != 0) {
return result;
@@ -390,8 +397,8 @@
return 0;
}
-int32_t OpenArchiveFd(int fd, const char* debug_file_name,
- ZipArchiveHandle* handle, bool assume_ownership) {
+int32_t OpenArchiveFd(int fd, const char* debug_file_name, ZipArchiveHandle* handle,
+ bool assume_ownership) {
ZipArchive* archive = new ZipArchive(fd, assume_ownership);
*handle = archive;
return OpenArchiveInternal(archive, debug_file_name);
@@ -411,7 +418,7 @@
}
int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debug_file_name,
- ZipArchiveHandle *handle) {
+ ZipArchiveHandle* handle) {
ZipArchive* archive = new ZipArchive(address, length);
*handle = archive;
return OpenArchiveInternal(archive, debug_file_name);
@@ -451,8 +458,7 @@
return 0;
}
-static int32_t FindEntry(const ZipArchive* archive, const int ent,
- ZipEntry* data) {
+static int32_t FindEntry(const ZipArchive* archive, const int ent, ZipEntry* data) {
const uint16_t nameLen = archive->hash_table[ent].name_length;
// Recover the start of the central directory entry from the filename
@@ -470,8 +476,7 @@
return kInvalidOffset;
}
- const CentralDirectoryRecord *cdr =
- reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+ const CentralDirectoryRecord* cdr = reinterpret_cast<const CentralDirectoryRecord*>(ptr);
// The offset of the start of the central directory in the zipfile.
// We keep this lying around so that we can sanity check all our lengths
@@ -499,15 +504,15 @@
uint8_t lfh_buf[sizeof(LocalFileHeader)];
if (!archive->mapped_zip.ReadAtOffset(lfh_buf, sizeof(lfh_buf), local_header_offset)) {
ALOGW("Zip: failed reading lfh name from offset %" PRId64,
- static_cast<int64_t>(local_header_offset));
+ static_cast<int64_t>(local_header_offset));
return kIoError;
}
- const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
+ const LocalFileHeader* lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
if (lfh->lfh_signature != LocalFileHeader::kSignature) {
ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
- static_cast<int64_t>(local_header_offset));
+ static_cast<int64_t>(local_header_offset));
return kInvalidOffset;
}
@@ -536,13 +541,12 @@
// header agree on the crc, compressed, and uncompressed sizes of the entry.
if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
data->has_data_descriptor = 0;
- if (data->compressed_length != lfh->compressed_size
- || data->uncompressed_length != lfh->uncompressed_size
- || data->crc32 != lfh->crc32) {
- ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32
- ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
- data->compressed_length, data->uncompressed_length, data->crc32,
- lfh->compressed_size, lfh->uncompressed_size, lfh->crc32);
+ if (data->compressed_length != lfh->compressed_size ||
+ data->uncompressed_length != lfh->uncompressed_size || data->crc32 != lfh->crc32) {
+ ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32 ", %" PRIx32
+ "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
+ data->compressed_length, data->uncompressed_length, data->crc32, lfh->compressed_size,
+ lfh->uncompressed_size, lfh->crc32);
return kInconsistentInformation;
}
} else {
@@ -580,8 +584,8 @@
return kInconsistentInformation;
}
- const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
- + lfh->file_name_length + lfh->extra_field_length;
+ const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader) +
+ lfh->file_name_length + lfh->extra_field_length;
if (data_offset > cd_offset) {
ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset));
return kInvalidOffset;
@@ -589,16 +593,17 @@
if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) {
ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
- static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset));
+ static_cast<int64_t>(data_offset), data->compressed_length,
+ static_cast<int64_t>(cd_offset));
return kInvalidOffset;
}
if (data->method == kCompressStored &&
- static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
- ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
- static_cast<int64_t>(data_offset), data->uncompressed_length,
- static_cast<int64_t>(cd_offset));
- return kInvalidOffset;
+ static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
+ ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
+ static_cast<int64_t>(data_offset), data->uncompressed_length,
+ static_cast<int64_t>(cd_offset));
+ return kInvalidOffset;
}
data->offset = data_offset;
@@ -613,8 +618,7 @@
ZipString suffix;
ZipArchive* archive;
- IterationHandle(const ZipString* in_prefix,
- const ZipString* in_suffix) {
+ IterationHandle(const ZipString* in_prefix, const ZipString* in_suffix) {
if (in_prefix) {
uint8_t* name_copy = new uint8_t[in_prefix->name_length];
memcpy(name_copy, in_prefix->name, in_prefix->name_length);
@@ -641,8 +645,7 @@
}
};
-int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
- const ZipString* optional_prefix,
+int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const ZipString* optional_prefix,
const ZipString* optional_suffix) {
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
@@ -655,7 +658,7 @@
cookie->position = 0;
cookie->archive = archive;
- *cookie_ptr = cookie ;
+ *cookie_ptr = cookie;
return 0;
}
@@ -663,16 +666,14 @@
delete reinterpret_cast<IterationHandle*>(cookie);
}
-int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName,
- ZipEntry* data) {
+int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, ZipEntry* data) {
const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
if (entryName.name_length == 0) {
ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
return kInvalidEntryName;
}
- const int64_t ent = EntryToIndex(archive->hash_table,
- archive->hash_table_size, entryName);
+ const int64_t ent = EntryToIndex(archive->hash_table, archive->hash_table_size, entryName);
if (ent < 0) {
ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name);
@@ -700,10 +701,8 @@
for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
if (hash_table[i].name != NULL &&
- (handle->prefix.name_length == 0 ||
- hash_table[i].StartsWith(handle->prefix)) &&
- (handle->suffix.name_length == 0 ||
- hash_table[i].EndsWith(handle->suffix))) {
+ (handle->prefix.name_length == 0 || hash_table[i].StartsWith(handle->prefix)) &&
+ (handle->suffix.name_length == 0 || hash_table[i].EndsWith(handle->suffix))) {
handle->position = (i + 1);
const int error = FindEntry(archive, i, data);
if (!error) {
@@ -723,8 +722,10 @@
public:
virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
virtual ~Writer() {}
+
protected:
Writer() = default;
+
private:
DISALLOW_COPY_AND_ASSIGN(Writer);
};
@@ -734,14 +735,12 @@
// the data appended to it.
class MemoryWriter : public Writer {
public:
- MemoryWriter(uint8_t* buf, size_t size) : Writer(),
- buf_(buf), size_(size), bytes_written_(0) {
- }
+ MemoryWriter(uint8_t* buf, size_t size) : Writer(), buf_(buf), size_(size), bytes_written_(0) {}
virtual bool Append(uint8_t* buf, size_t buf_size) override {
if (bytes_written_ + buf_size > size_) {
- ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
- size_, bytes_written_ + buf_size);
+ ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)", size_,
+ bytes_written_ + buf_size);
return false;
}
@@ -760,7 +759,6 @@
// The file will be truncated to the end of the written data.
class FileWriter : public Writer {
public:
-
// Creates a FileWriter for |fd| and prepare to write |entry| to it,
// guaranteeing that the file descriptor is valid and that there's enough
// space on the volume to write out the entry completely and that the file
@@ -819,8 +817,8 @@
virtual bool Append(uint8_t* buf, size_t buf_size) override {
if (total_bytes_written_ + buf_size > declared_length_) {
- ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
- declared_length_, total_bytes_written_ + buf_size);
+ ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)", declared_length_,
+ total_bytes_written_ + buf_size);
return false;
}
@@ -833,13 +831,10 @@
return result;
}
+
private:
- FileWriter(const int fd, const size_t declared_length) :
- Writer(),
- fd_(fd),
- declared_length_(declared_length),
- total_bytes_written_(0) {
- }
+ FileWriter(const int fd, const size_t declared_length)
+ : Writer(), fd_(fd), declared_length_(declared_length), total_bytes_written_(0) {}
const int fd_;
const size_t declared_length_;
@@ -882,8 +877,7 @@
zerr = zlib_inflateInit2(&zstream, -MAX_WBITS);
if (zerr != Z_OK) {
if (zerr == Z_VERSION_ERROR) {
- ALOGE("Installed zlib is not compatible with linked version (%s)",
- ZLIB_VERSION);
+ ALOGE("Installed zlib is not compatible with linked version (%s)", ZLIB_VERSION);
} else {
ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr);
}
@@ -892,7 +886,7 @@
}
auto zstream_deleter = [](z_stream* stream) {
- inflateEnd(stream); /* free up any allocated structures */
+ inflateEnd(stream); /* free up any allocated structures */
};
std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
@@ -919,15 +913,13 @@
/* uncompress the data */
zerr = inflate(&zstream, Z_NO_FLUSH);
if (zerr != Z_OK && zerr != Z_STREAM_END) {
- ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
- zerr, zstream.next_in, zstream.avail_in,
- zstream.next_out, zstream.avail_out);
+ ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)", zerr, zstream.next_in,
+ zstream.avail_in, zstream.next_out, zstream.avail_out);
return kZlibError;
}
/* write when we're full or when we're done */
- if (zstream.avail_out == 0 ||
- (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
+ if (zstream.avail_out == 0 || (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
const size_t write_size = zstream.next_out - &write_buf[0];
if (!writer->Append(&write_buf[0], write_size)) {
// The file might have declared a bogus length.
@@ -941,7 +933,7 @@
}
} while (zerr == Z_OK);
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+ assert(zerr == Z_STREAM_END); /* other errors should've been caught */
// NOTE: zstream.adler is always set to 0, because we're using the -MAX_WBITS
// "feature" of zlib to tell it there won't be a zlib file header. zlib
@@ -952,8 +944,8 @@
*crc_out = crc;
if (zstream.total_out != uncompressed_length || compressed_length != 0) {
- ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
- zstream.total_out, uncompressed_length);
+ ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")", zstream.total_out,
+ uncompressed_length);
return kInconsistentInformation;
}
@@ -961,7 +953,7 @@
}
static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, Writer* writer,
- uint64_t *crc_out) {
+ uint64_t* crc_out) {
static const uint32_t kBufSize = 32768;
std::vector<uint8_t> buf(kBufSize);
@@ -991,8 +983,7 @@
return 0;
}
-int32_t ExtractToWriter(ZipArchiveHandle handle,
- ZipEntry* entry, Writer* writer) {
+int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, Writer* writer) {
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
const uint16_t method = entry->method;
off64_t data_offset = entry->offset;
@@ -1027,14 +1018,12 @@
return return_value;
}
-int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry,
- uint8_t* begin, uint32_t size) {
+int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size) {
std::unique_ptr<Writer> writer(new MemoryWriter(begin, size));
return ExtractToWriter(handle, entry, writer.get());
}
-int32_t ExtractEntryToFile(ZipArchiveHandle handle,
- ZipEntry* entry, int fd) {
+int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd) {
std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry));
if (writer.get() == nullptr) {
return kIoError;
@@ -1061,8 +1050,7 @@
return reinterpret_cast<ZipArchive*>(handle)->mapped_zip.GetFileDescriptor();
}
-ZipString::ZipString(const char* entry_name)
- : name(reinterpret_cast<const uint8_t*>(entry_name)) {
+ZipString::ZipString(const char* entry_name) : name(reinterpret_cast<const uint8_t*>(entry_name)) {
size_t len = strlen(entry_name);
CHECK_LE(len, static_cast<size_t>(UINT16_MAX));
name_length = static_cast<uint16_t>(len);
@@ -1071,10 +1059,8 @@
#if !defined(_WIN32)
class ProcessWriter : public Writer {
public:
- ProcessWriter(ProcessZipEntryFunction func, void* cookie) : Writer(),
- proc_function_(func),
- cookie_(cookie) {
- }
+ ProcessWriter(ProcessZipEntryFunction func, void* cookie)
+ : Writer(), proc_function_(func), cookie_(cookie) {}
virtual bool Append(uint8_t* buf, size_t buf_size) override {
return proc_function_(buf, buf_size, cookie_);
@@ -1091,7 +1077,7 @@
return ExtractToWriter(handle, entry, &writer);
}
-#endif //!defined(_WIN32)
+#endif //! defined(_WIN32)
int MappedZipFile::GetFileDescriptor() const {
if (!has_fd_) {
@@ -1134,8 +1120,7 @@
return true;
} else {
if (offset < 0 || offset > static_cast<off64_t>(data_length_)) {
- ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n" , offset,
- data_length_);
+ ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", offset, data_length_);
return false;
}
@@ -1146,7 +1131,7 @@
bool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) {
if (has_fd_) {
- if(!android::base::ReadFully(fd_, buffer, read_amount)) {
+ if (!android::base::ReadFully(fd_, buffer, read_amount)) {
ALOGE("Zip: read from %d failed\n", fd_);
return false;
}
@@ -1172,7 +1157,6 @@
return false;
}
return ReadData(buf, len);
-
}
void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) {
@@ -1183,13 +1167,13 @@
bool ZipArchive::InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
size_t cd_size) {
if (mapped_zip.HasFd()) {
- if (!directory_map->create(debug_file_name, mapped_zip.GetFileDescriptor(),
- cd_start_offset, cd_size, true /* read only */)) {
+ if (!directory_map->create(debug_file_name, mapped_zip.GetFileDescriptor(), cd_start_offset,
+ cd_size, true /* read only */)) {
return false;
}
CHECK_EQ(directory_map->getDataLength(), cd_size);
- central_directory.Initialize(directory_map->getDataPtr(), 0/*offset*/, cd_size);
+ central_directory.Initialize(directory_map->getDataPtr(), 0 /*offset*/, cd_size);
} else {
if (mapped_zip.GetBasePtr() == nullptr) {
ALOGE("Zip: Failed to map central directory, bad mapped_zip base pointer\n");
@@ -1197,9 +1181,10 @@
}
if (static_cast<off64_t>(cd_start_offset) + static_cast<off64_t>(cd_size) >
mapped_zip.GetFileLength()) {
- ALOGE("Zip: Failed to map central directory, offset exceeds mapped memory region ("
- "start_offset %" PRId64 ", cd_size %zu, mapped_region_size %" PRId64 ")",
- static_cast<int64_t>(cd_start_offset), cd_size, mapped_zip.GetFileLength());
+ ALOGE(
+ "Zip: Failed to map central directory, offset exceeds mapped memory region ("
+ "start_offset %" PRId64 ", cd_size %zu, mapped_region_size %" PRId64 ")",
+ static_cast<int64_t>(cd_start_offset), cd_size, mapped_zip.GetFileLength());
return false;
}
diff --git a/libziparchive/zip_archive_common.h b/libziparchive/zip_archive_common.h
index bc1ebb4..8b99bde 100644
--- a/libziparchive/zip_archive_common.h
+++ b/libziparchive/zip_archive_common.h
@@ -57,6 +57,7 @@
uint32_t cd_start_offset;
// Length of the central directory comment.
uint16_t comment_length;
+
private:
EocdRecord() = default;
DISALLOW_COPY_AND_ASSIGN(EocdRecord);
@@ -111,6 +112,7 @@
// The offset to the local file header for this entry, from the
// beginning of this archive.
uint32_t local_file_header_offset;
+
private:
CentralDirectoryRecord() = default;
DISALLOW_COPY_AND_ASSIGN(CentralDirectoryRecord);
@@ -149,6 +151,7 @@
// The length of the extra field info (in bytes). This data
// will appear immediately after the entry file name.
uint16_t extra_field_length;
+
private:
LocalFileHeader() = default;
DISALLOW_COPY_AND_ASSIGN(LocalFileHeader);
@@ -164,6 +167,7 @@
uint32_t compressed_size;
// Uncompressed size of the entry.
uint32_t uncompressed_size;
+
private:
DataDescriptor() = default;
DISALLOW_COPY_AND_ASSIGN(DataDescriptor);
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index de93ecd..840f1af 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -92,21 +92,17 @@
class MappedZipFile {
public:
- explicit MappedZipFile(const int fd) :
- has_fd_(true),
- fd_(fd),
- base_ptr_(nullptr),
- data_length_(0),
- read_pos_(0) {}
+ explicit MappedZipFile(const int fd)
+ : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0), read_pos_(0) {}
- explicit MappedZipFile(void* address, size_t length) :
- has_fd_(false),
- fd_(-1),
- base_ptr_(address),
- data_length_(static_cast<off64_t>(length)),
- read_pos_(0) {}
+ explicit MappedZipFile(void* address, size_t length)
+ : has_fd_(false),
+ fd_(-1),
+ base_ptr_(address),
+ data_length_(static_cast<off64_t>(length)),
+ read_pos_(0) {}
- bool HasFd() const {return has_fd_;}
+ bool HasFd() const { return has_fd_; }
int GetFileDescriptor() const;
@@ -137,13 +133,11 @@
class CentralDirectory {
public:
- CentralDirectory(void) :
- base_ptr_(nullptr),
- length_(0) {}
+ CentralDirectory(void) : base_ptr_(nullptr), length_(0) {}
- const uint8_t* GetBasePtr() const {return base_ptr_;}
+ const uint8_t* GetBasePtr() const { return base_ptr_; }
- size_t GetMapLength() const {return length_;}
+ size_t GetMapLength() const { return length_; }
void Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
@@ -172,25 +166,25 @@
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(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(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) {
@@ -202,7 +196,6 @@
bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
size_t cd_size);
-
};
#endif // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index 3f336a6..50352ef 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -162,8 +162,7 @@
int zerr = zlib_inflateInit2(&z_stream_, -MAX_WBITS);
if (zerr != Z_OK) {
if (zerr == Z_VERSION_ERROR) {
- ALOGE("Installed zlib is not compatible with linked version (%s)",
- ZLIB_VERSION);
+ ALOGE("Installed zlib is not compatible with linked version (%s)", ZLIB_VERSION);
} else {
ALOGE("Call to inflateInit2 failed (zerr=%d)", zerr);
}
@@ -193,13 +192,14 @@
bool ZipArchiveStreamEntryCompressed::Verify() {
return z_stream_init_ && uncompressed_length_ == 0 && compressed_length_ == 0 &&
- crc32_ == computed_crc32_;
+ crc32_ == computed_crc32_;
}
const std::vector<uint8_t>* ZipArchiveStreamEntryCompressed::Read() {
if (z_stream_.avail_out == 0) {
z_stream_.next_out = out_.data();
- z_stream_.avail_out = out_.size();;
+ z_stream_.avail_out = out_.size();
+ ;
}
while (true) {
@@ -226,9 +226,8 @@
int zerr = inflate(&z_stream_, Z_NO_FLUSH);
if (zerr != Z_OK && zerr != Z_STREAM_END) {
- ALOGE("inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
- zerr, z_stream_.next_in, z_stream_.avail_in,
- z_stream_.next_out, z_stream_.avail_out);
+ ALOGE("inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)", zerr, z_stream_.next_in,
+ z_stream_.avail_in, z_stream_.next_out, z_stream_.avail_out);
return nullptr;
}
@@ -276,8 +275,8 @@
return length_ == 0;
}
-ZipArchiveStreamEntry* ZipArchiveStreamEntry::Create(
- ZipArchiveHandle handle, const ZipEntry& entry) {
+ZipArchiveStreamEntry* ZipArchiveStreamEntry::Create(ZipArchiveHandle handle,
+ const ZipEntry& entry) {
ZipArchiveStreamEntry* stream = nullptr;
if (entry.method != kCompressStored) {
stream = new ZipArchiveStreamEntryCompressed(handle);
@@ -292,8 +291,8 @@
return stream;
}
-ZipArchiveStreamEntry* ZipArchiveStreamEntry::CreateRaw(
- ZipArchiveHandle handle, const ZipEntry& entry) {
+ZipArchiveStreamEntry* ZipArchiveStreamEntry::CreateRaw(ZipArchiveHandle handle,
+ const ZipEntry& entry) {
ZipArchiveStreamEntry* stream = nullptr;
if (entry.method == kCompressStored) {
// Not compressed, don't need to do anything special.
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 52099c3..dbc14f0 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -40,23 +40,17 @@
static const std::string kValidZip = "valid.zip";
static const std::string kLargeZip = "large.zip";
static const std::string kBadCrcZip = "bad_crc.zip";
+static const std::string kCrashApk = "crash.apk";
+static const std::string kBadFilenameZip = "bad_filename.zip";
static const std::string kUpdateZip = "dummy-update.zip";
-static const std::vector<uint8_t> kATxtContents {
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- '\n'
-};
+static const std::vector<uint8_t> kATxtContents{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a',
+ 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\n'};
-static const std::vector<uint8_t> kATxtContentsCompressed {
- 'K', 'L', 'J', 'N', 'I', 'M', 'K', 207, 'H',
- 132, 210, '\\', '\0'
-};
+static const std::vector<uint8_t> kATxtContentsCompressed{'K', 'L', 'J', 'N', 'I', 'M', 'K',
+ 207, 'H', 132, 210, '\\', '\0'};
-static const std::vector<uint8_t> kBTxtContents {
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- '\n'
-};
+static const std::vector<uint8_t> kBTxtContents{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\n'};
static const std::string kATxtName("a.txt");
static const std::string kBTxtName("b.txt");
@@ -65,14 +59,12 @@
static const std::string kLargeCompressTxtName("compress.txt");
static const std::string kLargeUncompressTxtName("uncompress.txt");
-static int32_t OpenArchiveWrapper(const std::string& name,
- ZipArchiveHandle* handle) {
+static int32_t OpenArchiveWrapper(const std::string& name, ZipArchiveHandle* handle) {
const std::string abs_path = test_data_dir + "/" + name;
return OpenArchive(abs_path.c_str(), handle);
}
-static void AssertNameEquals(const std::string& name_str,
- const ZipString& name) {
+static void AssertNameEquals(const std::string& name_str, const ZipString& name) {
ASSERT_EQ(name_str.size(), name.name_length);
ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
}
@@ -85,7 +77,15 @@
TEST(ziparchive, Open) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+ CloseArchive(handle);
+ ASSERT_EQ(-1, OpenArchiveWrapper(kBadFilenameZip, &handle));
+ CloseArchive(handle);
+}
+
+TEST(ziparchive, OutOfBound) {
+ ZipArchiveHandle handle;
+ ASSERT_EQ(-8, OpenArchiveWrapper(kCrashApk, &handle));
CloseArchive(handle);
}
@@ -335,47 +335,36 @@
}
static const uint32_t kEmptyEntriesZip[] = {
- 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
- 0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
- 0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
- 0x00000a03, 0x60000000, 0x00443863, 0x00000000, 0x00000000, 0x09000000,
- 0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
- 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
- 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
+ 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000, 0x00090000,
+ 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13, 0x52e25c24, 0x000b7875,
+ 0x42890401, 0x88040000, 0x50000013, 0x1e02014b, 0x00000a03, 0x60000000, 0x00443863,
+ 0x00000000, 0x00000000, 0x09000000, 0x00001800, 0x00000000, 0xa0000000, 0x00000081,
+ 0x706d6500, 0x742e7974, 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904,
+ 0x13880400, 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000};
// This is a zip file containing a single entry (ab.txt) that contains
// 90072 repetitions of the string "ab\n" and has an uncompressed length
// of 270216 bytes.
static const uint16_t kAbZip[] = {
- 0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
- 0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
- 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
- 0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
- 0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
- 0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
- 0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02,
- 0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
- 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
- 0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
- 0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
- 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
- 0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
-};
+ 0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0, 0x2cda, 0x011b, 0x0000, 0x1f88,
+ 0x0004, 0x0006, 0x001c, 0x6261, 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
+ 0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000, 0xc2ed, 0x0d31, 0x0000, 0x030c,
+ 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa, 0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02, 0x1403, 0x0000, 0x0800, 0xd200,
+ 0x9851, 0xb046, 0xdac4, 0x1b2c, 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
+ 0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574, 0x0554, 0x0300, 0x097c, 0x553a,
+ 0x7875, 0x000b, 0x0401, 0x4289, 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
+ 0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000};
static const std::string kAbTxtName("ab.txt");
static const size_t kAbUncompressedSize = 270216;
@@ -396,7 +385,6 @@
uint8_t buffer[1];
ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
-
TemporaryFile tmp_output_file;
ASSERT_NE(-1, tmp_output_file.fd);
ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
@@ -410,7 +398,7 @@
TemporaryFile tmp_file;
ASSERT_NE(-1, tmp_file.fd);
ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
- sizeof(kAbZip) - 1));
+ sizeof(kAbZip) - 1));
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
@@ -438,8 +426,7 @@
// the same as the memory buffer we extracted directly to.
std::vector<uint8_t> file_contents(kAbUncompressedSize);
ASSERT_EQ(0, lseek64(tmp_output_file.fd, 0, SEEK_SET));
- ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0],
- file_contents.size()));
+ ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0], file_contents.size()));
ASSERT_EQ(file_contents, buffer);
for (int i = 0; i < 90072; ++i) {
@@ -455,7 +442,7 @@
ASSERT_NE(-1, tmp_file.fd);
// Create a file with 8 bytes of random garbage.
- static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
+ static const uint8_t trailer[] = {'A', 'n', 'd', 'r', 'o', 'i', 'd', 'z'};
ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
@@ -466,7 +453,7 @@
TEST(ziparchive, ExtractToFile) {
TemporaryFile tmp_file;
ASSERT_NE(-1, tmp_file.fd);
- const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
+ const uint8_t data[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
const size_t data_size = sizeof(data);
ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
@@ -480,7 +467,6 @@
ASSERT_EQ(0, FindEntry(handle, name, &entry));
ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
-
// Assert that the first 8 bytes of the file haven't been clobbered.
uint8_t read_buffer[data_size];
ASSERT_EQ(0, lseek64(tmp_file.fd, 0, SEEK_SET));
@@ -489,10 +475,9 @@
// Assert that the remainder of the file contains the incompressed data.
std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
- ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
- entry.uncompressed_length));
- ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(),
- kATxtContents.size()));
+ ASSERT_TRUE(
+ android::base::ReadFully(tmp_file.fd, uncompressed_data.data(), entry.uncompressed_length));
+ ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(), kATxtContents.size()));
// Assert that the total length of the file is sane
ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
@@ -509,7 +494,7 @@
// Memory map the file first and open the archive from the memory region.
android::FileMap file_map;
- file_map.create(zip_path.c_str(), fd, 0/*offset*/, sb.st_size, true);
+ file_map.create(zip_path.c_str(), fd, 0 /*offset*/, sb.st_size, true);
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
zip_path.c_str(), &handle));
@@ -525,9 +510,8 @@
}
#endif
-static void ZipArchiveStreamTest(
- ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
- bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
+static void ZipArchiveStreamTest(ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
+ bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
ZipString name;
SetZipString(&name, entry_name);
ASSERT_EQ(0, FindEntry(handle, name, entry));
@@ -556,9 +540,9 @@
ASSERT_EQ(total_size, read_data->size());
}
-static void ZipArchiveStreamTestUsingContents(
- const std::string& zip_file, const std::string& entry_name,
- const std::vector<uint8_t>& contents, bool raw) {
+static void ZipArchiveStreamTestUsingContents(const std::string& zip_file,
+ const std::string& entry_name,
+ const std::vector<uint8_t>& contents, bool raw) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
@@ -572,7 +556,8 @@
CloseArchive(handle);
}
-static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file, const std::string& entry_name) {
+static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file,
+ const std::string& entry_name) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
@@ -735,10 +720,8 @@
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- static struct option options[] = {
- { "test_data_dir", required_argument, nullptr, 't' },
- { nullptr, 0, nullptr, 0 }
- };
+ static struct option options[] = {{"test_data_dir", required_argument, nullptr, 't'},
+ {nullptr, 0, nullptr, 0}};
while (true) {
int option_index;
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 6d28bdb..6ad3366 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -16,11 +16,11 @@
#include "ziparchive/zip_writer.h"
-#include <cstdio>
#include <sys/param.h>
#include <sys/stat.h>
#include <zlib.h>
-#define DEF_MEM_LEVEL 8 // normally in zutil.h?
+#include <cstdio>
+#define DEF_MEM_LEVEL 8 // normally in zutil.h?
#include <memory>
#include <vector>
@@ -33,13 +33,13 @@
#include "zip_archive_common.h"
#if !defined(powerof2)
-#define powerof2(x) ((((x)-1)&(x))==0)
+#define powerof2(x) ((((x)-1) & (x)) == 0)
#endif
/* Zip compression methods we support */
enum {
- kCompressStored = 0, // no compression
- kCompressDeflated = 8, // standard deflate
+ kCompressStored = 0, // no compression
+ kCompressDeflated = 8, // standard deflate
};
// Size of the output buffer used for compression.
@@ -67,10 +67,7 @@
static const int32_t kInvalidAlignment = -6;
static const char* sErrorCodes[] = {
- "Invalid state",
- "IO error",
- "Invalid entry name",
- "Zlib error",
+ "Invalid state", "IO error", "Invalid entry name", "Zlib error",
};
const char* ZipWriter::ErrorCodeString(int32_t error_code) {
@@ -85,9 +82,13 @@
delete stream;
}
-ZipWriter::ZipWriter(FILE* f) : file_(f), seekable_(false), current_offset_(0),
- state_(State::kWritingZip), z_stream_(nullptr, DeleteZStream),
- buffer_(kBufSize) {
+ZipWriter::ZipWriter(FILE* f)
+ : file_(f),
+ seekable_(false),
+ current_offset_(0),
+ state_(State::kWritingZip),
+ z_stream_(nullptr, DeleteZStream),
+ buffer_(kBufSize) {
// Check if the file is seekable (regular file). If fstat fails, that's fine, subsequent calls
// will fail as well.
struct stat file_stats;
@@ -96,13 +97,14 @@
}
}
-ZipWriter::ZipWriter(ZipWriter&& writer) : file_(writer.file_),
- seekable_(writer.seekable_),
- current_offset_(writer.current_offset_),
- state_(writer.state_),
- files_(std::move(writer.files_)),
- z_stream_(std::move(writer.z_stream_)),
- buffer_(std::move(writer.buffer_)){
+ZipWriter::ZipWriter(ZipWriter&& writer)
+ : file_(writer.file_),
+ seekable_(writer.seekable_),
+ current_offset_(writer.current_offset_),
+ state_(writer.state_),
+ files_(std::move(writer.files_)),
+ z_stream_(std::move(writer.z_stream_)),
+ buffer_(std::move(writer.buffer_)) {
writer.file_ = nullptr;
writer.state_ = State::kError;
}
@@ -154,10 +156,10 @@
struct tm* ptm;
#if !defined(_WIN32)
- struct tm tm_result;
- ptm = localtime_r(&when, &tm_result);
+ struct tm tm_result;
+ ptm = localtime_r(&when, &tm_result);
#else
- ptm = localtime(&when);
+ ptm = localtime(&when);
#endif
int year = ptm->tm_year;
@@ -193,8 +195,8 @@
dst->extra_field_length = src.padding_length;
}
-int32_t ZipWriter::StartAlignedEntryWithTime(const char* path, size_t flags,
- time_t time, uint32_t alignment) {
+int32_t ZipWriter::StartAlignedEntryWithTime(const char* path, size_t flags, time_t time,
+ uint32_t alignment) {
if (state_ != State::kWritingZip) {
return kInvalidState;
}
@@ -252,9 +254,8 @@
return HandleError(kIoError);
}
- if (file_entry.padding_length != 0 &&
- fwrite(zero_padding.data(), 1, file_entry.padding_length, file_)
- != file_entry.padding_length) {
+ if (file_entry.padding_length != 0 && fwrite(zero_padding.data(), 1, file_entry.padding_length,
+ file_) != file_entry.padding_length) {
return HandleError(kIoError);
}
@@ -292,7 +293,7 @@
CHECK(state_ == State::kWritingZip);
// Initialize the z_stream for compression.
- z_stream_ = std::unique_ptr<z_stream, void(*)(z_stream*)>(new z_stream(), DeleteZStream);
+ z_stream_ = std::unique_ptr<z_stream, void (*)(z_stream*)>(new z_stream(), DeleteZStream);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
@@ -331,8 +332,8 @@
return result;
}
- current_file_entry_.crc32 = crc32(current_file_entry_.crc32,
- reinterpret_cast<const Bytef*>(data), len);
+ current_file_entry_.crc32 =
+ crc32(current_file_entry_.crc32, reinterpret_cast<const Bytef*>(data), len);
current_file_entry_.uncompressed_size += len;
return kNoError;
}
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index 9ad0252..c284273 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "ziparchive/zip_archive.h"
#include "ziparchive/zip_writer.h"
+#include "ziparchive/zip_archive.h"
#include <android-base/test_utils.h>
#include <gtest/gtest.h>
@@ -361,7 +361,7 @@
ASSERT_EQ(0, writer.StartEntry("large.txt", 0));
std::vector<uint8_t> data;
- data.resize(1024*1024, 0xef);
+ data.resize(1024 * 1024, 0xef);
ASSERT_EQ(0, writer.WriteBytes(data.data(), data.size()));
ASSERT_EQ(0, writer.FinishEntry());
@@ -382,8 +382,9 @@
ZipArchiveHandle handle,
ZipEntry* zip_entry) {
if (expected.size() != zip_entry->uncompressed_length) {
- return ::testing::AssertionFailure() << "uncompressed entry size "
- << zip_entry->uncompressed_length << " does not match expected size " << expected.size();
+ return ::testing::AssertionFailure()
+ << "uncompressed entry size " << zip_entry->uncompressed_length
+ << " does not match expected size " << expected.size();
}
std::string actual;
@@ -396,7 +397,7 @@
if (expected != actual) {
return ::testing::AssertionFailure() << "actual zip_entry data '" << actual
- << "' does not match expected '" << expected << "'";
+ << "' does not match expected '" << expected << "'";
}
return ::testing::AssertionSuccess();
}
diff --git a/logd/Android.bp b/logd/Android.bp
new file mode 100644
index 0000000..68b79d3
--- /dev/null
+++ b/logd/Android.bp
@@ -0,0 +1,78 @@
+// 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.
+
+// This is what we want to do:
+// event_logtags = $(shell
+// sed -n
+// "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p"
+// $(LOCAL_PATH)/$2/event.logtags)
+// event_flag := $(call event_logtags,auditd)
+// event_flag += $(call event_logtags,logd)
+// event_flag += $(call event_logtags,tag_def)
+// so make sure we do not regret hard-coding it as follows:
+event_flag = [
+ "-DAUDITD_LOG_TAG=1003",
+ "-DCHATTY_LOG_TAG=1004",
+ "-DTAG_DEF_LOG_TAG=1005",
+ "-DLIBLOG_LOG_TAG=1006"
+]
+
+cc_library_static {
+ name: "liblogd",
+
+ srcs: [
+ "LogCommand.cpp",
+ "CommandListener.cpp",
+ "LogListener.cpp",
+ "LogReader.cpp",
+ "FlushCommand.cpp",
+ "LogBuffer.cpp",
+ "LogBufferElement.cpp",
+ "LogBufferInterface.cpp",
+ "LogTimes.cpp",
+ "LogStatistics.cpp",
+ "LogWhiteBlackList.cpp",
+ "libaudit.c",
+ "LogAudit.cpp",
+ "LogKlog.cpp",
+ "LogTags.cpp",
+ ],
+ logtags: ["event.logtags"],
+
+ shared_libs: ["libbase"],
+
+ export_include_dirs: ["."],
+
+ cflags: ["-Werror"] + event_flag,
+}
+
+cc_binary {
+ name: "logd",
+ init_rc: ["logd.rc"],
+
+ srcs: ["main.cpp"],
+
+ static_libs: ["liblogd"],
+
+ shared_libs: [
+ "libsysutils",
+ "liblog",
+ "libcutils",
+ "libbase",
+ "libpackagelistparser",
+ "libcap",
+ ],
+
+ cflags: ["-Werror"],
+}
diff --git a/logd/Android.mk b/logd/Android.mk
index fb51992..1bca891 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -2,73 +2,6 @@
include $(CLEAR_VARS)
-LOCAL_MODULE:= liblogd
-
-LOCAL_SRC_FILES := \
- LogCommand.cpp \
- CommandListener.cpp \
- LogListener.cpp \
- LogReader.cpp \
- FlushCommand.cpp \
- LogBuffer.cpp \
- LogBufferElement.cpp \
- LogBufferInterface.cpp \
- LogTimes.cpp \
- LogStatistics.cpp \
- LogWhiteBlackList.cpp \
- libaudit.c \
- LogAudit.cpp \
- LogKlog.cpp \
- LogTags.cpp \
- event.logtags
-
-LOCAL_SHARED_LIBRARIES := \
- libbase
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-# This is what we want to do:
-# event_logtags = $(shell \
-# sed -n \
-# "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p" \
-# $(LOCAL_PATH)/$2/event.logtags)
-# event_flag := $(call event_logtags,auditd)
-# event_flag += $(call event_logtags,logd)
-# event_flag += $(call event_logtags,tag_def)
-# so make sure we do not regret hard-coding it as follows:
-event_flag := -DAUDITD_LOG_TAG=1003 -DCHATTY_LOG_TAG=1004 -DTAG_DEF_LOG_TAG=1005
-event_flag += -DLIBLOG_LOG_TAG=1006
-
-LOCAL_CFLAGS := -Werror $(event_flag)
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= logd
-
-LOCAL_INIT_RC := logd.rc
-
-LOCAL_SRC_FILES := \
- main.cpp
-
-LOCAL_STATIC_LIBRARIES := \
- liblogd
-
-LOCAL_SHARED_LIBRARIES := \
- libsysutils \
- liblog \
- libcutils \
- libbase \
- libpackagelistparser \
- libcap
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
LOCAL_MODULE := logtagd.rc
LOCAL_SRC_FILES := $(LOCAL_MODULE)
LOCAL_MODULE_CLASS := ETC
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 94f64e0..3893722 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -36,6 +36,8 @@
mount cgroup none /dev/memcg memory
# app mem cgroups, used by activity manager, lmkd and zygote
mkdir /dev/memcg/apps/ 0755 system system
+ # cgroup for system_server and surfaceflinger
+ mkdir /dev/memcg/system 0755 system system
start ueventd
@@ -221,6 +223,8 @@
mount pstore pstore /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
+ chmod 0440 /sys/fs/pstore/console-ramoops-0
chown system log /sys/fs/pstore/pmsg-ramoops-0
chmod 0440 /sys/fs/pstore/pmsg-ramoops-0
@@ -677,12 +681,17 @@
on property:security.perf_harden=1
write /proc/sys/kernel/perf_event_paranoid 3
+# on shutdown
+# In device's init.rc, this trigger can be used to do device-specific actions
+# before shutdown. e.g disable watchdog and mask error handling
+
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
class core
critical
seclabel u:r:ueventd:s0
+ shutdown critical
service healthd /sbin/healthd
class core