logd: refactor LastLogTimes a bit
There's still plenty of work that can be done here, particularly
re-doing the locking so each LogReaderThread does not mutually exclude
the others, but that's out of the scope here.
This change primarily removes the public 'mTimes' from LogBuffer and
creates a new LogReaderList class instead. It would have merged this
into LogReader, but that creates a circular dependency.
This change also removes the need to reference LogReader or
LogReaderList from LogAudit, LogKLog, and LogListener, instead relying
on LogBuffer()::log() to call LogReaderList::NotifyNewLog().
Test: logging unit tests
Change-Id: Ia874b57a9ec1254af1295bfa6f7af2f92a75755b
diff --git a/logd/Android.bp b/logd/Android.bp
index 3df59f5..4f1b2b2 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -36,6 +36,7 @@
"CommandListener.cpp",
"LogListener.cpp",
"LogReader.cpp",
+ "LogReaderList.cpp",
"LogReaderThread.cpp",
"LogBuffer.cpp",
"LogBufferElement.cpp",
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 6c42a28..520acaf 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -37,7 +37,6 @@
#include <private/android_logger.h>
#include "LogKlog.h"
-#include "LogReader.h"
#include "LogUtils.h"
#include "libaudit.h"
@@ -45,10 +44,9 @@
'<', '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
'0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>'
-LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg, LogStatistics* stats)
+LogAudit::LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats)
: SocketListener(getLogSocket(), false),
logbuf(buf),
- reader(reader),
fdDmesg(fdDmesg),
main(__android_logger_property_get_bool("ro.logd.auditd.main", BOOL_DEFAULT_TRUE)),
events(__android_logger_property_get_bool("ro.logd.auditd.events", BOOL_DEFAULT_TRUE)),
@@ -344,7 +342,6 @@
free(str);
if (notify) {
- reader->notifyNewLog(notify);
if (rc < 0) {
rc = message_len;
}
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index ee6e579..181920e 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -23,18 +23,15 @@
#include "LogBuffer.h"
#include "LogStatistics.h"
-class LogReader;
-
class LogAudit : public SocketListener {
LogBuffer* logbuf;
- LogReader* reader;
int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
bool main;
bool events;
bool initialized;
public:
- LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg, LogStatistics* stats);
+ LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats);
int log(char* buf, size_t len);
protected:
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 4fce751..bb54a5a 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -51,20 +51,15 @@
}
}
// Release any sleeping reader threads to dump their current content.
- LogReaderThread::wrlock();
-
- LastLogTimes::iterator times = mTimes.begin();
- while (times != mTimes.end()) {
- LogReaderThread* entry = times->get();
- entry->triggerReader_Locked();
- times++;
+ auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
+ for (const auto& reader_thread : reader_list_->reader_threads()) {
+ reader_thread->triggerReader_Locked();
}
-
- LogReaderThread::unlock();
}
-LogBuffer::LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune, LogStatistics* stats)
- : mTimes(*times), tags_(tags), prune_(prune), stats_(stats) {
+LogBuffer::LogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune,
+ LogStatistics* stats)
+ : reader_list_(reader_list), tags_(tags), prune_(prune), stats_(stats) {
pthread_rwlock_init(&mLogElementsLock, nullptr);
log_id_for_each(i) {
@@ -355,6 +350,7 @@
mLogElements.push_back(elem);
stats_->Add(elem);
maybePrune(elem->getLogId());
+ reader_list_->NotifyNewLog(1 << elem->getLogId());
}
// LogBuffer::wrlock() must be held when this function is called.
@@ -523,9 +519,8 @@
android::prdebug("Kicking blocked reader, pid %d, from LogBuffer::kickMe()\n",
me->client()->getPid());
me->release_Locked();
- } else if (me->timeout().tv_sec || me->timeout().tv_nsec) {
- // Allow a blocked WRAP timeout reader to
- // trigger and start reporting the log data.
+ } else if (me->deadline().time_since_epoch().count() != 0) {
+ // Allow a blocked WRAP deadline reader to trigger and start reporting the log data.
me->triggerReader_Locked();
} else {
// tell slow reader to skip entries to catch up
@@ -588,18 +583,18 @@
bool busy = false;
bool clearAll = pruneRows == ULONG_MAX;
- LogReaderThread::rdlock();
+ auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
// Region locked?
- LastLogTimes::iterator times = mTimes.begin();
- while (times != mTimes.end()) {
- LogReaderThread* entry = times->get();
- if (entry->IsWatching(id) && (!oldest || oldest->start() > entry->start() ||
- (oldest->start() == entry->start() &&
- (entry->timeout().tv_sec || entry->timeout().tv_nsec)))) {
- oldest = entry;
+ for (const auto& reader_thread : reader_list_->reader_threads()) {
+ if (!reader_thread->IsWatching(id)) {
+ continue;
}
- times++;
+ if (!oldest || oldest->start() > reader_thread->start() ||
+ (oldest->start() == reader_thread->start() &&
+ reader_thread->deadline().time_since_epoch().count() != 0)) {
+ oldest = reader_thread.get();
+ }
}
LogBufferElementCollection::iterator it;
@@ -628,7 +623,6 @@
break;
}
}
- LogReaderThread::unlock();
return busy;
}
@@ -884,8 +878,6 @@
}
}
- LogReaderThread::unlock();
-
return (pruneRows > 0) && busy;
}
@@ -907,20 +899,15 @@
// readers and let the clear run (below) deal with determining
// if we are still blocked and return an error code to caller.
if (busy) {
- LogReaderThread::wrlock();
- LastLogTimes::iterator times = mTimes.begin();
- while (times != mTimes.end()) {
- LogReaderThread* entry = times->get();
- // Killer punch
- if (entry->IsWatching(id)) {
+ auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
+ for (const auto& reader_thread : reader_list_->reader_threads()) {
+ if (reader_thread->IsWatching(id)) {
android::prdebug(
"Kicking blocked reader, pid %d, from LogBuffer::clear()\n",
- entry->client()->getPid());
- entry->release_Locked();
+ reader_thread->client()->getPid());
+ reader_thread->release_Locked();
}
- times++;
}
- LogReaderThread::unlock();
}
}
wrlock();
@@ -954,9 +941,9 @@
return retval;
}
-uint64_t LogBuffer::flushTo(SocketClient* reader, uint64_t start, pid_t* lastTid, bool privileged,
- bool security,
- const std::function<int(const LogBufferElement* element)>& filter) {
+uint64_t LogBuffer::flushTo(
+ SocketClient* reader, uint64_t start, pid_t* lastTid, bool privileged, bool security,
+ const std::function<FlushToResult(const LogBufferElement* element)>& filter) {
LogBufferElementCollection::iterator it;
uid_t uid = reader->getUid();
@@ -994,11 +981,11 @@
// NB: calling out to another object with wrlock() held (safe)
if (filter) {
- int ret = filter(element);
- if (ret == false) {
+ FlushToResult ret = filter(element);
+ if (ret == FlushToResult::kSkip) {
continue;
}
- if (ret != true) {
+ if (ret == FlushToResult::kStop) {
break;
}
}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 3c1ea5a..efcd2af 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -27,13 +27,21 @@
#include <sysutils/SocketClient.h>
#include "LogBufferElement.h"
-#include "LogReaderThread.h"
#include "LogStatistics.h"
#include "LogTags.h"
#include "LogWhiteBlackList.h"
typedef std::list<LogBufferElement*> LogBufferElementCollection;
+class LogReaderList;
+class LogReaderThread;
+
+enum class FlushToResult {
+ kSkip,
+ kStop,
+ kWrite,
+};
+
class LogBuffer {
LogBufferElementCollection mLogElements;
pthread_rwlock_t mLogElementsLock;
@@ -53,10 +61,8 @@
LogBufferElement* droppedElements[LOG_ID_MAX];
void log(LogBufferElement* elem);
- public:
- LastLogTimes& mTimes;
-
- LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune, LogStatistics* stats);
+ public:
+ LogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune, LogStatistics* stats);
~LogBuffer();
void init();
@@ -68,7 +74,7 @@
uint64_t flushTo(SocketClient* writer, uint64_t start,
pid_t* lastTid, // &lastTid[LOG_ID_MAX] or nullptr
bool privileged, bool security,
- const std::function<int(const LogBufferElement* element)>& filter);
+ const std::function<FlushToResult(const LogBufferElement* element)>& filter);
bool clear(log_id_t id, uid_t uid = AID_ROOT);
unsigned long getSize(log_id_t id);
@@ -96,6 +102,7 @@
// there are no logs for the given log type. Requires mLogElementsLock to be held.
LogBufferElementCollection::iterator GetOldest(log_id_t log_id);
+ LogReaderList* reader_list_;
LogTags* tags_;
PruneList* prune_;
LogStatistics* stats_;
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index bc94b45..5242dc3 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -31,7 +31,6 @@
#include <private/android_logger.h>
#include "LogBuffer.h"
-#include "LogReader.h"
#define KMSG_PRIORITY(PRI) \
'<', '0' + (LOG_SYSLOG | (PRI)) / 10, '0' + (LOG_SYSLOG | (PRI)) % 10, '>'
@@ -202,11 +201,9 @@
? log_time(log_time::EPOCH)
: (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
-LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead, bool auditd,
- LogStatistics* stats)
+LogKlog::LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats)
: SocketListener(fdRead, false),
logbuf(buf),
- reader(reader),
signature(CLOCK_MONOTONIC),
initialized(false),
enableLogging(true),
@@ -772,10 +769,5 @@
// Log message
int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n);
- // notify readers
- if (rc > 0) {
- reader->notifyNewLog(static_cast<unsigned int>(1 << LOG_ID_KERNEL));
- }
-
return rc;
}
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index a7dbe64..77b24bc 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -22,11 +22,9 @@
#include "LogStatistics.h"
class LogBuffer;
-class LogReader;
class LogKlog : public SocketListener {
LogBuffer* logbuf;
- LogReader* reader;
const log_time signature;
// Set once thread is started, separates KLOG_ACTION_READ_ALL
// and KLOG_ACTION_READ phases.
@@ -40,8 +38,7 @@
static log_time correction;
public:
- LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead, bool auditd,
- LogStatistics* stats);
+ LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats);
int log(const char* buf, ssize_t len);
static void convertMonotonicToReal(log_time& real) { real += correction; }
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index fbe6ea0..2057886 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -32,8 +32,7 @@
#include "LogListener.h"
#include "LogUtils.h"
-LogListener::LogListener(LogBuffer* buf, LogReader* reader)
- : socket_(GetLogSocket()), logbuf_(buf), reader_(reader) {}
+LogListener::LogListener(LogBuffer* buf) : socket_(GetLogSocket()), logbuf_(buf) {}
bool LogListener::StartListener() {
if (socket_ <= 0) {
@@ -121,13 +120,8 @@
// NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
// truncated message to the logs.
- int res = logbuf_->log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
- ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
- if (res > 0) {
- reader_->notifyNewLog(static_cast<unsigned int>(1 << logId));
- }
-
- return;
+ logbuf_->log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
+ ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
}
int LogListener::GetLogSocket() {
diff --git a/logd/LogListener.h b/logd/LogListener.h
index ce3e0f2..d468df8 100644
--- a/logd/LogListener.h
+++ b/logd/LogListener.h
@@ -21,7 +21,7 @@
class LogListener {
public:
- LogListener(LogBuffer* buf, LogReader* reader);
+ LogListener(LogBuffer* buf);
bool StartListener();
private:
@@ -31,5 +31,4 @@
int socket_;
LogBuffer* logbuf_;
- LogReader* reader_;
};
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index a590cef..cc51542 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -21,6 +21,8 @@
#include <sys/socket.h>
#include <sys/types.h>
+#include <chrono>
+
#include <cutils/sockets.h>
#include <private/android_logger.h>
@@ -33,27 +35,8 @@
return client->getUid() == AID_SYSTEM || client->getGid() == AID_SYSTEM;
}
-LogReader::LogReader(LogBuffer* logbuf)
- : SocketListener(getLogSocket(), true), mLogbuf(*logbuf) {
-}
-
-// When we are notified a new log entry is available, inform
-// listening sockets who are watching this entry's log id.
-void LogReader::notifyNewLog(unsigned int log_mask) {
- LastLogTimes& times = mLogbuf.mTimes;
-
- LogReaderThread::wrlock();
- for (const auto& entry : times) {
- if (!entry->IsWatchingMultiple(log_mask)) {
- continue;
- }
- if (entry->timeout().tv_sec || entry->timeout().tv_nsec) {
- continue;
- }
- entry->triggerReader_Locked();
- }
- LogReaderThread::unlock();
-}
+LogReader::LogReader(LogBuffer* logbuf, LogReaderList* reader_list)
+ : SocketListener(getLogSocket(), true), log_buffer_(logbuf), reader_list_(reader_list) {}
// Note returning false will release the SocketClient instance.
bool LogReader::onDataAvailable(SocketClient* cli) {
@@ -74,15 +57,15 @@
// Clients are only allowed to send one command, disconnect them if they
// send another.
- LogReaderThread::wrlock();
- for (const auto& entry : mLogbuf.mTimes) {
- if (entry->client() == cli) {
- entry->release_Locked();
- LogReaderThread::unlock();
- return false;
+ {
+ auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
+ for (const auto& entry : reader_list_->reader_threads()) {
+ if (entry->client() == cli) {
+ entry->release_Locked();
+ return false;
+ }
}
}
- LogReaderThread::unlock();
unsigned long tail = 0;
static const char _tail[] = " tail=";
@@ -99,11 +82,12 @@
start.strptime(cp + sizeof(_start) - 1, "%s.%q");
}
- uint64_t timeout = 0;
+ std::chrono::steady_clock::time_point deadline = {};
static const char _timeout[] = " timeout=";
cp = strstr(buffer, _timeout);
if (cp) {
- timeout = atol(cp + sizeof(_timeout) - 1) * NS_PER_SEC + log_time(CLOCK_MONOTONIC).nsec();
+ long timeout_seconds = atol(cp + sizeof(_timeout) - 1);
+ deadline = std::chrono::steady_clock::now() + std::chrono::seconds(timeout_seconds);
}
unsigned int logMask = -1;
@@ -137,8 +121,8 @@
if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
// Allow writer to get some cycles, and wait for pending notifications
sched_yield();
- LogReaderThread::wrlock();
- LogReaderThread::unlock();
+ reader_list_->reader_threads_lock().lock();
+ reader_list_->reader_threads_lock().unlock();
sched_yield();
nonBlock = true;
}
@@ -152,29 +136,29 @@
bool start_time_set = false;
uint64_t last = sequence;
auto log_find_start = [pid, logMask, start, &sequence, &start_time_set,
- &last](const LogBufferElement* element) -> int {
+ &last](const LogBufferElement* element) -> FlushToResult {
if (pid && pid != element->getPid()) {
- return 0;
+ return FlushToResult::kSkip;
}
if ((logMask & (1 << element->getLogId())) == 0) {
- return 0;
+ return FlushToResult::kSkip;
}
if (start == element->getRealTime()) {
sequence = element->getSequence();
start_time_set = true;
- return -1;
+ return FlushToResult::kStop;
} else {
if (start < element->getRealTime()) {
sequence = last;
start_time_set = true;
- return -1;
+ return FlushToResult::kStop;
}
last = element->getSequence();
}
- return 0;
+ return FlushToResult::kSkip;
};
- logbuf().flushTo(cli, sequence, nullptr, privileged, can_read_security, log_find_start);
+ log_buffer_->flushTo(cli, sequence, nullptr, privileged, can_read_security, log_find_start);
if (!start_time_set) {
if (nonBlock) {
@@ -187,42 +171,38 @@
android::prdebug(
"logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d "
- "start=%" PRIu64 "ns timeout=%" PRIu64 "ns\n",
+ "start=%" PRIu64 "ns deadline=%" PRIi64 "ns\n",
cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail, logMask,
- (int)pid, start.nsec(), timeout);
+ (int)pid, start.nsec(), static_cast<int64_t>(deadline.time_since_epoch().count()));
if (start == log_time::EPOCH) {
- timeout = 0;
+ deadline = {};
}
- LogReaderThread::wrlock();
- auto entry =
- std::make_unique<LogReaderThread>(*this, cli, nonBlock, tail, logMask, pid, start,
- sequence, timeout, privileged, can_read_security);
+ auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
+ auto entry = std::make_unique<LogReaderThread>(*this, *reader_list_, cli, nonBlock, tail,
+ logMask, pid, start, sequence, deadline,
+ privileged, can_read_security);
if (!entry->startReader_Locked()) {
- LogReaderThread::unlock();
return false;
}
// release client and entry reference counts once done
cli->incRef();
- mLogbuf.mTimes.emplace_front(std::move(entry));
+ reader_list_->reader_threads().emplace_front(std::move(entry));
// Set acceptable upper limit to wait for slow reader processing b/27242723
struct timeval t = { LOGD_SNDTIMEO, 0 };
setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
sizeof(t));
- LogReaderThread::unlock();
-
return true;
}
void LogReader::doSocketDelete(SocketClient* cli) {
- LastLogTimes& times = mLogbuf.mTimes;
- LogReaderThread::wrlock();
- LastLogTimes::iterator it = times.begin();
- while (it != times.end()) {
+ auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
+ auto it = reader_list_->reader_threads().begin();
+ while (it != reader_list_->reader_threads().end()) {
LogReaderThread* entry = it->get();
if (entry->client() == cli) {
entry->release_Locked();
@@ -230,7 +210,6 @@
}
it++;
}
- LogReaderThread::unlock();
}
int LogReader::getLogSocket() {
diff --git a/logd/LogReader.h b/logd/LogReader.h
index f00cc21..7df3f6b 100644
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -18,6 +18,7 @@
#include <sysutils/SocketListener.h>
+#include "LogReaderList.h"
#include "LogReaderThread.h"
#define LOGD_SNDTIMEO 32
@@ -25,21 +26,19 @@
class LogBuffer;
class LogReader : public SocketListener {
- LogBuffer& mLogbuf;
+ public:
+ explicit LogReader(LogBuffer* logbuf, LogReaderList* reader_list);
- public:
- explicit LogReader(LogBuffer* logbuf);
- void notifyNewLog(unsigned int logMask);
+ LogBuffer* log_buffer() const { return log_buffer_; }
- LogBuffer& logbuf(void) const {
- return mLogbuf;
- }
-
- protected:
+ protected:
virtual bool onDataAvailable(SocketClient* cli);
- private:
+ private:
static int getLogSocket();
void doSocketDelete(SocketClient* cli);
+
+ LogBuffer* log_buffer_;
+ LogReaderList* reader_list_;
};
diff --git a/logd/LogReaderList.cpp b/logd/LogReaderList.cpp
new file mode 100644
index 0000000..220027b
--- /dev/null
+++ b/logd/LogReaderList.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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 "LogReaderList.h"
+
+// When we are notified a new log entry is available, inform
+// listening sockets who are watching this entry's log id.
+void LogReaderList::NotifyNewLog(unsigned int log_mask) const {
+ auto lock = std::lock_guard{reader_threads_lock_};
+
+ for (const auto& entry : reader_threads_) {
+ if (!entry->IsWatchingMultiple(log_mask)) {
+ continue;
+ }
+ if (entry->deadline().time_since_epoch().count() != 0) {
+ continue;
+ }
+ entry->triggerReader_Locked();
+ }
+}
diff --git a/logd/LogReaderList.h b/logd/LogReaderList.h
new file mode 100644
index 0000000..0d84aba
--- /dev/null
+++ b/logd/LogReaderList.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <list>
+#include <memory>
+#include <mutex>
+
+#include "LogReaderThread.h"
+
+class LogReaderList {
+ public:
+ void NotifyNewLog(unsigned int log_mask) const;
+
+ std::list<std::unique_ptr<LogReaderThread>>& reader_threads() { return reader_threads_; }
+ std::mutex& reader_threads_lock() { return reader_threads_lock_; }
+
+ private:
+ std::list<std::unique_ptr<LogReaderThread>> reader_threads_;
+ mutable std::mutex reader_threads_lock_;
+};
\ No newline at end of file
diff --git a/logd/LogReaderThread.cpp b/logd/LogReaderThread.cpp
index 5413c4d..4889c24 100644
--- a/logd/LogReaderThread.cpp
+++ b/logd/LogReaderThread.cpp
@@ -27,14 +27,14 @@
using namespace std::placeholders;
-pthread_mutex_t LogReaderThread::timesLock = PTHREAD_MUTEX_INITIALIZER;
-
-LogReaderThread::LogReaderThread(LogReader& reader, SocketClient* client, bool non_block,
- unsigned long tail, unsigned int log_mask, pid_t pid,
- log_time start_time, uint64_t start, uint64_t timeout,
+LogReaderThread::LogReaderThread(LogReader& reader, LogReaderList& reader_list,
+ SocketClient* client, bool non_block, unsigned long tail,
+ unsigned int log_mask, pid_t pid, log_time start_time,
+ uint64_t start, std::chrono::steady_clock::time_point deadline,
bool privileged, bool can_read_security_logs)
: leading_dropped_(false),
reader_(reader),
+ reader_list_(reader_list),
log_mask_(log_mask),
pid_(pid),
tail_(tail),
@@ -43,13 +43,11 @@
client_(client),
start_time_(start_time),
start_(start),
+ deadline_(deadline),
non_block_(non_block),
privileged_(privileged),
can_read_security_logs_(can_read_security_logs) {
- timeout_.tv_sec = timeout / NS_PER_SEC;
- timeout_.tv_nsec = timeout % NS_PER_SEC;
memset(last_tid_, 0, sizeof(last_tid_));
- pthread_cond_init(&thread_triggered_condition_, nullptr);
cleanSkip_Locked();
}
@@ -64,27 +62,26 @@
SocketClient* client = client_;
- LogBuffer& logbuf = reader_.logbuf();
+ LogBuffer& logbuf = *reader_.log_buffer();
leading_dropped_ = true;
- wrlock();
+ auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
uint64_t start = start_;
while (!release_) {
- if (timeout_.tv_sec || timeout_.tv_nsec) {
- if (pthread_cond_clockwait(&thread_triggered_condition_, ×Lock, CLOCK_MONOTONIC,
- &timeout_) == ETIMEDOUT) {
- timeout_.tv_sec = 0;
- timeout_.tv_nsec = 0;
+ if (deadline_.time_since_epoch().count() != 0) {
+ if (thread_triggered_condition_.wait_until(lock, deadline_) ==
+ std::cv_status::timeout) {
+ deadline_ = {};
}
if (release_) {
break;
}
}
- unlock();
+ lock.unlock();
if (tail_) {
logbuf.flushTo(client, start, nullptr, privileged_, can_read_security_logs_,
@@ -105,7 +102,7 @@
start_time_.tv_sec = 0;
start_time_.tv_nsec = 0;
- wrlock();
+ lock.lock();
if (start == LogBufferElement::FLUSH_ERROR) {
break;
@@ -119,35 +116,30 @@
cleanSkip_Locked();
- if (!timeout_.tv_sec && !timeout_.tv_nsec) {
- pthread_cond_wait(&thread_triggered_condition_, ×Lock);
+ if (deadline_.time_since_epoch().count() == 0) {
+ thread_triggered_condition_.wait(lock);
}
}
- LogReader& reader = reader_;
- reader.release(client);
-
+ reader_.release(client);
client->decRef();
- LastLogTimes& times = reader.logbuf().mTimes;
- auto it = std::find_if(times.begin(), times.end(),
+ auto& log_reader_threads = reader_list_.reader_threads();
+ auto it = std::find_if(log_reader_threads.begin(), log_reader_threads.end(),
[this](const auto& other) { return other.get() == this; });
- if (it != times.end()) {
- times.erase(it);
+ if (it != log_reader_threads.end()) {
+ log_reader_threads.erase(it);
}
-
- unlock();
}
// A first pass to count the number of elements
-int LogReaderThread::FilterFirstPass(const LogBufferElement* element) {
- LogReaderThread::wrlock();
+FlushToResult LogReaderThread::FilterFirstPass(const LogBufferElement* element) {
+ auto lock = std::lock_guard{reader_list_.reader_threads_lock()};
if (leading_dropped_) {
if (element->getDropped()) {
- LogReaderThread::unlock();
- return false;
+ return FlushToResult::kSkip;
}
leading_dropped_ = false;
}
@@ -161,48 +153,46 @@
++count_;
}
- LogReaderThread::unlock();
-
- return false;
+ return FlushToResult::kSkip;
}
// A second pass to send the selected elements
-int LogReaderThread::FilterSecondPass(const LogBufferElement* element) {
- LogReaderThread::wrlock();
+FlushToResult LogReaderThread::FilterSecondPass(const LogBufferElement* element) {
+ auto lock = std::lock_guard{reader_list_.reader_threads_lock()};
start_ = element->getSequence();
if (skip_ahead_[element->getLogId()]) {
skip_ahead_[element->getLogId()]--;
- goto skip;
+ return FlushToResult::kSkip;
}
if (leading_dropped_) {
if (element->getDropped()) {
- goto skip;
+ return FlushToResult::kSkip;
}
leading_dropped_ = false;
}
// Truncate to close race between first and second pass
if (non_block_ && tail_ && index_ >= count_) {
- goto stop;
+ return FlushToResult::kStop;
}
if (!IsWatching(element->getLogId())) {
- goto skip;
+ return FlushToResult::kSkip;
}
if (pid_ && pid_ != element->getPid()) {
- goto skip;
+ return FlushToResult::kSkip;
}
if (start_time_ != log_time::EPOCH && element->getRealTime() <= start_time_) {
- goto skip;
+ return FlushToResult::kSkip;
}
if (release_) {
- goto stop;
+ return FlushToResult::kStop;
}
if (!tail_) {
@@ -212,7 +202,7 @@
++index_;
if (count_ > tail_ && index_ <= (count_ - tail_)) {
- goto skip;
+ return FlushToResult::kSkip;
}
if (!non_block_) {
@@ -221,18 +211,9 @@
ok:
if (!skip_ahead_[element->getLogId()]) {
- LogReaderThread::unlock();
- return true;
+ return FlushToResult::kWrite;
}
- // FALLTHRU
-
-skip:
- LogReaderThread::unlock();
- return false;
-
-stop:
- LogReaderThread::unlock();
- return -1;
+ return FlushToResult::kSkip;
}
void LogReaderThread::cleanSkip_Locked(void) {
diff --git a/logd/LogReaderThread.h b/logd/LogReaderThread.h
index 39a8b63..ce59cbb 100644
--- a/logd/LogReaderThread.h
+++ b/logd/LogReaderThread.h
@@ -21,31 +21,30 @@
#include <sys/types.h>
#include <time.h>
+#include <chrono>
+#include <condition_variable>
#include <list>
#include <memory>
#include <log/log.h>
#include <sysutils/SocketClient.h>
+#include "LogBuffer.h"
+
class LogReader;
class LogBufferElement;
class LogReaderThread {
- static pthread_mutex_t timesLock;
-
public:
- LogReaderThread(LogReader& reader, SocketClient* client, bool non_block, unsigned long tail,
- unsigned int log_mask, pid_t pid, log_time start_time, uint64_t sequence,
- uint64_t timeout, bool privileged, bool can_read_security_logs);
-
- // Protect List manipulations
- static void wrlock() { pthread_mutex_lock(×Lock); }
- static void rdlock() { pthread_mutex_lock(×Lock); }
- static void unlock() { pthread_mutex_unlock(×Lock); }
+ LogReaderThread(LogReader& reader, LogReaderList& reader_list, SocketClient* client,
+ bool non_block, unsigned long tail, unsigned int log_mask, pid_t pid,
+ log_time start_time, uint64_t sequence,
+ std::chrono::steady_clock::time_point deadline, bool privileged,
+ bool can_read_security_logs);
bool startReader_Locked();
- void triggerReader_Locked() { pthread_cond_signal(&thread_triggered_condition_); }
+ void triggerReader_Locked() { thread_triggered_condition_.notify_all(); }
void triggerSkip_Locked(log_id_t id, unsigned int skip) { skip_ahead_[id] = skip; }
void cleanSkip_Locked();
@@ -54,7 +53,7 @@
// gracefully shut down the socket.
shutdown(client_->getSocket(), SHUT_RDWR);
release_ = true;
- pthread_cond_signal(&thread_triggered_condition_);
+ thread_triggered_condition_.notify_all();
}
bool IsWatching(log_id_t id) const { return log_mask_ & (1 << id); }
@@ -62,13 +61,13 @@
const SocketClient* client() const { return client_; }
uint64_t start() const { return start_; }
- const timespec& timeout() const { return timeout_; }
+ std::chrono::steady_clock::time_point deadline() const { return deadline_; }
private:
void ThreadFunction();
// flushTo filter callbacks
- int FilterFirstPass(const LogBufferElement* element);
- int FilterSecondPass(const LogBufferElement* element);
+ FlushToResult FilterFirstPass(const LogBufferElement* element);
+ FlushToResult FilterSecondPass(const LogBufferElement* element);
// Set to true to cause the thread to end and the LogReaderThread to delete itself.
bool release_ = false;
@@ -77,10 +76,12 @@
bool leading_dropped_;
// Condition variable for waking the reader thread if there are messages pending for its client.
- pthread_cond_t thread_triggered_condition_;
+ std::condition_variable thread_triggered_condition_;
// Reference to the parent thread that manages log reader sockets.
LogReader& reader_;
+ // Reference to the parent list that shares its lock with each instance
+ LogReaderList& reader_list_;
// A mask of the logs buffers that are read by this reader.
const unsigned int log_mask_;
// If set to non-zero, only pids equal to this are read by the reader.
@@ -110,9 +111,9 @@
log_time start_time_;
// The point from which the reader will read logs once awoken.
uint64_t start_;
- // CLOCK_MONOTONIC based timeout used for log wrapping. If this timeout expires before logs
+ // CLOCK_MONOTONIC based deadline used for log wrapping. If this deadline expires before logs
// wrap, then wake up and send the logs to the reader anyway.
- timespec timeout_;
+ std::chrono::steady_clock::time_point deadline_;
// If this reader is 'dumpAndClose' and will disconnect once it has read its intended logs.
const bool non_block_;
@@ -122,5 +123,3 @@
// Whether or not this reader can read security logs. See CanReadSecurityLogs().
bool can_read_security_logs_;
};
-
-typedef std::list<std::unique_ptr<LogReaderThread>> LastLogTimes;
diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp
index 58610c4..3a18f25 100644
--- a/logd/fuzz/log_buffer_log_fuzzer.cpp
+++ b/logd/fuzz/log_buffer_log_fuzzer.cpp
@@ -16,6 +16,7 @@
#include <string>
#include "../LogBuffer.h"
+#include "../LogReaderList.h"
#include "../LogReaderThread.h"
#include "../LogStatistics.h"
@@ -95,11 +96,11 @@
return 0;
}
- LastLogTimes times;
+ LogReaderList reader_list;
LogTags tags;
PruneList prune_list;
LogStatistics stats(true);
- LogBuffer log_buffer(×, &tags, &prune_list, &stats);
+ LogBuffer log_buffer(&reader_list, &tags, &prune_list, &stats);
size_t data_left = size;
const uint8_t** pdata = &data;
diff --git a/logd/main.cpp b/logd/main.cpp
index cd8b195..a7b89b8 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -271,8 +271,10 @@
// A cache of event log tags
LogTags log_tags;
+
// Pruning configuration.
PruneList prune_list;
+
// Partial (required for chatty) or full logging statistics.
bool enable_full_log_statistics = __android_logger_property_get_bool(
"logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
@@ -282,18 +284,15 @@
// Serves the purpose of managing the last logs times read on a
// socket connection, and as a reader lock on a range of log
// entries.
-
- LastLogTimes* times = new LastLogTimes();
+ LogReaderList reader_list;
// LogBuffer is the object which is responsible for holding all
// log entries.
-
- LogBuffer* logBuf = new LogBuffer(times, &log_tags, &prune_list, &log_statistics);
+ LogBuffer* logBuf = new LogBuffer(&reader_list, &log_tags, &prune_list, &log_statistics);
// LogReader listens on /dev/socket/logdr. When a client
// connects, log entries in the LogBuffer are written to the client.
-
- LogReader* reader = new LogReader(logBuf);
+ LogReader* reader = new LogReader(logBuf, &reader_list);
if (reader->startListener()) {
return EXIT_FAILURE;
}
@@ -301,15 +300,13 @@
// LogListener listens on /dev/socket/logdw for client
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
-
- LogListener* swl = new LogListener(logBuf, reader);
+ LogListener* swl = new LogListener(logBuf);
if (!swl->StartListener()) {
return EXIT_FAILURE;
}
// Command listener listens on /dev/socket/logd for incoming logd
// administrative commands.
-
CommandListener* cl = new CommandListener(logBuf, &log_tags, &prune_list, &log_statistics);
if (cl->startListener()) {
return EXIT_FAILURE;
@@ -318,26 +315,22 @@
// LogAudit listens on NETLINK_AUDIT socket for selinux
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
-
LogAudit* al = nullptr;
if (auditd) {
- al = new LogAudit(
- logBuf, reader,
- __android_logger_property_get_bool("ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
- ? fdDmesg
- : -1,
- &log_statistics);
+ int dmesg_fd = __android_logger_property_get_bool("ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
+ ? fdDmesg
+ : -1;
+ al = new LogAudit(logBuf, dmesg_fd, &log_statistics);
}
LogKlog* kl = nullptr;
if (klogd) {
- kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr, &log_statistics);
+ kl = new LogKlog(logBuf, fdDmesg, fdPmesg, al != nullptr, &log_statistics);
}
readDmesg(al, kl);
// failure is an option ... messages are in dmesg (required by standard)
-
if (kl && kl->startListener()) {
delete kl;
}