Merge changes Ic7620978,I6d5bab58,Id1668c26,Icdb56b6f,Ic0c86a2b

* changes:
  logd: remove FlushCommand
  logd: rename mOldest -> oldest_
  logd: separate PruneList from LogBuffer
  logd: don't use SIGHUP to reinitialize
  logd: decouple LogTags from LogBuffer
This commit is contained in:
Tom Cherry 2020-05-04 22:12:48 +00:00 committed by Gerrit Code Review
commit 794acfc0fe
14 changed files with 146 additions and 421 deletions

View file

@ -36,7 +36,6 @@ cc_library_static {
"CommandListener.cpp",
"LogListener.cpp",
"LogReader.cpp",
"FlushCommand.cpp",
"LogBuffer.cpp",
"LogBufferElement.cpp",
"LogTimes.cpp",

View file

@ -31,6 +31,7 @@
#include <android-base/stringprintf.h>
#include <cutils/sockets.h>
#include <log/log_properties.h>
#include <private/android_filesystem_config.h>
#include <sysutils/SocketClient.h>
@ -38,37 +39,20 @@
#include "LogCommand.h"
#include "LogUtils.h"
CommandListener::CommandListener(LogBuffer* buf, LogReader* /*reader*/,
LogListener* /*swl*/)
: FrameworkListener(getLogSocket()) {
// registerCmd(new ShutdownCmd(buf, writer, swl));
registerCmd(new ClearCmd(buf));
registerCmd(new GetBufSizeCmd(buf));
registerCmd(new SetBufSizeCmd(buf));
registerCmd(new GetBufSizeUsedCmd(buf));
registerCmd(new GetStatisticsCmd(buf));
registerCmd(new SetPruneListCmd(buf));
registerCmd(new GetPruneListCmd(buf));
registerCmd(new GetEventTagCmd(buf));
registerCmd(new ReinitCmd());
CommandListener::CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune)
: FrameworkListener(getLogSocket()), buf_(buf), tags_(tags), prune_(prune) {
registerCmd(new ClearCmd(this));
registerCmd(new GetBufSizeCmd(this));
registerCmd(new SetBufSizeCmd(this));
registerCmd(new GetBufSizeUsedCmd(this));
registerCmd(new GetStatisticsCmd(this));
registerCmd(new SetPruneListCmd(this));
registerCmd(new GetPruneListCmd(this));
registerCmd(new GetEventTagCmd(this));
registerCmd(new ReinitCmd(this));
registerCmd(new ExitCmd(this));
}
CommandListener::ShutdownCmd::ShutdownCmd(LogReader* reader, LogListener* swl)
: LogCommand("shutdown"), mReader(*reader), mSwl(*swl) {
}
int CommandListener::ShutdownCmd::runCommand(SocketClient* /*cli*/,
int /*argc*/, char** /*argv*/) {
mSwl.stopListener();
mReader.stopListener();
exit(0);
}
CommandListener::ClearCmd::ClearCmd(LogBuffer* buf)
: LogCommand("clear"), mBuf(*buf) {
}
static void setname() {
static bool name_set;
if (!name_set) {
@ -96,14 +80,10 @@ int CommandListener::ClearCmd::runCommand(SocketClient* cli, int argc,
return 0;
}
cli->sendMsg(mBuf.clear((log_id_t)id, uid) ? "busy" : "success");
cli->sendMsg(buf()->clear((log_id_t)id, uid) ? "busy" : "success");
return 0;
}
CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer* buf)
: LogCommand("getLogSize"), mBuf(*buf) {
}
int CommandListener::GetBufSizeCmd::runCommand(SocketClient* cli, int argc,
char** argv) {
setname();
@ -118,17 +98,13 @@ int CommandListener::GetBufSizeCmd::runCommand(SocketClient* cli, int argc,
return 0;
}
unsigned long size = mBuf.getSize((log_id_t)id);
unsigned long size = buf()->getSize((log_id_t)id);
char buf[512];
snprintf(buf, sizeof(buf), "%lu", size);
cli->sendMsg(buf);
return 0;
}
CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer* buf)
: LogCommand("setLogSize"), mBuf(*buf) {
}
int CommandListener::SetBufSizeCmd::runCommand(SocketClient* cli, int argc,
char** argv) {
setname();
@ -149,7 +125,7 @@ int CommandListener::SetBufSizeCmd::runCommand(SocketClient* cli, int argc,
}
unsigned long size = atol(argv[2]);
if (mBuf.setSize((log_id_t)id, size)) {
if (buf()->setSize((log_id_t)id, size)) {
cli->sendMsg("Range Error");
return 0;
}
@ -158,10 +134,6 @@ int CommandListener::SetBufSizeCmd::runCommand(SocketClient* cli, int argc,
return 0;
}
CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer* buf)
: LogCommand("getLogSizeUsed"), mBuf(*buf) {
}
int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc,
char** argv) {
setname();
@ -176,17 +148,13 @@ int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc,
return 0;
}
unsigned long size = mBuf.getSizeUsed((log_id_t)id);
unsigned long size = buf()->getSizeUsed((log_id_t)id);
char buf[512];
snprintf(buf, sizeof(buf), "%lu", size);
cli->sendMsg(buf);
return 0;
}
CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer* buf)
: LogCommand("getStatistics"), mBuf(*buf) {
}
// This returns a string with a length prefix with the format <length>\n<data>\n\f. The length
// prefix includes the length of the prefix itself.
static std::string PackageString(const std::string& str) {
@ -241,25 +209,17 @@ int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc,
}
}
cli->sendMsg(PackageString(mBuf.formatStatistics(uid, pid, logMask)).c_str());
cli->sendMsg(PackageString(buf()->formatStatistics(uid, pid, logMask)).c_str());
return 0;
}
CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer* buf)
: LogCommand("getPruneList"), mBuf(*buf) {
}
int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli,
int /*argc*/, char** /*argv*/) {
setname();
cli->sendMsg(PackageString(mBuf.formatPrune()).c_str());
cli->sendMsg(PackageString(prune()->format()).c_str());
return 0;
}
CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer* buf)
: LogCommand("setPruneList"), mBuf(*buf) {
}
int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc,
char** argv) {
setname();
@ -276,7 +236,7 @@ int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc,
str += argv[i];
}
int ret = mBuf.initPrune(str.c_str());
int ret = prune()->init(str.c_str());
if (ret) {
cli->sendMsg("Invalid");
@ -288,10 +248,6 @@ int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc,
return 0;
}
CommandListener::GetEventTagCmd::GetEventTagCmd(LogBuffer* buf)
: LogCommand("getEventTag"), mBuf(*buf) {
}
int CommandListener::GetEventTagCmd::runCommand(SocketClient* cli, int argc,
char** argv) {
setname();
@ -328,39 +284,45 @@ int CommandListener::GetEventTagCmd::runCommand(SocketClient* cli, int argc,
cli->sendMsg("can not mix id= with either format= or name=");
return 0;
}
cli->sendMsg(PackageString(mBuf.formatEntry(atoi(id), uid)).c_str());
cli->sendMsg(PackageString(tags()->formatEntry(atoi(id), uid)).c_str());
return 0;
}
cli->sendMsg(PackageString(mBuf.formatGetEventTag(uid, name, format)).c_str());
cli->sendMsg(PackageString(tags()->formatGetEventTag(uid, name, format)).c_str());
return 0;
}
CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") {
}
int CommandListener::ReinitCmd::runCommand(SocketClient* cli, int /*argc*/,
char** /*argv*/) {
setname();
reinit_signal_handler(SIGHUP);
android::prdebug("logd reinit");
buf()->init();
prune()->init(nullptr);
// This only works on userdebug and eng devices to re-read the
// /data/misc/logd/event-log-tags file right after /data is mounted.
// The operation is near to boot and should only happen once. There
// are races associated with its use since it can trigger a Rebuild
// of the file, but that is a can-not-happen since the file was not
// read yet. More dangerous if called later, but if all is well it
// should just skip over everything and not write any new entries.
if (__android_log_is_debuggable()) {
tags()->ReadFileEventLogTags(tags()->debug_event_log_tags);
}
cli->sendMsg("success");
return 0;
}
CommandListener::ExitCmd::ExitCmd(CommandListener* parent)
: LogCommand("EXIT"), mParent(*parent) {
}
int CommandListener::ExitCmd::runCommand(SocketClient* cli, int /*argc*/,
char** /*argv*/) {
setname();
cli->sendMsg("success");
release(cli);
parent_->release(cli);
return 0;
}

