diff options
Diffstat (limited to 'logd/LogReader.cpp')
-rw-r--r-- | logd/LogReader.cpp | 231 |
1 files changed, 109 insertions, 122 deletions
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp index 9db8c00478..6c976931ff 100644 --- a/logd/LogReader.cpp +++ b/logd/LogReader.cpp @@ -21,26 +21,61 @@ #include <sys/socket.h> #include <sys/types.h> +#include <chrono> + +#include <android-base/logging.h> +#include <android-base/stringprintf.h> #include <cutils/sockets.h> +#include <private/android_filesystem_config.h> #include <private/android_logger.h> -#include "FlushCommand.h" #include "LogBuffer.h" #include "LogBufferElement.h" +#include "LogPermissions.h" #include "LogReader.h" #include "LogUtils.h" +#include "LogWriter.h" -LogReader::LogReader(LogBuffer* logbuf) - : SocketListener(getLogSocket(), true), mLogbuf(*logbuf) { +static bool CanReadSecurityLogs(SocketClient* client) { + return client->getUid() == AID_SYSTEM || client->getGid() == AID_SYSTEM; } -// 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); +static std::string SocketClientToName(SocketClient* client) { + return android::base::StringPrintf("pid %d, fd %d", client->getPid(), client->getSocket()); } +class SocketLogWriter : public LogWriter { + public: + SocketLogWriter(LogReader* reader, SocketClient* client, bool privileged) + : LogWriter(client->getUid(), privileged), reader_(reader), client_(client) {} + + bool Write(const logger_entry& entry, const char* msg) override { + struct iovec iovec[2]; + iovec[0].iov_base = const_cast<logger_entry*>(&entry); + iovec[0].iov_len = entry.hdr_size; + iovec[1].iov_base = const_cast<char*>(msg); + iovec[1].iov_len = entry.len; + + return client_->sendDatav(iovec, 1 + (entry.len != 0)) == 0; + } + + void Release() override { + reader_->release(client_); + client_->decRef(); + } + + void Shutdown() override { shutdown(client_->getSocket(), SHUT_RDWR); } + + std::string name() const override { return SocketClientToName(client_); } + + private: + LogReader* reader_; + SocketClient* client_; +}; + +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) { static bool name_set; @@ -53,22 +88,15 @@ bool LogReader::onDataAvailable(SocketClient* cli) { int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1); if (len <= 0) { - doSocketDelete(cli); + DoSocketDelete(cli); return false; } buffer[len] = '\0'; - // Clients are only allowed to send one command, disconnect them if they - // send another. - LogTimeEntry::wrlock(); - for (const auto& entry : mLogbuf.mTimes) { - if (entry->mClient == cli) { - entry->release_Locked(); - LogTimeEntry::unlock(); - return false; - } + // Clients are only allowed to send one command, disconnect them if they send another. + if (DoSocketDelete(cli)) { + return false; } - LogTimeEntry::unlock(); unsigned long tail = 0; static const char _tail[] = " tail="; @@ -85,12 +113,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_REALTIME).nsec(); + long timeout_seconds = atol(cp + sizeof(_timeout) - 1); + deadline = std::chrono::steady_clock::now() + std::chrono::seconds(timeout_seconds); } unsigned int logMask = -1; @@ -99,7 +127,7 @@ bool LogReader::onDataAvailable(SocketClient* cli) { if (cp) { logMask = 0; cp += sizeof(_logIds) - 1; - while (*cp && *cp != '\0') { + while (*cp != '\0') { int val = 0; while (isdigit(*cp)) { val = val * 10 + *cp - '0'; @@ -124,133 +152,92 @@ bool LogReader::onDataAvailable(SocketClient* cli) { if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) { // Allow writer to get some cycles, and wait for pending notifications sched_yield(); - LogTimeEntry::wrlock(); - LogTimeEntry::unlock(); + reader_list_->reader_threads_lock().lock(); + reader_list_->reader_threads_lock().unlock(); sched_yield(); nonBlock = true; } - log_time sequence = start; - // - // This somewhat expensive data validation operation is required - // for non-blocking, with timeout. The incoming timestamp must be - // in range of the list, if not, return immediately. This is - // used to prevent us from from getting stuck in timeout processing - // with an invalid time. - // - // Find if time is really present in the logs, monotonic or real, implicit - // conversion from monotonic or real as necessary to perform the check. - // Exit in the check loop ASAP as you find a transition from older to - // newer, but use the last entry found to ensure overlap. - // - if (nonBlock && (sequence != log_time::EPOCH) && timeout) { - class LogFindStart { // A lambda by another name - private: - const pid_t mPid; - const unsigned mLogMask; - bool mStartTimeSet; - log_time mStart; - log_time& mSequence; - log_time mLast; - bool mIsMonotonic; - - public: - LogFindStart(pid_t pid, unsigned logMask, log_time& sequence, - bool isMonotonic) - : mPid(pid), - mLogMask(logMask), - mStartTimeSet(false), - mStart(sequence), - mSequence(sequence), - mLast(sequence), - mIsMonotonic(isMonotonic) { - } + bool privileged = clientHasLogCredentials(cli); + bool can_read_security = CanReadSecurityLogs(cli); + if (!can_read_security) { + logMask &= ~(1 << LOG_ID_SECURITY); + } - static int callback(const LogBufferElement* element, void* obj) { - LogFindStart* me = reinterpret_cast<LogFindStart*>(obj); - if ((!me->mPid || (me->mPid == element->getPid())) && - (me->mLogMask & (1 << element->getLogId()))) { - log_time real = element->getRealTime(); - if (me->mStart == real) { - me->mSequence = real; - me->mStartTimeSet = true; - return -1; - } else if (!me->mIsMonotonic || android::isMonotonic(real)) { - if (me->mStart < real) { - me->mSequence = me->mLast; - me->mStartTimeSet = true; - return -1; - } - me->mLast = real; - } else { - me->mLast = real; - } + std::unique_ptr<LogWriter> socket_log_writer(new SocketLogWriter(this, cli, privileged)); + + uint64_t sequence = 1; + // Convert realtime to sequence number + if (start != log_time::EPOCH) { + bool start_time_set = false; + uint64_t last = sequence; + auto log_find_start = [pid, start, &sequence, &start_time_set, &last]( + log_id_t, pid_t element_pid, uint64_t element_sequence, + log_time element_realtime) -> FilterResult { + if (pid && pid != element_pid) { + return FilterResult::kSkip; + } + if (start == element_realtime) { + sequence = element_sequence; + start_time_set = true; + return FilterResult::kStop; + } else { + if (start < element_realtime) { + sequence = last; + start_time_set = true; + return FilterResult::kStop; } - return false; + last = element_sequence; } + return FilterResult::kSkip; + }; + auto flush_to_state = log_buffer_->CreateFlushToState(sequence, logMask); + log_buffer_->FlushTo(socket_log_writer.get(), *flush_to_state, log_find_start); - bool found() { - return mStartTimeSet; + if (!start_time_set) { + if (nonBlock) { + return false; } - - } logFindStart(pid, logMask, sequence, - logbuf().isMonotonic() && android::isMonotonic(start)); - - logbuf().flushTo(cli, sequence, nullptr, FlushCommand::hasReadLogs(cli), - FlushCommand::hasSecurityLogs(cli), - logFindStart.callback, &logFindStart); - - if (!logFindStart.found()) { - doSocketDelete(cli); - return false; + sequence = log_buffer_->sequence(); } } - android::prdebug( - "logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d " - "start=%" PRIu64 "ns timeout=%" PRIu64 "ns\n", - cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail, - logMask, (int)pid, sequence.nsec(), timeout); - - if (sequence == log_time::EPOCH) { - timeout = 0; - } + LOG(INFO) << android::base::StringPrintf( + "logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d " + "start=%" PRIu64 "ns deadline=%" PRIi64 "ns", + cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail, logMask, + (int)pid, start.nsec(), static_cast<int64_t>(deadline.time_since_epoch().count())); - LogTimeEntry::wrlock(); - auto entry = std::make_unique<LogTimeEntry>( - *this, cli, nonBlock, tail, logMask, pid, sequence, timeout); - if (!entry->startReader_Locked()) { - LogTimeEntry::unlock(); - return false; + if (start == log_time::EPOCH) { + deadline = {}; } + auto lock = std::lock_guard{reader_list_->reader_threads_lock()}; + auto entry = std::make_unique<LogReaderThread>(log_buffer_, reader_list_, + std::move(socket_log_writer), nonBlock, tail, + logMask, pid, start, sequence, deadline); // 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)); - LogTimeEntry::unlock(); - return true; } -void LogReader::doSocketDelete(SocketClient* cli) { - LastLogTimes& times = mLogbuf.mTimes; - LogTimeEntry::wrlock(); - LastLogTimes::iterator it = times.begin(); - while (it != times.end()) { - LogTimeEntry* entry = it->get(); - if (entry->mClient == cli) { - entry->release_Locked(); - break; +bool LogReader::DoSocketDelete(SocketClient* cli) { + auto cli_name = SocketClientToName(cli); + auto lock = std::lock_guard{reader_list_->reader_threads_lock()}; + for (const auto& reader : reader_list_->reader_threads()) { + if (reader->name() == cli_name) { + reader->release_Locked(); + return true; } - it++; } - LogTimeEntry::unlock(); + return false; } int LogReader::getLogSocket() { |