Merge "bootstat: Add more boot reasons."
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index a5e6f23..18f585d 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -22,6 +22,7 @@
#include <atomic>
#include <chrono>
+#include <condition_variable>
#include <memory>
#include <mutex>
#include <string>
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index 14eb16b..eb4df97 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -118,7 +118,7 @@
bool is_socket_spec(const std::string& spec) {
for (const auto& it : kLocalSocketTypes) {
std::string prefix = it.first + ":";
- if (StartsWith(spec, prefix.c_str())) {
+ if (StartsWith(spec, prefix)) {
return true;
}
}
@@ -128,7 +128,7 @@
bool is_local_socket_spec(const std::string& spec) {
for (const auto& it : kLocalSocketTypes) {
std::string prefix = it.first + ":";
- if (StartsWith(spec, prefix.c_str())) {
+ if (StartsWith(spec, prefix)) {
return true;
}
}
@@ -170,7 +170,7 @@
for (const auto& it : kLocalSocketTypes) {
std::string prefix = it.first + ":";
- if (StartsWith(spec, prefix.c_str())) {
+ if (StartsWith(spec, prefix)) {
if (!it.second.available) {
*error = StringPrintf("socket type %s is unavailable on this platform",
it.first.c_str());
@@ -213,7 +213,7 @@
for (const auto& it : kLocalSocketTypes) {
std::string prefix = it.first + ":";
- if (StartsWith(spec, prefix.c_str())) {
+ if (StartsWith(spec, prefix)) {
if (!it.second.available) {
*error = StringPrintf("attempted to listen on unavailable socket type: '%s'",
spec.c_str());
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 5cf2450..f221785 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -952,10 +952,18 @@
}
std::string list_transports(bool long_listing) {
- std::string result;
-
std::lock_guard<std::recursive_mutex> lock(transport_lock);
- for (const auto& t : transport_list) {
+
+ auto sorted_transport_list = transport_list;
+ sorted_transport_list.sort([](atransport*& x, atransport*& y) {
+ if (x->type != y->type) {
+ return x->type < y->type;
+ }
+ return strcmp(x->serial, y->serial) < 0;
+ });
+
+ std::string result;
+ for (const auto& t : sorted_transport_list) {
append_transport(t, &result, long_listing);
}
return result;
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index f93c696..afff2c9 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -42,6 +42,10 @@
// By default, output goes to logcat on Android and stderr on the host.
// A process can use `SetLogger` to decide where all logging goes.
// Implementations are provided for logcat, stderr, and dmesg.
+//
+// By default, the process' name is used as the log tag.
+// Code can choose a specific log tag by defining LOG_TAG
+// before including this header.
// This header also provides assertions:
//
@@ -63,6 +67,16 @@
#include "android-base/macros.h"
+// Note: DO NOT USE DIRECTLY. Use LOG_TAG instead.
+#ifdef _LOG_TAG_INTERNAL
+#error "_LOG_TAG_INTERNAL must not be defined"
+#endif
+#ifdef LOG_TAG
+#define _LOG_TAG_INTERNAL LOG_TAG
+#else
+#define _LOG_TAG_INTERNAL nullptr
+#endif
+
namespace android {
namespace base {
@@ -201,10 +215,10 @@
// Get an ostream that can be used for logging at the given severity and to the
// given destination. The same notes as for LOG_STREAM apply.
-#define LOG_STREAM_TO(dest, severity) \
- ::android::base::LogMessage(__FILE__, __LINE__, \
- ::android::base::dest, \
- SEVERITY_LAMBDA(severity), -1).stream()
+#define LOG_STREAM_TO(dest, severity) \
+ ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \
+ SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL, -1) \
+ .stream()
// Logs a message to logcat on Android otherwise to stderr. If the severity is
// FATAL it also causes an abort. For example:
@@ -231,10 +245,10 @@
#define PLOG(severity) PLOG_TO(DEFAULT, severity)
// Behaves like PLOG, but logs to the specified log ID.
-#define PLOG_TO(dest, severity) \
- LOGGING_PREAMBLE(severity) && \
- ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \
- SEVERITY_LAMBDA(severity), errno) \
+#define PLOG_TO(dest, severity) \
+ LOGGING_PREAMBLE(severity) && \
+ ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest, \
+ SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL, errno) \
.stream()
// Marker that code is yet to be implemented.
@@ -247,23 +261,26 @@
//
// CHECK(false == true) results in a log message of
// "Check failed: false == true".
-#define CHECK(x) \
- LIKELY((x)) || ABORT_AFTER_LOG_FATAL_EXPR(false) || \
- ::android::base::LogMessage( \
- __FILE__, __LINE__, ::android::base::DEFAULT, ::android::base::FATAL, \
- -1).stream() \
+#define CHECK(x) \
+ LIKELY((x)) || ABORT_AFTER_LOG_FATAL_EXPR(false) || \
+ ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+ ::android::base::FATAL, _LOG_TAG_INTERNAL, -1) \
+ .stream() \
<< "Check failed: " #x << " "
+// clang-format off
// Helper for CHECK_xx(x,y) macros.
-#define CHECK_OP(LHS, RHS, OP) \
- for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \
- UNLIKELY(!(_values.lhs OP _values.rhs)); \
- /* empty */) \
- ABORT_AFTER_LOG_FATAL \
- ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
- ::android::base::FATAL, -1).stream() \
- << "Check failed: " << #LHS << " " << #OP << " " << #RHS \
- << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
+#define CHECK_OP(LHS, RHS, OP) \
+ for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \
+ UNLIKELY(!(_values.lhs OP _values.rhs)); \
+ /* empty */) \
+ ABORT_AFTER_LOG_FATAL \
+ ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
+ ::android::base::FATAL, _LOG_TAG_INTERNAL, -1) \
+ .stream() \
+ << "Check failed: " << #LHS << " " << #OP << " " << #RHS << " (" #LHS "=" << _values.lhs \
+ << ", " #RHS "=" << _values.rhs << ") "
+// clang-format on
// Check whether a condition holds between x and y, LOG(FATAL) if not. The value
// of the expressions x and y is evaluated once. Extra logging can be appended
@@ -278,14 +295,17 @@
#define CHECK_GE(x, y) CHECK_OP(x, y, >= )
#define CHECK_GT(x, y) CHECK_OP(x, y, > )
+// clang-format off
// Helper for CHECK_STRxx(s1,s2) macros.
#define CHECK_STROP(s1, s2, sense) \
while (UNLIKELY((strcmp(s1, s2) == 0) != (sense))) \
ABORT_AFTER_LOG_FATAL \
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
- ::android::base::FATAL, -1).stream() \
+ ::android::base::FATAL, _LOG_TAG_INTERNAL, -1) \
+ .stream() \
<< "Check failed: " << "\"" << (s1) << "\"" \
<< ((sense) ? " == " : " != ") << "\"" << (s2) << "\""
+// clang-format on
// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
@@ -400,8 +420,8 @@
// of a CHECK. The destructor will abort if the severity is FATAL.
class LogMessage {
public:
- LogMessage(const char* file, unsigned int line, LogId id,
- LogSeverity severity, int error);
+ LogMessage(const char* file, unsigned int line, LogId id, LogSeverity severity, const char* tag,
+ int error);
~LogMessage();
@@ -410,12 +430,17 @@
std::ostream& stream();
// The routine that performs the actual logging.
- static void LogLine(const char* file, unsigned int line, LogId id,
- LogSeverity severity, const char* msg);
+ static void LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
+ const char* tag, const char* msg);
private:
const std::unique_ptr<LogMessageData> data_;
+ // TODO(b/35361699): remove these symbols once all prebuilds stop using it.
+ LogMessage(const char* file, unsigned int line, LogId id, LogSeverity severity, int error);
+ static void LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
+ const char* msg);
+
DISALLOW_COPY_AND_ASSIGN(LogMessage);
};
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index f5f5c11..c11acb1 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -57,12 +57,18 @@
extern template std::string Join(const std::vector<const char*>&, const std::string&);
// Tests whether 's' starts with 'prefix'.
+// TODO: string_view
bool StartsWith(const std::string& s, const char* prefix);
bool StartsWithIgnoreCase(const std::string& s, const char* prefix);
+bool StartsWith(const std::string& s, const std::string& prefix);
+bool StartsWithIgnoreCase(const std::string& s, const std::string& prefix);
// Tests whether 's' ends with 'suffix'.
+// TODO: string_view
bool EndsWith(const std::string& s, const char* suffix);
bool EndsWithIgnoreCase(const std::string& s, const char* suffix);
+bool EndsWith(const std::string& s, const std::string& prefix);
+bool EndsWithIgnoreCase(const std::string& s, const std::string& prefix);
// Tests whether 'lhs' equals 'rhs', ignoring case.
bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs);
diff --git a/base/logging.cpp b/base/logging.cpp
index 75078e5..0f2012a 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -187,8 +187,8 @@
}
#endif
-void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
- unsigned int line, const char* message) {
+void StderrLogger(LogId, LogSeverity severity, const char* tag, const char* file, unsigned int line,
+ const char* message) {
struct tm now;
time_t t = time(nullptr);
@@ -205,8 +205,8 @@
static_assert(arraysize(log_characters) - 1 == FATAL + 1,
"Mismatch in size of log_characters and values in LogSeverity");
char severity_char = log_characters[severity];
- fprintf(stderr, "%s %c %s %5d %5d %s:%u] %s\n", ProgramInvocationName().c_str(),
- severity_char, timestamp, getpid(), GetThreadId(), file, line, message);
+ fprintf(stderr, "%s %c %s %5d %5d %s:%u] %s\n", tag ? tag : "nullptr", severity_char, timestamp,
+ getpid(), GetThreadId(), file, line, message);
}
void DefaultAborter(const char* abort_message) {
@@ -344,14 +344,14 @@
// checks/logging in a function.
class LogMessageData {
public:
- LogMessageData(const char* file, unsigned int line, LogId id,
- LogSeverity severity, int error)
+ LogMessageData(const char* file, unsigned int line, LogId id, LogSeverity severity,
+ const char* tag, int error)
: file_(GetFileBasename(file)),
line_number_(line),
id_(id),
severity_(severity),
- error_(error) {
- }
+ tag_(tag),
+ error_(error) {}
const char* GetFile() const {
return file_;
@@ -365,6 +365,8 @@
return severity_;
}
+ const char* GetTag() const { return tag_; }
+
LogId GetId() const {
return id_;
}
@@ -387,15 +389,19 @@
const unsigned int line_number_;
const LogId id_;
const LogSeverity severity_;
+ const char* const tag_;
const int error_;
DISALLOW_COPY_AND_ASSIGN(LogMessageData);
};
-LogMessage::LogMessage(const char* file, unsigned int line, LogId id,
- LogSeverity severity, int error)
- : data_(new LogMessageData(file, line, id, severity, error)) {
-}
+LogMessage::LogMessage(const char* file, unsigned int line, LogId id, LogSeverity severity,
+ const char* tag, int error)
+ : data_(new LogMessageData(file, line, id, severity, tag, error)) {}
+
+LogMessage::LogMessage(const char* file, unsigned int line, LogId id, LogSeverity severity,
+ int error)
+ : LogMessage(file, line, id, severity, nullptr, error) {}
LogMessage::~LogMessage() {
// Check severity again. This is duplicate work wrt/ LOG macros, but not LOG_STREAM.
@@ -413,16 +419,16 @@
// Do the actual logging with the lock held.
std::lock_guard<std::mutex> lock(LoggingLock());
if (msg.find('\n') == std::string::npos) {
- LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
- data_->GetSeverity(), msg.c_str());
+ LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), data_->GetSeverity(),
+ data_->GetTag(), msg.c_str());
} else {
msg += '\n';
size_t i = 0;
while (i < msg.size()) {
size_t nl = msg.find('\n', i);
msg[nl] = '\0';
- LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
- data_->GetSeverity(), &msg[i]);
+ LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), data_->GetSeverity(),
+ data_->GetTag(), &msg[i]);
// Undo the zero-termination so we can give the complete message to the aborter.
msg[nl] = '\n';
i = nl + 1;
@@ -440,12 +446,17 @@
return data_->GetBuffer();
}
-void LogMessage::LogLine(const char* file, unsigned int line, LogId id,
- LogSeverity severity, const char* message) {
- const char* tag = ProgramInvocationName().c_str();
+void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
+ const char* tag, const char* message) {
+ if (tag == nullptr) tag = ProgramInvocationName().c_str();
Logger()(id, severity, tag, file, line, message);
}
+void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
+ const char* message) {
+ LogLine(file, line, id, severity, nullptr, message);
+}
+
LogSeverity GetMinimumLogSeverity() {
return gMinimumLogSeverity;
}
diff --git a/base/strings.cpp b/base/strings.cpp
index bfdaf12..a8bb2a9 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -91,12 +91,20 @@
return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
}
+bool StartsWith(const std::string& s, const std::string& prefix) {
+ return strncmp(s.c_str(), prefix.c_str(), prefix.size()) == 0;
+}
+
bool StartsWithIgnoreCase(const std::string& s, const char* prefix) {
return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
}
-static bool EndsWith(const std::string& s, const char* suffix, bool case_sensitive) {
- size_t suffix_length = strlen(suffix);
+bool StartsWithIgnoreCase(const std::string& s, const std::string& prefix) {
+ return strncasecmp(s.c_str(), prefix.c_str(), prefix.size()) == 0;
+}
+
+static bool EndsWith(const std::string& s, const char* suffix, size_t suffix_length,
+ bool case_sensitive) {
size_t string_length = s.size();
if (suffix_length > string_length) {
return false;
@@ -106,11 +114,19 @@
}
bool EndsWith(const std::string& s, const char* suffix) {
- return EndsWith(s, suffix, true);
+ return EndsWith(s, suffix, strlen(suffix), true);
+}
+
+bool EndsWith(const std::string& s, const std::string& suffix) {
+ return EndsWith(s, suffix.c_str(), suffix.size(), true);
}
bool EndsWithIgnoreCase(const std::string& s, const char* suffix) {
- return EndsWith(s, suffix, false);
+ return EndsWith(s, suffix, strlen(suffix), false);
+}
+
+bool EndsWithIgnoreCase(const std::string& s, const std::string& suffix) {
+ return EndsWith(s, suffix.c_str(), suffix.size(), false);
}
bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs) {
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 121197c..b8639ea 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -253,6 +253,26 @@
ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "FOO"));
}
+TEST(strings, StartsWith_std_string) {
+ ASSERT_TRUE(android::base::StartsWith("hello", std::string{"hell"}));
+ ASSERT_FALSE(android::base::StartsWith("goodbye", std::string{"hell"}));
+}
+
+TEST(strings, StartsWithIgnoreCase_std_string) {
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("HeLlO", std::string{"hell"}));
+ ASSERT_FALSE(android::base::StartsWithIgnoreCase("GoOdByE", std::string{"hell"}));
+}
+
+TEST(strings, EndsWith_std_string) {
+ ASSERT_TRUE(android::base::EndsWith("hello", std::string{"lo"}));
+ ASSERT_FALSE(android::base::EndsWith("goodbye", std::string{"lo"}));
+}
+
+TEST(strings, EndsWithIgnoreCase_std_string) {
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("HeLlO", std::string{"lo"}));
+ ASSERT_FALSE(android::base::EndsWithIgnoreCase("GoOdByE", std::string{"lo"}));
+}
+
TEST(strings, EqualsIgnoreCase) {
ASSERT_TRUE(android::base::EqualsIgnoreCase("foo", "FOO"));
ASSERT_TRUE(android::base::EqualsIgnoreCase("FOO", "foo"));
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 6b1d206..ae0a401 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -324,8 +324,7 @@
for (auto& s : knownReasons) {
if (s == "cold") break;
// Prefix defined as terminated by a nul or comma (,).
- if (android::base::StartsWith(r, s.c_str()) &&
- ((r.length() == s.length()) || (r[s.length()] == ','))) {
+ if (android::base::StartsWith(r, s) && ((r.length() == s.length()) || (r[s.length()] == ','))) {
return true;
}
}
@@ -337,8 +336,7 @@
for (auto& s : knownReasons) {
if (s == "recovery") break;
// Prefix defined as terminated by a nul or comma (,).
- if (android::base::StartsWith(r, s.c_str()) &&
- ((r.length() == s.length()) || (r[s.length()] == ','))) {
+ if (android::base::StartsWith(r, s) && ((r.length() == s.length()) || (r[s.length()] == ','))) {
return true;
}
}
@@ -349,8 +347,7 @@
bool isKnownRebootReason(const std::string& r) {
for (auto& s : knownReasons) {
// Prefix defined as terminated by a nul or comma (,).
- if (android::base::StartsWith(r, s.c_str()) &&
- ((r.length() == s.length()) || (r[s.length()] == ','))) {
+ if (android::base::StartsWith(r, s) && ((r.length() == s.length()) || (r[s.length()] == ','))) {
return true;
}
}
@@ -441,9 +438,11 @@
if (needle.length() > pos) return std::string::npos;
pos -= needle.length();
// fuzzy match to maximum kBitErrorRate
- do {
+ for (;;) {
if (numError(pos, needle) != std::string::npos) return pos;
- } while (pos-- != 0);
+ if (pos == 0) break;
+ --pos;
+ }
return std::string::npos;
}
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index e9a3ebd..4b32b9d 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -289,7 +289,7 @@
munmap(map, sizeof(int));
map[0] = '8';
} else if (!strcasecmp(arg, "seccomp")) {
- set_seccomp_filter();
+ set_system_seccomp_filter();
syscall(99999);
#if defined(__arm__)
} else if (!strcasecmp(arg, "kuser_helper_version")) {
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 02bc4b8..05e6efa 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -395,9 +395,6 @@
// crash_dump is ptracing us, fork off a copy of our address space for it to use.
create_vm_process();
- input_read.reset();
- input_write.reset();
-
// Don't leave a zombie child.
int status;
if (TEMP_FAILURE_RETRY(waitpid(crash_dump_pid, &status, 0)) == -1) {
@@ -406,6 +403,14 @@
} else if (WIFSTOPPED(status) || WIFSIGNALED(status)) {
async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped");
}
+
+ if (thread_info->siginfo->si_signo != DEBUGGER_SIGNAL) {
+ // For crashes, we don't need to minimize pause latency.
+ // Wait for the dump to complete before having the process exit, to avoid being murdered by
+ // ActivityManager or init.
+ TEMP_FAILURE_RETRY(read(input_read, &buf, sizeof(buf)));
+ }
+
return 0;
}
@@ -495,6 +500,17 @@
fatal_errno("failed to set dumpable");
}
+ // On kernels with yama_ptrace enabled, also allow any process to attach.
+ bool restore_orig_ptracer = true;
+ if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) != 0) {
+ if (errno == EINVAL) {
+ // This kernel does not support PR_SET_PTRACER_ANY, or Yama is not enabled.
+ restore_orig_ptracer = false;
+ } else {
+ fatal_errno("failed to set traceable");
+ }
+ }
+
// Essentially pthread_create without CLONE_FILES, so we still work during file descriptor
// exhaustion.
pid_t child_pid =
@@ -516,6 +532,11 @@
fatal_errno("failed to restore dumpable");
}
+ // Restore PR_SET_PTRACER to its original value.
+ if (restore_orig_ptracer && prctl(PR_SET_PTRACER, 0) != 0) {
+ fatal_errno("failed to restore traceable");
+ }
+
if (info->si_signo == DEBUGGER_SIGNAL) {
// If the signal is fatal, don't unlock the mutex to prevent other crashing threads from
// starting to dump right before our death.
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 624637a..89a125b 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -402,6 +402,10 @@
dump_signal_info(log, thread_info.siginfo);
}
+ if (primary_thread) {
+ dump_abort_message(log, process_memory, abort_msg_address);
+ }
+
dump_registers(log, thread_info.registers.get());
std::vector<backtrace_frame_data_t> frames;
@@ -419,10 +423,6 @@
}
if (primary_thread) {
- dump_abort_message(log, process_memory, abort_msg_address);
- }
-
- if (primary_thread) {
dump_memory_and_code(log, process_memory, thread_info.registers.get());
if (map) {
uintptr_t addr = 0;
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 4b94f9c..a2b80ad 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -38,6 +38,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
+#include <cutils/android_filesystem_config.h>
#include <cutils/android_reboot.h>
#include <cutils/partition_utils.h>
#include <cutils/properties.h>
@@ -353,7 +354,7 @@
reserved_blocks = max_reserved_blocks;
}
- if (ext4_r_blocks_count(sb) == reserved_blocks) {
+ if ((ext4_r_blocks_count(sb) == reserved_blocks) && (sb->s_def_resgid == AID_RESERVED_DISK)) {
return;
}
@@ -363,11 +364,12 @@
return;
}
- char buf[32];
- const char* argv[] = {TUNE2FS_BIN, "-r", buf, blk_device};
-
- snprintf(buf, sizeof(buf), "%" PRIu64, reserved_blocks);
LINFO << "Setting reserved block count on " << blk_device << " to " << reserved_blocks;
+
+ auto reserved_blocks_str = std::to_string(reserved_blocks);
+ auto reserved_gid_str = std::to_string(AID_RESERVED_DISK);
+ const char* argv[] = {
+ TUNE2FS_BIN, "-r", reserved_blocks_str.c_str(), "-g", reserved_gid_str.c_str(), blk_device};
if (!run_tune2fs(argv, ARRAY_SIZE(argv))) {
LERROR << "Failed to run " TUNE2FS_BIN " to set the number of reserved blocks on "
<< blk_device;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 34afed1..1c01d8c 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -638,6 +638,7 @@
* frees up memory of the return value without touching a and b. */
static struct fstab *in_place_merge(struct fstab *a, struct fstab *b)
{
+ if (!a && !b) return nullptr;
if (!a) return b;
if (!b) return a;
@@ -654,12 +655,13 @@
}
for (int i = a->num_entries, j = 0; i < total_entries; i++, j++) {
- // copy the pointer directly *without* malloc and memcpy
+ // Copy the structs by assignment.
a->recs[i] = b->recs[j];
}
- // Frees up b, but don't free b->recs[X] to make sure they are
- // accessible through a->recs[X].
+ // We can't call fs_mgr_free_fstab because a->recs still references the
+ // memory allocated by strdup.
+ free(b->recs);
free(b->fstab_filename);
free(b);
@@ -754,15 +756,17 @@
default_fstab = get_fstab_path();
}
- if (default_fstab.empty()) {
- LWARNING << __FUNCTION__ << "(): failed to find device default fstab";
+ struct fstab* fstab = nullptr;
+ if (!default_fstab.empty()) {
+ fstab = fs_mgr_read_fstab(default_fstab.c_str());
+ } else {
+ LINFO << __FUNCTION__ << "(): failed to find device default fstab";
}
+ struct fstab* fstab_dt = fs_mgr_read_fstab_dt();
+
// combines fstab entries passed in from device tree with
// the ones found from default_fstab file
- struct fstab *fstab_dt = fs_mgr_read_fstab_dt();
- struct fstab *fstab = fs_mgr_read_fstab(default_fstab.c_str());
-
return in_place_merge(fstab_dt, fstab);
}
diff --git a/init/action.cpp b/init/action.cpp
index 5fa6bec..ab51eea 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -358,7 +358,7 @@
Subcontext* action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
- if (StartsWith(filename, subcontext.path_prefix().c_str())) {
+ if (StartsWith(filename, subcontext.path_prefix())) {
action_subcontext = &subcontext;
break;
}
diff --git a/init/devices.cpp b/init/devices.cpp
index af6b50a..8d27f4f 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -127,7 +127,7 @@
}
bool Permissions::Match(const std::string& path) const {
- if (prefix_) return StartsWith(path, name_.c_str());
+ if (prefix_) return StartsWith(path, name_);
if (wildcard_) return fnmatch(name_.c_str(), path.c_str(), FNM_PATHNAME) == 0;
return path == name_;
}
@@ -300,9 +300,9 @@
static const std::string devices_platform_prefix = "/devices/platform/";
static const std::string devices_prefix = "/devices/";
- if (StartsWith(device, devices_platform_prefix.c_str())) {
+ if (StartsWith(device, devices_platform_prefix)) {
device = device.substr(devices_platform_prefix.length());
- } else if (StartsWith(device, devices_prefix.c_str())) {
+ } else if (StartsWith(device, devices_prefix)) {
device = device.substr(devices_prefix.length());
}
diff --git a/init/parser.cpp b/init/parser.cpp
index 6ddb09f..4c69bac 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -76,7 +76,7 @@
// current section parsers. This is meant for /sys/ and /dev/ line entries for
// uevent.
for (const auto& [prefix, callback] : line_callbacks_) {
- if (android::base::StartsWith(args[0], prefix.c_str())) {
+ if (android::base::StartsWith(args[0], prefix)) {
end_section();
if (auto result = callback(std::move(args)); !result) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 4b6c502..7aa94b0 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -58,7 +58,6 @@
#include "init.h"
#include "persistent_properties.h"
-#include "space_tokenizer.h"
#include "util.h"
using android::base::ReadFileToString;
@@ -69,6 +68,7 @@
using android::base::Trim;
using android::base::WriteStringToFile;
using android::properties::BuildTrie;
+using android::properties::ParsePropertyInfoFile;
using android::properties::PropertyInfoAreaFile;
using android::properties::PropertyInfoEntry;
@@ -350,13 +350,15 @@
ufds[0].events = POLLIN;
ufds[0].revents = 0;
while (*timeout_ms > 0) {
- Timer timer;
- int nr = poll(ufds, 1, *timeout_ms);
- uint64_t millis = timer.duration().count();
- *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
+ auto start_time = std::chrono::steady_clock::now();
+ int nr = poll(ufds, 1, *timeout_ms);
+ auto now = std::chrono::steady_clock::now();
+ auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+ uint64_t millis = time_elapsed.count();
+ *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis;
- if (nr > 0) {
- return true;
+ if (nr > 0) {
+ return true;
}
if (nr == 0) {
@@ -726,22 +728,6 @@
return 0;
}
-Result<PropertyInfoEntry> ParsePropertyInfoLine(const std::string& line) {
- auto tokenizer = SpaceTokenizer(line);
-
- auto property = tokenizer.GetNext();
- if (property.empty()) return Error() << "Did not find a property entry in '" << line << "'";
-
- auto context = tokenizer.GetNext();
- if (context.empty()) return Error() << "Did not find a context entry in '" << line << "'";
-
- // It is not an error to not find these, as older files will not contain them.
- auto exact_match = tokenizer.GetNext();
- auto schema = tokenizer.GetRemaining();
-
- return {property, context, schema, exact_match == "exact"};
-}
-
bool LoadPropertyInfoFromFile(const std::string& filename,
std::vector<PropertyInfoEntry>* property_infos) {
auto file_contents = std::string();
@@ -750,20 +736,14 @@
return false;
}
- for (const auto& line : Split(file_contents, "\n")) {
- auto trimmed_line = Trim(line);
- if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) {
- continue;
- }
-
- auto property_info = ParsePropertyInfoLine(line);
- if (!property_info) {
- LOG(ERROR) << "Could not read line from '" << filename << "': " << property_info.error();
- continue;
- }
-
- property_infos->emplace_back(*property_info);
+ auto errors = std::vector<std::string>{};
+ ParsePropertyInfoFile(file_contents, property_infos, &errors);
+ // Individual parsing errors are reported but do not cause a failed boot, which is what
+ // returning false would do here.
+ for (const auto& error : errors) {
+ LOG(ERROR) << "Could not read line from '" << filename << "': " << error;
}
+
return true;
}
diff --git a/init/service.cpp b/init/service.cpp
index 331b859..a4e33f7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -1125,7 +1125,7 @@
Subcontext* restart_action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
- if (StartsWith(filename, subcontext.path_prefix().c_str())) {
+ if (StartsWith(filename, subcontext.path_prefix())) {
restart_action_subcontext = &subcontext;
break;
}
diff --git a/init/space_tokenizer.h b/init/space_tokenizer.h
deleted file mode 100644
index e7e22c5..0000000
--- a/init/space_tokenizer.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 _INIT_SPACE_TOKENIZER_H
-#define _INIT_SPACE_TOKENIZER_H
-
-namespace android {
-namespace init {
-
-class SpaceTokenizer {
- public:
- SpaceTokenizer(const std::string& string)
- : string_(string), it_(string_.begin()), end_(string_.end()) {}
-
- std::string GetNext() {
- auto next = std::string();
- while (it_ != end_ && !isspace(*it_)) {
- next.push_back(*it_++);
- }
- while (it_ != end_ && isspace(*it_)) {
- it_++;
- }
- return next;
- }
-
- std::string GetRemaining() { return std::string(it_, end_); }
-
- private:
- std::string string_;
- std::string::const_iterator it_;
- std::string::const_iterator end_;
-};
-
-} // namespace init
-} // namespace android
-
-#endif
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 9cba109..6d00dc6 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -36,7 +36,7 @@
export_include_dirs: ["include"],
target: {
vendor: {
- export_include_dirs: ["include_vndk"],
+ override_export_include_dirs: ["include_vndk"],
},
linux_bionic: {
enabled: true,
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 2ecf5bc..2f2e262 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -122,6 +122,7 @@
#define AID_AUTOMOTIVE_EVS 1062 /* Automotive rear and surround view system */
#define AID_LOWPAN 1063 /* LoWPAN subsystem */
#define AID_HSM 1064 /* hardware security module subsystem */
+#define AID_RESERVED_DISK 1065 /* GID that has access to reserved disk space */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libcutils/tests/fs_config.cpp b/libcutils/tests/fs_config.cpp
index 391adb6..d5dc66a 100644
--- a/libcutils/tests/fs_config.cpp
+++ b/libcutils/tests/fs_config.cpp
@@ -81,7 +81,7 @@
}
// check if path is <partition>/
- if (android::base::StartsWith(path, prefix.c_str())) {
+ if (android::base::StartsWith(path, prefix)) {
// rebuild path to be system/<partition>/... to check for alias
path = alternate + path.substr(prefix.size());
for (second = 0; second < paths.size(); ++second) {
@@ -97,7 +97,7 @@
}
// check if path is system/<partition>/
- if (android::base::StartsWith(path, alternate.c_str())) {
+ if (android::base::StartsWith(path, alternate)) {
// rebuild path to be <partition>/... to check for alias
path = prefix + path.substr(alternate.size());
for (second = 0; second < paths.size(); ++second) {
diff --git a/liblog/Android.bp b/liblog/Android.bp
index d5bb29e..7d9e306 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -55,7 +55,7 @@
enabled: true,
},
vendor: {
- export_include_dirs: ["include_vndk"],
+ override_export_include_dirs: ["include_vndk"],
},
},
}
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 4b21edc..17983bc 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -19,4 +19,8 @@
"-fvisibility=hidden",
],
export_include_dirs: ["include"],
+ required: [
+ "llndk.libraries.txt",
+ "vndksp.libraries.txt",
+ ],
}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 8c8d064..6ddec4d 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -382,7 +382,7 @@
config_file_path, &sonames,
[&company_name](const std::string& soname, std::string* error_msg) {
if (android::base::StartsWith(soname, "lib") &&
- android::base::EndsWith(soname, ("." + company_name + ".so").c_str())) {
+ android::base::EndsWith(soname, "." + company_name + ".so")) {
return true;
} else {
*error_msg = "Library name \"" + soname +
@@ -662,22 +662,51 @@
return handle;
}
#else
- UNUSED(env, target_sdk_version, class_loader, library_path);
- *needs_native_bridge = false;
- void* handle = dlopen(path, RTLD_NOW);
- if (handle == nullptr) {
- if (NativeBridgeIsSupported(path)) {
- *needs_native_bridge = true;
- handle = NativeBridgeLoadLibrary(path, RTLD_NOW);
- if (handle == nullptr) {
- *error_msg = NativeBridgeGetError();
- }
+ UNUSED(env, target_sdk_version, class_loader);
+
+ // Do some best effort to emulate library-path support. It will not
+ // work for dependencies.
+ //
+ // Note: null has a special meaning and must be preserved.
+ std::string c_library_path; // Empty string by default.
+ if (library_path != nullptr && path != nullptr && path[0] != '/') {
+ ScopedUtfChars library_path_utf_chars(env, library_path);
+ c_library_path = library_path_utf_chars.c_str();
+ }
+
+ std::vector<std::string> library_paths = base::Split(c_library_path, ":");
+
+ for (const std::string& lib_path : library_paths) {
+ *needs_native_bridge = false;
+ const char* path_arg;
+ std::string complete_path;
+ if (path == nullptr) {
+ // Preserve null.
+ path_arg = nullptr;
} else {
- *needs_native_bridge = false;
+ complete_path = lib_path;
+ if (!complete_path.empty()) {
+ complete_path.append("/");
+ }
+ complete_path.append(path);
+ path_arg = complete_path.c_str();
+ }
+ void* handle = dlopen(path_arg, RTLD_NOW);
+ if (handle != nullptr) {
+ return handle;
+ }
+ if (NativeBridgeIsSupported(path_arg)) {
+ *needs_native_bridge = true;
+ handle = NativeBridgeLoadLibrary(path_arg, RTLD_NOW);
+ if (handle != nullptr) {
+ return handle;
+ }
+ *error_msg = NativeBridgeGetError();
+ } else {
*error_msg = dlerror();
}
}
- return handle;
+ return nullptr;
#endif
}
diff --git a/libsuspend/Android.bp b/libsuspend/Android.bp
index 32f1e1f..b3e36c2 100644
--- a/libsuspend/Android.bp
+++ b/libsuspend/Android.bp
@@ -9,11 +9,12 @@
srcs: [
"autosuspend.c",
- "autosuspend_wakeup_count.c",
+ "autosuspend_wakeup_count.cpp",
],
export_include_dirs: ["include"],
local_include_dirs: ["include"],
shared_libs: [
+ "libbase",
"liblog",
"libcutils",
],
diff --git a/libsuspend/autosuspend_ops.h b/libsuspend/autosuspend_ops.h
index 2f435d9..357b828 100644
--- a/libsuspend/autosuspend_ops.h
+++ b/libsuspend/autosuspend_ops.h
@@ -23,6 +23,8 @@
void (*set_wakeup_callback)(void (*func)(bool success));
};
+__BEGIN_DECLS
struct autosuspend_ops *autosuspend_wakeup_count_init(void);
+__END_DECLS
#endif
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
deleted file mode 100644
index 81cb44c..0000000
--- a/libsuspend/autosuspend_wakeup_count.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "libsuspend"
-//#define LOG_NDEBUG 0
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "autosuspend_ops.h"
-
-#define SYS_POWER_STATE "/sys/power/state"
-#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count"
-
-#define BASE_SLEEP_TIME 100000
-
-static int state_fd;
-static int wakeup_count_fd;
-static pthread_t suspend_thread;
-static sem_t suspend_lockout;
-static const char* sleep_state = "mem";
-static void (*wakeup_func)(bool success) = NULL;
-static int sleep_time = BASE_SLEEP_TIME;
-
-static void update_sleep_time(bool success) {
- if (success) {
- sleep_time = BASE_SLEEP_TIME;
- return;
- }
- // double sleep time after each failure up to one minute
- sleep_time = MIN(sleep_time * 2, 60000000);
-}
-
-static void* suspend_thread_func(void* arg __attribute__((unused))) {
- char buf[80];
- char wakeup_count[20];
- int wakeup_count_len;
- int ret;
- bool success = true;
-
- while (1) {
- update_sleep_time(success);
- usleep(sleep_time);
- success = false;
- ALOGV("%s: read wakeup_count", __func__);
- lseek(wakeup_count_fd, 0, SEEK_SET);
- wakeup_count_len = TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count,
- sizeof(wakeup_count)));
- if (wakeup_count_len < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error reading from %s: %s", SYS_POWER_WAKEUP_COUNT, buf);
- wakeup_count_len = 0;
- continue;
- }
- if (!wakeup_count_len) {
- ALOGE("Empty wakeup count");
- continue;
- }
-
- ALOGV("%s: wait", __func__);
- ret = sem_wait(&suspend_lockout);
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error waiting on semaphore: %s", buf);
- continue;
- }
-
- ALOGV("%s: write %*s to wakeup_count", __func__, wakeup_count_len, wakeup_count);
- ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len));
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error writing to %s: %s", SYS_POWER_WAKEUP_COUNT, buf);
- } else {
- ALOGV("%s: write %s to %s", __func__, sleep_state, SYS_POWER_STATE);
- ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state)));
- if (ret >= 0) {
- success = true;
- }
- void (*func)(bool success) = wakeup_func;
- if (func != NULL) {
- (*func)(success);
- }
- }
-
- ALOGV("%s: release sem", __func__);
- ret = sem_post(&suspend_lockout);
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error releasing semaphore: %s", buf);
- }
- }
- return NULL;
-}
-
-static int autosuspend_wakeup_count_enable(void) {
- char buf[80];
- int ret;
-
- ALOGV("autosuspend_wakeup_count_enable");
-
- ret = sem_post(&suspend_lockout);
-
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error changing semaphore: %s", buf);
- }
-
- ALOGV("autosuspend_wakeup_count_enable done");
-
- return ret;
-}
-
-static int autosuspend_wakeup_count_disable(void) {
- char buf[80];
- int ret;
-
- ALOGV("autosuspend_wakeup_count_disable");
-
- ret = sem_wait(&suspend_lockout);
-
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error changing semaphore: %s", buf);
- }
-
- ALOGV("autosuspend_wakeup_count_disable done");
-
- return ret;
-}
-
-static void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
- if (wakeup_func != NULL) {
- ALOGE("Duplicate wakeup callback applied, keeping original");
- return;
- }
- wakeup_func = func;
-}
-
-struct autosuspend_ops autosuspend_wakeup_count_ops = {
- .enable = autosuspend_wakeup_count_enable,
- .disable = autosuspend_wakeup_count_disable,
- .set_wakeup_callback = autosuspend_set_wakeup_callback,
-};
-
-struct autosuspend_ops* autosuspend_wakeup_count_init(void) {
- int ret;
- char buf[80];
-
- state_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_STATE, O_RDWR));
- if (state_fd < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error opening %s: %s", SYS_POWER_STATE, buf);
- goto err_open_state;
- }
-
- wakeup_count_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_WAKEUP_COUNT, O_RDWR));
- if (wakeup_count_fd < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error opening %s: %s", SYS_POWER_WAKEUP_COUNT, buf);
- goto err_open_wakeup_count;
- }
-
- ret = sem_init(&suspend_lockout, 0, 0);
- if (ret < 0) {
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error creating semaphore: %s", buf);
- goto err_sem_init;
- }
- ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
- if (ret) {
- strerror_r(ret, buf, sizeof(buf));
- ALOGE("Error creating thread: %s", buf);
- goto err_pthread_create;
- }
-
- ALOGI("Selected wakeup count");
- return &autosuspend_wakeup_count_ops;
-
-err_pthread_create:
- sem_destroy(&suspend_lockout);
-err_sem_init:
- close(wakeup_count_fd);
-err_open_wakeup_count:
- close(state_fd);
-err_open_state:
- return NULL;
-}
diff --git a/libsuspend/autosuspend_wakeup_count.cpp b/libsuspend/autosuspend_wakeup_count.cpp
new file mode 100644
index 0000000..cfca765
--- /dev/null
+++ b/libsuspend/autosuspend_wakeup_count.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "libsuspend"
+//#define LOG_NDEBUG 0
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+#include "autosuspend_ops.h"
+
+#define BASE_SLEEP_TIME 100000
+#define MAX_SLEEP_TIME 60000000
+
+static int state_fd;
+static int wakeup_count_fd;
+
+using android::base::ReadFdToString;
+using android::base::Trim;
+using android::base::WriteStringToFd;
+
+static pthread_t suspend_thread;
+static sem_t suspend_lockout;
+static const char* sleep_state = "mem";
+static void (*wakeup_func)(bool success) = NULL;
+static int sleep_time = BASE_SLEEP_TIME;
+static constexpr char sys_power_state[] = "/sys/power/state";
+static constexpr char sys_power_wakeup_count[] = "/sys/power/wakeup_count";
+
+static void update_sleep_time(bool success) {
+ if (success) {
+ sleep_time = BASE_SLEEP_TIME;
+ return;
+ }
+ // double sleep time after each failure up to one minute
+ sleep_time = MIN(sleep_time * 2, MAX_SLEEP_TIME);
+}
+
+static void* suspend_thread_func(void* arg __attribute__((unused))) {
+ int ret;
+ bool success = true;
+
+ while (1) {
+ update_sleep_time(success);
+ usleep(sleep_time);
+ success = false;
+ LOG(VERBOSE) << "read wakeup_count";
+ lseek(wakeup_count_fd, 0, SEEK_SET);
+ std::string wakeup_count;
+ if (!ReadFdToString(wakeup_count_fd, &wakeup_count)) {
+ PLOG(ERROR) << "error reading from " << sys_power_wakeup_count;
+ continue;
+ }
+
+ wakeup_count = Trim(wakeup_count);
+ if (wakeup_count.empty()) {
+ LOG(ERROR) << "empty wakeup count";
+ continue;
+ }
+
+ LOG(VERBOSE) << "wait";
+ ret = sem_wait(&suspend_lockout);
+ if (ret < 0) {
+ PLOG(ERROR) << "error waiting on semaphore";
+ continue;
+ }
+
+ LOG(VERBOSE) << "write " << wakeup_count << " to wakeup_count";
+ if (WriteStringToFd(wakeup_count, wakeup_count_fd)) {
+ LOG(VERBOSE) << "write " << sleep_state << " to " << sys_power_state;
+ success = WriteStringToFd(sleep_state, state_fd);
+
+ void (*func)(bool success) = wakeup_func;
+ if (func != NULL) {
+ (*func)(success);
+ }
+ } else {
+ PLOG(ERROR) << "error writing to " << sys_power_wakeup_count;
+ }
+
+ LOG(VERBOSE) << "release sem";
+ ret = sem_post(&suspend_lockout);
+ if (ret < 0) {
+ PLOG(ERROR) << "error releasing semaphore";
+ }
+ }
+ return NULL;
+}
+
+static int autosuspend_wakeup_count_enable(void) {
+ int ret;
+
+ LOG(VERBOSE) << "autosuspend_wakeup_count_enable";
+
+ ret = sem_post(&suspend_lockout);
+
+ if (ret < 0) {
+ PLOG(ERROR) << "error changing semaphore";
+ }
+
+ LOG(VERBOSE) << "autosuspend_wakeup_count_enable done";
+
+ return ret;
+}
+
+static int autosuspend_wakeup_count_disable(void) {
+ int ret;
+
+ LOG(VERBOSE) << "autosuspend_wakeup_count_disable";
+
+ ret = sem_wait(&suspend_lockout);
+
+ if (ret < 0) {
+ PLOG(ERROR) << "error changing semaphore";
+ }
+
+ LOG(VERBOSE) << "autosuspend_wakeup_count_disable done";
+
+ return ret;
+}
+
+static void autosuspend_set_wakeup_callback(void (*func)(bool success)) {
+ if (wakeup_func != NULL) {
+ LOG(ERROR) << "duplicate wakeup callback applied, keeping original";
+ return;
+ }
+ wakeup_func = func;
+}
+
+struct autosuspend_ops autosuspend_wakeup_count_ops = {
+ .enable = autosuspend_wakeup_count_enable,
+ .disable = autosuspend_wakeup_count_disable,
+ .set_wakeup_callback = autosuspend_set_wakeup_callback,
+};
+
+struct autosuspend_ops* autosuspend_wakeup_count_init(void) {
+ int ret;
+
+ state_fd = TEMP_FAILURE_RETRY(open(sys_power_state, O_RDWR));
+ if (state_fd < 0) {
+ PLOG(ERROR) << "error opening " << sys_power_state;
+ goto err_open_state;
+ }
+
+ wakeup_count_fd = TEMP_FAILURE_RETRY(open(sys_power_wakeup_count, O_RDWR));
+ if (wakeup_count_fd < 0) {
+ PLOG(ERROR) << "error opening " << sys_power_wakeup_count;
+ goto err_open_wakeup_count;
+ }
+
+ ret = sem_init(&suspend_lockout, 0, 0);
+ if (ret < 0) {
+ PLOG(ERROR) << "error creating semaphore";
+ goto err_sem_init;
+ }
+ ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
+ if (ret) {
+ LOG(ERROR) << "error creating thread: " << strerror(ret);
+ goto err_pthread_create;
+ }
+
+ LOG(INFO) << "selected wakeup count";
+ return &autosuspend_wakeup_count_ops;
+
+err_pthread_create:
+ sem_destroy(&suspend_lockout);
+err_sem_init:
+ close(wakeup_count_fd);
+err_open_wakeup_count:
+ close(state_fd);
+err_open_state:
+ return NULL;
+}
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index fad899f..133f3b9 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -215,6 +215,15 @@
],
}
+cc_binary {
+ name: "unwind_for_offline",
+ defaults: ["libunwindstack_tools"],
+
+ srcs: [
+ "tools/unwind_for_offline.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 {
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 1f3c6c3..285f879 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -35,10 +35,6 @@
namespace unwindstack {
static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
- struct iovec dst_iov = {
- .iov_base = dst,
- .iov_len = len,
- };
// Split up the remote read across page boundaries.
// From the manpage:
@@ -49,39 +45,49 @@
// perform a partial transfer that splits a single iovec element.
constexpr size_t kMaxIovecs = 64;
struct iovec src_iovs[kMaxIovecs];
- size_t iovecs_used = 0;
uint64_t cur = remote_src;
+ size_t total_read = 0;
while (len > 0) {
- if (iovecs_used == kMaxIovecs) {
- errno = EINVAL;
- return 0;
+ struct iovec dst_iov = {
+ .iov_base = &reinterpret_cast<uint8_t*>(dst)[total_read], .iov_len = len,
+ };
+
+ size_t iovecs_used = 0;
+ while (len > 0) {
+ if (iovecs_used == kMaxIovecs) {
+ break;
+ }
+
+ // struct iovec uses void* for iov_base.
+ if (cur >= UINTPTR_MAX) {
+ errno = EFAULT;
+ return total_read;
+ }
+
+ src_iovs[iovecs_used].iov_base = reinterpret_cast<void*>(cur);
+
+ uintptr_t misalignment = cur & (getpagesize() - 1);
+ size_t iov_len = getpagesize() - misalignment;
+ iov_len = std::min(iov_len, len);
+
+ len -= iov_len;
+ if (__builtin_add_overflow(cur, iov_len, &cur)) {
+ errno = EFAULT;
+ return total_read;
+ }
+
+ src_iovs[iovecs_used].iov_len = iov_len;
+ ++iovecs_used;
}
- // struct iovec uses void* for iov_base.
- if (cur >= UINTPTR_MAX) {
- errno = EFAULT;
- return 0;
+ ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0);
+ if (rc == -1) {
+ return total_read;
}
-
- src_iovs[iovecs_used].iov_base = reinterpret_cast<void*>(cur);
-
- uintptr_t misalignment = cur & (getpagesize() - 1);
- size_t iov_len = getpagesize() - misalignment;
- iov_len = std::min(iov_len, len);
-
- len -= iov_len;
- if (__builtin_add_overflow(cur, iov_len, &cur)) {
- errno = EFAULT;
- return 0;
- }
-
- src_iovs[iovecs_used].iov_len = iov_len;
- ++iovecs_used;
+ total_read += rc;
}
-
- ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0);
- return rc == -1 ? 0 : rc;
+ return total_read;
}
static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index f5492a2..fb56e8a 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -79,6 +79,35 @@
ASSERT_TRUE(Detach(pid));
}
+TEST_F(MemoryRemoteTest, read_large) {
+ static constexpr size_t kTotalPages = 245;
+ std::vector<uint8_t> src(kTotalPages * getpagesize());
+ for (size_t i = 0; i < kTotalPages; i++) {
+ memset(&src[i * getpagesize()], i, getpagesize());
+ }
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ while (true)
+ ;
+ exit(1);
+ }
+ ASSERT_LT(0, pid);
+ TestScopedPidReaper reap(pid);
+
+ ASSERT_TRUE(Attach(pid));
+
+ MemoryRemote remote(pid);
+
+ std::vector<uint8_t> dst(kTotalPages * getpagesize());
+ ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), src.size()));
+ for (size_t i = 0; i < kTotalPages * getpagesize(); i++) {
+ ASSERT_EQ(i / getpagesize(), dst[i]) << "Failed at byte " << i;
+ }
+
+ ASSERT_TRUE(Detach(pid));
+}
+
TEST_F(MemoryRemoteTest, read_partial) {
char* mapping = static_cast<char*>(
mmap(nullptr, 4 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
new file mode 100644
index 0000000..d64ef8f
--- /dev/null
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ */
+
+#define _GNU_SOURCE 1
+#include <errno.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
+
+#include <android-base/stringprintf.h>
+
+struct map_info_t {
+ uint64_t start;
+ uint64_t end;
+ uint64_t offset;
+ std::string name;
+};
+
+static bool Attach(pid_t pid) {
+ if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+ return false;
+ }
+
+ // Allow at least 1 second to attach properly.
+ for (size_t i = 0; i < 1000; i++) {
+ siginfo_t si;
+ if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+ return true;
+ }
+ usleep(1000);
+ }
+ printf("%d: Failed to stop.\n", pid);
+ return false;
+}
+
+bool SaveRegs(unwindstack::Regs* regs) {
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("regs.txt", "w+"), &fclose);
+ if (fp == nullptr) {
+ printf("Failed to create file regs.txt.\n");
+ return false;
+ }
+ regs->IterateRegisters([&fp](const char* name, uint64_t value) {
+ fprintf(fp.get(), "%s: %" PRIx64 "\n", name, value);
+ });
+
+ return true;
+}
+
+bool SaveStack(pid_t pid, uint64_t sp_start, uint64_t sp_end) {
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("stack.data", "w+"), &fclose);
+ if (fp == nullptr) {
+ printf("Failed to create stack.data.\n");
+ return false;
+ }
+
+ size_t bytes = fwrite(&sp_start, 1, sizeof(sp_start), fp.get());
+ if (bytes != sizeof(sp_start)) {
+ perror("Failed to write all data.");
+ return false;
+ }
+
+ std::vector<uint8_t> buffer(sp_end - sp_start);
+ auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
+ if (!process_memory->Read(sp_start, buffer.data(), buffer.size())) {
+ printf("Unable to read stack data.\n");
+ return false;
+ }
+
+ bytes = fwrite(buffer.data(), 1, buffer.size(), fp.get());
+ if (bytes != buffer.size()) {
+ printf("Failed to write all stack data: stack size %zu, written %zu\n", buffer.size(), bytes);
+ return 1;
+ }
+
+ return true;
+}
+
+bool CreateElfFromMemory(std::shared_ptr<unwindstack::Memory>& memory, map_info_t* info) {
+ std::string cur_name;
+ if (info->name.empty()) {
+ cur_name = android::base::StringPrintf("anonymous:%" PRIx64, info->start);
+ } else {
+ cur_name = basename(info->name.c_str());
+ cur_name = android::base::StringPrintf("%s:%" PRIx64, basename(info->name.c_str()), info->start);
+ }
+
+ std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
+ if (output == nullptr) {
+ printf("Cannot create %s\n", cur_name.c_str());
+ return false;
+ }
+ std::vector<uint8_t> buffer(info->end - info->start);
+ // If this is a mapped in file, it might not be possible to read the entire
+ // map, so read all that is readable.
+ size_t bytes = memory->Read(info->start, buffer.data(), buffer.size());
+ if (bytes == 0) {
+ printf("Cannot read data from address %" PRIx64 " length %zu\n", info->start, buffer.size());
+ return false;
+ }
+ size_t bytes_written = fwrite(buffer.data(), 1, bytes, output.get());
+ if (bytes_written != bytes) {
+ printf("Failed to write all data to file: bytes read %zu, written %zu\n", bytes, bytes_written);
+ return false;
+ }
+
+ // Replace the name with the new name.
+ info->name = cur_name;
+
+ return true;
+}
+
+bool CopyElfFromFile(map_info_t* info) {
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(info->name.c_str(), "r"), &fclose);
+ if (fp == nullptr) {
+ return false;
+ }
+
+ std::string cur_name = basename(info->name.c_str());
+ std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
+ if (output == nullptr) {
+ printf("Cannot create file %s\n", cur_name.c_str());
+ return false;
+ }
+ std::vector<uint8_t> buffer(10000);
+ size_t bytes;
+ while ((bytes = fread(buffer.data(), 1, buffer.size(), fp.get())) > 0) {
+ size_t bytes_written = fwrite(buffer.data(), 1, bytes, output.get());
+ if (bytes_written != bytes) {
+ printf("Bytes written doesn't match bytes read: read %zu, written %zu\n", bytes,
+ bytes_written);
+ return false;
+ }
+ }
+
+ // Replace the name with the new name.
+ info->name = cur_name;
+
+ return true;
+}
+
+int SaveData(pid_t pid) {
+ unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid);
+ if (regs == nullptr) {
+ printf("Unable to get remote reg data.\n");
+ return 1;
+ }
+
+ unwindstack::RemoteMaps maps(pid);
+ if (!maps.Parse()) {
+ printf("Unable to parse maps.\n");
+ return 1;
+ }
+
+ // Save the current state of the registers.
+ if (!SaveRegs(regs)) {
+ return 1;
+ }
+
+ // Do an unwind so we know how much of the stack to save, and what
+ // elf files are involved.
+ uint64_t sp = regs->sp();
+ auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
+ unwindstack::Unwinder unwinder(1024, &maps, regs, process_memory);
+ unwinder.Unwind();
+
+ std::unordered_map<uint64_t, map_info_t> maps_by_start;
+ uint64_t last_sp;
+ for (auto frame : unwinder.frames()) {
+ last_sp = frame.sp;
+ if (maps_by_start.count(frame.map_start) == 0) {
+ auto info = &maps_by_start[frame.map_start];
+ info->start = frame.map_start;
+ info->end = frame.map_end;
+ info->offset = frame.map_offset;
+ info->name = frame.map_name;
+ if (!CopyElfFromFile(info)) {
+ // Try to create the elf from memory, this will handle cases where
+ // the data only exists in memory such as vdso data on x86.
+ if (!CreateElfFromMemory(process_memory, info)) {
+ return 1;
+ }
+ }
+ }
+ }
+
+ if (!SaveStack(pid, sp, last_sp)) {
+ return 1;
+ }
+
+ std::vector<std::pair<uint64_t, map_info_t>> sorted_maps(maps_by_start.begin(),
+ maps_by_start.end());
+ std::sort(sorted_maps.begin(), sorted_maps.end(),
+ [](auto& a, auto& b) { return a.first < b.first; });
+
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("maps.txt", "w+"), &fclose);
+ if (fp == nullptr) {
+ printf("Failed to create maps.txt.\n");
+ return false;
+ }
+
+ for (auto& element : sorted_maps) {
+ map_info_t& map = element.second;
+ fprintf(fp.get(), "%" PRIx64 "-%" PRIx64 " r-xp %" PRIx64 " 00:00 0", map.start, map.end,
+ map.offset);
+ if (!map.name.empty()) {
+ fprintf(fp.get(), " %s", map.name.c_str());
+ }
+ fprintf(fp.get(), "\n");
+ }
+
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ printf("Usage: unwind_for_offline <PID>\n");
+ return 1;
+ }
+
+ pid_t pid = atoi(argv[1]);
+ if (!Attach(pid)) {
+ printf("Failed to attach to pid %d: %s\n", pid, strerror(errno));
+ return 1;
+ }
+
+ int return_code = SaveData(pid);
+
+ ptrace(PTRACE_DETACH, pid, 0, 0);
+
+ return return_code;
+}
diff --git a/libusbhost/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h
index a8dd673..9758b18 100644
--- a/libusbhost/include/usbhost/usbhost.h
+++ b/libusbhost/include/usbhost/usbhost.h
@@ -140,8 +140,26 @@
const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device);
/* Returns a USB descriptor string for the given string ID.
+ * Return value: < 0 on error. 0 on success.
+ * The string is returned in ucs2_out in USB-native UCS-2 encoding.
+ *
+ * parameters:
+ * id - the string descriptor index.
+ * timeout - in milliseconds (see Documentation/driver-api/usb/usb.rst)
+ * ucs2_out - Must point to null on call.
+ * Will be filled in with a buffer on success.
+ * If this is non-null on return, it must be free()d.
+ * response_size - size, in bytes, of ucs-2 string in ucs2_out.
+ * The size isn't guaranteed to include null termination.
+ * Call free() to free the result when you are done with it.
+ */
+int usb_device_get_string_ucs2(struct usb_device* device, int id, int timeout, void** ucs2_out,
+ size_t* response_size);
+
+/* Returns a USB descriptor string for the given string ID.
* Used to implement usb_device_get_manufacturer_name,
* usb_device_get_product_name and usb_device_get_serial.
+ * Returns ascii - non ascii characters will be replaced with '?'.
* Call free() to free the result when you are done with it.
*/
char* usb_device_get_string(struct usb_device *device, int id, int timeout);
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 4d286bf..fa0191b 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -464,17 +464,30 @@
return (struct usb_device_descriptor*)device->desc;
}
-char* usb_device_get_string(struct usb_device *device, int id, int timeout)
-{
- char string[256];
- __u16 buffer[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
+/* Returns a USB descriptor string for the given string ID.
+ * Return value: < 0 on error. 0 on success.
+ * The string is returned in ucs2_out in USB-native UCS-2 encoding.
+ *
+ * parameters:
+ * id - the string descriptor index.
+ * timeout - in milliseconds (see Documentation/driver-api/usb/usb.rst)
+ * ucs2_out - Must point to null on call.
+ * Will be filled in with a buffer on success.
+ * If this is non-null on return, it must be free()d.
+ * response_size - size, in bytes, of ucs-2 string in ucs2_out.
+ * The size isn't guaranteed to include null termination.
+ * Call free() to free the result when you are done with it.
+ */
+int usb_device_get_string_ucs2(struct usb_device* device, int id, int timeout, void** ucs2_out,
+ size_t* response_size) {
__u16 languages[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
- int i, result;
+ char response[MAX_STRING_DESCRIPTOR_LENGTH];
+ int result;
int languageCount = 0;
- if (id == 0) return NULL;
+ if (id == 0) return -1;
+ if (*ucs2_out != NULL) return -1;
- string[0] = 0;
memset(languages, 0, sizeof(languages));
// read list of supported languages
@@ -485,25 +498,54 @@
if (result > 0)
languageCount = (result - 2) / 2;
- for (i = 1; i <= languageCount; i++) {
- memset(buffer, 0, sizeof(buffer));
+ for (int i = 1; i <= languageCount; i++) {
+ memset(response, 0, sizeof(response));
- result = usb_device_control_transfer(device,
- USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
- (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer),
- timeout);
- if (result > 0) {
- int i;
- // skip first word, and copy the rest to the string, changing shorts to bytes.
- result /= 2;
- for (i = 1; i < result; i++)
- string[i - 1] = buffer[i];
- string[i - 1] = 0;
- return strdup(string);
+ result = usb_device_control_transfer(
+ device, USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) | id, languages[i], response, sizeof(response), timeout);
+ if (result >= 2) { // string contents begin at offset 2.
+ int descriptor_len = result - 2;
+ char* out = malloc(descriptor_len + 3);
+ if (out == NULL) {
+ return -1;
+ }
+ memcpy(out, response + 2, descriptor_len);
+ // trail with three additional NULLs, so that there's guaranteed
+ // to be a UCS-2 NULL character beyond whatever USB returned.
+ // The returned string length is still just what USB returned.
+ memset(out + descriptor_len, '\0', 3);
+ *ucs2_out = (void*)out;
+ *response_size = descriptor_len;
+ return 0;
}
}
+ return -1;
+}
- return NULL;
+/* Warning: previously this blindly returned the lower 8 bits of
+ * every UCS-2 character in a USB descriptor. Now it will replace
+ * values > 127 with ascii '?'.
+ */
+char* usb_device_get_string(struct usb_device* device, int id, int timeout) {
+ char* ascii_string = NULL;
+ size_t raw_string_len = 0;
+ size_t i;
+ if (usb_device_get_string_ucs2(device, id, timeout, (void**)&ascii_string, &raw_string_len) < 0)
+ return NULL;
+ if (ascii_string == NULL) return NULL;
+ for (i = 0; i < raw_string_len / 2; ++i) {
+ // wire format for USB is always little-endian.
+ char lower = ascii_string[2 * i];
+ char upper = ascii_string[2 * i + 1];
+ if (upper || (lower & 0x80)) {
+ ascii_string[i] = '?';
+ } else {
+ ascii_string[i] = lower;
+ }
+ }
+ ascii_string[i] = '\0';
+ return ascii_string;
}
char* usb_device_get_manufacturer_name(struct usb_device *device, int timeout)
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 5ccbcc2..f9f8c73 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -783,12 +783,12 @@
// block device).
//
// Returns a valid FileWriter on success, |nullptr| if an error occurred.
- static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
+ static FileWriter Create(int fd, const ZipEntry* entry) {
const uint32_t declared_length = entry->uncompressed_length;
const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
if (current_offset == -1) {
ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno));
- return nullptr;
+ return FileWriter{};
}
int result = 0;
@@ -808,7 +808,7 @@
ALOGW("Zip: unable to allocate %" PRId64 " bytes at offset %" PRId64 ": %s",
static_cast<int64_t>(declared_length), static_cast<int64_t>(current_offset),
strerror(errno));
- return std::unique_ptr<FileWriter>(nullptr);
+ return FileWriter{};
}
}
#endif // __linux__
@@ -816,7 +816,7 @@
struct stat sb;
if (fstat(fd, &sb) == -1) {
ALOGW("Zip: unable to fstat file: %s", strerror(errno));
- return std::unique_ptr<FileWriter>(nullptr);
+ return FileWriter{};
}
// Block device doesn't support ftruncate(2).
@@ -825,13 +825,22 @@
if (result == -1) {
ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
static_cast<int64_t>(declared_length + current_offset), strerror(errno));
- return std::unique_ptr<FileWriter>(nullptr);
+ return FileWriter{};
}
}
- return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
+ return FileWriter(fd, declared_length);
}
+ FileWriter(FileWriter&& other)
+ : fd_(other.fd_),
+ declared_length_(other.declared_length_),
+ total_bytes_written_(other.total_bytes_written_) {
+ other.fd_ = -1;
+ }
+
+ bool IsValid() const { return fd_ != -1; }
+
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_,
@@ -850,10 +859,10 @@
}
private:
- FileWriter(const int fd, const size_t declared_length)
+ explicit FileWriter(const int fd = -1, const size_t declared_length = 0)
: Writer(), fd_(fd), declared_length_(declared_length), total_bytes_written_(0) {}
- const int fd_;
+ int fd_;
const size_t declared_length_;
size_t total_bytes_written_;
};
@@ -1066,17 +1075,17 @@
}
int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size) {
- std::unique_ptr<zip_archive::Writer> writer(new MemoryWriter(begin, size));
- return ExtractToWriter(handle, entry, writer.get());
+ MemoryWriter writer(begin, size);
+ return ExtractToWriter(handle, entry, &writer);
}
int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd) {
- std::unique_ptr<zip_archive::Writer> writer(FileWriter::Create(fd, entry));
- if (writer.get() == nullptr) {
+ auto writer = FileWriter::Create(fd, entry);
+ if (!writer.IsValid()) {
return kIoError;
}
- return ExtractToWriter(handle, entry, writer.get());
+ return ExtractToWriter(handle, entry, &writer);
}
const char* ErrorCodeString(int32_t error_code) {
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index cb72f0e..ad673dc 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -64,11 +64,6 @@
return OpenArchive(abs_path.c_str(), handle);
}
-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));
-}
-
static void SetZipString(ZipString* zip_str, const std::string& str) {
zip_str->name = reinterpret_cast<const uint8_t*>(str.c_str());
zip_str->name_length = str.size();
@@ -117,132 +112,60 @@
close(fd);
}
-TEST(ziparchive, Iteration) {
+static void AssertIterationOrder(const ZipString* prefix, const ZipString* suffix,
+ const std::vector<std::string>& expected_names_sorted) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
void* iteration_cookie;
- ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
+ ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, prefix, suffix));
ZipEntry data;
+ std::vector<std::string> names;
+
ZipString name;
-
- // b/c.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b/c.txt", name);
-
- // b/d.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b/d.txt", name);
-
- // a.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("a.txt", name);
-
- // b.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b.txt", name);
-
- // b/
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b/", name);
+ for (size_t i = 0; i < expected_names_sorted.size(); ++i) {
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ names.push_back(std::string(reinterpret_cast<const char*>(name.name), name.name_length));
+ }
// End of iteration.
ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
-
CloseArchive(handle);
+
+ // Assert that the names are as expected.
+ std::sort(names.begin(), names.end());
+ ASSERT_EQ(expected_names_sorted, names);
+}
+
+TEST(ziparchive, Iteration) {
+ static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b.txt", "b/", "b/c.txt",
+ "b/d.txt"};
+
+ AssertIterationOrder(nullptr, nullptr, kExpectedMatchesSorted);
}
TEST(ziparchive, IterationWithPrefix) {
- ZipArchiveHandle handle;
- ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
- void* iteration_cookie;
ZipString prefix("b/");
- ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, nullptr));
+ static const std::vector<std::string> kExpectedMatchesSorted = {"b/", "b/c.txt", "b/d.txt"};
- ZipEntry data;
- ZipString name;
-
- // b/c.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b/c.txt", name);
-
- // b/d.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b/d.txt", name);
-
- // b/
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b/", name);
-
- // End of iteration.
- ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
-
- CloseArchive(handle);
+ AssertIterationOrder(&prefix, nullptr, kExpectedMatchesSorted);
}
TEST(ziparchive, IterationWithSuffix) {
- ZipArchiveHandle handle;
- ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
- void* iteration_cookie;
ZipString suffix(".txt");
- ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, &suffix));
+ static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b.txt", "b/c.txt",
+ "b/d.txt"};
- ZipEntry data;
- ZipString name;
-
- // b/c.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b/c.txt", name);
-
- // b/d.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b/d.txt", name);
-
- // a.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("a.txt", name);
-
- // b.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b.txt", name);
-
- // End of iteration.
- ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
-
- CloseArchive(handle);
+ AssertIterationOrder(nullptr, &suffix, kExpectedMatchesSorted);
}
TEST(ziparchive, IterationWithPrefixAndSuffix) {
- ZipArchiveHandle handle;
- ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
-
- void* iteration_cookie;
ZipString prefix("b");
ZipString suffix(".txt");
- ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
+ static const std::vector<std::string> kExpectedMatchesSorted = {"b.txt", "b/c.txt", "b/d.txt"};
- ZipEntry data;
- ZipString name;
-
- // b/c.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b/c.txt", name);
-
- // b/d.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b/d.txt", name);
-
- // b.txt
- ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
- AssertNameEquals("b.txt", name);
-
- // End of iteration.
- ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
-
- CloseArchive(handle);
+ AssertIterationOrder(&prefix, &suffix, kExpectedMatchesSorted);
}
TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
@@ -664,10 +587,11 @@
// an entry whose name is "name" and whose size is 12 (contents =
// "abdcdefghijk").
ZipEntry entry;
- ZipString empty_name;
- SetZipString(&empty_name, "name");
+ ZipString name;
+ std::string name_str = "name";
+ SetZipString(&name, name_str);
- ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
+ ASSERT_EQ(0, FindEntry(handle, name, &entry));
ASSERT_EQ(static_cast<uint32_t>(12), entry.uncompressed_length);
entry_out->resize(12);
@@ -687,7 +611,7 @@
ASSERT_EQ('k', entry[11]);
}
-TEST(ziparchive, InvalidDataDescriptors) {
+TEST(ziparchive, InvalidDataDescriptors_csize) {
std::vector<uint8_t> invalid_csize = kDataDescriptorZipFile;
invalid_csize[kCSizeOffset] = 0xfe;
@@ -696,13 +620,15 @@
ExtractEntryToMemory(invalid_csize, &entry, &error_code);
ASSERT_EQ(kInconsistentInformation, error_code);
+}
+TEST(ziparchive, InvalidDataDescriptors_size) {
std::vector<uint8_t> invalid_size = kDataDescriptorZipFile;
- invalid_csize[kSizeOffset] = 0xfe;
+ invalid_size[kSizeOffset] = 0xfe;
- error_code = 0;
- entry.clear();
- ExtractEntryToMemory(invalid_csize, &entry, &error_code);
+ std::vector<uint8_t> entry;
+ int32_t error_code = 0;
+ ExtractEntryToMemory(invalid_size, &entry, &error_code);
ASSERT_EQ(kInconsistentInformation, error_code);
}
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 5cfa2c8..fd83ecc 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -900,7 +900,9 @@
downgrade_pressure = (int64_t)property_get_int32("ro.lmk.downgrade_pressure", 60);
is_go_device = property_get_bool("ro.config.low_ram", false);
- mlockall(MCL_FUTURE);
+ if (mlockall(MCL_CURRENT | MCL_FUTURE))
+ ALOGW("mlockall failed: errno=%d", errno);
+
sched_setscheduler(0, SCHED_FIFO, ¶m);
if (!init())
mainloop();
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 1d0cc33..b76160d 100755
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -45,7 +45,7 @@
'0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>'
LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg)
- : SocketListener(mSock = getLogSocket(), false),
+ : SocketListener(getLogSocket(), false),
logbuf(buf),
reader(reader),
fdDmesg(fdDmesg),
@@ -53,8 +53,7 @@
BOOL_DEFAULT_TRUE)),
events(__android_logger_property_get_bool("ro.logd.auditd.events",
BOOL_DEFAULT_TRUE)),
- initialized(false),
- tooFast(false) {
+ initialized(false) {
static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
'l',
'o',
@@ -78,54 +77,12 @@
write(fdDmesg, auditd_message, sizeof(auditd_message));
}
-void LogAudit::checkRateLimit() {
- // trim list for AUDIT_RATE_LIMIT_BURST_DURATION of history
- log_time oldest(AUDIT_RATE_LIMIT_BURST_DURATION, 0);
- bucket.emplace(android_log_clockid());
- oldest = bucket.back() - oldest;
- while (bucket.front() < oldest) bucket.pop();
-
- static const size_t upperThreshold =
- ((AUDIT_RATE_LIMIT_BURST_DURATION *
- (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
- 1) /
- 2;
- if (bucket.size() >= upperThreshold) {
- // Hit peak, slow down source
- if (!tooFast) {
- tooFast = true;
- audit_rate_limit(mSock, AUDIT_RATE_LIMIT_MAX);
- }
-
- // We do not need to hold on to the full set of timing data history,
- // let's ensure it does not grow without bounds. This also ensures
- // that std::dequeue underneath behaves almost like a ring buffer.
- do {
- bucket.pop();
- } while (bucket.size() >= upperThreshold);
- return;
- }
-
- if (!tooFast) return;
-
- static const size_t lowerThreshold =
- AUDIT_RATE_LIMIT_BURST_DURATION * AUDIT_RATE_LIMIT_MAX;
-
- if (bucket.size() >= lowerThreshold) return;
-
- tooFast = false;
- // Went below max sustained rate, allow source to speed up
- audit_rate_limit(mSock, AUDIT_RATE_LIMIT_DEFAULT);
-}
-
bool LogAudit::onDataAvailable(SocketClient* cli) {
if (!initialized) {
prctl(PR_SET_NAME, "logd.auditd");
initialized = true;
}
- checkRateLimit();
-
struct audit_message rep;
rep.nlh.nlmsg_type = 0;
@@ -486,6 +443,5 @@
audit_close(fd);
fd = -1;
}
- (void)audit_rate_limit(fd, AUDIT_RATE_LIMIT_DEFAULT);
return fd;
}
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 2bd02d4..5904966 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -18,7 +18,6 @@
#define _LOGD_LOG_AUDIT_H__
#include <map>
-#include <queue>
#include <sysutils/SocketListener.h>
@@ -34,11 +33,6 @@
bool events;
bool initialized;
- bool tooFast;
- int mSock;
- std::queue<log_time> bucket;
- void checkRateLimit();
-
public:
LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg);
int log(char* buf, size_t len);
diff --git a/logd/libaudit.c b/logd/libaudit.c
index dfd56f2..9d9a857 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -160,7 +160,8 @@
* and the the mask set to AUDIT_STATUS_PID
*/
status.pid = pid;
- status.mask = AUDIT_STATUS_PID;
+ status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
+ status.rate_limit = AUDIT_RATE_LIMIT; /* audit entries per second */
/* Let the kernel know this pid will be registering for audit events */
rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
@@ -183,26 +184,6 @@
return 0;
}
-int audit_rate_limit(int fd, unsigned rate_limit) {
- int rc;
- struct audit_message rep;
- struct audit_status status;
-
- memset(&status, 0, sizeof(status));
-
- status.mask = AUDIT_STATUS_RATE_LIMIT;
- status.rate_limit = rate_limit; /* audit entries per second */
-
- rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
- if (rc < 0) {
- return rc;
- }
-
- audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
-
- return 0;
-}
-
int audit_open() {
return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
}
diff --git a/logd/libaudit.h b/logd/libaudit.h
index a2afe47..2a93ea3 100644
--- a/logd/libaudit.h
+++ b/logd/libaudit.h
@@ -89,22 +89,8 @@
*/
extern int audit_setup(int fd, pid_t pid);
-/**
- * Sets the rate limit to receive audit netlink events from the kernel
- * @param fd
- * The fd returned by a call to audit_open()
- * @param max_rate
- * The cap of the maximum number of audit messages a second
- * @return
- * This function returns 0 on success, -errno on error.
- */
-
-/* Guidelines to follow for dynamic rate_limit */
-#define AUDIT_RATE_LIMIT_DEFAULT 20 /* acceptable burst rate */
-#define AUDIT_RATE_LIMIT_BURST_DURATION 10 /* number of seconds of burst */
-#define AUDIT_RATE_LIMIT_MAX 5 /* acceptable sustained rate */
-
-extern int audit_rate_limit(int fd, unsigned rate_limit);
+/* Max audit messages per second */
+#define AUDIT_RATE_LIMIT 5
__END_DECLS
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 9e1541b..7d7a22f 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -1195,51 +1195,14 @@
<< "fail as this device is in a bad state, "
<< "but is not strictly a unit test failure.";
}
- // sepolicy_rate_limiter_maximum
- { // maximum precharch test block.
- static constexpr int rate = AUDIT_RATE_LIMIT_MAX;
- static constexpr int duration = 2;
- // Two seconds of a liveable sustained rate
- EXPECT_EQ(rate * duration,
- count_avc(sepolicy_rate(rate, rate * duration)));
- }
- // sepolicy_rate_limiter_sub_burst
- { // maximum period below half way between sustainable and burst rate
- static constexpr int threshold =
- ((AUDIT_RATE_LIMIT_BURST_DURATION *
- (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
- 1) /
- 2;
- static constexpr int rate =
- (threshold / AUDIT_RATE_LIMIT_BURST_DURATION) - 1;
- static constexpr int duration = AUDIT_RATE_LIMIT_BURST_DURATION;
- EXPECT_EQ(rate * duration,
- count_avc(sepolicy_rate(rate, rate * duration)));
- }
- // sepolicy_rate_limiter_spam
- { // hit avc: hard beyond reason block.
- // maximum period of double the maximum burst rate
- static constexpr int threshold =
- ((AUDIT_RATE_LIMIT_BURST_DURATION *
- (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
- 1) /
- 2;
- static constexpr int rate = AUDIT_RATE_LIMIT_DEFAULT * 2;
- static constexpr int duration = threshold / AUDIT_RATE_LIMIT_DEFAULT;
- EXPECT_GE(
- ((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) / 100, // +15% margin
- count_avc(sepolicy_rate(rate, rate * duration)));
- // give logd another 3 seconds to react to the burst before checking
- sepolicy_rate(rate, rate * 3);
- // maximum period at double maximum burst rate (spam filter kicked in)
- EXPECT_GE(threshold * 2,
- count_avc(sepolicy_rate(
- rate, rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
- // cool down, and check unspammy rate still works
- sleep(2);
- EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ lost
- count_avc(sepolicy_rate(1, AUDIT_RATE_LIMIT_BURST_DURATION)));
- }
+
+ static const int rate = AUDIT_RATE_LIMIT;
+ static const int duration = 2;
+ // Two seconds of sustained denials. Depending on the overlap in the time
+ // window that the kernel is considering vs what this test is considering,
+ // allow some additional denials to prevent a flaky test.
+ EXPECT_LE(count_avc(sepolicy_rate(rate, rate * duration)),
+ rate * duration + rate);
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/property_service/OWNERS b/property_service/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/property_service/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/property_service/libpropertyinfoparser/Android.bp b/property_service/libpropertyinfoparser/Android.bp
index 3e732b5..e0cd30c 100644
--- a/property_service/libpropertyinfoparser/Android.bp
+++ b/property_service/libpropertyinfoparser/Android.bp
@@ -1,10 +1,16 @@
cc_library_static {
name: "libpropertyinfoparser",
+ host_supported: true,
+ vendor_available: true,
srcs: ["property_info_parser.cpp"],
cpp_std: "experimental",
- sanitize: {
- misc_undefined: ["signed-integer-overflow"],
+ target: {
+ linux: {
+ sanitize: {
+ misc_undefined: ["signed-integer-overflow"],
+ },
+ },
},
cppflags: [
"-Wall",
diff --git a/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h b/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h
index 8c3507e..2ee8161 100644
--- a/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h
+++ b/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h
@@ -18,6 +18,7 @@
#define PROPERTY_INFO_PARSER_H
#include <stdint.h>
+#include <stdlib.h>
namespace android {
namespace properties {
diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp
index 20e5e13..5de7477 100644
--- a/property_service/libpropertyinfoserializer/Android.bp
+++ b/property_service/libpropertyinfoserializer/Android.bp
@@ -1,8 +1,14 @@
cc_defaults {
name: "propertyinfoserializer_defaults",
+ host_supported: true,
+ vendor_available: true,
cpp_std: "experimental",
- sanitize: {
- misc_undefined: ["signed-integer-overflow"],
+ target: {
+ linux: {
+ sanitize: {
+ misc_undefined: ["signed-integer-overflow"],
+ },
+ },
},
cppflags: [
"-Wall",
@@ -19,6 +25,7 @@
name: "libpropertyinfoserializer",
defaults: ["propertyinfoserializer_defaults"],
srcs: [
+ "property_info_file.cpp",
"property_info_serializer.cpp",
"trie_builder.cpp",
"trie_serializer.cpp",
diff --git a/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h b/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
index f7e708e..d2ec385 100644
--- a/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
+++ b/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
@@ -41,6 +41,10 @@
const std::string& default_context, const std::string& default_schema,
std::string* serialized_trie, std::string* error);
+void ParsePropertyInfoFile(const std::string& file_contents,
+ std::vector<PropertyInfoEntry>* property_infos,
+ std::vector<std::string>* errors);
+
} // namespace properties
} // namespace android
diff --git a/property_service/libpropertyinfoserializer/property_info_file.cpp b/property_service/libpropertyinfoserializer/property_info_file.cpp
new file mode 100644
index 0000000..702f219
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/property_info_file.cpp
@@ -0,0 +1,62 @@
+#include <property_info_serializer/property_info_serializer.h>
+
+#include <android-base/strings.h>
+
+#include "space_tokenizer.h"
+
+using android::base::Split;
+using android::base::StartsWith;
+using android::base::Trim;
+
+namespace android {
+namespace properties {
+
+bool ParsePropertyInfoLine(const std::string& line, PropertyInfoEntry* out, std::string* error) {
+ auto tokenizer = SpaceTokenizer(line);
+
+ auto property = tokenizer.GetNext();
+ if (property.empty()) {
+ *error = "Did not find a property entry in '" + line + "'";
+ return false;
+ }
+
+ auto context = tokenizer.GetNext();
+ if (context.empty()) {
+ *error = "Did not find a context entry in '" + line + "'";
+ return false;
+ }
+
+ // It is not an error to not find these, as older files will not contain them.
+ auto exact_match = tokenizer.GetNext();
+ auto schema = tokenizer.GetRemaining();
+
+ *out = {property, context, schema, exact_match == "exact"};
+ return true;
+}
+
+void ParsePropertyInfoFile(const std::string& file_contents,
+ std::vector<PropertyInfoEntry>* property_infos,
+ std::vector<std::string>* errors) {
+ // Do not clear property_infos to allow this function to be called on multiple files, with
+ // their results concatenated.
+ errors->clear();
+
+ for (const auto& line : Split(file_contents, "\n")) {
+ auto trimmed_line = Trim(line);
+ if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) {
+ continue;
+ }
+
+ auto property_info_entry = PropertyInfoEntry{};
+ auto parse_error = std::string{};
+ if (!ParsePropertyInfoLine(trimmed_line, &property_info_entry, &parse_error)) {
+ errors->emplace_back(parse_error);
+ continue;
+ }
+
+ property_infos->emplace_back(property_info_entry);
+ }
+}
+
+} // namespace properties
+} // namespace android
diff --git a/property_service/libpropertyinfoserializer/space_tokenizer.h b/property_service/libpropertyinfoserializer/space_tokenizer.h
new file mode 100644
index 0000000..fba0c58
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/space_tokenizer.h
@@ -0,0 +1,50 @@
+/*
+ * 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 PROPERTY_INFO_SERIALIZER_SPACE_TOKENIZER_H
+#define PROPERTY_INFO_SERIALIZER_SPACE_TOKENIZER_H
+
+namespace android {
+namespace properties {
+
+class SpaceTokenizer {
+ public:
+ SpaceTokenizer(const std::string& string)
+ : string_(string), it_(string_.begin()), end_(string_.end()) {}
+
+ std::string GetNext() {
+ auto next = std::string();
+ while (it_ != end_ && !isspace(*it_)) {
+ next.push_back(*it_++);
+ }
+ while (it_ != end_ && isspace(*it_)) {
+ it_++;
+ }
+ return next;
+ }
+
+ std::string GetRemaining() { return std::string(it_, end_); }
+
+ private:
+ std::string string_;
+ std::string::const_iterator it_;
+ std::string::const_iterator end_;
+};
+
+} // namespace properties
+} // namespace android
+
+#endif
diff --git a/property_service/property_info_checker/Android.bp b/property_service/property_info_checker/Android.bp
new file mode 100644
index 0000000..6e9e7f1
--- /dev/null
+++ b/property_service/property_info_checker/Android.bp
@@ -0,0 +1,19 @@
+cc_binary {
+ name: "property_info_checker",
+ host_supported: true,
+ static_executable: true,
+ cpp_std: "experimental",
+ target: {
+ linux: {
+ sanitize: {
+ misc_undefined: ["signed-integer-overflow"],
+ },
+ },
+ },
+ static_libs: [
+ "libpropertyinfoserializer",
+ "libpropertyinfoparser",
+ "libbase",
+ ],
+ srcs: ["property_info_checker.cpp"],
+}
diff --git a/property_service/property_info_checker/property_info_checker.cpp b/property_service/property_info_checker/property_info_checker.cpp
new file mode 100644
index 0000000..e4f8264
--- /dev/null
+++ b/property_service/property_info_checker/property_info_checker.cpp
@@ -0,0 +1,51 @@
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+
+#include <property_info_serializer/property_info_serializer.h>
+
+using android::base::ReadFileToString;
+using android::properties::BuildTrie;
+using android::properties::ParsePropertyInfoFile;
+using android::properties::PropertyInfoEntry;
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ std::cerr << "A list of property info files to be checked is expected on the command line"
+ << std::endl;
+ return -1;
+ }
+
+ auto property_info_entries = std::vector<PropertyInfoEntry>{};
+
+ for (int i = 1; i < argc; ++i) {
+ auto filename = argv[i];
+ auto file_contents = std::string{};
+ if (!ReadFileToString(filename, &file_contents)) {
+ std::cerr << "Could not read properties from '" << filename << "'" << std::endl;
+ return -1;
+ }
+
+ auto errors = std::vector<std::string>{};
+ ParsePropertyInfoFile(file_contents, &property_info_entries, &errors);
+ if (!errors.empty()) {
+ for (const auto& error : errors) {
+ std::cerr << "Could not read line from '" << filename << "': " << error << std::endl;
+ }
+ return -1;
+ }
+ }
+
+ auto serialized_contexts = std::string{};
+ auto build_trie_error = std::string{};
+
+ if (!BuildTrie(property_info_entries, "u:object_r:default_prop:s0", "\\s*", &serialized_contexts,
+ &build_trie_error)) {
+ std::cerr << "Unable to serialize property contexts: " << build_trie_error << std::endl;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 492d63a..19269d8 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -77,7 +77,7 @@
#
# create some directories (some are mount points) and symlinks
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
- sbin dev proc sys system data oem acct config storage mnt $(BOARD_ROOT_EXTRA_FOLDERS)); \
+ sbin dev proc sys system data odm oem acct config storage mnt $(BOARD_ROOT_EXTRA_FOLDERS)); \
ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
index df26f90..7036356 100644
--- a/rootdir/etc/ld.config.txt.in
+++ b/rootdir/etc/ld.config.txt.in
@@ -218,7 +218,7 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
-additional.namespaces = system
+additional.namespaces = system,vndk
###############################################################################
# "default" namespace
@@ -261,10 +261,39 @@
namespace.default.asan.permitted.paths += /data/asan/vendor
namespace.default.asan.permitted.paths += /vendor
-namespace.default.links = system
-namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
-namespace.default.link.system.shared_libs += %VNDK_SAMEPROCESS_LIBRARIES%
-namespace.default.link.system.shared_libs += %VNDK_CORE_LIBRARIES%
+namespace.default.links = system,vndk
+namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.default.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
+
+###############################################################################
+# "vndk" namespace
+#
+# This namespace is where VNDK and VNDK-SP libraries are loaded for
+# a vendor process.
+###############################################################################
+namespace.vndk.isolated = false
+
+namespace.vndk.search.paths = /system/${LIB}/vndk-sp${VNDK_VER}
+namespace.vndk.search.paths += /system/${LIB}/vndk${VNDK_VER}
+
+# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
+namespace.vndk.permitted.paths = /system/${LIB}/vndk-sp${VNDK_VER}/hw
+
+namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp${VNDK_VER}/hw
+namespace.vndk.asan.permitted.paths += /system/${LIB}/vndk-sp${VNDK_VER}/hw
+
+namespace.vndk.asan.search.paths = /data/asan/system/${LIB}/vndk-sp${VNDK_VER}
+namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp${VNDK_VER}
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk${VNDK_VER}
+namespace.vndk.asan.search.paths += /system/${LIB}/vndk${VNDK_VER}
+
+# When these NDK libs are required inside this namespace, then it is redirected
+# to the system namespace. This is possible since their ABI is stable across
+# Android releases.
+namespace.vndk.links = system
+namespace.vndk.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
# "system" namespace
@@ -274,13 +303,7 @@
###############################################################################
namespace.system.isolated = false
-namespace.system.search.paths = /system/${LIB}/vndk-sp${VNDK_VER}
-namespace.system.search.paths += /system/${LIB}/vndk${VNDK_VER}
-namespace.system.search.paths += /system/${LIB}
+namespace.system.search.paths = /system/${LIB}
-namespace.system.asan.search.paths = /data/asan/system/${LIB}/vndk-sp${VNDK_VER}
-namespace.system.asan.search.paths += /system/${LIB}/vndk-sp${VNDK_VER}
-namespace.system.asan.search.paths += /data/asan/system/${LIB}/vndk${VNDK_VER}
-namespace.system.asan.search.paths += /system/${LIB}/vndk${VNDK_VER}
-namespace.system.asan.search.paths += /data/asan/system/${LIB}
+namespace.system.asan.search.paths = /data/asan/system/${LIB}
namespace.system.asan.search.paths += /system/${LIB}
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index d836c4e..ac87979 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -2,7 +2,7 @@
class main
priority -20
user root
- group root readproc
+ group root readproc reserved_disk
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 80bb673..a535846 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -2,7 +2,7 @@
class main
priority -20
user root
- group root readproc
+ group root readproc reserved_disk
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -17,7 +17,7 @@
class main
priority -20
user root
- group root readproc
+ group root readproc reserved_disk
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 05ec16f..6fc810b 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -2,7 +2,7 @@
class main
priority -20
user root
- group root readproc
+ group root readproc reserved_disk
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 09db7b0..7ddd52e 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -2,7 +2,7 @@
class main
priority -20
user root
- group root readproc
+ group root readproc reserved_disk
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -17,7 +17,7 @@
class main
priority -20
user root
- group root readproc
+ group root readproc reserved_disk
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index 206204b..c423c69 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -175,18 +175,18 @@
one-true-awk: awk
-toolbox: getevent newfs\_msdos
+toolbox: getevent getprop newfs\_msdos
toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
dos2unix du echo env expand expr fallocate false file find flock free
-getenforce getprop groups gunzip gzip head hostname hwclock id ifconfig
-inotifyd insmod ionice iorenice kill killall ln load\_policy log logname
-losetup ls lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod
-mkswap mktemp modinfo modprobe more mount mountpoint mv netstat nice
-nl nohup od paste patch pgrep pidof pkill pmap printenv printf ps pwd
-readlink realpath renice restorecon rm rmdir rmmod runcon sed sendevent
-seq setenforce setprop setsid sha1sum sha224sum sha256sum sha384sum
+getenforce groups gunzip gzip head hostname hwclock id ifconfig inotifyd
+insmod ionice iorenice kill killall ln load\_policy log logname losetup
+ls lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod mkswap
+mktemp modinfo modprobe more mount mountpoint mv netstat nice nl nohup
+od paste patch pgrep pidof pkill pmap printenv printf ps pwd readlink
+realpath renice restorecon rm rmdir rmmod runcon sed sendevent seq
+setenforce setprop setsid sha1sum sha224sum sha256sum sha384sum
sha512sum sleep sort split start stat stop strings swapoff swapon sync
sysctl tac tail tar taskset tee time timeout top touch tr true truncate
tty ulimit umount uname uniq unix2dos uptime usleep uudecode uuencode
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index c4795a7..d1b6114 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -13,18 +13,26 @@
getevent \
newfs_msdos \
-ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
+OUR_CPP_TOOLS := \
+ getprop \
+
+ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS) $(OUR_CPP_TOOLS)
LOCAL_SRC_FILES := \
toolbox.c \
$(patsubst %,%.c,$(OUR_TOOLS)) \
+ $(patsubst %,%.cpp,$(OUR_CPP_TOOLS)) \
LOCAL_CFLAGS += $(common_cflags)
+LOCAL_CPPFLAGS += -std=gnu++1z
LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
LOCAL_SHARED_LIBRARIES := \
+ libbase \
libcutils \
+LOCAL_STATIC_LIBRARIES := libpropertyinfoparser
+
LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS))
LOCAL_MODULE := toolbox
diff --git a/toolbox/getprop.cpp b/toolbox/getprop.cpp
new file mode 100644
index 0000000..7818ff2
--- /dev/null
+++ b/toolbox/getprop.cpp
@@ -0,0 +1,126 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <getopt.h>
+#include <sys/system_properties.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <android-base/properties.h>
+#include <property_info_parser/property_info_parser.h>
+
+using android::base::GetProperty;
+using android::properties::PropertyInfoAreaFile;
+
+PropertyInfoAreaFile property_info_file;
+
+void PrintAllProperties(bool print_property_context) {
+ std::vector<std::pair<std::string, std::string>> properties;
+ __system_property_foreach(
+ [](const prop_info* pi, void* cookie) {
+ __system_property_read_callback(
+ pi,
+ [](void* cookie, const char* name, const char* value, unsigned) {
+ auto properties =
+ reinterpret_cast<std::vector<std::pair<std::string, std::string>>*>(cookie);
+ properties->emplace_back(name, value);
+ },
+ cookie);
+ },
+ &properties);
+
+ std::sort(properties.begin(), properties.end());
+
+ if (print_property_context) {
+ for (auto& [name, value] : properties) {
+ const char* context = nullptr;
+ property_info_file->GetPropertyInfo(name.c_str(), &context, nullptr);
+ value = context;
+ }
+ }
+
+ for (const auto& [name, value] : properties) {
+ std::cout << "[" << name << "]: [" << value << "]" << std::endl;
+ }
+}
+
+void PrintProperty(const char* name, const char* default_value, bool print_property_context) {
+ if (print_property_context) {
+ const char* context = nullptr;
+ property_info_file->GetPropertyInfo(name, &context, nullptr);
+ std::cout << context << std::endl;
+ } else {
+ std::cout << GetProperty(name, default_value) << std::endl;
+ }
+}
+
+extern "C" int getprop_main(int argc, char** argv) {
+ bool print_property_context = false;
+
+ while (true) {
+ static const struct option long_options[] = {
+ {"help", no_argument, nullptr, 'h'},
+ {nullptr, 0, nullptr, 0},
+ };
+
+ int arg = getopt_long(argc, argv, "Z", long_options, nullptr);
+
+ if (arg == -1) {
+ break;
+ }
+
+ switch (arg) {
+ case 'h':
+ std::cout << "usage: getprop [-Z] [NAME [DEFAULT]]\n\n"
+ "Gets an Android system property, or lists them all.\n"
+ "Use -Z to return the property context instead of the property value\n"
+ << std::endl;
+ return 0;
+ case 'Z':
+ print_property_context = true;
+ break;
+ case '?':
+ return -1;
+ default:
+ std::cerr << "getprop: getopt returned invalid result: " << arg << std::endl;
+ return -1;
+ }
+ }
+
+ if (print_property_context) {
+ property_info_file.LoadDefaultPath();
+ if (!property_info_file) {
+ std::cerr << "Unable to load property info file" << std::endl;
+ return -1;
+ }
+ }
+
+ if (optind >= argc) {
+ PrintAllProperties(print_property_context);
+ return 0;
+ }
+
+ if (optind < argc - 2) {
+ std::cerr << "getprop: Max 2 arguments (see \"getprop --help\")" << std::endl;
+ return -1;
+ }
+
+ PrintProperty(argv[optind], (optind == argc - 1) ? "" : argv[optind + 1], print_property_context);
+
+ return 0;
+}
diff --git a/trusty/OWNERS b/trusty/OWNERS
index 25291fd..357b4f4 100644
--- a/trusty/OWNERS
+++ b/trusty/OWNERS
@@ -1 +1,3 @@
bohr@google.com
+swillden@google.com
+dkrahn@google.com
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
index c61e89d..5b83e21 100644
--- a/trusty/storage/proxy/storage.c
+++ b/trusty/storage/proxy/storage.c
@@ -379,7 +379,7 @@
}
if (req->size > MAX_READ_SIZE) {
- ALOGW("%s: request is too large (%zd > %zd) - refusing\n",
+ ALOGW("%s: request is too large (%u > %d) - refusing\n",
__func__, req->size, MAX_READ_SIZE);
msg->result = STORAGE_ERR_NOT_VALID;
goto err_response;