View file

@ -14,85 +14,53 @@
* limitations under the License.
*/
#ifndef _COMMANDLISTENER_H__
#define _COMMANDLISTENER_H__
#pragma once
#include <sysutils/FrameworkListener.h>
#include "LogBuffer.h"
#include "LogCommand.h"
#include "LogListener.h"
#include "LogReader.h"
// See main.cpp for implementation
void reinit_signal_handler(int /*signal*/);
#include "LogTags.h"
#include "LogWhiteBlackList.h"
class CommandListener : public FrameworkListener {
public:
CommandListener(LogBuffer* buf, LogReader* reader, LogListener* swl);
virtual ~CommandListener() {
}
public:
CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune);
virtual ~CommandListener() {}
private:
private:
static int getLogSocket();
class ShutdownCmd : public LogCommand {
LogReader& mReader;
LogListener& mSwl;
LogBuffer* buf_;
LogTags* tags_;
PruneList* prune_;
public:
ShutdownCmd(LogReader* reader, LogListener* swl);
virtual ~ShutdownCmd() {
}
int runCommand(SocketClient* c, int argc, char** argv);
};
#define LogBufferCmd(name) \
#define LogCmd(name, command_string) \
class name##Cmd : public LogCommand { \
LogBuffer& mBuf; \
public: \
explicit name##Cmd(CommandListener* parent) \
: LogCommand(#command_string), parent_(parent) {} \
virtual ~name##Cmd() {} \
int runCommand(SocketClient* c, int argc, char** argv); \
\
public: \
explicit name##Cmd(LogBuffer* buf); \
virtual ~name##Cmd() { \
} \
int runCommand(SocketClient* c, int argc, char** argv); \
private: \
LogBuffer* buf() const { return parent_->buf_; } \
LogTags* tags() const { return parent_->tags_; } \
PruneList* prune() const { return parent_->prune_; } \
CommandListener* parent_; \
}
LogBufferCmd(Clear);
LogBufferCmd(GetBufSize);
LogBufferCmd(SetBufSize);
LogBufferCmd(GetBufSizeUsed);
LogBufferCmd(GetStatistics);
LogBufferCmd(GetPruneList);
LogBufferCmd(SetPruneList);
LogBufferCmd(GetEventTag);
#define LogCmd(name) \
class name##Cmd : public LogCommand { \
public: \
name##Cmd(); \
virtual ~name##Cmd() { \
} \
int runCommand(SocketClient* c, int argc, char** argv); \
}
LogCmd(Reinit);
#define LogParentCmd(name) \
class name##Cmd : public LogCommand { \
CommandListener& mParent; \
\
public: \
name##Cmd(); \
explicit name##Cmd(CommandListener* parent); \
virtual ~name##Cmd() { \
} \
int runCommand(SocketClient* c, int argc, char** argv); \
void release(SocketClient* c) { \
mParent.release(c); \
} \
}
LogParentCmd(Exit);
LogCmd(Clear, clear);
LogCmd(GetBufSize, getLogSize);
LogCmd(SetBufSize, setLogSize);
LogCmd(GetBufSizeUsed, getLogSizeUsed);
LogCmd(GetStatistics, getStatistics);
LogCmd(GetPruneList, getPruneList);
LogCmd(SetPruneList, setPruneList);
LogCmd(GetEventTag, getEventTag);
LogCmd(Reinit, reinit);
LogCmd(Exit, EXIT);
#undef LogCmd
};
#endif

