Merge "Rename single buffer mode to shared buffer mode" into nyc-dev
diff --git a/bootstat/Android.mk b/bootstat/Android.mk
index 3d02752..6300941 100644
--- a/bootstat/Android.mk
+++ b/bootstat/Android.mk
@@ -21,6 +21,7 @@
bootstat_lib_src_files := \
boot_event_record_store.cpp \
event_log_list_builder.cpp \
+ histogram_logger.cpp \
uptime_parser.cpp \
bootstat_src_files := \
@@ -41,17 +42,13 @@
-Wextra \
-Werror \
-bootstat_cppflags := \
- -Wno-non-virtual-dtor \
-
-bootstat_debug_cflags := \
- $(bootstat_cflags) \
- -UNDEBUG \
-
# 524291 corresponds to sysui_histogram, from
# frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
bootstat_cflags += -DHISTOGRAM_LOG_TAG=524291
+bootstat_debug_cflags := \
+ $(bootstat_cflags) \
+ -UNDEBUG \
# bootstat static library
# -----------------------------------------------------------------------------
@@ -60,7 +57,6 @@
LOCAL_MODULE := libbootstat
LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_CPPFLAGS := $(bootstat_cppflags)
LOCAL_C_INCLUDES := $(bootstat_c_includes)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_SRC_FILES := $(bootstat_lib_src_files)
@@ -76,7 +72,6 @@
LOCAL_MODULE := libbootstat_debug
LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_CPPFLAGS := $(bootstat_debug_cppflags)
LOCAL_C_INCLUDES := $(bootstat_c_includes)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_SRC_FILES := $(bootstat_lib_src_files)
@@ -92,7 +87,6 @@
LOCAL_MODULE := libbootstat_host_debug
LOCAL_CFLAGS := $(bootstat_debug_cflags)
-LOCAL_CPPFLAGS := $(bootstat_cppflags)
LOCAL_C_INCLUDES := $(bootstat_c_includes)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_SRC_FILES := $(bootstat_lib_src_files)
@@ -108,7 +102,6 @@
LOCAL_MODULE := bootstat
LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_CPPFLAGS := $(bootstat_cppflags)
LOCAL_C_INCLUDES := $(bootstat_c_includes)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_STATIC_LIBRARIES := libbootstat
@@ -126,7 +119,6 @@
LOCAL_MODULE := bootstat_tests
LOCAL_CFLAGS := $(bootstat_tests_cflags)
-LOCAL_CPPFLAGS := $(bootstat_cppflags)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_STATIC_LIBRARIES := libbootstat_debug libgmock
LOCAL_SRC_FILES := $(bootstat_test_src_files)
@@ -142,7 +134,6 @@
LOCAL_MODULE := bootstat_tests
LOCAL_CFLAGS := $(bootstat_tests_cflags)
-LOCAL_CPPFLAGS := $(bootstat_cppflags)
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_STATIC_LIBRARIES := libbootstat_host_debug libgmock_host
LOCAL_SRC_FILES := $(bootstat_test_src_files)
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index 40254f8..5d1fae9 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -21,9 +21,11 @@
#include <sys/stat.h>
#include <utime.h>
#include <cstdlib>
+#include <string>
#include <utility>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include "histogram_logger.h"
#include "uptime_parser.h"
namespace {
@@ -42,6 +44,20 @@
}
*uptime = file_stat.st_mtime;
+
+ // The following code (till function exit) is a debug test to ensure the
+ // validity of the file mtime value, i.e., to check that the record file
+ // mtime values are not changed once set.
+ // TODO(jhawkins): Remove this code.
+ std::string content;
+ if (!android::base::ReadFileToString(path, &content)) {
+ PLOG(ERROR) << "Failed to read " << path;
+ return false;
+ }
+
+ int32_t value = std::stoi(content);
+ bootstat::LogHistogram("bootstat_mtime_matches_content", value == *uptime);
+
return true;
}
@@ -61,8 +77,20 @@
void BootEventRecordStore::AddBootEventWithValue(
const std::string& event, int32_t value) {
std::string record_path = GetBootEventPath(event);
- if (creat(record_path.c_str(), S_IRUSR | S_IWUSR) == -1) {
+ int record_fd = creat(record_path.c_str(), S_IRUSR | S_IWUSR);
+ if (record_fd == -1) {
PLOG(ERROR) << "Failed to create " << record_path;
+ return;
+ }
+
+ // Writing the value as content in the record file is a debug measure to
+ // ensure the validity of the file mtime value, i.e., to check that the record
+ // file mtime values are not changed once set.
+ // TODO(jhawkins): Remove this block.
+ if (!android::base::WriteStringToFd(std::to_string(value), record_fd)) {
+ PLOG(ERROR) << "Failed to write value to " << record_path;
+ close(record_fd);
+ return;
}
// Fill out the stat structure for |record_path| in order to get the atime to
@@ -70,6 +98,8 @@
struct stat file_stat;
if (stat(record_path.c_str(), &file_stat) == -1) {
PLOG(ERROR) << "Failed to read " << record_path;
+ close(record_fd);
+ return;
}
// Set the |modtime| of the file to store the value of the boot event while
@@ -77,7 +107,11 @@
struct utimbuf times = {/* actime */ file_stat.st_atime, /* modtime */ value};
if (utime(record_path.c_str(), ×) == -1) {
PLOG(ERROR) << "Failed to set mtime for " << record_path;
+ close(record_fd);
+ return;
}
+
+ close(record_fd);
}
bool BootEventRecordStore::GetBootEvent(
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 4c8c8b6..360447f 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -32,26 +32,11 @@
#include <log/log.h>
#include "boot_event_record_store.h"
#include "event_log_list_builder.h"
+#include "histogram_logger.h"
#include "uptime_parser.h"
namespace {
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
-void LogBootEvent(const std::string& event, int32_t data) {
- LOG(INFO) << "Logging boot metric: " << event << " " << data;
-
- EventLogListBuilder log_builder;
- log_builder.Append(event);
- log_builder.Append(data);
-
- std::unique_ptr<uint8_t[]> log;
- size_t size;
- log_builder.Release(&log, &size);
-
- android_bWriteLog(HISTOGRAM_LOG_TAG, log.get(), size);
-}
-
// Scans the boot event record store for record files and logs each boot event
// via EventLog.
void LogBootEvents() {
@@ -59,7 +44,7 @@
auto events = boot_event_store.GetAllBootEvents();
for (auto i = events.cbegin(); i != events.cend(); ++i) {
- LogBootEvent(i->first, i->second);
+ bootstat::LogHistogram(i->first, i->second);
}
}
@@ -202,10 +187,10 @@
static const char* factory_reset_current_time = "factory_reset_current_time";
if (current_time_utc < 0) {
// UMA does not display negative values in buckets, so convert to positive.
- LogBootEvent(factory_reset_current_time, std::abs(current_time_utc));
+ bootstat::LogHistogram(factory_reset_current_time, std::abs(current_time_utc));
return;
} else {
- LogBootEvent(factory_reset_current_time, current_time_utc);
+ bootstat::LogHistogram(factory_reset_current_time, current_time_utc);
}
// The factory_reset boot event does not exist after the device is reset, so
@@ -221,7 +206,7 @@
// Calculate and record the difference in time between now and the
// factory_reset time.
time_t factory_reset_utc = record.second;
- LogBootEvent("factory_reset_record_value", factory_reset_utc);
+ bootstat::LogHistogram("factory_reset_record_value", factory_reset_utc);
time_t time_since_factory_reset = difftime(current_time_utc,
factory_reset_utc);
boot_event_store.AddBootEventWithValue("time_since_factory_reset",
diff --git a/bootstat/histogram_logger.cpp b/bootstat/histogram_logger.cpp
new file mode 100644
index 0000000..e3aad28
--- /dev/null
+++ b/bootstat/histogram_logger.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 "histogram_logger.h"
+
+#include <cstdlib>
+#include <memory>
+#include <android-base/logging.h>
+#include <log/log.h>
+#include "event_log_list_builder.h"
+
+namespace bootstat {
+
+void LogHistogram(const std::string& event, int32_t data) {
+ LOG(INFO) << "Logging histogram: " << event << " " << data;
+
+ EventLogListBuilder log_builder;
+ log_builder.Append(event);
+ log_builder.Append(data);
+
+ std::unique_ptr<uint8_t[]> log;
+ size_t size;
+ log_builder.Release(&log, &size);
+
+ android_bWriteLog(HISTOGRAM_LOG_TAG, log.get(), size);
+}
+
+} // namespace bootstat
\ No newline at end of file
diff --git a/bootstat/histogram_logger.h b/bootstat/histogram_logger.h
new file mode 100644
index 0000000..60c7776
--- /dev/null
+++ b/bootstat/histogram_logger.h
@@ -0,0 +1,26 @@
+/*
+ * 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 <cstdint>
+#include <string>
+
+namespace bootstat {
+
+// Builds an EventLog buffer named |event| containing |data| and writes
+// the log into the Tron histogram logs.
+void LogHistogram(const std::string& event, int32_t data);
+
+} // namespace bootstat
\ No newline at end of file
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index fff2880..12f507a 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -248,8 +248,8 @@
return 0;
}
-static bool should_attach_gdb(debugger_request_t* request) {
- if (request->action == DEBUGGER_ACTION_CRASH) {
+static bool should_attach_gdb(const debugger_request_t& request) {
+ if (request.action == DEBUGGER_ACTION_CRASH) {
return property_get_bool("debug.debuggerd.wait_for_gdb", false);
}
return false;
@@ -415,6 +415,7 @@
#ifdef SIGSTKFLT
case SIGSTKFLT:
#endif
+ case SIGSYS:
case SIGTRAP:
ALOGV("stopped -- fatal signal\n");
*crash_signal = signal;
@@ -487,7 +488,7 @@
// Don't attach to the sibling threads if we want to attach gdb.
// Supposedly, it makes the process less reliable.
- bool attach_gdb = should_attach_gdb(&request);
+ bool attach_gdb = should_attach_gdb(request);
if (attach_gdb) {
// Open all of the input devices we need to listen for VOLUMEDOWN before dropping privileges.
if (init_getevent() != 0) {
@@ -563,6 +564,10 @@
static void monitor_worker_process(int child_pid, const debugger_request_t& request) {
struct timespec timeout = {.tv_sec = 10, .tv_nsec = 0 };
+ if (should_attach_gdb(request)) {
+ // If wait_for_gdb is enabled, set the timeout to something large.
+ timeout.tv_sec = INT_MAX;
+ }
sigset_t signal_set;
sigemptyset(&signal_set);
@@ -576,15 +581,24 @@
siginfo_t siginfo;
int signal = TEMP_FAILURE_RETRY(sigtimedwait(&signal_set, &siginfo, &timeout));
if (signal == SIGCHLD) {
- pid_t rc = waitpid(0, &status, WNOHANG | WUNTRACED);
+ pid_t rc = waitpid(-1, &status, WNOHANG | WUNTRACED);
if (rc != child_pid) {
ALOGE("debuggerd: waitpid returned unexpected pid (%d), committing murder-suicide", rc);
+
+ if (WIFEXITED(status)) {
+ ALOGW("debuggerd: pid %d exited with status %d", rc, WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ ALOGW("debuggerd: pid %d received signal %d", rc, WTERMSIG(status));
+ } else if (WIFSTOPPED(status)) {
+ ALOGW("debuggerd: pid %d stopped by signal %d", rc, WSTOPSIG(status));
+ } else if (WIFCONTINUED(status)) {
+ ALOGW("debuggerd: pid %d continued", rc);
+ }
+
kill_worker = true;
kill_target = true;
kill_self = true;
- }
-
- if (WIFSIGNALED(status)) {
+ } else if (WIFSIGNALED(status)) {
ALOGE("debuggerd: worker process %d terminated due to signal %d", child_pid, WTERMSIG(status));
kill_worker = false;
kill_target = true;
@@ -608,15 +622,16 @@
}
}
- if (kill_target) {
- // Resume or kill the target, depending on what the initial request was.
- if (request.action == DEBUGGER_ACTION_CRASH) {
- ALOGE("debuggerd: killing target %d", request.pid);
- kill(request.pid, SIGKILL);
- } else {
- ALOGE("debuggerd: resuming target %d", request.pid);
- kill(request.pid, SIGCONT);
- }
+ int exit_signal = SIGCONT;
+ if (kill_target && request.action == DEBUGGER_ACTION_CRASH) {
+ ALOGE("debuggerd: killing target %d", request.pid);
+ exit_signal = SIGKILL;
+ } else {
+ ALOGW("debuggerd: resuming target %d", request.pid);
+ }
+
+ if (kill(request.pid, exit_signal) != 0) {
+ ALOGE("debuggerd: failed to send signal %d to target: %s", exit_signal, strerror(errno));
}
if (kill_self) {
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index 04238a6..c3ea1ed 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -19,7 +19,10 @@
#ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
#define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
+/* Android private interfaces */
+
#include <stdint.h>
+#include <sys/types.h>
#include <log/log.h>
#include <log/log_read.h>
@@ -95,4 +98,35 @@
char data[];
} android_log_event_string_t;
+#if defined(__cplusplus)
+extern "C" {
#endif
+
+#define ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE 256 /* 1MB file */
+#define ANDROID_LOG_PMSG_FILE_SEQUENCE 1000
+
+ssize_t __android_log_pmsg_file_write(
+ log_id_t logId,
+ char prio,
+ const char *filename,
+ const char *buf, size_t len);
+
+#define LOG_ID_ANY ((log_id_t)-1)
+#define ANDROID_LOG_ANY ANDROID_LOG_UNKNOWN
+
+/* first 5 arguments match __android_log_msg_file_write, a cast is safe */
+typedef ssize_t (*__android_log_pmsg_file_read_fn)(
+ log_id_t logId,
+ char prio,
+ const char *filename,
+ const char *buf, size_t len, void *arg);
+
+ssize_t __android_log_pmsg_file_read(
+ log_id_t logId, char prio, const char *prefix,
+ __android_log_pmsg_file_read_fn fn, void *arg);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_ */
diff --git a/include/system/graphics.h b/include/system/graphics.h
index 880cb9f..eabe18e 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -1038,6 +1038,34 @@
} android_dataspace_t;
+/*
+ * Color transforms that may be applied by hardware composer to the whole
+ * display.
+ */
+typedef enum android_color_transform {
+ /* Applies no transform to the output color */
+ HAL_COLOR_TRANSFORM_IDENTITY = 0,
+
+ /* Applies an arbitrary transform defined by a 4x4 affine matrix */
+ HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
+
+ /* Applies a transform that inverts the value or luminance of the color, but
+ * does not modify hue or saturation */
+ HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
+
+ /* Applies a transform that maps all colors to shades of gray */
+ HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
+
+ /* Applies a transform which corrects for protanopic color blindness */
+ HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
+
+ /* Applies a transform which corrects for deuteranopic color blindness */
+ HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
+
+ /* Applies a transform which corrects for tritanopic color blindness */
+ HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6
+} android_color_transform_t;
+
#ifdef __cplusplus
}
#endif
diff --git a/init/init.cpp b/init/init.cpp
index 4aef823..0ff55a5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,6 +18,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <fstream>
#include <libgen.h>
#include <paths.h>
#include <signal.h>
@@ -290,6 +291,100 @@
return result;
}
+static void security_failure() {
+ ERROR("Security failure; rebooting into recovery mode...\n");
+ android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+ while (true) { pause(); } // never reached
+}
+
+#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
+#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
+
+/* __attribute__((unused)) due to lack of mips support: see mips block
+ * in set_mmap_rnd_bits_action */
+static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
+ std::string path;
+ if (compat) {
+ path = MMAP_RND_COMPAT_PATH;
+ } else {
+ path = MMAP_RND_PATH;
+ }
+ std::ifstream inf(path, std::fstream::in);
+ if (!inf) {
+ return false;
+ }
+ while (start >= min) {
+ // try to write out new value
+ std::string str_val = std::to_string(start);
+ std::ofstream of(path, std::fstream::out);
+ if (!of) {
+ return false;
+ }
+ of << str_val << std::endl;
+ of.close();
+
+ // check to make sure it was recorded
+ inf.seekg(0);
+ std::string str_rec;
+ inf >> str_rec;
+ if (str_val.compare(str_rec) == 0) {
+ break;
+ }
+ start--;
+ }
+ inf.close();
+ return (start >= min);
+}
+
+/*
+ * Set /proc/sys/vm/mmap_rnd_bits and potentially
+ * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
+ * Returns -1 if unable to set these to an acceptable value. Apply
+ * upstream patch-sets https://lkml.org/lkml/2015/12/21/337 and
+ * https://lkml.org/lkml/2016/2/4/831 to enable this.
+ */
+static int set_mmap_rnd_bits_action(const std::vector<std::string>& args)
+{
+ int ret = -1;
+
+ /* values are arch-dependent */
+#if defined(__aarch64__)
+ /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
+ if (set_mmap_rnd_bits_min(33, 24, false)
+ && set_mmap_rnd_bits_min(16, 16, true)) {
+ ret = 0;
+ }
+#elif defined(__x86_64__)
+ /* x86_64 supports 28 - 32 bits */
+ if (set_mmap_rnd_bits_min(32, 32, false)
+ && set_mmap_rnd_bits_min(16, 16, true)) {
+ ret = 0;
+ }
+#elif defined(__arm__) || defined(__i386__)
+ /* check to see if we're running on 64-bit kernel */
+ bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
+ /* supported 32-bit architecture must have 16 bits set */
+ if (set_mmap_rnd_bits_min(16, 16, h64)) {
+ ret = 0;
+ }
+#elif defined(__mips__) || defined(__mips64__)
+ // TODO: add mips support b/27788820
+ ret = 0;
+#else
+ ERROR("Unknown architecture\n");
+#endif
+
+#ifdef __BRILLO__
+ // TODO: b/27794137
+ ret = 0;
+#endif
+ if (ret == -1) {
+ ERROR("Unable to set adequate mmap entropy value!\n");
+ security_failure();
+ }
+ return ret;
+}
+
static int keychord_init_action(const std::vector<std::string>& args)
{
keychord_init();
@@ -492,12 +587,6 @@
return 0;
}
-static void security_failure() {
- ERROR("Security failure; rebooting into recovery mode...\n");
- android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
- while (true) { pause(); } // never reached
-}
-
static void selinux_initialize(bool in_kernel_domain) {
Timer t;
@@ -646,6 +735,7 @@
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+ am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
am.QueueBuiltinAction(console_init_action, "console_init");
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 995abc0..0d2e11b 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -52,24 +52,8 @@
}
}
-extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
- int* status);
-
std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
std::string func_name = GetFunctionNameRaw(pc, offset);
- if (!func_name.empty()) {
-#if defined(__APPLE__)
- // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
- if (func_name[0] != '_') {
- return func_name;
- }
-#endif
- char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
- if (name) {
- func_name = name;
- free(name);
- }
- }
return func_name;
}
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index ac14046..dc3ed67 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -564,7 +564,7 @@
uint64_t eh_frame_vaddr = 0;
std::vector<uint8_t> eh_frame_data;
- for (auto it = elf->begin_sections(); it != elf->end_sections(); ++it) {
+ for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
llvm::ErrorOr<llvm::StringRef> name = elf->getSectionName(&*it);
if (name) {
if (name.get() == ".debug_frame") {
@@ -603,7 +603,7 @@
}
std::vector<ProgramHeader> program_headers;
- for (auto it = elf->begin_program_headers(); it != elf->end_program_headers(); ++it) {
+ for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) {
ProgramHeader header;
header.vaddr = it->p_vaddr;
header.file_offset = it->p_offset;
diff --git a/libcutils/qtaguid.c b/libcutils/qtaguid.c
index 00e211c..2fbe02e 100644
--- a/libcutils/qtaguid.c
+++ b/libcutils/qtaguid.c
@@ -75,7 +75,8 @@
savedErrno = 0;
}
if (res < 0) {
- ALOGI("Failed write_ctrl(%s) res=%d errno=%d", cmd, res, savedErrno);
+ // ALOGV is enough because all the callers also log failures
+ ALOGV("Failed write_ctrl(%s) res=%d errno=%d", cmd, res, savedErrno);
}
close(fd);
return -savedErrno;
diff --git a/liblog/Android.bp b/liblog/Android.bp
index ee883f0..9e8491b 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -14,20 +14,30 @@
// limitations under the License.
//
-liblog_host_sources = [
- "logd_write.c",
+liblog_sources = [
+ "log_event_list.c",
"log_event_write.c",
+ "logger_write.c",
+ "config_write.c",
+ "logger_name.c",
+ "logger_lock.c",
+]
+liblog_host_sources = [
"fake_log_device.c",
//"event.logtags",
+ "fake_writer.c",
]
liblog_target_sources = [
- "logd_write.c",
- "log_event_write.c",
"event_tag_map.c",
+ "config_read.c",
"log_time.cpp",
"log_is_loggable.c",
"logprint.c",
- "log_read.c",
+ "pmsg_reader.c",
+ "pmsg_writer.c",
+ "logd_reader.c",
+ "logd_writer.c",
+ "logger_read.c",
]
// Shared and static library for host and device
@@ -36,6 +46,8 @@
name: "liblog",
host_supported: true,
+ srcs: liblog_sources,
+
target: {
host: {
srcs: liblog_host_sources,
@@ -64,6 +76,7 @@
cflags: [
"-Werror",
+ "-fvisibility=hidden",
// This is what we want to do:
// liblog_cflags := $(shell \
// sed -n \
@@ -71,7 +84,6 @@
// $(LOCAL_PATH)/event.logtags)
// so make sure we do not regret hard-coding it as follows:
"-DLIBLOG_LOG_TAG=1005",
- "-DSNET_EVENT_LOG_TAG=1397638484",
],
compile_multilib: "both",
stl: "none",
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 6d53a4a..01c8e77 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -24,10 +24,14 @@
# so make sure we do not regret hard-coding it as follows:
liblog_cflags := -DLIBLOG_LOG_TAG=1005
-liblog_sources := logd_write.c log_event_list.c log_event_write.c
+liblog_sources := log_event_list.c log_event_write.c logger_write.c
+liblog_sources += config_write.c logger_name.c logger_lock.c
liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
+liblog_host_sources += fake_writer.c
liblog_target_sources := $(liblog_sources) event_tag_map.c
-liblog_target_sources += log_time.cpp log_is_loggable.c logprint.c log_read.c
+liblog_target_sources += config_read.c log_time.cpp log_is_loggable.c logprint.c
+liblog_target_sources += pmsg_reader.c pmsg_writer.c
+liblog_target_sources += logd_reader.c logd_writer.c logger_read.c
# Shared and static library for host
# ========================================================
diff --git a/liblog/config_read.c b/liblog/config_read.c
new file mode 100644
index 0000000..1f54152
--- /dev/null
+++ b/liblog/config_read.c
@@ -0,0 +1,62 @@
+/*
+ * 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 "config_read.h"
+#include "logger.h"
+
+LIBLOG_HIDDEN struct listnode __android_log_transport_read =
+ { &__android_log_transport_read, &__android_log_transport_read };
+LIBLOG_HIDDEN struct listnode __android_log_persist_read =
+ { &__android_log_persist_read, &__android_log_persist_read };
+
+static void __android_log_add_transport(
+ struct listnode *list, struct android_log_transport_read *transport) {
+ size_t i;
+
+ /* Try to keep one functioning transport for each log buffer id */
+ for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
+ struct android_log_transport_read *transp;
+
+ if (list_empty(list)) {
+ if (!transport->available || ((*transport->available)(i) >= 0)) {
+ list_add_tail(list, &transport->node);
+ return;
+ }
+ } else {
+ read_transport_for_each(transp, list) {
+ if (!transp->available) {
+ return;
+ }
+ if (((*transp->available)(i) < 0) &&
+ (!transport->available ||
+ ((*transport->available)(i) >= 0))) {
+ list_add_tail(list, &transport->node);
+ return;
+ }
+ }
+ }
+ }
+}
+
+LIBLOG_HIDDEN void __android_log_config_read() {
+#if (FAKE_LOG_DEVICE == 0)
+ extern struct android_log_transport_read logdLoggerRead;
+ extern struct android_log_transport_read pmsgLoggerRead;
+
+ __android_log_add_transport(&__android_log_transport_read, &logdLoggerRead);
+ __android_log_add_transport(&__android_log_persist_read, &pmsgLoggerRead);
+#endif
+}
diff --git a/liblog/config_read.h b/liblog/config_read.h
new file mode 100644
index 0000000..67f4c20
--- /dev/null
+++ b/liblog/config_read.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBLOG_CONFIG_READ_H__
+#define _LIBLOG_CONFIG_READ_H__
+
+#include <cutils/list.h>
+
+#include "log_portability.h"
+
+__BEGIN_DECLS
+
+extern LIBLOG_HIDDEN struct listnode __android_log_transport_read;
+extern LIBLOG_HIDDEN struct listnode __android_log_persist_read;
+
+#define read_transport_for_each(transp, transports) \
+ for (transp = node_to_item((transports)->next, \
+ struct android_log_transport_read, node); \
+ (transp != node_to_item(transports, \
+ struct android_log_transport_read, node)); \
+ transp = node_to_item(transp->node.next, \
+ struct android_log_transport_read, node)) \
+
+#define read_transport_for_each_safe(transp, n, transports) \
+ for (transp = node_to_item((transports)->next, \
+ struct android_log_transport_read, node), \
+ n = transp->node.next; \
+ (transp != node_to_item(transports, \
+ struct android_log_transport_read, node)); \
+ transp = node_to_item(n, struct android_log_transport_read, node), \
+ n = transp->node.next)
+
+LIBLOG_HIDDEN void __android_log_config_read();
+
+__END_DECLS
+
+#endif /* _LIBLOG_CONFIG_READ_H__ */
diff --git a/liblog/config_write.c b/liblog/config_write.c
new file mode 100644
index 0000000..d689f63
--- /dev/null
+++ b/liblog/config_write.c
@@ -0,0 +1,66 @@
+/*
+ * 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 "config_write.h"
+#include "logger.h"
+
+LIBLOG_HIDDEN struct listnode __android_log_transport_write =
+ { &__android_log_transport_write, &__android_log_transport_write };
+LIBLOG_HIDDEN struct listnode __android_log_persist_write =
+ { &__android_log_persist_write, &__android_log_persist_write};
+
+static void __android_log_add_transport(
+ struct listnode *list, struct android_log_transport_write *transport) {
+ size_t i;
+
+ /* Try to keep one functioning transport for each log buffer id */
+ for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
+ struct android_log_transport_write *transp;
+
+ if (list_empty(list)) {
+ if (!transport->available || ((*transport->available)(i) >= 0)) {
+ list_add_tail(list, &transport->node);
+ return;
+ }
+ } else {
+ write_transport_for_each(transp, list) {
+ if (!transp->available) {
+ return;
+ }
+ if (((*transp->available)(i) < 0) &&
+ (!transport->available ||
+ ((*transport->available)(i) >= 0))) {
+ list_add_tail(list, &transport->node);
+ return;
+ }
+ }
+ }
+ }
+}
+
+LIBLOG_HIDDEN void __android_log_config_write() {
+#if (FAKE_LOG_DEVICE == 0)
+ extern struct android_log_transport_write logdLoggerWrite;
+ extern struct android_log_transport_write pmsgLoggerWrite;
+
+ __android_log_add_transport(&__android_log_transport_write, &logdLoggerWrite);
+ __android_log_add_transport(&__android_log_persist_write, &pmsgLoggerWrite);
+#else
+ extern struct android_log_transport_write fakeLoggerWrite;
+
+ __android_log_add_transport(&__android_log_transport_write, &fakeLoggerWrite);
+#endif
+}
diff --git a/liblog/config_write.h b/liblog/config_write.h
new file mode 100644
index 0000000..3a02a4e
--- /dev/null
+++ b/liblog/config_write.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBLOG_CONFIG_WRITE_H__
+#define _LIBLOG_CONFIG_WRITE_H__
+
+#include <cutils/list.h>
+
+#include "log_portability.h"
+
+__BEGIN_DECLS
+
+extern LIBLOG_HIDDEN struct listnode __android_log_transport_write;
+extern LIBLOG_HIDDEN struct listnode __android_log_persist_write;
+
+#define write_transport_for_each(transp, transports) \
+ for (transp = node_to_item((transports)->next, \
+ struct android_log_transport_write, node); \
+ (transp != node_to_item(transports, \
+ struct android_log_transport_write, node)); \
+ transp = node_to_item(transp->node.next, \
+ struct android_log_transport_write, node)) \
+
+#define write_transport_for_each_safe(transp, n, transports) \
+ for (transp = node_to_item((transports)->next, \
+ struct android_log_transport_write, node), \
+ n = transp->node.next; \
+ (transp != node_to_item(transports, \
+ struct android_log_transport_write, node)); \
+ transp = node_to_item(n, struct android_log_transport_write, node), \
+ n = transp->node.next)
+
+LIBLOG_HIDDEN void __android_log_config_write();
+
+__END_DECLS
+
+#endif /* _LIBLOG_CONFIG_WRITE_H__ */
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 870c69a..64d872a 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -24,7 +24,7 @@
#include <log/event_tag_map.h>
#include <log/log.h>
-#include "log_cdefs.h"
+#include "log_portability.h"
#define OUT_TAG "EventTagMap"
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index c73e03e..cc67f3e 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -31,7 +31,7 @@
#include <log/logd.h>
#include "fake_log_device.h"
-#include "log_cdefs.h"
+#include "log_portability.h"
#define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index 672b446..4529b5d 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -19,7 +19,7 @@
#include <sys/types.h>
-#include "log_cdefs.h"
+#include "log_portability.h"
struct iovec;
diff --git a/liblog/fake_writer.c b/liblog/fake_writer.c
new file mode 100644
index 0000000..dab8bc5
--- /dev/null
+++ b/liblog/fake_writer.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007-2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <log/log.h>
+
+#include "config_write.h"
+#include "fake_log_device.h"
+#include "log_portability.h"
+#include "logger.h"
+
+static int fakeOpen();
+static void fakeClose();
+static int fakeWrite(log_id_t log_id, struct timespec *ts,
+ struct iovec *vec, size_t nr);
+
+static int logFds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 };
+
+LIBLOG_HIDDEN struct android_log_transport_write fakeLoggerWrite = {
+ .node = { &fakeLoggerWrite.node, &fakeLoggerWrite.node },
+ .context.private = &logFds,
+ .name = "fake",
+ .available = NULL,
+ .open = fakeOpen,
+ .close = fakeClose,
+ .write = fakeWrite,
+};
+
+static int fakeOpen() {
+ int i;
+
+ for (i = 0; i < LOG_ID_MAX; i++) {
+ char buf[sizeof("/dev/log_security")];
+ snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
+ logFds[i] = fakeLogOpen(buf, O_WRONLY);
+ }
+ return 0;
+}
+
+static void fakeClose() {
+ int i;
+
+ for (i = 0; i < LOG_ID_MAX; i++) {
+ fakeLogClose(logFds[i]);
+ logFds[i] = -1;
+ }
+}
+
+static int fakeWrite(log_id_t log_id, struct timespec *ts __unused,
+ struct iovec *vec, size_t nr)
+{
+ ssize_t ret;
+ int logFd;
+
+ if (/*(int)log_id >= 0 &&*/ (int)log_id >= (int)LOG_ID_MAX) {
+ return -EBADF;
+ }
+
+ logFd = logFds[(int)log_id];
+ ret = TEMP_FAILURE_RETRY(fakeLogWritev(logFd, vec, nr));
+ if (ret < 0) {
+ ret = -errno;
+ }
+
+ return ret;
+}
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
index a77c56e..64d9024 100644
--- a/liblog/log_event_list.c
+++ b/liblog/log_event_list.c
@@ -25,7 +25,7 @@
#include <log/log.h>
#include <log/logger.h>
-#include "log_cdefs.h"
+#include "log_portability.h"
#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
index 3535b94..b9827a1 100644
--- a/liblog/log_event_write.c
+++ b/liblog/log_event_write.c
@@ -18,7 +18,7 @@
#include <log/log.h>
-#include "log_cdefs.h"
+#include "log_portability.h"
#define MAX_SUBTAG_LEN 32
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 47fde20..551fa76 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -23,7 +23,7 @@
#include <android/log.h>
-#include "log_cdefs.h"
+#include "log_portability.h"
static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
diff --git a/liblog/log_cdefs.h b/liblog/log_portability.h
similarity index 65%
rename from liblog/log_cdefs.h
rename to liblog/log_portability.h
index 3a52625..3ad2060 100644
--- a/liblog/log_cdefs.h
+++ b/liblog/log_portability.h
@@ -14,10 +14,13 @@
* limitations under the License.
*/
-#ifndef _LIBLOG_CDEFS_H__
-#define _LIBLOG_CDEFS_H__
+#ifndef _LIBLOG_PORTABILITY_H__
+#define _LIBLOG_PORTABILITY_H__
#include <sys/cdefs.h>
+#include <unistd.h>
+
+/* Helpful private sys/cdefs.h like definitions */
/* Declare this library function hidden and internal */
#if defined(_WIN32)
@@ -46,9 +49,34 @@
#define LIBLOG_WEAK __attribute__((weak,visibility("default")))
#endif
+/* possible missing definitions in sys/cdefs.h */
+
+/* DECLS */
+#ifndef __BEGIN_DECLS
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS }
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+#endif
+
/* Unused argument. For C code only, remove symbol name for C++ */
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
-#endif /* _LIBLOG_CDEFS_H__ */
+/* possible missing definitions in unistd.h */
+
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({ \
+ __typeof__(exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
+#endif
+
+#endif /* _LIBLOG_PORTABILITY_H__ */
diff --git a/liblog/log_read.c b/liblog/log_read.c
deleted file mode 100644
index 4b83944..0000000
--- a/liblog/log_read.c
+++ /dev/null
@@ -1,917 +0,0 @@
-/*
-** Copyright 2013-2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stddef.h>
-#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <cutils/list.h>
-#include <cutils/sockets.h>
-#include <log/log.h>
-#include <log/logger.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "log_cdefs.h"
-
-/* branchless on many architectures. */
-#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
-
-/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
-
-#if defined(_WIN32)
-
-LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
-{
- errno = ENOSYS;
- return -ENOSYS;
-}
-
-#else /* !_WIN32 */
-
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/select.h>
-#include <sys/types.h>
-
-/* Private copy of ../libcutils/socket_local.h prevent library loops */
-#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
-#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
-/* End of ../libcutils/socket_local.h */
-
-#define LISTEN_BACKLOG 4
-
-/* Documented in header file. */
-LIBLOG_WEAK int socket_make_sockaddr_un(const char *name, int namespaceId,
- struct sockaddr_un *p_addr,
- socklen_t *alen)
-{
- memset (p_addr, 0, sizeof (*p_addr));
- size_t namelen;
-
- switch (namespaceId) {
- case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
-#if defined(__linux__)
- namelen = strlen(name);
-
- /* Test with length +1 for the *initial* '\0'. */
- if ((namelen + 1) > sizeof(p_addr->sun_path)) {
- goto error;
- }
-
- /*
- * Note: The path in this case is *not* supposed to be
- * '\0'-terminated. ("man 7 unix" for the gory details.)
- */
-
- p_addr->sun_path[0] = 0;
- memcpy(p_addr->sun_path + 1, name, namelen);
-#else
- /* this OS doesn't have the Linux abstract namespace */
-
- namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
- /* unix_path_max appears to be missing on linux */
- if (namelen > sizeof(*p_addr)
- - offsetof(struct sockaddr_un, sun_path) - 1) {
- goto error;
- }
-
- strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
- strcat(p_addr->sun_path, name);
-#endif
- break;
-
- case ANDROID_SOCKET_NAMESPACE_RESERVED:
- namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
- /* unix_path_max appears to be missing on linux */
- if (namelen > sizeof(*p_addr)
- - offsetof(struct sockaddr_un, sun_path) - 1) {
- goto error;
- }
-
- strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
- strcat(p_addr->sun_path, name);
- break;
-
- case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
- namelen = strlen(name);
- /* unix_path_max appears to be missing on linux */
- if (namelen > sizeof(*p_addr)
- - offsetof(struct sockaddr_un, sun_path) - 1) {
- goto error;
- }
-
- strcpy(p_addr->sun_path, name);
- break;
-
- default:
- /* invalid namespace id */
- return -1;
- }
-
- p_addr->sun_family = AF_LOCAL;
- *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
- return 0;
-error:
- return -1;
-}
-
-/**
- * connect to peer named "name" on fd
- * returns same fd or -1 on error.
- * fd is not closed on error. that's your job.
- *
- * Used by AndroidSocketImpl
- */
-LIBLOG_WEAK int socket_local_client_connect(int fd, const char *name,
- int namespaceId, int type __unused)
-{
- struct sockaddr_un addr;
- socklen_t alen;
- int err;
-
- err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
-
- if (err < 0) {
- goto error;
- }
-
- if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
- goto error;
- }
-
- return fd;
-
-error:
- return -1;
-}
-
-/**
- * connect to peer named "name"
- * returns fd or -1 on error
- */
-LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
-{
- int s;
-
- s = socket(AF_LOCAL, type, 0);
- if(s < 0) return -1;
-
- if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
- close(s);
- return -1;
- }
-
- return s;
-}
-
-#endif /* !_WIN32 */
-/* End of ../libcutils/socket_local_client.c */
-
-#define logger_for_each(logger, logger_list) \
- for (logger = node_to_item((logger_list)->node.next, struct logger, node); \
- logger != node_to_item(&(logger_list)->node, struct logger, node); \
- logger = node_to_item((logger)->node.next, struct logger, node))
-
-/* In the future, we would like to make this list extensible */
-static const char *LOG_NAME[LOG_ID_MAX] = {
- [LOG_ID_MAIN] = "main",
- [LOG_ID_RADIO] = "radio",
- [LOG_ID_EVENTS] = "events",
- [LOG_ID_SYSTEM] = "system",
- [LOG_ID_CRASH] = "crash",
- [LOG_ID_SECURITY] = "security",
- [LOG_ID_KERNEL] = "kernel",
-};
-
-LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
-{
- if (log_id >= LOG_ID_MAX) {
- log_id = LOG_ID_MAIN;
- }
- return LOG_NAME[log_id];
-}
-
-LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char *logName)
-{
- const char *b;
- int ret;
-
- if (!logName) {
- return -1; /* NB: log_id_t is unsigned */
- }
- b = strrchr(logName, '/');
- if (!b) {
- b = logName;
- } else {
- ++b;
- }
-
- for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
- const char *l = LOG_NAME[ret];
- if (l && !strcmp(b, l)) {
- return ret;
- }
- }
- return -1; /* should never happen */
-}
-
-struct logger_list {
- struct listnode node;
- int mode;
- unsigned int tail;
- log_time start;
- pid_t pid;
- int sock;
-};
-
-struct logger {
- struct listnode node;
- struct logger_list *top;
- log_id_t id;
-};
-
-/* android_logger_alloc unimplemented, no use case */
-/* android_logger_free not exported */
-static void android_logger_free(struct logger *logger)
-{
- if (!logger) {
- return;
- }
-
- list_remove(&logger->node);
-
- free(logger);
-}
-
-/* android_logger_alloc unimplemented, no use case */
-
-/* method for getting the associated sublog id */
-LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger *logger)
-{
- return logger->id;
-}
-
-/* worker for sending the command to the logger */
-static ssize_t send_log_msg(struct logger *logger,
- const char *msg, char *buf, size_t buf_size)
-{
- ssize_t ret;
- size_t len;
- char *cp;
- int errno_save = 0;
- int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (sock < 0) {
- return sock;
- }
-
- if (msg) {
- snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1);
- }
-
- len = strlen(buf) + 1;
- ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
- if (ret <= 0) {
- goto done;
- }
-
- len = buf_size;
- cp = buf;
- while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
- struct pollfd p;
-
- if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
- break;
- }
-
- len -= ret;
- cp += ret;
-
- memset(&p, 0, sizeof(p));
- p.fd = sock;
- p.events = POLLIN;
-
- /* Give other side 20ms to refill pipe */
- ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
-
- if (ret <= 0) {
- break;
- }
-
- if (!(p.revents & POLLIN)) {
- ret = 0;
- break;
- }
- }
-
- if (ret >= 0) {
- ret += buf_size - len;
- }
-
-done:
- if ((ret == -1) && errno) {
- errno_save = errno;
- }
- close(sock);
- if (errno_save) {
- errno = errno_save;
- }
- return ret;
-}
-
-static int check_log_success(char *buf, ssize_t ret)
-{
- if (ret < 0) {
- return ret;
- }
-
- if (strncmp(buf, "success", 7)) {
- errno = EINVAL;
- return -1;
- }
-
- return 0;
-}
-
-/* Determine the credentials of the caller */
-static bool uid_has_log_permission(uid_t uid)
-{
- return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
-}
-
-static uid_t get_best_effective_uid()
-{
- uid_t euid;
- uid_t uid;
- gid_t gid;
- ssize_t i;
- static uid_t last_uid = (uid_t) -1;
-
- if (last_uid != (uid_t) -1) {
- return last_uid;
- }
- uid = getuid();
- if (uid_has_log_permission(uid)) {
- return last_uid = uid;
- }
- euid = geteuid();
- if (uid_has_log_permission(euid)) {
- return last_uid = euid;
- }
- gid = getgid();
- if (uid_has_log_permission(gid)) {
- return last_uid = gid;
- }
- gid = getegid();
- if (uid_has_log_permission(gid)) {
- return last_uid = gid;
- }
- i = getgroups((size_t) 0, NULL);
- if (i > 0) {
- gid_t list[i];
-
- getgroups(i, list);
- while (--i >= 0) {
- if (uid_has_log_permission(list[i])) {
- return last_uid = list[i];
- }
- }
- }
- return last_uid = uid;
-}
-
-LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger)
-{
- char buf[512];
-
- if (logger->top->mode & ANDROID_LOG_PSTORE) {
- if (uid_has_log_permission(get_best_effective_uid())) {
- return unlink("/sys/fs/pstore/pmsg-ramoops-0");
- }
- errno = EPERM;
- return -1;
- }
- return check_log_success(buf,
- send_log_msg(logger, "clear %d", buf, sizeof(buf)));
-}
-
-/* returns the total size of the log's ring buffer */
-LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger)
-{
- char buf[512];
-
- ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
- if (ret < 0) {
- return ret;
- }
-
- if ((buf[0] < '0') || ('9' < buf[0])) {
- return -1;
- }
-
- return atol(buf);
-}
-
-LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger,
- unsigned long size)
-{
- char buf[512];
-
- snprintf(buf, sizeof(buf), "setLogSize %d %lu",
- logger ? logger->id : (unsigned) -1, size);
-
- return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
-}
-
-/*
- * returns the readable size of the log's ring buffer (that is, amount of the
- * log consumed)
- */
-LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size(
- struct logger *logger)
-{
- char buf[512];
-
- ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
- if (ret < 0) {
- return ret;
- }
-
- if ((buf[0] < '0') || ('9' < buf[0])) {
- return -1;
- }
-
- return atol(buf);
-}
-
-/*
- * returns the logger version
- */
-LIBLOG_ABI_PUBLIC int android_logger_get_log_version(
- struct logger *logger __unused)
-{
- return 4;
-}
-
-/*
- * returns statistics
- */
-LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics(
- struct logger_list *logger_list,
- char *buf, size_t len)
-{
- struct logger *logger;
- char *cp = buf;
- size_t remaining = len;
- size_t n;
-
- n = snprintf(cp, remaining, "getStatistics");
- n = min(n, remaining);
- remaining -= n;
- cp += n;
-
- logger_for_each(logger, logger_list) {
- n = snprintf(cp, remaining, " %d", logger->id);
- n = min(n, remaining);
- remaining -= n;
- cp += n;
- }
-
- if (logger_list->pid) {
- snprintf(cp, remaining, " pid=%u", logger_list->pid);
- }
-
- return send_log_msg(NULL, NULL, buf, len);
-}
-
-LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list(
- struct logger_list *logger_list __unused,
- char *buf, size_t len)
-{
- return send_log_msg(NULL, "getPruneList", buf, len);
-}
-
-LIBLOG_ABI_PUBLIC int android_logger_set_prune_list(
- struct logger_list *logger_list __unused,
- char *buf, size_t len)
-{
- const char cmd[] = "setPruneList ";
- const size_t cmdlen = sizeof(cmd) - 1;
-
- if (strlen(buf) > (len - cmdlen)) {
- return -ENOMEM; /* KISS */
- }
- memmove(buf + cmdlen, buf, len - cmdlen);
- buf[len - 1] = '\0';
- memcpy(buf, cmd, cmdlen);
-
- return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
-}
-
-LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
- int mode,
- unsigned int tail,
- pid_t pid)
-{
- struct logger_list *logger_list;
-
- logger_list = calloc(1, sizeof(*logger_list));
- if (!logger_list) {
- return NULL;
- }
-
- list_init(&logger_list->node);
- logger_list->mode = mode;
- logger_list->start.tv_sec = 0;
- logger_list->start.tv_nsec = 0;
- logger_list->tail = tail;
- logger_list->pid = pid;
- logger_list->sock = -1;
-
- return logger_list;
-}
-
-LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time(
- int mode,
- log_time start,
- pid_t pid)
-{
- struct logger_list *logger_list;
-
- logger_list = calloc(1, sizeof(*logger_list));
- if (!logger_list) {
- return NULL;
- }
-
- list_init(&logger_list->node);
- logger_list->mode = mode;
- logger_list->start = start;
- logger_list->tail = 0;
- logger_list->pid = pid;
- logger_list->sock = -1;
-
- return logger_list;
-}
-
-/* android_logger_list_register unimplemented, no use case */
-/* android_logger_list_unregister unimplemented, no use case */
-
-/* Open the named log and add it to the logger list */
-LIBLOG_ABI_PUBLIC struct logger *android_logger_open(
- struct logger_list *logger_list,
- log_id_t id)
-{
- struct logger *logger;
-
- if (!logger_list || (id >= LOG_ID_MAX)) {
- goto err;
- }
-
- logger_for_each(logger, logger_list) {
- if (logger->id == id) {
- goto ok;
- }
- }
-
- logger = calloc(1, sizeof(*logger));
- if (!logger) {
- goto err;
- }
-
- logger->id = id;
- list_add_tail(&logger_list->node, &logger->node);
- logger->top = logger_list;
- goto ok;
-
-err:
- logger = NULL;
-ok:
- return logger;
-}
-
-/* Open the single named log and make it part of a new logger list */
-LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open(
- log_id_t id,
- int mode,
- unsigned int tail,
- pid_t pid)
-{
- struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid);
- if (!logger_list) {
- return NULL;
- }
-
- if (!android_logger_open(logger_list, id)) {
- android_logger_list_free(logger_list);
- return NULL;
- }
-
- return logger_list;
-}
-
-static int android_logger_list_read_pstore(struct logger_list *logger_list,
- struct log_msg *log_msg)
-{
- ssize_t ret;
- off_t current, next;
- uid_t uid;
- struct logger *logger;
- struct __attribute__((__packed__)) {
- android_pmsg_log_header_t p;
- android_log_header_t l;
- } buf;
- static uint8_t preread_count;
- bool is_system;
-
- memset(log_msg, 0, sizeof(*log_msg));
-
- if (logger_list->sock < 0) {
- int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
-
- if (fd < 0) {
- return -errno;
- }
- logger_list->sock = fd;
- preread_count = 0;
- }
-
- while(1) {
- if (preread_count < sizeof(buf)) {
- ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
- &buf.p.magic + preread_count,
- sizeof(buf) - preread_count));
- if (ret < 0) {
- return -errno;
- }
- preread_count += ret;
- }
- if (preread_count != sizeof(buf)) {
- return preread_count ? -EIO : -EAGAIN;
- }
- if ((buf.p.magic != LOGGER_MAGIC)
- || (buf.p.len <= sizeof(buf))
- || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD))
- || (buf.l.id >= LOG_ID_MAX)
- || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) {
- do {
- memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
- } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
- continue;
- }
- preread_count = 0;
-
- logger_for_each(logger, logger_list) {
- if (buf.l.id != logger->id) {
- continue;
- }
-
- if ((logger_list->start.tv_sec || logger_list->start.tv_nsec)
- && ((logger_list->start.tv_sec > buf.l.realtime.tv_sec)
- || ((logger_list->start.tv_sec == buf.l.realtime.tv_sec)
- && (logger_list->start.tv_nsec > buf.l.realtime.tv_nsec)))) {
- break;
- }
-
- if (logger_list->pid && (logger_list->pid != buf.p.pid)) {
- break;
- }
-
- uid = get_best_effective_uid();
- is_system = uid_has_log_permission(uid);
- if (!is_system && (uid != buf.p.uid)) {
- break;
- }
-
- ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
- is_system ?
- log_msg->entry_v4.msg :
- log_msg->entry_v3.msg,
- buf.p.len - sizeof(buf)));
- if (ret < 0) {
- return -errno;
- }
- if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
- return -EIO;
- }
-
- log_msg->entry_v4.len = buf.p.len - sizeof(buf);
- log_msg->entry_v4.hdr_size = is_system ?
- sizeof(log_msg->entry_v4) :
- sizeof(log_msg->entry_v3);
- log_msg->entry_v4.pid = buf.p.pid;
- log_msg->entry_v4.tid = buf.l.tid;
- log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
- log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
- log_msg->entry_v4.lid = buf.l.id;
- if (is_system) {
- log_msg->entry_v4.uid = buf.p.uid;
- }
-
- return ret;
- }
-
- current = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
- (off_t)0, SEEK_CUR));
- if (current < 0) {
- return -errno;
- }
- next = TEMP_FAILURE_RETRY(lseek(logger_list->sock,
- (off_t)(buf.p.len - sizeof(buf)),
- SEEK_CUR));
- if (next < 0) {
- return -errno;
- }
- if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
- return -EIO;
- }
- }
-}
-
-static void caught_signal(int signum __unused)
-{
-}
-
-/* Read from the selected logs */
-LIBLOG_ABI_PUBLIC int android_logger_list_read(
- struct logger_list *logger_list,
- struct log_msg *log_msg)
-{
- int ret, e;
- struct logger *logger;
- struct sigaction ignore;
- struct sigaction old_sigaction;
- unsigned int old_alarm = 0;
-
- if (!logger_list) {
- return -EINVAL;
- }
-
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- return android_logger_list_read_pstore(logger_list, log_msg);
- }
-
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- }
-
- if (logger_list->sock < 0) {
- char buffer[256], *cp, c;
-
- int sock = socket_local_client("logdr",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET);
- if (sock < 0) {
- if ((sock == -1) && errno) {
- return -errno;
- }
- return sock;
- }
-
- strcpy(buffer,
- (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream");
- cp = buffer + strlen(buffer);
-
- strcpy(cp, " lids");
- cp += 5;
- c = '=';
- int remaining = sizeof(buffer) - (cp - buffer);
- logger_for_each(logger, logger_list) {
- ret = snprintf(cp, remaining, "%c%u", c, logger->id);
- ret = min(ret, remaining);
- remaining -= ret;
- cp += ret;
- c = ',';
- }
-
- if (logger_list->tail) {
- ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
- ret = min(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
-
- if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
- if (logger_list->mode & ANDROID_LOG_WRAP) {
- // ToDo: alternate API to allow timeout to be adjusted.
- ret = snprintf(cp, remaining, " timeout=%u",
- ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
- ret = min(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
- ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
- logger_list->start.tv_sec,
- logger_list->start.tv_nsec);
- ret = min(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
-
- if (logger_list->pid) {
- ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
- ret = min(ret, remaining);
- cp += ret;
- }
-
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- /* Deal with an unresponsive logd */
- sigaction(SIGALRM, &ignore, &old_sigaction);
- old_alarm = alarm(30);
- }
- ret = write(sock, buffer, cp - buffer);
- e = errno;
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- if (e == EINTR) {
- e = ETIMEDOUT;
- }
- alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, NULL);
- }
-
- if (ret <= 0) {
- close(sock);
- if ((ret == -1) && e) {
- return -e;
- }
- if (ret == 0) {
- return -EIO;
- }
- return ret;
- }
-
- logger_list->sock = sock;
- }
-
- while(1) {
- memset(log_msg, 0, sizeof(*log_msg));
-
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- /* particularily useful if tombstone is reporting for logd */
- sigaction(SIGALRM, &ignore, &old_sigaction);
- old_alarm = alarm(30);
- }
- /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
- ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
- e = errno;
- if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
- if ((ret == 0) || (e == EINTR)) {
- e = EAGAIN;
- ret = -1;
- }
- alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, NULL);
- }
-
- if ((ret == -1) && e) {
- return -e;
- }
- return ret;
- }
- /* NOTREACH */
- return ret;
-}
-
-/* Close all the logs */
-LIBLOG_ABI_PUBLIC void android_logger_list_free(
- struct logger_list *logger_list)
-{
- if (logger_list == NULL) {
- return;
- }
-
- while (!list_empty(&logger_list->node)) {
- struct listnode *node = list_head(&logger_list->node);
- struct logger *logger = node_to_item(node, struct logger, node);
- android_logger_free(logger);
- }
-
- if (logger_list->sock >= 0) {
- close (logger_list->sock);
- }
-
- free(logger_list);
-}
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index b6af222..d2bf181 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -21,7 +21,7 @@
#include <log/log_read.h>
-#include "log_cdefs.h"
+#include "log_portability.h"
LIBLOG_ABI_PRIVATE const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
LIBLOG_ABI_PRIVATE const timespec log_time::EPOCH = { 0, 0 };
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
new file mode 100644
index 0000000..d844104
--- /dev/null
+++ b/liblog/logd_reader.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 2007-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 <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdatomic.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+#include <log/logd.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_read.h"
+#include "log_portability.h"
+#include "logger.h"
+
+/* branchless on many architectures. */
+#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
+
+static int logdAvailable(log_id_t LogId);
+static int logdVersion(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+static int logdRead(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ struct log_msg *log_msg);
+static int logdPoll(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp);
+static void logdClose(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp);
+static int logdClear(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+static ssize_t logdSetSize(struct android_log_logger *logger,
+ struct android_log_transport_context *transp,
+ size_t size);
+static ssize_t logdGetSize(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+static ssize_t logdGetReadableSize(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+static ssize_t logdGetPrune(struct android_log_logger_list *logger,
+ struct android_log_transport_context *transp,
+ char *buf, size_t len);
+static ssize_t logdSetPrune(struct android_log_logger_list *logger,
+ struct android_log_transport_context *transp,
+ char *buf, size_t len);
+static ssize_t logdGetStats(struct android_log_logger_list *logger,
+ struct android_log_transport_context *transp,
+ char *buf, size_t len);
+
+LIBLOG_HIDDEN struct android_log_transport_read logdLoggerRead = {
+ .node = { &logdLoggerRead.node, &logdLoggerRead.node },
+ .name = "logd",
+ .available = logdAvailable,
+ .version = logdVersion,
+ .read = logdRead,
+ .poll = logdPoll,
+ .close = logdClose,
+ .clear = logdClear,
+ .getSize = logdGetSize,
+ .setSize = logdSetSize,
+ .getReadableSize = logdGetSize,
+ .getPrune = logdGetPrune,
+ .setPrune = logdSetPrune,
+ .getStats = logdGetStats,
+};
+
+static int logdAvailable(log_id_t logId)
+{
+ if (logId > LOG_ID_KERNEL) {
+ return -EINVAL;
+ }
+ if (logId == LOG_ID_SECURITY) {
+ uid_t uid = __android_log_uid();
+ if (uid != AID_SYSTEM) {
+ return -EPERM;
+ }
+ }
+ if (access("/dev/socket/logdw", W_OK) == 0) {
+ return 0;
+ }
+ return -EBADF;
+}
+
+/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
+
+#if defined(_WIN32)
+
+LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
+{
+ errno = ENOSYS;
+ return -ENOSYS;
+}
+
+#else /* !_WIN32 */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+
+/* Private copy of ../libcutils/socket_local.h prevent library loops */
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+/* End of ../libcutils/socket_local.h */
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+LIBLOG_WEAK int socket_make_sockaddr_un(const char *name, int namespaceId,
+ struct sockaddr_un *p_addr,
+ socklen_t *alen)
+{
+ memset (p_addr, 0, sizeof (*p_addr));
+ size_t namelen;
+
+ switch (namespaceId) {
+ case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#if defined(__linux__)
+ namelen = strlen(name);
+
+ /* Test with length +1 for the *initial* '\0'. */
+ if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+ goto error;
+ }
+
+ /*
+ * Note: The path in this case is *not* supposed to be
+ * '\0'-terminated. ("man 7 unix" for the gory details.)
+ */
+
+ p_addr->sun_path[0] = 0;
+ memcpy(p_addr->sun_path + 1, name, namelen);
+#else
+ /* this OS doesn't have the Linux abstract namespace */
+
+ namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen > sizeof(*p_addr)
+ - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+#endif
+ break;
+
+ case ANDROID_SOCKET_NAMESPACE_RESERVED:
+ namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen > sizeof(*p_addr)
+ - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+ break;
+
+ case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+ namelen = strlen(name);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen > sizeof(*p_addr)
+ - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, name);
+ break;
+
+ default:
+ /* invalid namespace id */
+ return -1;
+ }
+
+ p_addr->sun_family = AF_LOCAL;
+ *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+ return 0;
+error:
+ return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ *
+ * Used by AndroidSocketImpl
+ */
+LIBLOG_WEAK int socket_local_client_connect(int fd, const char *name,
+ int namespaceId, int type __unused)
+{
+ struct sockaddr_un addr;
+ socklen_t alen;
+ int err;
+
+ err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+ if (err < 0) {
+ goto error;
+ }
+
+ if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
+ goto error;
+ }
+
+ return fd;
+
+error:
+ return -1;
+}
+
+/**
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+LIBLOG_WEAK int socket_local_client(const char *name, int namespaceId, int type)
+{
+ int s;
+
+ s = socket(AF_LOCAL, type, 0);
+ if(s < 0) return -1;
+
+ if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+#endif /* !_WIN32 */
+/* End of ../libcutils/socket_local_client.c */
+
+/* worker for sending the command to the logger */
+static ssize_t send_log_msg(struct android_log_logger *logger,
+ const char *msg, char *buf, size_t buf_size)
+{
+ ssize_t ret;
+ size_t len;
+ char *cp;
+ int errno_save = 0;
+ int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (sock < 0) {
+ return sock;
+ }
+
+ if (msg) {
+ snprintf(buf, buf_size, msg, logger ? logger->logId : (unsigned) -1);
+ }
+
+ len = strlen(buf) + 1;
+ ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
+ if (ret <= 0) {
+ goto done;
+ }
+
+ len = buf_size;
+ cp = buf;
+ while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
+ struct pollfd p;
+
+ if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
+ break;
+ }
+
+ len -= ret;
+ cp += ret;
+
+ memset(&p, 0, sizeof(p));
+ p.fd = sock;
+ p.events = POLLIN;
+
+ /* Give other side 20ms to refill pipe */
+ ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
+
+ if (ret <= 0) {
+ break;
+ }
+
+ if (!(p.revents & POLLIN)) {
+ ret = 0;
+ break;
+ }
+ }
+
+ if (ret >= 0) {
+ ret += buf_size - len;
+ }
+
+done:
+ if ((ret == -1) && errno) {
+ errno_save = errno;
+ }
+ close(sock);
+ if (errno_save) {
+ errno = errno_save;
+ }
+ return ret;
+}
+
+static int check_log_success(char *buf, ssize_t ret)
+{
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (strncmp(buf, "success", 7)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int logdClear(struct android_log_logger *logger,
+ struct android_log_transport_context *transp __unused)
+{
+ char buf[512];
+
+ return check_log_success(buf,
+ send_log_msg(logger, "clear %d", buf, sizeof(buf)));
+}
+
+/* returns the total size of the log's ring buffer */
+static ssize_t logdGetSize(struct android_log_logger *logger,
+ struct android_log_transport_context *transp __unused)
+{
+ char buf[512];
+
+ ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if ((buf[0] < '0') || ('9' < buf[0])) {
+ return -1;
+ }
+
+ return atol(buf);
+}
+
+static ssize_t logdSetSize(
+ struct android_log_logger *logger,
+ struct android_log_transport_context *transp __unused,
+ size_t size)
+{
+ char buf[512];
+
+ snprintf(buf, sizeof(buf), "setLogSize %d %zu", logger->logId, size);
+
+ return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
+}
+
+/*
+ * returns the readable size of the log's ring buffer (that is, amount of the
+ * log consumed)
+ */
+static ssize_t logdGetReadableSize(
+ struct android_log_logger *logger,
+ struct android_log_transport_context *transp __unused)
+{
+ char buf[512];
+
+ ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if ((buf[0] < '0') || ('9' < buf[0])) {
+ return -1;
+ }
+
+ return atol(buf);
+}
+
+/*
+ * returns the logger version
+ */
+static int logdVersion(
+ struct android_log_logger *logger __unused,
+ struct android_log_transport_context *transp __unused)
+{
+ uid_t uid = __android_log_uid();
+ return ((uid != AID_ROOT) && (uid != AID_LOG) && (uid != AID_SYSTEM)) ? 3 : 4;
+}
+
+/*
+ * returns statistics
+ */
+static ssize_t logdGetStats(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp __unused,
+ char *buf, size_t len)
+{
+ struct android_log_logger *logger;
+ char *cp = buf;
+ size_t remaining = len;
+ size_t n;
+
+ n = snprintf(cp, remaining, "getStatistics");
+ n = min(n, remaining);
+ remaining -= n;
+ cp += n;
+
+ logger_for_each(logger, logger_list) {
+ n = snprintf(cp, remaining, " %d", logger->logId);
+ n = min(n, remaining);
+ remaining -= n;
+ cp += n;
+ }
+
+ if (logger_list->pid) {
+ snprintf(cp, remaining, " pid=%u", logger_list->pid);
+ }
+
+ return send_log_msg(NULL, NULL, buf, len);
+}
+
+static ssize_t logdGetPrune(
+ struct android_log_logger_list *logger_list __unused,
+ struct android_log_transport_context *transp __unused,
+ char *buf, size_t len)
+{
+ return send_log_msg(NULL, "getPruneList", buf, len);
+}
+
+static ssize_t logdSetPrune(
+ struct android_log_logger_list *logger_list __unused,
+ struct android_log_transport_context *transp __unused,
+ char *buf, size_t len)
+{
+ const char cmd[] = "setPruneList ";
+ const size_t cmdlen = sizeof(cmd) - 1;
+
+ if (strlen(buf) > (len - cmdlen)) {
+ return -ENOMEM; /* KISS */
+ }
+ memmove(buf + cmdlen, buf, len - cmdlen);
+ buf[len - 1] = '\0';
+ memcpy(buf, cmd, cmdlen);
+
+ return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
+}
+
+
+static void caught_signal(int signum __unused)
+{
+}
+
+static int logdOpen(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp)
+{
+ struct android_log_logger *logger;
+ struct sigaction ignore;
+ struct sigaction old_sigaction;
+ unsigned int old_alarm = 0;
+ char buffer[256], *cp, c;
+ int e, ret, remaining;
+
+ int sock = transp->context.sock;
+ if (sock > 0) {
+ return sock;
+ }
+
+ if (!logger_list) {
+ return -EINVAL;
+ }
+
+ sock = socket_local_client("logdr",
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_SEQPACKET);
+ if (sock == 0) {
+ /* Guarantee not file descriptor zero */
+ int newsock = socket_local_client("logdr",
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_SEQPACKET);
+ close(sock);
+ sock = newsock;
+ }
+ if (sock <= 0) {
+ if ((sock == -1) && errno) {
+ return -errno;
+ }
+ return sock;
+ }
+
+ strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ?
+ "dumpAndClose" : "stream");
+ cp = buffer + strlen(buffer);
+
+ strcpy(cp, " lids");
+ cp += 5;
+ c = '=';
+ remaining = sizeof(buffer) - (cp - buffer);
+ logger_for_each(logger, logger_list) {
+ ret = snprintf(cp, remaining, "%c%u", c, logger->logId);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ c = ',';
+ }
+
+ if (logger_list->tail) {
+ ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
+
+ if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
+ if (logger_list->mode & ANDROID_LOG_WRAP) {
+ // ToDo: alternate API to allow timeout to be adjusted.
+ ret = snprintf(cp, remaining, " timeout=%u",
+ ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
+ ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
+ logger_list->start.tv_sec,
+ logger_list->start.tv_nsec);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
+
+ if (logger_list->pid) {
+ ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
+ ret = min(ret, remaining);
+ cp += ret;
+ }
+
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+ /* Deal with an unresponsive logd */
+ memset(&ignore, 0, sizeof(ignore));
+ ignore.sa_handler = caught_signal;
+ sigemptyset(&ignore.sa_mask);
+ /* particularily useful if tombstone is reporting for logd */
+ sigaction(SIGALRM, &ignore, &old_sigaction);
+ old_alarm = alarm(30);
+ }
+ ret = write(sock, buffer, cp - buffer);
+ e = errno;
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+ if (e == EINTR) {
+ e = ETIMEDOUT;
+ }
+ alarm(old_alarm);
+ sigaction(SIGALRM, &old_sigaction, NULL);
+ }
+
+ if (ret <= 0) {
+ close(sock);
+ if ((ret == -1) && e) {
+ return -e;
+ }
+ if (ret == 0) {
+ return -EIO;
+ }
+ return ret;
+ }
+
+ return transp->context.sock = sock;
+}
+
+/* Read from the selected logs */
+static int logdRead(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ struct log_msg *log_msg)
+{
+ int ret, e;
+ struct sigaction ignore;
+ struct sigaction old_sigaction;
+ unsigned int old_alarm = 0;
+
+ ret = logdOpen(logger_list, transp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ memset(log_msg, 0, sizeof(*log_msg));
+
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+ memset(&ignore, 0, sizeof(ignore));
+ ignore.sa_handler = caught_signal;
+ sigemptyset(&ignore.sa_mask);
+ /* particularily useful if tombstone is reporting for logd */
+ sigaction(SIGALRM, &ignore, &old_sigaction);
+ old_alarm = alarm(30);
+ }
+
+ /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
+ ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
+ e = errno;
+
+ if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
+ if ((ret == 0) || (e == EINTR)) {
+ e = EAGAIN;
+ ret = -1;
+ }
+ alarm(old_alarm);
+ sigaction(SIGALRM, &old_sigaction, NULL);
+ }
+
+ if ((ret == -1) && e) {
+ return -e;
+ }
+ return ret;
+}
+
+static int logdPoll(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp)
+{
+ struct pollfd p;
+
+ int ret = logdOpen(logger_list, transp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ memset(&p, 0, sizeof(p));
+ p.fd = ret;
+ p.events = POLLIN;
+ ret = poll(&p, 1, 20);
+ if ((ret > 0) && !(p.revents & POLLIN)) {
+ ret = 0;
+ }
+ if ((ret == -1) && errno) {
+ return -errno;
+ }
+ return ret;
+}
+
+/* Close all the logs */
+static void logdClose(struct android_log_logger_list *logger_list __unused,
+ struct android_log_transport_context *transp)
+{
+ if (transp->context.sock > 0) {
+ close (transp->context.sock);
+ transp->context.sock = -1;
+ }
+}
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
deleted file mode 100644
index 85a4aab..0000000
--- a/liblog/logd_write.c
+++ /dev/null
@@ -1,724 +0,0 @@
-/*
- * Copyright (C) 2007-2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#if (FAKE_LOG_DEVICE == 0)
-#include <endian.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#if !defined(_WIN32)
-#include <pthread.h>
-#endif
-#include <stdarg.h>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#if (FAKE_LOG_DEVICE == 0)
-#include <sys/socket.h>
-#include <sys/un.h>
-#endif
-#include <time.h>
-#include <unistd.h>
-
-#ifdef __BIONIC__
-#include <android/set_abort_message.h>
-#endif
-
-#include <log/event_tag_map.h>
-#include <log/logd.h>
-#include <log/logger.h>
-#include <log/log_read.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "log_cdefs.h"
-
-#define LOG_BUF_SIZE 1024
-
-#if FAKE_LOG_DEVICE
-/* This will be defined when building for the host. */
-#include "fake_log_device.h"
-#endif
-
-static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
-static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
-
-#if !defined(_WIN32)
-static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-
-static void lock()
-{
- /*
- * If we trigger a signal handler in the middle of locked activity and the
- * signal handler logs a message, we could get into a deadlock state.
- */
- pthread_mutex_lock(&log_init_lock);
-}
-
-static int trylock()
-{
- return pthread_mutex_trylock(&log_init_lock);
-}
-
-static void unlock()
-{
- pthread_mutex_unlock(&log_init_lock);
-}
-
-#else /* !defined(_WIN32) */
-
-#define lock() ((void)0)
-#define trylock() (0) /* success */
-#define unlock() ((void)0)
-
-#endif /* !defined(_WIN32) */
-
-#if FAKE_LOG_DEVICE
-static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 };
-#else
-static int logd_fd = -1;
-static int pstore_fd = -1;
-#endif
-
-/*
- * This is used by the C++ code to decide if it should write logs through
- * the C code. Basically, if /dev/socket/logd is available, we're running in
- * the simulator rather than a desktop tool and want to use the device.
- */
-static enum {
- kLogUninitialized, kLogNotAvailable, kLogAvailable
-} g_log_status = kLogUninitialized;
-
-LIBLOG_ABI_PUBLIC int __android_log_dev_available()
-{
- if (g_log_status == kLogUninitialized) {
- if (access("/dev/socket/logdw", W_OK) == 0)
- g_log_status = kLogAvailable;
- else
- g_log_status = kLogNotAvailable;
- }
-
- return (g_log_status == kLogAvailable);
-}
-
-/* log_init_lock assumed */
-static int __write_to_log_initialize()
-{
- int i, ret = 0;
-
-#if FAKE_LOG_DEVICE
- for (i = 0; i < LOG_ID_MAX; i++) {
- char buf[sizeof("/dev/log_security")];
- snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
- log_fds[i] = fakeLogOpen(buf, O_WRONLY);
- }
-#else
- if (pstore_fd < 0) {
- pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
- }
-
- if (logd_fd < 0) {
- i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
- if (i < 0) {
- ret = -errno;
- } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
- ret = -errno;
- close(i);
- } else {
- struct sockaddr_un un;
- memset(&un, 0, sizeof(struct sockaddr_un));
- un.sun_family = AF_UNIX;
- strcpy(un.sun_path, "/dev/socket/logdw");
-
- if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
- sizeof(struct sockaddr_un))) < 0) {
- ret = -errno;
- close(i);
- } else {
- logd_fd = i;
- }
- }
- }
-#endif
-
- return ret;
-}
-
-static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
-{
- ssize_t ret;
-#if FAKE_LOG_DEVICE
- int log_fd;
-
- if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
- log_fd = log_fds[(int)log_id];
- } else {
- return -EBADF;
- }
- do {
- ret = fakeLogWritev(log_fd, vec, nr);
- if (ret < 0) {
- ret = -errno;
- }
- } while (ret == -EINTR);
-#else
- static const unsigned header_length = 2;
- struct iovec newVec[nr + header_length];
- android_log_header_t header;
- android_pmsg_log_header_t pmsg_header;
- struct timespec ts;
- size_t i, payload_size;
- static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
- static pid_t last_pid = (pid_t) -1;
- static atomic_int_fast32_t dropped;
- static atomic_int_fast32_t dropped_security;
-
- if (!nr) {
- return -EINVAL;
- }
-
- if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
- last_uid = getuid();
- }
- if (last_pid == (pid_t) -1) {
- last_pid = getpid();
- }
- if (log_id == LOG_ID_SECURITY) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
- /* Matches clientHasLogCredentials() in logd */
- if ((last_uid != AID_SYSTEM) && (last_uid != AID_ROOT) && (last_uid != AID_LOG)) {
- uid_t uid = geteuid();
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
- gid_t gid = getgid();
- if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
- gid = getegid();
- if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
- int num_groups;
- gid_t *groups;
-
- num_groups = getgroups(0, NULL);
- if (num_groups <= 0) {
- return -EPERM;
- }
- groups = calloc(num_groups, sizeof(gid_t));
- if (!groups) {
- return -ENOMEM;
- }
- num_groups = getgroups(num_groups, groups);
- while (num_groups > 0) {
- if (groups[num_groups - 1] == AID_LOG) {
- break;
- }
- --num_groups;
- }
- free(groups);
- if (num_groups <= 0) {
- return -EPERM;
- }
- }
- }
- }
- }
- if (!__android_log_security()) {
- atomic_store(&dropped_security, 0);
- return -EPERM;
- }
- } else if (log_id == LOG_ID_EVENTS) {
- static atomic_uintptr_t map;
- int ret;
- const char *tag;
- EventTagMap *m, *f;
-
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
-
- tag = NULL;
- f = NULL;
- m = (EventTagMap *)atomic_load(&map);
-
- if (!m) {
- ret = trylock();
- m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */
- if (!m) {
- m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
- if (ret) { /* trylock failed, use local copy, mark for close */
- f = m;
- } else {
- if (!m) { /* One chance to open map file */
- m = (EventTagMap *)(uintptr_t)-1LL;
- }
- atomic_store(&map, (uintptr_t)m);
- }
- }
- if (!ret) { /* trylock succeeded, unlock */
- unlock();
- }
- }
- if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
- tag = android_lookupEventTag(
- m,
- htole32(((uint32_t *)vec[0].iov_base)[0]));
- }
- ret = __android_log_is_loggable(ANDROID_LOG_INFO,
- tag,
- ANDROID_LOG_VERBOSE);
- if (f) { /* local copy marked for close */
- android_closeEventTagMap(f);
- }
- if (!ret) {
- return -EPERM;
- }
- } else {
- /* Validate the incoming tag, tag content can not split across iovec */
- char prio = ANDROID_LOG_VERBOSE;
- const char *tag = vec[0].iov_base;
- size_t len = vec[0].iov_len;
- if (!tag) {
- len = 0;
- }
- if (len > 0) {
- prio = *tag;
- if (len > 1) {
- --len;
- ++tag;
- } else {
- len = vec[1].iov_len;
- tag = ((const char *)vec[1].iov_base);
- if (!tag) {
- len = 0;
- }
- }
- }
- /* tag must be nul terminated */
- if (strnlen(tag, len) >= len) {
- tag = NULL;
- }
-
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- clock_gettime(android_log_clockid(), &ts);
-
- pmsg_header.magic = LOGGER_MAGIC;
- pmsg_header.len = sizeof(pmsg_header) + sizeof(header);
- pmsg_header.uid = last_uid;
- pmsg_header.pid = last_pid;
-
- header.tid = gettid();
- header.realtime.tv_sec = ts.tv_sec;
- header.realtime.tv_nsec = ts.tv_nsec;
-
- newVec[0].iov_base = (unsigned char *) &pmsg_header;
- newVec[0].iov_len = sizeof(pmsg_header);
- newVec[1].iov_base = (unsigned char *) &header;
- newVec[1].iov_len = sizeof(header);
-
- if (logd_fd > 0) {
- int32_t snapshot = atomic_exchange_explicit(&dropped_security, 0,
- memory_order_relaxed);
- if (snapshot) {
- android_log_event_int_t buffer;
-
- header.id = LOG_ID_SECURITY;
- buffer.header.tag = htole32(LIBLOG_LOG_TAG);
- buffer.payload.type = EVENT_TYPE_INT;
- buffer.payload.data = htole32(snapshot);
-
- newVec[2].iov_base = &buffer;
- newVec[2].iov_len = sizeof(buffer);
-
- ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
- if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
- atomic_fetch_add_explicit(&dropped_security, snapshot,
- memory_order_relaxed);
- }
- }
- snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
- if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO,
- "liblog",
- ANDROID_LOG_VERBOSE)) {
- android_log_event_int_t buffer;
-
- header.id = LOG_ID_EVENTS;
- buffer.header.tag = htole32(LIBLOG_LOG_TAG);
- buffer.payload.type = EVENT_TYPE_INT;
- buffer.payload.data = htole32(snapshot);
-
- newVec[2].iov_base = &buffer;
- newVec[2].iov_len = sizeof(buffer);
-
- ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
- if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
- atomic_fetch_add_explicit(&dropped, snapshot,
- memory_order_relaxed);
- }
- }
- }
-
- header.id = log_id;
-
- for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
- newVec[i].iov_base = vec[i - header_length].iov_base;
- payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
-
- if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) {
- newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD;
- if (newVec[i].iov_len) {
- ++i;
- }
- payload_size = LOGGER_ENTRY_MAX_PAYLOAD;
- break;
- }
- }
- pmsg_header.len += payload_size;
-
- if (pstore_fd >= 0) {
- TEMP_FAILURE_RETRY(writev(pstore_fd, newVec, i));
- }
-
- if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
- /*
- * ignore log messages we send to ourself (logd).
- * Such log messages are often generated by libraries we depend on
- * which use standard Android logging.
- */
- return 0;
- }
-
- if (logd_fd < 0) {
- return -EBADF;
- }
-
- /*
- * The write below could be lost, but will never block.
- *
- * To logd, we drop the pmsg_header
- *
- * ENOTCONN occurs if logd dies.
- * EAGAIN occurs if logd is overloaded.
- */
- ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
- if (ret < 0) {
- ret = -errno;
- if (ret == -ENOTCONN) {
- lock();
- close(logd_fd);
- logd_fd = -1;
- ret = __write_to_log_initialize();
- unlock();
-
- if (ret < 0) {
- return ret;
- }
-
- ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, i - 1));
- if (ret < 0) {
- ret = -errno;
- }
- }
- }
-
- if (ret > (ssize_t)sizeof(header)) {
- ret -= sizeof(header);
- } else if (ret == -EAGAIN) {
- atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
- if (log_id == LOG_ID_SECURITY) {
- atomic_fetch_add_explicit(&dropped_security, 1,
- memory_order_relaxed);
- }
- }
-#endif
-
- return ret;
-}
-
-#if FAKE_LOG_DEVICE
-static const char *LOG_NAME[LOG_ID_MAX] = {
- [LOG_ID_MAIN] = "main",
- [LOG_ID_RADIO] = "radio",
- [LOG_ID_EVENTS] = "events",
- [LOG_ID_SYSTEM] = "system",
- [LOG_ID_CRASH] = "crash",
- [LOG_ID_SECURITY] = "security",
- [LOG_ID_KERNEL] = "kernel",
-};
-
-LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
-{
- if (log_id >= LOG_ID_MAX) {
- log_id = LOG_ID_MAIN;
- }
- return LOG_NAME[log_id];
-}
-#endif
-
-static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
-{
- lock();
-
- if (write_to_log == __write_to_log_init) {
- int ret;
-
- ret = __write_to_log_initialize();
- if (ret < 0) {
- unlock();
-#if (FAKE_LOG_DEVICE == 0)
- if (pstore_fd >= 0) {
- __write_to_log_daemon(log_id, vec, nr);
- }
-#endif
- return ret;
- }
-
- write_to_log = __write_to_log_daemon;
- }
-
- unlock();
-
- return write_to_log(log_id, vec, nr);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char *tag,
- const char *msg)
-{
- return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
- const char *tag, const char *msg)
-{
- struct iovec vec[3];
- char tmp_tag[32];
-
- if (!tag)
- tag = "";
-
- /* XXX: This needs to go! */
- if ((bufID != LOG_ID_RADIO) &&
- (!strcmp(tag, "HTC_RIL") ||
- !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
- !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
- !strcmp(tag, "AT") ||
- !strcmp(tag, "GSM") ||
- !strcmp(tag, "STK") ||
- !strcmp(tag, "CDMA") ||
- !strcmp(tag, "PHONE") ||
- !strcmp(tag, "SMS"))) {
- bufID = LOG_ID_RADIO;
- /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
- snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
- tag = tmp_tag;
- }
-
-#if __BIONIC__
- if (prio == ANDROID_LOG_FATAL) {
- android_set_abort_message(msg);
- }
-#endif
-
- vec[0].iov_base = (unsigned char *) &prio;
- vec[0].iov_len = 1;
- vec[1].iov_base = (void *) tag;
- vec[1].iov_len = strlen(tag) + 1;
- vec[2].iov_base = (void *) msg;
- vec[2].iov_len = strlen(msg) + 1;
-
- return write_to_log(bufID, vec, 3);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char *tag,
- const char *fmt, va_list ap)
-{
- char buf[LOG_BUF_SIZE];
-
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
-
- return __android_log_write(prio, tag, buf);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char *tag,
- const char *fmt, ...)
-{
- va_list ap;
- char buf[LOG_BUF_SIZE];
-
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
-
- return __android_log_write(prio, tag, buf);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
- const char *tag,
- const char *fmt, ...)
-{
- va_list ap;
- char buf[LOG_BUF_SIZE];
-
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
-
- return __android_log_buf_write(bufID, prio, tag, buf);
-}
-
-LIBLOG_ABI_PUBLIC void __android_log_assert(
- const char *cond,
- const char *tag,
- const char *fmt, ...)
-{
- char buf[LOG_BUF_SIZE];
-
- if (fmt) {
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
- } else {
- /* Msg not provided, log condition. N.B. Do not use cond directly as
- * format string as it could contain spurious '%' syntax (e.g.
- * "%d" in "blocks%devs == 0").
- */
- if (cond)
- snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
- else
- strcpy(buf, "Unspecified assertion failed");
- }
-
- __android_log_write(ANDROID_LOG_FATAL, tag, buf);
- abort(); /* abort so we have a chance to debug the situation */
- /* NOTREACHED */
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag,
- const void *payload, size_t len)
-{
- struct iovec vec[2];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
-
- return write_to_log(LOG_ID_EVENTS, vec, 2);
-}
-
-LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
- const void *payload,
- size_t len)
-{
- struct iovec vec[2];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
-
- return write_to_log(LOG_ID_SECURITY, vec, 2);
-}
-
-/*
- * Like __android_log_bwrite, but takes the type as well. Doesn't work
- * for the general case where we're generating lists of stuff, but very
- * handy if we just want to dump an integer into the log.
- */
-LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type,
- const void *payload, size_t len)
-{
- struct iovec vec[3];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = (void*)payload;
- vec[2].iov_len = len;
-
- return write_to_log(LOG_ID_EVENTS, vec, 3);
-}
-
-/*
- * Like __android_log_bwrite, but used for writing strings to the
- * event log.
- */
-LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char *payload)
-{
- struct iovec vec[4];
- char type = EVENT_TYPE_STRING;
- uint32_t len = strlen(payload);
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = &len;
- vec[2].iov_len = sizeof(len);
- vec[3].iov_base = (void*)payload;
- vec[3].iov_len = len;
-
- return write_to_log(LOG_ID_EVENTS, vec, 4);
-}
-
-/*
- * Like __android_log_security_bwrite, but used for writing strings to the
- * security log.
- */
-LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag,
- const char *payload)
-{
- struct iovec vec[4];
- char type = EVENT_TYPE_STRING;
- uint32_t len = strlen(payload);
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = &len;
- vec[2].iov_len = sizeof(len);
- vec[3].iov_base = (void*)payload;
- vec[3].iov_len = len;
-
- return write_to_log(LOG_ID_SECURITY, vec, 4);
-}
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
new file mode 100644
index 0000000..696237d
--- /dev/null
+++ b/liblog/logd_writer.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2007-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 <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdatomic.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+#include <log/logd.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_write.h"
+#include "log_portability.h"
+#include "logger.h"
+
+/* branchless on many architectures. */
+#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
+
+static int logdAvailable(log_id_t LogId);
+static int logdOpen();
+static void logdClose();
+static int logdWrite(log_id_t logId, struct timespec *ts,
+ struct iovec *vec, size_t nr);
+
+LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = {
+ .node = { &logdLoggerWrite.node, &logdLoggerWrite.node },
+ .context.sock = -1,
+ .name = "logd",
+ .available = logdAvailable,
+ .open = logdOpen,
+ .close = logdClose,
+ .write = logdWrite,
+};
+
+/* log_init_lock assumed */
+static int logdOpen()
+{
+ int i, ret = 0;
+
+ if (logdLoggerWrite.context.sock < 0) {
+ i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+ if (i < 0) {
+ ret = -errno;
+ } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
+ ret = -errno;
+ close(i);
+ } else {
+ struct sockaddr_un un;
+ memset(&un, 0, sizeof(struct sockaddr_un));
+ un.sun_family = AF_UNIX;
+ strcpy(un.sun_path, "/dev/socket/logdw");
+
+ if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
+ sizeof(struct sockaddr_un))) < 0) {
+ ret = -errno;
+ close(i);
+ } else {
+ logdLoggerWrite.context.sock = i;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void logdClose()
+{
+ if (logdLoggerWrite.context.sock >= 0) {
+ close(logdLoggerWrite.context.sock);
+ logdLoggerWrite.context.sock = -1;
+ }
+}
+
+static int logdAvailable(log_id_t logId)
+{
+ if (logId > LOG_ID_SECURITY) {
+ return -EINVAL;
+ }
+ if (logId == LOG_ID_SECURITY) {
+ uid_t uid = __android_log_uid();
+ if ((uid != AID_LOG) && (uid != AID_ROOT) && (uid != AID_SYSTEM)) {
+ return -EPERM;
+ }
+ }
+ if (logdLoggerWrite.context.sock < 0) {
+ if (access("/dev/socket/logdw", W_OK) == 0) {
+ return 0;
+ }
+ return -EBADF;
+ }
+ return 1;
+}
+
+static int logdWrite(log_id_t logId, struct timespec *ts,
+ struct iovec *vec, size_t nr)
+{
+ ssize_t ret;
+ static const unsigned headerLength = 1;
+ struct iovec newVec[nr + headerLength];
+ android_log_header_t header;
+ size_t i, payloadSize;
+ static atomic_int_fast32_t dropped;
+ static atomic_int_fast32_t droppedSecurity;
+
+ if (logdLoggerWrite.context.sock < 0) {
+ return -EBADF;
+ }
+
+ /* logd, after initialization and priv drop */
+ if (__android_log_uid() == AID_LOGD) {
+ /*
+ * ignore log messages we send to ourself (logd).
+ * Such log messages are often generated by libraries we depend on
+ * which use standard Android logging.
+ */
+ return 0;
+ }
+
+ /*
+ * struct {
+ * // what we provide to socket
+ * android_log_header_t header;
+ * // caller provides
+ * union {
+ * struct {
+ * char prio;
+ * char payload[];
+ * } string;
+ * struct {
+ * uint32_t tag
+ * char payload[];
+ * } binary;
+ * };
+ * };
+ */
+
+ header.tid = gettid();
+ header.realtime.tv_sec = ts->tv_sec;
+ header.realtime.tv_nsec = ts->tv_nsec;
+
+ newVec[0].iov_base = (unsigned char *)&header;
+ newVec[0].iov_len = sizeof(header);
+
+ if (logdLoggerWrite.context.sock > 0) {
+ int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0,
+ memory_order_relaxed);
+ if (snapshot) {
+ android_log_event_int_t buffer;
+
+ header.id = LOG_ID_SECURITY;
+ buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+ buffer.payload.type = EVENT_TYPE_INT;
+ buffer.payload.data = htole32(snapshot);
+
+ newVec[headerLength].iov_base = &buffer;
+ newVec[headerLength].iov_len = sizeof(buffer);
+
+ ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
+ if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+ atomic_fetch_add_explicit(&droppedSecurity, snapshot,
+ memory_order_relaxed);
+ }
+ }
+ snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+ if (snapshot && __android_log_is_loggable(ANDROID_LOG_INFO,
+ "liblog",
+ ANDROID_LOG_VERBOSE)) {
+ android_log_event_int_t buffer;
+
+ header.id = LOG_ID_EVENTS;
+ buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+ buffer.payload.type = EVENT_TYPE_INT;
+ buffer.payload.data = htole32(snapshot);
+
+ newVec[headerLength].iov_base = &buffer;
+ newVec[headerLength].iov_len = sizeof(buffer);
+
+ ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, 2));
+ if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+ atomic_fetch_add_explicit(&dropped, snapshot,
+ memory_order_relaxed);
+ }
+ }
+ }
+
+ header.id = logId;
+
+ for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
+ newVec[i].iov_base = vec[i - headerLength].iov_base;
+ payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
+
+ if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
+ newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
+ if (newVec[i].iov_len) {
+ ++i;
+ }
+ break;
+ }
+ }
+
+ /*
+ * The write below could be lost, but will never block.
+ *
+ * ENOTCONN occurs if logd dies.
+ * EAGAIN occurs if logd is overloaded.
+ */
+ ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
+ if (ret < 0) {
+ ret = -errno;
+ if (ret == -ENOTCONN) {
+ __android_log_lock();
+ logdClose();
+ ret = logdOpen();
+ __android_log_unlock();
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = TEMP_FAILURE_RETRY(writev(logdLoggerWrite.context.sock, newVec, i));
+ if (ret < 0) {
+ ret = -errno;
+ }
+ }
+ }
+
+ if (ret > (ssize_t)sizeof(header)) {
+ ret -= sizeof(header);
+ } else if (ret == -EAGAIN) {
+ atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
+ if (logId == LOG_ID_SECURITY) {
+ atomic_fetch_add_explicit(&droppedSecurity, 1,
+ memory_order_relaxed);
+ }
+ }
+
+ return ret;
+}
diff --git a/liblog/logger.h b/liblog/logger.h
new file mode 100644
index 0000000..61bc396
--- /dev/null
+++ b/liblog/logger.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBLOG_LOGGER_H__
+#define _LIBLOG_LOGGER_H__
+
+#include <stdbool.h>
+#include <log/uio.h>
+
+#include <cutils/list.h>
+#include <log/log.h>
+#include <log/log_read.h>
+#include <log/logger.h>
+
+#include "log_portability.h"
+
+__BEGIN_DECLS
+
+/* Union, sock or fd of zero is not allowed unless static initialized */
+union android_log_context {
+ void *private;
+ int sock;
+ int fd;
+ struct listnode *node;
+};
+
+struct android_log_transport_write {
+ struct listnode node;
+ const char *name;
+ union android_log_context context; /* Initialized by static allocation */
+
+ int (*available)(log_id_t logId);
+ int (*open)();
+ void (*close)();
+ int (*write)(log_id_t logId, struct timespec *ts, struct iovec *vec, size_t nr);
+};
+
+struct android_log_logger_list;
+struct android_log_transport_context;
+struct android_log_logger;
+
+struct android_log_transport_read {
+ struct listnode node;
+ const char *name;
+
+ int (*available)(log_id_t logId);
+ int (*version)(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+ void (*close)(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp);
+
+ /*
+ * Expect all to instantiate open on any call, so we do not have
+ * an expicit open call
+ */
+ int (*read)(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ struct log_msg *log_msg);
+ /* Assumption is only called if not ANDROID_LOG_NONBLOCK */
+ int (*poll)(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp);
+
+ int (*clear)(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+ ssize_t (*setSize)(struct android_log_logger *logger,
+ struct android_log_transport_context *transp,
+ size_t size);
+ ssize_t (*getSize)(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+ ssize_t (*getReadableSize)(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+
+ ssize_t (*getPrune)(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ char *buf, size_t len);
+ ssize_t (*setPrune)(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ char *buf, size_t len);
+ ssize_t (*getStats)(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ char *buf, size_t len);
+};
+
+struct android_log_logger_list {
+ struct listnode logger;
+ struct listnode transport;
+ int mode;
+ unsigned int tail;
+ log_time start;
+ pid_t pid;
+};
+
+struct android_log_logger {
+ struct listnode node;
+ struct android_log_logger_list *parent;
+
+ log_id_t logId;
+};
+
+struct android_log_transport_context {
+ struct listnode node;
+ union android_log_context context; /* zero init per-transport context */
+ struct android_log_logger_list *parent;
+
+ struct android_log_transport_read *transport;
+ unsigned logMask;
+ int ret;
+ struct log_msg logMsg; /* valid is logMsg.len != 0 */
+};
+
+/* assumes caller has structures read-locked, single threaded, or fenced */
+#define transport_context_for_each(transp, logger_list) \
+ for (transp = node_to_item((logger_list)->transport.next, \
+ struct android_log_transport_context, \
+ node); \
+ (transp != node_to_item(&(logger_list)->transport, \
+ struct android_log_transport_context, \
+ node)) && \
+ (transp->parent == (logger_list)); \
+ transp = node_to_item(transp->node.next, \
+ struct android_log_transport_context, node))
+
+#define logger_for_each(logp, logger_list) \
+ for (logp = node_to_item((logger_list)->logger.next, \
+ struct android_log_logger, node); \
+ (logp != node_to_item(&(logger_list)->logger, \
+ struct android_log_logger, node)) && \
+ (logp->parent == (logger_list)); \
+ logp = node_to_item((logp)->node.next, \
+ struct android_log_logger, node))
+
+/* OS specific dribs and drabs */
+
+#if defined(_WIN32)
+typedef uint32_t uid_t;
+#endif
+
+LIBLOG_HIDDEN uid_t __android_log_uid();
+LIBLOG_HIDDEN pid_t __android_log_pid();
+LIBLOG_HIDDEN void __android_log_lock();
+LIBLOG_HIDDEN int __android_log_trylock();
+LIBLOG_HIDDEN void __android_log_unlock();
+
+__END_DECLS
+
+#endif /* _LIBLOG_LOGGER_H__ */
diff --git a/liblog/logger_lock.c b/liblog/logger_lock.c
new file mode 100644
index 0000000..ee979bd
--- /dev/null
+++ b/liblog/logger_lock.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007-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.
+ */
+
+/*
+ * Some OS specific dribs and drabs (locking etc).
+ */
+
+#if !defined(_WIN32)
+#include <pthread.h>
+#endif
+
+#include <private/android_filesystem_config.h>
+
+#include "logger.h"
+
+LIBLOG_HIDDEN uid_t __android_log_uid()
+{
+#if defined(_WIN32)
+ return AID_SYSTEM;
+#else
+ static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
+
+ if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
+ last_uid = getuid();
+ }
+ return last_uid;
+#endif
+}
+
+LIBLOG_HIDDEN pid_t __android_log_pid()
+{
+ static pid_t last_pid = (pid_t) -1;
+
+ if (last_pid == (pid_t) -1) {
+ last_pid = getpid();
+ }
+ return last_pid;
+}
+
+#if !defined(_WIN32)
+static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+LIBLOG_HIDDEN void __android_log_lock()
+{
+#if !defined(_WIN32)
+ /*
+ * If we trigger a signal handler in the middle of locked activity and the
+ * signal handler logs a message, we could get into a deadlock state.
+ */
+ pthread_mutex_lock(&log_init_lock);
+#endif
+}
+
+LIBLOG_HIDDEN int __android_log_trylock()
+{
+#if !defined(_WIN32)
+ return pthread_mutex_trylock(&log_init_lock);
+#else
+ return 0;
+#endif
+}
+
+LIBLOG_HIDDEN void __android_log_unlock()
+{
+#if !defined(_WIN32)
+ pthread_mutex_unlock(&log_init_lock);
+#endif
+}
diff --git a/liblog/logger_name.c b/liblog/logger_name.c
new file mode 100644
index 0000000..b7ccac5
--- /dev/null
+++ b/liblog/logger_name.c
@@ -0,0 +1,65 @@
+/*
+** Copyright 2013-2014, 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 <string.h>
+
+#include <log/log.h>
+#include <log/logger.h>
+
+#include "log_portability.h"
+
+/* In the future, we would like to make this list extensible */
+static const char *LOG_NAME[LOG_ID_MAX] = {
+ [LOG_ID_MAIN] = "main",
+ [LOG_ID_RADIO] = "radio",
+ [LOG_ID_EVENTS] = "events",
+ [LOG_ID_SYSTEM] = "system",
+ [LOG_ID_CRASH] = "crash",
+ [LOG_ID_SECURITY] = "security",
+ [LOG_ID_KERNEL] = "kernel",
+};
+
+LIBLOG_ABI_PUBLIC const char *android_log_id_to_name(log_id_t log_id)
+{
+ if (log_id >= LOG_ID_MAX) {
+ log_id = LOG_ID_MAIN;
+ }
+ return LOG_NAME[log_id];
+}
+
+LIBLOG_ABI_PUBLIC log_id_t android_name_to_log_id(const char *logName)
+{
+ const char *b;
+ int ret;
+
+ if (!logName) {
+ return -1; /* NB: log_id_t is unsigned */
+ }
+ b = strrchr(logName, '/');
+ if (!b) {
+ b = logName;
+ } else {
+ ++b;
+ }
+
+ for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
+ const char *l = LOG_NAME[ret];
+ if (l && !strcmp(b, l)) {
+ return ret;
+ }
+ }
+ return -1; /* should never happen */
+}
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
new file mode 100644
index 0000000..f15c7cd
--- /dev/null
+++ b/liblog/logger_read.c
@@ -0,0 +1,474 @@
+/*
+** Copyright 2013-2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cutils/list.h>
+#include <log/log.h>
+#include <log/logger.h>
+
+#include "config_read.h"
+#include "log_portability.h"
+#include "logger.h"
+
+/* android_logger_alloc unimplemented, no use case */
+/* android_logger_free not exported */
+static void android_logger_free(struct logger *logger)
+{
+ struct android_log_logger *logger_internal =
+ (struct android_log_logger *)logger;
+
+ if (!logger_internal) {
+ return;
+ }
+
+ list_remove(&logger_internal->node);
+
+ free(logger_internal);
+}
+
+/* android_logger_alloc unimplemented, no use case */
+
+/* method for getting the associated sublog id */
+LIBLOG_ABI_PUBLIC log_id_t android_logger_get_id(struct logger *logger)
+{
+ return ((struct android_log_logger *)logger)->logId;
+}
+
+static int init_transport_context(struct android_log_logger_list *logger_list)
+{
+ struct android_log_transport_read *transport;
+ struct listnode *node;
+
+ if (!logger_list) {
+ return -EINVAL;
+ }
+
+ if (list_empty(&logger_list->logger)) {
+ return -EINVAL;
+ }
+
+ if (!list_empty(&logger_list->transport)) {
+ return 0;
+ }
+
+ __android_log_lock();
+ /* mini __write_to_log_initialize() to populate transports */
+ if (list_empty(&__android_log_transport_read) &&
+ list_empty(&__android_log_persist_read)) {
+ __android_log_config_read();
+ }
+ __android_log_unlock();
+
+ node = (logger_list->mode & ANDROID_LOG_PSTORE) ?
+ &__android_log_persist_read : &__android_log_transport_read;
+
+ read_transport_for_each(transport, node) {
+ struct android_log_transport_context *transp;
+ struct android_log_logger *logger;
+ unsigned logMask = 0;
+
+ logger_for_each(logger, logger_list) {
+ log_id_t logId = logger->logId;
+
+ if (transport->read &&
+ (!transport->available ||
+ (transport->available(logId) >= 0))) {
+ logMask |= 1 << logId;
+ }
+ }
+ if (!logMask) {
+ continue;
+ }
+ transp = calloc(1, sizeof(*transp));
+ if (!transp) {
+ return -ENOMEM;
+ }
+ transp->parent = logger_list;
+ transp->transport = transport;
+ transp->logMask = logMask;
+ transp->ret = 1;
+ list_add_tail(&logger_list->transport, &transp->node);
+ }
+ if (list_empty(&logger_list->transport)) {
+ return -ENODEV;
+ }
+ return 0;
+}
+
+#define LOGGER_FUNCTION(logger, def, func, args...) \
+ ssize_t ret = -EINVAL; \
+ struct android_log_transport_context *transp; \
+ struct android_log_logger *logger_internal = \
+ (struct android_log_logger *)logger; \
+ \
+ if (!logger_internal) { \
+ return ret; \
+ } \
+ ret = init_transport_context(logger_internal->parent); \
+ if (ret < 0) { \
+ return ret; \
+ } \
+ \
+ ret = (def); \
+ transport_context_for_each(transp, logger_internal->parent) { \
+ if ((transp->logMask & (1 << logger_internal->logId)) && \
+ transp->transport && transp->transport->func) { \
+ ssize_t retval = (transp->transport->func)(logger_internal, \
+ transp, ## args); \
+ if ((ret >= 0) || (ret == (def))) { \
+ ret = retval; \
+ } \
+ } \
+ } \
+ return ret
+
+LIBLOG_ABI_PUBLIC int android_logger_clear(struct logger *logger)
+{
+ LOGGER_FUNCTION(logger, -ENODEV, clear);
+}
+
+/* returns the total size of the log's ring buffer */
+LIBLOG_ABI_PUBLIC long android_logger_get_log_size(struct logger *logger)
+{
+ LOGGER_FUNCTION(logger, -ENODEV, getSize);
+}
+
+LIBLOG_ABI_PUBLIC int android_logger_set_log_size(struct logger *logger,
+ unsigned long size)
+{
+ LOGGER_FUNCTION(logger, -ENODEV, setSize, size);
+}
+
+/*
+ * returns the readable size of the log's ring buffer (that is, amount of the
+ * log consumed)
+ */
+LIBLOG_ABI_PUBLIC long android_logger_get_log_readable_size(
+ struct logger *logger)
+{
+ LOGGER_FUNCTION(logger, -ENODEV, getReadableSize);
+}
+
+/*
+ * returns the logger version
+ */
+LIBLOG_ABI_PUBLIC int android_logger_get_log_version(struct logger *logger)
+{
+ LOGGER_FUNCTION(logger, 4, version);
+}
+
+#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...) \
+ struct android_log_transport_context *transp; \
+ struct android_log_logger_list *logger_list_internal = \
+ (struct android_log_logger_list *)logger_list; \
+ \
+ ssize_t ret = init_transport_context(logger_list_internal); \
+ if (ret < 0) { \
+ return ret; \
+ } \
+ \
+ ret = (def); \
+ transport_context_for_each(transp, logger_list_internal) { \
+ if (transp->transport && (transp->transport->func)) { \
+ ssize_t retval = (transp->transport->func)(logger_list_internal, \
+ transp, ## args); \
+ if ((ret >= 0) || (ret == (def))) { \
+ ret = retval; \
+ } \
+ } \
+ } \
+ return ret
+
+/*
+ * returns statistics
+ */
+LIBLOG_ABI_PUBLIC ssize_t android_logger_get_statistics(
+ struct logger_list *logger_list,
+ char *buf, size_t len)
+{
+ LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getStats, buf, len);
+}
+
+LIBLOG_ABI_PUBLIC ssize_t android_logger_get_prune_list(
+ struct logger_list *logger_list,
+ char *buf, size_t len)
+{
+ LOGGER_LIST_FUNCTION(logger_list, -ENODEV, getPrune, buf, len);
+}
+
+LIBLOG_ABI_PUBLIC int android_logger_set_prune_list(
+ struct logger_list *logger_list,
+ char *buf, size_t len)
+{
+ LOGGER_LIST_FUNCTION(logger_list, -ENODEV, setPrune, buf, len);
+}
+
+LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc(
+ int mode,
+ unsigned int tail,
+ pid_t pid)
+{
+ struct android_log_logger_list *logger_list;
+
+ logger_list = calloc(1, sizeof(*logger_list));
+ if (!logger_list) {
+ return NULL;
+ }
+
+ list_init(&logger_list->logger);
+ list_init(&logger_list->transport);
+ logger_list->mode = mode;
+ logger_list->tail = tail;
+ logger_list->pid = pid;
+
+ return (struct logger_list *)logger_list;
+}
+
+LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_alloc_time(
+ int mode,
+ log_time start,
+ pid_t pid)
+{
+ struct android_log_logger_list *logger_list;
+
+ logger_list = calloc(1, sizeof(*logger_list));
+ if (!logger_list) {
+ return NULL;
+ }
+
+ list_init(&logger_list->logger);
+ list_init(&logger_list->transport);
+ logger_list->mode = mode;
+ logger_list->start = start;
+ logger_list->pid = pid;
+
+ return (struct logger_list *)logger_list;
+}
+
+/* android_logger_list_register unimplemented, no use case */
+/* android_logger_list_unregister unimplemented, no use case */
+
+/* Open the named log and add it to the logger list */
+LIBLOG_ABI_PUBLIC struct logger *android_logger_open(
+ struct logger_list *logger_list,
+ log_id_t logId)
+{
+ struct android_log_logger_list *logger_list_internal =
+ (struct android_log_logger_list *)logger_list;
+ struct android_log_logger *logger;
+
+ if (!logger_list_internal || (logId >= LOG_ID_MAX)) {
+ goto err;
+ }
+
+ logger_for_each(logger, logger_list_internal) {
+ if (logger->logId == logId) {
+ goto ok;
+ }
+ }
+
+ logger = calloc(1, sizeof(*logger));
+ if (!logger) {
+ goto err;
+ }
+
+ logger->logId = logId;
+ list_add_tail(&logger_list_internal->logger, &logger->node);
+ logger->parent = logger_list_internal;
+
+ /* Reset known transports to re-evaluate, we just added one */
+ while (!list_empty(&logger_list_internal->transport)) {
+ struct listnode *node = list_head(&logger_list_internal->transport);
+ struct android_log_transport_context *transp =
+ node_to_item(node, struct android_log_transport_context, node);
+
+ list_remove(&transp->node);
+ free(transp);
+ }
+ goto ok;
+
+err:
+ logger = NULL;
+ok:
+ return (struct logger *)logger;
+}
+
+/* Open the single named log and make it part of a new logger list */
+LIBLOG_ABI_PUBLIC struct logger_list *android_logger_list_open(
+ log_id_t logId,
+ int mode,
+ unsigned int tail,
+ pid_t pid)
+{
+ struct logger_list *logger_list =
+ android_logger_list_alloc(mode, tail, pid);
+
+ if (!logger_list) {
+ return NULL;
+ }
+
+ if (!android_logger_open(logger_list, logId)) {
+ android_logger_list_free(logger_list);
+ return NULL;
+ }
+
+ return logger_list;
+}
+
+/* Read from the selected logs */
+LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
+ struct log_msg *log_msg)
+{
+ struct android_log_transport_context *transp;
+ struct android_log_logger_list *logger_list_internal =
+ (struct android_log_logger_list *)logger_list;
+
+ int ret = init_transport_context(logger_list_internal);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* at least one transport */
+ transp = node_to_item(logger_list_internal->transport.next,
+ struct android_log_transport_context, node);
+
+ /* more than one transport? */
+ if (transp->node.next != &logger_list_internal->transport) {
+ /* Poll and merge sort the entries if from multiple transports */
+ struct android_log_transport_context *oldest = NULL;
+ int ret;
+ int polled = 0;
+ do {
+ if (polled) {
+ sched_yield();
+ }
+ ret = -1000;
+ polled = 0;
+ do {
+ int retval = transp->ret;
+ if ((retval > 0) && !transp->logMsg.entry.len) {
+ if (!transp->transport->read) {
+ retval = transp->ret = 0;
+ } else if ((logger_list_internal->mode &
+ ANDROID_LOG_NONBLOCK) ||
+ !transp->transport->poll) {
+ retval = transp->ret = (*transp->transport->read)(
+ logger_list_internal,
+ transp,
+ &transp->logMsg);
+ } else {
+ int pollval = (*transp->transport->poll)(
+ logger_list_internal, transp);
+ if (pollval <= 0) {
+ sched_yield();
+ pollval = (*transp->transport->poll)(
+ logger_list_internal, transp);
+ }
+ polled = 1;
+ if (pollval < 0) {
+ if ((pollval == -EINTR) || (pollval == -EAGAIN)) {
+ return -EAGAIN;
+ }
+ retval = transp->ret = pollval;
+ } else if (pollval > 0) {
+ retval = transp->ret = (*transp->transport->read)(
+ logger_list_internal,
+ transp,
+ &transp->logMsg);
+ }
+ }
+ }
+ if (ret < retval) {
+ ret = retval;
+ }
+ if ((transp->ret > 0) && transp->logMsg.entry.len &&
+ (!oldest ||
+ (oldest->logMsg.entry.sec >
+ transp->logMsg.entry.sec) ||
+ ((oldest->logMsg.entry.sec ==
+ transp->logMsg.entry.sec) &&
+ (oldest->logMsg.entry.nsec >
+ transp->logMsg.entry.nsec)))) {
+ oldest = transp;
+ }
+ transp = node_to_item(transp->node.next,
+ struct android_log_transport_context,
+ node);
+ } while (transp != node_to_item(
+ &logger_list_internal->transport,
+ struct android_log_transport_context,
+ node));
+ if (!oldest &&
+ (logger_list_internal->mode & ANDROID_LOG_NONBLOCK)) {
+ return (ret < 0) ? ret : -EAGAIN;
+ }
+ transp = node_to_item(logger_list_internal->transport.next,
+ struct android_log_transport_context, node);
+ } while (!oldest && (ret > 0));
+ if (!oldest) {
+ return ret;
+ }
+ memcpy(log_msg, &oldest->logMsg, oldest->logMsg.entry.len +
+ (oldest->logMsg.entry.hdr_size ?
+ oldest->logMsg.entry.hdr_size :
+ sizeof(struct logger_entry)));
+ oldest->logMsg.entry.len = 0; /* Mark it as copied */
+ return oldest->ret;
+ }
+
+ /* if only one, no need to copy into transport_context and merge-sort */
+ return (transp->transport->read)(logger_list_internal, transp, log_msg);
+}
+
+/* Close all the logs */
+LIBLOG_ABI_PUBLIC void android_logger_list_free(struct logger_list *logger_list)
+{
+ struct android_log_logger_list *logger_list_internal =
+ (struct android_log_logger_list *)logger_list;
+
+ if (logger_list_internal == NULL) {
+ return;
+ }
+
+ while (!list_empty(&logger_list_internal->transport)) {
+ struct listnode *node = list_head(&logger_list_internal->transport);
+ struct android_log_transport_context *transp =
+ node_to_item(node, struct android_log_transport_context, node);
+
+ if (transp->transport && transp->transport->close) {
+ (*transp->transport->close)(logger_list_internal, transp);
+ }
+ list_remove(&transp->node);
+ free(transp);
+ }
+
+ while (!list_empty(&logger_list_internal->logger)) {
+ struct listnode *node = list_head(&logger_list_internal->logger);
+ struct android_log_logger *logger =
+ node_to_item(node, struct android_log_logger, node);
+ android_logger_free((struct logger *)logger);
+ }
+
+ free(logger_list_internal);
+}
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
new file mode 100644
index 0000000..a4155e9
--- /dev/null
+++ b/liblog/logger_write.c
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2007-2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdatomic.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#ifdef __BIONIC__
+#include <android/set_abort_message.h>
+#endif
+
+#include <log/event_tag_map.h>
+#include <log/logd.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_write.h"
+#include "log_portability.h"
+#include "logger.h"
+
+#define LOG_BUF_SIZE 1024
+
+static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
+static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
+
+/*
+ * This is used by the C++ code to decide if it should write logs through
+ * the C code. Basically, if /dev/socket/logd is available, we're running in
+ * the simulator rather than a desktop tool and want to use the device.
+ */
+static enum {
+ kLogUninitialized, kLogNotAvailable, kLogAvailable
+} g_log_status = kLogUninitialized;
+
+LIBLOG_ABI_PUBLIC int __android_log_dev_available()
+{
+ struct android_log_transport_write *node;
+ size_t i;
+
+ if (list_empty(&__android_log_transport_write)) {
+ return kLogUninitialized;
+ }
+ for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+ write_transport_for_each(node, &__android_log_transport_write) {
+ if (node->write &&
+ (!node->available || ((*node->available)(i) >= 0))) {
+ return kLogAvailable;
+ }
+ }
+ }
+ return kLogNotAvailable;
+}
+
+/* log_init_lock assumed */
+static int __write_to_log_initialize()
+{
+ struct android_log_transport_write *transport;
+ struct listnode *n;
+ int i = 0, ret = 0;
+
+ __android_log_config_write();
+ write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
+ if (!transport->open || ((*transport->open)() < 0)) {
+ if (transport->close) {
+ (*transport->close)();
+ }
+ list_remove(&transport->node);
+ continue;
+ }
+ ++ret;
+ }
+ write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
+ if (!transport->open || ((*transport->open)() < 0)) {
+ if (transport->close) {
+ (*transport->close)();
+ }
+ list_remove(&transport->node);
+ continue;
+ }
+ ++i;
+ }
+ if (!ret && !i) {
+ return -ENODEV;
+ }
+
+ return ret;
+}
+
+/*
+ * Extract a 4-byte value from a byte stream. le32toh open coded
+ */
+static inline uint32_t get4LE(const uint8_t* src)
+{
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+static int __write_to_log_daemon(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+ struct android_log_transport_write *node;
+ int ret;
+ struct timespec ts;
+ size_t len, i;
+
+ for (len = i = 0; i < nr; ++i) {
+ len += vec[i].iov_len;
+ }
+ if (!len) {
+ return -EINVAL;
+ }
+
+#if defined(__BIONIC__)
+ if (log_id == LOG_ID_SECURITY) {
+ uid_t uid;
+
+ if (vec[0].iov_len < 4) {
+ return -EINVAL;
+ }
+
+ uid = __android_log_uid();
+ /* Matches clientHasLogCredentials() in logd */
+ if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+ uid = geteuid();
+ if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+ gid_t gid = getgid();
+ if ((gid != AID_SYSTEM) &&
+ (gid != AID_ROOT) &&
+ (gid != AID_LOG)) {
+ gid = getegid();
+ if ((gid != AID_SYSTEM) &&
+ (gid != AID_ROOT) &&
+ (gid != AID_LOG)) {
+ int num_groups;
+ gid_t *groups;
+
+ num_groups = getgroups(0, NULL);
+ if (num_groups <= 0) {
+ return -EPERM;
+ }
+ groups = calloc(num_groups, sizeof(gid_t));
+ if (!groups) {
+ return -ENOMEM;
+ }
+ num_groups = getgroups(num_groups, groups);
+ while (num_groups > 0) {
+ if (groups[num_groups - 1] == AID_LOG) {
+ break;
+ }
+ --num_groups;
+ }
+ free(groups);
+ if (num_groups <= 0) {
+ return -EPERM;
+ }
+ }
+ }
+ }
+ }
+ if (!__android_log_security()) {
+ /* If only we could reset downstream logd counter */
+ return -EPERM;
+ }
+ } else if (log_id == LOG_ID_EVENTS) {
+ static atomic_uintptr_t map;
+ const char *tag;
+ EventTagMap *m, *f;
+
+ if (vec[0].iov_len < 4) {
+ return -EINVAL;
+ }
+
+ tag = NULL;
+ f = NULL;
+ m = (EventTagMap *)atomic_load(&map);
+
+ if (!m) {
+ ret = __android_log_trylock();
+ m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */
+ if (!m) {
+ m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+ if (ret) { /* trylock failed, use local copy, mark for close */
+ f = m;
+ } else {
+ if (!m) { /* One chance to open map file */
+ m = (EventTagMap *)(uintptr_t)-1LL;
+ }
+ atomic_store(&map, (uintptr_t)m);
+ }
+ }
+ if (!ret) { /* trylock succeeded, unlock */
+ __android_log_unlock();
+ }
+ }
+ if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
+ tag = android_lookupEventTag(m, get4LE(vec[0].iov_base));
+ }
+ ret = __android_log_is_loggable(ANDROID_LOG_INFO,
+ tag,
+ ANDROID_LOG_VERBOSE);
+ if (f) { /* local copy marked for close */
+ android_closeEventTagMap(f);
+ }
+ if (!ret) {
+ return -EPERM;
+ }
+ } else {
+ /* Validate the incoming tag, tag content can not split across iovec */
+ char prio = ANDROID_LOG_VERBOSE;
+ const char *tag = vec[0].iov_base;
+ size_t len = vec[0].iov_len;
+ if (!tag) {
+ len = 0;
+ }
+ if (len > 0) {
+ prio = *tag;
+ if (len > 1) {
+ --len;
+ ++tag;
+ } else {
+ len = vec[1].iov_len;
+ tag = ((const char *)vec[1].iov_base);
+ if (!tag) {
+ len = 0;
+ }
+ }
+ }
+ /* tag must be nul terminated */
+ if (strnlen(tag, len) >= len) {
+ tag = NULL;
+ }
+
+ if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+ return -EPERM;
+ }
+ }
+
+ clock_gettime(android_log_clockid(), &ts);
+#else
+ /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
+ {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ }
+#endif
+
+ ret = 0;
+ write_transport_for_each(node, &__android_log_transport_write) {
+ if (node->write) {
+ ssize_t retval;
+ retval = (*node->write)(log_id, &ts, vec, nr);
+ if (ret >= 0) {
+ ret = retval;
+ }
+ }
+ }
+
+ write_transport_for_each(node, &__android_log_persist_write) {
+ if (node->write) {
+ (void)(*node->write)(log_id, &ts, vec, nr);
+ }
+ }
+
+ return ret;
+}
+
+static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+ __android_log_lock();
+
+ if (write_to_log == __write_to_log_init) {
+ int ret;
+
+ ret = __write_to_log_initialize();
+ if (ret < 0) {
+ __android_log_unlock();
+ if (!list_empty(&__android_log_persist_write)) {
+ __write_to_log_daemon(log_id, vec, nr);
+ }
+ return ret;
+ }
+
+ write_to_log = __write_to_log_daemon;
+ }
+
+ __android_log_unlock();
+
+ return write_to_log(log_id, vec, nr);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_write(int prio, const char *tag,
+ const char *msg)
+{
+ return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
+ const char *tag, const char *msg)
+{
+ struct iovec vec[3];
+ char tmp_tag[32];
+
+ if (!tag)
+ tag = "";
+
+ /* XXX: This needs to go! */
+ if ((bufID != LOG_ID_RADIO) &&
+ (!strcmp(tag, "HTC_RIL") ||
+ !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+ !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
+ !strcmp(tag, "AT") ||
+ !strcmp(tag, "GSM") ||
+ !strcmp(tag, "STK") ||
+ !strcmp(tag, "CDMA") ||
+ !strcmp(tag, "PHONE") ||
+ !strcmp(tag, "SMS"))) {
+ bufID = LOG_ID_RADIO;
+ /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
+ snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+ tag = tmp_tag;
+ }
+
+#if __BIONIC__
+ if (prio == ANDROID_LOG_FATAL) {
+ android_set_abort_message(msg);
+ }
+#endif
+
+ vec[0].iov_base = (unsigned char *) &prio;
+ vec[0].iov_len = 1;
+ vec[1].iov_base = (void *) tag;
+ vec[1].iov_len = strlen(tag) + 1;
+ vec[2].iov_base = (void *) msg;
+ vec[2].iov_len = strlen(msg) + 1;
+
+ return write_to_log(bufID, vec, 3);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_vprint(int prio, const char *tag,
+ const char *fmt, va_list ap)
+{
+ char buf[LOG_BUF_SIZE];
+
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+
+ return __android_log_write(prio, tag, buf);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_print(int prio, const char *tag,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char buf[LOG_BUF_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+ va_end(ap);
+
+ return __android_log_write(prio, tag, buf);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_buf_print(int bufID, int prio,
+ const char *tag,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char buf[LOG_BUF_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+ va_end(ap);
+
+ return __android_log_buf_write(bufID, prio, tag, buf);
+}
+
+LIBLOG_ABI_PUBLIC void __android_log_assert(const char *cond, const char *tag,
+ const char *fmt, ...)
+{
+ char buf[LOG_BUF_SIZE];
+
+ if (fmt) {
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+ va_end(ap);
+ } else {
+ /* Msg not provided, log condition. N.B. Do not use cond directly as
+ * format string as it could contain spurious '%' syntax (e.g.
+ * "%d" in "blocks%devs == 0").
+ */
+ if (cond)
+ snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
+ else
+ strcpy(buf, "Unspecified assertion failed");
+ }
+
+ __android_log_write(ANDROID_LOG_FATAL, tag, buf);
+ abort(); /* abort so we have a chance to debug the situation */
+ /* NOTREACHED */
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_bwrite(int32_t tag,
+ const void *payload, size_t len)
+{
+ struct iovec vec[2];
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = (void*)payload;
+ vec[1].iov_len = len;
+
+ return write_to_log(LOG_ID_EVENTS, vec, 2);
+}
+
+LIBLOG_ABI_PUBLIC int __android_log_security_bwrite(int32_t tag,
+ const void *payload,
+ size_t len)
+{
+ struct iovec vec[2];
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = (void*)payload;
+ vec[1].iov_len = len;
+
+ return write_to_log(LOG_ID_SECURITY, vec, 2);
+}
+
+/*
+ * Like __android_log_bwrite, but takes the type as well. Doesn't work
+ * for the general case where we're generating lists of stuff, but very
+ * handy if we just want to dump an integer into the log.
+ */
+LIBLOG_ABI_PUBLIC int __android_log_btwrite(int32_t tag, char type,
+ const void *payload, size_t len)
+{
+ struct iovec vec[3];
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = (void*)payload;
+ vec[2].iov_len = len;
+
+ return write_to_log(LOG_ID_EVENTS, vec, 3);
+}
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+LIBLOG_ABI_PUBLIC int __android_log_bswrite(int32_t tag, const char *payload)
+{
+ struct iovec vec[4];
+ char type = EVENT_TYPE_STRING;
+ uint32_t len = strlen(payload);
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = &len;
+ vec[2].iov_len = sizeof(len);
+ vec[3].iov_base = (void*)payload;
+ vec[3].iov_len = len;
+
+ return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
+
+/*
+ * Like __android_log_security_bwrite, but used for writing strings to the
+ * security log.
+ */
+LIBLOG_ABI_PUBLIC int __android_log_security_bswrite(int32_t tag,
+ const char *payload)
+{
+ struct iovec vec[4];
+ char type = EVENT_TYPE_STRING;
+ uint32_t len = strlen(payload);
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = &len;
+ vec[2].iov_len = sizeof(len);
+ vec[3].iov_base = (void*)payload;
+ vec[3].iov_len = len;
+
+ return write_to_log(LOG_ID_SECURITY, vec, 4);
+}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 02df8dd..9b60d4a 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -34,7 +34,7 @@
#include <log/logprint.h>
#include <private/android_filesystem_config.h>
-#include "log_cdefs.h"
+#include "log_portability.h"
#define MS_PER_NSEC 1000000
#define US_PER_NSEC 1000
@@ -512,8 +512,18 @@
}
if (msgStart == -1) {
- fprintf(stderr, "+++ LOG: malformed log message\n");
- return -1;
+ /* +++ LOG: malformed log message, DYB */
+ for (i = 1; i < buf->len; i++) {
+ /* odd characters in tag? */
+ if ((msg[i] <= ' ') || (msg[i] == ':') || (msg[i] >= 0x7f)) {
+ msg[i] = '\0';
+ msgStart = i + 1;
+ break;
+ }
+ }
+ if (msgStart == -1) {
+ msgStart = buf->len - 1; /* All tag, no message, print truncates */
+ }
}
if (msgEnd == -1) {
/* incoming message not null-terminated; force it */
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
new file mode 100644
index 0000000..5695e8a
--- /dev/null
+++ b/liblog/pmsg_reader.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (C) 2007-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 <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_read.h"
+#include "logger.h"
+
+static int pmsgAvailable(log_id_t logId);
+static int pmsgVersion(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+static int pmsgRead(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ struct log_msg *log_msg);
+static void pmsgClose(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp);
+static int pmsgClear(struct android_log_logger *logger,
+ struct android_log_transport_context *transp);
+
+LIBLOG_HIDDEN struct android_log_transport_read pmsgLoggerRead = {
+ .node = { &pmsgLoggerRead.node, &pmsgLoggerRead.node },
+ .name = "pmsg",
+ .available = pmsgAvailable,
+ .version = pmsgVersion,
+ .read = pmsgRead,
+ .poll = NULL,
+ .close = pmsgClose,
+ .clear = pmsgClear,
+ .setSize = NULL,
+ .getSize = NULL,
+ .getReadableSize = NULL,
+ .getPrune = NULL,
+ .setPrune = NULL,
+ .getStats = NULL,
+};
+
+static int pmsgAvailable(log_id_t logId)
+{
+ if (logId > LOG_ID_SECURITY) {
+ return -EINVAL;
+ }
+ if (access("/dev/pmsg0", W_OK) == 0) {
+ return 0;
+ }
+ return -EBADF;
+}
+
+/* Determine the credentials of the caller */
+static bool uid_has_log_permission(uid_t uid)
+{
+ return (uid == AID_SYSTEM) || (uid == AID_LOG) || (uid == AID_ROOT);
+}
+
+static uid_t get_best_effective_uid()
+{
+ uid_t euid;
+ uid_t uid;
+ gid_t gid;
+ ssize_t i;
+ static uid_t last_uid = (uid_t) -1;
+
+ if (last_uid != (uid_t) -1) {
+ return last_uid;
+ }
+ uid = __android_log_uid();
+ if (uid_has_log_permission(uid)) {
+ return last_uid = uid;
+ }
+ euid = geteuid();
+ if (uid_has_log_permission(euid)) {
+ return last_uid = euid;
+ }
+ gid = getgid();
+ if (uid_has_log_permission(gid)) {
+ return last_uid = gid;
+ }
+ gid = getegid();
+ if (uid_has_log_permission(gid)) {
+ return last_uid = gid;
+ }
+ i = getgroups((size_t) 0, NULL);
+ if (i > 0) {
+ gid_t list[i];
+
+ getgroups(i, list);
+ while (--i >= 0) {
+ if (uid_has_log_permission(list[i])) {
+ return last_uid = list[i];
+ }
+ }
+ }
+ return last_uid = uid;
+}
+
+static int pmsgClear(struct android_log_logger *logger __unused,
+ struct android_log_transport_context *transp __unused)
+{
+ if (uid_has_log_permission(get_best_effective_uid())) {
+ return unlink("/sys/fs/pstore/pmsg-ramoops-0");
+ }
+ errno = EPERM;
+ return -1;
+}
+
+/*
+ * returns the logger version
+ */
+static int pmsgVersion(struct android_log_logger *logger __unused,
+ struct android_log_transport_context *transp __unused)
+{
+ return 4;
+}
+
+static int pmsgRead(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ struct log_msg *log_msg)
+{
+ ssize_t ret;
+ off_t current, next;
+ uid_t uid;
+ struct android_log_logger *logger;
+ struct __attribute__((__packed__)) {
+ android_pmsg_log_header_t p;
+ android_log_header_t l;
+ } buf;
+ static uint8_t preread_count;
+ bool is_system;
+
+ memset(log_msg, 0, sizeof(*log_msg));
+
+ if (transp->context.fd <= 0) {
+ int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+
+ if (fd < 0) {
+ return -errno;
+ }
+ if (fd == 0) { /* Argggg */
+ fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+ close(0);
+ if (fd < 0) {
+ return -errno;
+ }
+ }
+ transp->context.fd = fd;
+ preread_count = 0;
+ }
+
+ while(1) {
+ if (preread_count < sizeof(buf)) {
+ ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
+ &buf.p.magic + preread_count,
+ sizeof(buf) - preread_count));
+ if (ret < 0) {
+ return -errno;
+ }
+ preread_count += ret;
+ }
+ if (preread_count != sizeof(buf)) {
+ return preread_count ? -EIO : -EAGAIN;
+ }
+ if ((buf.p.magic != LOGGER_MAGIC)
+ || (buf.p.len <= sizeof(buf))
+ || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD))
+ || (buf.l.id >= LOG_ID_MAX)
+ || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) {
+ do {
+ memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
+ } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
+ continue;
+ }
+ preread_count = 0;
+
+ if ((transp->logMask & (1 << buf.l.id)) &&
+ ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
+ ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
+ ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
+ (logger_list->start.tv_nsec <=
+ buf.l.realtime.tv_nsec)))) &&
+ (!logger_list->pid || (logger_list->pid == buf.p.pid))) {
+ uid = get_best_effective_uid();
+ is_system = uid_has_log_permission(uid);
+ if (is_system || (uid == buf.p.uid)) {
+ ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
+ is_system ?
+ log_msg->entry_v4.msg :
+ log_msg->entry_v3.msg,
+ buf.p.len - sizeof(buf)));
+ if (ret < 0) {
+ return -errno;
+ }
+ if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
+ return -EIO;
+ }
+
+ log_msg->entry_v4.len = buf.p.len - sizeof(buf);
+ log_msg->entry_v4.hdr_size = is_system ?
+ sizeof(log_msg->entry_v4) :
+ sizeof(log_msg->entry_v3);
+ log_msg->entry_v4.pid = buf.p.pid;
+ log_msg->entry_v4.tid = buf.l.tid;
+ log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
+ log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
+ log_msg->entry_v4.lid = buf.l.id;
+ if (is_system) {
+ log_msg->entry_v4.uid = buf.p.uid;
+ }
+
+ return ret;
+ }
+ }
+
+ current = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
+ (off_t)0, SEEK_CUR));
+ if (current < 0) {
+ return -errno;
+ }
+ next = TEMP_FAILURE_RETRY(lseek(transp->context.fd,
+ (off_t)(buf.p.len - sizeof(buf)),
+ SEEK_CUR));
+ if (next < 0) {
+ return -errno;
+ }
+ if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
+ return -EIO;
+ }
+ }
+}
+
+static void pmsgClose(struct android_log_logger_list *logger_list __unused,
+ struct android_log_transport_context *transp) {
+ if (transp->context.fd > 0) {
+ close (transp->context.fd);
+ }
+ transp->context.fd = 0;
+}
+
+LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_read(
+ log_id_t logId,
+ char prio,
+ const char *prefix,
+ __android_log_pmsg_file_read_fn fn, void *arg) {
+ ssize_t ret;
+ struct android_log_logger_list logger_list;
+ struct android_log_transport_context transp;
+ struct content {
+ struct listnode node;
+ union {
+ struct logger_entry_v4 entry;
+ struct logger_entry_v4 entry_v4;
+ struct logger_entry_v3 entry_v3;
+ struct logger_entry_v2 entry_v2;
+ struct logger_entry entry_v1;
+ };
+ } *content;
+ struct names {
+ struct listnode node;
+ struct listnode content;
+ log_id_t id;
+ char prio;
+ char name[];
+ } *names;
+ struct listnode name_list;
+ struct listnode *node, *n;
+ size_t len, prefix_len;
+
+ if (!fn) {
+ return -EINVAL;
+ }
+
+ /* Add just enough clues in logger_list and transp to make API function */
+ memset(&logger_list, 0, sizeof(logger_list));
+ memset(&transp, 0, sizeof(transp));
+
+ logger_list.mode = ANDROID_LOG_PSTORE |
+ ANDROID_LOG_NONBLOCK |
+ ANDROID_LOG_RDONLY;
+ transp.logMask = (unsigned)-1;
+ if (logId != LOG_ID_ANY) {
+ transp.logMask = (1 << logId);
+ }
+ transp.logMask &= ~((1 << LOG_ID_KERNEL) |
+ (1 << LOG_ID_EVENTS) |
+ (1 << LOG_ID_SECURITY));
+ if (!transp.logMask) {
+ return -EINVAL;
+ }
+
+ /* Initialize name list */
+ list_init(&name_list);
+
+ ret = SSIZE_MAX;
+
+ /* Validate incoming prefix, shift until it contains only 0 or 1 : or / */
+ prefix_len = 0;
+ if (prefix) {
+ const char *prev = NULL, *last = NULL, *cp = prefix;
+ while ((cp = strpbrk(cp, "/:"))) {
+ prev = last;
+ last = cp;
+ cp = cp + 1;
+ }
+ if (prev) {
+ prefix = prev + 1;
+ }
+ prefix_len = strlen(prefix);
+ }
+
+ /* Read the file content */
+ while (pmsgRead(&logger_list, &transp, &transp.logMsg) > 0) {
+ char *cp;
+ size_t hdr_size = transp.logMsg.entry.hdr_size ?
+ transp.logMsg.entry.hdr_size : sizeof(transp.logMsg.entry_v1);
+ char *msg = (char *)&transp.logMsg + hdr_size;
+ char *split = NULL;
+
+ /* Check for invalid sequence number */
+ if ((transp.logMsg.entry.nsec % ANDROID_LOG_PMSG_FILE_SEQUENCE) ||
+ ((transp.logMsg.entry.nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
+ ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE)) {
+ continue;
+ }
+
+ /* Determine if it has <dirbase>:<filebase> format for tag */
+ len = transp.logMsg.entry.len - sizeof(prio);
+ for (cp = msg + sizeof(prio);
+ *cp && isprint(*cp) && !isspace(*cp) && --len;
+ ++cp) {
+ if (*cp == ':') {
+ if (split) {
+ break;
+ }
+ split = cp;
+ }
+ }
+ if (*cp || !split) {
+ continue;
+ }
+
+ /* Filters */
+ if (prefix_len && strncmp(msg + sizeof(prio), prefix, prefix_len)) {
+ size_t offset;
+ /*
+ * Allow : to be a synonym for /
+ * Things we do dealing with const char * and do not alloc
+ */
+ split = strchr(prefix, ':');
+ if (split) {
+ continue;
+ }
+ split = strchr(prefix, '/');
+ if (!split) {
+ continue;
+ }
+ offset = split - prefix;
+ if ((msg[offset + sizeof(prio)] != ':') ||
+ strncmp(msg + sizeof(prio), prefix, offset)) {
+ continue;
+ }
+ ++offset;
+ if ((prefix_len > offset) &&
+ strncmp(&msg[offset + sizeof(prio)], split + 1, prefix_len - offset)) {
+ continue;
+ }
+ }
+
+ if ((prio != ANDROID_LOG_ANY) && (*msg < prio)) {
+ continue;
+ }
+
+ /* check if there is an existing entry */
+ list_for_each(node, &name_list) {
+ names = node_to_item(node, struct names, node);
+ if (!strcmp(names->name, msg + sizeof(prio)) &&
+ (names->id == transp.logMsg.entry.lid) &&
+ (names->prio == *msg)) {
+ break;
+ }
+ }
+
+ /* We do not have an existing entry, create and add one */
+ if (node == &name_list) {
+ static const char numbers[] = "0123456789";
+ unsigned long long nl;
+
+ len = strlen(msg + sizeof(prio)) + 1;
+ names = calloc(1, sizeof(*names) + len);
+ if (!names) {
+ ret = -ENOMEM;
+ break;
+ }
+ strcpy(names->name, msg + sizeof(prio));
+ names->id = transp.logMsg.entry.lid;
+ names->prio = *msg;
+ list_init(&names->content);
+ /*
+ * Insert in reverse numeric _then_ alpha sorted order as
+ * representative of log rotation:
+ *
+ * log.10
+ * klog.10
+ * . . .
+ * log.2
+ * klog.2
+ * log.1
+ * klog.1
+ * log
+ * klog
+ *
+ * thus when we present the content, we are provided the oldest
+ * first, which when 'refreshed' could spill off the end of the
+ * pmsg FIFO but retaining the newest data for last with best
+ * chances to survive.
+ */
+ nl = 0;
+ cp = strpbrk(names->name, numbers);
+ if (cp) {
+ nl = strtoull(cp, NULL, 10);
+ }
+ list_for_each_reverse(node, &name_list) {
+ struct names *a_name = node_to_item(node, struct names, node);
+ const char *r = a_name->name;
+ int compare = 0;
+
+ unsigned long long nr = 0;
+ cp = strpbrk(r, numbers);
+ if (cp) {
+ nr = strtoull(cp, NULL, 10);
+ }
+ if (nr != nl) {
+ compare = (nl > nr) ? 1 : -1;
+ }
+ if (compare == 0) {
+ compare = strcmp(names->name, r);
+ }
+ if (compare <= 0) {
+ break;
+ }
+ }
+ list_add_head(node, &names->node);
+ }
+
+ /* Remove any file fragments that match our sequence number */
+ list_for_each_safe(node, n, &names->content) {
+ content = node_to_item(node, struct content, node);
+ if (transp.logMsg.entry.nsec == content->entry.nsec) {
+ list_remove(&content->node);
+ free(content);
+ }
+ }
+
+ /* Add content */
+ content = calloc(1, sizeof(content->node) +
+ hdr_size + transp.logMsg.entry.len);
+ if (!content) {
+ ret = -ENOMEM;
+ break;
+ }
+ memcpy(&content->entry, &transp.logMsg.entry,
+ hdr_size + transp.logMsg.entry.len);
+
+ /* Insert in sequence number sorted order, to ease reconstruction */
+ list_for_each_reverse(node, &names->content) {
+ if ((node_to_item(node, struct content, node))->entry.nsec <
+ transp.logMsg.entry.nsec) {
+ break;
+ }
+ }
+ list_add_head(node, &content->node);
+ }
+ pmsgClose(&logger_list, &transp);
+
+ /* Progress through all the collected files */
+ list_for_each_safe(node, n, &name_list) {
+ struct listnode *content_node, *m;
+ char *buf;
+ size_t sequence, tag_len;
+
+ names = node_to_item(node, struct names, node);
+
+ /* Construct content into a linear buffer */
+ buf = NULL;
+ len = 0;
+ sequence = 0;
+ tag_len = strlen(names->name) + sizeof(char); /* tag + nul */
+ list_for_each_safe(content_node, m, &names->content) {
+ ssize_t add_len;
+
+ content = node_to_item(content_node, struct content, node);
+ add_len = content->entry.len - tag_len - sizeof(prio);
+ if (add_len <= 0) {
+ list_remove(content_node);
+ free(content);
+ continue;
+ }
+
+ if (!buf) {
+ buf = malloc(sizeof(char));
+ if (!buf) {
+ ret = -ENOMEM;
+ list_remove(content_node);
+ free(content);
+ continue;
+ }
+ *buf = '\0';
+ }
+
+ /* Missing sequence numbers */
+ while (sequence < content->entry.nsec) {
+ /* plus space for enforced nul */
+ buf = realloc(buf, len + sizeof(char) + sizeof(char));
+ if (!buf) {
+ break;
+ }
+ buf[len] = '\f'; /* Mark missing content with a form feed */
+ buf[++len] = '\0';
+ sequence += ANDROID_LOG_PMSG_FILE_SEQUENCE;
+ }
+ if (!buf) {
+ ret = -ENOMEM;
+ list_remove(content_node);
+ free(content);
+ continue;
+ }
+ /* plus space for enforced nul */
+ buf = realloc(buf, len + add_len + sizeof(char));
+ if (!buf) {
+ ret = -ENOMEM;
+ list_remove(content_node);
+ free(content);
+ continue;
+ }
+ memcpy(buf + len,
+ (char *)&content->entry + content->entry.hdr_size +
+ tag_len + sizeof(prio),
+ add_len);
+ len += add_len;
+ buf[len] = '\0'; /* enforce trailing hidden nul */
+ sequence = content->entry.nsec + ANDROID_LOG_PMSG_FILE_SEQUENCE;
+
+ list_remove(content_node);
+ free(content);
+ }
+ if (buf) {
+ if (len) {
+ /* Buffer contains enforced trailing nul just beyond length */
+ ssize_t r;
+ *strchr(names->name, ':') = '/'; /* Convert back to filename */
+ r = (*fn)(names->id, names->prio, names->name, buf, len, arg);
+ if ((ret >= 0) && (r > 0)) {
+ if (ret == SSIZE_MAX) {
+ ret = r;
+ } else {
+ ret += r;
+ }
+ } else if (r < ret) {
+ ret = r;
+ }
+ }
+ free(buf);
+ }
+ list_remove(node);
+ free(names);
+ }
+ return (ret == SSIZE_MAX) ? -ENOENT : ret;
+}
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
new file mode 100644
index 0000000..7034ceb
--- /dev/null
+++ b/liblog/pmsg_writer.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2007-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.
+ */
+
+/*
+ * pmsg write handler
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <log/log.h>
+#include <log/logger.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
+
+#include "config_write.h"
+#include "log_portability.h"
+#include "logger.h"
+
+static int pmsgOpen();
+static void pmsgClose();
+static int pmsgAvailable(log_id_t logId);
+static int pmsgWrite(log_id_t logId, struct timespec *ts,
+ struct iovec *vec, size_t nr);
+
+LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = {
+ .node = { &pmsgLoggerWrite.node, &pmsgLoggerWrite.node },
+ .context.fd = -1,
+ .name = "pmsg",
+ .available = pmsgAvailable,
+ .open = pmsgOpen,
+ .close = pmsgClose,
+ .write = pmsgWrite,
+};
+
+static int pmsgOpen()
+{
+ if (pmsgLoggerWrite.context.fd < 0) {
+ pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+ }
+
+ return pmsgLoggerWrite.context.fd;
+}
+
+static void pmsgClose()
+{
+ if (pmsgLoggerWrite.context.fd >= 0) {
+ close(pmsgLoggerWrite.context.fd);
+ pmsgLoggerWrite.context.fd = -1;
+ }
+}
+
+static int pmsgAvailable(log_id_t logId)
+{
+ if (logId > LOG_ID_SECURITY) {
+ return -EINVAL;
+ }
+ if (pmsgLoggerWrite.context.fd < 0) {
+ if (access("/dev/pmsg0", W_OK) == 0) {
+ return 0;
+ }
+ return -EBADF;
+ }
+ return 1;
+}
+
+static int pmsgWrite(log_id_t logId, struct timespec *ts,
+ struct iovec *vec, size_t nr)
+{
+ static const unsigned headerLength = 2;
+ struct iovec newVec[nr + headerLength];
+ android_log_header_t header;
+ android_pmsg_log_header_t pmsgHeader;
+ size_t i, payloadSize;
+ ssize_t ret;
+
+ if (pmsgLoggerWrite.context.fd < 0) {
+ return -EBADF;
+ }
+
+ /*
+ * struct {
+ * // what we provide to pstore
+ * android_pmsg_log_header_t pmsgHeader;
+ * // what we provide to file
+ * android_log_header_t header;
+ * // caller provides
+ * union {
+ * struct {
+ * char prio;
+ * char payload[];
+ * } string;
+ * struct {
+ * uint32_t tag
+ * char payload[];
+ * } binary;
+ * };
+ * };
+ */
+
+ pmsgHeader.magic = LOGGER_MAGIC;
+ pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
+ pmsgHeader.uid = __android_log_uid();
+ pmsgHeader.pid = __android_log_pid();
+
+ header.id = logId;
+ header.tid = gettid();
+ header.realtime.tv_sec = ts->tv_sec;
+ header.realtime.tv_nsec = ts->tv_nsec;
+
+ newVec[0].iov_base = (unsigned char *)&pmsgHeader;
+ newVec[0].iov_len = sizeof(pmsgHeader);
+ newVec[1].iov_base = (unsigned char *)&header;
+ newVec[1].iov_len = sizeof(header);
+
+ for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
+ newVec[i].iov_base = vec[i - headerLength].iov_base;
+ payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
+
+ if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
+ newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
+ if (newVec[i].iov_len) {
+ ++i;
+ }
+ payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
+ break;
+ }
+ }
+ pmsgHeader.len += payloadSize;
+
+ ret = TEMP_FAILURE_RETRY(writev(pmsgLoggerWrite.context.fd, newVec, i));
+ if (ret < 0) {
+ ret = errno ? -errno : -ENOTCONN;
+ }
+
+ if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
+ ret -= sizeof(header) - sizeof(pmsgHeader);
+ }
+
+ return ret;
+}
+
+/*
+ * Virtual pmsg filesystem
+ *
+ * Payload will comprise the string "<basedir>:<basefile>\0<content>" to a
+ * maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the
+ * file.
+ *
+ * Will hijack the header.realtime.tv_nsec field for a sequence number in usec.
+ */
+
+static inline const char *strnrchr(const char *buf, size_t len, char c) {
+ const char *cp = buf + len;
+ while ((--cp > buf) && (*cp != c));
+ if (cp <= buf) {
+ return buf + len;
+ }
+ return cp;
+}
+
+/* Write a buffer as filename references (tag = <basedir>:<basename>) */
+LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_write(
+ log_id_t logId,
+ char prio,
+ const char *filename,
+ const char *buf, size_t len) {
+ int fd;
+ size_t length, packet_len;
+ const char *tag;
+ char *cp, *slash;
+ struct timespec ts;
+ struct iovec vec[3];
+
+ /* Make sure the logId value is not a bad idea */
+ if ((logId == LOG_ID_KERNEL) || /* Verbotten */
+ (logId == LOG_ID_EVENTS) || /* Do not support binary content */
+ (logId == LOG_ID_SECURITY) || /* Bad idea to allow */
+ ((unsigned)logId >= 32)) { /* fit within logMask on arch32 */
+ return -EINVAL;
+ }
+
+ clock_gettime(android_log_clockid(), &ts);
+
+ cp = strdup(filename);
+ if (!cp) {
+ return -ENOMEM;
+ }
+
+ fd = pmsgLoggerWrite.context.fd;
+ if (fd < 0) {
+ __android_log_lock();
+ fd = pmsgOpen();
+ __android_log_unlock();
+ if (fd < 0) {
+ return -EBADF;
+ }
+ }
+
+ tag = cp;
+ slash = strrchr(cp, '/');
+ if (slash) {
+ *slash = ':';
+ slash = strrchr(cp, '/');
+ if (slash) {
+ tag = slash + 1;
+ }
+ }
+
+ length = strlen(tag) + 1;
+ packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length;
+
+ vec[0].iov_base = &prio;
+ vec[0].iov_len = sizeof(char);
+ vec[1].iov_base = (unsigned char *)tag;
+ vec[1].iov_len = length;
+
+ for (ts.tv_nsec = 0, length = len;
+ length;
+ ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
+ ssize_t ret;
+ size_t transfer;
+
+ if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
+ ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
+ len -= length;
+ break;
+ }
+
+ transfer = length;
+ if (transfer > packet_len) {
+ transfer = strnrchr(buf, packet_len - 1, '\n') - buf;
+ if ((transfer < length) && (buf[transfer] == '\n')) {
+ ++transfer;
+ }
+ }
+
+ vec[2].iov_base = (unsigned char *)buf;
+ vec[2].iov_len = transfer;
+
+ ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
+
+ if (ret <= 0) {
+ free(cp);
+ return ret;
+ }
+ length -= transfer;
+ buf += transfer;
+ }
+ free(cp);
+ return len;
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index af3a3b4..329898f 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -896,7 +896,10 @@
trouble: the fashion of the world is to avoid\n\
cost, and you encounter it\n\
LEONATO\n\
-Never came trouble to my house in the likeness of your grace";
+Never came trouble to my house in the likeness of your grace,\n\
+for trouble being gone, comfort should remain, but\n\
+when you depart from me, sorrow abides and happiness\n\
+takes his leave.";
TEST(liblog, max_payload) {
pid_t pid = getpid();
@@ -1001,8 +1004,10 @@
fflush(stderr);
int printLogLine =
android_log_printLogLine(logformat, fileno(stderr), &entry);
+ // Legacy tag truncation
EXPECT_LE(128, printLogLine);
- EXPECT_GT(LOGGER_ENTRY_MAX_PAYLOAD, printLogLine);
+ // Measured maximum if we try to print part of the tag as message
+ EXPECT_GT(LOGGER_ENTRY_MAX_PAYLOAD * 13 / 8, printLogLine);
}
android_log_format_free(logformat);
}
@@ -2451,3 +2456,56 @@
EXPECT_LE(0, android_log_destroy(&ctx));
ASSERT_TRUE(NULL == ctx);
}
+
+static const char __pmsg_file[] =
+ "/data/william-shakespeare/MuchAdoAboutNothing.txt";
+
+TEST(liblog, __android_log_pmsg_file_write) {
+ EXPECT_LT(0, __android_log_pmsg_file_write(
+ LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
+ __pmsg_file, max_payload_buf, sizeof(max_payload_buf)));
+ fprintf(stderr, "Reboot, ensure file %s matches\n"
+ "with liblog.__android_log_msg_file_read test\n",
+ __pmsg_file);
+}
+
+ssize_t __pmsg_fn(log_id_t logId, char prio, const char *filename,
+ const char *buf, size_t len, void *arg) {
+ EXPECT_TRUE(NULL == arg);
+ EXPECT_EQ(LOG_ID_CRASH, logId);
+ EXPECT_EQ(ANDROID_LOG_VERBOSE, prio);
+ EXPECT_FALSE(NULL == strstr(__pmsg_file, filename));
+ EXPECT_EQ(len, sizeof(max_payload_buf));
+ EXPECT_EQ(0, strcmp(max_payload_buf, buf));
+
+ ++signaled;
+ if ((len != sizeof(max_payload_buf)) ||
+ strcmp(max_payload_buf, buf)) {
+ fprintf(stderr, "comparison fails on content \"%s\"\n", buf);
+ }
+ return !arg ||
+ (LOG_ID_CRASH != logId) ||
+ (ANDROID_LOG_VERBOSE != prio) ||
+ !strstr(__pmsg_file, filename) ||
+ (len != sizeof(max_payload_buf)) ||
+ !!strcmp(max_payload_buf, buf) ? -ENOEXEC : 1;
+}
+
+TEST(liblog, __android_log_pmsg_file_read) {
+ signaled = 0;
+
+ ssize_t ret = __android_log_pmsg_file_read(
+ LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
+ __pmsg_file, __pmsg_fn, NULL);
+
+ if (ret == -ENOENT) {
+ fprintf(stderr,
+ "No pre-boot results of liblog.__android_log_mesg_file_write to "
+ "compare with,\n"
+ "false positive test result.\n");
+ return;
+ }
+
+ EXPECT_LT(0, ret);
+ EXPECT_EQ(1U, signaled);
+}
diff --git a/liblog/uio.c b/liblog/uio.c
index d0184dc..ac0558f 100644
--- a/liblog/uio.c
+++ b/liblog/uio.c
@@ -20,7 +20,7 @@
#include <log/uio.h>
-#include "log_cdefs.h"
+#include "log_portability.h"
LIBLOG_ABI_PUBLIC int readv(int fd, struct iovec *vecs, int count)
{
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 5ab957d..1bc1659 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -37,6 +37,9 @@
#include <processgroup/processgroup.h>
+// Uncomment line below use memory cgroups for keeping track of (forked) PIDs
+// #define USE_MEMCG 1
+
#define MEM_CGROUP_PATH "/dev/memcg/apps"
#define MEM_CGROUP_TASKS "/dev/memcg/apps/tasks"
#define ACCT_CGROUP_PATH "/acct"
@@ -67,6 +70,7 @@
};
static const char* getCgroupRootPath() {
+#ifdef USE_MEMCG
static const char* cgroup_root_path = NULL;
std::call_once(init_path_flag, [&]() {
// Check if mem cgroup is mounted, only then check for write-access to avoid
@@ -75,6 +79,9 @@
ACCT_CGROUP_PATH : MEM_CGROUP_PATH;
});
return cgroup_root_path;
+#else
+ return ACCT_CGROUP_PATH;
+#endif
}
static int convertUidToPath(char *path, size_t size, uid_t uid)
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index 6244761..e6c94ff 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -1,5 +1,6 @@
libandroid.so
libc.so
+libcamera2ndk.so
libdl.so
libEGL.so
libGLESv1_CM.so
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index d499f38..292730a 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -1,5 +1,6 @@
libandroid.so
libc.so
+libcamera2ndk.so
libdl.so
libEGL.so
libGLESv1_CM.so
diff --git a/run-as/package.c b/run-as/package.c
index aea89e5..86824c2 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -182,6 +182,10 @@
if (ret < 0)
return -1;
+ /* /data/user/0 is a known safe symlink */
+ if (strcmp("/data/user/0", path) == 0)
+ return 0;
+
/* must be a real directory, not a symlink */
if (!S_ISDIR(st.st_mode))
goto BAD;