Merge "Revert "Adding e4crypt support""
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 7f9536e..b3661e4 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -55,3 +55,4 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libsysutils_intermediates/import_includes)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/grep $(PRODUCT_OUT)/system/bin/toolbox)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index d37ca36..ad85184f 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -79,18 +79,19 @@
#if !ADB_HOST
void start_device_log(void) {
- adb_mkdir("/data/adb", 0775);
-
struct tm now;
time_t t;
tzset();
time(&t);
localtime_r(&t, &now);
- char path[PATH_MAX];
- strftime(path, sizeof(path), "/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt", &now);
+ char timestamp[PATH_MAX];
+ strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now);
- int fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+ char path[PATH_MAX];
+ snprintf(path, sizeof(path), "/data/adb/adb-%s-%d", timestamp, getpid());
+
+ int fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
if (fd == -1) {
return;
}
@@ -100,10 +101,6 @@
dup2(fd, STDERR_FILENO);
fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
adb_close(fd);
-
- fd = unix_open("/dev/null", O_RDONLY);
- dup2(fd, 0);
- adb_close(fd);
}
#endif
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
index c1e4b13..a03fcf1 100644
--- a/adb/adb_main.cpp
+++ b/adb/adb_main.cpp
@@ -349,9 +349,23 @@
return 0;
}
+#if !ADB_HOST
+void close_stdin() {
+ int fd = unix_open("/dev/null", O_RDONLY);
+ if (fd == -1) {
+ perror("failed to open /dev/null, stdin will remain open");
+ return;
+ }
+ dup2(fd, 0);
+ adb_close(fd);
+}
+#endif
+
int main(int argc, char **argv) {
#if ADB_HOST
adb_sysdeps_init();
+#else
+ close_stdin();
#endif
adb_trace_init();
diff --git a/base/Android.mk b/base/Android.mk
index 17d6ece..7bd317b 100644
--- a/base/Android.mk
+++ b/base/Android.mk
@@ -18,13 +18,17 @@
libbase_src_files := \
file.cpp \
+ logging.cpp \
stringprintf.cpp \
strings.cpp \
libbase_test_src_files := \
file_test.cpp \
+ logging_test.cpp \
stringprintf_test.cpp \
strings_test.cpp \
+ test_main.cpp \
+ test_utils.cpp \
libbase_cppflags := \
-Wall \
@@ -40,6 +44,7 @@
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CPPFLAGS := $(libbase_cppflags)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcutils
LOCAL_MULTILIB := both
include $(BUILD_STATIC_LIBRARY)
@@ -49,6 +54,7 @@
LOCAL_WHOLE_STATIC_LIBRARIES := libbase
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_MULTILIB := both
include $(BUILD_SHARED_LIBRARY)
@@ -60,6 +66,7 @@
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CPPFLAGS := $(libbase_cppflags)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcutils
LOCAL_MULTILIB := both
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -68,6 +75,7 @@
LOCAL_WHOLE_STATIC_LIBRARIES := libbase
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcutils
LOCAL_MULTILIB := both
include $(BUILD_HOST_SHARED_LIBRARY)
@@ -77,6 +85,7 @@
LOCAL_MODULE := libbase_test
LOCAL_CLANG := true
LOCAL_SRC_FILES := $(libbase_test_src_files)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_CPPFLAGS := $(libbase_cppflags)
LOCAL_SHARED_LIBRARIES := libbase
LOCAL_MULTILIB := both
@@ -87,6 +96,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libbase_test
LOCAL_SRC_FILES := $(libbase_test_src_files)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_CPPFLAGS := $(libbase_cppflags)
LOCAL_SHARED_LIBRARIES := libbase
LOCAL_MULTILIB := both
diff --git a/base/CPPLINT.cfg b/base/CPPLINT.cfg
index 5ee068e..a61c08d 100644
--- a/base/CPPLINT.cfg
+++ b/base/CPPLINT.cfg
@@ -1,2 +1,2 @@
set noparent
-filter=-build/header_guard
+filter=-build/header_guard,-build/include,-build/c++11
diff --git a/base/file_test.cpp b/base/file_test.cpp
index 34b8755..fc48b32 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -24,29 +24,7 @@
#include <string>
-class TemporaryFile {
- public:
- TemporaryFile() {
- init("/data/local/tmp");
- if (fd == -1) {
- init("/tmp");
- }
- }
-
- ~TemporaryFile() {
- close(fd);
- unlink(filename);
- }
-
- int fd;
- char filename[1024];
-
- private:
- void init(const char* tmp_dir) {
- snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
- fd = mkstemp(filename);
- }
-};
+#include "test_utils.h"
TEST(file, ReadFileToString_ENOENT) {
std::string s("hello");
diff --git a/base/include/base/logging.h b/base/include/base/logging.h
new file mode 100644
index 0000000..5e115fe
--- /dev/null
+++ b/base/include/base/logging.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2015 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 BASE_LOGGING_H
+#define BASE_LOGGING_H
+
+#include <memory>
+#include <ostream>
+
+#include "base/macros.h"
+
+namespace android {
+namespace base {
+
+enum LogSeverity {
+ VERBOSE,
+ DEBUG,
+ INFO,
+ WARNING,
+ ERROR,
+ FATAL,
+};
+
+// Configure logging based on ANDROID_LOG_TAGS environment variable.
+// We need to parse a string that looks like
+//
+// *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
+//
+// The tag (or '*' for the global level) comes first, followed by a colon and a
+// letter indicating the minimum priority level we're expected to log. This can
+// be used to reveal or conceal logs with specific tags.
+extern void InitLogging(char* argv[]);
+
+// Returns the command line used to invoke the current tool or nullptr if
+// InitLogging hasn't been performed.
+extern const char* GetCmdLine();
+
+// The command used to start the program, such as "/system/bin/dalvikvm". If
+// InitLogging hasn't been performed then just returns "unknown"
+extern const char* ProgramInvocationName();
+
+// A short version of the command used to start the program, such as "dalvikvm".
+// If InitLogging hasn't been performed then just returns "unknown"
+extern const char* ProgramInvocationShortName();
+
+// Logs a message to logcat on Android otherwise to stderr. If the severity is
+// FATAL it also causes an abort. For example:
+//
+// LOG(FATAL) << "We didn't expect to reach here";
+#define LOG(severity) \
+ ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::severity, \
+ -1).stream()
+
+// A variant of LOG that also logs the current errno value. To be used when
+// library calls fail.
+#define PLOG(severity) \
+ ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::severity, \
+ errno).stream()
+
+// Marker that code is yet to be implemented.
+#define UNIMPLEMENTED(level) \
+ LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
+
+// Check whether condition x holds and LOG(FATAL) if not. The value of the
+// expression x is only evaluated once. Extra logging can be appended using <<
+// after. For example:
+//
+// CHECK(false == true) results in a log message of
+// "Check failed: false == true".
+#define CHECK(x) \
+ if (UNLIKELY(!(x))) \
+ ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, \
+ -1).stream() \
+ << "Check failed: " #x << " "
+
+// Helper for CHECK_xx(x,y) macros.
+#define CHECK_OP(LHS, RHS, OP) \
+ for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \
+ UNLIKELY(!(_values.lhs OP _values.rhs)); \
+ /* empty */) \
+ ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, -1) \
+ .stream() \
+ << "Check failed: " << #LHS << " " << #OP << " " << #RHS \
+ << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
+
+// Check whether a condition holds between x and y, LOG(FATAL) if not. The value
+// of the expressions x and y is evaluated once. Extra logging can be appended
+// using << after. For example:
+//
+// CHECK_NE(0 == 1, false) results in
+// "Check failed: false != false (0==1=false, false=false) ".
+#define CHECK_EQ(x, y) CHECK_OP(x, y, == )
+#define CHECK_NE(x, y) CHECK_OP(x, y, != )
+#define CHECK_LE(x, y) CHECK_OP(x, y, <= )
+#define CHECK_LT(x, y) CHECK_OP(x, y, < )
+#define CHECK_GE(x, y) CHECK_OP(x, y, >= )
+#define CHECK_GT(x, y) CHECK_OP(x, y, > )
+
+// Helper for CHECK_STRxx(s1,s2) macros.
+#define CHECK_STROP(s1, s2, sense) \
+ if (UNLIKELY((strcmp(s1, s2) == 0) != sense)) \
+ LOG(FATAL) << "Check failed: " \
+ << "\"" << s1 << "\"" \
+ << (sense ? " == " : " != ") << "\"" << s2 << "\""
+
+// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
+#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
+#define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false)
+
+// Perform the pthread function call(args), LOG(FATAL) on error.
+#define CHECK_PTHREAD_CALL(call, args, what) \
+ do { \
+ int rc = call args; \
+ if (rc != 0) { \
+ errno = rc; \
+ PLOG(FATAL) << #call << " failed for " << what; \
+ } \
+ } while (false)
+
+// CHECK that can be used in a constexpr function. For example:
+//
+// constexpr int half(int n) {
+// return
+// DCHECK_CONSTEXPR(n >= 0, , 0)
+// CHECK_CONSTEXPR((n & 1) == 0),
+// << "Extra debugging output: n = " << n, 0)
+// n / 2;
+// }
+#define CHECK_CONSTEXPR(x, out, dummy) \
+ (UNLIKELY(!(x))) \
+ ? (LOG(FATAL) << "Check failed: " << #x out, dummy) \
+ :
+
+// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally
+// CHECK should be used unless profiling identifies a CHECK as being in
+// performance critical code.
+#if defined(NDEBUG)
+static constexpr bool kEnableDChecks = false;
+#else
+static constexpr bool kEnableDChecks = true;
+#endif
+
+#define DCHECK(x) \
+ if (::android::base::kEnableDChecks) CHECK(x)
+#define DCHECK_EQ(x, y) \
+ if (::android::base::kEnableDChecks) CHECK_EQ(x, y)
+#define DCHECK_NE(x, y) \
+ if (::android::base::kEnableDChecks) CHECK_NE(x, y)
+#define DCHECK_LE(x, y) \
+ if (::android::base::kEnableDChecks) CHECK_LE(x, y)
+#define DCHECK_LT(x, y) \
+ if (::android::base::kEnableDChecks) CHECK_LT(x, y)
+#define DCHECK_GE(x, y) \
+ if (::android::base::kEnableDChecks) CHECK_GE(x, y)
+#define DCHECK_GT(x, y) \
+ if (::android::base::kEnableDChecks) CHECK_GT(x, y)
+#define DCHECK_STREQ(s1, s2) \
+ if (::android::base::kEnableDChecks) CHECK_STREQ(s1, s2)
+#define DCHECK_STRNE(s1, s2) \
+ if (::android::base::kEnableDChecks) CHECK_STRNE(s1, s2)
+#if defined(NDEBUG)
+#define DCHECK_CONSTEXPR(x, out, dummy)
+#else
+#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy)
+#endif
+
+// Temporary class created to evaluate the LHS and RHS, used with
+// MakeEagerEvaluator to infer the types of LHS and RHS.
+template <typename LHS, typename RHS>
+struct EagerEvaluator {
+ EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
+ }
+ LHS lhs;
+ RHS rhs;
+};
+
+// Helper function for CHECK_xx.
+template <typename LHS, typename RHS>
+static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
+ return EagerEvaluator<LHS, RHS>(lhs, rhs);
+}
+
+// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated
+// as strings. To compare strings use CHECK_STREQ and CHECK_STRNE. We rely on
+// signed/unsigned warnings to protect you against combinations not explicitly
+// listed below.
+#define EAGER_PTR_EVALUATOR(T1, T2) \
+ template <> \
+ struct EagerEvaluator<T1, T2> { \
+ EagerEvaluator(T1 l, T2 r) \
+ : lhs(reinterpret_cast<const void*>(l)), \
+ rhs(reinterpret_cast<const void*>(r)) { \
+ } \
+ const void* lhs; \
+ const void* rhs; \
+ }
+EAGER_PTR_EVALUATOR(const char*, const char*);
+EAGER_PTR_EVALUATOR(const char*, char*);
+EAGER_PTR_EVALUATOR(char*, const char*);
+EAGER_PTR_EVALUATOR(char*, char*);
+EAGER_PTR_EVALUATOR(const unsigned char*, const unsigned char*);
+EAGER_PTR_EVALUATOR(const unsigned char*, unsigned char*);
+EAGER_PTR_EVALUATOR(unsigned char*, const unsigned char*);
+EAGER_PTR_EVALUATOR(unsigned char*, unsigned char*);
+EAGER_PTR_EVALUATOR(const signed char*, const signed char*);
+EAGER_PTR_EVALUATOR(const signed char*, signed char*);
+EAGER_PTR_EVALUATOR(signed char*, const signed char*);
+EAGER_PTR_EVALUATOR(signed char*, signed char*);
+
+// Data for the log message, not stored in LogMessage to avoid increasing the
+// stack size.
+class LogMessageData;
+
+// A LogMessage is a temporarily scoped object used by LOG and the unlikely part
+// of a CHECK. The destructor will abort if the severity is FATAL.
+class LogMessage {
+ public:
+ LogMessage(const char* file, unsigned int line, LogSeverity severity,
+ int error);
+
+ ~LogMessage();
+
+ // Returns the stream associated with the message, the LogMessage performs
+ // output when it goes out of scope.
+ std::ostream& stream();
+
+ // The routine that performs the actual logging.
+ static void LogLine(const char* file, unsigned int line, LogSeverity severity,
+ const char* msg);
+
+ // A variant of the above for use with little stack.
+ static void LogLineLowStack(const char* file, unsigned int line,
+ LogSeverity severity, const char* msg);
+
+ private:
+ const std::unique_ptr<LogMessageData> data_;
+
+ DISALLOW_COPY_AND_ASSIGN(LogMessage);
+};
+
+// Allows to temporarily change the minimum severity level for logging.
+class ScopedLogSeverity {
+ public:
+ explicit ScopedLogSeverity(LogSeverity level);
+ ~ScopedLogSeverity();
+
+ private:
+ LogSeverity old_;
+};
+
+} // namespace base
+} // namespace android
+
+#endif // BASE_LOGGING_H
diff --git a/base/include/base/strings.h b/base/include/base/strings.h
index 5ddfbbd..ab56aad 100644
--- a/base/include/base/strings.h
+++ b/base/include/base/strings.h
@@ -23,10 +23,15 @@
namespace android {
namespace base {
-// Splits a string using the given separator character into a vector of strings.
-// Empty strings will be omitted.
-void Split(const std::string& s, char separator,
- std::vector<std::string>* result);
+// Splits a string into a vector of strings.
+//
+// The string is split at each occurence of a character in delimiters.
+//
+// Empty splits will be omitted. I.e. Split("a,,b", ",") -> {"a", "b"}
+//
+// The empty string is not a valid delimiter list.
+std::vector<std::string> Split(const std::string& s,
+ const std::string& delimiters);
// Trims whitespace off both ends of the given string.
std::string Trim(const std::string& s);
diff --git a/base/logging.cpp b/base/logging.cpp
new file mode 100644
index 0000000..8bfb204
--- /dev/null
+++ b/base/logging.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2015 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 "base/logging.h"
+
+#include <iostream>
+#include <limits>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "base/strings.h"
+#include "cutils/threads.h"
+
+// Headers for LogMessage::LogLine.
+#ifdef __ANDROID__
+#include <android/set_abort_message.h>
+#include "cutils/log.h"
+#else
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+namespace android {
+namespace base {
+
+static std::mutex logging_lock;
+
+static LogSeverity gMinimumLogSeverity = INFO;
+static std::unique_ptr<std::string> gCmdLine;
+static std::unique_ptr<std::string> gProgramInvocationName;
+static std::unique_ptr<std::string> gProgramInvocationShortName;
+
+const char* GetCmdLine() {
+ return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr;
+}
+
+const char* ProgramInvocationName() {
+ return (gProgramInvocationName.get() != nullptr)
+ ? gProgramInvocationName->c_str()
+ : "unknown";
+}
+
+const char* ProgramInvocationShortName() {
+ return (gProgramInvocationShortName.get() != nullptr)
+ ? gProgramInvocationShortName->c_str()
+ : "unknown";
+}
+
+void InitLogging(char* argv[]) {
+ if (gCmdLine.get() != nullptr) {
+ return;
+ }
+
+ // Stash the command line for later use. We can use /proc/self/cmdline on
+ // Linux to recover this, but we don't have that luxury on the Mac, and there
+ // are a couple of argv[0] variants that are commonly used.
+ if (argv != nullptr) {
+ gCmdLine.reset(new std::string(argv[0]));
+ for (size_t i = 1; argv[i] != nullptr; ++i) {
+ gCmdLine->append(" ");
+ gCmdLine->append(argv[i]);
+ }
+ gProgramInvocationName.reset(new std::string(argv[0]));
+ const char* last_slash = strrchr(argv[0], '/');
+ gProgramInvocationShortName.reset(
+ new std::string((last_slash != nullptr) ? last_slash + 1 : argv[0]));
+ } else {
+ // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux.
+ gCmdLine.reset(new std::string("<unset>"));
+ }
+ const char* tags = getenv("ANDROID_LOG_TAGS");
+ if (tags == nullptr) {
+ return;
+ }
+
+ std::vector<std::string> specs = Split(tags, " ");
+ for (size_t i = 0; i < specs.size(); ++i) {
+ // "tag-pattern:[vdiwefs]"
+ std::string spec(specs[i]);
+ if (spec.size() == 3 && StartsWith(spec, "*:")) {
+ switch (spec[2]) {
+ case 'v':
+ gMinimumLogSeverity = VERBOSE;
+ continue;
+ case 'd':
+ gMinimumLogSeverity = DEBUG;
+ continue;
+ case 'i':
+ gMinimumLogSeverity = INFO;
+ continue;
+ case 'w':
+ gMinimumLogSeverity = WARNING;
+ continue;
+ case 'e':
+ gMinimumLogSeverity = ERROR;
+ continue;
+ case 'f':
+ gMinimumLogSeverity = FATAL;
+ continue;
+ // liblog will even suppress FATAL if you say 's' for silent, but that's
+ // crazy!
+ case 's':
+ gMinimumLogSeverity = FATAL;
+ continue;
+ }
+ }
+ LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags
+ << ")";
+ }
+}
+
+// This indirection greatly reduces the stack impact of having lots of
+// checks/logging in a function.
+class LogMessageData {
+ public:
+ LogMessageData(const char* file, unsigned int line, LogSeverity severity,
+ int error)
+ : file_(file), line_number_(line), severity_(severity), error_(error) {
+ const char* last_slash = strrchr(file, '/');
+ file = (last_slash == nullptr) ? file : last_slash + 1;
+ }
+
+ const char* GetFile() const {
+ return file_;
+ }
+
+ unsigned int GetLineNumber() const {
+ return line_number_;
+ }
+
+ LogSeverity GetSeverity() const {
+ return severity_;
+ }
+
+ int GetError() const {
+ return error_;
+ }
+
+ std::ostream& GetBuffer() {
+ return buffer_;
+ }
+
+ std::string ToString() const {
+ return buffer_.str();
+ }
+
+ private:
+ std::ostringstream buffer_;
+ const char* const file_;
+ const unsigned int line_number_;
+ const LogSeverity severity_;
+ const int error_;
+
+ DISALLOW_COPY_AND_ASSIGN(LogMessageData);
+};
+
+LogMessage::LogMessage(const char* file, unsigned int line,
+ LogSeverity severity, int error)
+ : data_(new LogMessageData(file, line, severity, error)) {
+}
+
+LogMessage::~LogMessage() {
+ if (data_->GetSeverity() < gMinimumLogSeverity) {
+ return; // No need to format something we're not going to output.
+ }
+
+ // Finish constructing the message.
+ if (data_->GetError() != -1) {
+ data_->GetBuffer() << ": " << strerror(data_->GetError());
+ }
+ std::string msg(data_->ToString());
+
+ // Do the actual logging with the lock held.
+ {
+ std::lock_guard<std::mutex> lock(logging_lock);
+ if (msg.find('\n') == std::string::npos) {
+ LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(),
+ msg.c_str());
+ } else {
+ msg += '\n';
+ size_t i = 0;
+ while (i < msg.size()) {
+ size_t nl = msg.find('\n', i);
+ msg[nl] = '\0';
+ LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(),
+ &msg[i]);
+ i = nl + 1;
+ }
+ }
+ }
+
+ // Abort if necessary.
+ if (data_->GetSeverity() == FATAL) {
+#ifdef __ANDROID__
+ android_set_abort_message(msg.c_str());
+#endif
+ abort();
+ }
+}
+
+std::ostream& LogMessage::stream() {
+ return data_->GetBuffer();
+}
+
+#ifdef __ANDROID__
+static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
+ ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
+ ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL};
+static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
+ "Mismatch in size of kLogSeverityToAndroidLogPriority and values "
+ "in LogSeverity");
+#endif
+
+void LogMessage::LogLine(const char* file, unsigned int line,
+ LogSeverity log_severity, const char* message) {
+#ifdef __ANDROID__
+ const char* tag = ProgramInvocationShortName();
+ int priority = kLogSeverityToAndroidLogPriority[log_severity];
+ if (priority == ANDROID_LOG_FATAL) {
+ LOG_PRI(priority, tag, "%s:%u] %s", file, line, message);
+ } else {
+ LOG_PRI(priority, tag, "%s", message);
+ }
+#else
+ static const char* log_characters = "VDIWEF";
+ CHECK_EQ(strlen(log_characters), FATAL + 1U);
+ char severity = log_characters[log_severity];
+ fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationShortName(),
+ severity, getpid(), gettid(), file, line, message);
+#endif
+}
+
+void LogMessage::LogLineLowStack(const char* file, unsigned int line,
+ LogSeverity log_severity, const char* message) {
+#ifdef __ANDROID__
+ // Use android_writeLog() to avoid stack-based buffers used by
+ // android_printLog().
+ const char* tag = ProgramInvocationShortName();
+ int priority = kLogSeverityToAndroidLogPriority[log_severity];
+ char* buf = nullptr;
+ size_t buf_size = 0u;
+ if (priority == ANDROID_LOG_FATAL) {
+ // Allocate buffer for snprintf(buf, buf_size, "%s:%u] %s", file, line,
+ // message) below. If allocation fails, fall back to printing only the
+ // message.
+ buf_size = strlen(file) + 1 /* ':' */ +
+ std::numeric_limits<typeof(line)>::max_digits10 + 2 /* "] " */ +
+ strlen(message) + 1 /* terminating 0 */;
+ buf = reinterpret_cast<char*>(malloc(buf_size));
+ }
+ if (buf != nullptr) {
+ snprintf(buf, buf_size, "%s:%u] %s", file, line, message);
+ android_writeLog(priority, tag, buf);
+ free(buf);
+ } else {
+ android_writeLog(priority, tag, message);
+ }
+#else
+ static const char* log_characters = "VDIWEF";
+ CHECK_EQ(strlen(log_characters), FATAL + 1U);
+
+ const char* program_name = ProgramInvocationShortName();
+ write(STDERR_FILENO, program_name, strlen(program_name));
+ write(STDERR_FILENO, " ", 1);
+ write(STDERR_FILENO, &log_characters[log_severity], 1);
+ write(STDERR_FILENO, " ", 1);
+ // TODO: pid and tid.
+ write(STDERR_FILENO, file, strlen(file));
+ // TODO: line.
+ UNUSED(line);
+ write(STDERR_FILENO, "] ", 2);
+ write(STDERR_FILENO, message, strlen(message));
+ write(STDERR_FILENO, "\n", 1);
+#endif
+}
+
+ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
+ old_ = gMinimumLogSeverity;
+ gMinimumLogSeverity = level;
+}
+
+ScopedLogSeverity::~ScopedLogSeverity() {
+ gMinimumLogSeverity = old_;
+}
+
+} // namespace base
+} // namespace android
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
new file mode 100644
index 0000000..0a03e38
--- /dev/null
+++ b/base/logging_test.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2015 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 "base/logging.h"
+
+#include <regex>
+#include <string>
+
+#include "base/file.h"
+#include "base/stringprintf.h"
+#include "test_utils.h"
+
+#include <gtest/gtest.h>
+
+#ifdef __ANDROID__
+#define HOST_TEST(suite, name) TEST(suite, DISABLED_ ## name)
+#else
+#define HOST_TEST(suite, name) TEST(suite, name)
+#endif
+
+class CapturedStderr {
+ public:
+ CapturedStderr() : old_stderr_(-1) {
+ init();
+ }
+
+ ~CapturedStderr() {
+ reset();
+ }
+
+ int fd() const {
+ return temp_file_.fd;
+ }
+
+ private:
+ void init() {
+ old_stderr_ = dup(STDERR_FILENO);
+ ASSERT_NE(-1, old_stderr_);
+ ASSERT_NE(-1, dup2(fd(), STDERR_FILENO));
+ }
+
+ void reset() {
+ ASSERT_NE(-1, dup2(old_stderr_, STDERR_FILENO));
+ ASSERT_EQ(0, close(old_stderr_));
+ }
+
+ TemporaryFile temp_file_;
+ int old_stderr_;
+};
+
+HOST_TEST(logging, CHECK) {
+ ASSERT_DEATH(CHECK(false), "Check failed: false ");
+ CHECK(true);
+
+ ASSERT_DEATH(CHECK_EQ(0, 1), "Check failed: 0 == 1 ");
+ CHECK_EQ(0, 0);
+
+ ASSERT_DEATH(CHECK_STREQ("foo", "bar"), R"(Check failed: "foo" == "bar")");
+ CHECK_STREQ("foo", "foo");
+}
+
+std::string make_log_pattern(android::base::LogSeverity severity,
+ const char* message) {
+ static const char* log_characters = "VDIWEF";
+ char log_char = log_characters[severity];
+ return android::base::StringPrintf(
+ "%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ " __FILE__
+ ":[[:digit:]]+] %s",
+ log_char, message);
+}
+
+HOST_TEST(logging, LOG) {
+ ASSERT_DEATH(LOG(FATAL) << "foobar", "foobar");
+
+ {
+ CapturedStderr cap;
+ LOG(WARNING) << "foobar";
+ ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+ std::string output;
+ android::base::ReadFdToString(cap.fd(), &output);
+
+ std::regex message_regex(
+ make_log_pattern(android::base::WARNING, "foobar"));
+ ASSERT_TRUE(std::regex_search(output, message_regex));
+ }
+
+ {
+ CapturedStderr cap;
+ LOG(INFO) << "foobar";
+ ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+ std::string output;
+ android::base::ReadFdToString(cap.fd(), &output);
+
+ std::regex message_regex(
+ make_log_pattern(android::base::INFO, "foobar"));
+ ASSERT_TRUE(std::regex_search(output, message_regex));
+ }
+
+ {
+ CapturedStderr cap;
+ LOG(DEBUG) << "foobar";
+ ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+ std::string output;
+ android::base::ReadFdToString(cap.fd(), &output);
+ ASSERT_TRUE(output.empty());
+ }
+
+ {
+ android::base::ScopedLogSeverity severity(android::base::DEBUG);
+ CapturedStderr cap;
+ LOG(DEBUG) << "foobar";
+ ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+ std::string output;
+ android::base::ReadFdToString(cap.fd(), &output);
+
+ std::regex message_regex(
+ make_log_pattern(android::base::DEBUG, "foobar"));
+ ASSERT_TRUE(std::regex_search(output, message_regex));
+ }
+}
+
+HOST_TEST(logging, PLOG) {
+ {
+ CapturedStderr cap;
+ errno = ENOENT;
+ PLOG(INFO) << "foobar";
+ ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+ std::string output;
+ android::base::ReadFdToString(cap.fd(), &output);
+
+ std::regex message_regex(make_log_pattern(
+ android::base::INFO, "foobar: No such file or directory"));
+ ASSERT_TRUE(std::regex_search(output, message_regex));
+ }
+}
+
+HOST_TEST(logging, UNIMPLEMENTED) {
+ {
+ CapturedStderr cap;
+ errno = ENOENT;
+ UNIMPLEMENTED(ERROR);
+ ASSERT_EQ(0, lseek(cap.fd(), SEEK_SET, 0));
+
+ std::string output;
+ android::base::ReadFdToString(cap.fd(), &output);
+
+ std::string expected_message =
+ android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__);
+ std::regex message_regex(
+ make_log_pattern(android::base::ERROR, expected_message.c_str()));
+ ASSERT_TRUE(std::regex_search(output, message_regex));
+ }
+}
diff --git a/base/strings.cpp b/base/strings.cpp
index 224a46f..5f7eccc 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -16,27 +16,39 @@
#include "base/strings.h"
+#include <stdlib.h>
+
#include <string>
#include <vector>
namespace android {
namespace base {
-void Split(const std::string& s, char separator,
- std::vector<std::string>* result) {
- const char* p = s.data();
- const char* end = p + s.size();
- while (p != end) {
- if (*p == separator) {
- ++p;
- } else {
- const char* start = p;
- while (++p != end && *p != separator) {
- // Skip to the next occurrence of the separator.
- }
- result->push_back(std::string(start, p - start));
- }
+#define CHECK_NE(a, b) \
+ if ((a) == (b)) abort();
+
+std::vector<std::string> Split(const std::string& s,
+ const std::string& delimiters) {
+ CHECK_NE(delimiters.size(), 0U);
+
+ std::vector<std::string> split;
+ if (s.size() == 0) {
+ // Split("", d) returns {} rather than {""}.
+ return split;
}
+
+ size_t base = 0;
+ size_t found;
+ do {
+ found = s.find_first_of(delimiters, base);
+ if (found != base) {
+ split.push_back(s.substr(base, found - base));
+ }
+
+ base = found + 1;
+ } while (found != s.npos);
+
+ return split;
}
std::string Trim(const std::string& s) {
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 824598d..1bf07a1 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -22,21 +22,18 @@
#include <vector>
TEST(strings, split_empty) {
- std::vector<std::string> parts;
- android::base::Split("", '\0', &parts);
+ std::vector<std::string> parts = android::base::Split("", ",");
ASSERT_EQ(0U, parts.size());
}
TEST(strings, split_single) {
- std::vector<std::string> parts;
- android::base::Split("foo", ',', &parts);
+ std::vector<std::string> parts = android::base::Split("foo", ",");
ASSERT_EQ(1U, parts.size());
ASSERT_EQ("foo", parts[0]);
}
TEST(strings, split_simple) {
- std::vector<std::string> parts;
- android::base::Split("foo,bar,baz", ',', &parts);
+ std::vector<std::string> parts = android::base::Split("foo,bar,baz", ",");
ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("bar", parts[1]);
@@ -44,8 +41,30 @@
}
TEST(strings, split_with_empty_part) {
- std::vector<std::string> parts;
- android::base::Split("foo,,bar", ',', &parts);
+ std::vector<std::string> parts = android::base::Split("foo,,bar", ",");
+ ASSERT_EQ(2U, parts.size());
+ ASSERT_EQ("foo", parts[0]);
+ ASSERT_EQ("bar", parts[1]);
+}
+
+TEST(strings, split_null_char) {
+ std::vector<std::string> parts =
+ android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1));
+ ASSERT_EQ(2U, parts.size());
+ ASSERT_EQ("foo", parts[0]);
+ ASSERT_EQ("bar", parts[1]);
+}
+
+TEST(strings, split_any) {
+ std::vector<std::string> parts = android::base::Split("foo:bar,baz", ",:");
+ ASSERT_EQ(3U, parts.size());
+ ASSERT_EQ("foo", parts[0]);
+ ASSERT_EQ("bar", parts[1]);
+ ASSERT_EQ("baz", parts[2]);
+}
+
+TEST(strings, split_any_with_empty_part) {
+ std::vector<std::string> parts = android::base::Split("foo:,bar", ",:");
ASSERT_EQ(2U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("bar", parts[1]);
diff --git a/base/test_main.cpp b/base/test_main.cpp
new file mode 100644
index 0000000..c49ca4b
--- /dev/null
+++ b/base/test_main.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 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 <gtest/gtest.h>
+
+#include "base/logging.h"
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ android::base::InitLogging(argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
new file mode 100644
index 0000000..1f6d3cf
--- /dev/null
+++ b/base/test_utils.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 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 "test_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+TemporaryFile::TemporaryFile() {
+ init("/data/local/tmp");
+ if (fd == -1) {
+ init("/tmp");
+ }
+}
+
+TemporaryFile::~TemporaryFile() {
+ close(fd);
+ unlink(filename);
+}
+
+void TemporaryFile::init(const char* tmp_dir) {
+ snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
+ fd = mkstemp(filename);
+}
diff --git a/base/test_utils.h b/base/test_utils.h
new file mode 100644
index 0000000..132d3a7
--- /dev/null
+++ b/base/test_utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 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 TEST_UTILS_H
+#define TEST_UTILS_H
+
+class TemporaryFile {
+ public:
+ TemporaryFile();
+ ~TemporaryFile();
+
+ int fd;
+ char filename[1024];
+
+ private:
+ void init(const char* tmp_dir);
+};
+
+#endif // TEST_UTILS_H
diff --git a/include/cutils/threads.h b/include/cutils/threads.h
index ade9a0c..3133cdb 100644
--- a/include/cutils/threads.h
+++ b/include/cutils/threads.h
@@ -32,14 +32,16 @@
#if !defined(_WIN32)
#include <pthread.h>
+#include <sys/types.h>
typedef struct {
pthread_mutex_t lock;
int has_tls;
pthread_key_t tls;
-
} thread_store_t;
+extern pid_t gettid();
+
#define THREAD_STORE_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0 }
#else // !defined(_WIN32)
@@ -51,7 +53,6 @@
int has_tls;
DWORD tls;
CRITICAL_SECTION lock;
-
} thread_store_t;
#define THREAD_STORE_INITIALIZER { 0, 0, 0, {0, 0, 0, 0, 0, 0} }
diff --git a/include/system/audio.h b/include/system/audio.h
index 17bf260..04252e7 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -872,7 +872,7 @@
typedef int audio_port_handle_t;
#define AUDIO_PORT_HANDLE_NONE 0
-/* the maximum length for the human-readable device name. i.e. "Alesis iO4"*/
+/* the maximum length for the human-readable device name */
#define AUDIO_PORT_MAX_NAME_LEN 128
/* maximum audio device address length */
diff --git a/include/zipfile/zipfile.h b/include/zipfile/zipfile.h
deleted file mode 100644
index 0ae4ee4..0000000
--- a/include/zipfile/zipfile.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2008 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 _ZIPFILE_ZIPFILE_H
-#define _ZIPFILE_ZIPFILE_H
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void* zipfile_t;
-typedef void* zipentry_t;
-
-// Provide a buffer. Returns NULL on failure.
-zipfile_t init_zipfile(const void* data, size_t size);
-
-// Release the zipfile resources.
-void release_zipfile(zipfile_t file);
-
-// Get a named entry object. Returns NULL if it doesn't exist
-// or if we won't be able to decompress it. The zipentry_t is
-// freed by release_zipfile()
-zipentry_t lookup_zipentry(zipfile_t file, const char* entryName);
-
-// Return the size of the entry.
-size_t get_zipentry_size(zipentry_t entry);
-
-// return the filename of this entry, you own the memory returned
-char* get_zipentry_name(zipentry_t entry);
-
-// The buffer must be 1.001 times the buffer size returned
-// by get_zipentry_size. Returns nonzero on failure.
-int decompress_zipentry(zipentry_t entry, void* buf, int bufsize);
-
-// iterate through the entries in the zip file. pass a pointer to
-// a void* initialized to NULL to start. Returns NULL when done
-zipentry_t iterate_zipfile(zipfile_t file, void** cookie);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // _ZIPFILE_ZIPFILE_H
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 530eba8..03c8b30 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -30,6 +30,7 @@
#include <time.h>
#include <unistd.h>
+#include <memory>
#include <string>
#include <base/file.h>
@@ -114,9 +115,9 @@
static void do_log_procs(FILE* log) {
do_log_uptime(log);
- DIR* dir = opendir("/proc");
+ std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir("/proc"), closedir);
struct dirent* entry;
- while ((entry = readdir(dir)) != NULL) {
+ while ((entry = readdir(dir.get())) != NULL) {
// Only match numeric values.
char* end;
int pid = strtol(entry->d_name, &end, 10);
@@ -146,7 +147,6 @@
}
}
}
- closedir(dir);
fputc('\n', log);
}
diff --git a/init/builtins.cpp b/init/builtins.cpp
index e659cfa..6daea37 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -475,7 +475,7 @@
int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
if (wp_ret < 0) {
/* Unexpected error code. We will continue anyway. */
- NOTICE("waitpid failed rc=%d, errno=%d\n", wp_ret, errno);
+ NOTICE("waitpid failed rc=%d: %s\n", wp_ret, strerror(errno));
}
if (WIFEXITED(status)) {
diff --git a/init/devices.cpp b/init/devices.cpp
index 3a9b753..9bce39a 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -49,9 +49,9 @@
#include "log.h"
#define SYSFS_PREFIX "/sys"
-#define FIRMWARE_DIR1 "/etc/firmware"
-#define FIRMWARE_DIR2 "/vendor/firmware"
-#define FIRMWARE_DIR3 "/firmware/image"
+static const char *firmware_dirs[] = { "/etc/firmware",
+ "/vendor/firmware",
+ "/firmware/image" };
extern struct selabel_handle *sehandle;
@@ -818,8 +818,9 @@
static void process_firmware_event(struct uevent *uevent)
{
- char *root, *loading, *data, *file1 = NULL, *file2 = NULL, *file3 = NULL;
+ char *root, *loading, *data;
int l, loading_fd, data_fd, fw_fd;
+ size_t i;
int booting = is_booting();
INFO("firmware: loading '%s' for '%s'\n",
@@ -837,62 +838,49 @@
if (l == -1)
goto loading_free_out;
- l = asprintf(&file1, FIRMWARE_DIR1"/%s", uevent->firmware);
- if (l == -1)
- goto data_free_out;
-
- l = asprintf(&file2, FIRMWARE_DIR2"/%s", uevent->firmware);
- if (l == -1)
- goto data_free_out;
-
- l = asprintf(&file3, FIRMWARE_DIR3"/%s", uevent->firmware);
- if (l == -1)
- goto data_free_out;
-
loading_fd = open(loading, O_WRONLY|O_CLOEXEC);
if(loading_fd < 0)
- goto file_free_out;
+ goto data_free_out;
data_fd = open(data, O_WRONLY|O_CLOEXEC);
if(data_fd < 0)
goto loading_close_out;
try_loading_again:
- fw_fd = open(file1, O_RDONLY|O_CLOEXEC);
- if(fw_fd < 0) {
- fw_fd = open(file2, O_RDONLY|O_CLOEXEC);
- if (fw_fd < 0) {
- fw_fd = open(file3, O_RDONLY|O_CLOEXEC);
- if (fw_fd < 0) {
- if (booting) {
- /* If we're not fully booted, we may be missing
- * filesystems needed for firmware, wait and retry.
- */
- usleep(100000);
- booting = is_booting();
- goto try_loading_again;
- }
- INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
- write(loading_fd, "-1", 2);
- goto data_close_out;
- }
+ for (i = 0; i < ARRAY_SIZE(firmware_dirs); i++) {
+ char *file = NULL;
+ l = asprintf(&file, "%s/%s", firmware_dirs[i], uevent->firmware);
+ if (l == -1)
+ goto data_free_out;
+ fw_fd = open(file, O_RDONLY|O_CLOEXEC);
+ free(file);
+ if (fw_fd >= 0) {
+ if(!load_firmware(fw_fd, loading_fd, data_fd))
+ INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
+ else
+ INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
+ break;
}
}
-
- if(!load_firmware(fw_fd, loading_fd, data_fd))
- INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
- else
- INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
+ if (fw_fd < 0) {
+ if (booting) {
+ /* If we're not fully booted, we may be missing
+ * filesystems needed for firmware, wait and retry.
+ */
+ usleep(100000);
+ booting = is_booting();
+ goto try_loading_again;
+ }
+ INFO("firmware: could not open '%s': %s\n", uevent->firmware, strerror(errno));
+ write(loading_fd, "-1", 2);
+ goto data_close_out;
+ }
close(fw_fd);
data_close_out:
close(data_fd);
loading_close_out:
close(loading_fd);
-file_free_out:
- free(file1);
- free(file2);
- free(file3);
data_free_out:
free(data);
loading_free_out:
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 7db203f..57eb299 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -118,6 +118,7 @@
switch (*s++) {
case 'b':
if (!strcmp(s, "ootchart_init")) return K_bootchart_init;
+ break;
case 'c':
if (!strcmp(s, "opy")) return K_copy;
if (!strcmp(s, "apability")) return K_capability;
diff --git a/init/keychords.cpp b/init/keychords.cpp
index d6464bd..2e996ea 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -80,7 +80,7 @@
ret = write(fd, keychords, keychords_length);
if (ret != keychords_length) {
- ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
+ ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
close(fd);
fd = -1;
}
diff --git a/init/keywords.h b/init/keywords.h
index 532d7c5..09f645b 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -89,8 +89,8 @@
KEYWORD(symlink, COMMAND, 1, do_symlink)
KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
KEYWORD(user, OPTION, 0, 0)
- KEYWORD(verity_load_state, COMMAND, 1, do_verity_load_state)
- KEYWORD(verity_update_state, COMMAND, 1, do_verity_update_state)
+ KEYWORD(verity_load_state, COMMAND, 0, do_verity_load_state)
+ KEYWORD(verity_update_state, COMMAND, 0, do_verity_update_state)
KEYWORD(wait, COMMAND, 1, do_wait)
KEYWORD(write, COMMAND, 2, do_write)
KEYWORD(copy, COMMAND, 2, do_copy)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 13d671f..363b377 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -26,6 +26,8 @@
#include <errno.h>
#include <sys/poll.h>
+#include <memory>
+
#include <cutils/misc.h>
#include <cutils/sockets.h>
#include <cutils/multiuser.h>
@@ -159,7 +161,7 @@
snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
fd = mkstemp(tempPath);
if (fd < 0) {
- ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno);
+ ERROR("Unable to write persistent property to temp file %s: %s\n", tempPath, strerror(errno));
return;
}
write(fd, value, strlen(value));
@@ -248,7 +250,7 @@
int property_set(const char* name, const char* value) {
int rc = property_set_impl(name, value);
if (rc == -1) {
- ERROR("property_set(\"%s\", \"%s\" failed\n", name, value);
+ ERROR("property_set(\"%s\", \"%s\") failed\n", name, value);
}
return rc;
}
@@ -287,15 +289,15 @@
close(s);
return;
} else if (nr < 0) {
- ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno));
+ ERROR("sys_prop: error waiting for uid=%d to send property message: %s\n", cr.uid, strerror(errno));
close(s);
return;
}
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
if(r != sizeof(prop_msg)) {
- ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n",
- r, sizeof(prop_msg), errno);
+ ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n",
+ r, sizeof(prop_msg), strerror(errno));
close(s);
return;
}
@@ -425,64 +427,62 @@
}
}
-static void load_persistent_properties()
-{
- DIR* dir = opendir(PERSISTENT_PROPERTY_DIR);
- int dir_fd;
- struct dirent* entry;
- char value[PROP_VALUE_MAX];
- int fd, length;
- struct stat sb;
+static void load_persistent_properties() {
+ persistent_properties_loaded = 1;
- if (dir) {
- dir_fd = dirfd(dir);
- while ((entry = readdir(dir)) != NULL) {
- if (strncmp("persist.", entry->d_name, strlen("persist.")))
- continue;
- if (entry->d_type != DT_REG)
- continue;
- /* open the file and read the property value */
- fd = openat(dir_fd, entry->d_name, O_RDONLY | O_NOFOLLOW);
- if (fd < 0) {
- ERROR("Unable to open persistent property file \"%s\" errno: %d\n",
- entry->d_name, errno);
- continue;
- }
- if (fstat(fd, &sb) < 0) {
- ERROR("fstat on property file \"%s\" failed errno: %d\n", entry->d_name, errno);
- close(fd);
- continue;
- }
-
- // File must not be accessible to others, be owned by root/root, and
- // not be a hard link to any other file.
- if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0)
- || (sb.st_uid != 0)
- || (sb.st_gid != 0)
- || (sb.st_nlink != 1)) {
- ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%u mode=%o)\n",
- entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
- (unsigned int)sb.st_nlink, sb.st_mode);
- close(fd);
- continue;
- }
-
- length = read(fd, value, sizeof(value) - 1);
- if (length >= 0) {
- value[length] = 0;
- property_set(entry->d_name, value);
- } else {
- ERROR("Unable to read persistent property file %s errno: %d\n",
- entry->d_name, errno);
- }
- close(fd);
- }
- closedir(dir);
- } else {
- ERROR("Unable to open persistent property directory %s errno: %d\n", PERSISTENT_PROPERTY_DIR, errno);
+ std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir);
+ if (!dir) {
+ ERROR("Unable to open persistent property directory \"%s\": %s\n",
+ PERSISTENT_PROPERTY_DIR, strerror(errno));
+ return;
}
- persistent_properties_loaded = 1;
+ struct dirent* entry;
+ while ((entry = readdir(dir.get())) != NULL) {
+ if (strncmp("persist.", entry->d_name, strlen("persist."))) {
+ continue;
+ }
+ if (entry->d_type != DT_REG) {
+ continue;
+ }
+
+ // Open the file and read the property value.
+ int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW);
+ if (fd == -1) {
+ ERROR("Unable to open persistent property file \"%s\": %s\n",
+ entry->d_name, strerror(errno));
+ continue;
+ }
+
+ struct stat sb;
+ if (fstat(fd, &sb) == -1) {
+ ERROR("fstat on property file \"%s\" failed: %s\n", entry->d_name, strerror(errno));
+ close(fd);
+ continue;
+ }
+
+ // File must not be accessible to others, be owned by root/root, and
+ // not be a hard link to any other file.
+ if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || (sb.st_uid != 0) || (sb.st_gid != 0) ||
+ (sb.st_nlink != 1)) {
+ ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%u mode=%o)\n",
+ entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
+ (unsigned int)sb.st_nlink, sb.st_mode);
+ close(fd);
+ continue;
+ }
+
+ char value[PROP_VALUE_MAX];
+ int length = read(fd, value, sizeof(value) - 1);
+ if (length >= 0) {
+ value[length] = 0;
+ property_set(entry->d_name, value);
+ } else {
+ ERROR("Unable to read persistent property file %s: %s\n",
+ entry->d_name, strerror(errno));
+ }
+ close(fd);
+ }
}
void property_init(void)
diff --git a/init/readme.txt b/init/readme.txt
index 7443330..4c8d0d3 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -137,32 +137,9 @@
Commands
--------
-exec [ <seclabel> [ <user> [ <group> ]* ] ] -- <command> [ <argument> ]*
- Fork and execute command with the given arguments. The command starts
- after "--" so that an optional security context, user, and supplementary
- groups can be provided. No other commands will be run until this one
- finishes.
-
-execonce <path> [ <argument> ]*
- Fork and execute a program (<path>). This will block until
- the program completes execution. This command can be run at most
- once during init's lifetime. Subsequent invocations are ignored.
- It is best to avoid execonce as unlike the builtin commands, it runs
- the risk of getting init "stuck".
-
-export <name> <value>
- Set the environment variable <name> equal to <value> in the
- global environment (which will be inherited by all processes
- started after this command is executed)
-
-ifup <interface>
- Bring the network interface <interface> online.
-
-import <filename>
- Parse an init config file, extending the current configuration.
-
-hostname <name>
- Set the host name.
+bootchart_init
+ Start bootcharting if configured (see below).
+ This is included in the default init.rc.
chmod <octal-mode> <path>
Change file access permissions.
@@ -175,9 +152,18 @@
not already running.
class_stop <serviceclass>
- Stop all services of the specified class if they are
+ Stop and disable all services of the specified class if they are
currently running.
+class_reset <serviceclass>
+ Stop all services of the specified class if they are
+ currently running, without disabling them. They can be restarted
+ later using class_start.
+
+copy <src> <dst>
+ Copies a file. Similar to write, but useful for binary/large
+ amounts of data.
+
domainname <name>
Set the domain name.
@@ -190,9 +176,41 @@
on property:ro.boot.myfancyhardware=1
enable my_fancy_service_for_my_fancy_hardware
+exec [ <seclabel> [ <user> [ <group> ]* ] ] -- <command> [ <argument> ]*
+ Fork and execute command with the given arguments. The command starts
+ after "--" so that an optional security context, user, and supplementary
+ groups can be provided. No other commands will be run until this one
+ finishes.
+
+execonce <path> [ <argument> ]*
+ Use exec instead. This command will be removed after existing callers have
+ moved to exec.
+
+export <name> <value>
+ Set the environment variable <name> equal to <value> in the
+ global environment (which will be inherited by all processes
+ started after this command is executed)
+
+hostname <name>
+ Set the host name.
+
+ifup <interface>
+ Bring the network interface <interface> online.
+
+import <filename>
+ Parse an init config file, extending the current configuration.
+
insmod <path>
Install the module at <path>
+load_all_props
+ Loads properties from /system, /vendor, et cetera.
+ This is included in the default init.rc.
+
+load_persist_props
+ Loads persistent properties when /data has been decrypted.
+ This is included in the default init.rc.
+
loglevel <level>
Sets the kernel log level to level. Properties are expanded within <level>.
@@ -202,6 +220,9 @@
owned by the root user and root group. If provided, the mode, owner and group
will be updated if the directory exists already.
+mount_all <fstab>
+ Calls fs_mgr_mount_all on the given fs_mgr-format fstab.
+
mount <type> <device> <dir> [ <flag> ]* [<options>]
Attempt to mount the named device at the directory <dir>
<device> may be of the form mtd@name to specify a mtd block
@@ -210,6 +231,13 @@
<options> include "barrier=1", "noauto_da_alloc", "discard", ... as
a comma separated string, eg: barrier=1,noauto_da_alloc
+powerctl
+ Internal implementation detail used to respond to changes to the
+ "sys.powerctl" system property, used to implement rebooting.
+
+restart <service>
+ Like stop, but doesn't disable the service.
+
restorecon <path> [ <path> ]*
Restore the file named by <path> to the security context specified
in the file_contexts configuration.
@@ -220,6 +248,14 @@
Recursively restore the directory tree named by <path> to the
security contexts specified in the file_contexts configuration.
+rm <path>
+ Calls unlink(2) on the given path. You might want to
+ use "exec -- rm ..." instead (provided the system partition is
+ already mounted).
+
+rmdir <path>
+ Calls rmdir(2) on the given path.
+
setcon <seclabel>
Set the current process security context to the specified string.
This is typically only used from early-init to set the init context
@@ -238,6 +274,9 @@
stop <service>
Stop a service from running if it is currently running.
+swapon_all <fstab>
+ Calls fs_mgr_swapon_all on the given fstab file.
+
symlink <target> <path>
Create a symbolic link at <path> with the value <target>
@@ -248,10 +287,18 @@
Trigger an event. Used to queue an action from another
action.
+verity_load_state
+ Internal implementation detail used to load dm-verity state.
+
+verity_update_state <mount_point>
+ Internal implementation detail used to update dm-verity state and
+ set the partition.<mount_point>.verified properties used by adb remount
+ because fs_mgr can't set them directly itself.
+
wait <path> [ <timeout> ]
- Poll for the existence of the given file and return when found,
- or the timeout has been reached. If timeout is not specified it
- currently defaults to five seconds.
+ Poll for the existence of the given file and return when found,
+ or the timeout has been reached. If timeout is not specified it
+ currently defaults to five seconds.
write <path> <content>
Open the file at <path> and write a string to it with write(2).
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 2c5e351..d890319 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -64,7 +64,7 @@
endif
-# Static library for host
+# Shared and static library for host
# ========================================================
LOCAL_MODULE := libcutils
LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
@@ -76,6 +76,16 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_STATIC_LIBRARY)
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils
+LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
+LOCAL_SHARED_LIBRARIES := liblog
+ifneq ($(HOST_OS),windows)
+LOCAL_CFLAGS += -Werror
+endif
+LOCAL_MULTILIB := both
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_HOST_SHARED_LIBRARY)
# Tests for host
# ========================================================
diff --git a/libcutils/threads.c b/libcutils/threads.c
index ca600b3..5f5577b 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -14,9 +14,25 @@
** limitations under the License.
*/
-#include <cutils/threads.h>
+#include "cutils/threads.h"
#if !defined(_WIN32)
+
+// For gettid.
+#if defined(__APPLE__)
+#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <unistd.h>
+#elif defined(__linux__) && !defined(__ANDROID__)
+#include <syscall.h>
+#include <unistd.h>
+#elif defined(_WIN32)
+#include <Windows.h>
+#endif
+
void* thread_store_get( thread_store_t* store )
{
if (!store->has_tls)
@@ -42,6 +58,24 @@
pthread_setspecific( store->tls, value );
}
+// No definition needed for Android because we'll just pick up bionic's copy.
+#ifndef __ANDROID__
+pid_t gettid() {
+#if defined(__APPLE__)
+ uint64_t owner;
+ int rc = pthread_threadid_np(NULL, &owner);
+ if (rc != 0) {
+ abort();
+ }
+ return owner;
+#elif defined(__linux__)
+ return syscall(__NR_gettid);
+#elif defined(_WIN32)
+ return (pid_t)GetCurrentThreadId();
+#endif
+}
+#endif // __ANDROID__
+
#else /* !defined(_WIN32) */
void* thread_store_get( thread_store_t* store )
{
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 8f8cc3f..dfe34d1 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -90,15 +90,6 @@
return (g_log_status == kLogAvailable);
}
-#if !FAKE_LOG_DEVICE
-/* give up, resources too limited */
-static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused,
- size_t nr __unused)
-{
- return -1;
-}
-#endif
-
/* log_init_lock assumed */
static int __write_to_log_initialize()
{
@@ -111,40 +102,32 @@
log_fds[i] = fakeLogOpen(buf, O_WRONLY);
}
#else
- if (logd_fd >= 0) {
- i = logd_fd;
- logd_fd = -1;
- close(i);
+ if (pstore_fd < 0) {
+ pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
}
- if (pstore_fd >= 0) {
- i = pstore_fd;
- pstore_fd = -1;
- close(i);
- }
- pstore_fd = open("/dev/pmsg0", O_WRONLY);
- i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (i < 0) {
- ret = -errno;
- write_to_log = __write_to_log_null;
- } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) {
- ret = -errno;
- close(i);
- i = -1;
- write_to_log = __write_to_log_null;
- } 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 (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) {
+ 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);
- i = -1;
+ } 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;
+ }
}
}
- logd_fd = i;
#endif
return ret;
@@ -293,6 +276,8 @@
#if !defined(_WIN32)
pthread_mutex_lock(&log_init_lock);
#endif
+ close(logd_fd);
+ logd_fd = -1;
ret = __write_to_log_initialize();
#if !defined(_WIN32)
pthread_mutex_unlock(&log_init_lock);
@@ -351,6 +336,11 @@
#if !defined(_WIN32)
pthread_mutex_unlock(&log_init_lock);
#endif
+#if (FAKE_LOG_DEVICE == 0)
+ if (pstore_fd >= 0) {
+ __write_to_log_daemon(log_id, vec, nr);
+ }
+#endif
return ret;
}
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 6475649..58285f1 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -1123,7 +1123,7 @@
int32_t ExtractEntryToFile(ZipArchiveHandle handle,
ZipEntry* entry, int fd) {
- const int32_t declared_length = entry->uncompressed_length;
+ const uint32_t declared_length = entry->uncompressed_length;
const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
if (current_offset == -1) {
diff --git a/libzipfile/Android.mk b/libzipfile/Android.mk
deleted file mode 100644
index f054e15..0000000
--- a/libzipfile/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# build host static library
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- centraldir.c \
- zipfile.c
-
-LOCAL_STATIC_LIBRARIES := libz
-
-LOCAL_MODULE:= libzipfile
-
-LOCAL_CFLAGS := -Werror
-
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-# build device static library
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- centraldir.c \
- zipfile.c
-
-LOCAL_STATIC_LIBRARIES := libz
-
-LOCAL_MODULE:= libzipfile
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_STATIC_LIBRARY)
-
-
-# build test_zipfile
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- test_zipfile.c
-
-LOCAL_STATIC_LIBRARIES := libzipfile libz
-
-LOCAL_MODULE := test_zipfile
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/libzipfile/MODULE_LICENSE_APACHE2 b/libzipfile/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libzipfile/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libzipfile/NOTICE b/libzipfile/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/libzipfile/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/libzipfile/centraldir.c b/libzipfile/centraldir.c
deleted file mode 100644
index 69cf47a..0000000
--- a/libzipfile/centraldir.c
+++ /dev/null
@@ -1,222 +0,0 @@
-#include "private.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <utils/Compat.h>
-
-enum {
- // finding the directory
- CD_SIGNATURE = 0x06054b50,
- EOCD_LEN = 22, // EndOfCentralDir len, excl. comment
- MAX_COMMENT_LEN = 65535,
- MAX_EOCD_SEARCH = MAX_COMMENT_LEN + EOCD_LEN,
-
- // central directory entries
- ENTRY_SIGNATURE = 0x02014b50,
- ENTRY_LEN = 46, // CentralDirEnt len, excl. var fields
-
- // local file header
- LFH_SIZE = 30,
-};
-
-unsigned int
-read_le_int(const unsigned char* buf)
-{
- return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
-unsigned int
-read_le_short(const unsigned char* buf)
-{
- return buf[0] | (buf[1] << 8);
-}
-
-static int
-read_central_dir_values(Zipfile* file, const unsigned char* buf, int len)
-{
- if (len < EOCD_LEN) {
- // looks like ZIP file got truncated
- fprintf(stderr, " Zip EOCD: expected >= %d bytes, found %d\n",
- EOCD_LEN, len);
- return -1;
- }
-
- file->disknum = read_le_short(&buf[0x04]);
- file->diskWithCentralDir = read_le_short(&buf[0x06]);
- file->entryCount = read_le_short(&buf[0x08]);
- file->totalEntryCount = read_le_short(&buf[0x0a]);
- file->centralDirSize = read_le_int(&buf[0x0c]);
- file->centralDirOffest = read_le_int(&buf[0x10]);
- file->commentLen = read_le_short(&buf[0x14]);
-
- if (file->commentLen > 0) {
- if (EOCD_LEN + file->commentLen > len) {
- fprintf(stderr, "EOCD(%d) + comment(%d) exceeds len (%d)\n",
- EOCD_LEN, file->commentLen, len);
- return -1;
- }
- file->comment = buf + EOCD_LEN;
- }
-
- return 0;
-}
-
-static int
-read_central_directory_entry(Zipfile* file, Zipentry* entry,
- const unsigned char** buf, ssize_t* len)
-{
- const unsigned char* p;
-
- unsigned short extraFieldLength;
- unsigned short fileCommentLength;
- unsigned long localHeaderRelOffset;
- unsigned int dataOffset;
-
- p = *buf;
-
- if (*len < ENTRY_LEN) {
- fprintf(stderr, "cde entry not large enough\n");
- return -1;
- }
-
- if (read_le_int(&p[0x00]) != ENTRY_SIGNATURE) {
- fprintf(stderr, "Whoops: didn't find expected signature\n");
- return -1;
- }
-
- entry->compressionMethod = read_le_short(&p[0x0a]);
- entry->compressedSize = read_le_int(&p[0x14]);
- entry->uncompressedSize = read_le_int(&p[0x18]);
- entry->fileNameLength = read_le_short(&p[0x1c]);
- extraFieldLength = read_le_short(&p[0x1e]);
- fileCommentLength = read_le_short(&p[0x20]);
- localHeaderRelOffset = read_le_int(&p[0x2a]);
-
- p += ENTRY_LEN;
-
- // filename
- if (entry->fileNameLength != 0) {
- entry->fileName = p;
- } else {
- entry->fileName = NULL;
- }
- p += entry->fileNameLength;
-
- // extra field
- p += extraFieldLength;
-
- // comment, if any
- p += fileCommentLength;
-
- *buf = p;
-
- // the size of the extraField in the central dir is how much data there is,
- // but the one in the local file header also contains some padding.
- p = file->buf + localHeaderRelOffset;
- extraFieldLength = read_le_short(&p[0x1c]);
-
- dataOffset = localHeaderRelOffset + LFH_SIZE
- + entry->fileNameLength + extraFieldLength;
- entry->data = file->buf + dataOffset;
-#if 0
- printf("file->buf=%p entry->data=%p dataOffset=%x localHeaderRelOffset=%d "
- "entry->fileNameLength=%d extraFieldLength=%d\n",
- file->buf, entry->data, dataOffset, localHeaderRelOffset,
- entry->fileNameLength, extraFieldLength);
-#endif
- return 0;
-}
-
-/*
- * Find the central directory and read the contents.
- *
- * The fun thing about ZIP archives is that they may or may not be
- * readable from start to end. In some cases, notably for archives
- * that were written to stdout, the only length information is in the
- * central directory at the end of the file.
- *
- * Of course, the central directory can be followed by a variable-length
- * comment field, so we have to scan through it backwards. The comment
- * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
- * itself, plus apparently sometimes people throw random junk on the end
- * just for the fun of it.
- *
- * This is all a little wobbly. If the wrong value ends up in the EOCD
- * area, we're hosed. This appears to be the way that everbody handles
- * it though, so we're in pretty good company if this fails.
- */
-int
-read_central_dir(Zipfile *file)
-{
- int err;
-
- const unsigned char* buf = file->buf;
- ZD_TYPE bufsize = file->bufsize;
- const unsigned char* eocd;
- const unsigned char* p;
- const unsigned char* start;
- ssize_t len;
- int i;
-
- // too small to be a ZIP archive?
- if (bufsize < EOCD_LEN) {
- fprintf(stderr, "Length is " ZD " -- too small\n", bufsize);
- goto bail;
- }
-
- // find the end-of-central-dir magic
- if (bufsize > MAX_EOCD_SEARCH) {
- start = buf + bufsize - MAX_EOCD_SEARCH;
- } else {
- start = buf;
- }
- p = buf + bufsize - 4;
- while (p >= start) {
- if (*p == 0x50 && read_le_int(p) == CD_SIGNATURE) {
- eocd = p;
- break;
- }
- p--;
- }
- if (p < start) {
- fprintf(stderr, "EOCD not found, not Zip\n");
- goto bail;
- }
-
- // extract eocd values
- err = read_central_dir_values(file, eocd, (buf+bufsize)-eocd);
- if (err != 0) {
- goto bail;
- }
-
- if (file->disknum != 0
- || file->diskWithCentralDir != 0
- || file->entryCount != file->totalEntryCount) {
- fprintf(stderr, "Archive spanning not supported\n");
- goto bail;
- }
-
- // Loop through and read the central dir entries.
- p = buf + file->centralDirOffest;
- len = (buf+bufsize)-p;
- for (i=0; i < file->totalEntryCount; i++) {
- Zipentry* entry = malloc(sizeof(Zipentry));
- memset(entry, 0, sizeof(Zipentry));
-
- err = read_central_directory_entry(file, entry, &p, &len);
- if (err != 0) {
- fprintf(stderr, "read_central_directory_entry failed\n");
- free(entry);
- goto bail;
- }
-
- // add it to our list
- entry->next = file->entries;
- file->entries = entry;
- }
-
- return 0;
-bail:
- return -1;
-}
diff --git a/libzipfile/private.h b/libzipfile/private.h
deleted file mode 100644
index 06f788d..0000000
--- a/libzipfile/private.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef PRIVATE_H
-#define PRIVATE_H
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-typedef struct Zipentry {
- unsigned long fileNameLength;
- const unsigned char* fileName;
- unsigned short compressionMethod;
- unsigned int uncompressedSize;
- unsigned int compressedSize;
- const unsigned char* data;
-
- struct Zipentry* next;
-} Zipentry;
-
-typedef struct Zipfile
-{
- const unsigned char *buf;
- ssize_t bufsize;
-
- // Central directory
- unsigned short disknum; //mDiskNumber;
- unsigned short diskWithCentralDir; //mDiskWithCentralDir;
- unsigned short entryCount; //mNumEntries;
- unsigned short totalEntryCount; //mTotalNumEntries;
- unsigned int centralDirSize; //mCentralDirSize;
- unsigned int centralDirOffest; // offset from first disk //mCentralDirOffset;
- unsigned short commentLen; //mCommentLen;
- const unsigned char* comment; //mComment;
-
- Zipentry* entries;
-} Zipfile;
-
-int read_central_dir(Zipfile* file);
-
-unsigned int read_le_int(const unsigned char* buf);
-unsigned int read_le_short(const unsigned char* buf);
-
-#endif // PRIVATE_H
-
diff --git a/libzipfile/test_zipfile.c b/libzipfile/test_zipfile.c
deleted file mode 100644
index 1aaa913..0000000
--- a/libzipfile/test_zipfile.c
+++ /dev/null
@@ -1,94 +0,0 @@
-#include <zipfile/zipfile.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-void dump_zipfile(FILE* to, zipfile_t file);
-
-int
-main(int argc, char** argv)
-{
- FILE* f;
- size_t size, unsize;
- void* buf;
- void* scratch;
- zipfile_t zip;
- zipentry_t entry;
- int err;
- enum { HUH, LIST, UNZIP } what = HUH;
-
- if (strcmp(argv[2], "-l") == 0 && argc == 3) {
- what = LIST;
- }
- else if (strcmp(argv[2], "-u") == 0 && argc == 5) {
- what = UNZIP;
- }
- else {
- fprintf(stderr, "usage: test_zipfile ZIPFILE -l\n"
- " lists the files in the zipfile\n"
- " test_zipfile ZIPFILE -u FILENAME SAVETO\n"
- " saves FILENAME from the zip file into SAVETO\n");
- return 1;
- }
-
- f = fopen(argv[1], "r");
- if (f == NULL) {
- fprintf(stderr, "couldn't open %s\n", argv[1]);
- return 1;
- }
-
- fseek(f, 0, SEEK_END);
- size = ftell(f);
- rewind(f);
-
- buf = malloc(size);
- fread(buf, 1, size, f);
-
- zip = init_zipfile(buf, size);
- if (zip == NULL) {
- fprintf(stderr, "inti_zipfile failed\n");
- return 1;
- }
-
- fclose(f);
-
-
- switch (what)
- {
- case HUH:
- break;
- case LIST:
- dump_zipfile(stdout, zip);
- break;
- case UNZIP:
- entry = lookup_zipentry(zip, argv[3]);
- if (entry == NULL) {
- fprintf(stderr, "zip file '%s' does not contain file '%s'\n",
- argv[1], argv[1]);
- return 1;
- }
- f = fopen(argv[4], "w");
- if (f == NULL) {
- fprintf(stderr, "can't open file for writing '%s'\n", argv[4]);
- return 1;
- }
- unsize = get_zipentry_size(entry);
- size = unsize * 1.001;
- scratch = malloc(size);
- printf("scratch=%p\n", scratch);
- err = decompress_zipentry(entry, scratch, size);
- if (err != 0) {
- fprintf(stderr, "error decompressing file\n");
- return 1;
- }
- fwrite(scratch, unsize, 1, f);
- free(scratch);
- fclose(f);
- break;
- }
-
- free(buf);
-
- return 0;
-}
-
diff --git a/libzipfile/zipfile.c b/libzipfile/zipfile.c
deleted file mode 100644
index 1032ecc..0000000
--- a/libzipfile/zipfile.c
+++ /dev/null
@@ -1,159 +0,0 @@
-#include <zipfile/zipfile.h>
-
-#include "private.h"
-#include <stdlib.h>
-#include <string.h>
-#include <zlib.h>
-#define DEF_MEM_LEVEL 8 // normally in zutil.h?
-
-zipfile_t
-init_zipfile(const void* data, size_t size)
-{
- int err;
-
- Zipfile *file = malloc(sizeof(Zipfile));
- if (file == NULL) return NULL;
- memset(file, 0, sizeof(Zipfile));
- file->buf = data;
- file->bufsize = size;
-
- err = read_central_dir(file);
- if (err != 0) goto fail;
-
- return file;
-fail:
- free(file);
- return NULL;
-}
-
-void
-release_zipfile(zipfile_t f)
-{
- Zipfile* file = (Zipfile*)f;
- Zipentry* entry = file->entries;
- while (entry) {
- Zipentry* next = entry->next;
- free(entry);
- entry = next;
- }
- free(file);
-}
-
-zipentry_t
-lookup_zipentry(zipfile_t f, const char* entryName)
-{
- Zipfile* file = (Zipfile*)f;
- Zipentry* entry = file->entries;
- while (entry) {
- if (0 == memcmp(entryName, entry->fileName, entry->fileNameLength)) {
- return entry;
- }
- entry = entry->next;
- }
- return NULL;
-}
-
-size_t
-get_zipentry_size(zipentry_t entry)
-{
- return ((Zipentry*)entry)->uncompressedSize;
-}
-
-char*
-get_zipentry_name(zipentry_t entry)
-{
- Zipentry* e = (Zipentry*)entry;
- int l = e->fileNameLength;
- char* s = malloc(l+1);
- memcpy(s, e->fileName, l);
- s[l] = '\0';
- return s;
-}
-
-enum {
- STORED = 0,
- DEFLATED = 8
-};
-
-static int
-inflate_wrapper(unsigned char* out, int unlen, const unsigned char* in, int clen)
-{
- z_stream zstream;
- int err = 0;
- int zerr;
-
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = (void*)in;
- zstream.avail_in = clen;
- zstream.next_out = (Bytef*) out;
- zstream.avail_out = unlen;
- zstream.data_type = Z_UNKNOWN;
-
- // Use the undocumented "negative window bits" feature to tell zlib
- // that there's no zlib header waiting for it.
- zerr = inflateInit2(&zstream, -MAX_WBITS);
- if (zerr != Z_OK) {
- return -1;
- }
-
- // uncompress the data
- zerr = inflate(&zstream, Z_FINISH);
- if (zerr != Z_STREAM_END) {
- fprintf(stderr, "zerr=%d Z_STREAM_END=%d total_out=%lu\n", zerr, Z_STREAM_END,
- zstream.total_out);
- err = -1;
- }
-
- inflateEnd(&zstream);
- return err;
-}
-
-int
-decompress_zipentry(zipentry_t e, void* buf, int bufsize)
-{
- Zipentry* entry = (Zipentry*)e;
- switch (entry->compressionMethod)
- {
- case STORED:
- memcpy(buf, entry->data, entry->uncompressedSize);
- return 0;
- case DEFLATED:
- return inflate_wrapper(buf, bufsize, entry->data, entry->compressedSize);
- default:
- return -1;
- }
-}
-
-void
-dump_zipfile(FILE* to, zipfile_t file)
-{
- Zipfile* zip = (Zipfile*)file;
- Zipentry* entry = zip->entries;
- int i;
-
- fprintf(to, "entryCount=%d\n", zip->entryCount);
- for (i=0; i<zip->entryCount; i++) {
- fprintf(to, " file \"");
- fwrite(entry->fileName, entry->fileNameLength, 1, to);
- fprintf(to, "\"\n");
- entry = entry->next;
- }
-}
-
-zipentry_t
-iterate_zipfile(zipfile_t file, void** cookie)
-{
- Zipentry* entry = (Zipentry*)*cookie;
- if (entry == NULL) {
- Zipfile* zip = (Zipfile*)file;
- *cookie = zip->entries;
- return *cookie;
- } else {
- entry = entry->next;
- *cookie = entry;
- return entry;
- }
-}
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 2693583..d11b129 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -27,8 +27,6 @@
#include "LogBuffer.h"
#include "LogReader.h"
-#include "LogStatistics.h"
-#include "LogWhiteBlackList.h"
// Default
#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
@@ -193,7 +191,7 @@
LogTimeEntry::unlock();
}
- stats.add(len, log_id, uid, pid);
+ stats.add(elem);
maybePrune(log_id);
pthread_mutex_unlock(&mLogElementsLock);
}
@@ -216,6 +214,16 @@
}
}
+LogBufferElementCollection::iterator LogBuffer::erase(LogBufferElementCollection::iterator it) {
+ LogBufferElement *e = *it;
+
+ it = mLogElements.erase(it);
+ stats.subtract(e);
+ delete e;
+
+ return it;
+}
+
// prune "pruneRows" of type "id" from the buffer.
//
// mLogElementsLock must be held when this function is called.
@@ -250,12 +258,8 @@
continue;
}
- uid_t uid = e->getUid();
-
- if (uid == caller_uid) {
- it = mLogElements.erase(it);
- stats.subtract(e->getMsgLen(), id, uid, e->getPid());
- delete e;
+ if (e->getUid() == caller_uid) {
+ it = erase(it);
pruneRows--;
if (pruneRows == 0) {
break;
@@ -269,6 +273,7 @@
}
// prune by worst offender by uid
+ bool hasBlacklist = mPrune.naughty();
while (pruneRows > 0) {
// recalculate the worst offender on every batched pass
uid_t worst = (uid_t) -1;
@@ -276,19 +281,23 @@
size_t second_worst_sizes = 0;
if ((id != LOG_ID_CRASH) && mPrune.worstUidEnabled()) {
- LidStatistics &l = stats.id(id);
- l.sort();
- UidStatisticsCollection::iterator iu = l.begin();
- if (iu != l.end()) {
- UidStatistics *u = *iu;
- worst = u->getUid();
- worst_sizes = u->sizes();
- if (++iu != l.end()) {
- second_worst_sizes = (*iu)->sizes();
+ const UidEntry **sorted = stats.sort(2, id);
+
+ if (sorted) {
+ if (sorted[0] && sorted[1]) {
+ worst = sorted[0]->getKey();
+ worst_sizes = sorted[0]->getSizes();
+ second_worst_sizes = sorted[1]->getSizes();
}
+ delete [] sorted;
}
}
+ // skip if we have neither worst nor naughty filters
+ if ((worst == (uid_t) -1) && !hasBlacklist) {
+ break;
+ }
+
bool kick = false;
for(it = mLogElements.begin(); it != mLogElements.end();) {
LogBufferElement *e = *it;
@@ -304,24 +313,28 @@
uid_t uid = e->getUid();
- if ((uid == worst) || mPrune.naughty(e)) { // Worst or BlackListed
- it = mLogElements.erase(it);
- unsigned short len = e->getMsgLen();
- stats.subtract(len, id, uid, e->getPid());
- delete e;
- pruneRows--;
- if (uid == worst) {
- kick = true;
- if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
- break;
- }
- worst_sizes -= len;
- } else if (pruneRows == 0) {
- break;
- }
- } else {
+ // !Worst and !BlackListed?
+ if ((uid != worst) && (!hasBlacklist || !mPrune.naughty(e))) {
++it;
+ continue;
}
+
+ unsigned short len = e->getMsgLen();
+ it = erase(it);
+ pruneRows--;
+ if (pruneRows == 0) {
+ break;
+ }
+
+ if (uid != worst) {
+ continue;
+ }
+
+ kick = true;
+ if (worst_sizes < second_worst_sizes) {
+ break;
+ }
+ worst_sizes -= len;
}
if (!kick || !mPrune.worstUidEnabled()) {
@@ -330,58 +343,63 @@
}
bool whitelist = false;
+ bool hasWhitelist = mPrune.nice();
it = mLogElements.begin();
while((pruneRows > 0) && (it != mLogElements.end())) {
LogBufferElement *e = *it;
- if (e->getLogId() == id) {
- if (oldest && (oldest->mStart <= e->getSequence())) {
- if (!whitelist) {
- if (stats.sizes(id) > (2 * log_buffer_size(id))) {
- // kick a misbehaving log reader client off the island
- oldest->release_Locked();
- } else {
- oldest->triggerSkip_Locked(id, pruneRows);
- }
- }
+
+ if (e->getLogId() != id) {
+ it++;
+ continue;
+ }
+
+ if (oldest && (oldest->mStart <= e->getSequence())) {
+ if (whitelist) {
break;
}
- if (mPrune.nice(e)) { // WhiteListed
- whitelist = true;
- it++;
- continue;
+ if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+ // kick a misbehaving log reader client off the island
+ oldest->release_Locked();
+ } else {
+ oldest->triggerSkip_Locked(id, pruneRows);
}
-
- it = mLogElements.erase(it);
- stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
- delete e;
- pruneRows--;
- } else {
- it++;
+ break;
}
+
+ if (hasWhitelist && mPrune.nice(e)) { // WhiteListed
+ whitelist = true;
+ it++;
+ continue;
+ }
+
+ it = erase(it);
+ pruneRows--;
}
+ // Do not save the whitelist if we are reader range limited
if (whitelist && (pruneRows > 0)) {
it = mLogElements.begin();
while((it != mLogElements.end()) && (pruneRows > 0)) {
LogBufferElement *e = *it;
- if (e->getLogId() == id) {
- if (oldest && (oldest->mStart <= e->getSequence())) {
- if (stats.sizes(id) > (2 * log_buffer_size(id))) {
- // kick a misbehaving log reader client off the island
- oldest->release_Locked();
- } else {
- oldest->triggerSkip_Locked(id, pruneRows);
- }
- break;
- }
- it = mLogElements.erase(it);
- stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
- delete e;
- pruneRows--;
- } else {
- it++;
+
+ if (e->getLogId() != id) {
+ ++it;
+ continue;
}
+
+ if (oldest && (oldest->mStart <= e->getSequence())) {
+ if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+ // kick a misbehaving log reader client off the island
+ oldest->release_Locked();
+ } else {
+ oldest->triggerSkip_Locked(id, pruneRows);
+ }
+ break;
+ }
+
+ it = erase(it);
+ pruneRows--;
}
}
@@ -487,22 +505,9 @@
}
void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
- uint64_t oldest = UINT64_MAX;
-
pthread_mutex_lock(&mLogElementsLock);
- // Find oldest element in the log(s)
- LogBufferElementCollection::iterator it;
- for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
- LogBufferElement *element = *it;
-
- if ((logMask & (1 << element->getLogId()))) {
- oldest = element->getSequence();
- break;
- }
- }
-
- stats.format(strp, uid, logMask, oldest);
+ stats.format(strp, uid, logMask);
pthread_mutex_unlock(&mLogElementsLock);
}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 13e6aa8..a29e015 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -78,7 +78,7 @@
private:
void maybePrune(log_id_t id);
void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
-
+ LogBufferElementCollection::iterator erase(LogBufferElementCollection::iterator it);
};
#endif // _LOGD_LOG_BUFFER_H__
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 25f1450..0628d3e 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -17,8 +17,9 @@
#ifndef _LOGD_LOG_BUFFER_ELEMENT_H__
#define _LOGD_LOG_BUFFER_ELEMENT_H__
-#include <sys/types.h>
#include <stdatomic.h>
+#include <sys/types.h>
+
#include <sysutils/SocketClient.h>
#include <log/log.h>
#include <log/log_read.h>
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 5a70689..accd660 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,10 +14,12 @@
* limitations under the License.
*/
+#include <algorithm> // std::max
#include <fcntl.h>
-#include <malloc.h>
-#include <stdarg.h>
-#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <log/logger.h>
#include <private/android_filesystem_config.h>
@@ -25,80 +27,21 @@
#include "LogStatistics.h"
-PidStatistics::PidStatistics(pid_t pid, char *name)
- : pid(pid)
- , mSizesTotal(0)
- , mElementsTotal(0)
- , mSizes(0)
- , mElements(0)
- , name(name)
- , mGone(false)
-{ }
-
-#ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR
-PidStatistics::PidStatistics(const PidStatistics ©)
- : pid(copy->pid)
- , name(copy->name ? strdup(copy->name) : NULL)
- , mSizesTotal(copy->mSizesTotal)
- , mElementsTotal(copy->mElementsTotal)
- , mSizes(copy->mSizes)
- , mElements(copy->mElements)
- , mGone(copy->mGone)
-{ }
-#endif
-
-PidStatistics::~PidStatistics() {
- free(name);
-}
-
-bool PidStatistics::pidGone() {
- if (mGone || (pid == gone)) {
- return true;
- }
- if (pid == 0) {
- return false;
- }
- if (kill(pid, 0) && (errno != EPERM)) {
- mGone = true;
- return true;
- }
- return false;
-}
-
-void PidStatistics::setName(char *new_name) {
- free(name);
- name = new_name;
-}
-
-void PidStatistics::add(unsigned short size) {
- mSizesTotal += size;
- ++mElementsTotal;
- mSizes += size;
- ++mElements;
-}
-
-bool PidStatistics::subtract(unsigned short size) {
- mSizes -= size;
- --mElements;
- return (mElements == 0) && pidGone();
-}
-
-void PidStatistics::addTotal(size_t size, size_t element) {
- if (pid == gone) {
- mSizesTotal += size;
- mElementsTotal += element;
+LogStatistics::LogStatistics() {
+ log_id_for_each(id) {
+ mSizes[id] = 0;
+ mElements[id] = 0;
+ mSizesTotal[id] = 0;
+ mElementsTotal[id] = 0;
}
}
-// must call free to release return value
-// If only we could sniff our own logs for:
-// <time> <pid> <pid> E AndroidRuntime: Process: <name>, PID: <pid>
-// which debuggerd prints as a process is crashing.
-char *PidStatistics::pidToName(pid_t pid) {
+// caller must own and free character string
+char *LogStatistics::pidToName(pid_t pid) {
char *retval = NULL;
if (pid == 0) { // special case from auditd for kernel
retval = strdup("logd.auditd");
- } else if (pid != gone) {
+ } else {
char buffer[512];
snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
int fd = open(buffer, O_RDONLY);
@@ -117,358 +60,105 @@
return retval;
}
-UidStatistics::UidStatistics(uid_t uid)
- : uid(uid)
- , mSizes(0)
- , mElements(0) {
- Pids.clear();
-}
-
-UidStatistics::~UidStatistics() {
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end();) {
- delete (*it);
- it = erase(it);
- }
-}
-
-void UidStatistics::add(unsigned short size, pid_t pid) {
- mSizes += size;
- ++mElements;
-
- PidStatistics *p = NULL;
- PidStatisticsCollection::iterator last;
- PidStatisticsCollection::iterator it;
- for (last = it = begin(); it != end(); last = it, ++it) {
- p = *it;
- if (pid == p->getPid()) {
- p->add(size);
- return;
- }
- }
- // insert if the gone entry.
- bool insert_before_last = (last != it) && p && (p->getPid() == p->gone);
- p = new PidStatistics(pid, pidToName(pid));
- if (insert_before_last) {
- insert(last, p);
- } else {
- push_back(p);
- }
- p->add(size);
-}
-
-void UidStatistics::subtract(unsigned short size, pid_t pid) {
- mSizes -= size;
- --mElements;
-
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if (pid == p->getPid()) {
- if (p->subtract(size)) {
- size_t szsTotal = p->sizesTotal();
- size_t elsTotal = p->elementsTotal();
- delete p;
- erase(it);
- it = end();
- --it;
- if (it == end()) {
- p = new PidStatistics(p->gone);
- push_back(p);
- } else {
- p = *it;
- if (p->getPid() != p->gone) {
- p = new PidStatistics(p->gone);
- push_back(p);
- }
- }
- p->addTotal(szsTotal, elsTotal);
- }
- return;
- }
- }
-}
-
-void UidStatistics::sort() {
- for (bool pass = true; pass;) {
- pass = false;
- PidStatisticsCollection::iterator it = begin();
- if (it != end()) {
- PidStatisticsCollection::iterator lt = it;
- PidStatistics *l = (*lt);
- while (++it != end()) {
- PidStatistics *n = (*it);
- if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) {
- pass = true;
- erase(it);
- insert(lt, n);
- it = lt;
- n = l;
- }
- lt = it;
- l = n;
- }
- }
- }
-}
-
-size_t UidStatistics::sizes(pid_t pid) {
- if (pid == pid_all) {
- return sizes();
- }
-
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if (pid == p->getPid()) {
- return p->sizes();
- }
- }
- return 0;
-}
-
-size_t UidStatistics::elements(pid_t pid) {
- if (pid == pid_all) {
- return elements();
- }
-
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if (pid == p->getPid()) {
- return p->elements();
- }
- }
- return 0;
-}
-
-size_t UidStatistics::sizesTotal(pid_t pid) {
- size_t sizes = 0;
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if ((pid == pid_all) || (pid == p->getPid())) {
- sizes += p->sizesTotal();
- }
- }
- return sizes;
-}
-
-size_t UidStatistics::elementsTotal(pid_t pid) {
- size_t elements = 0;
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if ((pid == pid_all) || (pid == p->getPid())) {
- elements += p->elementsTotal();
- }
- }
- return elements;
-}
-
-LidStatistics::LidStatistics() {
- Uids.clear();
-}
-
-LidStatistics::~LidStatistics() {
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end();) {
- delete (*it);
- it = Uids.erase(it);
- }
-}
-
-void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) {
- UidStatistics *u;
- UidStatisticsCollection::iterator it;
- UidStatisticsCollection::iterator last;
-
- if (uid == (uid_t) -1) { // init
- uid = (uid_t) AID_ROOT;
- }
-
- for (last = it = begin(); it != end(); last = it, ++it) {
- u = *it;
- if (uid == u->getUid()) {
- u->add(size, pid);
- if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) {
- Uids.erase(it);
- Uids.insert(last, u);
- }
- return;
- }
- }
- u = new UidStatistics(uid);
- if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) {
- Uids.insert(last, u);
- } else {
- Uids.push_back(u);
- }
- u->add(size, pid);
-}
-
-void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) {
- if (uid == (uid_t) -1) { // init
- uid = (uid_t) AID_ROOT;
- }
-
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if (uid == u->getUid()) {
- u->subtract(size, pid);
- return;
- }
- }
-}
-
-void LidStatistics::sort() {
- for (bool pass = true; pass;) {
- pass = false;
- UidStatisticsCollection::iterator it = begin();
- if (it != end()) {
- UidStatisticsCollection::iterator lt = it;
- UidStatistics *l = (*lt);
- while (++it != end()) {
- UidStatistics *n = (*it);
- if (n->sizes() > l->sizes()) {
- pass = true;
- Uids.erase(it);
- Uids.insert(lt, n);
- it = lt;
- n = l;
- }
- lt = it;
- l = n;
- }
- }
- }
-}
-
-size_t LidStatistics::sizes(uid_t uid, pid_t pid) {
- size_t sizes = 0;
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if ((uid == uid_all) || (uid == u->getUid())) {
- sizes += u->sizes(pid);
- }
- }
- return sizes;
-}
-
-size_t LidStatistics::elements(uid_t uid, pid_t pid) {
- size_t elements = 0;
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if ((uid == uid_all) || (uid == u->getUid())) {
- elements += u->elements(pid);
- }
- }
- return elements;
-}
-
-size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) {
- size_t sizes = 0;
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if ((uid == uid_all) || (uid == u->getUid())) {
- sizes += u->sizesTotal(pid);
- }
- }
- return sizes;
-}
-
-size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) {
- size_t elements = 0;
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if ((uid == uid_all) || (uid == u->getUid())) {
- elements += u->elementsTotal(pid);
- }
- }
- return elements;
-}
-
-LogStatistics::LogStatistics()
- : mStatistics(false)
- , start(CLOCK_MONOTONIC) {
- log_id_for_each(i) {
- mSizes[i] = 0;
- mElements[i] = 0;
- }
-}
-
-void LogStatistics::add(unsigned short size,
- log_id_t log_id, uid_t uid, pid_t pid) {
+void LogStatistics::add(LogBufferElement *e) {
+ log_id_t log_id = e->getLogId();
+ unsigned short size = e->getMsgLen();
mSizes[log_id] += size;
++mElements[log_id];
- if (!mStatistics) {
- return;
+
+ uid_t uid = e->getUid();
+ android::hash_t hash = android::hash_type(uid);
+ uidTable_t &table = uidTable[log_id];
+ ssize_t index = table.find(-1, hash, uid);
+ if (index == -1) {
+ UidEntry initEntry(uid);
+ initEntry.add(size);
+ table.add(hash, initEntry);
+ } else {
+ UidEntry &entry = table.editEntryAt(index);
+ entry.add(size);
}
- id(log_id).add(size, uid, pid);
+
+ mSizesTotal[log_id] += size;
+ ++mElementsTotal[log_id];
}
-void LogStatistics::subtract(unsigned short size,
- log_id_t log_id, uid_t uid, pid_t pid) {
+void LogStatistics::subtract(LogBufferElement *e) {
+ log_id_t log_id = e->getLogId();
+ unsigned short size = e->getMsgLen();
mSizes[log_id] -= size;
--mElements[log_id];
- if (!mStatistics) {
- return;
+
+ uid_t uid = e->getUid();
+ android::hash_t hash = android::hash_type(uid);
+ uidTable_t &table = uidTable[log_id];
+ ssize_t index = table.find(-1, hash, uid);
+ if (index != -1) {
+ UidEntry &entry = table.editEntryAt(index);
+ if (entry.subtract(size)) {
+ table.removeAt(index);
+ }
}
- id(log_id).subtract(size, uid, pid);
}
-size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) {
- if (log_id != log_id_all) {
- return id(log_id).sizes(uid, pid);
+// caller must own and delete UidEntry array
+const UidEntry **LogStatistics::sort(size_t n, log_id id) {
+ if (!n) {
+ return NULL;
}
- size_t sizes = 0;
- log_id_for_each(i) {
- sizes += id(i).sizes(uid, pid);
+
+ const UidEntry **retval = new const UidEntry* [n];
+ memset(retval, 0, sizeof(*retval) * n);
+
+ uidTable_t &table = uidTable[id];
+ ssize_t index = -1;
+ while ((index = table.next(index)) >= 0) {
+ const UidEntry &entry = table.entryAt(index);
+ size_t s = entry.getSizes();
+ ssize_t i = n - 1;
+ while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0));
+ if (++i < (ssize_t)n) {
+ size_t b = n - i - 1;
+ if (b) {
+ memmove(&retval[i+1], &retval[i], b * sizeof(retval[0]));
+ }
+ retval[i] = &entry;
+ }
}
- return sizes;
+ return retval;
}
-size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) {
- if (log_id != log_id_all) {
- return id(log_id).elements(uid, pid);
+// caller must own and free character string
+char *LogStatistics::uidToName(uid_t uid) {
+ // Local hard coded favourites
+ if (uid == AID_LOGD) {
+ return strdup("auditd");
}
- size_t elements = 0;
- log_id_for_each(i) {
- elements += id(i).elements(uid, pid);
+
+ // Android hard coded
+ const struct android_id_info *info = android_ids;
+
+ for (size_t i = 0; i < android_id_count; ++i) {
+ if (info->aid == uid) {
+ return strdup(info->name);
+ }
+ ++info;
}
- return elements;
+
+ // No one
+ return NULL;
}
-size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) {
- if (log_id != log_id_all) {
- return id(log_id).sizesTotal(uid, pid);
- }
- size_t sizes = 0;
- log_id_for_each(i) {
- sizes += id(i).sizesTotal(uid, pid);
- }
- return sizes;
+static void format_line(android::String8 &output,
+ android::String8 &name, android::String8 &size) {
+ static const size_t total_len = 70;
+
+ output.appendFormat("%s%*s\n", name.string(),
+ (int)std::max(total_len - name.length() - 1, size.length() + 1),
+ size.string());
}
-size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) {
- if (log_id != log_id_all) {
- return id(log_id).elementsTotal(uid, pid);
- }
- size_t elements = 0;
- log_id_for_each(i) {
- elements += id(i).elementsTotal(uid, pid);
- }
- return elements;
-}
-
-void LogStatistics::format(char **buf,
- uid_t uid, unsigned int logMask, log_time oldest) {
- static const unsigned short spaces_current = 13;
+void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
static const unsigned short spaces_total = 19;
if (*buf) {
@@ -476,368 +166,142 @@
*buf = NULL;
}
- android::String8 string(" span -> size/num");
- size_t oldLength;
- short spaces = 2;
+ // Report on total logging, current and for all time
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
+ android::String8 output("size/num");
+ size_t oldLength;
+ short spaces = 1;
+
+ log_id_for_each(id) {
+ if (!(logMask & (1 << id))) {
continue;
}
- oldLength = string.length();
+ oldLength = output.length();
if (spaces < 0) {
spaces = 0;
}
- string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
- spaces += spaces_total + oldLength - string.length();
-
- LidStatistics &l = id(i);
- l.sort();
-
- UidStatisticsCollection::iterator iu;
- for (iu = l.begin(); iu != l.end(); ++iu) {
- (*iu)->sort();
- }
+ output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
+ spaces += spaces_total + oldLength - output.length();
}
- spaces = 1;
- log_time t(CLOCK_MONOTONIC);
- unsigned long long d;
- if (mStatistics) {
- d = t.nsec() - start.nsec();
- string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
- d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
- (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+ spaces = 4;
+ output.appendFormat("\nTotal");
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
- continue;
- }
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s%zu/%zu", spaces, "",
- sizesTotal(i), elementsTotal(i));
- spaces += spaces_total + oldLength - string.length();
+ log_id_for_each(id) {
+ if (!(logMask & (1 << id))) {
+ continue;
}
- spaces = 1;
+ oldLength = output.length();
+ if (spaces < 0) {
+ spaces = 0;
+ }
+ output.appendFormat("%*s%zu/%zu", spaces, "",
+ sizesTotal(id), elementsTotal(id));
+ spaces += spaces_total + oldLength - output.length();
}
- d = t.nsec() - oldest.nsec();
- string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
- d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
- (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+ spaces = 6;
+ output.appendFormat("\nNow");
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
+ log_id_for_each(id) {
+ if (!(logMask & (1 << id))) {
continue;
}
- size_t els = elements(i);
+ size_t els = elements(id);
if (els) {
- oldLength = string.length();
+ oldLength = output.length();
if (spaces < 0) {
spaces = 0;
}
- string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
- spaces -= string.length() - oldLength;
+ output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els);
+ spaces -= output.length() - oldLength;
}
spaces += spaces_total;
}
- // Construct list of worst spammers by Pid
- static const unsigned char num_spammers = 10;
- bool header = false;
+ // Report on Chattiest
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
+ // Chattiest by application (UID)
+ log_id_for_each(id) {
+ if (!(logMask & (1 << id))) {
continue;
}
- PidStatisticsCollection pids;
- pids.clear();
+ static const size_t maximum_sorted_entries = 32;
+ const UidEntry **sorted = sort(maximum_sorted_entries, id);
- LidStatistics &l = id(i);
- UidStatisticsCollection::iterator iu;
- for (iu = l.begin(); iu != l.end(); ++iu) {
- UidStatistics &u = *(*iu);
- PidStatisticsCollection::iterator ip;
- for (ip = u.begin(); ip != u.end(); ++ip) {
- PidStatistics *p = (*ip);
- if (p->getPid() == p->gone) {
- break;
- }
-
- size_t mySizes = p->sizes();
-
- PidStatisticsCollection::iterator q;
- unsigned char num = 0;
- for (q = pids.begin(); q != pids.end(); ++q) {
- if (mySizes > (*q)->sizes()) {
- pids.insert(q, p);
- break;
- }
- // do we need to traverse deeper in the list?
- if (++num > num_spammers) {
- break;
- }
- }
- if (q == pids.end()) {
- pids.push_back(p);
- }
- }
+ if (!sorted) {
+ continue;
}
- size_t threshold = sizes(i);
- if (threshold < 65536) {
- threshold = 65536;
- }
- threshold /= 100;
+ bool print = false;
+ for(size_t index = 0; index < maximum_sorted_entries; ++index) {
+ const UidEntry *entry = sorted[index];
- PidStatisticsCollection::iterator pt = pids.begin();
-
- for(int line = 0;
- (pt != pids.end()) && (line < num_spammers);
- ++line, pt = pids.erase(pt)) {
- PidStatistics *p = *pt;
-
- size_t sizes = p->sizes();
- if (sizes < threshold) {
+ if (!entry) {
break;
}
- char *name = p->getName();
- pid_t pid = p->getPid();
- if (!name || !*name) {
- name = pidToName(pid);
- if (name) {
- if (*name) {
- p->setName(name);
- } else {
- free(name);
- name = NULL;
- }
+ size_t sizes = entry->getSizes();
+ if (sizes < (65536/100)) {
+ break;
+ }
+
+ uid_t u = entry->getKey();
+ if ((uid != AID_ROOT) && (u != uid)) {
+ continue;
+ }
+
+ if (!print) {
+ if (uid == AID_ROOT) {
+ output.appendFormat(
+ "\n\nChattiest UIDs in %s:\n",
+ android_log_id_to_name(id));
+ android::String8 name("UID");
+ android::String8 size("Size");
+ format_line(output, name, size);
+ } else {
+ output.appendFormat(
+ "\n\nLogging for your UID in %s:\n",
+ android_log_id_to_name(id));
}
+ print = true;
}
- if (!header) {
- string.appendFormat("\n\nChattiest clients:\n"
- "log id %-*s PID[?] name",
- spaces_total, "size/total");
- header = true;
+ android::String8 name("");
+ name.appendFormat("%u", u);
+ char *n = uidToName(u);
+ if (n) {
+ name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n);
+ free(n);
}
- size_t sizesTotal = p->sizesTotal();
+ android::String8 size("");
+ size.appendFormat("%zu", sizes);
- android::String8 sz("");
- if (sizes == sizesTotal) {
- sz.appendFormat("%zu", sizes);
- } else {
- sz.appendFormat("%zu/%zu", sizes, sizesTotal);
- }
-
- android::String8 pd("");
- pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' ');
-
- string.appendFormat("\n%-7s%-*s %-7s%s",
- line ? "" : android_log_id_to_name(i),
- spaces_total, sz.string(), pd.string(),
- name ? name : "");
+ format_line(output, name, size);
}
- pids.clear();
+ delete [] sorted;
}
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
- continue;
- }
-
- header = false;
- bool first = true;
-
- UidStatisticsCollection::iterator ut;
- for(ut = id(i).begin(); ut != id(i).end(); ++ut) {
- UidStatistics *up = *ut;
- if ((uid != AID_ROOT) && (uid != up->getUid())) {
- continue;
- }
-
- PidStatisticsCollection::iterator pt = up->begin();
- if (pt == up->end()) {
- continue;
- }
-
- android::String8 intermediate;
-
- if (!header) {
- // header below tuned to match spaces_total and spaces_current
- spaces = 0;
- intermediate = string.format("%s: UID/PID Total size/num",
- android_log_id_to_name(i));
- string.appendFormat("\n\n%-31sNow "
- "UID/PID[?] Total Now",
- intermediate.string());
- intermediate.clear();
- header = true;
- }
-
- bool oneline = ++pt == up->end();
- --pt;
-
- if (!oneline) {
- first = true;
- } else if (!first && (spaces > 0)) {
- string.appendFormat("%*s", spaces, "");
- }
- spaces = 0;
-
- uid_t u = up->getUid();
- PidStatistics *pp = *pt;
- pid_t p = pp->getPid();
-
- if (!oneline) {
- intermediate = string.format("%d", u);
- } else if (p == PidStatistics::gone) {
- intermediate = string.format("%d/?", u);
- } else if (pp->pidGone()) {
- intermediate = string.format("%d/%d?", u, p);
- } else {
- intermediate = string.format("%d/%d", u, p);
- }
- string.appendFormat(first ? "\n%-12s" : "%-12s",
- intermediate.string());
- intermediate.clear();
-
- size_t elsTotal = up->elementsTotal();
- oldLength = string.length();
- string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal);
- spaces += spaces_total + oldLength - string.length();
-
- size_t els = up->elements();
- if (els == elsTotal) {
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s=", spaces, "");
- spaces = -1;
- } else if (els) {
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
- spaces -= string.length() - oldLength;
- }
- spaces += spaces_current;
-
- first = !first;
-
- if (oneline) {
- continue;
- }
-
- size_t gone_szs = 0;
- size_t gone_els = 0;
-
- for(; pt != up->end(); ++pt) {
- pp = *pt;
- p = pp->getPid();
-
- // If a PID no longer has any current logs, and is not
- // active anymore, skip & report totals for gone.
- elsTotal = pp->elementsTotal();
- size_t szsTotal = pp->sizesTotal();
- if (p == pp->gone) {
- gone_szs += szsTotal;
- gone_els += elsTotal;
- continue;
- }
- els = pp->elements();
- bool gone = pp->pidGone();
- if (gone && (els == 0)) {
- // ToDo: garbage collection: move this statistical bucket
- // from its current UID/PID to UID/? (races and
- // wrap around are our achilles heel). Below is
- // merely lipservice to catch PIDs that were still
- // around when the stats were pruned to zero.
- gone_szs += szsTotal;
- gone_els += elsTotal;
- continue;
- }
-
- if (!first && (spaces > 0)) {
- string.appendFormat("%*s", spaces, "");
- }
- spaces = 0;
-
- intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p);
- string.appendFormat(first ? "\n%-12s" : "%-12s",
- intermediate.string());
- intermediate.clear();
-
- oldLength = string.length();
- string.appendFormat("%zu/%zu", szsTotal, elsTotal);
- spaces += spaces_total + oldLength - string.length();
-
- if (els == elsTotal) {
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s=", spaces, "");
- spaces = -1;
- } else if (els) {
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s%zu/%zu", spaces, "",
- pp->sizes(), els);
- spaces -= string.length() - oldLength;
- }
- spaces += spaces_current;
-
- first = !first;
- }
-
- if (gone_els) {
- if (!first && (spaces > 0)) {
- string.appendFormat("%*s", spaces, "");
- }
-
- intermediate = string.format("%d/?", u);
- string.appendFormat(first ? "\n%-12s" : "%-12s",
- intermediate.string());
- intermediate.clear();
-
- spaces = spaces_total + spaces_current;
-
- oldLength = string.length();
- string.appendFormat("%zu/%zu", gone_szs, gone_els);
- spaces -= string.length() - oldLength;
-
- first = !first;
- }
- }
- }
-
- *buf = strdup(string.string());
+ *buf = strdup(output.string());
}
uid_t LogStatistics::pidToUid(pid_t pid) {
- log_id_for_each(i) {
- LidStatistics &l = id(i);
- UidStatisticsCollection::iterator iu;
- for (iu = l.begin(); iu != l.end(); ++iu) {
- UidStatistics &u = *(*iu);
- PidStatisticsCollection::iterator ip;
- for (ip = u.begin(); ip != u.end(); ++ip) {
- if ((*ip)->getPid() == pid) {
- return u.getUid();
- }
+ char buffer[512];
+ snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
+ FILE *fp = fopen(buffer, "r");
+ if (fp) {
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ int uid;
+ if (sscanf(buffer, "Groups: %d", &uid) == 1) {
+ fclose(fp);
+ return uid;
}
}
+ fclose(fp);
}
return getuid(); // associate this with the logger
}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index f892cd0..d5b8762 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -20,175 +20,60 @@
#include <sys/types.h>
#include <log/log.h>
-#include <log/log_read.h>
-#include <utils/List.h>
+#include <utils/BasicHashtable.h>
+
+#include "LogBufferElement.h"
#define log_id_for_each(i) \
for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
-class PidStatistics {
- const pid_t pid;
-
- // Total
- size_t mSizesTotal;
- size_t mElementsTotal;
- // Current
- size_t mSizes;
- size_t mElements;
-
- char *name;
- bool mGone;
-
-public:
- static const pid_t gone = (pid_t) -1;
-
- PidStatistics(pid_t pid, char *name = NULL);
- PidStatistics(const PidStatistics ©);
- ~PidStatistics();
-
- pid_t getPid() const { return pid; }
- bool pidGone();
- char *getName() const { return name; }
- void setName(char *name);
-
- void add(unsigned short size);
- bool subtract(unsigned short size); // returns true if stats and PID gone
- void addTotal(size_t size, size_t element);
-
- size_t sizes() const { return mSizes; }
- size_t elements() const { return mElements; }
-
- size_t sizesTotal() const { return mSizesTotal; }
- size_t elementsTotal() const { return mElementsTotal; }
-
- // helper
- static char *pidToName(pid_t pid);
-};
-
-typedef android::List<PidStatistics *> PidStatisticsCollection;
-
-class UidStatistics {
+struct UidEntry {
const uid_t uid;
+ size_t size;
- PidStatisticsCollection Pids;
+ UidEntry(uid_t uid):uid(uid),size(0) { }
- void insert(PidStatisticsCollection::iterator i, PidStatistics *p)
- { Pids.insert(i, p); }
- void push_back(PidStatistics *p) { Pids.push_back(p); }
-
- size_t mSizes;
- size_t mElements;
-
-public:
- UidStatistics(uid_t uid);
- ~UidStatistics();
-
- PidStatisticsCollection::iterator begin() { return Pids.begin(); }
- PidStatisticsCollection::iterator end() { return Pids.end(); }
- PidStatisticsCollection::iterator erase(PidStatisticsCollection::iterator i)
- { return Pids.erase(i); }
-
- uid_t getUid() { return uid; }
-
- void add(unsigned short size, pid_t pid);
- void subtract(unsigned short size, pid_t pid);
- void sort();
-
- static const pid_t pid_all = (pid_t) -1;
-
- // fast track current value
- size_t sizes() const { return mSizes; };
- size_t elements() const { return mElements; };
-
- // statistical track
- size_t sizes(pid_t pid);
- size_t elements(pid_t pid);
-
- size_t sizesTotal(pid_t pid = pid_all);
- size_t elementsTotal(pid_t pid = pid_all);
-
- // helper
- static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
-};
-
-typedef android::List<UidStatistics *> UidStatisticsCollection;
-
-class LidStatistics {
- UidStatisticsCollection Uids;
-
-public:
- LidStatistics();
- ~LidStatistics();
-
- UidStatisticsCollection::iterator begin() { return Uids.begin(); }
- UidStatisticsCollection::iterator end() { return Uids.end(); }
-
- void add(unsigned short size, uid_t uid, pid_t pid);
- void subtract(unsigned short size, uid_t uid, pid_t pid);
- void sort();
-
- static const pid_t pid_all = (pid_t) -1;
- static const uid_t uid_all = (uid_t) -1;
-
- size_t sizes(uid_t uid = uid_all, pid_t pid = pid_all);
- size_t elements(uid_t uid = uid_all, pid_t pid = pid_all);
-
- size_t sizesTotal(uid_t uid = uid_all, pid_t pid = pid_all);
- size_t elementsTotal(uid_t uid = uid_all, pid_t pid = pid_all);
+ inline const uid_t&getKey() const { return uid; }
+ size_t getSizes() const { return size; }
+ inline void add(size_t s) { size += s; }
+ inline bool subtract(size_t s) { size -= s; return !size; }
};
// Log Statistics
class LogStatistics {
- LidStatistics LogIds[LOG_ID_MAX];
-
size_t mSizes[LOG_ID_MAX];
size_t mElements[LOG_ID_MAX];
+ size_t mSizesTotal[LOG_ID_MAX];
+ size_t mElementsTotal[LOG_ID_MAX];
- bool mStatistics;
-
- static const unsigned short mBuckets[14];
- log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])];
+ // uid to size list
+ typedef android::BasicHashtable<uid_t, UidEntry> uidTable_t;
+ uidTable_t uidTable[LOG_ID_MAX];
public:
- const log_time start;
-
LogStatistics();
- LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
+ void enableStatistics() { }
- void enableStatistics() { mStatistics = true; }
+ void add(LogBufferElement *entry);
+ void subtract(LogBufferElement *entry);
- void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
- void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
- void sort();
+ // Caller must delete array
+ const UidEntry **sort(size_t n, log_id i);
// fast track current value by id only
size_t sizes(log_id_t id) const { return mSizes[id]; }
size_t elements(log_id_t id) const { return mElements[id]; }
-
- // statistical track
- static const log_id_t log_id_all = (log_id_t) -1;
- static const uid_t uid_all = (uid_t) -1;
- static const pid_t pid_all = (pid_t) -1;
-
- size_t sizes(log_id_t id, uid_t uid, pid_t pid = pid_all);
- size_t elements(log_id_t id, uid_t uid, pid_t pid = pid_all);
- size_t sizes() { return sizes(log_id_all, uid_all); }
- size_t elements() { return elements(log_id_all, uid_all); }
-
- size_t sizesTotal(log_id_t id = log_id_all,
- uid_t uid = uid_all,
- pid_t pid = pid_all);
- size_t elementsTotal(log_id_t id = log_id_all,
- uid_t uid = uid_all,
- pid_t pid = pid_all);
+ size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
+ size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
// *strp = malloc, balance with free
- void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest);
+ void format(char **strp, uid_t uid, unsigned int logMask);
// helper
- static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
+ char *pidToName(pid_t pid);
uid_t pidToUid(pid_t pid);
+ char *uidToName(uid_t uid);
};
#endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 769d651..5f60801 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -61,7 +61,9 @@
int init(char *str);
bool naughty(LogBufferElement *element);
+ bool naughty(void) { return !mNaughty.empty(); }
bool nice(LogBufferElement *element);
+ bool nice(void) { return !mNice.empty(); }
bool worstUidEnabled() const { return mWorstUidEnabled; }
// *strp is malloc'd, use free to release
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 4d50bf0..599236f 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -146,8 +146,6 @@
PERM_ANDROID_OBB,
/* This node is "/Android/media" */
PERM_ANDROID_MEDIA,
- /* This node is "/Android/user" */
- PERM_ANDROID_USER,
} perm_t;
/* Permissions structure to derive */
@@ -250,7 +248,7 @@
__u32 inode_ctr;
Hashmap* package_to_appid;
- Hashmap* appid_with_rw;
+ Hashmap* uid_with_rw;
};
/* Private data used by a single fuse handler. */
@@ -472,6 +470,7 @@
/* Legacy internal layout places users at top level */
node->perm = PERM_ROOT;
node->userid = strtoul(node->name, NULL, 10);
+ node->gid = multiuser_get_uid(node->userid, AID_SDCARD_R);
break;
case PERM_ROOT:
/* Assume masked off by default. */
@@ -483,14 +482,14 @@
} else if (fuse->split_perms) {
if (!strcasecmp(node->name, "DCIM")
|| !strcasecmp(node->name, "Pictures")) {
- node->gid = AID_SDCARD_PICS;
+ node->gid = multiuser_get_uid(node->userid, AID_SDCARD_PICS);
} else if (!strcasecmp(node->name, "Alarms")
|| !strcasecmp(node->name, "Movies")
|| !strcasecmp(node->name, "Music")
|| !strcasecmp(node->name, "Notifications")
|| !strcasecmp(node->name, "Podcasts")
|| !strcasecmp(node->name, "Ringtones")) {
- node->gid = AID_SDCARD_AV;
+ node->gid = multiuser_get_uid(node->userid, AID_SDCARD_AV);
}
}
break;
@@ -510,13 +509,6 @@
/* App-specific directories inside; let anyone traverse */
node->perm = PERM_ANDROID_MEDIA;
node->mode = 0771;
- } else if (!strcasecmp(node->name, "user")) {
- /* User directories must only be accessible to system, protected
- * by sdcard_all. Zygote will bind mount the appropriate user-
- * specific path. */
- node->perm = PERM_ANDROID_USER;
- node->gid = AID_SDCARD_ALL;
- node->mode = 0770;
}
break;
case PERM_ANDROID_DATA:
@@ -528,13 +520,6 @@
}
node->mode = 0770;
break;
- case PERM_ANDROID_USER:
- /* Root of a secondary user */
- node->perm = PERM_ROOT;
- node->userid = strtoul(node->name, NULL, 10);
- node->gid = AID_SDCARD_R;
- node->mode = 0771;
- break;
}
}
@@ -545,8 +530,7 @@
return true;
}
- appid_t appid = multiuser_get_app_id(hdr->uid);
- return hashmapContainsKey(fuse->appid_with_rw, (void*) (uintptr_t) appid);
+ return hashmapContainsKey(fuse->uid_with_rw, (void*) (uintptr_t) hdr->uid);
}
/* Kernel has already enforced everything we returned through
@@ -725,7 +709,7 @@
}
static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
- gid_t write_gid, derive_t derive, bool split_perms) {
+ gid_t write_gid, userid_t owner_user, derive_t derive, bool split_perms) {
pthread_mutex_init(&fuse->lock, NULL);
fuse->fd = fd;
@@ -760,7 +744,7 @@
fuse->root.mode = 0771;
fuse->root.gid = AID_SDCARD_R;
fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
- fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
+ fuse->uid_with_rw = hashmapCreate(128, int_hash, int_equals);
snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/obb", source_path);
fs_prepare_dir(fuse->obbpath, 0775, getuid(), getgid());
break;
@@ -769,9 +753,10 @@
* /Android/user and shared OBB path under /Android/obb. */
fuse->root.perm = PERM_ROOT;
fuse->root.mode = 0771;
- fuse->root.gid = AID_SDCARD_R;
+ fuse->root.userid = owner_user;
+ fuse->root.gid = multiuser_get_uid(owner_user, AID_SDCARD_R);
fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
- fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
+ fuse->uid_with_rw = hashmapCreate(128, int_hash, int_equals);
snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/Android/obb", source_path);
break;
}
@@ -1692,7 +1677,7 @@
pthread_mutex_lock(&fuse->lock);
hashmapForEach(fuse->package_to_appid, remove_str_to_int, fuse->package_to_appid);
- hashmapForEach(fuse->appid_with_rw, remove_int_to_null, fuse->appid_with_rw);
+ hashmapForEach(fuse->uid_with_rw, remove_int_to_null, fuse->uid_with_rw);
FILE* file = fopen(kPackagesListFile, "r");
if (!file) {
@@ -1713,9 +1698,14 @@
char* token = strtok(gids, ",");
while (token != NULL) {
- if (strtoul(token, NULL, 10) == fuse->write_gid) {
- hashmapPut(fuse->appid_with_rw, (void*) (uintptr_t) appid, (void*) (uintptr_t) 1);
- break;
+ // Current packages.list format is a bit funky; it blends per
+ // user GID membership into a single per-app line. Here we
+ // work backwards from the groups to build the per-user UIDs
+ // that have write permission.
+ gid_t gid = strtoul(token, NULL, 10);
+ if (multiuser_get_app_id(gid) == fuse->write_gid) {
+ uid_t uid = multiuser_get_uid(multiuser_get_user_id(gid), appid);
+ hashmapPut(fuse->uid_with_rw, (void*) (uintptr_t) uid, (void*) (uintptr_t) 1);
}
token = strtok(NULL, ",");
}
@@ -1724,7 +1714,7 @@
TRACE("read_package_list: found %zu packages, %zu with write_gid\n",
hashmapSize(fuse->package_to_appid),
- hashmapSize(fuse->appid_with_rw));
+ hashmapSize(fuse->uid_with_rw));
fclose(file);
pthread_mutex_unlock(&fuse->lock);
return 0;
@@ -1849,7 +1839,7 @@
}
static int run(const char* source_path, const char* dest_path, uid_t uid,
- gid_t gid, gid_t write_gid, int num_threads, derive_t derive,
+ gid_t gid, gid_t write_gid, userid_t owner_user, int num_threads, derive_t derive,
bool split_perms) {
int fd;
char opts[256];
@@ -1893,7 +1883,7 @@
goto error;
}
- fuse_init(&fuse, fd, source_path, write_gid, derive, split_perms);
+ fuse_init(&fuse, fd, source_path, write_gid, owner_user, derive, split_perms);
umask(0);
res = ignite_fuse(&fuse, num_threads);
@@ -1914,6 +1904,7 @@
uid_t uid = 0;
gid_t gid = 0;
gid_t write_gid = AID_SDCARD_RW;
+ userid_t owner_user = 0;
int num_threads = DEFAULT_NUM_THREADS;
derive_t derive = DERIVE_NONE;
bool split_perms = false;
@@ -1922,7 +1913,7 @@
int fs_version;
int opt;
- while ((opt = getopt(argc, argv, "u:g:w:t:dls")) != -1) {
+ while ((opt = getopt(argc, argv, "u:g:w:o:t:dls")) != -1) {
switch (opt) {
case 'u':
uid = strtoul(optarg, NULL, 10);
@@ -1933,6 +1924,9 @@
case 'w':
write_gid = strtoul(optarg, NULL, 10);
break;
+ case 'o':
+ owner_user = strtoul(optarg, NULL, 10);
+ break;
case 't':
num_threads = strtoul(optarg, NULL, 10);
break;
@@ -1999,6 +1993,7 @@
sleep(1);
}
- res = run(source_path, dest_path, uid, gid, write_gid, num_threads, derive, split_perms);
+ res = run(source_path, dest_path, uid, gid, write_gid, owner_user,
+ num_threads, derive, split_perms);
return res < 0 ? 1 : 0;
}
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 959dc22..9b57d59 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -59,7 +59,6 @@
renice \
restorecon \
route \
- runcon \
sendevent \
setprop \
start \
diff --git a/toolbox/runcon.c b/toolbox/runcon.c
deleted file mode 100644
index 4a57bf3..0000000
--- a/toolbox/runcon.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-
-int runcon_main(int argc, char **argv)
-{
- int rc;
-
- if (argc < 3) {
- fprintf(stderr, "usage: %s context program args...\n", argv[0]);
- exit(1);
- }
-
- rc = setexeccon(argv[1]);
- if (rc < 0) {
- fprintf(stderr, "Could not set context to %s: %s\n", argv[1], strerror(errno));
- exit(2);
- }
-
- argv += 2;
- argc -= 2;
- execvp(argv[0], argv);
- fprintf(stderr, "Could not exec %s: %s\n", argv[0], strerror(errno));
- exit(3);
-}
diff --git a/toolbox/uptime.c b/toolbox/uptime.c
index 2dd8084..ebfb15e 100644
--- a/toolbox/uptime.c
+++ b/toolbox/uptime.c
@@ -29,71 +29,33 @@
* SUCH DAMAGE.
*/
-#include <sys/time.h>
-#include <linux/ioctl.h>
-#include <linux/rtc.h>
-#include <linux/android_alarm.h>
-#include <fcntl.h>
+#include <errno.h>
#include <stdio.h>
+#include <string.h>
#include <time.h>
-#include <unistd.h>
static void format_time(int time, char* buffer) {
- int seconds, minutes, hours, days;
-
- seconds = time % 60;
+ int seconds = time % 60;
time /= 60;
- minutes = time % 60;
+ int minutes = time % 60;
time /= 60;
- hours = time % 24;
- days = time / 24;
+ int hours = time % 24;
+ int days = time / 24;
- if (days > 0)
- sprintf(buffer, "%d days, %02d:%02d:%02d", days, hours, minutes, seconds);
- else
+ if (days > 0) {
+ sprintf(buffer, "%d day%s, %02d:%02d:%02d", days, (days == 1) ? "" : "s", hours, minutes, seconds);
+ } else {
sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
+ }
}
-static int elapsedRealtimeAlarm(struct timespec *ts)
-{
- int fd, result;
-
- fd = open("/dev/alarm", O_RDONLY);
- if (fd < 0)
- return fd;
-
- result = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), ts);
- close(fd);
-
- return result;
-}
-
-int64_t elapsedRealtime()
-{
- struct timespec ts;
-
- int result = elapsedRealtimeAlarm(&ts);
- if (result < 0)
- result = clock_gettime(CLOCK_BOOTTIME, &ts);
-
- if (result == 0)
- return ts.tv_sec;
- return -1;
-}
-
-int uptime_main(int argc __attribute__((unused)),
- char *argv[] __attribute__((unused)))
-{
- float up_time, idle_time;
- char up_string[100], idle_string[100], sleep_string[100];
- int elapsed;
- struct timespec up_timespec;
-
+int uptime_main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {
FILE* file = fopen("/proc/uptime", "r");
if (!file) {
fprintf(stderr, "Could not open /proc/uptime\n");
return -1;
}
+ float idle_time;
if (fscanf(file, "%*f %f", &idle_time) != 1) {
fprintf(stderr, "Could not parse /proc/uptime\n");
fclose(file);
@@ -101,18 +63,21 @@
}
fclose(file);
- if (clock_gettime(CLOCK_MONOTONIC, &up_timespec) < 0) {
- fprintf(stderr, "Could not get monotonic time\n");
+ struct timespec up_timespec;
+ if (clock_gettime(CLOCK_MONOTONIC, &up_timespec) == -1) {
+ fprintf(stderr, "Could not get monotonic time: %s\n", strerror(errno));
return -1;
}
- up_time = up_timespec.tv_sec + up_timespec.tv_nsec / 1e9;
+ float up_time = up_timespec.tv_sec + up_timespec.tv_nsec / 1e9;
- elapsed = elapsedRealtime();
- if (elapsed < 0) {
- fprintf(stderr, "elapsedRealtime failed\n");
+ struct timespec elapsed_timespec;
+ if (clock_gettime(CLOCK_BOOTTIME, &elapsed_timespec) == -1) {
+ fprintf(stderr, "Could not get boot time: %s\n", strerror(errno));
return -1;
}
+ int elapsed = elapsed_timespec.tv_sec;
+ char up_string[100], idle_string[100], sleep_string[100];
format_time(elapsed, up_string);
format_time((int)idle_time, idle_string);
format_time((int)(elapsed - up_time), sleep_string);