View file

@ -1,75 +0,0 @@
/*
* Copyright (C) 2012-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <private/android_filesystem_config.h>
#include "FlushCommand.h"
#include "LogBuffer.h"
#include "LogBufferElement.h"
#include "LogCommand.h"
#include "LogReader.h"
#include "LogTimes.h"
#include "LogUtils.h"
// runSocketCommand is called once for every open client on the
// log reader socket. Here we manage and associated the reader
// client tracking and log region locks LastLogTimes list of
// LogTimeEntrys, and spawn a transitory per-client thread to
// work at filing data to the socket.
//
// global LogTimeEntry::wrlock() is used to protect access,
// reference counts are used to ensure that individual
// LogTimeEntry lifetime is managed when not protected.
void FlushCommand::runSocketCommand(SocketClient* client) {
LogTimeEntry* entry = nullptr;
LastLogTimes& times = mReader.logbuf().mTimes;
LogTimeEntry::wrlock();
LastLogTimes::iterator it = times.begin();
while (it != times.end()) {
entry = it->get();
if (entry->mClient == client) {
if (!entry->isWatchingMultiple(mLogMask)) {
LogTimeEntry::unlock();
return;
}
if (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec) {
LogTimeEntry::unlock();
return;
}
entry->triggerReader_Locked();
LogTimeEntry::unlock();
return;
}
it++;
}
LogTimeEntry::unlock();
}
bool FlushCommand::hasReadLogs(SocketClient* client) {
return clientHasLogCredentials(client);
}
static bool clientHasSecurityCredentials(SocketClient* client) {
return (client->getUid() == AID_SYSTEM) || (client->getGid() == AID_SYSTEM);
}
bool FlushCommand::hasSecurityLogs(SocketClient* client) {
return clientHasSecurityCredentials(client);
}

View file

@ -1,43 +0,0 @@
/*
* Copyright (C) 2012-2013 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 _FLUSH_COMMAND_H
#define _FLUSH_COMMAND_H
#include <android/log.h>
#include <sysutils/SocketClientCommand.h>
class LogBufferElement;
#include "LogTimes.h"
class LogReader;
class FlushCommand : public SocketClientCommand {
LogReader& mReader;
log_mask_t mLogMask;
public:
explicit FlushCommand(LogReader& reader, log_mask_t logMask)
: mReader(reader), mLogMask(logMask) {
}
virtual void runSocketCommand(SocketClient* client);
static bool hasReadLogs(SocketClient* client);
static bool hasSecurityLogs(SocketClient* client);
};
#endif

View file

@ -92,11 +92,7 @@ void LogBuffer::init() {
unlock();
}
// We may have been triggered by a SIGHUP. Release any sleeping reader
// threads to dump their current content.
//
// NB: this is _not_ performed in the context of a SIGHUP, it is
// performed during startup, and in context of reinit administrative thread
// Release any sleeping reader threads to dump their current content.
LogTimeEntry::wrlock();
LastLogTimes::iterator times = mTimes.begin();
@ -109,8 +105,11 @@ void LogBuffer::init() {
LogTimeEntry::unlock();
}
LogBuffer::LogBuffer(LastLogTimes* times)
: monotonic(android_log_clockid() == CLOCK_MONOTONIC), mTimes(*times) {
LogBuffer::LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune)
: monotonic(android_log_clockid() == CLOCK_MONOTONIC),
mTimes(*times),
tags_(tags),
prune_(prune) {
pthread_rwlock_init(&mLogElementsLock, nullptr);
log_id_for_each(i) {
@ -130,14 +129,14 @@ LogBuffer::~LogBuffer() {
LogBufferElementCollection::iterator LogBuffer::GetOldest(log_id_t log_id) {
auto it = mLogElements.begin();
if (mOldest[log_id]) {
it = *mOldest[log_id];
if (oldest_[log_id]) {
it = *oldest_[log_id];
}
while (it != mLogElements.end() && (*it)->getLogId() != log_id) {
it++;
}
if (it != mLogElements.end()) {
mOldest[log_id] = it;
oldest_[log_id] = it;
}
return it;
}
@ -232,7 +231,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
const char* tag = nullptr;
size_t tag_len = 0;
if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
tag = tagToName(elem->getTag());
tag = tags_->tagToName(elem->getTag());
if (tag) {
tag_len = strlen(tag);
}
@ -461,7 +460,7 @@ LogBufferElementCollection::iterator LogBuffer::erase(
bool setLast[LOG_ID_MAX];
bool doSetLast = false;
log_id_for_each(i) { doSetLast |= setLast[i] = mOldest[i] && it == *mOldest[i]; }
log_id_for_each(i) { doSetLast |= setLast[i] = oldest_[i] && it == *oldest_[i]; }
#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
LogBufferElementCollection::iterator bad = it;
int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
@ -473,9 +472,9 @@ LogBufferElementCollection::iterator LogBuffer::erase(
log_id_for_each(i) {
if (setLast[i]) {
if (__predict_false(it == mLogElements.end())) {
mOldest[i] = std::nullopt;
oldest_[i] = std::nullopt;
} else {
mOldest[i] = it; // Store the next iterator even if it does not correspond to
oldest_[i] = it; // Store the next iterator even if it does not correspond to
// the same log_id, as a starting point for GetOldest().
}
}
@ -698,7 +697,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
}
// prune by worst offenders; by blacklist, UID, and by PID of system UID
bool hasBlacklist = (id != LOG_ID_SECURITY) && mPrune.naughty();
bool hasBlacklist = (id != LOG_ID_SECURITY) && prune_->naughty();
while (!clearAll && (pruneRows > 0)) {
// recalculate the worst offender on every batched pass
int worst = -1; // not valid for getUid() or getKey()
@ -706,7 +705,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
size_t second_worst_sizes = 0;
pid_t worstPid = 0; // POSIX guarantees PID != 0
if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) {
if (worstUidEnabledForLogid(id) && prune_->worstUidEnabled()) {
// Calculate threshold as 12.5% of available storage
size_t threshold = log_buffer_size(id) / 8;
@ -720,7 +719,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
.findWorst(worst, worst_sizes, second_worst_sizes,
threshold);
if ((worst == AID_SYSTEM) && mPrune.worstPidOfSystemEnabled()) {
if ((worst == AID_SYSTEM) && prune_->worstPidOfSystemEnabled()) {
stats.sortPids(worst, (pid_t)0, 2, id)
.findWorst(worstPid, worst_sizes, second_worst_sizes);
}
@ -802,7 +801,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
? element->getTag()
: element->getUid();
if (hasBlacklist && mPrune.naughty(element)) {
if (hasBlacklist && prune_->naughty(element)) {
last.clear(element);
it = erase(it);
if (dropped) {
@ -899,13 +898,13 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
}
last.clear();
if (!kick || !mPrune.worstUidEnabled()) {
if (!kick || !prune_->worstUidEnabled()) {
break; // the following loop will ask bad clients to skip/drop
}
}
bool whitelist = false;
bool hasWhitelist = (id != LOG_ID_SECURITY) && mPrune.nice() && !clearAll;
bool hasWhitelist = (id != LOG_ID_SECURITY) && prune_->nice() && !clearAll;
it = GetOldest(id);
while ((pruneRows > 0) && (it != mLogElements.end())) {
LogBufferElement* element = *it;
@ -921,7 +920,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
break;
}
if (hasWhitelist && !element->getDropped() && mPrune.nice(element)) {
if (hasWhitelist && !element->getDropped() && prune_->nice(element)) {
// WhiteListed
whitelist = true;
it++;

View file

@ -14,8 +14,7 @@
* limitations under the License.
*/
#ifndef _LOGD_LOG_BUFFER_H__
#define _LOGD_LOG_BUFFER_H__
#pragma once
#include <sys/types.h>
@ -81,10 +80,6 @@ class LogBuffer {
LogStatistics stats;
PruneList mPrune;
// Keeps track of the iterator to the oldest log message of a given log type, as an
// optimization when pruning logs. Use GetOldest() to retrieve.
std::optional<LogBufferElementCollection::iterator> mOldest[LOG_ID_MAX];
// watermark of any worst/chatty uid processing
typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator>
LogBufferIteratorMap;
@ -98,8 +93,6 @@ class LogBuffer {
bool monotonic;
LogTags tags;
LogBufferElement* lastLoggedElements[LOG_ID_MAX];
LogBufferElement* droppedElements[LOG_ID_MAX];
void log(LogBufferElement* elem);
@ -107,7 +100,7 @@ class LogBuffer {
public:
LastLogTimes& mTimes;
explicit LogBuffer(LastLogTimes* times);
LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune);
~LogBuffer();
void init();
bool isMonotonic() {
@ -136,24 +129,6 @@ class LogBuffer {
stats.enableStatistics();
}
int initPrune(const char* cp) {
return mPrune.init(cp);
}
std::string formatPrune() {
return mPrune.format();
}
std::string formatGetEventTag(uid_t uid, const char* name,
const char* format) {
return tags.formatGetEventTag(uid, name, format);
}
std::string formatEntry(uint32_t tag, uid_t uid) {
return tags.formatEntry(tag, uid);
}
const char* tagToName(uint32_t tag) {
return tags.tagToName(tag);
}
// helper must be protected directly or implicitly by wrlock()/unlock()
const char* pidToName(pid_t pid) {
return stats.pidToName(pid);
@ -186,6 +161,11 @@ class LogBuffer {
// Returns an iterator to the oldest element for a given log type, or mLogElements.end() if
// there are no logs for the given log type. Requires mLogElementsLock to be held.
LogBufferElementCollection::iterator GetOldest(log_id_t log_id);
};
#endif // _LOGD_LOG_BUFFER_H__
LogTags* tags_;
PruneList* prune_;
// Keeps track of the iterator to the oldest log message of a given log type, as an
// optimization when pruning logs. Use GetOldest() to retrieve.
std::optional<LogBufferElementCollection::iterator> oldest_[LOG_ID_MAX];
};

View file

@ -24,21 +24,35 @@
#include <cutils/sockets.h>
#include <private/android_logger.h>
#include "FlushCommand.h"
#include "LogBuffer.h"
#include "LogBufferElement.h"
#include "LogReader.h"
#include "LogUtils.h"
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(log_mask_t logMask) {
FlushCommand command(*this, logMask);
runOnEachSocket(&command);
void LogReader::notifyNewLog(log_mask_t log_mask) {
LastLogTimes& times = mLogbuf.mTimes;
LogTimeEntry::wrlock();
for (const auto& entry : times) {
if (!entry->isWatchingMultiple(log_mask)) {
continue;
}
if (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec) {
continue;
}
entry->triggerReader_Locked();
}
LogTimeEntry::unlock();
}
// Note returning false will release the SocketClient instance.
@ -129,6 +143,9 @@ bool LogReader::onDataAvailable(SocketClient* cli) {
nonBlock = true;
}
bool privileged = clientHasLogCredentials(cli);
bool can_read_security = CanReadSecurityLogs(cli);
uint64_t sequence = 1;
// Convert realtime to sequence number
if (start != log_time::EPOCH) {
@ -178,8 +195,7 @@ bool LogReader::onDataAvailable(SocketClient* cli) {
} logFindStart(logMask, pid, start, sequence,
logbuf().isMonotonic() && android::isMonotonic(start));
logbuf().flushTo(cli, sequence, nullptr, FlushCommand::hasReadLogs(cli),
FlushCommand::hasSecurityLogs(cli),
logbuf().flushTo(cli, sequence, nullptr, privileged, can_read_security,
logFindStart.callback, &logFindStart);
if (!logFindStart.found()) {
@ -203,7 +219,7 @@ bool LogReader::onDataAvailable(SocketClient* cli) {
LogTimeEntry::wrlock();
auto entry = std::make_unique<LogTimeEntry>(*this, cli, nonBlock, tail, logMask, pid, start,
sequence, timeout);
sequence, timeout, privileged, can_read_security);
if (!entry->startReader_Locked()) {
LogTimeEntry::unlock();
return false;

View file

@ -391,23 +391,6 @@ const char* android::tagToName(uint32_t tag) {
return me->tagToName(tag);
}
// Prototype in LogUtils.h allowing external access to our database.
//
// This only works on userdebug and eng devices to re-read the
// /data/misc/logd/event-log-tags file right after /data is mounted.
// The operation is near to boot and should only happen once. There
// are races associated with its use since it can trigger a Rebuild
// of the file, but that is a can-not-happen since the file was not
// read yet. More dangerous if called later, but if all is well it
// should just skip over everything and not write any new entries.
void android::ReReadEventLogTags() {
LogTags* me = logtags;
if (me && __android_log_is_debuggable()) {
me->ReadFileEventLogTags(me->debug_event_log_tags);
}
}
// converts an event tag into a format
const char* LogTags::tagToFormat(uint32_t tag) const {
tag2format_const_iterator iform;

View file

@ -18,7 +18,6 @@
#include <string.h>
#include <sys/prctl.h>
#include "FlushCommand.h"
#include "LogBuffer.h"
#include "LogReader.h"
#include "LogTimes.h"
@ -27,7 +26,8 @@ pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client, bool nonBlock,
unsigned long tail, log_mask_t logMask, pid_t pid, log_time start_time,
uint64_t start, uint64_t timeout)
uint64_t start, uint64_t timeout, bool privileged,
bool can_read_security_logs)
: leadingDropped(false),
mReader(reader),
mLogMask(logMask),
@ -38,7 +38,9 @@ LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client, bool nonBloc
mClient(client),
mStartTime(start_time),
mStart(start),
mNonBlock(nonBlock) {
mNonBlock(nonBlock),
privileged_(privileged),
can_read_security_logs_(can_read_security_logs) {
mTimeout.tv_sec = timeout / NS_PER_SEC;
mTimeout.tv_nsec = timeout % NS_PER_SEC;
memset(mLastTid, 0, sizeof(mLastTid));
@ -72,9 +74,6 @@ void* LogTimeEntry::threadStart(void* obj) {
LogBuffer& logbuf = me->mReader.logbuf();
bool privileged = FlushCommand::hasReadLogs(client);
bool security = FlushCommand::hasSecurityLogs(client);
me->leadingDropped = true;
wrlock();
@ -96,12 +95,12 @@ void* LogTimeEntry::threadStart(void* obj) {
unlock();
if (me->mTail) {
logbuf.flushTo(client, start, nullptr, privileged, security,
logbuf.flushTo(client, start, nullptr, me->privileged_, me->can_read_security_logs_,
FilterFirstPass, me);
me->leadingDropped = true;
}
start = logbuf.flushTo(client, start, me->mLastTid, privileged,
security, FilterSecondPass, me);
start = logbuf.flushTo(client, start, me->mLastTid, me->privileged_,
me->can_read_security_logs_, FilterSecondPass, me);
// We only ignore entries before the original start time for the first flushTo(), if we
// get entries after this first flush before the original start time, then the client

View file

@ -52,7 +52,7 @@ class LogTimeEntry {
public:
LogTimeEntry(LogReader& reader, SocketClient* client, bool nonBlock, unsigned long tail,
log_mask_t logMask, pid_t pid, log_time start_time, uint64_t sequence,
uint64_t timeout);
uint64_t timeout, bool privileged, bool can_read_security_logs);
SocketClient* mClient;
log_time mStartTime;
@ -98,6 +98,10 @@ class LogTimeEntry {
// flushTo filter callbacks
static int FilterFirstPass(const LogBufferElement* element, void* me);
static int FilterSecondPass(const LogBufferElement* element, void* me);
private:
bool privileged_;
bool can_read_security_logs_;
};
typedef std::list<std::unique_ptr<LogTimeEntry>> LastLogTimes;

View file

@ -14,8 +14,7 @@
* limitations under the License.
*/
#ifndef _LOGD_LOG_UTILS_H__
#define _LOGD_LOG_UTILS_H__
#pragma once
#include <sys/cdefs.h>
#include <sys/types.h>
@ -41,7 +40,6 @@ char* tidToName(pid_t tid);
// Furnished in LogTags.cpp. Thread safe.
const char* tagToName(uint32_t tag);
void ReReadEventLogTags();
// Furnished by LogKlog.cpp
char* log_strntok_r(char* s, ssize_t& len, char*& saveptr, ssize_t& sublen);
@ -72,5 +70,3 @@ static inline bool worstUidEnabledForLogid(log_id_t id) {
return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) ||
(id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
}
#endif // _LOGD_LOG_UTILS_H__

View file

@ -94,12 +94,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
}
LastLogTimes times;
LogBuffer log_buffer(&times);
LogTags tags;
PruneList prune_list;
LogBuffer log_buffer(&times, &tags, &prune_list);
size_t data_left = size;
const uint8_t** pdata = &data;
log_buffer.enableStatistics();
log_buffer.initPrune(nullptr);
prune_list.init(nullptr);
// We want to get pruning code to get called.
log_id_for_each(i) { log_buffer.setSize(i, 10000); }

View file

@ -52,6 +52,7 @@
#include "LogBuffer.h"
#include "LogKlog.h"
#include "LogListener.h"
#include "LogTags.h"
#include "LogUtils.h"
#define KMSG_PRIORITY(PRI) \
@ -150,50 +151,6 @@ void android::prdebug(const char* fmt, ...) {
}
}
static sem_t reinit;
static bool reinit_running = false;
static LogBuffer* logBuf = nullptr;
static void* reinit_thread_start(void* /*obj*/) {
prctl(PR_SET_NAME, "logd.daemon");
while (reinit_running && !sem_wait(&reinit) && reinit_running) {
if (fdDmesg >= 0) {
static const char reinit_message[] = { KMSG_PRIORITY(LOG_INFO),
'l',
'o',
'g',
'd',
'.',
'd',
'a',
'e',
'm',
'o',
'n',
':',
' ',
'r',
'e',
'i',
'n',
'i',
't',
'\n' };
write(fdDmesg, reinit_message, sizeof(reinit_message));
}
// Anything that reads persist.<property>
if (logBuf) {
logBuf->init();
logBuf->initPrune(nullptr);
}
android::ReReadEventLogTags();
}
return nullptr;
}
char* android::uidToName(uid_t u) {
struct Userdata {
uid_t uid;
@ -220,12 +177,6 @@ char* android::uidToName(uid_t u) {
return userdata.name;
}
// Serves as a global method to trigger reinitialization
// and as a function that can be provided to signal().
void reinit_signal_handler(int /*signal*/) {
sem_post(&reinit);
}
static void readDmesg(LogAudit* al, LogKlog* kl) {
if (!al && !kl) {
return;
@ -336,24 +287,10 @@ int main(int argc, char* argv[]) {
return EXIT_FAILURE;
}
// Reinit Thread
sem_init(&reinit, 0, 0);
pthread_attr_t attr;
if (!pthread_attr_init(&attr)) {
struct sched_param param;
memset(&param, 0, sizeof(param));
pthread_attr_setschedparam(&attr, &param);
pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
pthread_t thread;
reinit_running = true;
if (pthread_create(&thread, &attr, reinit_thread_start, nullptr)) {
reinit_running = false;
}
}
pthread_attr_destroy(&attr);
}
// A cache of event log tags
LogTags log_tags;
// Pruning configuration.
PruneList prune_list;
// Serves the purpose of managing the last logs times read on a
// socket connection, and as a reader lock on a range of log
@ -364,9 +301,7 @@ int main(int argc, char* argv[]) {
// LogBuffer is the object which is responsible for holding all
// log entries.
logBuf = new LogBuffer(times);
signal(SIGHUP, reinit_signal_handler);
LogBuffer* logBuf = new LogBuffer(times, &log_tags, &prune_list);
if (__android_logger_property_get_bool(
"logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
@ -396,7 +331,7 @@ int main(int argc, char* argv[]) {
// Command listener listens on /dev/socket/logd for incoming logd
// administrative commands.
CommandListener* cl = new CommandListener(logBuf, reader, swl);
CommandListener* cl = new CommandListener(logBuf, &log_tags, &prune_list);
if (cl->startListener()) {
return EXIT_FAILURE;
}