Merge "Improve RefBase documentation, especially for clients."
diff --git a/adb/Android.mk b/adb/Android.mk
index 7c029be..3512323 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -111,7 +111,7 @@
# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils_static libcrypto_static libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
include $(BUILD_STATIC_LIBRARY)
@@ -134,7 +134,7 @@
# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_utils_static libcrypto_static libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils libcrypto libbase
LOCAL_C_INCLUDES_windows := development/host/windows/usb/api/
LOCAL_MULTILIB := first
@@ -154,7 +154,7 @@
shell_service_test.cpp \
LOCAL_SANITIZE := $(adb_target_sanitize)
-LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils_static libcrypto_static
+LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils libcrypto
LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
include $(BUILD_NATIVE_TEST)
@@ -194,8 +194,8 @@
LOCAL_SHARED_LIBRARIES := libbase
LOCAL_STATIC_LIBRARIES := \
libadb \
- libcrypto_utils_static \
- libcrypto_static \
+ libcrypto_utils \
+ libcrypto \
libcutils \
libdiagnose_usb \
@@ -257,8 +257,8 @@
LOCAL_STATIC_LIBRARIES := \
libadb \
libbase \
- libcrypto_utils_static \
- libcrypto_static \
+ libcrypto_utils \
+ libcrypto \
libdiagnose_usb \
liblog \
@@ -334,8 +334,8 @@
libsquashfs_utils \
libcutils \
libbase \
- libcrypto_utils_static \
- libcrypto_static \
+ libcrypto_utils \
+ libcrypto \
libminijail \
libdebuggerd_client \
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index fbca770..3368b7f 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -28,8 +28,11 @@
#include <unistd.h>
#include <utime.h>
+#include <chrono>
#include <functional>
#include <memory>
+#include <sstream>
+#include <string>
#include <vector>
#include "sysdeps.h"
@@ -94,14 +97,112 @@
}
};
+enum class TransferDirection {
+ push,
+ pull,
+};
+
+struct TransferLedger {
+ std::chrono::steady_clock::time_point start_time;
+ uint64_t files_transferred;
+ uint64_t files_skipped;
+ uint64_t bytes_transferred;
+ uint64_t bytes_expected;
+ bool expect_multiple_files;
+
+ TransferLedger() {
+ Reset();
+ }
+
+ bool operator==(const TransferLedger& other) const {
+ return files_transferred == other.files_transferred &&
+ files_skipped == other.files_skipped && bytes_transferred == other.bytes_transferred;
+ }
+
+ bool operator!=(const TransferLedger& other) const {
+ return !(*this == other);
+ }
+
+ void Reset() {
+ start_time = std::chrono::steady_clock::now();
+ files_transferred = 0;
+ files_skipped = 0;
+ bytes_transferred = 0;
+ bytes_expected = 0;
+ }
+
+ std::string TransferRate() {
+ if (bytes_transferred == 0) return "";
+
+ std::chrono::duration<double> duration;
+ duration = std::chrono::steady_clock::now() - start_time;
+
+ double s = duration.count();
+ if (s == 0) {
+ return "";
+ }
+ double rate = (static_cast<double>(bytes_transferred) / s) / (1024 * 1024);
+ return android::base::StringPrintf(" %.1f MB/s (%" PRIu64 " bytes in %.3fs)", rate,
+ bytes_transferred, s);
+ }
+
+ void ReportProgress(LinePrinter& lp, const std::string& file, uint64_t file_copied_bytes,
+ uint64_t file_total_bytes) {
+ char overall_percentage_str[5] = "?";
+ if (bytes_expected != 0) {
+ int overall_percentage = static_cast<int>(bytes_transferred * 100 / bytes_expected);
+ // If we're pulling symbolic links, we'll pull the target of the link rather than
+ // just create a local link, and that will cause us to go over 100%.
+ if (overall_percentage <= 100) {
+ snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
+ overall_percentage);
+ }
+ }
+
+ std::string output;
+ if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
+ // This case can happen if we're racing against something that wrote to the file
+ // between our stat and our read, or if we're reading a magic file that lies about
+ // its size. Just show how much we've copied.
+ output = android::base::StringPrintf("[%4s] %s: %" PRId64 "/?", overall_percentage_str,
+ file.c_str(), file_copied_bytes);
+ } else {
+ // If we're transferring multiple files, we want to know how far through the current
+ // file we are, as well as the overall percentage.
+ if (expect_multiple_files) {
+ int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
+ output = android::base::StringPrintf("[%4s] %s: %d%%", overall_percentage_str,
+ file.c_str(), file_percentage);
+ } else {
+ output =
+ android::base::StringPrintf("[%4s] %s", overall_percentage_str, file.c_str());
+ }
+ }
+ lp.Print(output, LinePrinter::LineType::INFO);
+ }
+
+ void ReportTransferRate(LinePrinter& lp, const std::string& name, TransferDirection direction) {
+ const char* direction_str = (direction == TransferDirection::push) ? "pushed" : "pulled";
+ std::stringstream ss;
+ if (!name.empty()) {
+ ss << name << ": ";
+ }
+ ss << files_transferred << " file" << ((files_transferred == 1) ? "" : "s") << " "
+ << direction_str << ".";
+ if (files_skipped > 0) {
+ ss << " " << files_skipped << " file" << ((files_skipped == 1) ? "" : "s")
+ << " skipped.";
+ }
+ ss << TransferRate();
+
+ lp.Print(ss.str(), LinePrinter::LineType::INFO);
+ lp.KeepInfoLine();
+ }
+};
+
class SyncConnection {
public:
- SyncConnection()
- : total_bytes_(0),
- start_time_ms_(CurrentTimeMs()),
- expected_total_bytes_(0),
- expect_multiple_files_(false),
- expect_done_(false) {
+ SyncConnection() : expect_done_(false) {
max = SYNC_DATA_MAX; // TODO: decide at runtime.
std::string error;
@@ -140,6 +241,40 @@
return rc != 0;
}
+ void NewTransfer() {
+ current_ledger_.Reset();
+ }
+
+ void RecordBytesTransferred(size_t bytes) {
+ current_ledger_.bytes_transferred += bytes;
+ global_ledger_.bytes_transferred += bytes;
+ }
+
+ void RecordFilesTransferred(size_t files) {
+ current_ledger_.files_transferred += files;
+ global_ledger_.files_transferred += files;
+ }
+
+ void RecordFilesSkipped(size_t files) {
+ current_ledger_.files_skipped += files;
+ global_ledger_.files_skipped += files;
+ }
+
+ void ReportProgress(const std::string& file, uint64_t file_copied_bytes,
+ uint64_t file_total_bytes) {
+ current_ledger_.ReportProgress(line_printer_, file, file_copied_bytes, file_total_bytes);
+ }
+
+ void ReportTransferRate(const std::string& file, TransferDirection direction) {
+ current_ledger_.ReportTransferRate(line_printer_, file, direction);
+ }
+
+ void ReportOverallTransferRate(TransferDirection direction) {
+ if (current_ledger_ != global_ledger_) {
+ global_ledger_.ReportTransferRate(line_printer_, "", direction);
+ }
+ }
+
bool SendRequest(int id, const char* path_and_mode) {
size_t path_length = strlen(path_and_mode);
if (path_length > 1024) {
@@ -199,7 +334,9 @@
WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
expect_done_ = true;
- total_bytes_ += data_length;
+
+ // RecordFilesTransferred gets called in CopyDone.
+ RecordBytesTransferred(data_length);
ReportProgress(rpath, data_length, data_length);
return true;
}
@@ -242,7 +379,7 @@
sbuf.size = bytes_read;
WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
- total_bytes_ += bytes_read;
+ RecordBytesTransferred(bytes_read);
bytes_copied += bytes_read;
// Check to see if we've received an error from the other side.
@@ -259,6 +396,8 @@
msg.data.id = ID_DONE;
msg.data.size = mtime;
expect_done_ = true;
+
+ // RecordFilesTransferred gets called in CopyDone.
return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
}
@@ -271,6 +410,7 @@
if (msg.status.id == ID_OKAY) {
if (expect_done_) {
expect_done_ = false;
+ RecordFilesTransferred(1);
return true;
} else {
Error("failed to copy '%s' to '%s': received premature success", from, to);
@@ -296,44 +436,6 @@
return false;
}
- std::string TransferRate() {
- uint64_t ms = CurrentTimeMs() - start_time_ms_;
- if (total_bytes_ == 0 || ms == 0) return "";
-
- double s = static_cast<double>(ms) / 1000LL;
- double rate = (static_cast<double>(total_bytes_) / s) / (1024*1024);
- return android::base::StringPrintf(" %.1f MB/s (%" PRId64 " bytes in %.3fs)",
- rate, total_bytes_, s);
- }
-
- void ReportProgress(const char* file, uint64_t file_copied_bytes, uint64_t file_total_bytes) {
- char overall_percentage_str[5] = "?";
- if (expected_total_bytes_ != 0) {
- int overall_percentage = static_cast<int>(total_bytes_ * 100 / expected_total_bytes_);
- // If we're pulling symbolic links, we'll pull the target of the link rather than
- // just create a local link, and that will cause us to go over 100%.
- if (overall_percentage <= 100) {
- snprintf(overall_percentage_str, sizeof(overall_percentage_str), "%d%%",
- overall_percentage);
- }
- }
-
- if (file_copied_bytes > file_total_bytes || file_total_bytes == 0) {
- // This case can happen if we're racing against something that wrote to the file
- // between our stat and our read, or if we're reading a magic file that lies about
- // its size. Just show how much we've copied.
- Printf("[%4s] %s: %" PRId64 "/?", overall_percentage_str, file, file_copied_bytes);
- } else {
- // If we're transferring multiple files, we want to know how far through the current
- // file we are, as well as the overall percentage.
- if (expect_multiple_files_) {
- int file_percentage = static_cast<int>(file_copied_bytes * 100 / file_total_bytes);
- Printf("[%4s] %s: %d%%", overall_percentage_str, file, file_percentage);
- } else {
- Printf("[%4s] %s", overall_percentage_str, file);
- }
- }
- }
void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
std::string s;
@@ -346,6 +448,18 @@
line_printer_.Print(s, LinePrinter::INFO);
}
+ void Println(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
+ std::string s;
+
+ va_list ap;
+ va_start(ap, fmt);
+ android::base::StringAppendV(&s, fmt, ap);
+ va_end(ap);
+
+ line_printer_.Print(s, LinePrinter::INFO);
+ line_printer_.KeepInfoLine();
+ }
+
void Error(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
std::string s = "adb: error: ";
@@ -369,33 +483,29 @@
}
void ComputeExpectedTotalBytes(const std::vector<copyinfo>& file_list) {
- expected_total_bytes_ = 0;
+ current_ledger_.bytes_expected = 0;
for (const copyinfo& ci : file_list) {
// Unfortunately, this doesn't work for symbolic links, because we'll copy the
// target of the link rather than just creating a link. (But ci.size is the link size.)
- if (!ci.skip) expected_total_bytes_ += ci.size;
+ if (!ci.skip) current_ledger_.bytes_expected += ci.size;
}
- expect_multiple_files_ = true;
+ current_ledger_.expect_multiple_files = true;
}
void SetExpectedTotalBytes(uint64_t expected_total_bytes) {
- expected_total_bytes_ = expected_total_bytes;
- expect_multiple_files_ = false;
+ current_ledger_.bytes_expected = expected_total_bytes;
+ current_ledger_.expect_multiple_files = false;
}
- uint64_t total_bytes_;
-
// TODO: add a char[max] buffer here, to replace syncsendbuf...
int fd;
size_t max;
private:
- uint64_t start_time_ms_;
-
- uint64_t expected_total_bytes_;
- bool expect_multiple_files_;
bool expect_done_;
+ TransferLedger global_ledger_;
+ TransferLedger current_ledger_;
LinePrinter line_printer_;
bool SendQuit() {
@@ -422,12 +532,6 @@
}
return true;
}
-
- static uint64_t CurrentTimeMs() {
- struct timeval tv;
- gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
- return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
- }
};
typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
@@ -570,13 +674,12 @@
return false;
}
- sc.total_bytes_ += msg.data.size;
-
bytes_copied += msg.data.size;
-
+ sc.RecordBytesTransferred(msg.data.size);
sc.ReportProgress(rpath, bytes_copied, size);
}
+ sc.RecordFilesTransferred(1);
adb_close(lfd);
return true;
}
@@ -661,13 +764,14 @@
static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
std::string rpath, bool check_timestamps,
bool list_only) {
+ sc.NewTransfer();
+
// Make sure that both directory paths end in a slash.
// Both paths are known to be nonempty, so we don't need to check.
ensure_trailing_separators(lpath, rpath);
// Recursively build the list of files to copy.
std::vector<copyinfo> file_list;
- int pushed = 0;
int skipped = 0;
if (!local_build_list(sc, &file_list, lpath, rpath)) {
return false;
@@ -699,21 +803,19 @@
for (const copyinfo& ci : file_list) {
if (!ci.skip) {
if (list_only) {
- sc.Error("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
+ sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
} else {
if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode)) {
return false;
}
}
- pushed++;
} else {
skipped++;
}
}
- sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s", rpath.c_str(),
- pushed, (pushed == 1) ? "" : "s", skipped,
- (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
+ sc.RecordFilesSkipped(skipped);
+ sc.ReportTransferRate(lpath, TransferDirection::push);
return true;
}
@@ -789,10 +891,14 @@
path_holder += adb_basename(src_path);
dst_path = path_holder.c_str();
}
+
+ sc.NewTransfer();
sc.SetExpectedTotalBytes(st.st_size);
success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
+ sc.ReportTransferRate(src_path, TransferDirection::push);
}
+ sc.ReportOverallTransferRate(TransferDirection::push);
return success;
}
@@ -878,6 +984,8 @@
static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
std::string lpath, bool copy_attrs) {
+ sc.NewTransfer();
+
// Make sure that both directory paths end in a slash.
// Both paths are known to be nonempty, so we don't need to check.
ensure_trailing_separators(lpath, rpath);
@@ -891,7 +999,6 @@
sc.ComputeExpectedTotalBytes(file_list);
- int pulled = 0;
int skipped = 0;
for (const copyinfo &ci : file_list) {
if (!ci.skip) {
@@ -903,7 +1010,6 @@
ci.lpath.c_str(), strerror(errno));
return false;
}
- pulled++;
continue;
}
@@ -914,15 +1020,13 @@
if (copy_attrs && set_time_and_mode(ci.lpath, ci.time, ci.mode)) {
return false;
}
- pulled++;
} else {
skipped++;
}
}
- sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s", rpath.c_str(),
- pulled, (pulled == 1) ? "" : "s", skipped,
- (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
+ sc.RecordFilesSkipped(skipped);
+ sc.ReportTransferRate(rpath, TransferDirection::pull);
return true;
}
@@ -1021,6 +1125,7 @@
dst_path = path_holder.c_str();
}
+ sc.NewTransfer();
sc.SetExpectedTotalBytes(src_size);
if (!sync_recv(sc, src_path, dst_path)) {
success = false;
@@ -1031,8 +1136,10 @@
success = false;
continue;
}
+ sc.ReportTransferRate(src_path, TransferDirection::pull);
}
+ sc.ReportOverallTransferRate(TransferDirection::pull);
return success;
}
@@ -1040,5 +1147,9 @@
SyncConnection sc;
if (!sc.IsValid()) return false;
- return copy_local_dir_remote(sc, lpath, rpath, true, list_only);
+ bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only);
+ if (!list_only) {
+ sc.ReportOverallTransferRate(TransferDirection::push);
+ }
+ return success;
}
diff --git a/adb/line_printer.cpp b/adb/line_printer.cpp
index 4ec8979..64d10b6 100644
--- a/adb/line_printer.cpp
+++ b/adb/line_printer.cpp
@@ -124,4 +124,5 @@
void LinePrinter::KeepInfoLine() {
if (!have_blank_line_) Out("\n");
+ have_blank_line_ = true;
}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index ee27406..109a548 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -952,7 +952,7 @@
_socket_set_errno(err);
return -1;
}
- std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*> addrinfo(addrinfo_ptr, freeaddrinfo);
+ std::unique_ptr<struct addrinfo, decltype(&freeaddrinfo)> addrinfo(addrinfo_ptr, freeaddrinfo);
addrinfo_ptr = nullptr;
// TODO: Try all the addresses if there's more than one? This just uses
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 56e2dde..66d60c9 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -53,8 +53,8 @@
typedef std::function<void(LogId, LogSeverity, const char*, const char*,
unsigned int, const char*)> LogFunction;
-extern void StderrLogger(LogId, LogSeverity, const char*, const char*,
- unsigned int, const char*);
+void KernelLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);
+void StderrLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*);
#ifdef __ANDROID__
// We expose this even though it is the default because a user that wants to
@@ -79,17 +79,14 @@
// The tag (or '*' for the global level) comes first, followed by a colon and a
// letter indicating the minimum priority level we're expected to log. This can
// be used to reveal or conceal logs with specific tags.
-extern void InitLogging(char* argv[], LogFunction&& logger);
+void InitLogging(char* argv[], LogFunction&& logger);
// Configures logging using the default logger (logd for the device, stderr for
// the host).
-extern void InitLogging(char* argv[]);
+void InitLogging(char* argv[]);
// Replace the current logger.
-extern void SetLogger(LogFunction&& logger);
-
-// Get the minimum severity level for logging.
-extern LogSeverity GetMinimumLogSeverity();
+void SetLogger(LogFunction&& logger);
class ErrnoRestorer {
public:
@@ -334,6 +331,12 @@
DISALLOW_COPY_AND_ASSIGN(LogMessage);
};
+// Get the minimum severity level for logging.
+LogSeverity GetMinimumLogSeverity();
+
+// Set the minimum severity level for logging, returning the old severity.
+LogSeverity SetMinimumLogSeverity(LogSeverity new_severity);
+
// Allows to temporarily change the minimum severity level for logging.
class ScopedLogSeverity {
public:
diff --git a/base/logging.cpp b/base/logging.cpp
index 959bb8b..1f47a9f 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-#ifdef _WIN32
+#if defined(_WIN32)
#include <windows.h>
#endif
#include "android-base/logging.h"
+#include <fcntl.h>
#include <libgen.h>
#include <time.h>
@@ -30,6 +31,10 @@
#include <errno.h>
#endif
+#if defined(__linux__)
+#include <sys/uio.h>
+#endif
+
#include <iostream>
#include <limits>
#include <sstream>
@@ -172,10 +177,6 @@
static LogSeverity gMinimumLogSeverity = INFO;
static auto& gProgramInvocationName = *new std::unique_ptr<std::string>();
-LogSeverity GetMinimumLogSeverity() {
- return gMinimumLogSeverity;
-}
-
static const char* ProgramInvocationName() {
if (gProgramInvocationName == nullptr) {
gProgramInvocationName.reset(new std::string(getprogname()));
@@ -184,6 +185,42 @@
return gProgramInvocationName->c_str();
}
+#if defined(__linux__)
+void KernelLogger(android::base::LogId, android::base::LogSeverity severity,
+ const char* tag, const char*, unsigned int, const char* msg) {
+ static constexpr int kLogSeverityToKernelLogLevel[] = {
+ [android::base::VERBOSE] = 7, // KERN_DEBUG (there is no verbose kernel log level)
+ [android::base::DEBUG] = 7, // KERN_DEBUG
+ [android::base::INFO] = 6, // KERN_INFO
+ [android::base::WARNING] = 4, // KERN_WARNING
+ [android::base::ERROR] = 3, // KERN_ERROR
+ [android::base::FATAL] = 2, // KERN_CRIT
+ };
+ static_assert(arraysize(kLogSeverityToKernelLogLevel) == android::base::FATAL + 1,
+ "Mismatch in size of kLogSeverityToKernelLogLevel and values in LogSeverity");
+
+ static int klog_fd = TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
+ if (klog_fd == -1) return;
+
+ int level = kLogSeverityToKernelLogLevel[severity];
+
+ // The kernel's printk buffer is only 1024 bytes.
+ // TODO: should we automatically break up long lines into multiple lines?
+ // Or we could log but with something like "..." at the end?
+ char buf[1024];
+ size_t size = snprintf(buf, sizeof(buf), "<%d>%s: %s\n", level, tag, msg);
+ if (size > sizeof(buf)) {
+ size = snprintf(buf, sizeof(buf), "<%d>%s: %zu-byte message too long for printk\n",
+ level, tag, size);
+ }
+
+ iovec iov[1];
+ iov[0].iov_base = buf;
+ iov[0].iov_len = size;
+ TEMP_FAILURE_RETRY(writev(klog_fd, iov, 1));
+}
+#endif
+
void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
unsigned int line, const char* message) {
struct tm now;
@@ -211,28 +248,26 @@
LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
}
-static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
- ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
- ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
-};
-static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
- "Mismatch in size of kLogSeverityToAndroidLogPriority and values "
- "in LogSeverity");
-
-static const log_id kLogIdToAndroidLogId[] = {
- LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
-};
-static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
- "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
-
void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
const char* file, unsigned int line,
const char* message) {
+ static constexpr android_LogPriority kLogSeverityToAndroidLogPriority[] = {
+ ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
+ ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
+ };
+ static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
+ "Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity");
+
int priority = kLogSeverityToAndroidLogPriority[severity];
if (id == DEFAULT) {
id = default_log_id_;
}
+ static constexpr log_id kLogIdToAndroidLogId[] = {
+ LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
+ };
+ static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
+ "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
log_id lg_id = kLogIdToAndroidLogId[id];
if (priority == ANDROID_LOG_FATAL) {
@@ -427,13 +462,22 @@
gLogger(id, severity, tag, file, line, message);
}
-ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
- old_ = gMinimumLogSeverity;
- gMinimumLogSeverity = level;
+LogSeverity GetMinimumLogSeverity() {
+ return gMinimumLogSeverity;
+}
+
+LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) {
+ LogSeverity old_severity = gMinimumLogSeverity;
+ gMinimumLogSeverity = new_severity;
+ return old_severity;
+}
+
+ScopedLogSeverity::ScopedLogSeverity(LogSeverity new_severity) {
+ old_ = SetMinimumLogSeverity(new_severity);
}
ScopedLogSeverity::~ScopedLogSeverity() {
- gMinimumLogSeverity = old_;
+ SetMinimumLogSeverity(old_);
}
} // namespace base
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 7da3ca4..d6b699b 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -7,8 +7,8 @@
libfec \
libfec_rs \
libbase \
- libcrypto_utils_static \
- libcrypto_static \
+ libcrypto_utils \
+ libcrypto \
libext4_utils_static \
libsquashfs_utils \
libselinux
diff --git a/include/utils/Condition.h b/include/utils/Condition.h
index a420185..5650598 100644
--- a/include/utils/Condition.h
+++ b/include/utils/Condition.h
@@ -54,7 +54,7 @@
};
Condition();
- Condition(int type);
+ explicit Condition(int type);
~Condition();
// Wait on the condition variable. Lock the mutex before calling.
status_t wait(Mutex& mutex);
diff --git a/include/utils/Mutex.h b/include/utils/Mutex.h
index f027c79..8b720b9 100644
--- a/include/utils/Mutex.h
+++ b/include/utils/Mutex.h
@@ -48,8 +48,8 @@
};
Mutex();
- Mutex(const char* name);
- Mutex(int type, const char* name = NULL);
+ explicit Mutex(const char* name);
+ explicit Mutex(int type, const char* name = NULL);
~Mutex();
// lock or unlock the mutex
@@ -73,8 +73,8 @@
// constructed and released when Autolock goes out of scope.
class Autolock {
public:
- inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
- inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
+ inline explicit Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
+ inline explicit Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
inline ~Autolock() { mLock.unlock(); }
private:
Mutex& mLock;
diff --git a/include/utils/RWLock.h b/include/utils/RWLock.h
index e743b1c..d5b81d3 100644
--- a/include/utils/RWLock.h
+++ b/include/utils/RWLock.h
@@ -47,8 +47,8 @@
};
RWLock();
- RWLock(const char* name);
- RWLock(int type, const char* name = NULL);
+ explicit RWLock(const char* name);
+ explicit RWLock(int type, const char* name = NULL);
~RWLock();
status_t readLock();
@@ -59,7 +59,7 @@
class AutoRLock {
public:
- inline AutoRLock(RWLock& rwlock) : mLock(rwlock) { mLock.readLock(); }
+ inline explicit AutoRLock(RWLock& rwlock) : mLock(rwlock) { mLock.readLock(); }
inline ~AutoRLock() { mLock.unlock(); }
private:
RWLock& mLock;
@@ -67,7 +67,7 @@
class AutoWLock {
public:
- inline AutoWLock(RWLock& rwlock) : mLock(rwlock) { mLock.writeLock(); }
+ inline explicit AutoWLock(RWLock& rwlock) : mLock(rwlock) { mLock.writeLock(); }
inline ~AutoWLock() { mLock.unlock(); }
private:
RWLock& mLock;
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 273f5aa..a232a65 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -372,12 +372,12 @@
inline wp() : m_ptr(0) { }
- wp(T* other);
+ wp(T* other); // NOLINT(implicit)
wp(const wp<T>& other);
- wp(const sp<T>& other);
- template<typename U> wp(U* other);
- template<typename U> wp(const sp<U>& other);
- template<typename U> wp(const wp<U>& other);
+ explicit wp(const sp<T>& other);
+ template<typename U> wp(U* other); // NOLINT(implicit)
+ template<typename U> wp(const sp<U>& other); // NOLINT(implicit)
+ template<typename U> wp(const wp<U>& other); // NOLINT(implicit)
~wp();
diff --git a/include/utils/StrongPointer.h b/include/utils/StrongPointer.h
index 50fde35..d90b788 100644
--- a/include/utils/StrongPointer.h
+++ b/include/utils/StrongPointer.h
@@ -60,12 +60,12 @@
public:
inline sp() : m_ptr(0) { }
- sp(T* other);
+ sp(T* other); // NOLINT(implicit)
sp(const sp<T>& other);
sp(sp<T>&& other);
- template<typename U> sp(U* other);
- template<typename U> sp(const sp<U>& other);
- template<typename U> sp(sp<U>&& other);
+ template<typename U> sp(U* other); // NOLINT(implicit)
+ template<typename U> sp(const sp<U>& other); // NOLINT(implicit)
+ template<typename U> sp(sp<U>&& other); // NOLINT(implicit)
~sp();
diff --git a/include/utils/Thread.h b/include/utils/Thread.h
index 1532b7e..0f7ac9f 100644
--- a/include/utils/Thread.h
+++ b/include/utils/Thread.h
@@ -41,7 +41,7 @@
public:
// Create a Thread object, but doesn't create or start the associated
// thread. See the run() method.
- Thread(bool canCallJava = true);
+ explicit Thread(bool canCallJava = true);
virtual ~Thread();
// Start the thread in threadLoop() which needs to be implemented.
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
index 61d618e..64d25c5 100644
--- a/include/utils/TypeHelpers.h
+++ b/include/utils/TypeHelpers.h
@@ -240,7 +240,7 @@
key_value_pair_t() { }
key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }
key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v) { }
- key_value_pair_t(const KEY& k) : key(k) { }
+ explicit key_value_pair_t(const KEY& k) : key(k) { }
inline bool operator < (const key_value_pair_t& o) const {
return strictly_order_type(key, o.key);
}
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
index 21ad71c..4dd91fd 100644
--- a/include/utils/VectorImpl.h
+++ b/include/utils/VectorImpl.h
@@ -132,7 +132,7 @@
{
public:
SortedVectorImpl(size_t itemSize, uint32_t flags);
- SortedVectorImpl(const VectorImpl& rhs);
+ explicit SortedVectorImpl(const VectorImpl& rhs);
virtual ~SortedVectorImpl();
SortedVectorImpl& operator = (const SortedVectorImpl& rhs);
diff --git a/init/Android.mk b/init/Android.mk
index 7aa3c3f..5888456 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -94,8 +94,8 @@
libc \
libselinux \
liblog \
- libcrypto_utils_static \
- libcrypto_static \
+ libcrypto_utils \
+ libcrypto \
libc++_static \
libdl \
libsparse_static \
diff --git a/init/action.cpp b/init/action.cpp
index f3e362e..ed88f6d 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -118,7 +118,8 @@
Timer t;
int result = command.InvokeFunc();
- if (klog_get_level() >= KLOG_DEBUG_LEVEL) {
+ // TODO: this should probably be changed to "if (failed || took a long time)"...
+ if (android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
std::string trigger_name = BuildTriggersString();
std::string cmd_str = command.BuildCommandString();
std::string source = command.BuildSourceString();
diff --git a/init/builtins.cpp b/init/builtins.cpp
index d64c3d2..3d220c5 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -482,11 +482,7 @@
* not return.
*/
static int do_mount_all(const std::vector<std::string>& args) {
- pid_t pid;
int ret = -1;
- int child_ret = -1;
- int status;
- struct fstab *fstab;
const char* fstabfile = args[1].c_str();
/*
@@ -495,9 +491,10 @@
* process if anything goes wrong (crash or memory leak), and wait for
* the child to finish in the parent.
*/
- pid = fork();
+ pid_t pid = fork();
if (pid > 0) {
/* Parent. Wait for the child to return */
+ int status;
int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
if (wp_ret == -1) {
// Unexpected error code. We will continue anyway.
@@ -511,9 +508,13 @@
}
} else if (pid == 0) {
/* child, call fs_mgr_mount_all() */
- klog_set_level(6); /* So we can see what fs_mgr_mount_all() does */
- fstab = fs_mgr_read_fstab(fstabfile);
- child_ret = fs_mgr_mount_all(fstab);
+
+ // So we can always see what fs_mgr_mount_all() does.
+ // Only needed if someone explicitly changes the default log level in their init.rc.
+ android::base::ScopedLogSeverity info(android::base::INFO);
+
+ struct fstab* fstab = fs_mgr_read_fstab(fstabfile);
+ int child_ret = fs_mgr_mount_all(fstab);
fs_mgr_free_fstab(fstab);
if (child_ret == -1) {
PLOG(ERROR) << "fs_mgr_mount_all returned an error";
@@ -866,12 +867,23 @@
}
static int do_loglevel(const std::vector<std::string>& args) {
+ // TODO: support names instead/as well?
int log_level = std::stoi(args[1]);
- if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
- LOG(ERROR) << "loglevel: invalid log level " << log_level;
- return -EINVAL;
+ android::base::LogSeverity severity;
+ switch (log_level) {
+ case 7: severity = android::base::DEBUG; break;
+ case 6: severity = android::base::INFO; break;
+ case 5:
+ case 4: severity = android::base::WARNING; break;
+ case 3: severity = android::base::ERROR; break;
+ case 2:
+ case 1:
+ case 0: severity = android::base::FATAL; break;
+ default:
+ LOG(ERROR) << "loglevel: invalid log level " << log_level;
+ return -EINVAL;
}
- klog_set_level(log_level);
+ android::base::SetMinimumLogSeverity(severity);
return 0;
}
diff --git a/init/log.cpp b/init/log.cpp
index 379141a..8618340 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -17,52 +17,16 @@
#include "log.h"
#include <fcntl.h>
-#include <stdlib.h>
#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/uio.h>
#include <selinux/selinux.h>
-static const int kLogSeverityToKLogLevel[] = {
- [android::base::VERBOSE] = KLOG_DEBUG_LEVEL,
- [android::base::DEBUG] = KLOG_DEBUG_LEVEL,
- [android::base::INFO] = KLOG_INFO_LEVEL,
- [android::base::WARNING] = KLOG_WARNING_LEVEL,
- [android::base::ERROR] = KLOG_ERROR_LEVEL,
- [android::base::FATAL] = KLOG_ERROR_LEVEL,
-};
-static_assert(arraysize(kLogSeverityToKLogLevel) == android::base::FATAL + 1,
- "Mismatch in size of kLogSeverityToKLogLevel and values in LogSeverity");
-
-static void KernelLogger(android::base::LogId, android::base::LogSeverity severity,
- const char* tag, const char*, unsigned int, const char* msg) {
- int level = kLogSeverityToKLogLevel[severity];
- if (level > klog_get_level()) return;
-
- // The kernel's printk buffer is only 1024 bytes.
- // TODO: should we automatically break up long lines into multiple lines?
- // Or we could log but with something like "..." at the end?
- char buf[1024];
- size_t size = snprintf(buf, sizeof(buf), "<%d>%s: %s\n", level, tag, msg);
- if (size > sizeof(buf)) {
- size = snprintf(buf, sizeof(buf), "<%d>%s: %zu-byte message too long for printk\n",
- level, tag, size);
- }
-
- iovec iov[1];
- iov[0].iov_base = buf;
- iov[0].iov_len = size;
- klog_writev(level, iov, 1);
-}
-
void InitKernelLogging(char* argv[]) {
// Make stdin/stdout/stderr all point to /dev/null.
int fd = open("/sys/fs/selinux/null", O_RDWR);
if (fd == -1) {
int saved_errno = errno;
- android::base::InitLogging(argv, &KernelLogger);
+ android::base::InitLogging(argv, &android::base::KernelLogger);
errno = saved_errno;
PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
}
@@ -71,8 +35,7 @@
dup2(fd, 2);
if (fd > 2) close(fd);
- android::base::InitLogging(argv, &KernelLogger);
- klog_set_level(KLOG_INFO_LEVEL);
+ android::base::InitLogging(argv, &android::base::KernelLogger);
}
int selinux_klog_callback(int type, const char *fmt, ...) {
@@ -87,6 +50,6 @@
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
- KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
+ android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
return 0;
}
diff --git a/init/log.h b/init/log.h
index cf552a1..8fa6d74 100644
--- a/init/log.h
+++ b/init/log.h
@@ -19,8 +19,6 @@
#include <android-base/logging.h>
-#include <cutils/klog.h>
-
void InitKernelLogging(char* argv[]);
int selinux_klog_callback(int level, const char* fmt, ...) __printflike(2, 3);
diff --git a/init/readme.txt b/init/readme.txt
index 7260775..4c04f17 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -514,6 +514,3 @@
Alternatively, use the emulator:
emulator -partition-size 1024 -verbose -show-kernel -no-window
-
-You might want to change the klog_set_level call so you see all the kernel
-logging in dmesg (or the emulator output).
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
new file mode 100644
index 0000000..ca7bd31
--- /dev/null
+++ b/libcrypto_utils/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library {
+ name: "libcrypto_utils",
+ host_supported: true,
+ srcs: [
+ "android_pubkey.c",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-std=c99",
+ ],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+ shared_libs: ["libcrypto"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+}
diff --git a/libcrypto_utils/Android.mk b/libcrypto_utils/Android.mk
deleted file mode 100644
index b6d2204..0000000
--- a/libcrypto_utils/Android.mk
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcrypto_utils
-LOCAL_SRC_FILES := android_pubkey.c
-LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES := libcrypto
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcrypto_utils
-LOCAL_SRC_FILES := android_pubkey.c
-LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES := libcrypto
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcrypto_utils_static
-LOCAL_SRC_FILES := android_pubkey.c
-LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libcrypto
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcrypto_utils_static
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_SRC_FILES := android_pubkey.c
-LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libcrypto_static
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index d7b4b0b..5c68add 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -45,9 +45,6 @@
#define POLICY_DEBUG 0
-// This prctl is only available in Android kernels.
-#define PR_SET_TIMERSLACK_PID 41
-
// timer slack value in nS enforced when the thread moves to background
#define TIMER_SLACK_BG 40000000
#define TIMER_SLACK_FG 50000
@@ -293,9 +290,9 @@
}
static void set_timerslack_ns(int tid, unsigned long long slack) {
+ // v4.6+ kernels support the /proc/<tid>/timerslack_ns interface.
+ // TODO: once we've backported this, log if the open(2) fails.
char buf[64];
-
- /* v4.6+ kernels support the /proc/<tid>/timerslack_ns interface. */
snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", tid);
int fd = open(buf, O_WRONLY | O_CLOEXEC);
if (fd != -1) {
@@ -306,11 +303,6 @@
close(fd);
return;
}
-
- /* If the above fails, try the old common.git PR_SET_TIMERSLACK_PID. */
- if (prctl(PR_SET_TIMERSLACK_PID, slack, tid) == -1) {
- SLOGE("set_timerslack_ns prctl failed: %s\n", strerror(errno));
- }
}
int set_sched_policy(int tid, SchedPolicy policy)
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 530c747..ada7d5f 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -21,6 +21,7 @@
srcs: [
"MemsetTest.cpp",
"PropertiesTest.cpp",
+ "sched_policy_test.cpp",
"trace-dev_test.cpp",
],
},
diff --git a/libcutils/tests/sched_policy_test.cpp b/libcutils/tests/sched_policy_test.cpp
new file mode 100644
index 0000000..173174a
--- /dev/null
+++ b/libcutils/tests/sched_policy_test.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include <sys/capability.h>
+
+#include <cutils/sched_policy.h>
+
+#include <gtest/gtest.h>
+
+bool hasCapSysNice() {
+ __user_cap_header_struct header;
+ memset(&header, 0, sizeof(header));
+ header.version = _LINUX_CAPABILITY_VERSION_3;
+
+ __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3];
+ if (capget(&header, &caps[0])) {
+ GTEST_LOG_(WARNING) << "failed to get process capabilities";
+ return false;
+ }
+
+ auto nice_idx = CAP_TO_INDEX(CAP_SYS_NICE);
+ auto nice_mask = CAP_TO_MASK(CAP_SYS_NICE);
+ return caps[nice_idx].effective & nice_mask;
+}
+
+long long medianSleepTime() {
+ std::vector<long long> sleepTimes;
+ constexpr size_t numSamples = 100;
+
+ for (size_t i = 0; i < numSamples; i++) {
+ auto start = std::chrono::steady_clock::now();
+ std::this_thread::sleep_for(std::chrono::nanoseconds(1));
+ auto end = std::chrono::steady_clock::now();
+
+ auto diff = end - start;
+ sleepTimes.push_back(diff.count());
+ }
+
+ constexpr auto median = numSamples / 2;
+ std::nth_element(sleepTimes.begin(), sleepTimes.begin() + median,
+ sleepTimes.end());
+ return sleepTimes[median];
+}
+
+TEST(SchedPolicy, set_sched_policy) {
+ if (!hasCapSysNice()) {
+ GTEST_LOG_(INFO) << "skipping test that requires CAP_SYS_NICE";
+ return;
+ }
+
+ // A measureable effect of scheduling policy is that the kernel has 800x
+ // greater slack time in waking up a sleeping background thread.
+ //
+ // Look for 100x difference in how long FB and BG threads actually sleep
+ // when trying to sleep for 1 ns. This difference is large enough not
+ // to happen by chance, but small enough (compared to 800x) to keep inherent
+ // fuzziness in scheduler behavior from causing false negatives.
+ const unsigned int BG_FG_SLACK_FACTOR = 100;
+
+ ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
+ auto bgSleepTime = medianSleepTime();
+
+ ASSERT_EQ(0, set_sched_policy(0, SP_FOREGROUND));
+ auto fgSleepTime = medianSleepTime();
+ ASSERT_GT(bgSleepTime, fgSleepTime * BG_FG_SLACK_FACTOR);
+}
+
+TEST(SchedPolicy, get_sched_policy) {
+ SchedPolicy policy;
+ ASSERT_EQ(0, get_sched_policy(0, &policy));
+
+ const char *policyName = get_sched_policy_name(policy);
+ EXPECT_NE(nullptr, policyName);
+ EXPECT_STRNE("error", policyName);
+
+ ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND));
+ SchedPolicy newPolicy;
+ ASSERT_EQ(0, get_sched_policy(0, &newPolicy));
+ EXPECT_EQ(SP_BACKGROUND, newPolicy);
+}
diff --git a/libsync/Android.mk b/libsync/Android.mk
index fd1c88c..f407bd1 100644
--- a/libsync/Android.mk
+++ b/libsync/Android.mk
@@ -4,17 +4,27 @@
LOCAL_SRC_FILES := sync.c
LOCAL_MODULE := libsync
LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
+# libsync_recovery is only intended for the recovery binary.
+# Future versions of the kernel WILL require an updated libsync, and will break
+# anything statically linked against the current libsync.
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := sync.c
+LOCAL_MODULE := libsync_recovery
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
+include $(BUILD_STATIC_LIBRARY)
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES := sync.c sync_test.c
LOCAL_MODULE := sync_test
LOCAL_MODULE_TAGS := optional tests
-LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index f3d6d8f..dc96aef 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -114,8 +114,9 @@
int32_t SharedBuffer::release(uint32_t flags) const
{
int32_t prev = 1;
- if (onlyOwner() || ((prev = mRefs.fetch_sub(1, std::memory_order_release) == 1)
- && (atomic_thread_fence(std::memory_order_acquire), true))) {
+ if (onlyOwner()
+ || (((prev = mRefs.fetch_sub(1, std::memory_order_release)) == 1)
+ && (atomic_thread_fence(std::memory_order_acquire), true))) {
mRefs.store(0, std::memory_order_relaxed);
if ((flags & eKeepStorage) == 0) {
free(const_cast<SharedBuffer*>(this));
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 5bac717..7e2bac7 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -26,6 +26,7 @@
#include <string>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
@@ -109,29 +110,27 @@
(g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
for (int i = g_maxRotatedLogs ; i > 0 ; i--) {
- char *file0, *file1;
+ std::string file1 = android::base::StringPrintf(
+ "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
- asprintf(&file1, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
-
+ std::string file0;
if (i - 1 == 0) {
- asprintf(&file0, "%s", g_outputFileName);
+ file0 = android::base::StringPrintf("%s", g_outputFileName);
} else {
- asprintf(&file0, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1);
+ file0 = android::base::StringPrintf(
+ "%s.%.*d", g_outputFileName, maxRotationCountDigits, i - 1);
}
- if (!file0 || !file1) {
+ if ((file0.length() == 0) || (file1.length() == 0)) {
perror("while rotating log files");
break;
}
- err = rename(file0, file1);
+ err = rename(file0.c_str(), file1.c_str());
if (err < 0 && errno != ENOENT) {
perror("while rotating log files");
}
-
- free(file1);
- free(file0);
}
g_outFD = openLogFile(g_outputFileName);
@@ -231,13 +230,15 @@
}
}
-static void setupOutput()
-{
-
+static void setupOutputAndSchedulingPolicy(bool blocking) {
if (g_outputFileName == NULL) {
g_outFD = STDOUT_FILENO;
+ return;
+ }
- } else {
+ if (blocking) {
+ // Lower priority and set to batch scheduling if we are saving
+ // the logs into files and taking continuous content.
if (set_sched_policy(0, SP_BACKGROUND) < 0) {
fprintf(stderr, "failed to set background scheduling policy\n");
}
@@ -251,26 +252,26 @@
if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
fprintf(stderr, "failed set to priority\n");
}
-
- g_outFD = openLogFile (g_outputFileName);
-
- if (g_outFD < 0) {
- logcat_panic(false, "couldn't open output file");
- }
-
- struct stat statbuf;
- if (fstat(g_outFD, &statbuf) == -1) {
- close(g_outFD);
- logcat_panic(false, "couldn't get output file stat\n");
- }
-
- if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
- close(g_outFD);
- logcat_panic(false, "invalid output file stat\n");
- }
-
- g_outByteCount = statbuf.st_size;
}
+
+ g_outFD = openLogFile (g_outputFileName);
+
+ if (g_outFD < 0) {
+ logcat_panic(false, "couldn't open output file");
+ }
+
+ struct stat statbuf;
+ if (fstat(g_outFD, &statbuf) == -1) {
+ close(g_outFD);
+ logcat_panic(false, "couldn't get output file stat\n");
+ }
+
+ if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
+ close(g_outFD);
+ logcat_panic(false, "invalid output file stat\n");
+ }
+
+ g_outByteCount = statbuf.st_size;
}
static void show_help(const char *cmd)
@@ -284,6 +285,8 @@
" Rotate log every kbytes. Requires -f option\n"
" -n <count>, --rotate-count=<count>\n"
" Sets max number of rotated logs to <count>, default 4\n"
+ " --id=<id> If the signature id for logging to file changes, then clear\n"
+ " the fileset and continue\n"
" -v <format>, --format=<format>\n"
" Sets log print format verb and adverbs, where <format> is:\n"
" brief long process raw tag thread threadtime time\n"
@@ -443,7 +446,7 @@
return t.strptime(cp, "%s.%q");
}
-// Find last logged line in gestalt of all matching existing output files
+// Find last logged line in <outputFileName>, or <outputFileName>.1
static log_time lastLogTime(char *outputFileName) {
log_time retval(log_time::EPOCH);
if (!outputFileName) {
@@ -468,24 +471,18 @@
return retval;
}
- clockid_t clock_type = android_log_clockid();
- log_time now(clock_type);
- bool monotonic = clock_type == CLOCK_MONOTONIC;
+ log_time now(android_log_clockid());
size_t len = strlen(file);
log_time modulo(0, NS_PER_SEC);
struct dirent *dp;
while ((dp = readdir(dir.get())) != NULL) {
- if ((dp->d_type != DT_REG)
- // If we are using realtime, check all files that match the
- // basename for latest time. If we are using monotonic time
- // then only check the main file because time cycles on
- // every reboot.
- || strncmp(dp->d_name, file, len + monotonic)
- || (dp->d_name[len]
- && ((dp->d_name[len] != '.')
- || !isdigit(dp->d_name[len+1])))) {
+ if ((dp->d_type != DT_REG) ||
+ (strncmp(dp->d_name, file, len) != 0) ||
+ (dp->d_name[len] &&
+ ((dp->d_name[len] != '.') ||
+ (strtoll(dp->d_name + 1, NULL, 10) != 1)))) {
continue;
}
@@ -547,6 +544,7 @@
unsigned long setLogSize = 0;
int getPruneList = 0;
char *setPruneList = NULL;
+ char *setId = NULL;
int printStatistics = 0;
int mode = ANDROID_LOG_RDONLY;
const char *forceFilters = NULL;
@@ -574,6 +572,7 @@
int option_index = 0;
// list of long-argument only strings for later comparison
static const char pid_str[] = "pid";
+ static const char id_str[] = "id";
static const char wrap_str[] = "wrap";
static const char print_str[] = "print";
static const struct option long_options[] = {
@@ -588,6 +587,7 @@
{ "grep", required_argument, NULL, 'e' },
// hidden and undocumented reserved alias for --max-count
{ "head", required_argument, NULL, 'm' },
+ { id_str, required_argument, NULL, 0 },
{ "last", no_argument, NULL, 'L' },
{ "max-count", required_argument, NULL, 'm' },
{ pid_str, required_argument, NULL, 0 },
@@ -613,7 +613,7 @@
switch (ret) {
case 0:
- // One of the long options
+ // only long options
if (long_options[option_index].name == pid_str) {
// ToDo: determine runtime PID_MAX?
if (!getSizeTArg(optarg, &pid, 1)) {
@@ -644,6 +644,10 @@
g_printItAnyways = true;
break;
}
+ if (long_options[option_index].name == id_str) {
+ setId = optarg && optarg[0] ? optarg : NULL;
+ break;
+ }
break;
case 's':
@@ -657,7 +661,7 @@
break;
case 'L':
- mode |= ANDROID_LOG_PSTORE;
+ mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
break;
case 'd':
@@ -968,7 +972,20 @@
logcat_panic(true, "-r requires -f as well\n");
}
- setupOutput();
+ if (setId != NULL) {
+ if (g_outputFileName == NULL) {
+ logcat_panic(true, "--id='%s' requires -f as well\n", setId);
+ }
+
+ std::string file_name = android::base::StringPrintf("%s.id", g_outputFileName);
+ std::string file;
+ bool file_ok = android::base::ReadFileToString(file_name, &file);
+ android::base::WriteStringToFile(setId, file_name,
+ S_IRUSR | S_IWUSR, getuid(), getgid());
+ if (!file_ok || (file.compare(setId) == 0)) {
+ setId = NULL;
+ }
+ }
if (hasSetLogFormat == 0) {
const char* logFormat = getenv("ANDROID_PRINTF_LOG");
@@ -1034,34 +1051,33 @@
continue;
}
- if (clearLog) {
+ if (clearLog || setId) {
if (g_outputFileName) {
int maxRotationCountDigits =
(g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
for (int i = g_maxRotatedLogs ; i >= 0 ; --i) {
- char *file;
+ std::string file;
if (i == 0) {
- asprintf(&file, "%s", g_outputFileName);
+ file = android::base::StringPrintf("%s", g_outputFileName);
} else {
- asprintf(&file, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
+ file = android::base::StringPrintf("%s.%.*d",
+ g_outputFileName, maxRotationCountDigits, i);
}
- if (!file) {
+ if (file.length() == 0) {
perror("while clearing log files");
clearFail = clearFail ?: dev->device;
break;
}
- err = unlink(file);
+ err = unlink(file.c_str());
if (err < 0 && errno != ENOENT && clearFail == NULL) {
perror("while clearing log files");
clearFail = dev->device;
}
-
- free(file);
}
} else if (android_logger_clear(dev->logger)) {
clearFail = clearFail ?: dev->device;
@@ -1177,7 +1193,6 @@
return EXIT_SUCCESS;
}
-
if (getLogSize) {
return EXIT_SUCCESS;
}
@@ -1188,6 +1203,8 @@
return EXIT_SUCCESS;
}
+ setupOutputAndSchedulingPolicy((mode & ANDROID_LOG_NONBLOCK) == 0);
+
//LOG_EVENT_INT(10, 12345);
//LOG_EVENT_LONG(11, 0x1122334455667788LL);
//LOG_EVENT_STRING(0, "whassup, doc?");
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
index ce1a451..1da1942 100644
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -35,7 +35,7 @@
# all exec/services are called with umask(077), so no gain beyond 0700
mkdir /data/misc/logd 0700 logd log
# logd for write to /data/misc/logd, log group for read from pstore (-L)
- exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256}
+ exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
start logcatd
# stop logcatd service and clear data
@@ -56,7 +56,7 @@
stop logcatd
# logcatd service
-service logcatd /system/bin/logcat -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256}
+service logcatd /system/bin/logcat -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
class late_start
disabled
# logd for write to /data/misc/logd, log group for read from log daemon
diff --git a/logcat/logpersist b/logcat/logpersist
index f0e7d42..c09b6b2 100755
--- a/logcat/logpersist
+++ b/logcat/logpersist
@@ -17,8 +17,9 @@
;;
esac
+log_uid=logd
log_tag_property=persist.log.tag
-data=/data/misc/logd
+data=/data/misc/logd/logcat
service=logcatd
size_default=256
buffer_default=all
@@ -74,11 +75,12 @@
if [ -n "${size}${buffer}" -o "true" = "${clear}" ]; then
echo WARNING: Can not use --clear, --size or --buffer with ${progname%.*}.cat >&2
fi
- su logd ls "${data}" |
+ su ${log_uid} ls "${data%/*}" |
tr -d '\r' |
sort -ru |
- sed "s#^#${data}/#" |
- su logd xargs cat
+ sed "s#^#${data%/*}/#" |
+ grep "${data}[.]*[0-9]*\$" |
+ su ${log_uid} xargs cat
;;
*.start)
current_buffer="`getprop ${property#persist.}.buffer`"
@@ -139,7 +141,7 @@
sleep 1
getprop ${property#persist.}
# also generate an error return code if not found running
- pgrep -u ${data##*/} ${service%d}
+ pgrep -u ${log_uid} ${service%d}
;;
*.stop)
if [ -n "${size}${buffer}" ]; then
@@ -171,6 +173,6 @@
if [ X"${log_tag}" != X"`getprop ${log_tag_property}`" ] ||
[ X"${logd_logpersistd}" != X"`getprop ${property}`" ]; then
- echo "WARNING: killing Settings" >&2
+ echo "WARNING: killing Settings application to pull in new values" >&2
am force-stop com.android.settings
fi
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 0043d1b..3daee13 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -848,6 +849,75 @@
EXPECT_FALSE(system(command));
}
+static int logrotate_count_id(const char *logcat_cmd, const char *tmp_out_dir) {
+
+ static const char log_filename[] = "log.txt";
+ char command[strlen(tmp_out_dir) + strlen(logcat_cmd) + strlen(log_filename) + 32];
+
+ snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
+
+ int ret;
+ EXPECT_FALSE((ret = system(command)));
+ if (ret) {
+ return -1;
+ }
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
+ EXPECT_NE(nullptr, dir);
+ if (!dir) {
+ return -1;
+ }
+ struct dirent *entry;
+ int count = 0;
+ while ((entry = readdir(dir.get()))) {
+ if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
+ continue;
+ }
+ ++count;
+ }
+ return count;
+}
+
+TEST(logcat, logrotate_id) {
+ static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n 32 -r 1 --id=test";
+ static const char logcat_short_cmd[] = "logcat -b all -t 10 -f %s/%s -n 32 -r 1 --id=test";
+ static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+ static const char log_filename[] = "log.txt";
+ char tmp_out_dir[strlen(tmp_out_dir_form) + 1];
+ ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
+
+ EXPECT_EQ(34, logrotate_count_id(logcat_cmd, tmp_out_dir));
+ EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+
+ char id_file[strlen(tmp_out_dir_form) + strlen(log_filename) + 5];
+ snprintf(id_file, sizeof(id_file), "%s/%s.id", tmp_out_dir, log_filename);
+ if (getuid() != 0) {
+ chmod(id_file, 0);
+ EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+ }
+ unlink(id_file);
+ EXPECT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+
+ FILE *fp = fopen(id_file, "w");
+ if (fp) {
+ fprintf(fp, "not_a_test");
+ fclose(fp);
+ }
+ if (getuid() != 0) {
+ chmod(id_file, 0); // API to preserve content even with signature change
+ ASSERT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
+ chmod(id_file, 0600);
+ }
+
+ int new_signature;
+ EXPECT_LE(2, (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir)));
+ EXPECT_GT(34, new_signature);
+
+ static const char cleanup_cmd[] = "rm -rf %s";
+ char command[strlen(cleanup_cmd) + strlen(tmp_out_dir_form)];
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+}
+
TEST(logcat, logrotate_nodir) {
// expect logcat to error out on writing content and exit(1) for nodir
EXPECT_EQ(W_EXITCODE(1, 0),
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index ac2b128..0495463 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -605,126 +605,124 @@
const char *tag = "";
const char *etag = tag;
size_t taglen = len - (p - buf);
- if (!isspace(*p) && *p) {
- const char *bt, *et, *cp;
+ const char *bt = p;
- bt = p;
- if ((taglen >= 6) && !fast<strncmp>(p, "[INFO]", 6)) {
- // <PRI>[<TIME>] "[INFO]"<tag> ":" message
- bt = p + 6;
- taglen -= 6;
- }
- for(et = bt; taglen && *et && (*et != ':') && !isspace(*et); ++et, --taglen) {
- // skip ':' within [ ... ]
- if (*et == '[') {
- while (taglen && *et && *et != ']') {
- ++et;
- --taglen;
- }
- }
- }
- for(cp = et; taglen && isspace(*cp); ++cp, --taglen);
- size_t size;
+ static const char infoBrace[] = "[INFO]";
+ static const size_t infoBraceLen = strlen(infoBrace);
+ if ((taglen >= infoBraceLen) && !fast<strncmp>(p, infoBrace, infoBraceLen)) {
+ // <PRI>[<TIME>] "[INFO]"<tag> ":" message
+ bt = p + infoBraceLen;
+ taglen -= infoBraceLen;
+ }
+ const char *et;
+ for (et = bt; taglen && *et && (*et != ':') && !isspace(*et); ++et, --taglen) {
+ // skip ':' within [ ... ]
+ if (*et == '[') {
+ while (taglen && *et && *et != ']') {
+ ++et;
+ --taglen;
+ }
+ if (!taglen) {
+ break;
+ }
+ }
+ }
+ const char *cp;
+ for (cp = et; taglen && isspace(*cp); ++cp, --taglen);
+
+ // Validate tag
+ size_t size = et - bt;
+ if (taglen && size) {
if (*cp == ':') {
+ // ToDo: handle case insensitive colon separated logging stutter:
+ // <tag> : <tag>: ...
+
// One Word
tag = bt;
etag = et;
p = cp + 1;
- } else if (taglen) {
- size = et - bt;
- if ((taglen > size) && // enough space for match plus trailing :
- (*bt == *cp) && // ubber fast<strncmp> pair
- fast<strncmp>(bt + 1, cp + 1, size - 1)) {
- // <PRI>[<TIME>] <tag>_host '<tag>.<num>' : message
- if (!fast<strncmp>(bt + size - 5, "_host", 5)
- && !fast<strncmp>(bt + 1, cp + 1, size - 6)) {
+ } else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) {
+ // clean up any tag stutter
+ if (!fast<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
+ // <PRI>[<TIME>] <tag> <tag> : message
+ // <PRI>[<TIME>] <tag> <tag>: message
+ // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
+ // <PRI>[<TIME>] <tag> '<tag><num>' : message
+ // <PRI>[<TIME>] <tag> '<tag><stuff>' : message
+ const char *b = cp;
+ cp += size;
+ taglen -= size;
+ while (--taglen && !isspace(*++cp) && (*cp != ':'));
+ const char *e;
+ for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
+ if (taglen && (*cp == ':')) {
+ tag = b;
+ etag = e;
+ p = cp + 1;
+ }
+ } else {
+ // what about <PRI>[<TIME>] <tag>_host '<tag><stuff>' : message
+ static const char host[] = "_host";
+ static const size_t hostlen = strlen(host);
+ if ((size > hostlen) &&
+ !fast<strncmp>(bt + size - hostlen, host, hostlen) &&
+ !fast<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
const char *b = cp;
- cp += size - 5;
- taglen -= size - 5;
+ cp += size - hostlen;
+ taglen -= size - hostlen;
if (*cp == '.') {
while (--taglen && !isspace(*++cp) && (*cp != ':'));
const char *e;
- for(e = cp; taglen && isspace(*cp); ++cp, --taglen);
- if (*cp == ':') {
+ for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
+ if (taglen && (*cp == ':')) {
tag = b;
etag = e;
p = cp + 1;
}
}
} else {
- while (--taglen && !isspace(*++cp) && (*cp != ':'));
- const char *e;
- for(e = cp; taglen && isspace(*cp); ++cp, --taglen);
- // Two words
- if (*cp == ':') {
- tag = bt;
- etag = e;
- p = cp + 1;
- }
- }
- } else if (isspace(cp[size])) {
- cp += size;
- taglen -= size;
- while (--taglen && isspace(*++cp));
- // <PRI>[<TIME>] <tag> <tag> : message
- if (*cp == ':') {
- tag = bt;
- etag = et;
- p = cp + 1;
- }
- } else if (cp[size] == ':') {
- // <PRI>[<TIME>] <tag> <tag> : message
- tag = bt;
- etag = et;
- p = cp + size + 1;
- } else if ((cp[size] == '.') || isdigit(cp[size])) {
- // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
- // <PRI>[<TIME>] <tag> '<tag><num>' : message
- const char *b = cp;
- cp += size;
- taglen -= size;
- while (--taglen && !isspace(*++cp) && (*cp != ':'));
- const char *e = cp;
- while (taglen && isspace(*cp)) {
- ++cp;
- --taglen;
- }
- if (*cp == ':') {
- tag = b;
- etag = e;
- p = cp + 1;
- }
- } else {
- while (--taglen && !isspace(*++cp) && (*cp != ':'));
- const char *e = cp;
- while (taglen && isspace(*cp)) {
- ++cp;
- --taglen;
- }
- // Two words
- if (*cp == ':') {
- tag = bt;
- etag = e;
- p = cp + 1;
+ goto twoWord;
}
}
- } /* else no tag */
- size = etag - tag;
- if ((size <= 1)
- // register names like x9
- || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1])))
- // register names like x18 but not driver names like en0
- || ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2])))
- // blacklist
- || ((size == 3) && !fast<strncmp>(tag, "CPU", 3))
- || ((size == 7) && !fast<strncasecmp>(tag, "WARNING", 7))
- || ((size == 5) && !fast<strncasecmp>(tag, "ERROR", 5))
- || ((size == 4) && !fast<strncasecmp>(tag, "INFO", 4))) {
- p = start;
- etag = tag = "";
+ } else {
+ // <PRI>[<TIME>] <tag> <stuff>' : message
+twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':'));
+ const char *e;
+ for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
+ // Two words
+ if (taglen && (*cp == ':')) {
+ tag = bt;
+ etag = e;
+ p = cp + 1;
+ }
}
+ } // else no tag
+
+ static const char cpu[] = "CPU";
+ static const size_t cpuLen = strlen(cpu);
+ static const char warning[] = "WARNING";
+ static const size_t warningLen = strlen(warning);
+ static const char error[] = "ERROR";
+ static const size_t errorLen = strlen(error);
+ static const char info[] = "INFO";
+ static const size_t infoLen = strlen(info);
+
+ size = etag - tag;
+ if ((size <= 1)
+ // register names like x9
+ || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1])))
+ // register names like x18 but not driver names like en0
+ || ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2])))
+ // blacklist
+ || ((size == cpuLen) && !fast<strncmp>(tag, cpu, cpuLen))
+ || ((size == warningLen) && !fast<strncasecmp>(tag, warning, warningLen))
+ || ((size == errorLen) && !fast<strncasecmp>(tag, error, errorLen))
+ || ((size == infoLen) && !fast<strncasecmp>(tag, info, infoLen))) {
+ p = start;
+ etag = tag = "";
}
+
// Suppress additional stutter in tag:
// eg: [143:healthd]healthd -> [143:healthd]
taglen = etag - tag;