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
This commit is contained in:
parent
a269c7c3d1
commit
68630a0dbe
17 changed files with 232 additions and 241 deletions
|
@ -36,6 +36,7 @@ cc_library_static {
|
|||
"CommandListener.cpp",
|
||||
"LogListener.cpp",
|
||||
"LogReader.cpp",
|
||||
"LogReaderList.cpp",
|
||||
"LogReaderThread.cpp",
|
||||
"LogBuffer.cpp",
|
||||
"LogBufferElement.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 @@ int LogAudit::logPrint(const char* fmt, ...) {
|
|||
free(str);
|
||||
|
||||
if (notify) {
|
||||
reader->notifyNewLog(notify);
|
||||
if (rc < 0) {
|
||||
rc = message_len;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -51,20 +51,15 @@ void LogBuffer::init() {
|
|||
}
|
||||
}
|
||||
// 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 @@ void LogBuffer::log(LogBufferElement* elem) {
|
|||
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 @@ void LogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows
|
|||
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 LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
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;
|
||||
}
|
||||
if (!oldest || oldest->start() > reader_thread->start() ||
|
||||
(oldest->start() == reader_thread->start() &&
|
||||
reader_thread->deadline().time_since_epoch().count() != 0)) {
|
||||
oldest = reader_thread.get();
|
||||
}
|
||||
times++;
|
||||
}
|
||||
|
||||
LogBufferElementCollection::iterator it;
|
||||
|
@ -628,7 +623,6 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
LogReaderThread::unlock();
|
||||
return busy;
|
||||
}
|
||||
|
||||
|
@ -884,8 +878,6 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
}
|
||||
}
|
||||
|
||||
LogReaderThread::unlock();
|
||||
|
||||
return (pruneRows > 0) && busy;
|
||||
}
|
||||
|
||||
|
@ -907,20 +899,15 @@ bool LogBuffer::clear(log_id_t id, uid_t uid) {
|
|||
// 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 @@ unsigned long LogBuffer::getSize(log_id_t id) {
|
|||
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 @@ uint64_t LogBuffer::flushTo(SocketClient* reader, uint64_t start, pid_t* lastTid
|
|||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 @@ class LogBuffer {
|
|||
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 @@ class LogBuffer {
|
|||
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 @@ class LogBuffer {
|
|||
// 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_;
|
||||
|
|
|
@ -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 LogKlog::correction = (log_time(CLOCK_REALTIME) < log_time(CLOCK_MONOTO
|
|||
? 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 @@ int LogKlog::log(const char* buf, ssize_t len) {
|
|||
// 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;
|
||||
}
|
||||
|
|
|
@ -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 @@ class LogKlog : public SocketListener {
|
|||
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; }
|
||||
|
|
|
@ -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 @@ void LogListener::HandleData() {
|
|||
// 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() {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
class LogListener {
|
||||
public:
|
||||
LogListener(LogBuffer* buf, LogReader* reader);
|
||||
LogListener(LogBuffer* buf);
|
||||
bool StartListener();
|
||||
|
||||
private:
|
||||
|
@ -31,5 +31,4 @@ class LogListener {
|
|||
|
||||
int socket_;
|
||||
LogBuffer* logbuf_;
|
||||
LogReader* reader_;
|
||||
};
|
||||
|
|
|
@ -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 @@ static bool CanReadSecurityLogs(SocketClient* client) {
|
|||
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 @@ bool LogReader::onDataAvailable(SocketClient* cli) {
|
|||
|
||||
// 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 @@ bool LogReader::onDataAvailable(SocketClient* cli) {
|
|||
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 @@ bool LogReader::onDataAvailable(SocketClient* cli) {
|
|||
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 LogReader::onDataAvailable(SocketClient* cli) {
|
|||
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 @@ bool LogReader::onDataAvailable(SocketClient* cli) {
|
|||
|
||||
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 @@ void LogReader::doSocketDelete(SocketClient* cli) {
|
|||
}
|
||||
it++;
|
||||
}
|
||||
LogReaderThread::unlock();
|
||||
}
|
||||
|
||||
int LogReader::getLogSocket() {
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
|
33
logd/LogReaderList.cpp
Normal file
33
logd/LogReaderList.cpp
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
35
logd/LogReaderList.h
Normal file
35
logd/LogReaderList.h
Normal file
|
@ -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_;
|
||||
};
|
|
@ -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 @@ LogReaderThread::LogReaderThread(LogReader& reader, SocketClient* client, bool n
|
|||
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 @@ void LogReaderThread::ThreadFunction() {
|
|||
|
||||
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 @@ void LogReaderThread::ThreadFunction() {
|
|||
start_time_.tv_sec = 0;
|
||||
start_time_.tv_nsec = 0;
|
||||
|
||||
wrlock();
|
||||
lock.lock();
|
||||
|
||||
if (start == LogBufferElement::FLUSH_ERROR) {
|
||||
break;
|
||||
|
@ -119,35 +116,30 @@ void LogReaderThread::ThreadFunction() {
|
|||
|
||||
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 @@ int LogReaderThread::FilterFirstPass(const LogBufferElement* element) {
|
|||
++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 @@ int LogReaderThread::FilterSecondPass(const LogBufferElement* element) {
|
|||
++index_;
|
||||
|
||||
if (count_ > tail_ && index_ <= (count_ - tail_)) {
|
||||
goto skip;
|
||||
return FlushToResult::kSkip;
|
||||
}
|
||||
|
||||
if (!non_block_) {
|
||||
|
@ -221,18 +211,9 @@ int LogReaderThread::FilterSecondPass(const LogBufferElement* element) {
|
|||
|
||||
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) {
|
||||
|
|
|
@ -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 @@ class LogReaderThread {
|
|||
// 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 @@ class LogReaderThread {
|
|||
|
||||
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 @@ class LogReaderThread {
|
|||
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 @@ class LogReaderThread {
|
|||
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 @@ class LogReaderThread {
|
|||
// Whether or not this reader can read security logs. See CanReadSecurityLogs().
|
||||
bool can_read_security_logs_;
|
||||
};
|
||||
|
||||
typedef std::list<std::unique_ptr<LogReaderThread>> LastLogTimes;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "../LogBuffer.h"
|
||||
#include "../LogReaderList.h"
|
||||
#include "../LogReaderThread.h"
|
||||
#include "../LogStatistics.h"
|
||||
|
||||
|
@ -95,11 +96,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||
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;
|
||||
|
||||
|
|
|
@ -271,8 +271,10 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
// 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 @@ int main(int argc, char* argv[]) {
|
|||
// 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 @@ int main(int argc, char* argv[]) {
|
|||
// 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 @@ int main(int argc, char* argv[]) {
|
|||
// 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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue