logd: specify clang format
Switch _all_ file's coding style to match to ease all future changes. SideEffects: None Test: compile Bug: 35373582 Change-Id: I470cb17f64fa48f14aafc02f574e296bffe3a3f3
This commit is contained in:
parent
488525b47b
commit
501c373916
32 changed files with 1735 additions and 1616 deletions
11
logd/.clang-format
Normal file
11
logd/.clang-format
Normal file
|
@ -0,0 +1,11 @@
|
|||
BasedOnStyle: Google
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
|
||||
CommentPragmas: NOLINT:.*
|
||||
DerivePointerAlignment: false
|
||||
IndentWidth: 4
|
||||
PointerAlignment: Left
|
||||
TabWidth: 4
|
||||
PenaltyExcessCharacter: 32
|
||||
|
||||
Cpp11BracedListStyle: false
|
|
@ -20,8 +20,8 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -37,9 +37,9 @@
|
|||
#include "LogCommand.h"
|
||||
#include "LogUtils.h"
|
||||
|
||||
CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
|
||||
LogListener * /*swl*/) :
|
||||
FrameworkListener(getLogSocket()) {
|
||||
CommandListener::CommandListener(LogBuffer* buf, LogReader* /*reader*/,
|
||||
LogListener* /*swl*/)
|
||||
: FrameworkListener(getLogSocket()) {
|
||||
// registerCmd(new ShutdownCmd(buf, writer, swl));
|
||||
registerCmd(new ClearCmd(buf));
|
||||
registerCmd(new GetBufSizeCmd(buf));
|
||||
|
@ -53,24 +53,19 @@ CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
|
|||
registerCmd(new ExitCmd(this));
|
||||
}
|
||||
|
||||
CommandListener::ShutdownCmd::ShutdownCmd(LogReader *reader,
|
||||
LogListener *swl) :
|
||||
LogCommand("shutdown"),
|
||||
mReader(*reader),
|
||||
mSwl(*swl) {
|
||||
CommandListener::ShutdownCmd::ShutdownCmd(LogReader* reader, LogListener* swl)
|
||||
: LogCommand("shutdown"), mReader(*reader), mSwl(*swl) {
|
||||
}
|
||||
|
||||
int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
|
||||
int /*argc*/,
|
||||
char ** /*argv*/) {
|
||||
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) {
|
||||
CommandListener::ClearCmd::ClearCmd(LogBuffer* buf)
|
||||
: LogCommand("clear"), mBuf(*buf) {
|
||||
}
|
||||
|
||||
static void setname() {
|
||||
|
@ -81,8 +76,8 @@ static void setname() {
|
|||
}
|
||||
}
|
||||
|
||||
int CommandListener::ClearCmd::runCommand(SocketClient *cli,
|
||||
int argc, char **argv) {
|
||||
int CommandListener::ClearCmd::runCommand(SocketClient* cli, int argc,
|
||||
char** argv) {
|
||||
setname();
|
||||
uid_t uid = cli->getUid();
|
||||
if (clientHasLogCredentials(cli)) {
|
||||
|
@ -100,17 +95,16 @@ int CommandListener::ClearCmd::runCommand(SocketClient *cli,
|
|||
return 0;
|
||||
}
|
||||
|
||||
cli->sendMsg(mBuf.clear((log_id_t) id, uid) ? "busy" : "success");
|
||||
cli->sendMsg(mBuf.clear((log_id_t)id, uid) ? "busy" : "success");
|
||||
return 0;
|
||||
}
|
||||
|
||||
CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf) :
|
||||
LogCommand("getLogSize"),
|
||||
mBuf(*buf) {
|
||||
CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer* buf)
|
||||
: LogCommand("getLogSize"), mBuf(*buf) {
|
||||
}
|
||||
|
||||
int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
|
||||
int argc, char **argv) {
|
||||
int CommandListener::GetBufSizeCmd::runCommand(SocketClient* cli, int argc,
|
||||
char** argv) {
|
||||
setname();
|
||||
if (argc < 2) {
|
||||
cli->sendMsg("Missing Argument");
|
||||
|
@ -123,20 +117,19 @@ int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned long size = mBuf.getSize((log_id_t) id);
|
||||
unsigned long size = mBuf.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) {
|
||||
CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer* buf)
|
||||
: LogCommand("setLogSize"), mBuf(*buf) {
|
||||
}
|
||||
|
||||
int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
|
||||
int argc, char **argv) {
|
||||
int CommandListener::SetBufSizeCmd::runCommand(SocketClient* cli, int argc,
|
||||
char** argv) {
|
||||
setname();
|
||||
if (!clientHasLogCredentials(cli)) {
|
||||
cli->sendMsg("Permission Denied");
|
||||
|
@ -155,7 +148,7 @@ int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
|
|||
}
|
||||
|
||||
unsigned long size = atol(argv[2]);
|
||||
if (mBuf.setSize((log_id_t) id, size)) {
|
||||
if (mBuf.setSize((log_id_t)id, size)) {
|
||||
cli->sendMsg("Range Error");
|
||||
return 0;
|
||||
}
|
||||
|
@ -164,13 +157,12 @@ int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
|
|||
return 0;
|
||||
}
|
||||
|
||||
CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf) :
|
||||
LogCommand("getLogSizeUsed"),
|
||||
mBuf(*buf) {
|
||||
CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer* buf)
|
||||
: LogCommand("getLogSizeUsed"), mBuf(*buf) {
|
||||
}
|
||||
|
||||
int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
|
||||
int argc, char **argv) {
|
||||
int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc,
|
||||
char** argv) {
|
||||
setname();
|
||||
if (argc < 2) {
|
||||
cli->sendMsg("Missing Argument");
|
||||
|
@ -183,29 +175,29 @@ int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned long size = mBuf.getSizeUsed((log_id_t) id);
|
||||
unsigned long size = mBuf.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) {
|
||||
CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer* buf)
|
||||
: LogCommand("getStatistics"), mBuf(*buf) {
|
||||
}
|
||||
|
||||
static std::string package_string(const std::string &str) {
|
||||
static std::string package_string(const std::string& str) {
|
||||
// Calculate total buffer size prefix, count is the string length w/o nul
|
||||
char fmt[32];
|
||||
for(size_t l = str.length(), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
|
||||
for (size_t l = str.length(), y = 0, x = 6; y != x;
|
||||
y = x, x = strlen(fmt) - 2) {
|
||||
snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
|
||||
}
|
||||
return android::base::StringPrintf(fmt, str.c_str());
|
||||
}
|
||||
|
||||
int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
|
||||
int argc, char **argv) {
|
||||
int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc,
|
||||
char** argv) {
|
||||
setname();
|
||||
uid_t uid = cli->getUid();
|
||||
if (clientHasLogCredentials(cli)) {
|
||||
|
@ -236,30 +228,28 @@ int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
|
|||
}
|
||||
}
|
||||
|
||||
cli->sendMsg(package_string(mBuf.formatStatistics(uid, pid,
|
||||
logMask)).c_str());
|
||||
cli->sendMsg(
|
||||
package_string(mBuf.formatStatistics(uid, pid, logMask)).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf) :
|
||||
LogCommand("getPruneList"),
|
||||
mBuf(*buf) {
|
||||
CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer* buf)
|
||||
: LogCommand("getPruneList"), mBuf(*buf) {
|
||||
}
|
||||
|
||||
int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
|
||||
int /*argc*/, char ** /*argv*/) {
|
||||
int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli,
|
||||
int /*argc*/, char** /*argv*/) {
|
||||
setname();
|
||||
cli->sendMsg(package_string(mBuf.formatPrune()).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf) :
|
||||
LogCommand("setPruneList"),
|
||||
mBuf(*buf) {
|
||||
CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer* buf)
|
||||
: LogCommand("setPruneList"), mBuf(*buf) {
|
||||
}
|
||||
|
||||
int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
|
||||
int argc, char **argv) {
|
||||
int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc,
|
||||
char** argv) {
|
||||
setname();
|
||||
if (!clientHasLogCredentials(cli)) {
|
||||
cli->sendMsg("Permission Denied");
|
||||
|
@ -286,22 +276,21 @@ int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
|
|||
return 0;
|
||||
}
|
||||
|
||||
CommandListener::GetEventTagCmd::GetEventTagCmd(LogBuffer *buf) :
|
||||
LogCommand("getEventTag"),
|
||||
mBuf(*buf) {
|
||||
CommandListener::GetEventTagCmd::GetEventTagCmd(LogBuffer* buf)
|
||||
: LogCommand("getEventTag"), mBuf(*buf) {
|
||||
}
|
||||
|
||||
int CommandListener::GetEventTagCmd::runCommand(SocketClient *cli,
|
||||
int argc, char ** argv) {
|
||||
int CommandListener::GetEventTagCmd::runCommand(SocketClient* cli, int argc,
|
||||
char** argv) {
|
||||
setname();
|
||||
uid_t uid = cli->getUid();
|
||||
if (clientHasLogCredentials(cli)) {
|
||||
uid = AID_ROOT;
|
||||
}
|
||||
|
||||
const char *name = NULL;
|
||||
const char *format = NULL;
|
||||
const char *id = NULL;
|
||||
const char* name = NULL;
|
||||
const char* format = NULL;
|
||||
const char* id = NULL;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
static const char _name[] = "name=";
|
||||
if (!strncmp(argv[i], _name, strlen(_name))) {
|
||||
|
@ -331,8 +320,8 @@ int CommandListener::GetEventTagCmd::runCommand(SocketClient *cli,
|
|||
return 0;
|
||||
}
|
||||
|
||||
cli->sendMsg(package_string(mBuf.formatGetEventTag(uid,
|
||||
name, format)).c_str());
|
||||
cli->sendMsg(
|
||||
package_string(mBuf.formatGetEventTag(uid, name, format)).c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -340,8 +329,8 @@ int CommandListener::GetEventTagCmd::runCommand(SocketClient *cli,
|
|||
CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") {
|
||||
}
|
||||
|
||||
int CommandListener::ReinitCmd::runCommand(SocketClient *cli,
|
||||
int /*argc*/, char ** /*argv*/) {
|
||||
int CommandListener::ReinitCmd::runCommand(SocketClient* cli, int /*argc*/,
|
||||
char** /*argv*/) {
|
||||
setname();
|
||||
|
||||
reinit_signal_handler(SIGHUP);
|
||||
|
@ -351,13 +340,12 @@ int CommandListener::ReinitCmd::runCommand(SocketClient *cli,
|
|||
return 0;
|
||||
}
|
||||
|
||||
CommandListener::ExitCmd::ExitCmd(CommandListener *parent) :
|
||||
LogCommand("EXIT"),
|
||||
mParent(*parent) {
|
||||
CommandListener::ExitCmd::ExitCmd(CommandListener* parent)
|
||||
: LogCommand("EXIT"), mParent(*parent) {
|
||||
}
|
||||
|
||||
int CommandListener::ExitCmd::runCommand(SocketClient * cli,
|
||||
int /*argc*/, char ** /*argv*/) {
|
||||
int CommandListener::ExitCmd::runCommand(SocketClient* cli, int /*argc*/,
|
||||
char** /*argv*/) {
|
||||
setname();
|
||||
|
||||
cli->sendMsg("success");
|
||||
|
@ -371,9 +359,8 @@ int CommandListener::getLogSocket() {
|
|||
int sock = android_get_control_socket(socketName);
|
||||
|
||||
if (sock < 0) {
|
||||
sock = socket_local_server(socketName,
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_STREAM);
|
||||
sock = socket_local_server(
|
||||
socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
|
||||
}
|
||||
|
||||
return sock;
|
||||
|
|
|
@ -18,40 +18,43 @@
|
|||
#define _COMMANDLISTENER_H__
|
||||
|
||||
#include <sysutils/FrameworkListener.h>
|
||||
#include "LogCommand.h"
|
||||
#include "LogBuffer.h"
|
||||
#include "LogReader.h"
|
||||
#include "LogCommand.h"
|
||||
#include "LogListener.h"
|
||||
#include "LogReader.h"
|
||||
|
||||
// See main.cpp for implementation
|
||||
void reinit_signal_handler(int /*signal*/);
|
||||
|
||||
class CommandListener : public FrameworkListener {
|
||||
public:
|
||||
CommandListener(LogBuffer* buf, LogReader* reader, LogListener* swl);
|
||||
virtual ~CommandListener() {
|
||||
}
|
||||
|
||||
public:
|
||||
CommandListener(LogBuffer *buf, LogReader *reader, LogListener *swl);
|
||||
virtual ~CommandListener() {}
|
||||
|
||||
private:
|
||||
private:
|
||||
static int getLogSocket();
|
||||
|
||||
class ShutdownCmd : public LogCommand {
|
||||
LogReader &mReader;
|
||||
LogListener &mSwl;
|
||||
LogReader& mReader;
|
||||
LogListener& mSwl;
|
||||
|
||||
public:
|
||||
ShutdownCmd(LogReader *reader, LogListener *swl);
|
||||
virtual ~ShutdownCmd() {}
|
||||
int runCommand(SocketClient *c, int argc, char ** argv);
|
||||
public:
|
||||
ShutdownCmd(LogReader* reader, LogListener* swl);
|
||||
virtual ~ShutdownCmd() {
|
||||
}
|
||||
int runCommand(SocketClient* c, int argc, char** argv);
|
||||
};
|
||||
|
||||
#define LogBufferCmd(name) \
|
||||
class name##Cmd : public LogCommand { \
|
||||
LogBuffer &mBuf; \
|
||||
public: \
|
||||
explicit name##Cmd(LogBuffer *buf); \
|
||||
virtual ~name##Cmd() {} \
|
||||
int runCommand(SocketClient *c, int argc, char ** argv); \
|
||||
#define LogBufferCmd(name) \
|
||||
class name##Cmd : public LogCommand { \
|
||||
LogBuffer& mBuf; \
|
||||
\
|
||||
public: \
|
||||
explicit name##Cmd(LogBuffer* buf); \
|
||||
virtual ~name##Cmd() { \
|
||||
} \
|
||||
int runCommand(SocketClient* c, int argc, char** argv); \
|
||||
}
|
||||
|
||||
LogBufferCmd(Clear);
|
||||
|
@ -63,29 +66,33 @@ private:
|
|||
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); \
|
||||
#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); } \
|
||||
#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);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,20 +26,16 @@
|
|||
#include "LogTimes.h"
|
||||
#include "LogUtils.h"
|
||||
|
||||
FlushCommand::FlushCommand(LogReader &reader,
|
||||
bool nonBlock,
|
||||
unsigned long tail,
|
||||
unsigned int logMask,
|
||||
pid_t pid,
|
||||
uint64_t start,
|
||||
uint64_t timeout) :
|
||||
mReader(reader),
|
||||
mNonBlock(nonBlock),
|
||||
mTail(tail),
|
||||
mLogMask(logMask),
|
||||
mPid(pid),
|
||||
mStart(start),
|
||||
mTimeout((start > 1) ? timeout : 0) {
|
||||
FlushCommand::FlushCommand(LogReader& reader, bool nonBlock, unsigned long tail,
|
||||
unsigned int logMask, pid_t pid, uint64_t start,
|
||||
uint64_t timeout)
|
||||
: mReader(reader),
|
||||
mNonBlock(nonBlock),
|
||||
mTail(tail),
|
||||
mLogMask(logMask),
|
||||
mPid(pid),
|
||||
mStart(start),
|
||||
mTimeout((start > 1) ? timeout : 0) {
|
||||
}
|
||||
|
||||
// runSocketCommand is called once for every open client on the
|
||||
|
@ -51,13 +47,13 @@ FlushCommand::FlushCommand(LogReader &reader,
|
|||
// global LogTimeEntry::lock() 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 = NULL;
|
||||
LastLogTimes × = mReader.logbuf().mTimes;
|
||||
void FlushCommand::runSocketCommand(SocketClient* client) {
|
||||
LogTimeEntry* entry = NULL;
|
||||
LastLogTimes& times = mReader.logbuf().mTimes;
|
||||
|
||||
LogTimeEntry::lock();
|
||||
LastLogTimes::iterator it = times.begin();
|
||||
while(it != times.end()) {
|
||||
while (it != times.end()) {
|
||||
entry = (*it);
|
||||
if (entry->mClient == client) {
|
||||
if (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec) {
|
||||
|
@ -77,7 +73,7 @@ void FlushCommand::runSocketCommand(SocketClient *client) {
|
|||
|
||||
if (it == times.end()) {
|
||||
// Create LogTimeEntry in notifyNewLog() ?
|
||||
if (mTail == (unsigned long) -1) {
|
||||
if (mTail == (unsigned long)-1) {
|
||||
LogTimeEntry::unlock();
|
||||
return;
|
||||
}
|
||||
|
@ -93,14 +89,14 @@ void FlushCommand::runSocketCommand(SocketClient *client) {
|
|||
LogTimeEntry::unlock();
|
||||
}
|
||||
|
||||
bool FlushCommand::hasReadLogs(SocketClient *client) {
|
||||
bool FlushCommand::hasReadLogs(SocketClient* client) {
|
||||
return clientHasLogCredentials(client);
|
||||
}
|
||||
|
||||
static bool clientHasSecurityCredentials(SocketClient *client) {
|
||||
static bool clientHasSecurityCredentials(SocketClient* client) {
|
||||
return (client->getUid() == AID_SYSTEM) || (client->getGid() == AID_SYSTEM);
|
||||
}
|
||||
|
||||
bool FlushCommand::hasSecurityLogs(SocketClient *client) {
|
||||
bool FlushCommand::hasSecurityLogs(SocketClient* client) {
|
||||
return clientHasSecurityCredentials(client);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class LogBufferElement;
|
|||
class LogReader;
|
||||
|
||||
class FlushCommand : public SocketClientCommand {
|
||||
LogReader &mReader;
|
||||
LogReader& mReader;
|
||||
bool mNonBlock;
|
||||
unsigned long mTail;
|
||||
unsigned int mLogMask;
|
||||
|
@ -34,18 +34,15 @@ class FlushCommand : public SocketClientCommand {
|
|||
uint64_t mStart;
|
||||
uint64_t mTimeout;
|
||||
|
||||
public:
|
||||
explicit FlushCommand(LogReader &mReader,
|
||||
bool nonBlock = false,
|
||||
unsigned long tail = -1,
|
||||
unsigned int logMask = -1,
|
||||
pid_t pid = 0,
|
||||
uint64_t start = 1,
|
||||
uint64_t timeout = 0);
|
||||
virtual void runSocketCommand(SocketClient *client);
|
||||
public:
|
||||
explicit FlushCommand(LogReader& mReader, bool nonBlock = false,
|
||||
unsigned long tail = -1, unsigned int logMask = -1,
|
||||
pid_t pid = 0, uint64_t start = 1,
|
||||
uint64_t timeout = 0);
|
||||
virtual void runSocketCommand(SocketClient* client);
|
||||
|
||||
static bool hasReadLogs(SocketClient *client);
|
||||
static bool hasSecurityLogs(SocketClient *client);
|
||||
static bool hasReadLogs(SocketClient* client);
|
||||
static bool hasSecurityLogs(SocketClient* client);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,38 +29,52 @@
|
|||
#include <private/android_filesystem_config.h>
|
||||
#include <private/android_logger.h>
|
||||
|
||||
#include "libaudit.h"
|
||||
#include "LogAudit.h"
|
||||
#include "LogBuffer.h"
|
||||
#include "LogKlog.h"
|
||||
#include "LogReader.h"
|
||||
#include "LogUtils.h"
|
||||
#include "libaudit.h"
|
||||
|
||||
#define KMSG_PRIORITY(PRI) \
|
||||
'<', \
|
||||
'0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
|
||||
'0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, \
|
||||
'>'
|
||||
#define KMSG_PRIORITY(PRI) \
|
||||
'<', '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) :
|
||||
SocketListener(mSock = getLogSocket(), false),
|
||||
logbuf(buf),
|
||||
reader(reader),
|
||||
fdDmesg(fdDmesg),
|
||||
main(__android_logger_property_get_bool("ro.logd.auditd.main",
|
||||
LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg)
|
||||
: SocketListener(mSock = 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)),
|
||||
events(__android_logger_property_get_bool("ro.logd.auditd.events",
|
||||
BOOL_DEFAULT_TRUE)),
|
||||
initialized(false),
|
||||
tooFast(false) {
|
||||
initialized(false),
|
||||
tooFast(false) {
|
||||
static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
|
||||
'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
|
||||
' ', 's', 't', 'a', 'r', 't', '\n' };
|
||||
'l',
|
||||
'o',
|
||||
'g',
|
||||
'd',
|
||||
'.',
|
||||
'a',
|
||||
'u',
|
||||
'd',
|
||||
'i',
|
||||
't',
|
||||
'd',
|
||||
':',
|
||||
' ',
|
||||
's',
|
||||
't',
|
||||
'a',
|
||||
'r',
|
||||
't',
|
||||
'\n' };
|
||||
write(fdDmesg, auditd_message, sizeof(auditd_message));
|
||||
}
|
||||
|
||||
void LogAudit::checkRateLimit() {
|
||||
|
||||
// trim list for AUDIT_RATE_LIMIT_BURST_DURATION of history
|
||||
log_time oldest(AUDIT_RATE_LIMIT_BURST_DURATION, 0);
|
||||
bucket.emplace(android_log_clockid());
|
||||
|
@ -69,8 +83,9 @@ void LogAudit::checkRateLimit() {
|
|||
|
||||
static const size_t upperThreshold =
|
||||
((AUDIT_RATE_LIMIT_BURST_DURATION *
|
||||
(AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) + 1) /
|
||||
2;
|
||||
(AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
|
||||
1) /
|
||||
2;
|
||||
if (bucket.size() >= upperThreshold) {
|
||||
// Hit peak, slow down source
|
||||
if (!tooFast) {
|
||||
|
@ -89,8 +104,8 @@ void LogAudit::checkRateLimit() {
|
|||
|
||||
if (!tooFast) return;
|
||||
|
||||
static const size_t lowerThreshold = AUDIT_RATE_LIMIT_BURST_DURATION *
|
||||
AUDIT_RATE_LIMIT_MAX;
|
||||
static const size_t lowerThreshold =
|
||||
AUDIT_RATE_LIMIT_BURST_DURATION * AUDIT_RATE_LIMIT_MAX;
|
||||
|
||||
if (bucket.size() >= lowerThreshold) return;
|
||||
|
||||
|
@ -99,7 +114,7 @@ void LogAudit::checkRateLimit() {
|
|||
audit_rate_limit(mSock, AUDIT_RATE_LIMIT_DEFAULT);
|
||||
}
|
||||
|
||||
bool LogAudit::onDataAvailable(SocketClient *cli) {
|
||||
bool LogAudit::onDataAvailable(SocketClient* cli) {
|
||||
if (!initialized) {
|
||||
prctl(PR_SET_NAME, "logd.auditd");
|
||||
initialized = true;
|
||||
|
@ -123,14 +138,14 @@ bool LogAudit::onDataAvailable(SocketClient *cli) {
|
|||
return true;
|
||||
}
|
||||
|
||||
int LogAudit::logPrint(const char *fmt, ...) {
|
||||
int LogAudit::logPrint(const char* fmt, ...) {
|
||||
if (fmt == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
|
||||
char *str = NULL;
|
||||
char* str = NULL;
|
||||
va_start(args, fmt);
|
||||
int rc = vasprintf(&str, fmt, args);
|
||||
va_end(args);
|
||||
|
@ -139,7 +154,7 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
char *cp;
|
||||
char* cp;
|
||||
// Work around kernels missing
|
||||
// https://github.com/torvalds/linux/commit/b8f89caafeb55fba75b74bea25adc4e4cd91be67
|
||||
// Such kernels improperly add newlines inside audit messages.
|
||||
|
@ -160,19 +175,19 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
|
||||
// Dedupe messages, checking for identical messages starting with avc:
|
||||
static unsigned count;
|
||||
static char *last_str;
|
||||
static char* last_str;
|
||||
static bool last_info;
|
||||
|
||||
if (last_str != NULL) {
|
||||
static const char avc[] = "): avc: ";
|
||||
char *avcl = strstr(last_str, avc);
|
||||
char* avcl = strstr(last_str, avc);
|
||||
bool skip = false;
|
||||
|
||||
if (avcl) {
|
||||
char *avcr = strstr(str, avc);
|
||||
char* avcr = strstr(str, avc);
|
||||
|
||||
skip = avcr && !fastcmp<strcmp>(avcl + strlen(avc),
|
||||
avcr + strlen(avc));
|
||||
skip = avcr &&
|
||||
!fastcmp<strcmp>(avcl + strlen(avc), avcr + strlen(avc));
|
||||
if (skip) {
|
||||
++count;
|
||||
free(last_str);
|
||||
|
@ -183,19 +198,17 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
if (!skip) {
|
||||
static const char resume[] = " duplicate messages suppressed\n";
|
||||
|
||||
iov[0].iov_base = last_info ?
|
||||
const_cast<char *>(log_info) :
|
||||
const_cast<char *>(log_warning);
|
||||
iov[0].iov_len = last_info ?
|
||||
sizeof(log_info) :
|
||||
sizeof(log_warning);
|
||||
iov[0].iov_base = last_info ? const_cast<char*>(log_info)
|
||||
: const_cast<char*>(log_warning);
|
||||
iov[0].iov_len =
|
||||
last_info ? sizeof(log_info) : sizeof(log_warning);
|
||||
iov[1].iov_base = last_str;
|
||||
iov[1].iov_len = strlen(last_str);
|
||||
if (count > 1) {
|
||||
iov[2].iov_base = const_cast<char *>(resume);
|
||||
iov[2].iov_base = const_cast<char*>(resume);
|
||||
iov[2].iov_len = strlen(resume);
|
||||
} else {
|
||||
iov[2].iov_base = const_cast<char *>(newline);
|
||||
iov[2].iov_base = const_cast<char*>(newline);
|
||||
iov[2].iov_len = strlen(newline);
|
||||
}
|
||||
|
||||
|
@ -210,15 +223,12 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
last_info = info;
|
||||
}
|
||||
if (count == 0) {
|
||||
iov[0].iov_base = info ?
|
||||
const_cast<char *>(log_info) :
|
||||
const_cast<char *>(log_warning);
|
||||
iov[0].iov_len = info ?
|
||||
sizeof(log_info) :
|
||||
sizeof(log_warning);
|
||||
iov[0].iov_base = info ? const_cast<char*>(log_info)
|
||||
: const_cast<char*>(log_warning);
|
||||
iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
|
||||
iov[1].iov_base = str;
|
||||
iov[1].iov_len = strlen(str);
|
||||
iov[2].iov_base = const_cast<char *>(newline);
|
||||
iov[2].iov_base = const_cast<char*>(newline);
|
||||
iov[2].iov_len = strlen(newline);
|
||||
|
||||
writev(fdDmesg, iov, arraysize(iov));
|
||||
|
@ -236,10 +246,10 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
log_time now;
|
||||
|
||||
static const char audit_str[] = " audit(";
|
||||
char *timeptr = strstr(str, audit_str);
|
||||
if (timeptr
|
||||
&& ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q")))
|
||||
&& (*cp == ':')) {
|
||||
char* timeptr = strstr(str, audit_str);
|
||||
if (timeptr &&
|
||||
((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q"))) &&
|
||||
(*cp == ':')) {
|
||||
memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
|
||||
memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
|
||||
if (!isMonotonic()) {
|
||||
|
@ -258,7 +268,7 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
}
|
||||
|
||||
static const char pid_str[] = " pid=";
|
||||
char *pidptr = strstr(str, pid_str);
|
||||
char* pidptr = strstr(str, pid_str);
|
||||
if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
|
||||
cp = pidptr + sizeof(pid_str) - 1;
|
||||
pid = 0;
|
||||
|
@ -280,19 +290,19 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
|
||||
bool notify = false;
|
||||
|
||||
if (events) { // begin scope for event buffer
|
||||
if (events) { // begin scope for event buffer
|
||||
uint32_t buffer[(n + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
|
||||
|
||||
android_log_event_string_t *event
|
||||
= reinterpret_cast<android_log_event_string_t *>(buffer);
|
||||
android_log_event_string_t* event =
|
||||
reinterpret_cast<android_log_event_string_t*>(buffer);
|
||||
event->header.tag = htole32(AUDITD_LOG_TAG);
|
||||
event->type = EVENT_TYPE_STRING;
|
||||
event->length = htole32(l);
|
||||
memcpy(event->data, str, l);
|
||||
|
||||
rc = logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
|
||||
reinterpret_cast<char *>(event),
|
||||
(n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
|
||||
reinterpret_cast<char*>(event),
|
||||
(n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX);
|
||||
if (rc >= 0) {
|
||||
notify = true;
|
||||
}
|
||||
|
@ -302,9 +312,9 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
// log to main
|
||||
|
||||
static const char comm_str[] = " comm=\"";
|
||||
const char *comm = strstr(str, comm_str);
|
||||
const char *estr = str + strlen(str);
|
||||
const char *commfree = NULL;
|
||||
const char* comm = strstr(str, comm_str);
|
||||
const char* estr = str + strlen(str);
|
||||
const char* commfree = NULL;
|
||||
if (comm) {
|
||||
estr = comm;
|
||||
comm += sizeof(comm_str) - 1;
|
||||
|
@ -320,7 +330,7 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
}
|
||||
}
|
||||
|
||||
const char *ecomm = strchr(comm, '"');
|
||||
const char* ecomm = strchr(comm, '"');
|
||||
if (ecomm) {
|
||||
++ecomm;
|
||||
l = ecomm - comm;
|
||||
|
@ -335,7 +345,7 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
size_t e = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - b);
|
||||
n = b + e + l + 2;
|
||||
|
||||
if (main) { // begin scope for main buffer
|
||||
if (main) { // begin scope for main buffer
|
||||
char newstr[n];
|
||||
|
||||
*newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
|
||||
|
@ -344,7 +354,7 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
strncpy(newstr + 1 + l + b, ecomm, e);
|
||||
|
||||
rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
|
||||
(n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
|
||||
(n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX);
|
||||
|
||||
if (rc >= 0) {
|
||||
notify = true;
|
||||
|
@ -352,7 +362,7 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
// end scope for main buffer
|
||||
}
|
||||
|
||||
free(const_cast<char *>(commfree));
|
||||
free(const_cast<char*>(commfree));
|
||||
free(str);
|
||||
|
||||
if (notify) {
|
||||
|
@ -365,8 +375,8 @@ int LogAudit::logPrint(const char *fmt, ...) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
int LogAudit::log(char *buf, size_t len) {
|
||||
char *audit = strstr(buf, " audit(");
|
||||
int LogAudit::log(char* buf, size_t len) {
|
||||
char* audit = strstr(buf, " audit(");
|
||||
if (!audit || (audit >= &buf[len])) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -374,7 +384,7 @@ int LogAudit::log(char *buf, size_t len) {
|
|||
*audit = '\0';
|
||||
|
||||
int rc;
|
||||
char *type = strstr(buf, "type=");
|
||||
char* type = strstr(buf, "type=");
|
||||
if (type && (type < &buf[len])) {
|
||||
rc = logPrint("%s %s", type, audit + 1);
|
||||
} else {
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
class LogReader;
|
||||
|
||||
class LogAudit : public SocketListener {
|
||||
LogBuffer *logbuf;
|
||||
LogReader *reader;
|
||||
int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
|
||||
LogBuffer* logbuf;
|
||||
LogReader* reader;
|
||||
int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
|
||||
bool main;
|
||||
bool events;
|
||||
bool initialized;
|
||||
|
@ -38,18 +38,20 @@ class LogAudit : public SocketListener {
|
|||
std::queue<log_time> bucket;
|
||||
void checkRateLimit();
|
||||
|
||||
public:
|
||||
LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg);
|
||||
int log(char *buf, size_t len);
|
||||
bool isMonotonic() { return logbuf->isMonotonic(); }
|
||||
public:
|
||||
LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg);
|
||||
int log(char* buf, size_t len);
|
||||
bool isMonotonic() {
|
||||
return logbuf->isMonotonic();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool onDataAvailable(SocketClient *cli);
|
||||
protected:
|
||||
virtual bool onDataAvailable(SocketClient* cli);
|
||||
|
||||
private:
|
||||
private:
|
||||
static int getLogSocket();
|
||||
int logPrint(const char *fmt, ...)
|
||||
__attribute__ ((__format__ (__printf__, 2, 3)));
|
||||
int logPrint(const char* fmt, ...)
|
||||
__attribute__((__format__(__printf__, 2, 3)));
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -72,8 +72,8 @@ void LogBuffer::init() {
|
|||
//
|
||||
pthread_mutex_lock(&mLogElementsLock);
|
||||
LogBufferElementCollection::iterator it = mLogElements.begin();
|
||||
while((it != mLogElements.end())) {
|
||||
LogBufferElement *e = *it;
|
||||
while ((it != mLogElements.end())) {
|
||||
LogBufferElement* e = *it;
|
||||
if (monotonic) {
|
||||
if (!android::isMonotonic(e->mRealTime)) {
|
||||
LogKlog::convertRealToMonotonic(e->mRealTime);
|
||||
|
@ -96,8 +96,8 @@ void LogBuffer::init() {
|
|||
LogTimeEntry::lock();
|
||||
|
||||
LastLogTimes::iterator times = mTimes.begin();
|
||||
while(times != mTimes.end()) {
|
||||
LogTimeEntry *entry = (*times);
|
||||
while (times != mTimes.end()) {
|
||||
LogTimeEntry* entry = (*times);
|
||||
if (entry->owned_Locked()) {
|
||||
entry->triggerReader_Locked();
|
||||
}
|
||||
|
@ -107,9 +107,8 @@ void LogBuffer::init() {
|
|||
LogTimeEntry::unlock();
|
||||
}
|
||||
|
||||
LogBuffer::LogBuffer(LastLogTimes *times):
|
||||
monotonic(android_log_clockid() == CLOCK_MONOTONIC),
|
||||
mTimes(*times) {
|
||||
LogBuffer::LogBuffer(LastLogTimes* times)
|
||||
: monotonic(android_log_clockid() == CLOCK_MONOTONIC), mTimes(*times) {
|
||||
pthread_mutex_init(&mLogElementsLock, NULL);
|
||||
|
||||
log_id_for_each(i) {
|
||||
|
@ -127,28 +126,26 @@ LogBuffer::~LogBuffer() {
|
|||
}
|
||||
}
|
||||
|
||||
enum match_type {
|
||||
DIFFERENT,
|
||||
SAME,
|
||||
SAME_LIBLOG
|
||||
};
|
||||
enum match_type { DIFFERENT, SAME, SAME_LIBLOG };
|
||||
|
||||
static enum match_type identical(LogBufferElement* elem, LogBufferElement* last) {
|
||||
static enum match_type identical(LogBufferElement* elem,
|
||||
LogBufferElement* last) {
|
||||
// is it mostly identical?
|
||||
// if (!elem) return DIFFERENT;
|
||||
// if (!elem) return DIFFERENT;
|
||||
unsigned short lenl = elem->getMsgLen();
|
||||
if (!lenl) return DIFFERENT;
|
||||
// if (!last) return DIFFERENT;
|
||||
// if (!last) return DIFFERENT;
|
||||
unsigned short lenr = last->getMsgLen();
|
||||
if (!lenr) return DIFFERENT;
|
||||
// if (elem->getLogId() != last->getLogId()) return DIFFERENT;
|
||||
// if (elem->getLogId() != last->getLogId()) return DIFFERENT;
|
||||
if (elem->getUid() != last->getUid()) return DIFFERENT;
|
||||
if (elem->getPid() != last->getPid()) return DIFFERENT;
|
||||
if (elem->getTid() != last->getTid()) return DIFFERENT;
|
||||
|
||||
// last is more than a minute old, stop squashing identical messages
|
||||
if (elem->getRealTime().nsec() >
|
||||
(last->getRealTime().nsec() + 60 * NS_PER_SEC)) return DIFFERENT;
|
||||
(last->getRealTime().nsec() + 60 * NS_PER_SEC))
|
||||
return DIFFERENT;
|
||||
|
||||
// Identical message
|
||||
const char* msgl = elem->getMsg();
|
||||
|
@ -158,47 +155,47 @@ static enum match_type identical(LogBufferElement* elem, LogBufferElement* last)
|
|||
// liblog tagged messages (content gets summed)
|
||||
if ((elem->getLogId() == LOG_ID_EVENTS) &&
|
||||
(lenl == sizeof(android_log_event_int_t)) &&
|
||||
!fastcmp<memcmp>(msgl, msgr,
|
||||
sizeof(android_log_event_int_t) - sizeof(int32_t)) &&
|
||||
(elem->getTag() == LIBLOG_LOG_TAG)) return SAME_LIBLOG;
|
||||
!fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_int_t) -
|
||||
sizeof(int32_t)) &&
|
||||
(elem->getTag() == LIBLOG_LOG_TAG))
|
||||
return SAME_LIBLOG;
|
||||
}
|
||||
|
||||
// audit message (except sequence number) identical?
|
||||
static const char avc[] = "): avc: ";
|
||||
|
||||
if (last->isBinary()) {
|
||||
if (fastcmp<memcmp>(msgl, msgr,
|
||||
sizeof(android_log_event_string_t) -
|
||||
sizeof(int32_t))) return DIFFERENT;
|
||||
if (fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_string_t) -
|
||||
sizeof(int32_t)))
|
||||
return DIFFERENT;
|
||||
msgl += sizeof(android_log_event_string_t);
|
||||
lenl -= sizeof(android_log_event_string_t);
|
||||
msgr += sizeof(android_log_event_string_t);
|
||||
lenr -= sizeof(android_log_event_string_t);
|
||||
}
|
||||
const char *avcl = android::strnstr(msgl, lenl, avc);
|
||||
const char* avcl = android::strnstr(msgl, lenl, avc);
|
||||
if (!avcl) return DIFFERENT;
|
||||
lenl -= avcl - msgl;
|
||||
const char *avcr = android::strnstr(msgr, lenr, avc);
|
||||
const char* avcr = android::strnstr(msgr, lenr, avc);
|
||||
if (!avcr) return DIFFERENT;
|
||||
lenr -= avcr - msgr;
|
||||
if (lenl != lenr) return DIFFERENT;
|
||||
if (fastcmp<memcmp>(avcl + strlen(avc),
|
||||
avcr + strlen(avc), lenl)) return DIFFERENT;
|
||||
if (fastcmp<memcmp>(avcl + strlen(avc), avcr + strlen(avc), lenl))
|
||||
return DIFFERENT;
|
||||
return SAME;
|
||||
}
|
||||
|
||||
int LogBuffer::log(log_id_t log_id, log_time realtime,
|
||||
uid_t uid, pid_t pid, pid_t tid,
|
||||
const char *msg, unsigned short len) {
|
||||
int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
|
||||
pid_t tid, const char* msg, unsigned short len) {
|
||||
if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LogBufferElement *elem = new LogBufferElement(log_id, realtime,
|
||||
uid, pid, tid, msg, len);
|
||||
LogBufferElement* elem =
|
||||
new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len);
|
||||
if (log_id != LOG_ID_SECURITY) {
|
||||
int prio = ANDROID_LOG_INFO;
|
||||
const char *tag = NULL;
|
||||
const char* tag = NULL;
|
||||
if (log_id == LOG_ID_EVENTS) {
|
||||
tag = tagToName(elem->getTag());
|
||||
} else {
|
||||
|
@ -219,7 +216,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime,
|
|||
pthread_mutex_lock(&mLogElementsLock);
|
||||
LogBufferElement* currentLast = lastLoggedElements[log_id];
|
||||
if (currentLast) {
|
||||
LogBufferElement *dropped = droppedElements[log_id];
|
||||
LogBufferElement* dropped = droppedElements[log_id];
|
||||
unsigned short count = dropped ? dropped->getDropped() : 0;
|
||||
//
|
||||
// State Init
|
||||
|
@ -309,7 +306,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime,
|
|||
uint32_t swab = event->payload.data;
|
||||
unsigned long long total = htole32(swab);
|
||||
event = reinterpret_cast<android_log_event_int_t*>(
|
||||
const_cast<char*>(elem->getMsg()));
|
||||
const_cast<char*>(elem->getMsg()));
|
||||
swab = event->payload.data;
|
||||
|
||||
lastLoggedElements[LOG_ID_EVENTS] = elem;
|
||||
|
@ -346,15 +343,15 @@ int LogBuffer::log(log_id_t log_id, log_time realtime,
|
|||
pthread_mutex_unlock(&mLogElementsLock);
|
||||
return len;
|
||||
}
|
||||
if (dropped) { // State 1 or 2
|
||||
if (count) { // State 2
|
||||
log(dropped); // report chatty
|
||||
} else { // State 1
|
||||
delete dropped;
|
||||
if (dropped) { // State 1 or 2
|
||||
if (count) { // State 2
|
||||
log(dropped); // report chatty
|
||||
} else { // State 1
|
||||
delete dropped;
|
||||
}
|
||||
droppedElements[log_id] = NULL;
|
||||
log(currentLast); // report last message in the series
|
||||
} else { // State 0
|
||||
log(currentLast); // report last message in the series
|
||||
} else { // State 0
|
||||
delete currentLast;
|
||||
}
|
||||
}
|
||||
|
@ -390,7 +387,7 @@ void LogBuffer::log(LogBufferElement* elem) {
|
|||
LogTimeEntry::lock();
|
||||
|
||||
LastLogTimes::iterator times = mTimes.begin();
|
||||
while(times != mTimes.end()) {
|
||||
while (times != mTimes.end()) {
|
||||
LogTimeEntry* entry = (*times);
|
||||
if (entry->owned_Locked()) {
|
||||
if (!entry->mNonBlock) {
|
||||
|
@ -405,8 +402,7 @@ void LogBuffer::log(LogBufferElement* elem) {
|
|||
times++;
|
||||
}
|
||||
|
||||
if (end_always
|
||||
|| (end_set && (end >= (*last)->getSequence()))) {
|
||||
if (end_always || (end_set && (end >= (*last)->getSequence()))) {
|
||||
mLogElements.push_back(elem);
|
||||
} else {
|
||||
mLogElements.insert(last, elem);
|
||||
|
@ -444,30 +440,31 @@ void LogBuffer::maybePrune(log_id_t id) {
|
|||
}
|
||||
|
||||
LogBufferElementCollection::iterator LogBuffer::erase(
|
||||
LogBufferElementCollection::iterator it, bool coalesce) {
|
||||
LogBufferElement *element = *it;
|
||||
LogBufferElementCollection::iterator it, bool coalesce) {
|
||||
LogBufferElement* element = *it;
|
||||
log_id_t id = element->getLogId();
|
||||
|
||||
// Remove iterator references in the various lists that will become stale
|
||||
// after the element is erased from the main logging list.
|
||||
|
||||
{ // start of scope for found iterator
|
||||
int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
|
||||
element->getTag() : element->getUid();
|
||||
{ // start of scope for found iterator
|
||||
int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
|
||||
? element->getTag()
|
||||
: element->getUid();
|
||||
LogBufferIteratorMap::iterator found = mLastWorst[id].find(key);
|
||||
if ((found != mLastWorst[id].end()) && (it == found->second)) {
|
||||
mLastWorst[id].erase(found);
|
||||
}
|
||||
}
|
||||
|
||||
{ // start of scope for pid found iterator
|
||||
{ // start of scope for pid found iterator
|
||||
// element->getUid() may not be AID_SYSTEM for next-best-watermark.
|
||||
// will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and
|
||||
// long term code stability, find() check should be fast for those ids.
|
||||
LogBufferPidIteratorMap::iterator found =
|
||||
mLastWorstPidOfSystem[id].find(element->getPid());
|
||||
if ((found != mLastWorstPidOfSystem[id].end())
|
||||
&& (it == found->second)) {
|
||||
if ((found != mLastWorstPidOfSystem[id].end()) &&
|
||||
(it == found->second)) {
|
||||
mLastWorstPidOfSystem[id].erase(found);
|
||||
}
|
||||
}
|
||||
|
@ -479,34 +476,35 @@ LogBufferElementCollection::iterator LogBuffer::erase(
|
|||
}
|
||||
#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
|
||||
LogBufferElementCollection::iterator bad = it;
|
||||
int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
|
||||
element->getTag() : element->getUid();
|
||||
int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
|
||||
? element->getTag()
|
||||
: element->getUid();
|
||||
#endif
|
||||
it = mLogElements.erase(it);
|
||||
if (doSetLast) {
|
||||
log_id_for_each(i) {
|
||||
if (setLast[i]) {
|
||||
if (__predict_false(it == mLogElements.end())) { // impossible
|
||||
if (__predict_false(it == mLogElements.end())) { // impossible
|
||||
mLastSet[i] = false;
|
||||
mLast[i] = mLogElements.begin();
|
||||
} else {
|
||||
mLast[i] = it; // push down the road as next-best-watermark
|
||||
mLast[i] = it; // push down the road as next-best-watermark
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
|
||||
log_id_for_each(i) {
|
||||
for(auto b : mLastWorst[i]) {
|
||||
for (auto b : mLastWorst[i]) {
|
||||
if (bad == b.second) {
|
||||
android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n",
|
||||
i, b.first, key);
|
||||
android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n", i,
|
||||
b.first, key);
|
||||
}
|
||||
}
|
||||
for(auto b : mLastWorstPidOfSystem[i]) {
|
||||
for (auto b : mLastWorstPidOfSystem[i]) {
|
||||
if (bad == b.second) {
|
||||
android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n",
|
||||
i, b.first);
|
||||
android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n", i,
|
||||
b.first);
|
||||
}
|
||||
}
|
||||
if (mLastSet[i] && (bad == mLast[i])) {
|
||||
|
@ -539,32 +537,29 @@ class LogBufferElementKey {
|
|||
uint64_t value;
|
||||
} __packed;
|
||||
|
||||
public:
|
||||
LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid):
|
||||
uid(uid),
|
||||
pid(pid),
|
||||
tid(tid)
|
||||
{
|
||||
public:
|
||||
LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid)
|
||||
: uid(uid), pid(pid), tid(tid) {
|
||||
}
|
||||
explicit LogBufferElementKey(uint64_t key) : value(key) {
|
||||
}
|
||||
explicit LogBufferElementKey(uint64_t key):value(key) { }
|
||||
|
||||
uint64_t getKey() { return value; }
|
||||
uint64_t getKey() {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
class LogBufferElementLast {
|
||||
|
||||
typedef std::unordered_map<uint64_t, LogBufferElement *> LogBufferElementMap;
|
||||
typedef std::unordered_map<uint64_t, LogBufferElement*> LogBufferElementMap;
|
||||
LogBufferElementMap map;
|
||||
|
||||
public:
|
||||
|
||||
bool coalesce(LogBufferElement *element, unsigned short dropped) {
|
||||
LogBufferElementKey key(element->getUid(),
|
||||
element->getPid(),
|
||||
public:
|
||||
bool coalesce(LogBufferElement* element, unsigned short dropped) {
|
||||
LogBufferElementKey key(element->getUid(), element->getPid(),
|
||||
element->getTid());
|
||||
LogBufferElementMap::iterator it = map.find(key.getKey());
|
||||
if (it != map.end()) {
|
||||
LogBufferElement *found = it->second;
|
||||
LogBufferElement* found = it->second;
|
||||
unsigned short moreDropped = found->getDropped();
|
||||
if ((dropped + moreDropped) > USHRT_MAX) {
|
||||
map.erase(it);
|
||||
|
@ -576,9 +571,8 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
void add(LogBufferElement *element) {
|
||||
LogBufferElementKey key(element->getUid(),
|
||||
element->getPid(),
|
||||
void add(LogBufferElement* element) {
|
||||
LogBufferElementKey key(element->getUid(), element->getPid(),
|
||||
element->getTid());
|
||||
map[key.getKey()] = element;
|
||||
}
|
||||
|
@ -587,20 +581,19 @@ public:
|
|||
map.clear();
|
||||
}
|
||||
|
||||
void clear(LogBufferElement *element) {
|
||||
uint64_t current = element->getRealTime().nsec()
|
||||
- (EXPIRE_RATELIMIT * NS_PER_SEC);
|
||||
for(LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
|
||||
LogBufferElement *mapElement = it->second;
|
||||
if ((mapElement->getDropped() >= EXPIRE_THRESHOLD)
|
||||
&& (current > mapElement->getRealTime().nsec())) {
|
||||
void clear(LogBufferElement* element) {
|
||||
uint64_t current =
|
||||
element->getRealTime().nsec() - (EXPIRE_RATELIMIT * NS_PER_SEC);
|
||||
for (LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
|
||||
LogBufferElement* mapElement = it->second;
|
||||
if ((mapElement->getDropped() >= EXPIRE_THRESHOLD) &&
|
||||
(current > mapElement->getRealTime().nsec())) {
|
||||
it = map.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// prune "pruneRows" of type "id" from the buffer.
|
||||
|
@ -651,7 +644,7 @@ public:
|
|||
// mLogElementsLock must be held when this function is called.
|
||||
//
|
||||
bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
||||
LogTimeEntry *oldest = NULL;
|
||||
LogTimeEntry* oldest = NULL;
|
||||
bool busy = false;
|
||||
bool clearAll = pruneRows == ULONG_MAX;
|
||||
|
||||
|
@ -659,13 +652,12 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
|
||||
// Region locked?
|
||||
LastLogTimes::iterator times = mTimes.begin();
|
||||
while(times != mTimes.end()) {
|
||||
LogTimeEntry *entry = (*times);
|
||||
if (entry->owned_Locked() && entry->isWatching(id)
|
||||
&& (!oldest ||
|
||||
(oldest->mStart > entry->mStart) ||
|
||||
((oldest->mStart == entry->mStart) &&
|
||||
(entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec)))) {
|
||||
while (times != mTimes.end()) {
|
||||
LogTimeEntry* entry = (*times);
|
||||
if (entry->owned_Locked() && entry->isWatching(id) &&
|
||||
(!oldest || (oldest->mStart > entry->mStart) ||
|
||||
((oldest->mStart == entry->mStart) &&
|
||||
(entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec)))) {
|
||||
oldest = entry;
|
||||
}
|
||||
times++;
|
||||
|
@ -673,14 +665,15 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
|
||||
LogBufferElementCollection::iterator it;
|
||||
|
||||
if (__predict_false(caller_uid != AID_ROOT)) { // unlikely
|
||||
if (__predict_false(caller_uid != AID_ROOT)) { // unlikely
|
||||
// Only here if clear all request from non system source, so chatty
|
||||
// filter logistics is not required.
|
||||
it = mLastSet[id] ? mLast[id] : mLogElements.begin();
|
||||
while (it != mLogElements.end()) {
|
||||
LogBufferElement *element = *it;
|
||||
LogBufferElement* element = *it;
|
||||
|
||||
if ((element->getLogId() != id) || (element->getUid() != caller_uid)) {
|
||||
if ((element->getLogId() != id) ||
|
||||
(element->getUid() != caller_uid)) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
@ -713,26 +706,28 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
bool hasBlacklist = (id != LOG_ID_SECURITY) && mPrune.naughty();
|
||||
while (!clearAll && (pruneRows > 0)) {
|
||||
// recalculate the worst offender on every batched pass
|
||||
int worst = -1; // not valid for getUid() or getKey()
|
||||
int worst = -1; // not valid for getUid() or getKey()
|
||||
size_t worst_sizes = 0;
|
||||
size_t second_worst_sizes = 0;
|
||||
pid_t worstPid = 0; // POSIX guarantees PID != 0
|
||||
pid_t worstPid = 0; // POSIX guarantees PID != 0
|
||||
|
||||
if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) {
|
||||
// Calculate threshold as 12.5% of available storage
|
||||
size_t threshold = log_buffer_size(id) / 8;
|
||||
|
||||
if ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) {
|
||||
stats.sortTags(AID_ROOT, (pid_t)0, 2, id).findWorst(
|
||||
worst, worst_sizes, second_worst_sizes, threshold);
|
||||
stats.sortTags(AID_ROOT, (pid_t)0, 2, id)
|
||||
.findWorst(worst, worst_sizes, second_worst_sizes,
|
||||
threshold);
|
||||
// per-pid filter for AID_SYSTEM sources is too complex
|
||||
} else {
|
||||
stats.sort(AID_ROOT, (pid_t)0, 2, id).findWorst(
|
||||
worst, worst_sizes, second_worst_sizes, threshold);
|
||||
stats.sort(AID_ROOT, (pid_t)0, 2, id)
|
||||
.findWorst(worst, worst_sizes, second_worst_sizes,
|
||||
threshold);
|
||||
|
||||
if ((worst == AID_SYSTEM) && mPrune.worstPidOfSystemEnabled()) {
|
||||
stats.sortPids(worst, (pid_t)0, 2, id).findWorst(
|
||||
worstPid, worst_sizes, second_worst_sizes);
|
||||
stats.sortPids(worst, (pid_t)0, 2, id)
|
||||
.findWorst(worstPid, worst_sizes, second_worst_sizes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -751,35 +746,34 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
// - check age-out of preserved logs
|
||||
bool gc = pruneRows <= 1;
|
||||
if (!gc && (worst != -1)) {
|
||||
{ // begin scope for worst found iterator
|
||||
LogBufferIteratorMap::iterator found = mLastWorst[id].find(worst);
|
||||
if ((found != mLastWorst[id].end())
|
||||
&& (found->second != mLogElements.end())) {
|
||||
{ // begin scope for worst found iterator
|
||||
LogBufferIteratorMap::iterator found =
|
||||
mLastWorst[id].find(worst);
|
||||
if ((found != mLastWorst[id].end()) &&
|
||||
(found->second != mLogElements.end())) {
|
||||
leading = false;
|
||||
it = found->second;
|
||||
}
|
||||
}
|
||||
if (worstPid) { // begin scope for pid worst found iterator
|
||||
if (worstPid) { // begin scope for pid worst found iterator
|
||||
// FYI: worstPid only set if !LOG_ID_EVENTS and
|
||||
// !LOG_ID_SECURITY, not going to make that assumption ...
|
||||
LogBufferPidIteratorMap::iterator found
|
||||
= mLastWorstPidOfSystem[id].find(worstPid);
|
||||
if ((found != mLastWorstPidOfSystem[id].end())
|
||||
&& (found->second != mLogElements.end())) {
|
||||
LogBufferPidIteratorMap::iterator found =
|
||||
mLastWorstPidOfSystem[id].find(worstPid);
|
||||
if ((found != mLastWorstPidOfSystem[id].end()) &&
|
||||
(found->second != mLogElements.end())) {
|
||||
leading = false;
|
||||
it = found->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
static const timespec too_old = {
|
||||
EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
|
||||
};
|
||||
static const timespec too_old = { EXPIRE_HOUR_THRESHOLD * 60 * 60, 0 };
|
||||
LogBufferElementCollection::iterator lastt;
|
||||
lastt = mLogElements.end();
|
||||
--lastt;
|
||||
LogBufferElementLast last;
|
||||
while (it != mLogElements.end()) {
|
||||
LogBufferElement *element = *it;
|
||||
LogBufferElement* element = *it;
|
||||
|
||||
if (oldest && (oldest->mStart <= element->getSequence())) {
|
||||
busy = true;
|
||||
|
@ -813,9 +807,9 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
continue;
|
||||
}
|
||||
|
||||
int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
|
||||
element->getTag() :
|
||||
element->getUid();
|
||||
int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
|
||||
? element->getTag()
|
||||
: element->getUid();
|
||||
|
||||
if (hasBlacklist && mPrune.naughty(element)) {
|
||||
last.clear(element);
|
||||
|
@ -839,32 +833,32 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((element->getRealTime() < ((*lastt)->getRealTime() - too_old))
|
||||
|| (element->getRealTime() > (*lastt)->getRealTime())) {
|
||||
if ((element->getRealTime() < ((*lastt)->getRealTime() - too_old)) ||
|
||||
(element->getRealTime() > (*lastt)->getRealTime())) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (dropped) {
|
||||
last.add(element);
|
||||
if (worstPid
|
||||
&& ((!gc && (element->getPid() == worstPid))
|
||||
|| (mLastWorstPidOfSystem[id].find(element->getPid())
|
||||
== mLastWorstPidOfSystem[id].end()))) {
|
||||
if (worstPid &&
|
||||
((!gc && (element->getPid() == worstPid)) ||
|
||||
(mLastWorstPidOfSystem[id].find(element->getPid()) ==
|
||||
mLastWorstPidOfSystem[id].end()))) {
|
||||
// element->getUid() may not be AID_SYSTEM, next best
|
||||
// watermark if current one empty. id is not LOG_ID_EVENTS
|
||||
// or LOG_ID_SECURITY because of worstPid check.
|
||||
mLastWorstPidOfSystem[id][element->getPid()] = it;
|
||||
}
|
||||
if ((!gc && !worstPid && (key == worst))
|
||||
|| (mLastWorst[id].find(key) == mLastWorst[id].end())) {
|
||||
if ((!gc && !worstPid && (key == worst)) ||
|
||||
(mLastWorst[id].find(key) == mLastWorst[id].end())) {
|
||||
mLastWorst[id][key] = it;
|
||||
}
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((key != worst)
|
||||
|| (worstPid && (element->getPid() != worstPid))) {
|
||||
if ((key != worst) ||
|
||||
(worstPid && (element->getPid() != worstPid))) {
|
||||
leading = false;
|
||||
last.clear(element);
|
||||
++it;
|
||||
|
@ -892,16 +886,16 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
it = erase(it, true);
|
||||
} else {
|
||||
last.add(element);
|
||||
if (worstPid && (!gc
|
||||
|| (mLastWorstPidOfSystem[id].find(worstPid)
|
||||
== mLastWorstPidOfSystem[id].end()))) {
|
||||
if (worstPid &&
|
||||
(!gc || (mLastWorstPidOfSystem[id].find(worstPid) ==
|
||||
mLastWorstPidOfSystem[id].end()))) {
|
||||
// element->getUid() may not be AID_SYSTEM, next best
|
||||
// watermark if current one empty. id is not
|
||||
// LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid.
|
||||
mLastWorstPidOfSystem[id][worstPid] = it;
|
||||
}
|
||||
if ((!gc && !worstPid) ||
|
||||
(mLastWorst[id].find(worst) == mLastWorst[id].end())) {
|
||||
(mLastWorst[id].find(worst) == mLastWorst[id].end())) {
|
||||
mLastWorst[id][worst] = it;
|
||||
}
|
||||
++it;
|
||||
|
@ -915,15 +909,15 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
last.clear();
|
||||
|
||||
if (!kick || !mPrune.worstUidEnabled()) {
|
||||
break; // the following loop will ask bad clients to skip/drop
|
||||
break; // the following loop will ask bad clients to skip/drop
|
||||
}
|
||||
}
|
||||
|
||||
bool whitelist = false;
|
||||
bool hasWhitelist = (id != LOG_ID_SECURITY) && mPrune.nice() && !clearAll;
|
||||
it = mLastSet[id] ? mLast[id] : mLogElements.begin();
|
||||
while((pruneRows > 0) && (it != mLogElements.end())) {
|
||||
LogBufferElement *element = *it;
|
||||
while ((pruneRows > 0) && (it != mLogElements.end())) {
|
||||
LogBufferElement* element = *it;
|
||||
|
||||
if (element->getLogId() != id) {
|
||||
it++;
|
||||
|
@ -966,8 +960,8 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
|||
// Do not save the whitelist if we are reader range limited
|
||||
if (whitelist && (pruneRows > 0)) {
|
||||
it = mLastSet[id] ? mLast[id] : mLogElements.begin();
|
||||
while((it != mLogElements.end()) && (pruneRows > 0)) {
|
||||
LogBufferElement *element = *it;
|
||||
while ((it != mLogElements.end()) && (pruneRows > 0)) {
|
||||
LogBufferElement* element = *it;
|
||||
|
||||
if (element->getLogId() != id) {
|
||||
++it;
|
||||
|
@ -1007,7 +1001,7 @@ bool LogBuffer::clear(log_id_t id, uid_t uid) {
|
|||
bool busy = true;
|
||||
// If it takes more than 4 tries (seconds) to clear, then kill reader(s)
|
||||
for (int retry = 4;;) {
|
||||
if (retry == 1) { // last pass
|
||||
if (retry == 1) { // last pass
|
||||
// Check if it is still busy after the sleep, we say prune
|
||||
// one entry, not another clear run, so we are looking for
|
||||
// the quick side effect of the return value to tell us if
|
||||
|
@ -1023,7 +1017,7 @@ bool LogBuffer::clear(log_id_t id, uid_t uid) {
|
|||
LogTimeEntry::lock();
|
||||
LastLogTimes::iterator times = mTimes.begin();
|
||||
while (times != mTimes.end()) {
|
||||
LogTimeEntry *entry = (*times);
|
||||
LogTimeEntry* entry = (*times);
|
||||
// Killer punch
|
||||
if (entry->owned_Locked() && entry->isWatching(id)) {
|
||||
entry->release_Locked();
|
||||
|
@ -1039,7 +1033,7 @@ bool LogBuffer::clear(log_id_t id, uid_t uid) {
|
|||
if (!busy || !--retry) {
|
||||
break;
|
||||
}
|
||||
sleep (1); // Let reader(s) catch up after notification
|
||||
sleep(1); // Let reader(s) catch up after notification
|
||||
}
|
||||
return busy;
|
||||
}
|
||||
|
@ -1073,9 +1067,8 @@ unsigned long LogBuffer::getSize(log_id_t id) {
|
|||
}
|
||||
|
||||
uint64_t LogBuffer::flushTo(
|
||||
SocketClient *reader, const uint64_t start,
|
||||
bool privileged, bool security,
|
||||
int (*filter)(const LogBufferElement *element, void *arg), void *arg) {
|
||||
SocketClient* reader, const uint64_t start, bool privileged, bool security,
|
||||
int (*filter)(const LogBufferElement* element, void* arg), void* arg) {
|
||||
LogBufferElementCollection::iterator it;
|
||||
uint64_t max = start;
|
||||
uid_t uid = reader->getUid();
|
||||
|
@ -1088,9 +1081,10 @@ uint64_t LogBuffer::flushTo(
|
|||
} else {
|
||||
// Client wants to start from some specified time. Chances are
|
||||
// we are better off starting from the end of the time sorted list.
|
||||
for (it = mLogElements.end(); it != mLogElements.begin(); /* do nothing */) {
|
||||
for (it = mLogElements.end(); it != mLogElements.begin();
|
||||
/* do nothing */) {
|
||||
--it;
|
||||
LogBufferElement *element = *it;
|
||||
LogBufferElement* element = *it;
|
||||
if (element->getSequence() <= start) {
|
||||
it++;
|
||||
break;
|
||||
|
@ -1103,7 +1097,7 @@ uint64_t LogBuffer::flushTo(
|
|||
pid_t lastTid[LOG_ID_MAX] = { 0 };
|
||||
|
||||
for (; it != mLogElements.end(); ++it) {
|
||||
LogBufferElement *element = *it;
|
||||
LogBufferElement* element = *it;
|
||||
|
||||
if (!privileged && (element->getUid() != uid)) {
|
||||
continue;
|
||||
|
@ -1134,8 +1128,8 @@ uint64_t LogBuffer::flushTo(
|
|||
// multiple identical squash. chatty that differs source
|
||||
// is due to spam filter. chatty to chatty of different
|
||||
// source is also due to spam filter.
|
||||
lastTid[element->getLogId()] = (element->getDropped() && !sameTid) ?
|
||||
0 : element->getTid();
|
||||
lastTid[element->getLogId()] =
|
||||
(element->getDropped() && !sameTid) ? 0 : element->getTid();
|
||||
|
||||
pthread_mutex_unlock(&mLogElementsLock);
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
#include <sysutils/SocketClient.h>
|
||||
|
||||
#include "LogBufferElement.h"
|
||||
#include "LogStatistics.h"
|
||||
#include "LogTags.h"
|
||||
#include "LogTimes.h"
|
||||
#include "LogStatistics.h"
|
||||
#include "LogWhiteBlackList.h"
|
||||
|
||||
//
|
||||
|
@ -41,7 +41,7 @@
|
|||
//
|
||||
namespace android {
|
||||
|
||||
static bool isMonotonic(const log_time &mono) {
|
||||
static bool isMonotonic(const log_time& mono) {
|
||||
static const uint32_t EPOCH_PLUS_2_YEARS = 2 * 24 * 60 * 60 * 1461 / 4;
|
||||
static const uint32_t EPOCH_PLUS_MINUTE = 60;
|
||||
|
||||
|
@ -70,10 +70,9 @@ static bool isMonotonic(const log_time &mono) {
|
|||
/* dividing line half way between monotonic and realtime */
|
||||
return mono.tv_sec < ((cpu.tv_sec + now.tv_sec) / 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef std::list<LogBufferElement *> LogBufferElementCollection;
|
||||
typedef std::list<LogBufferElement*> LogBufferElementCollection;
|
||||
|
||||
class LogBuffer {
|
||||
LogBufferElementCollection mLogElements;
|
||||
|
@ -86,14 +85,12 @@ class LogBuffer {
|
|||
LogBufferElementCollection::iterator mLast[LOG_ID_MAX];
|
||||
bool mLastSet[LOG_ID_MAX];
|
||||
// watermark of any worst/chatty uid processing
|
||||
typedef std::unordered_map<uid_t,
|
||||
LogBufferElementCollection::iterator>
|
||||
LogBufferIteratorMap;
|
||||
typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator>
|
||||
LogBufferIteratorMap;
|
||||
LogBufferIteratorMap mLastWorst[LOG_ID_MAX];
|
||||
// watermark of any worst/chatty pid of system processing
|
||||
typedef std::unordered_map<pid_t,
|
||||
LogBufferElementCollection::iterator>
|
||||
LogBufferPidIteratorMap;
|
||||
typedef std::unordered_map<pid_t, LogBufferElementCollection::iterator>
|
||||
LogBufferPidIteratorMap;
|
||||
LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX];
|
||||
|
||||
unsigned long mMaxSize[LOG_ID_MAX];
|
||||
|
@ -106,21 +103,23 @@ class LogBuffer {
|
|||
LogBufferElement* droppedElements[LOG_ID_MAX];
|
||||
void log(LogBufferElement* elem);
|
||||
|
||||
public:
|
||||
LastLogTimes &mTimes;
|
||||
public:
|
||||
LastLogTimes& mTimes;
|
||||
|
||||
explicit LogBuffer(LastLogTimes *times);
|
||||
explicit LogBuffer(LastLogTimes* times);
|
||||
~LogBuffer();
|
||||
void init();
|
||||
bool isMonotonic() { return monotonic; }
|
||||
bool isMonotonic() {
|
||||
return monotonic;
|
||||
}
|
||||
|
||||
int log(log_id_t log_id, log_time realtime,
|
||||
uid_t uid, pid_t pid, pid_t tid,
|
||||
const char *msg, unsigned short len);
|
||||
uint64_t flushTo(SocketClient *writer, const uint64_t start,
|
||||
int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
|
||||
const char* msg, unsigned short len);
|
||||
uint64_t flushTo(SocketClient* writer, const uint64_t start,
|
||||
bool privileged, bool security,
|
||||
int (*filter)(const LogBufferElement *element, void *arg) = NULL,
|
||||
void *arg = NULL);
|
||||
int (*filter)(const LogBufferElement* element,
|
||||
void* arg) = NULL,
|
||||
void* arg = NULL);
|
||||
|
||||
bool clear(log_id_t id, uid_t uid = AID_ROOT);
|
||||
unsigned long getSize(log_id_t id);
|
||||
|
@ -133,27 +132,42 @@ public:
|
|||
stats.enableStatistics();
|
||||
}
|
||||
|
||||
int initPrune(const char *cp) { return mPrune.init(cp); }
|
||||
std::string formatPrune() { return mPrune.format(); }
|
||||
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) {
|
||||
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); }
|
||||
const char* tagToName(uint32_t tag) {
|
||||
return tags.tagToName(tag);
|
||||
}
|
||||
|
||||
// helper must be protected directly or implicitly by lock()/unlock()
|
||||
const char *pidToName(pid_t pid) { return stats.pidToName(pid); }
|
||||
uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
|
||||
const char *uidToName(uid_t uid) { return stats.uidToName(uid); }
|
||||
void lock() { pthread_mutex_lock(&mLogElementsLock); }
|
||||
void unlock() { pthread_mutex_unlock(&mLogElementsLock); }
|
||||
|
||||
private:
|
||||
const char* pidToName(pid_t pid) {
|
||||
return stats.pidToName(pid);
|
||||
}
|
||||
uid_t pidToUid(pid_t pid) {
|
||||
return stats.pidToUid(pid);
|
||||
}
|
||||
const char* uidToName(uid_t uid) {
|
||||
return stats.uidToName(uid);
|
||||
}
|
||||
void lock() {
|
||||
pthread_mutex_lock(&mLogElementsLock);
|
||||
}
|
||||
void unlock() {
|
||||
pthread_mutex_unlock(&mLogElementsLock);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t minPrune = 4;
|
||||
static constexpr size_t maxPrune = 256;
|
||||
|
||||
|
@ -163,4 +177,4 @@ private:
|
|||
LogBufferElementCollection::iterator it, bool coalesce = false);
|
||||
};
|
||||
|
||||
#endif // _LOGD_LOG_BUFFER_H__
|
||||
#endif // _LOGD_LOG_BUFFER_H__
|
||||
|
|
|
@ -35,41 +35,41 @@ atomic_int_fast64_t LogBufferElement::sequence(1);
|
|||
|
||||
LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
|
||||
uid_t uid, pid_t pid, pid_t tid,
|
||||
const char *msg, unsigned short len) :
|
||||
mUid(uid),
|
||||
mPid(pid),
|
||||
mTid(tid),
|
||||
mSequence(sequence.fetch_add(1, memory_order_relaxed)),
|
||||
mRealTime(realtime),
|
||||
mMsgLen(len),
|
||||
mLogId(log_id) {
|
||||
const char* msg, unsigned short len)
|
||||
: mUid(uid),
|
||||
mPid(pid),
|
||||
mTid(tid),
|
||||
mSequence(sequence.fetch_add(1, memory_order_relaxed)),
|
||||
mRealTime(realtime),
|
||||
mMsgLen(len),
|
||||
mLogId(log_id) {
|
||||
mMsg = new char[len];
|
||||
memcpy(mMsg, msg, len);
|
||||
mTag = (isBinary() && (mMsgLen >= sizeof(uint32_t))) ?
|
||||
le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag) :
|
||||
0;
|
||||
mTag = (isBinary() && (mMsgLen >= sizeof(uint32_t)))
|
||||
? le32toh(reinterpret_cast<android_event_header_t*>(mMsg)->tag)
|
||||
: 0;
|
||||
}
|
||||
|
||||
LogBufferElement::LogBufferElement(const LogBufferElement &elem) :
|
||||
mTag(elem.mTag),
|
||||
mUid(elem.mUid),
|
||||
mPid(elem.mPid),
|
||||
mTid(elem.mTid),
|
||||
mSequence(elem.mSequence),
|
||||
mRealTime(elem.mRealTime),
|
||||
mMsgLen(elem.mMsgLen),
|
||||
mLogId(elem.mLogId) {
|
||||
LogBufferElement::LogBufferElement(const LogBufferElement& elem)
|
||||
: mTag(elem.mTag),
|
||||
mUid(elem.mUid),
|
||||
mPid(elem.mPid),
|
||||
mTid(elem.mTid),
|
||||
mSequence(elem.mSequence),
|
||||
mRealTime(elem.mRealTime),
|
||||
mMsgLen(elem.mMsgLen),
|
||||
mLogId(elem.mLogId) {
|
||||
mMsg = new char[mMsgLen];
|
||||
memcpy(mMsg, elem.mMsg, mMsgLen);
|
||||
}
|
||||
|
||||
LogBufferElement::~LogBufferElement() {
|
||||
delete [] mMsg;
|
||||
delete[] mMsg;
|
||||
}
|
||||
|
||||
// caller must own and free character string
|
||||
char *android::tidToName(pid_t tid) {
|
||||
char *retval = NULL;
|
||||
char* android::tidToName(pid_t tid) {
|
||||
char* retval = NULL;
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
|
||||
int fd = open(buffer, O_RDONLY);
|
||||
|
@ -89,7 +89,7 @@ char *android::tidToName(pid_t tid) {
|
|||
}
|
||||
|
||||
// if nothing for comm, check out cmdline
|
||||
char *name = android::pidToName(tid);
|
||||
char* name = android::pidToName(tid);
|
||||
if (!retval) {
|
||||
retval = name;
|
||||
name = NULL;
|
||||
|
@ -101,8 +101,8 @@ char *android::tidToName(pid_t tid) {
|
|||
size_t retval_len = strlen(retval);
|
||||
size_t name_len = strlen(name);
|
||||
// KISS: ToDo: Only checks prefix truncated, not suffix, or both
|
||||
if ((retval_len < name_len)
|
||||
&& !fastcmp<strcmp>(retval, name + name_len - retval_len)) {
|
||||
if ((retval_len < name_len) &&
|
||||
!fastcmp<strcmp>(retval, name + name_len - retval_len)) {
|
||||
free(retval);
|
||||
retval = name;
|
||||
} else {
|
||||
|
@ -113,21 +113,20 @@ char *android::tidToName(pid_t tid) {
|
|||
}
|
||||
|
||||
// assumption: mMsg == NULL
|
||||
size_t LogBufferElement::populateDroppedMessage(char*& buffer,
|
||||
LogBuffer* parent, bool lastSame) {
|
||||
size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogBuffer* parent,
|
||||
bool lastSame) {
|
||||
static const char tag[] = "chatty";
|
||||
|
||||
if (!__android_log_is_loggable_len(ANDROID_LOG_INFO,
|
||||
tag, strlen(tag),
|
||||
if (!__android_log_is_loggable_len(ANDROID_LOG_INFO, tag, strlen(tag),
|
||||
ANDROID_LOG_VERBOSE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char format_uid[] = "uid=%u%s%s %s %u line%s";
|
||||
parent->lock();
|
||||
const char *name = parent->uidToName(mUid);
|
||||
const char* name = parent->uidToName(mUid);
|
||||
parent->unlock();
|
||||
const char *commName = android::tidToName(mTid);
|
||||
const char* commName = android::tidToName(mTid);
|
||||
if (!commName && (mTid != mPid)) {
|
||||
commName = android::tidToName(mPid);
|
||||
}
|
||||
|
@ -140,35 +139,35 @@ size_t LogBufferElement::populateDroppedMessage(char*& buffer,
|
|||
size_t len = strlen(name + 1);
|
||||
if (!strncmp(name + 1, commName + 1, len)) {
|
||||
if (commName[len + 1] == '\0') {
|
||||
free(const_cast<char *>(commName));
|
||||
free(const_cast<char*>(commName));
|
||||
commName = NULL;
|
||||
} else {
|
||||
free(const_cast<char *>(name));
|
||||
free(const_cast<char*>(name));
|
||||
name = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (name) {
|
||||
char *buf = NULL;
|
||||
char* buf = NULL;
|
||||
asprintf(&buf, "(%s)", name);
|
||||
if (buf) {
|
||||
free(const_cast<char *>(name));
|
||||
free(const_cast<char*>(name));
|
||||
name = buf;
|
||||
}
|
||||
}
|
||||
if (commName) {
|
||||
char *buf = NULL;
|
||||
char* buf = NULL;
|
||||
asprintf(&buf, " %s", commName);
|
||||
if (buf) {
|
||||
free(const_cast<char *>(commName));
|
||||
free(const_cast<char*>(commName));
|
||||
commName = buf;
|
||||
}
|
||||
}
|
||||
// identical to below to calculate the buffer size required
|
||||
const char* type = lastSame ? "identical" : "expire";
|
||||
size_t len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
|
||||
commName ? commName : "", type,
|
||||
mDropped, (mDropped > 1) ? "s" : "");
|
||||
commName ? commName : "", type, mDropped,
|
||||
(mDropped > 1) ? "s" : "");
|
||||
|
||||
size_t hdrLen;
|
||||
if (isBinary()) {
|
||||
|
@ -177,17 +176,17 @@ size_t LogBufferElement::populateDroppedMessage(char*& buffer,
|
|||
hdrLen = 1 + sizeof(tag);
|
||||
}
|
||||
|
||||
buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
|
||||
buffer = static_cast<char*>(calloc(1, hdrLen + len + 1));
|
||||
if (!buffer) {
|
||||
free(const_cast<char *>(name));
|
||||
free(const_cast<char *>(commName));
|
||||
free(const_cast<char*>(name));
|
||||
free(const_cast<char*>(commName));
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t retval = hdrLen + len;
|
||||
if (isBinary()) {
|
||||
android_log_event_string_t *event =
|
||||
reinterpret_cast<android_log_event_string_t *>(buffer);
|
||||
android_log_event_string_t* event =
|
||||
reinterpret_cast<android_log_event_string_t*>(buffer);
|
||||
|
||||
event->header.tag = htole32(CHATTY_LOG_TAG);
|
||||
event->type = EVENT_TYPE_STRING;
|
||||
|
@ -199,10 +198,10 @@ size_t LogBufferElement::populateDroppedMessage(char*& buffer,
|
|||
}
|
||||
|
||||
snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "",
|
||||
commName ? commName : "", type,
|
||||
mDropped, (mDropped > 1) ? "s" : "");
|
||||
free(const_cast<char *>(name));
|
||||
free(const_cast<char *>(commName));
|
||||
commName ? commName : "", type, mDropped,
|
||||
(mDropped > 1) ? "s" : "");
|
||||
free(const_cast<char*>(name));
|
||||
free(const_cast<char*>(commName));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -213,9 +212,8 @@ uint64_t LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent,
|
|||
|
||||
memset(&entry, 0, sizeof(struct logger_entry_v4));
|
||||
|
||||
entry.hdr_size = privileged ?
|
||||
sizeof(struct logger_entry_v4) :
|
||||
sizeof(struct logger_entry_v3);
|
||||
entry.hdr_size = privileged ? sizeof(struct logger_entry_v4)
|
||||
: sizeof(struct logger_entry_v3);
|
||||
entry.lid = mLogId;
|
||||
entry.pid = mPid;
|
||||
entry.tid = mTid;
|
||||
|
@ -227,13 +225,11 @@ uint64_t LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent,
|
|||
iovec[0].iov_base = &entry;
|
||||
iovec[0].iov_len = entry.hdr_size;
|
||||
|
||||
char *buffer = NULL;
|
||||
char* buffer = NULL;
|
||||
|
||||
if (!mMsg) {
|
||||
entry.len = populateDroppedMessage(buffer, parent, lastSame);
|
||||
if (!entry.len) {
|
||||
return mSequence;
|
||||
}
|
||||
if (!entry.len) return mSequence;
|
||||
iovec[1].iov_base = buffer;
|
||||
} else {
|
||||
entry.len = mMsgLen;
|
||||
|
@ -243,9 +239,7 @@ uint64_t LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent,
|
|||
|
||||
uint64_t retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mSequence;
|
||||
|
||||
if (buffer) {
|
||||
free(buffer);
|
||||
}
|
||||
if (buffer) free(buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -26,69 +26,89 @@
|
|||
|
||||
class LogBuffer;
|
||||
|
||||
#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
|
||||
// non-chatty UIDs less than this age in hours
|
||||
#define EXPIRE_THRESHOLD 10 // A smaller expire count is considered too
|
||||
// chatty for the temporal expire messages
|
||||
#define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration
|
||||
#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
|
||||
// non-chatty UIDs less than this age in hours
|
||||
#define EXPIRE_THRESHOLD 10 // A smaller expire count is considered too
|
||||
// chatty for the temporal expire messages
|
||||
#define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration
|
||||
|
||||
class LogBufferElement {
|
||||
|
||||
friend LogBuffer;
|
||||
|
||||
// sized to match reality of incoming log packets
|
||||
uint32_t mTag; // only valid for isBinary()
|
||||
uint32_t mTag; // only valid for isBinary()
|
||||
const uint32_t mUid;
|
||||
const uint32_t mPid;
|
||||
const uint32_t mTid;
|
||||
const uint64_t mSequence;
|
||||
log_time mRealTime;
|
||||
char *mMsg;
|
||||
char* mMsg;
|
||||
union {
|
||||
const uint16_t mMsgLen; // mMSg != NULL
|
||||
uint16_t mDropped; // mMsg == NULL
|
||||
const uint16_t mMsgLen; // mMSg != NULL
|
||||
uint16_t mDropped; // mMsg == NULL
|
||||
};
|
||||
const uint8_t mLogId;
|
||||
|
||||
static atomic_int_fast64_t sequence;
|
||||
|
||||
// assumption: mMsg == NULL
|
||||
size_t populateDroppedMessage(char*& buffer,
|
||||
LogBuffer* parent,
|
||||
size_t populateDroppedMessage(char*& buffer, LogBuffer* parent,
|
||||
bool lastSame);
|
||||
public:
|
||||
LogBufferElement(log_id_t log_id, log_time realtime,
|
||||
uid_t uid, pid_t pid, pid_t tid,
|
||||
const char *msg, unsigned short len);
|
||||
LogBufferElement(const LogBufferElement &elem);
|
||||
|
||||
public:
|
||||
LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
|
||||
pid_t tid, const char* msg, unsigned short len);
|
||||
LogBufferElement(const LogBufferElement& elem);
|
||||
virtual ~LogBufferElement();
|
||||
|
||||
bool isBinary(void) const {
|
||||
return (mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY);
|
||||
}
|
||||
|
||||
log_id_t getLogId() const { return static_cast<log_id_t>(mLogId); }
|
||||
uid_t getUid(void) const { return mUid; }
|
||||
pid_t getPid(void) const { return mPid; }
|
||||
pid_t getTid(void) const { return mTid; }
|
||||
uint32_t getTag() const { return mTag; }
|
||||
unsigned short getDropped(void) const { return mMsg ? 0 : mDropped; }
|
||||
log_id_t getLogId() const {
|
||||
return static_cast<log_id_t>(mLogId);
|
||||
}
|
||||
uid_t getUid(void) const {
|
||||
return mUid;
|
||||
}
|
||||
pid_t getPid(void) const {
|
||||
return mPid;
|
||||
}
|
||||
pid_t getTid(void) const {
|
||||
return mTid;
|
||||
}
|
||||
uint32_t getTag() const {
|
||||
return mTag;
|
||||
}
|
||||
unsigned short getDropped(void) const {
|
||||
return mMsg ? 0 : mDropped;
|
||||
}
|
||||
unsigned short setDropped(unsigned short value) {
|
||||
if (mMsg) {
|
||||
delete [] mMsg;
|
||||
delete[] mMsg;
|
||||
mMsg = NULL;
|
||||
}
|
||||
return mDropped = value;
|
||||
}
|
||||
unsigned short getMsgLen() const { return mMsg ? mMsgLen : 0; }
|
||||
const char* getMsg() const { return mMsg; }
|
||||
uint64_t getSequence(void) const { return mSequence; }
|
||||
static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
|
||||
log_time getRealTime(void) const { return mRealTime; }
|
||||
unsigned short getMsgLen() const {
|
||||
return mMsg ? mMsgLen : 0;
|
||||
}
|
||||
const char* getMsg() const {
|
||||
return mMsg;
|
||||
}
|
||||
uint64_t getSequence(void) const {
|
||||
return mSequence;
|
||||
}
|
||||
static uint64_t getCurrentSequence(void) {
|
||||
return sequence.load(memory_order_relaxed);
|
||||
}
|
||||
log_time getRealTime(void) const {
|
||||
return mRealTime;
|
||||
}
|
||||
|
||||
static const uint64_t FLUSH_ERROR;
|
||||
uint64_t flushTo(SocketClient* writer, LogBuffer* parent,
|
||||
bool privileged, bool lastSame);
|
||||
uint64_t flushTo(SocketClient* writer, LogBuffer* parent, bool privileged,
|
||||
bool lastSame);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "LogCommand.h"
|
||||
#include "LogUtils.h"
|
||||
|
||||
LogCommand::LogCommand(const char *cmd) : FrameworkCommand(cmd) {
|
||||
LogCommand::LogCommand(const char* cmd) : FrameworkCommand(cmd) {
|
||||
}
|
||||
|
||||
// gets a list of supplementary group IDs associated with
|
||||
|
@ -40,8 +40,8 @@ LogCommand::LogCommand(const char *cmd) : FrameworkCommand(cmd) {
|
|||
// has open permissions, and one that has restricted
|
||||
// permissions.
|
||||
|
||||
static bool groupIsLog(char *buf) {
|
||||
char *ptr;
|
||||
static bool groupIsLog(char* buf) {
|
||||
char* ptr;
|
||||
static const char ws[] = " \n";
|
||||
|
||||
for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(NULL, ws, &ptr)) {
|
||||
|
@ -91,15 +91,14 @@ bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid) {
|
|||
// doubt, but we expect the falses should be reduced significantly as
|
||||
// three times is a charm.
|
||||
//
|
||||
for (int retry = 3;
|
||||
!(ret = foundGid && foundUid && foundLog) && retry;
|
||||
--retry) {
|
||||
FILE *file = fopen(filename, "r");
|
||||
for (int retry = 3; !(ret = foundGid && foundUid && foundLog) && retry;
|
||||
--retry) {
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (!file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char *line = NULL;
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
while (getline(&line, &len, file) > 0) {
|
||||
static const char groups_string[] = "Groups:\t";
|
||||
|
@ -111,29 +110,25 @@ bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid) {
|
|||
foundLog = true;
|
||||
}
|
||||
} else if (strncmp(uid_string, line, sizeof(uid_string) - 1) == 0) {
|
||||
uid_t u[4] = { (uid_t) -1, (uid_t) -1, (uid_t) -1, (uid_t) -1};
|
||||
uid_t u[4] = { (uid_t)-1, (uid_t)-1, (uid_t)-1, (uid_t)-1 };
|
||||
|
||||
sscanf(line + sizeof(uid_string) - 1, "%u\t%u\t%u\t%u",
|
||||
&u[0], &u[1], &u[2], &u[3]);
|
||||
sscanf(line + sizeof(uid_string) - 1, "%u\t%u\t%u\t%u", &u[0],
|
||||
&u[1], &u[2], &u[3]);
|
||||
|
||||
// Protect against PID reuse by checking that UID is the same
|
||||
if ((uid == u[0])
|
||||
&& (uid == u[1])
|
||||
&& (uid == u[2])
|
||||
&& (uid == u[3])) {
|
||||
if ((uid == u[0]) && (uid == u[1]) && (uid == u[2]) &&
|
||||
(uid == u[3])) {
|
||||
foundUid = true;
|
||||
}
|
||||
} else if (strncmp(gid_string, line, sizeof(gid_string) - 1) == 0) {
|
||||
gid_t g[4] = { (gid_t) -1, (gid_t) -1, (gid_t) -1, (gid_t) -1};
|
||||
gid_t g[4] = { (gid_t)-1, (gid_t)-1, (gid_t)-1, (gid_t)-1 };
|
||||
|
||||
sscanf(line + sizeof(gid_string) - 1, "%u\t%u\t%u\t%u",
|
||||
&g[0], &g[1], &g[2], &g[3]);
|
||||
sscanf(line + sizeof(gid_string) - 1, "%u\t%u\t%u\t%u", &g[0],
|
||||
&g[1], &g[2], &g[3]);
|
||||
|
||||
// Protect against PID reuse by checking that GID is the same
|
||||
if ((gid == g[0])
|
||||
&& (gid == g[1])
|
||||
&& (gid == g[2])
|
||||
&& (gid == g[3])) {
|
||||
if ((gid == g[0]) && (gid == g[1]) && (gid == g[2]) &&
|
||||
(gid == g[3])) {
|
||||
foundGid = true;
|
||||
}
|
||||
}
|
||||
|
@ -145,6 +140,6 @@ bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool clientHasLogCredentials(SocketClient *cli) {
|
||||
bool clientHasLogCredentials(SocketClient* cli) {
|
||||
return clientHasLogCredentials(cli->getUid(), cli->getGid(), cli->getPid());
|
||||
}
|
||||
|
|
|
@ -17,13 +17,14 @@
|
|||
#ifndef _LOGD_COMMAND_H
|
||||
#define _LOGD_COMMAND_H
|
||||
|
||||
#include <sysutils/SocketClient.h>
|
||||
#include <sysutils/FrameworkCommand.h>
|
||||
#include <sysutils/SocketClient.h>
|
||||
|
||||
class LogCommand : public FrameworkCommand {
|
||||
public:
|
||||
explicit LogCommand(const char *cmd);
|
||||
virtual ~LogCommand() {}
|
||||
public:
|
||||
explicit LogCommand(const char* cmd);
|
||||
virtual ~LogCommand() {
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
364
logd/LogKlog.cpp
364
logd/LogKlog.cpp
|
@ -25,25 +25,22 @@
|
|||
#include <sys/uio.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <private/android_logger.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
#include <private/android_logger.h>
|
||||
|
||||
#include "LogBuffer.h"
|
||||
#include "LogKlog.h"
|
||||
#include "LogReader.h"
|
||||
|
||||
#define KMSG_PRIORITY(PRI) \
|
||||
'<', \
|
||||
'0' + (LOG_SYSLOG | (PRI)) / 10, \
|
||||
'0' + (LOG_SYSLOG | (PRI)) % 10, \
|
||||
'>'
|
||||
#define KMSG_PRIORITY(PRI) \
|
||||
'<', '0' + (LOG_SYSLOG | (PRI)) / 10, '0' + (LOG_SYSLOG | (PRI)) % 10, '>'
|
||||
|
||||
static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
|
||||
|
||||
// Parsing is hard
|
||||
|
||||
// called if we see a '<', s is the next character, returns pointer after '>'
|
||||
static char *is_prio(char *s, size_t len) {
|
||||
static char* is_prio(char* s, size_t len) {
|
||||
if (!len || !isdigit(*s++)) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -60,7 +57,7 @@ static char *is_prio(char *s, size_t len) {
|
|||
}
|
||||
|
||||
// called if we see a '[', s is the next character, returns pointer after ']'
|
||||
static char *is_timestamp(char *s, size_t len) {
|
||||
static char* is_timestamp(char* s, size_t len) {
|
||||
while (len && (*s == ' ')) {
|
||||
++s;
|
||||
--len;
|
||||
|
@ -83,19 +80,20 @@ static char *is_timestamp(char *s, size_t len) {
|
|||
}
|
||||
|
||||
// Like strtok_r with "\r\n" except that we look for log signatures (regex)
|
||||
// \(\(<[0-9]\{1,4\}>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[] *[0-9]+[.][0-9]+[]] \)
|
||||
// \(\(<[0-9]\{1,4\}>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[]
|
||||
// *[0-9]+[.][0-9]+[]] \)
|
||||
// and split if we see a second one without a newline.
|
||||
// We allow nuls in content, monitoring the overall length and sub-length of
|
||||
// the discovered tokens.
|
||||
|
||||
#define SIGNATURE_MASK 0xF0
|
||||
#define SIGNATURE_MASK 0xF0
|
||||
// <digit> following ('0' to '9' masked with ~SIGNATURE_MASK) added to signature
|
||||
#define LESS_THAN_SIG SIGNATURE_MASK
|
||||
#define OPEN_BRACKET_SIG ((SIGNATURE_MASK << 1) & SIGNATURE_MASK)
|
||||
#define LESS_THAN_SIG SIGNATURE_MASK
|
||||
#define OPEN_BRACKET_SIG ((SIGNATURE_MASK << 1) & SIGNATURE_MASK)
|
||||
// space is one more than <digit> of 9
|
||||
#define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10))
|
||||
|
||||
char *log_strntok_r(char *s, size_t *len, char **last, size_t *sublen) {
|
||||
char* log_strntok_r(char* s, size_t* len, char** last, size_t* sublen) {
|
||||
*sublen = 0;
|
||||
if (!*len) {
|
||||
return NULL;
|
||||
|
@ -144,32 +142,24 @@ char *log_strntok_r(char *s, size_t *len, char **last, size_t *sublen) {
|
|||
--*len;
|
||||
size_t adjust;
|
||||
switch (c) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
s[-1] = '\0';
|
||||
*last = s;
|
||||
return tok;
|
||||
|
||||
case '<':
|
||||
peek = is_prio(s, *len);
|
||||
if (!peek) {
|
||||
break;
|
||||
}
|
||||
if (s != (tok + 1)) { // not first?
|
||||
case '\r':
|
||||
case '\n':
|
||||
s[-1] = '\0';
|
||||
*s &= ~SIGNATURE_MASK;
|
||||
*s |= LESS_THAN_SIG; // signature for '<'
|
||||
*last = s;
|
||||
return tok;
|
||||
}
|
||||
adjust = peek - s;
|
||||
if (adjust > *len) {
|
||||
adjust = *len;
|
||||
}
|
||||
*sublen += adjust;
|
||||
*len -= adjust;
|
||||
s = peek;
|
||||
if ((*s == '[') && ((peek = is_timestamp(s + 1, *len - 1)))) {
|
||||
|
||||
case '<':
|
||||
peek = is_prio(s, *len);
|
||||
if (!peek) {
|
||||
break;
|
||||
}
|
||||
if (s != (tok + 1)) { // not first?
|
||||
s[-1] = '\0';
|
||||
*s &= ~SIGNATURE_MASK;
|
||||
*s |= LESS_THAN_SIG; // signature for '<'
|
||||
*last = s;
|
||||
return tok;
|
||||
}
|
||||
adjust = peek - s;
|
||||
if (adjust > *len) {
|
||||
adjust = *len;
|
||||
|
@ -177,33 +167,41 @@ char *log_strntok_r(char *s, size_t *len, char **last, size_t *sublen) {
|
|||
*sublen += adjust;
|
||||
*len -= adjust;
|
||||
s = peek;
|
||||
}
|
||||
break;
|
||||
|
||||
case '[':
|
||||
peek = is_timestamp(s, *len);
|
||||
if (!peek) {
|
||||
break;
|
||||
}
|
||||
if (s != (tok + 1)) { // not first?
|
||||
s[-1] = '\0';
|
||||
if (*s == ' ') {
|
||||
*s = OPEN_BRACKET_SPACE;
|
||||
} else {
|
||||
*s &= ~SIGNATURE_MASK;
|
||||
*s |= OPEN_BRACKET_SIG; // signature for '['
|
||||
if ((*s == '[') && ((peek = is_timestamp(s + 1, *len - 1)))) {
|
||||
adjust = peek - s;
|
||||
if (adjust > *len) {
|
||||
adjust = *len;
|
||||
}
|
||||
*sublen += adjust;
|
||||
*len -= adjust;
|
||||
s = peek;
|
||||
}
|
||||
*last = s;
|
||||
return tok;
|
||||
}
|
||||
adjust = peek - s;
|
||||
if (adjust > *len) {
|
||||
adjust = *len;
|
||||
}
|
||||
*sublen += adjust;
|
||||
*len -= adjust;
|
||||
s = peek;
|
||||
break;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
peek = is_timestamp(s, *len);
|
||||
if (!peek) {
|
||||
break;
|
||||
}
|
||||
if (s != (tok + 1)) { // not first?
|
||||
s[-1] = '\0';
|
||||
if (*s == ' ') {
|
||||
*s = OPEN_BRACKET_SPACE;
|
||||
} else {
|
||||
*s &= ~SIGNATURE_MASK;
|
||||
*s |= OPEN_BRACKET_SIG; // signature for '['
|
||||
}
|
||||
*last = s;
|
||||
return tok;
|
||||
}
|
||||
adjust = peek - s;
|
||||
if (adjust > *len) {
|
||||
adjust = *len;
|
||||
}
|
||||
*sublen += adjust;
|
||||
*len -= adjust;
|
||||
s = peek;
|
||||
break;
|
||||
}
|
||||
++*sublen;
|
||||
}
|
||||
|
@ -215,22 +213,23 @@ log_time LogKlog::correction =
|
|||
? log_time::EPOCH
|
||||
: (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
|
||||
|
||||
LogKlog::LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd) :
|
||||
SocketListener(fdRead, false),
|
||||
logbuf(buf),
|
||||
reader(reader),
|
||||
signature(CLOCK_MONOTONIC),
|
||||
initialized(false),
|
||||
enableLogging(true),
|
||||
auditd(auditd) {
|
||||
LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
|
||||
bool auditd)
|
||||
: SocketListener(fdRead, false),
|
||||
logbuf(buf),
|
||||
reader(reader),
|
||||
signature(CLOCK_MONOTONIC),
|
||||
initialized(false),
|
||||
enableLogging(true),
|
||||
auditd(auditd) {
|
||||
static const char klogd_message[] = "%slogd.klogd: %" PRIu64 "\n";
|
||||
char buffer[sizeof(priority_message) + sizeof(klogd_message) + 20 - 4];
|
||||
snprintf(buffer, sizeof(buffer), klogd_message, priority_message,
|
||||
signature.nsec());
|
||||
signature.nsec());
|
||||
write(fdWrite, buffer, strlen(buffer));
|
||||
}
|
||||
|
||||
bool LogKlog::onDataAvailable(SocketClient *cli) {
|
||||
bool LogKlog::onDataAvailable(SocketClient* cli) {
|
||||
if (!initialized) {
|
||||
prctl(PR_SET_NAME, "logd.klogd");
|
||||
initialized = true;
|
||||
|
@ -240,10 +239,11 @@ bool LogKlog::onDataAvailable(SocketClient *cli) {
|
|||
char buffer[LOGGER_ENTRY_MAX_PAYLOAD];
|
||||
size_t len = 0;
|
||||
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
ssize_t retval = 0;
|
||||
if ((sizeof(buffer) - 1 - len) > 0) {
|
||||
retval = read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
|
||||
retval =
|
||||
read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
|
||||
}
|
||||
if ((retval == 0) && (len == 0)) {
|
||||
break;
|
||||
|
@ -253,12 +253,11 @@ bool LogKlog::onDataAvailable(SocketClient *cli) {
|
|||
}
|
||||
len += retval;
|
||||
bool full = len == (sizeof(buffer) - 1);
|
||||
char *ep = buffer + len;
|
||||
char* ep = buffer + len;
|
||||
*ep = '\0';
|
||||
size_t sublen;
|
||||
for(char *ptr = NULL, *tok = buffer;
|
||||
((tok = log_strntok_r(tok, &len, &ptr, &sublen)));
|
||||
tok = NULL) {
|
||||
for (char *ptr = NULL, *tok = buffer;
|
||||
((tok = log_strntok_r(tok, &len, &ptr, &sublen))); tok = NULL) {
|
||||
if (((tok + sublen) >= ep) && (retval != 0) && full) {
|
||||
memmove(buffer, tok, sublen);
|
||||
len = sublen;
|
||||
|
@ -273,12 +272,10 @@ bool LogKlog::onDataAvailable(SocketClient *cli) {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LogKlog::calculateCorrection(const log_time &monotonic,
|
||||
const char *real_string,
|
||||
size_t len) {
|
||||
void LogKlog::calculateCorrection(const log_time& monotonic,
|
||||
const char* real_string, size_t len) {
|
||||
log_time real;
|
||||
const char *ep = real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC");
|
||||
const char* ep = real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC");
|
||||
if (!ep || (ep > &real_string[len]) || (real > log_time(CLOCK_REALTIME))) {
|
||||
return;
|
||||
}
|
||||
|
@ -323,10 +320,9 @@ const char* android::strnstr(const char* s, size_t len, const char* needle) {
|
|||
return s;
|
||||
}
|
||||
|
||||
void LogKlog::sniffTime(log_time &now,
|
||||
const char **buf, size_t len,
|
||||
void LogKlog::sniffTime(log_time& now, const char** buf, size_t len,
|
||||
bool reverse) {
|
||||
const char *cp = now.strptime(*buf, "[ %s.%q]");
|
||||
const char* cp = now.strptime(*buf, "[ %s.%q]");
|
||||
if (cp && (cp >= &(*buf)[len])) {
|
||||
cp = NULL;
|
||||
}
|
||||
|
@ -346,28 +342,28 @@ void LogKlog::sniffTime(log_time &now,
|
|||
}
|
||||
|
||||
const char* b;
|
||||
if (((b = android::strnstr(cp, len, suspendStr)))
|
||||
&& ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
|
||||
if (((b = android::strnstr(cp, len, suspendStr))) &&
|
||||
((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
|
||||
len -= b - cp;
|
||||
calculateCorrection(now, b, len);
|
||||
} else if (((b = android::strnstr(cp, len, resumeStr)))
|
||||
&& ((size_t)((b += sizeof(resumeStr) - 1) - cp) < len)) {
|
||||
} else if (((b = android::strnstr(cp, len, resumeStr))) &&
|
||||
((size_t)((b += sizeof(resumeStr) - 1) - cp) < len)) {
|
||||
len -= b - cp;
|
||||
calculateCorrection(now, b, len);
|
||||
} else if (((b = android::strnstr(cp, len, healthd)))
|
||||
&& ((size_t)((b += sizeof(healthd) - 1) - cp) < len)
|
||||
&& ((b = android::strnstr(b, len -= b - cp, battery)))
|
||||
&& ((size_t)((b += sizeof(battery) - 1) - cp) < len)) {
|
||||
} else if (((b = android::strnstr(cp, len, healthd))) &&
|
||||
((size_t)((b += sizeof(healthd) - 1) - cp) < len) &&
|
||||
((b = android::strnstr(b, len -= b - cp, battery))) &&
|
||||
((size_t)((b += sizeof(battery) - 1) - cp) < len)) {
|
||||
// NB: healthd is roughly 150us late, so we use it instead to
|
||||
// trigger a check for ntp-induced or hardware clock drift.
|
||||
log_time real(CLOCK_REALTIME);
|
||||
log_time mono(CLOCK_MONOTONIC);
|
||||
correction = (real < mono) ? log_time::EPOCH : (real - mono);
|
||||
} else if (((b = android::strnstr(cp, len, suspendedStr)))
|
||||
&& ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
|
||||
} else if (((b = android::strnstr(cp, len, suspendedStr))) &&
|
||||
((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
|
||||
len -= b - cp;
|
||||
log_time real;
|
||||
char *endp;
|
||||
char* endp;
|
||||
real.tv_sec = strtol(b, &endp, 10);
|
||||
if ((*endp == '.') && ((size_t)(endp - b) < len)) {
|
||||
unsigned long multiplier = NS_PER_SEC;
|
||||
|
@ -398,14 +394,11 @@ void LogKlog::sniffTime(log_time &now,
|
|||
}
|
||||
}
|
||||
|
||||
pid_t LogKlog::sniffPid(const char **buf, size_t len) {
|
||||
const char *cp = *buf;
|
||||
pid_t LogKlog::sniffPid(const char** buf, size_t len) {
|
||||
const char* cp = *buf;
|
||||
// HTC kernels with modified printk "c0 1648 "
|
||||
if ((len > 9) &&
|
||||
(cp[0] == 'c') &&
|
||||
isdigit(cp[1]) &&
|
||||
(isdigit(cp[2]) || (cp[2] == ' ')) &&
|
||||
(cp[3] == ' ')) {
|
||||
if ((len > 9) && (cp[0] == 'c') && isdigit(cp[1]) &&
|
||||
(isdigit(cp[2]) || (cp[2] == ' ')) && (cp[3] == ' ')) {
|
||||
bool gotDigit = false;
|
||||
int i;
|
||||
for (i = 4; i < 9; ++i) {
|
||||
|
@ -419,7 +412,7 @@ pid_t LogKlog::sniffPid(const char **buf, size_t len) {
|
|||
int pid = 0;
|
||||
char dummy;
|
||||
if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) {
|
||||
*buf = cp + 10; // skip-it-all
|
||||
*buf = cp + 10; // skip-it-all
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
|
@ -432,7 +425,7 @@ pid_t LogKlog::sniffPid(const char **buf, size_t len) {
|
|||
if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &dummy) == 2) {
|
||||
return pid;
|
||||
}
|
||||
break; // Only the first one
|
||||
break; // Only the first one
|
||||
}
|
||||
++cp;
|
||||
--len;
|
||||
|
@ -441,12 +434,12 @@ pid_t LogKlog::sniffPid(const char **buf, size_t len) {
|
|||
}
|
||||
|
||||
// kernel log prefix, convert to a kernel log priority number
|
||||
static int parseKernelPrio(const char **buf, size_t len) {
|
||||
static int parseKernelPrio(const char** buf, size_t len) {
|
||||
int pri = LOG_USER | LOG_INFO;
|
||||
const char *cp = *buf;
|
||||
const char* cp = *buf;
|
||||
if (len && (*cp == '<')) {
|
||||
pri = 0;
|
||||
while(--len && isdigit(*++cp)) {
|
||||
while (--len && isdigit(*++cp)) {
|
||||
pri = (pri * 10) + *cp - '0';
|
||||
}
|
||||
if (len && (*cp == '>')) {
|
||||
|
@ -502,42 +495,42 @@ void LogKlog::synchronize(const char* buf, size_t len) {
|
|||
|
||||
// Convert kernel log priority number into an Android Logger priority number
|
||||
static int convertKernelPrioToAndroidPrio(int pri) {
|
||||
switch(pri & LOG_PRIMASK) {
|
||||
case LOG_EMERG:
|
||||
switch (pri & LOG_PRIMASK) {
|
||||
case LOG_EMERG:
|
||||
// FALLTHRU
|
||||
case LOG_ALERT:
|
||||
case LOG_ALERT:
|
||||
// FALLTHRU
|
||||
case LOG_CRIT:
|
||||
return ANDROID_LOG_FATAL;
|
||||
case LOG_CRIT:
|
||||
return ANDROID_LOG_FATAL;
|
||||
|
||||
case LOG_ERR:
|
||||
return ANDROID_LOG_ERROR;
|
||||
case LOG_ERR:
|
||||
return ANDROID_LOG_ERROR;
|
||||
|
||||
case LOG_WARNING:
|
||||
return ANDROID_LOG_WARN;
|
||||
case LOG_WARNING:
|
||||
return ANDROID_LOG_WARN;
|
||||
|
||||
default:
|
||||
default:
|
||||
// FALLTHRU
|
||||
case LOG_NOTICE:
|
||||
case LOG_NOTICE:
|
||||
// FALLTHRU
|
||||
case LOG_INFO:
|
||||
break;
|
||||
case LOG_INFO:
|
||||
break;
|
||||
|
||||
case LOG_DEBUG:
|
||||
return ANDROID_LOG_DEBUG;
|
||||
case LOG_DEBUG:
|
||||
return ANDROID_LOG_DEBUG;
|
||||
}
|
||||
|
||||
return ANDROID_LOG_INFO;
|
||||
}
|
||||
|
||||
static const char *strnrchr(const char *s, size_t len, char c) {
|
||||
const char *save = NULL;
|
||||
for (;len; ++s, len--) {
|
||||
if (*s == c) {
|
||||
save = s;
|
||||
static const char* strnrchr(const char* s, size_t len, char c) {
|
||||
const char* save = NULL;
|
||||
for (; len; ++s, len--) {
|
||||
if (*s == c) {
|
||||
save = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
return save;
|
||||
return save;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -621,38 +614,41 @@ int LogKlog::log(const char* buf, size_t len) {
|
|||
while ((p < &buf[len]) && (isspace(*p) || !*p)) {
|
||||
++p;
|
||||
}
|
||||
if (p >= &buf[len]) { // timestamp, no content
|
||||
if (p >= &buf[len]) { // timestamp, no content
|
||||
return 0;
|
||||
}
|
||||
start = p;
|
||||
const char *tag = "";
|
||||
const char *etag = tag;
|
||||
const char* tag = "";
|
||||
const char* etag = tag;
|
||||
size_t taglen = len - (p - buf);
|
||||
const char *bt = p;
|
||||
const char* bt = p;
|
||||
|
||||
static const char infoBrace[] = "[INFO]";
|
||||
static const size_t infoBraceLen = strlen(infoBrace);
|
||||
if ((taglen >= infoBraceLen) && !fastcmp<strncmp>(p, infoBrace, infoBraceLen)) {
|
||||
if ((taglen >= infoBraceLen) &&
|
||||
!fastcmp<strncmp>(p, infoBrace, infoBraceLen)) {
|
||||
// <PRI>[<TIME>] "[INFO]"<tag> ":" message
|
||||
bt = p + infoBraceLen;
|
||||
taglen -= infoBraceLen;
|
||||
}
|
||||
|
||||
const char *et;
|
||||
for (et = bt; taglen && *et && (*et != ':') && !isspace(*et); ++et, --taglen) {
|
||||
// skip ':' within [ ... ]
|
||||
if (*et == '[') {
|
||||
while (taglen && *et && *et != ']') {
|
||||
++et;
|
||||
--taglen;
|
||||
}
|
||||
if (!taglen) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const char* et;
|
||||
for (et = bt; taglen && *et && (*et != ':') && !isspace(*et);
|
||||
++et, --taglen) {
|
||||
// skip ':' within [ ... ]
|
||||
if (*et == '[') {
|
||||
while (taglen && *et && *et != ']') {
|
||||
++et;
|
||||
--taglen;
|
||||
}
|
||||
if (!taglen) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const char* cp;
|
||||
for (cp = et; taglen && isspace(*cp); ++cp, --taglen) {
|
||||
}
|
||||
const char *cp;
|
||||
for (cp = et; taglen && isspace(*cp); ++cp, --taglen);
|
||||
|
||||
// Validate tag
|
||||
size_t size = et - bt;
|
||||
|
@ -667,18 +663,20 @@ int LogKlog::log(const char* buf, size_t len) {
|
|||
p = cp + 1;
|
||||
} else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) {
|
||||
// clean up any tag stutter
|
||||
if (!fastcmp<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
|
||||
if (!fastcmp<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
|
||||
// <PRI>[<TIME>] <tag> <tag> : message
|
||||
// <PRI>[<TIME>] <tag> <tag>: message
|
||||
// <PRI>[<TIME>] <tag> '<tag>.<num>' : message
|
||||
// <PRI>[<TIME>] <tag> '<tag><num>' : message
|
||||
// <PRI>[<TIME>] <tag> '<tag><stuff>' : message
|
||||
const char *b = cp;
|
||||
const char* b = cp;
|
||||
cp += size;
|
||||
taglen -= size;
|
||||
while (--taglen && !isspace(*++cp) && (*cp != ':'));
|
||||
const char *e;
|
||||
for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
|
||||
while (--taglen && !isspace(*++cp) && (*cp != ':')) {
|
||||
}
|
||||
const char* e;
|
||||
for (e = cp; taglen && isspace(*cp); ++cp, --taglen) {
|
||||
}
|
||||
if (taglen && (*cp == ':')) {
|
||||
tag = b;
|
||||
etag = e;
|
||||
|
@ -689,15 +687,17 @@ int LogKlog::log(const char* buf, size_t len) {
|
|||
static const char host[] = "_host";
|
||||
static const size_t hostlen = strlen(host);
|
||||
if ((size > hostlen) &&
|
||||
!fastcmp<strncmp>(bt + size - hostlen, host, hostlen) &&
|
||||
!fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
|
||||
const char *b = cp;
|
||||
!fastcmp<strncmp>(bt + size - hostlen, host, hostlen) &&
|
||||
!fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
|
||||
const char* b = cp;
|
||||
cp += size - hostlen;
|
||||
taglen -= size - hostlen;
|
||||
if (*cp == '.') {
|
||||
while (--taglen && !isspace(*++cp) && (*cp != ':'));
|
||||
const char *e;
|
||||
for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
|
||||
while (--taglen && !isspace(*++cp) && (*cp != ':')) {
|
||||
}
|
||||
const char* e;
|
||||
for (e = cp; taglen && isspace(*cp); ++cp, --taglen) {
|
||||
}
|
||||
if (taglen && (*cp == ':')) {
|
||||
tag = b;
|
||||
etag = e;
|
||||
|
@ -709,10 +709,13 @@ int LogKlog::log(const char* buf, size_t len) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// <PRI>[<TIME>] <tag> <stuff>' : message
|
||||
twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':'));
|
||||
const char *e;
|
||||
for (e = cp; taglen && isspace(*cp); ++cp, --taglen);
|
||||
// <PRI>[<TIME>] <tag> <stuff>' : message
|
||||
twoWord:
|
||||
while (--taglen && !isspace(*++cp) && (*cp != ':')) {
|
||||
}
|
||||
const char* e;
|
||||
for (e = cp; taglen && isspace(*cp); ++cp, --taglen) {
|
||||
}
|
||||
// Two words
|
||||
if (taglen && (*cp == ':')) {
|
||||
tag = bt;
|
||||
|
@ -720,7 +723,7 @@ twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':'));
|
|||
p = cp + 1;
|
||||
}
|
||||
}
|
||||
} // else no tag
|
||||
} // else no tag
|
||||
|
||||
static const char cpu[] = "CPU";
|
||||
static const size_t cpuLen = strlen(cpu);
|
||||
|
@ -732,16 +735,17 @@ twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':'));
|
|||
static const size_t infoLen = strlen(info);
|
||||
|
||||
size = etag - tag;
|
||||
if ((size <= 1)
|
||||
if ((size <= 1) ||
|
||||
// register names like x9
|
||||
|| ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1])))
|
||||
((size == 2) && (isdigit(tag[0]) || isdigit(tag[1]))) ||
|
||||
// register names like x18 but not driver names like en0
|
||||
|| ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2])))
|
||||
((size == 3) && (isdigit(tag[1]) && isdigit(tag[2]))) ||
|
||||
// blacklist
|
||||
|| ((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen))
|
||||
|| ((size == warningLen) && !fastcmp<strncasecmp>(tag, warning, warningLen))
|
||||
|| ((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen))
|
||||
|| ((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
|
||||
((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen)) ||
|
||||
((size == warningLen) &&
|
||||
!fastcmp<strncasecmp>(tag, warning, warningLen)) ||
|
||||
((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen)) ||
|
||||
((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
|
||||
p = start;
|
||||
etag = tag = "";
|
||||
}
|
||||
|
@ -750,7 +754,7 @@ twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':'));
|
|||
// eg: [143:healthd]healthd -> [143:healthd]
|
||||
taglen = etag - tag;
|
||||
// Mediatek-special printk induced stutter
|
||||
const char *mp = strnrchr(tag, ']', taglen);
|
||||
const char* mp = strnrchr(tag, ']', taglen);
|
||||
if (mp && (++mp < etag)) {
|
||||
size_t s = etag - mp;
|
||||
if (((s + s) < taglen) && !fastcmp<memcmp>(mp, mp - 1 - s, s)) {
|
||||
|
@ -767,7 +771,7 @@ twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':'));
|
|||
}
|
||||
// truncate trailing space or nuls
|
||||
size_t b = len - (p - buf);
|
||||
while (b && (isspace(p[b-1]) || !p[b-1])) {
|
||||
while (b && (isspace(p[b - 1]) || !p[b - 1])) {
|
||||
--b;
|
||||
}
|
||||
// trick ... allow tag with empty content to be logged. log() drops empty
|
||||
|
@ -796,7 +800,7 @@ twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':'));
|
|||
// truncating length argument to logbuf->log() below. Gain is protection
|
||||
// of stack sanity and speedup, loss is truncated long-line content.
|
||||
char newstr[n];
|
||||
char *np = newstr;
|
||||
char* np = newstr;
|
||||
|
||||
// Convert priority into single-byte Android logger priority
|
||||
*np = convertKernelPrioToAndroidPrio(pri);
|
||||
|
@ -828,10 +832,10 @@ twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':'));
|
|||
unsigned abs0 = (diff0 < 0) ? -diff0 : diff0;
|
||||
int diff1 = (vote_time[1] - vote_time[2]) / near_seconds;
|
||||
unsigned abs1 = (diff1 < 0) ? -diff1 : diff1;
|
||||
if ((abs1 <= 1) && // last two were in agreement on timezone
|
||||
((abs0 + 1) % (timezones_seconds / near_seconds)) <= 2) {
|
||||
if ((abs1 <= 1) && // last two were in agreement on timezone
|
||||
((abs0 + 1) % (timezones_seconds / near_seconds)) <= 2) {
|
||||
abs0 = (abs0 + 1) / (timezones_seconds / near_seconds) *
|
||||
timezones_seconds;
|
||||
timezones_seconds;
|
||||
now.tv_sec -= (diff0 < 0) ? -abs0 : abs0;
|
||||
}
|
||||
}
|
||||
|
@ -839,7 +843,7 @@ twoWord: while (--taglen && !isspace(*++cp) && (*cp != ':'));
|
|||
|
||||
// Log message
|
||||
int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
|
||||
(unsigned short) n);
|
||||
(unsigned short)n);
|
||||
|
||||
// notify readers
|
||||
if (!rc) {
|
||||
|
|
|
@ -20,14 +20,14 @@
|
|||
#include <private/android_logger.h>
|
||||
#include <sysutils/SocketListener.h>
|
||||
|
||||
char *log_strntok_r(char *s, size_t *len, char **saveptr, size_t *sublen);
|
||||
char* log_strntok_r(char* s, size_t* len, char** saveptr, size_t* sublen);
|
||||
|
||||
class LogBuffer;
|
||||
class LogReader;
|
||||
|
||||
class LogKlog : public SocketListener {
|
||||
LogBuffer *logbuf;
|
||||
LogReader *reader;
|
||||
LogBuffer* logbuf;
|
||||
LogReader* reader;
|
||||
const log_time signature;
|
||||
// Set once thread is started, separates KLOG_ACTION_READ_ALL
|
||||
// and KLOG_ACTION_READ phases.
|
||||
|
@ -40,22 +40,28 @@ class LogKlog : public SocketListener {
|
|||
|
||||
static log_time correction;
|
||||
|
||||
public:
|
||||
LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd);
|
||||
int log(const char *buf, size_t len);
|
||||
void synchronize(const char *buf, size_t len);
|
||||
public:
|
||||
LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
|
||||
bool auditd);
|
||||
int log(const char* buf, size_t len);
|
||||
void synchronize(const char* buf, size_t len);
|
||||
|
||||
bool isMonotonic() { return logbuf->isMonotonic(); }
|
||||
static void convertMonotonicToReal(log_time &real) { real += correction; }
|
||||
static void convertRealToMonotonic(log_time &real) { real -= correction; }
|
||||
|
||||
protected:
|
||||
void sniffTime(log_time &now, const char **buf, size_t len, bool reverse);
|
||||
pid_t sniffPid(const char **buf, size_t len);
|
||||
void calculateCorrection(const log_time &monotonic,
|
||||
const char *real_string, size_t len);
|
||||
virtual bool onDataAvailable(SocketClient *cli);
|
||||
bool isMonotonic() {
|
||||
return logbuf->isMonotonic();
|
||||
}
|
||||
static void convertMonotonicToReal(log_time& real) {
|
||||
real += correction;
|
||||
}
|
||||
static void convertRealToMonotonic(log_time& real) {
|
||||
real -= correction;
|
||||
}
|
||||
|
||||
protected:
|
||||
void sniffTime(log_time& now, const char** buf, size_t len, bool reverse);
|
||||
pid_t sniffPid(const char** buf, size_t len);
|
||||
void calculateCorrection(const log_time& monotonic, const char* real_string,
|
||||
size_t len);
|
||||
virtual bool onDataAvailable(SocketClient* cli);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,32 +30,24 @@
|
|||
#include "LogListener.h"
|
||||
#include "LogUtils.h"
|
||||
|
||||
LogListener::LogListener(LogBuffer *buf, LogReader *reader) :
|
||||
SocketListener(getLogSocket(), false),
|
||||
logbuf(buf),
|
||||
reader(reader) {
|
||||
LogListener::LogListener(LogBuffer* buf, LogReader* reader)
|
||||
: SocketListener(getLogSocket(), false), logbuf(buf), reader(reader) {
|
||||
}
|
||||
|
||||
bool LogListener::onDataAvailable(SocketClient *cli) {
|
||||
bool LogListener::onDataAvailable(SocketClient* cli) {
|
||||
static bool name_set;
|
||||
if (!name_set) {
|
||||
prctl(PR_SET_NAME, "logd.writer");
|
||||
name_set = true;
|
||||
}
|
||||
|
||||
char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time)
|
||||
+ LOGGER_ENTRY_MAX_PAYLOAD];
|
||||
char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time) +
|
||||
LOGGER_ENTRY_MAX_PAYLOAD];
|
||||
struct iovec iov = { buffer, sizeof(buffer) };
|
||||
|
||||
alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
|
||||
struct msghdr hdr = {
|
||||
NULL,
|
||||
0,
|
||||
&iov,
|
||||
1,
|
||||
control,
|
||||
sizeof(control),
|
||||
0,
|
||||
NULL, 0, &iov, 1, control, sizeof(control), 0,
|
||||
};
|
||||
|
||||
int socket = cli->getSocket();
|
||||
|
@ -68,13 +60,13 @@ bool LogListener::onDataAvailable(SocketClient *cli) {
|
|||
return false;
|
||||
}
|
||||
|
||||
struct ucred *cred = NULL;
|
||||
struct ucred* cred = NULL;
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
while (cmsg != NULL) {
|
||||
if (cmsg->cmsg_level == SOL_SOCKET
|
||||
&& cmsg->cmsg_type == SCM_CREDENTIALS) {
|
||||
cred = (struct ucred *)CMSG_DATA(cmsg);
|
||||
if (cmsg->cmsg_level == SOL_SOCKET &&
|
||||
cmsg->cmsg_type == SCM_CREDENTIALS) {
|
||||
cred = (struct ucred*)CMSG_DATA(cmsg);
|
||||
break;
|
||||
}
|
||||
cmsg = CMSG_NXTHDR(&hdr, cmsg);
|
||||
|
@ -91,26 +83,29 @@ bool LogListener::onDataAvailable(SocketClient *cli) {
|
|||
return false;
|
||||
}
|
||||
|
||||
android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer);
|
||||
if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX || header->id == LOG_ID_KERNEL) {
|
||||
android_log_header_t* header =
|
||||
reinterpret_cast<android_log_header_t*>(buffer);
|
||||
if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX ||
|
||||
header->id == LOG_ID_KERNEL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((header->id == LOG_ID_SECURITY) &&
|
||||
(!__android_log_security() ||
|
||||
!clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
|
||||
(!__android_log_security() ||
|
||||
!clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char *msg = ((char *)buffer) + sizeof(android_log_header_t);
|
||||
char* msg = ((char*)buffer) + sizeof(android_log_header_t);
|
||||
n -= sizeof(android_log_header_t);
|
||||
|
||||
// NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
|
||||
// truncated message to the logs.
|
||||
|
||||
if (logbuf->log((log_id_t)header->id, header->realtime,
|
||||
cred->uid, cred->pid, header->tid, msg,
|
||||
((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX) >= 0) {
|
||||
if (logbuf->log((log_id_t)header->id, header->realtime, cred->uid,
|
||||
cred->pid, header->tid, msg,
|
||||
((size_t)n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX) >=
|
||||
0) {
|
||||
reader->notifyNewLog();
|
||||
}
|
||||
|
||||
|
@ -122,9 +117,8 @@ int LogListener::getLogSocket() {
|
|||
int sock = android_get_control_socket(socketName);
|
||||
|
||||
if (sock < 0) {
|
||||
sock = socket_local_server(socketName,
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_DGRAM);
|
||||
sock = socket_local_server(
|
||||
socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
|
||||
}
|
||||
|
||||
int on = 1;
|
||||
|
|
|
@ -21,16 +21,16 @@
|
|||
#include "LogReader.h"
|
||||
|
||||
class LogListener : public SocketListener {
|
||||
LogBuffer *logbuf;
|
||||
LogReader *reader;
|
||||
LogBuffer* logbuf;
|
||||
LogReader* reader;
|
||||
|
||||
public:
|
||||
LogListener(LogBuffer *buf, LogReader *reader);
|
||||
public:
|
||||
LogListener(LogBuffer* buf, LogReader* reader);
|
||||
|
||||
protected:
|
||||
virtual bool onDataAvailable(SocketClient *cli);
|
||||
protected:
|
||||
virtual bool onDataAvailable(SocketClient* cli);
|
||||
|
||||
private:
|
||||
private:
|
||||
static int getLogSocket();
|
||||
};
|
||||
|
||||
|
|
|
@ -29,9 +29,8 @@
|
|||
#include "LogReader.h"
|
||||
#include "LogUtils.h"
|
||||
|
||||
LogReader::LogReader(LogBuffer *logbuf) :
|
||||
SocketListener(getLogSocket(), true),
|
||||
mLogbuf(*logbuf) {
|
||||
LogReader::LogReader(LogBuffer* logbuf)
|
||||
: SocketListener(getLogSocket(), true), mLogbuf(*logbuf) {
|
||||
}
|
||||
|
||||
// When we are notified a new log entry is available, inform
|
||||
|
@ -41,7 +40,7 @@ void LogReader::notifyNewLog() {
|
|||
runOnEachSocket(&command);
|
||||
}
|
||||
|
||||
bool LogReader::onDataAvailable(SocketClient *cli) {
|
||||
bool LogReader::onDataAvailable(SocketClient* cli) {
|
||||
static bool name_set;
|
||||
if (!name_set) {
|
||||
prctl(PR_SET_NAME, "logd.reader");
|
||||
|
@ -59,7 +58,7 @@ bool LogReader::onDataAvailable(SocketClient *cli) {
|
|||
|
||||
unsigned long tail = 0;
|
||||
static const char _tail[] = " tail=";
|
||||
char *cp = strstr(buffer, _tail);
|
||||
char* cp = strstr(buffer, _tail);
|
||||
if (cp) {
|
||||
tail = atol(cp + sizeof(_tail) - 1);
|
||||
}
|
||||
|
@ -124,32 +123,33 @@ bool LogReader::onDataAvailable(SocketClient *cli) {
|
|||
const pid_t mPid;
|
||||
const unsigned mLogMask;
|
||||
bool startTimeSet;
|
||||
log_time &start;
|
||||
uint64_t &sequence;
|
||||
log_time& start;
|
||||
uint64_t& sequence;
|
||||
uint64_t last;
|
||||
bool isMonotonic;
|
||||
|
||||
public:
|
||||
LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence, bool isMonotonic) :
|
||||
mPid(pid),
|
||||
mLogMask(logMask),
|
||||
startTimeSet(false),
|
||||
start(start),
|
||||
sequence(sequence),
|
||||
last(sequence),
|
||||
isMonotonic(isMonotonic) {
|
||||
public:
|
||||
LogFindStart(unsigned logMask, pid_t pid, log_time& start,
|
||||
uint64_t& sequence, bool isMonotonic)
|
||||
: mPid(pid),
|
||||
mLogMask(logMask),
|
||||
startTimeSet(false),
|
||||
start(start),
|
||||
sequence(sequence),
|
||||
last(sequence),
|
||||
isMonotonic(isMonotonic) {
|
||||
}
|
||||
|
||||
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()))) {
|
||||
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()))) {
|
||||
if (me->start == element->getRealTime()) {
|
||||
me->sequence = element->getSequence();
|
||||
me->startTimeSet = true;
|
||||
return -1;
|
||||
} else if (!me->isMonotonic ||
|
||||
android::isMonotonic(element->getRealTime())) {
|
||||
android::isMonotonic(element->getRealTime())) {
|
||||
if (me->start < element->getRealTime()) {
|
||||
me->sequence = me->last;
|
||||
me->startTimeSet = true;
|
||||
|
@ -163,7 +163,9 @@ bool LogReader::onDataAvailable(SocketClient *cli) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool found() { return startTimeSet; }
|
||||
bool found() {
|
||||
return startTimeSet;
|
||||
}
|
||||
} logFindStart(logMask, pid, start, sequence,
|
||||
logbuf().isMonotonic() && android::isMonotonic(start));
|
||||
|
||||
|
@ -184,18 +186,19 @@ bool LogReader::onDataAvailable(SocketClient *cli) {
|
|||
|
||||
// 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));
|
||||
setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
|
||||
sizeof(t));
|
||||
|
||||
command.runSocketCommand(cli);
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogReader::doSocketDelete(SocketClient *cli) {
|
||||
LastLogTimes × = mLogbuf.mTimes;
|
||||
void LogReader::doSocketDelete(SocketClient* cli) {
|
||||
LastLogTimes& times = mLogbuf.mTimes;
|
||||
LogTimeEntry::lock();
|
||||
LastLogTimes::iterator it = times.begin();
|
||||
while(it != times.end()) {
|
||||
LogTimeEntry *entry = (*it);
|
||||
while (it != times.end()) {
|
||||
LogTimeEntry* entry = (*it);
|
||||
if (entry->mClient == cli) {
|
||||
times.erase(it);
|
||||
entry->release_Locked();
|
||||
|
@ -211,9 +214,8 @@ int LogReader::getLogSocket() {
|
|||
int sock = android_get_control_socket(socketName);
|
||||
|
||||
if (sock < 0) {
|
||||
sock = socket_local_server(socketName,
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_SEQPACKET);
|
||||
sock = socket_local_server(
|
||||
socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
|
||||
}
|
||||
|
||||
return sock;
|
||||
|
|
|
@ -24,22 +24,23 @@
|
|||
class LogBuffer;
|
||||
|
||||
class LogReader : public SocketListener {
|
||||
LogBuffer &mLogbuf;
|
||||
LogBuffer& mLogbuf;
|
||||
|
||||
public:
|
||||
explicit LogReader(LogBuffer *logbuf);
|
||||
public:
|
||||
explicit LogReader(LogBuffer* logbuf);
|
||||
void notifyNewLog();
|
||||
|
||||
LogBuffer &logbuf(void) const { return mLogbuf; }
|
||||
LogBuffer& logbuf(void) const {
|
||||
return mLogbuf;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool onDataAvailable(SocketClient *cli);
|
||||
protected:
|
||||
virtual bool onDataAvailable(SocketClient* cli);
|
||||
|
||||
private:
|
||||
private:
|
||||
static int getLogSocket();
|
||||
|
||||
void doSocketDelete(SocketClient *cli);
|
||||
|
||||
void doSocketDelete(SocketClient* cli);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -41,12 +41,14 @@ LogStatistics::LogStatistics() : enable(false) {
|
|||
|
||||
namespace android {
|
||||
|
||||
size_t sizesTotal() { return LogStatistics::sizesTotal(); }
|
||||
size_t sizesTotal() {
|
||||
return LogStatistics::sizesTotal();
|
||||
}
|
||||
|
||||
// caller must own and free character string
|
||||
char *pidToName(pid_t pid) {
|
||||
char *retval = NULL;
|
||||
if (pid == 0) { // special case from auditd/klogd for kernel
|
||||
char* pidToName(pid_t pid) {
|
||||
char* retval = NULL;
|
||||
if (pid == 0) { // special case from auditd/klogd for kernel
|
||||
retval = strdup("logd");
|
||||
} else {
|
||||
char buffer[512];
|
||||
|
@ -55,7 +57,7 @@ char *pidToName(pid_t pid) {
|
|||
if (fd >= 0) {
|
||||
ssize_t ret = read(fd, buffer, sizeof(buffer));
|
||||
if (ret > 0) {
|
||||
buffer[sizeof(buffer)-1] = '\0';
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
// frameworks intermediate state
|
||||
if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
|
||||
retval = strdup(buffer);
|
||||
|
@ -66,10 +68,9 @@ char *pidToName(pid_t pid) {
|
|||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LogStatistics::add(LogBufferElement *element) {
|
||||
void LogStatistics::add(LogBufferElement* element) {
|
||||
log_id_t log_id = element->getLogId();
|
||||
unsigned short size = element->getMsgLen();
|
||||
mSizes[log_id] += size;
|
||||
|
@ -114,7 +115,7 @@ void LogStatistics::add(LogBufferElement *element) {
|
|||
}
|
||||
}
|
||||
|
||||
void LogStatistics::subtract(LogBufferElement *element) {
|
||||
void LogStatistics::subtract(LogBufferElement* element) {
|
||||
log_id_t log_id = element->getLogId();
|
||||
unsigned short size = element->getMsgLen();
|
||||
mSizes[log_id] -= size;
|
||||
|
@ -151,7 +152,7 @@ void LogStatistics::subtract(LogBufferElement *element) {
|
|||
|
||||
// Atomically set an entry to drop
|
||||
// entry->setDropped(1) must follow this call, caller should do this explicitly.
|
||||
void LogStatistics::drop(LogBufferElement *element) {
|
||||
void LogStatistics::drop(LogBufferElement* element) {
|
||||
log_id_t log_id = element->getLogId();
|
||||
unsigned short size = element->getMsgLen();
|
||||
mSizes[log_id] -= size;
|
||||
|
@ -180,7 +181,7 @@ void LogStatistics::drop(LogBufferElement *element) {
|
|||
}
|
||||
|
||||
// caller must own and free character string
|
||||
const char *LogStatistics::uidToName(uid_t uid) const {
|
||||
const char* LogStatistics::uidToName(uid_t uid) const {
|
||||
// Local hard coded favourites
|
||||
if (uid == AID_LOGD) {
|
||||
return strdup("auditd");
|
||||
|
@ -189,7 +190,7 @@ const char *LogStatistics::uidToName(uid_t uid) const {
|
|||
// Android system
|
||||
if (uid < AID_APP) {
|
||||
// in bionic, thread safe as long as we copy the results
|
||||
struct passwd *pwd = getpwuid(uid);
|
||||
struct passwd* pwd = getpwuid(uid);
|
||||
if (pwd) {
|
||||
return strdup(pwd->pw_name);
|
||||
}
|
||||
|
@ -197,7 +198,7 @@ const char *LogStatistics::uidToName(uid_t uid) const {
|
|||
|
||||
// Parse /data/system/packages.list
|
||||
uid_t userId = uid % AID_USER_OFFSET;
|
||||
const char *name = android::uidToName(userId);
|
||||
const char* name = android::uidToName(userId);
|
||||
if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
|
||||
name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
|
||||
}
|
||||
|
@ -207,24 +208,25 @@ const char *LogStatistics::uidToName(uid_t uid) const {
|
|||
|
||||
// Android application
|
||||
if (uid >= AID_APP) {
|
||||
struct passwd *pwd = getpwuid(uid);
|
||||
struct passwd* pwd = getpwuid(uid);
|
||||
if (pwd) {
|
||||
return strdup(pwd->pw_name);
|
||||
}
|
||||
}
|
||||
|
||||
// report uid -> pid(s) -> pidToName if unique
|
||||
for(pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
|
||||
const PidEntry &entry = it->second;
|
||||
for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
|
||||
++it) {
|
||||
const PidEntry& entry = it->second;
|
||||
|
||||
if (entry.getUid() == uid) {
|
||||
const char *nameTmp = entry.getName();
|
||||
const char* nameTmp = entry.getName();
|
||||
|
||||
if (nameTmp) {
|
||||
if (!name) {
|
||||
name = strdup(nameTmp);
|
||||
} else if (fastcmp<strcmp>(name, nameTmp)) {
|
||||
free(const_cast<char *>(name));
|
||||
free(const_cast<char*>(name));
|
||||
name = NULL;
|
||||
break;
|
||||
}
|
||||
|
@ -236,26 +238,24 @@ const char *LogStatistics::uidToName(uid_t uid) const {
|
|||
return name;
|
||||
}
|
||||
|
||||
std::string UidEntry::formatHeader(const std::string &name, log_id_t id) const {
|
||||
std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
|
||||
bool isprune = worstUidEnabledForLogid(id);
|
||||
return formatLine(android::base::StringPrintf(
|
||||
name.c_str(), android_log_id_to_name(id)),
|
||||
return formatLine(android::base::StringPrintf(name.c_str(),
|
||||
android_log_id_to_name(id)),
|
||||
std::string("Size"),
|
||||
std::string(isprune ? "+/- Pruned" : ""))
|
||||
+ formatLine(std::string("UID PACKAGE"),
|
||||
std::string("BYTES"),
|
||||
std::string(isprune ? "+/- Pruned" : "")) +
|
||||
formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
|
||||
std::string(isprune ? "NUM" : ""));
|
||||
}
|
||||
|
||||
std::string UidEntry::format(const LogStatistics &stat, log_id_t id) const {
|
||||
std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
|
||||
uid_t uid = getUid();
|
||||
std::string name = android::base::StringPrintf("%u", uid);
|
||||
const char *nameTmp = stat.uidToName(uid);
|
||||
const char* nameTmp = stat.uidToName(uid);
|
||||
if (nameTmp) {
|
||||
name += android::base::StringPrintf(
|
||||
"%*s%s", (int)std::max(6 - name.length(), (size_t)1),
|
||||
"", nameTmp);
|
||||
free(const_cast<char *>(nameTmp));
|
||||
"%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", nameTmp);
|
||||
free(const_cast<char*>(nameTmp));
|
||||
}
|
||||
|
||||
std::string size = android::base::StringPrintf("%zu", getSizes());
|
||||
|
@ -263,15 +263,16 @@ std::string UidEntry::format(const LogStatistics &stat, log_id_t id) const {
|
|||
std::string pruned = "";
|
||||
if (worstUidEnabledForLogid(id)) {
|
||||
size_t totalDropped = 0;
|
||||
for (LogStatistics::uidTable_t::const_iterator it = stat.uidTable[id].begin();
|
||||
it != stat.uidTable[id].end(); ++it) {
|
||||
for (LogStatistics::uidTable_t::const_iterator it =
|
||||
stat.uidTable[id].begin();
|
||||
it != stat.uidTable[id].end(); ++it) {
|
||||
totalDropped += it->second.getDropped();
|
||||
}
|
||||
size_t sizes = stat.sizes(id);
|
||||
size_t totalSize = stat.sizesTotal(id);
|
||||
size_t totalElements = stat.elementsTotal(id);
|
||||
float totalVirtualSize = (float)sizes + (float)totalDropped * totalSize
|
||||
/ totalElements;
|
||||
float totalVirtualSize =
|
||||
(float)sizes + (float)totalDropped * totalSize / totalElements;
|
||||
size_t entrySize = getSizes();
|
||||
float virtualEntrySize = entrySize;
|
||||
int realPermille = virtualEntrySize * 1000.0 / sizes;
|
||||
|
@ -281,31 +282,29 @@ std::string UidEntry::format(const LogStatistics &stat, log_id_t id) const {
|
|||
virtualEntrySize += (float)dropped * totalSize / totalElements;
|
||||
}
|
||||
int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
|
||||
int permille = (realPermille - virtualPermille) * 1000L
|
||||
/ (virtualPermille ?: 1);
|
||||
int permille =
|
||||
(realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
|
||||
if ((permille < -1) || (1 < permille)) {
|
||||
std::string change;
|
||||
const char *units = "%";
|
||||
const char *prefix = (permille > 0) ? "+" : "";
|
||||
const char* units = "%";
|
||||
const char* prefix = (permille > 0) ? "+" : "";
|
||||
|
||||
if (permille > 999) {
|
||||
permille = (permille + 1000) / 100; // Now tenths fold
|
||||
permille = (permille + 1000) / 100; // Now tenths fold
|
||||
units = "X";
|
||||
prefix = "";
|
||||
}
|
||||
if ((-99 < permille) && (permille < 99)) {
|
||||
change = android::base::StringPrintf("%s%d.%u%s",
|
||||
prefix,
|
||||
permille / 10,
|
||||
change = android::base::StringPrintf(
|
||||
"%s%d.%u%s", prefix, permille / 10,
|
||||
((permille < 0) ? (-permille % 10) : (permille % 10)),
|
||||
units);
|
||||
} else {
|
||||
change = android::base::StringPrintf("%s%d%s",
|
||||
prefix,
|
||||
(permille + 5) / 10, units);
|
||||
change = android::base::StringPrintf(
|
||||
"%s%d%s", prefix, (permille + 5) / 10, units);
|
||||
}
|
||||
ssize_t spaces = EntryBaseConstants::pruned_len
|
||||
- 2 - pruned.length() - change.length();
|
||||
ssize_t spaces = EntryBaseConstants::pruned_len - 2 -
|
||||
pruned.length() - change.length();
|
||||
if ((spaces <= 0) && pruned.length()) {
|
||||
spaces = 1;
|
||||
}
|
||||
|
@ -323,8 +322,8 @@ std::string UidEntry::format(const LogStatistics &stat, log_id_t id) const {
|
|||
}
|
||||
|
||||
static const size_t maximum_sorted_entries = 32;
|
||||
std::unique_ptr<const PidEntry *[]> sorted
|
||||
= stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
|
||||
std::unique_ptr<const PidEntry* []> sorted =
|
||||
stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
|
||||
|
||||
if (!sorted.get()) {
|
||||
return output;
|
||||
|
@ -333,7 +332,7 @@ std::string UidEntry::format(const LogStatistics &stat, log_id_t id) const {
|
|||
size_t index;
|
||||
bool hasDropped = false;
|
||||
for (index = 0; index < maximum_sorted_entries; ++index) {
|
||||
const PidEntry *entry = sorted[index];
|
||||
const PidEntry* entry = sorted[index];
|
||||
if (!entry) {
|
||||
break;
|
||||
}
|
||||
|
@ -345,43 +344,39 @@ std::string UidEntry::format(const LogStatistics &stat, log_id_t id) const {
|
|||
}
|
||||
byPid += entry->format(stat, id);
|
||||
}
|
||||
if (index > 1) { // print this only if interesting
|
||||
if (index > 1) { // print this only if interesting
|
||||
std::string ditto("\" ");
|
||||
output += formatLine(std::string(" PID/UID COMMAND LINE"),
|
||||
ditto, hasDropped ? ditto : std::string(""));
|
||||
output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
|
||||
hasDropped ? ditto : std::string(""));
|
||||
output += byPid;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string PidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
|
||||
return formatLine(name,
|
||||
std::string("Size"),
|
||||
std::string("Pruned"))
|
||||
+ formatLine(std::string(" PID/UID COMMAND LINE"),
|
||||
std::string("BYTES"),
|
||||
std::string("NUM"));
|
||||
std::string PidEntry::formatHeader(const std::string& name,
|
||||
log_id_t /* id */) const {
|
||||
return formatLine(name, std::string("Size"), std::string("Pruned")) +
|
||||
formatLine(std::string(" PID/UID COMMAND LINE"),
|
||||
std::string("BYTES"), std::string("NUM"));
|
||||
}
|
||||
|
||||
std::string PidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
|
||||
std::string PidEntry::format(const LogStatistics& stat,
|
||||
log_id_t /* id */) const {
|
||||
uid_t uid = getUid();
|
||||
pid_t pid = getPid();
|
||||
std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
|
||||
const char *nameTmp = getName();
|
||||
const char* nameTmp = getName();
|
||||
if (nameTmp) {
|
||||
name += android::base::StringPrintf(
|
||||
"%*s%s", (int)std::max(12 - name.length(), (size_t)1),
|
||||
"", nameTmp);
|
||||
"%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
|
||||
} else if ((nameTmp = stat.uidToName(uid))) {
|
||||
name += android::base::StringPrintf(
|
||||
"%*s%s", (int)std::max(12 - name.length(), (size_t)1),
|
||||
"", nameTmp);
|
||||
free(const_cast<char *>(nameTmp));
|
||||
"%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
|
||||
free(const_cast<char*>(nameTmp));
|
||||
}
|
||||
|
||||
std::string size = android::base::StringPrintf("%zu",
|
||||
getSizes());
|
||||
std::string size = android::base::StringPrintf("%zu", getSizes());
|
||||
|
||||
std::string pruned = "";
|
||||
size_t dropped = getDropped();
|
||||
|
@ -392,36 +387,31 @@ std::string PidEntry::format(const LogStatistics &stat, log_id_t /* id */) const
|
|||
return formatLine(name, size, pruned);
|
||||
}
|
||||
|
||||
std::string TidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
|
||||
return formatLine(name,
|
||||
std::string("Size"),
|
||||
std::string("Pruned"))
|
||||
+ formatLine(std::string(" TID/UID COMM"),
|
||||
std::string("BYTES"),
|
||||
std::string TidEntry::formatHeader(const std::string& name,
|
||||
log_id_t /* id */) const {
|
||||
return formatLine(name, std::string("Size"), std::string("Pruned")) +
|
||||
formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
|
||||
std::string("NUM"));
|
||||
}
|
||||
|
||||
std::string TidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
|
||||
std::string TidEntry::format(const LogStatistics& stat,
|
||||
log_id_t /* id */) const {
|
||||
uid_t uid = getUid();
|
||||
std::string name = android::base::StringPrintf("%5u/%u",
|
||||
getTid(), uid);
|
||||
const char *nameTmp = getName();
|
||||
std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
|
||||
const char* nameTmp = getName();
|
||||
if (nameTmp) {
|
||||
name += android::base::StringPrintf(
|
||||
"%*s%s", (int)std::max(12 - name.length(), (size_t)1),
|
||||
"", nameTmp);
|
||||
"%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
|
||||
} else if ((nameTmp = stat.uidToName(uid))) {
|
||||
// if we do not have a PID name, lets punt to try UID name?
|
||||
name += android::base::StringPrintf(
|
||||
"%*s%s", (int)std::max(12 - name.length(), (size_t)1),
|
||||
"", nameTmp);
|
||||
free(const_cast<char *>(nameTmp));
|
||||
"%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
|
||||
free(const_cast<char*>(nameTmp));
|
||||
// We tried, better to not have a name at all, we still
|
||||
// have TID/UID by number to report in any case.
|
||||
}
|
||||
|
||||
std::string size = android::base::StringPrintf("%zu",
|
||||
getSizes());
|
||||
std::string size = android::base::StringPrintf("%zu", getSizes());
|
||||
|
||||
std::string pruned = "";
|
||||
size_t dropped = getDropped();
|
||||
|
@ -432,35 +422,30 @@ std::string TidEntry::format(const LogStatistics &stat, log_id_t /* id */) const
|
|||
return formatLine(name, size, pruned);
|
||||
}
|
||||
|
||||
std::string TagEntry::formatHeader(const std::string &name, log_id_t id) const {
|
||||
std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
|
||||
bool isprune = worstUidEnabledForLogid(id);
|
||||
return formatLine(name,
|
||||
std::string("Size"),
|
||||
std::string(isprune ? "Prune" : ""))
|
||||
+ formatLine(std::string(" TAG/UID TAGNAME"),
|
||||
std::string("BYTES"),
|
||||
std::string(isprune ? "NUM" : ""));
|
||||
return formatLine(name, std::string("Size"),
|
||||
std::string(isprune ? "Prune" : "")) +
|
||||
formatLine(std::string(" TAG/UID TAGNAME"),
|
||||
std::string("BYTES"), std::string(isprune ? "NUM" : ""));
|
||||
}
|
||||
|
||||
std::string TagEntry::format(const LogStatistics & /* stat */, log_id_t /* id */) const {
|
||||
std::string TagEntry::format(const LogStatistics& /* stat */,
|
||||
log_id_t /* id */) const {
|
||||
std::string name;
|
||||
uid_t uid = getUid();
|
||||
if (uid == (uid_t)-1) {
|
||||
name = android::base::StringPrintf("%7u",
|
||||
getKey());
|
||||
name = android::base::StringPrintf("%7u", getKey());
|
||||
} else {
|
||||
name = android::base::StringPrintf("%7u/%u",
|
||||
getKey(), uid);
|
||||
name = android::base::StringPrintf("%7u/%u", getKey(), uid);
|
||||
}
|
||||
const char *nameTmp = getName();
|
||||
const char* nameTmp = getName();
|
||||
if (nameTmp) {
|
||||
name += android::base::StringPrintf(
|
||||
"%*s%s", (int)std::max(14 - name.length(), (size_t)1),
|
||||
"", nameTmp);
|
||||
"%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
|
||||
}
|
||||
|
||||
std::string size = android::base::StringPrintf("%zu",
|
||||
getSizes());
|
||||
std::string size = android::base::StringPrintf("%zu", getSizes());
|
||||
|
||||
std::string pruned = "";
|
||||
size_t dropped = getDropped();
|
||||
|
@ -506,11 +491,13 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
|
|||
totalSize += szs;
|
||||
size_t els = elementsTotal(id);
|
||||
totalEls += els;
|
||||
output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
|
||||
output +=
|
||||
android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
|
||||
spaces += spaces_total + oldLength - output.length();
|
||||
}
|
||||
if (spaces < 0) spaces = 0;
|
||||
output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, totalEls);
|
||||
output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
|
||||
totalEls);
|
||||
|
||||
static const char NowStr[] = "\nNow";
|
||||
spaces = 10 - strlen(NowStr);
|
||||
|
@ -528,13 +515,15 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
|
|||
size_t szs = sizes(id);
|
||||
totalSize += szs;
|
||||
totalEls += els;
|
||||
output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
|
||||
output +=
|
||||
android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
|
||||
spaces -= output.length() - oldLength;
|
||||
}
|
||||
spaces += spaces_total;
|
||||
}
|
||||
if (spaces < 0) spaces = 0;
|
||||
output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, totalEls);
|
||||
output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
|
||||
totalEls);
|
||||
|
||||
static const char OverheadStr[] = "\nOverhead";
|
||||
spaces = 10 - strlen(OverheadStr);
|
||||
|
@ -551,7 +540,7 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
|
|||
// estimate the std::list overhead.
|
||||
static const size_t overhead =
|
||||
((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
|
||||
-sizeof(uint64_t)) +
|
||||
-sizeof(uint64_t)) +
|
||||
sizeof(std::list<LogBufferElement*>);
|
||||
size_t szs = sizes(id) + els * overhead;
|
||||
totalSize += szs;
|
||||
|
@ -572,16 +561,14 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
|
|||
log_id_for_each(id) {
|
||||
if (!(logMask & (1 << id))) continue;
|
||||
|
||||
name = (uid == AID_ROOT)
|
||||
? "Chattiest UIDs in %s log buffer:"
|
||||
: "Logging for your UID in %s log buffer:";
|
||||
name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
|
||||
: "Logging for your UID in %s log buffer:";
|
||||
output += uidTable[id].format(*this, uid, pid, name, id);
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
name = ((uid == AID_ROOT) && !pid)
|
||||
? "Chattiest PIDs:"
|
||||
: "Logging for this PID:";
|
||||
name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
|
||||
: "Logging for this PID:";
|
||||
output += pidTable.format(*this, uid, pid, name);
|
||||
name = "Chattiest TIDs";
|
||||
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
|
||||
|
@ -600,7 +587,8 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
|
|||
name = "Chattiest security log buffer TAGs";
|
||||
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
|
||||
name += ":";
|
||||
output += securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
|
||||
output +=
|
||||
securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
|
||||
}
|
||||
|
||||
return output;
|
||||
|
@ -611,7 +599,7 @@ namespace android {
|
|||
uid_t pidToUid(pid_t pid) {
|
||||
char buffer[512];
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
|
||||
FILE *fp = fopen(buffer, "r");
|
||||
FILE* fp = fopen(buffer, "r");
|
||||
if (fp) {
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
int uid;
|
||||
|
@ -622,9 +610,8 @@ uid_t pidToUid(pid_t pid) {
|
|||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return AID_LOGD; // associate this with the logger
|
||||
return AID_LOGD; // associate this with the logger
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uid_t LogStatistics::pidToUid(pid_t pid) {
|
||||
|
@ -632,10 +619,10 @@ uid_t LogStatistics::pidToUid(pid_t pid) {
|
|||
}
|
||||
|
||||
// caller must free character string
|
||||
const char *LogStatistics::pidToName(pid_t pid) const {
|
||||
const char* LogStatistics::pidToName(pid_t pid) const {
|
||||
// An inconvenient truth ... getName() can alter the object
|
||||
pidTable_t &writablePidTable = const_cast<pidTable_t &>(pidTable);
|
||||
const char *name = writablePidTable.add(pid)->second.getName();
|
||||
pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
|
||||
const char* name = writablePidTable.add(pid)->second.getName();
|
||||
if (!name) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -21,26 +21,25 @@
|
|||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <algorithm> // std::max
|
||||
#include <algorithm> // std::max
|
||||
#include <memory>
|
||||
#include <string> // std::string
|
||||
#include <string> // std::string
|
||||
#include <unordered_map>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android/log.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#include "LogBufferElement.h"
|
||||
#include "LogUtils.h"
|
||||
|
||||
#define log_id_for_each(i) \
|
||||
for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t) ((i) + 1))
|
||||
for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t)((i) + 1))
|
||||
|
||||
class LogStatistics;
|
||||
|
||||
template <typename TKey, typename TEntry>
|
||||
class LogHashtable {
|
||||
|
||||
std::unordered_map<TKey, TEntry> map;
|
||||
|
||||
size_t bucket_size() const {
|
||||
|
@ -58,9 +57,10 @@ class LogHashtable {
|
|||
static const size_t unordered_map_per_entry_overhead = sizeof(void*);
|
||||
static const size_t unordered_map_bucket_overhead = sizeof(void*);
|
||||
|
||||
public:
|
||||
|
||||
size_t size() const { return map.size(); }
|
||||
public:
|
||||
size_t size() const {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
// Estimate unordered_map memory usage.
|
||||
size_t sizeOf() const {
|
||||
|
@ -70,20 +70,21 @@ public:
|
|||
}
|
||||
|
||||
typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
|
||||
typedef typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
|
||||
typedef
|
||||
typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
|
||||
|
||||
std::unique_ptr<const TEntry *[]> sort(uid_t uid, pid_t pid,
|
||||
std::unique_ptr<const TEntry* []> sort(uid_t uid, pid_t pid,
|
||||
size_t len) const {
|
||||
if (!len) {
|
||||
std::unique_ptr<const TEntry *[]> sorted(NULL);
|
||||
std::unique_ptr<const TEntry* []> sorted(NULL);
|
||||
return sorted;
|
||||
}
|
||||
|
||||
const TEntry **retval = new const TEntry* [len];
|
||||
const TEntry** retval = new const TEntry*[len];
|
||||
memset(retval, 0, sizeof(*retval) * len);
|
||||
|
||||
for(const_iterator it = map.begin(); it != map.end(); ++it) {
|
||||
const TEntry &entry = it->second;
|
||||
for (const_iterator it = map.begin(); it != map.end(); ++it) {
|
||||
const TEntry& entry = it->second;
|
||||
|
||||
if ((uid != AID_ROOT) && (uid != entry.getUid())) {
|
||||
continue;
|
||||
|
@ -94,8 +95,8 @@ public:
|
|||
|
||||
size_t sizes = entry.getSizes();
|
||||
ssize_t index = len - 1;
|
||||
while ((!retval[index] || (sizes > retval[index]->getSizes()))
|
||||
&& (--index >= 0))
|
||||
while ((!retval[index] || (sizes > retval[index]->getSizes())) &&
|
||||
(--index >= 0))
|
||||
;
|
||||
if (++index < (ssize_t)len) {
|
||||
size_t num = len - index - 1;
|
||||
|
@ -106,11 +107,11 @@ public:
|
|||
retval[index] = &entry;
|
||||
}
|
||||
}
|
||||
std::unique_ptr<const TEntry *[]> sorted(retval);
|
||||
std::unique_ptr<const TEntry* []> sorted(retval);
|
||||
return sorted;
|
||||
}
|
||||
|
||||
inline iterator add(TKey key, LogBufferElement *element) {
|
||||
inline iterator add(TKey key, LogBufferElement* element) {
|
||||
iterator it = map.find(key);
|
||||
if (it == map.end()) {
|
||||
it = map.insert(std::make_pair(key, TEntry(element))).first;
|
||||
|
@ -130,41 +131,46 @@ public:
|
|||
return it;
|
||||
}
|
||||
|
||||
void subtract(TKey key, LogBufferElement *element) {
|
||||
void subtract(TKey key, LogBufferElement* element) {
|
||||
iterator it = map.find(key);
|
||||
if ((it != map.end()) && it->second.subtract(element)) {
|
||||
map.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
inline void drop(TKey key, LogBufferElement *element) {
|
||||
inline void drop(TKey key, LogBufferElement* element) {
|
||||
iterator it = map.find(key);
|
||||
if (it != map.end()) {
|
||||
it->second.drop(element);
|
||||
}
|
||||
}
|
||||
|
||||
inline iterator begin() { return map.begin(); }
|
||||
inline const_iterator begin() const { return map.begin(); }
|
||||
inline iterator end() { return map.end(); }
|
||||
inline const_iterator end() const { return map.end(); }
|
||||
inline iterator begin() {
|
||||
return map.begin();
|
||||
}
|
||||
inline const_iterator begin() const {
|
||||
return map.begin();
|
||||
}
|
||||
inline iterator end() {
|
||||
return map.end();
|
||||
}
|
||||
inline const_iterator end() const {
|
||||
return map.end();
|
||||
}
|
||||
|
||||
std::string format(
|
||||
const LogStatistics &stat,
|
||||
uid_t uid,
|
||||
pid_t pid,
|
||||
const std::string &name = std::string(""),
|
||||
log_id_t id = LOG_ID_MAX) const {
|
||||
std::string format(const LogStatistics& stat, uid_t uid, pid_t pid,
|
||||
const std::string& name = std::string(""),
|
||||
log_id_t id = LOG_ID_MAX) const {
|
||||
static const size_t maximum_sorted_entries = 32;
|
||||
std::string output;
|
||||
std::unique_ptr<const TEntry *[]> sorted = sort(uid, pid,
|
||||
maximum_sorted_entries);
|
||||
std::unique_ptr<const TEntry* []> sorted =
|
||||
sort(uid, pid, maximum_sorted_entries);
|
||||
if (!sorted.get()) {
|
||||
return output;
|
||||
}
|
||||
bool headerPrinted = false;
|
||||
for (size_t index = 0; index < maximum_sorted_entries; ++index) {
|
||||
const TEntry *entry = sorted[index];
|
||||
const TEntry* entry = sorted[index];
|
||||
if (!entry) {
|
||||
break;
|
||||
}
|
||||
|
@ -180,42 +186,45 @@ public:
|
|||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
namespace EntryBaseConstants {
|
||||
static constexpr size_t pruned_len = 14;
|
||||
static constexpr size_t total_len = 80;
|
||||
static constexpr size_t pruned_len = 14;
|
||||
static constexpr size_t total_len = 80;
|
||||
}
|
||||
|
||||
struct EntryBase {
|
||||
size_t size;
|
||||
|
||||
EntryBase():size(0) { }
|
||||
explicit EntryBase(LogBufferElement *element):size(element->getMsgLen()) { }
|
||||
EntryBase() : size(0) {
|
||||
}
|
||||
explicit EntryBase(LogBufferElement* element) : size(element->getMsgLen()) {
|
||||
}
|
||||
|
||||
size_t getSizes() const { return size; }
|
||||
size_t getSizes() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
inline void add(LogBufferElement *element) { size += element->getMsgLen(); }
|
||||
inline bool subtract(LogBufferElement *element) {
|
||||
inline void add(LogBufferElement* element) {
|
||||
size += element->getMsgLen();
|
||||
}
|
||||
inline bool subtract(LogBufferElement* element) {
|
||||
size -= element->getMsgLen();
|
||||
return !size;
|
||||
}
|
||||
|
||||
static std::string formatLine(
|
||||
const std::string &name,
|
||||
const std::string &size,
|
||||
const std::string &pruned) {
|
||||
ssize_t drop_len = std::max(pruned.length() + 1,
|
||||
EntryBaseConstants::pruned_len);
|
||||
ssize_t size_len = std::max(size.length() + 1,
|
||||
EntryBaseConstants::total_len
|
||||
- name.length() - drop_len - 1);
|
||||
static std::string formatLine(const std::string& name,
|
||||
const std::string& size,
|
||||
const std::string& pruned) {
|
||||
ssize_t drop_len =
|
||||
std::max(pruned.length() + 1, EntryBaseConstants::pruned_len);
|
||||
ssize_t size_len =
|
||||
std::max(size.length() + 1, EntryBaseConstants::total_len -
|
||||
name.length() - drop_len - 1);
|
||||
|
||||
std::string ret = android::base::StringPrintf("%s%*s%*s",
|
||||
name.c_str(),
|
||||
(int)size_len, size.c_str(),
|
||||
(int)drop_len, pruned.c_str());
|
||||
std::string ret = android::base::StringPrintf(
|
||||
"%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
|
||||
(int)drop_len, pruned.c_str());
|
||||
// remove any trailing spaces
|
||||
size_t pos = ret.size();
|
||||
size_t len = 0;
|
||||
|
@ -228,23 +237,25 @@ struct EntryBase {
|
|||
struct EntryBaseDropped : public EntryBase {
|
||||
size_t dropped;
|
||||
|
||||
EntryBaseDropped():dropped(0) { }
|
||||
explicit EntryBaseDropped(LogBufferElement *element):
|
||||
EntryBase(element),
|
||||
dropped(element->getDropped()) {
|
||||
EntryBaseDropped() : dropped(0) {
|
||||
}
|
||||
explicit EntryBaseDropped(LogBufferElement* element)
|
||||
: EntryBase(element), dropped(element->getDropped()) {
|
||||
}
|
||||
|
||||
size_t getDropped() const { return dropped; }
|
||||
size_t getDropped() const {
|
||||
return dropped;
|
||||
}
|
||||
|
||||
inline void add(LogBufferElement *element) {
|
||||
inline void add(LogBufferElement* element) {
|
||||
dropped += element->getDropped();
|
||||
EntryBase::add(element);
|
||||
}
|
||||
inline bool subtract(LogBufferElement *element) {
|
||||
inline bool subtract(LogBufferElement* element) {
|
||||
dropped -= element->getDropped();
|
||||
return EntryBase::subtract(element) && !dropped;
|
||||
}
|
||||
inline void drop(LogBufferElement *element) {
|
||||
inline void drop(LogBufferElement* element) {
|
||||
dropped += 1;
|
||||
EntryBase::subtract(element);
|
||||
}
|
||||
|
@ -254,25 +265,31 @@ struct UidEntry : public EntryBaseDropped {
|
|||
const uid_t uid;
|
||||
pid_t pid;
|
||||
|
||||
explicit UidEntry(LogBufferElement *element):
|
||||
EntryBaseDropped(element),
|
||||
uid(element->getUid()),
|
||||
pid(element->getPid()) {
|
||||
explicit UidEntry(LogBufferElement* element)
|
||||
: EntryBaseDropped(element),
|
||||
uid(element->getUid()),
|
||||
pid(element->getPid()) {
|
||||
}
|
||||
|
||||
inline const uid_t&getKey() const { return uid; }
|
||||
inline const uid_t&getUid() const { return getKey(); }
|
||||
inline const pid_t&getPid() const { return pid; }
|
||||
inline const uid_t& getKey() const {
|
||||
return uid;
|
||||
}
|
||||
inline const uid_t& getUid() const {
|
||||
return getKey();
|
||||
}
|
||||
inline const pid_t& getPid() const {
|
||||
return pid;
|
||||
}
|
||||
|
||||
inline void add(LogBufferElement *element) {
|
||||
inline void add(LogBufferElement* element) {
|
||||
if (pid != element->getPid()) {
|
||||
pid = -1;
|
||||
}
|
||||
EntryBaseDropped::add(element);
|
||||
}
|
||||
|
||||
std::string formatHeader(const std::string &name, log_id_t id) const;
|
||||
std::string format(const LogStatistics &stat, log_id_t id) const;
|
||||
std::string formatHeader(const std::string& name, log_id_t id) const;
|
||||
std::string format(const LogStatistics& stat, log_id_t id) const;
|
||||
};
|
||||
|
||||
namespace android {
|
||||
|
@ -282,32 +299,42 @@ uid_t pidToUid(pid_t pid);
|
|||
struct PidEntry : public EntryBaseDropped {
|
||||
const pid_t pid;
|
||||
uid_t uid;
|
||||
char *name;
|
||||
char* name;
|
||||
|
||||
explicit PidEntry(pid_t pid):
|
||||
EntryBaseDropped(),
|
||||
pid(pid),
|
||||
uid(android::pidToUid(pid)),
|
||||
name(android::pidToName(pid)) {
|
||||
explicit PidEntry(pid_t pid)
|
||||
: EntryBaseDropped(),
|
||||
pid(pid),
|
||||
uid(android::pidToUid(pid)),
|
||||
name(android::pidToName(pid)) {
|
||||
}
|
||||
explicit PidEntry(LogBufferElement *element):
|
||||
EntryBaseDropped(element),
|
||||
pid(element->getPid()),
|
||||
uid(element->getUid()),
|
||||
name(android::pidToName(pid)) {
|
||||
explicit PidEntry(LogBufferElement* element)
|
||||
: EntryBaseDropped(element),
|
||||
pid(element->getPid()),
|
||||
uid(element->getUid()),
|
||||
name(android::pidToName(pid)) {
|
||||
}
|
||||
PidEntry(const PidEntry &element):
|
||||
EntryBaseDropped(element),
|
||||
pid(element.pid),
|
||||
uid(element.uid),
|
||||
name(element.name ? strdup(element.name) : NULL) {
|
||||
PidEntry(const PidEntry& element)
|
||||
: EntryBaseDropped(element),
|
||||
pid(element.pid),
|
||||
uid(element.uid),
|
||||
name(element.name ? strdup(element.name) : NULL) {
|
||||
}
|
||||
~PidEntry() {
|
||||
free(name);
|
||||
}
|
||||
~PidEntry() { free(name); }
|
||||
|
||||
const pid_t&getKey() const { return pid; }
|
||||
const pid_t&getPid() const { return getKey(); }
|
||||
const uid_t&getUid() const { return uid; }
|
||||
const char*getName() const { return name; }
|
||||
const pid_t& getKey() const {
|
||||
return pid;
|
||||
}
|
||||
const pid_t& getPid() const {
|
||||
return getKey();
|
||||
}
|
||||
const uid_t& getUid() const {
|
||||
return uid;
|
||||
}
|
||||
const char* getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
inline void add(pid_t newPid) {
|
||||
if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
|
||||
|
@ -319,7 +346,7 @@ struct PidEntry : public EntryBaseDropped {
|
|||
}
|
||||
}
|
||||
|
||||
inline void add(LogBufferElement *element) {
|
||||
inline void add(LogBufferElement* element) {
|
||||
uid_t incomingUid = element->getUid();
|
||||
if (getUid() != incomingUid) {
|
||||
uid = incomingUid;
|
||||
|
@ -331,44 +358,56 @@ struct PidEntry : public EntryBaseDropped {
|
|||
EntryBaseDropped::add(element);
|
||||
}
|
||||
|
||||
std::string formatHeader(const std::string &name, log_id_t id) const;
|
||||
std::string format(const LogStatistics &stat, log_id_t id) const;
|
||||
std::string formatHeader(const std::string& name, log_id_t id) const;
|
||||
std::string format(const LogStatistics& stat, log_id_t id) const;
|
||||
};
|
||||
|
||||
struct TidEntry : public EntryBaseDropped {
|
||||
const pid_t tid;
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
char *name;
|
||||
char* name;
|
||||
|
||||
TidEntry(pid_t tid, pid_t pid):
|
||||
EntryBaseDropped(),
|
||||
tid(tid),
|
||||
pid(pid),
|
||||
uid(android::pidToUid(tid)),
|
||||
name(android::tidToName(tid)) {
|
||||
TidEntry(pid_t tid, pid_t pid)
|
||||
: EntryBaseDropped(),
|
||||
tid(tid),
|
||||
pid(pid),
|
||||
uid(android::pidToUid(tid)),
|
||||
name(android::tidToName(tid)) {
|
||||
}
|
||||
explicit TidEntry(LogBufferElement *element):
|
||||
EntryBaseDropped(element),
|
||||
tid(element->getTid()),
|
||||
pid(element->getPid()),
|
||||
uid(element->getUid()),
|
||||
name(android::tidToName(tid)) {
|
||||
explicit TidEntry(LogBufferElement* element)
|
||||
: EntryBaseDropped(element),
|
||||
tid(element->getTid()),
|
||||
pid(element->getPid()),
|
||||
uid(element->getUid()),
|
||||
name(android::tidToName(tid)) {
|
||||
}
|
||||
TidEntry(const TidEntry &element):
|
||||
EntryBaseDropped(element),
|
||||
tid(element.tid),
|
||||
pid(element.pid),
|
||||
uid(element.uid),
|
||||
name(element.name ? strdup(element.name) : NULL) {
|
||||
TidEntry(const TidEntry& element)
|
||||
: EntryBaseDropped(element),
|
||||
tid(element.tid),
|
||||
pid(element.pid),
|
||||
uid(element.uid),
|
||||
name(element.name ? strdup(element.name) : NULL) {
|
||||
}
|
||||
~TidEntry() {
|
||||
free(name);
|
||||
}
|
||||
~TidEntry() { free(name); }
|
||||
|
||||
const pid_t&getKey() const { return tid; }
|
||||
const pid_t&getTid() const { return getKey(); }
|
||||
const pid_t&getPid() const { return pid; }
|
||||
const uid_t&getUid() const { return uid; }
|
||||
const char*getName() const { return name; }
|
||||
const pid_t& getKey() const {
|
||||
return tid;
|
||||
}
|
||||
const pid_t& getTid() const {
|
||||
return getKey();
|
||||
}
|
||||
const pid_t& getPid() const {
|
||||
return pid;
|
||||
}
|
||||
const uid_t& getUid() const {
|
||||
return uid;
|
||||
}
|
||||
const char* getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
inline void add(pid_t incomingTid) {
|
||||
if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
|
||||
|
@ -380,7 +419,7 @@ struct TidEntry : public EntryBaseDropped {
|
|||
}
|
||||
}
|
||||
|
||||
inline void add(LogBufferElement *element) {
|
||||
inline void add(LogBufferElement* element) {
|
||||
uid_t incomingUid = element->getUid();
|
||||
pid_t incomingPid = element->getPid();
|
||||
if ((getUid() != incomingUid) || (getPid() != incomingPid)) {
|
||||
|
@ -394,8 +433,8 @@ struct TidEntry : public EntryBaseDropped {
|
|||
EntryBaseDropped::add(element);
|
||||
}
|
||||
|
||||
std::string formatHeader(const std::string &name, log_id_t id) const;
|
||||
std::string format(const LogStatistics &stat, log_id_t id) const;
|
||||
std::string formatHeader(const std::string& name, log_id_t id) const;
|
||||
std::string format(const LogStatistics& stat, log_id_t id) const;
|
||||
};
|
||||
|
||||
struct TagEntry : public EntryBaseDropped {
|
||||
|
@ -403,19 +442,27 @@ struct TagEntry : public EntryBaseDropped {
|
|||
pid_t pid;
|
||||
uid_t uid;
|
||||
|
||||
explicit TagEntry(LogBufferElement *element):
|
||||
EntryBaseDropped(element),
|
||||
tag(element->getTag()),
|
||||
pid(element->getPid()),
|
||||
uid(element->getUid()) {
|
||||
explicit TagEntry(LogBufferElement* element)
|
||||
: EntryBaseDropped(element),
|
||||
tag(element->getTag()),
|
||||
pid(element->getPid()),
|
||||
uid(element->getUid()) {
|
||||
}
|
||||
|
||||
const uint32_t&getKey() const { return tag; }
|
||||
const pid_t&getPid() const { return pid; }
|
||||
const uid_t&getUid() const { return uid; }
|
||||
const char*getName() const { return android::tagToName(tag); }
|
||||
const uint32_t& getKey() const {
|
||||
return tag;
|
||||
}
|
||||
const pid_t& getPid() const {
|
||||
return pid;
|
||||
}
|
||||
const uid_t& getUid() const {
|
||||
return uid;
|
||||
}
|
||||
const char* getName() const {
|
||||
return android::tagToName(tag);
|
||||
}
|
||||
|
||||
inline void add(LogBufferElement *element) {
|
||||
inline void add(LogBufferElement* element) {
|
||||
if (uid != element->getUid()) {
|
||||
uid = -1;
|
||||
}
|
||||
|
@ -425,27 +472,27 @@ struct TagEntry : public EntryBaseDropped {
|
|||
EntryBaseDropped::add(element);
|
||||
}
|
||||
|
||||
std::string formatHeader(const std::string &name, log_id_t id) const;
|
||||
std::string format(const LogStatistics &stat, log_id_t id) const;
|
||||
std::string formatHeader(const std::string& name, log_id_t id) const;
|
||||
std::string format(const LogStatistics& stat, log_id_t id) const;
|
||||
};
|
||||
|
||||
template <typename TEntry>
|
||||
class LogFindWorst {
|
||||
std::unique_ptr<const TEntry *[]> sorted;
|
||||
std::unique_ptr<const TEntry* []> sorted;
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit LogFindWorst(std::unique_ptr<const TEntry* []>&& sorted)
|
||||
: sorted(std::move(sorted)) {
|
||||
}
|
||||
|
||||
explicit LogFindWorst(std::unique_ptr<const TEntry *[]> &&sorted) : sorted(std::move(sorted)) { }
|
||||
|
||||
void findWorst(int &worst,
|
||||
size_t &worst_sizes, size_t &second_worst_sizes,
|
||||
size_t threshold) {
|
||||
void findWorst(int& worst, size_t& worst_sizes, size_t& second_worst_sizes,
|
||||
size_t threshold) {
|
||||
if (sorted.get() && sorted[0] && sorted[1]) {
|
||||
worst_sizes = sorted[0]->getSizes();
|
||||
if ((worst_sizes > threshold)
|
||||
// Allow time horizon to extend roughly tenfold, assume
|
||||
// average entry length is 100 characters.
|
||||
&& (worst_sizes > (10 * sorted[0]->getDropped()))) {
|
||||
&& (worst_sizes > (10 * sorted[0]->getDropped()))) {
|
||||
worst = sorted[0]->getKey();
|
||||
second_worst_sizes = sorted[1]->getSizes();
|
||||
if (second_worst_sizes < threshold) {
|
||||
|
@ -455,13 +502,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void findWorst(int &worst,
|
||||
size_t worst_sizes, size_t &second_worst_sizes) {
|
||||
void findWorst(int& worst, size_t worst_sizes, size_t& second_worst_sizes) {
|
||||
if (sorted.get() && sorted[0] && sorted[1]) {
|
||||
worst = sorted[0]->getKey();
|
||||
second_worst_sizes = worst_sizes
|
||||
- sorted[0]->getSizes()
|
||||
+ sorted[1]->getSizes();
|
||||
second_worst_sizes =
|
||||
worst_sizes - sorted[0]->getSizes() + sorted[1]->getSizes();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -506,11 +551,11 @@ class LogStatistics {
|
|||
tagTable.sizeOf() + securityTagTable.sizeOf() +
|
||||
(pidTable.size() * sizeof(pidTable_t::iterator)) +
|
||||
(tagTable.size() * sizeof(tagTable_t::iterator));
|
||||
for(auto it : pidTable) {
|
||||
for (auto it : pidTable) {
|
||||
const char* name = it.second.getName();
|
||||
if (name) size += strlen(name) + 1;
|
||||
}
|
||||
for(auto it : tidTable) {
|
||||
for (auto it : tidTable) {
|
||||
const char* name = it.second.getName();
|
||||
if (name) size += strlen(name) + 1;
|
||||
}
|
||||
|
@ -518,23 +563,25 @@ class LogStatistics {
|
|||
size += uidTable[id].sizeOf();
|
||||
size += uidTable[id].size() * sizeof(uidTable_t::iterator);
|
||||
size += pidSystemTable[id].sizeOf();
|
||||
size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
|
||||
size +=
|
||||
pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
LogStatistics();
|
||||
|
||||
void enableStatistics() { enable = true; }
|
||||
void enableStatistics() {
|
||||
enable = true;
|
||||
}
|
||||
|
||||
void add(LogBufferElement *entry);
|
||||
void subtract(LogBufferElement *entry);
|
||||
void add(LogBufferElement* entry);
|
||||
void subtract(LogBufferElement* entry);
|
||||
// entry->setDropped(1) must follow this call
|
||||
void drop(LogBufferElement *entry);
|
||||
void drop(LogBufferElement* entry);
|
||||
// Correct for coalescing two entries referencing dropped content
|
||||
void erase(LogBufferElement *element) {
|
||||
void erase(LogBufferElement* element) {
|
||||
log_id_t log_id = element->getLogId();
|
||||
--mElements[log_id];
|
||||
--mDroppedElements[log_id];
|
||||
|
@ -543,7 +590,8 @@ public:
|
|||
LogFindWorst<UidEntry> sort(uid_t uid, pid_t pid, size_t len, log_id id) {
|
||||
return LogFindWorst<UidEntry>(uidTable[id].sort(uid, pid, len));
|
||||
}
|
||||
LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len, log_id id) {
|
||||
LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len,
|
||||
log_id id) {
|
||||
return LogFindWorst<PidEntry>(pidSystemTable[id].sort(uid, pid, len));
|
||||
}
|
||||
LogFindWorst<TagEntry> sortTags(uid_t uid, pid_t pid, size_t len, log_id) {
|
||||
|
@ -551,21 +599,31 @@ public:
|
|||
}
|
||||
|
||||
// fast track current value by id only
|
||||
size_t sizes(log_id_t id) const { return mSizes[id]; }
|
||||
size_t elements(log_id_t id) const { return mElements[id]; }
|
||||
size_t sizes(log_id_t id) const {
|
||||
return mSizes[id];
|
||||
}
|
||||
size_t elements(log_id_t id) const {
|
||||
return mElements[id];
|
||||
}
|
||||
size_t realElements(log_id_t id) const {
|
||||
return mElements[id] - mDroppedElements[id];
|
||||
}
|
||||
size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
|
||||
size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
|
||||
static size_t sizesTotal() { return SizesTotal; }
|
||||
size_t sizesTotal(log_id_t id) const {
|
||||
return mSizesTotal[id];
|
||||
}
|
||||
size_t elementsTotal(log_id_t id) const {
|
||||
return mElementsTotal[id];
|
||||
}
|
||||
static size_t sizesTotal() {
|
||||
return SizesTotal;
|
||||
}
|
||||
|
||||
std::string format(uid_t uid, pid_t pid, unsigned int logMask) const;
|
||||
|
||||
// helper (must be locked directly or implicitly by mLogElementsLock)
|
||||
const char *pidToName(pid_t pid) const;
|
||||
const char* pidToName(pid_t pid) const;
|
||||
uid_t pidToUid(pid_t pid);
|
||||
const char *uidToName(uid_t uid) const;
|
||||
const char* uidToName(uid_t uid) const;
|
||||
};
|
||||
|
||||
#endif // _LOGD_LOG_STATISTICS_H__
|
||||
#endif // _LOGD_LOG_STATISTICS_H__
|
||||
|
|
147
logd/LogTags.cpp
147
logd/LogTags.cpp
|
@ -50,11 +50,13 @@ static uid_t sniffUid(const char* comment, const char* endp) {
|
|||
if (!comment) return AID_ROOT;
|
||||
|
||||
if (*comment == '#') ++comment;
|
||||
while ((comment < endp) && (*comment != '\n') && isspace(*comment)) ++comment;
|
||||
while ((comment < endp) && (*comment != '\n') && isspace(*comment))
|
||||
++comment;
|
||||
static const char uid_str[] = "uid=";
|
||||
if (((comment + strlen(uid_str)) >= endp) ||
|
||||
fastcmp<strncmp>(comment, uid_str, strlen(uid_str)) ||
|
||||
!isdigit(comment[strlen(uid_str)])) return AID_ROOT;
|
||||
fastcmp<strncmp>(comment, uid_str, strlen(uid_str)) ||
|
||||
!isdigit(comment[strlen(uid_str)]))
|
||||
return AID_ROOT;
|
||||
char* cp;
|
||||
unsigned long Uid = strtoul(comment + 4, &cp, 10);
|
||||
if ((cp > endp) || (Uid >= INT_MAX)) return AID_ROOT;
|
||||
|
@ -86,34 +88,32 @@ bool LogTags::RebuildFileEventLogTags(const char* filename, bool warn) {
|
|||
}
|
||||
|
||||
// dump what we already know back into the file?
|
||||
fd = TEMP_FAILURE_RETRY(open(filename,
|
||||
O_WRONLY | O_TRUNC | O_CLOEXEC |
|
||||
O_NOFOLLOW | O_BINARY));
|
||||
fd = TEMP_FAILURE_RETRY(open(
|
||||
filename, O_WRONLY | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
|
||||
if (fd >= 0) {
|
||||
time_t now = time(NULL);
|
||||
struct tm tm;
|
||||
localtime_r(&now, &tm);
|
||||
char timebuf[20];
|
||||
size_t len = strftime(timebuf, sizeof(timebuf),
|
||||
"%Y-%m-%d %H:%M:%S", &tm);
|
||||
size_t len =
|
||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", &tm);
|
||||
android::base::WriteStringToFd(
|
||||
android::base::StringPrintf(
|
||||
"# Rebuilt %.20s, content owned by logd\n", timebuf),
|
||||
fd);
|
||||
for (const auto& it : tag2total) {
|
||||
android::base::WriteStringToFd(formatEntry_locked(it.first,
|
||||
AID_ROOT),
|
||||
fd);
|
||||
android::base::WriteStringToFd(
|
||||
formatEntry_locked(it.first, AID_ROOT), fd);
|
||||
}
|
||||
TEMP_FAILURE_RETRY(close(fd));
|
||||
}
|
||||
}
|
||||
|
||||
if (warn) {
|
||||
android::prdebug(((fd < 0) ?
|
||||
"%s failed to rebuild" :
|
||||
"%s missing, damaged or truncated; rebuilt"),
|
||||
filename);
|
||||
android::prdebug(
|
||||
((fd < 0) ? "%s failed to rebuild"
|
||||
: "%s missing, damaged or truncated; rebuilt"),
|
||||
filename);
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
|
@ -126,10 +126,9 @@ bool LogTags::RebuildFileEventLogTags(const char* filename, bool warn) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void LogTags::AddEventLogTags(uint32_t tag, uid_t uid,
|
||||
const std::string& Name,
|
||||
const std::string& Format,
|
||||
const char* source, bool warn) {
|
||||
void LogTags::AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
|
||||
const std::string& Format, const char* source,
|
||||
bool warn) {
|
||||
std::string Key = Name;
|
||||
if (Format.length()) Key += "+" + Format;
|
||||
|
||||
|
@ -178,8 +177,8 @@ void LogTags::AddEventLogTags(uint32_t tag, uid_t uid,
|
|||
WritePersistEventLogTags(tag, uid, source);
|
||||
} else if (warn && !newOne && source) {
|
||||
// For the files, we want to report dupes.
|
||||
android::prdebug("Multiple tag %" PRIu32 " %s %s %s", tag,
|
||||
Name.c_str(), Format.c_str(), source);
|
||||
android::prdebug("Multiple tag %" PRIu32 " %s %s %s", tag, Name.c_str(),
|
||||
Format.c_str(), source);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,7 +192,7 @@ void LogTags::ReadFileEventLogTags(const char* filename, bool warn) {
|
|||
}
|
||||
std::string content;
|
||||
if (android::base::ReadFileToString(filename, &content)) {
|
||||
char* cp = (char*) content.c_str();
|
||||
char* cp = (char*)content.c_str();
|
||||
char* endp = cp + content.length();
|
||||
|
||||
{
|
||||
|
@ -228,16 +227,19 @@ void LogTags::ReadFileEventLogTags(const char* filename, bool warn) {
|
|||
std::string Name(name, cp - name);
|
||||
#ifdef ALLOW_NOISY_LOGGING_OF_PROBLEM_WITH_LOTS_OF_TECHNICAL_DEBT
|
||||
static const size_t maximum_official_tag_name_size = 24;
|
||||
if (warn && (Name.length() > maximum_official_tag_name_size)) {
|
||||
android::prdebug("tag name too long %s", Name.c_str());
|
||||
if (warn &&
|
||||
(Name.length() > maximum_official_tag_name_size)) {
|
||||
android::prdebug("tag name too long %s", Name.c_str());
|
||||
}
|
||||
#endif
|
||||
if (hasAlpha && ((cp >= endp) || (*cp == '#') || isspace(*cp))) {
|
||||
if (hasAlpha &&
|
||||
((cp >= endp) || (*cp == '#') || isspace(*cp))) {
|
||||
if (Tag > emptyTag) {
|
||||
if (*cp != '\n') lineStart = NULL;
|
||||
continue;
|
||||
}
|
||||
while ((cp < endp) && (*cp != '\n') && isspace(*cp)) ++cp;
|
||||
while ((cp < endp) && (*cp != '\n') && isspace(*cp))
|
||||
++cp;
|
||||
const char* format = cp;
|
||||
uid_t uid = AID_ROOT;
|
||||
while ((cp < endp) && (*cp != '\n')) {
|
||||
|
@ -263,7 +265,9 @@ void LogTags::ReadFileEventLogTags(const char* filename, bool warn) {
|
|||
}
|
||||
lineStart = NULL;
|
||||
}
|
||||
} else if (!isspace(*cp)) break;
|
||||
} else if (!isspace(*cp)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
|
@ -273,8 +277,7 @@ void LogTags::ReadFileEventLogTags(const char* filename, bool warn) {
|
|||
}
|
||||
|
||||
// Extract a 4-byte value from a byte stream.
|
||||
static inline uint32_t get4LE(const char* msg)
|
||||
{
|
||||
static inline uint32_t get4LE(const char* msg) {
|
||||
const uint8_t* src = reinterpret_cast<const uint8_t*>(msg);
|
||||
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
|
||||
}
|
||||
|
@ -284,8 +287,8 @@ static inline uint32_t get4LE(const char* msg)
|
|||
// database with any found.
|
||||
void LogTags::ReadPersistEventLogTags() {
|
||||
struct logger_list* logger_list = android_logger_list_alloc(
|
||||
ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK,
|
||||
0, (pid_t)0);
|
||||
ANDROID_LOG_RDONLY | ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK, 0,
|
||||
(pid_t)0);
|
||||
if (!logger_list) return;
|
||||
|
||||
struct logger* e = android_logger_open(logger_list, LOG_ID_EVENTS);
|
||||
|
@ -305,8 +308,9 @@ void LogTags::ReadPersistEventLogTags() {
|
|||
if (log_msg.entry.len <= sizeof(uint32_t)) continue;
|
||||
uint32_t Tag = get4LE(msg);
|
||||
if (Tag != TAG_DEF_LOG_TAG) continue;
|
||||
uid_t uid = (log_msg.entry.hdr_size >= sizeof(logger_entry_v4)) ?
|
||||
log_msg.entry.uid : AID_ROOT;
|
||||
uid_t uid = (log_msg.entry.hdr_size >= sizeof(logger_entry_v4))
|
||||
? log_msg.entry.uid
|
||||
: AID_ROOT;
|
||||
|
||||
std::string Name;
|
||||
std::string Format;
|
||||
|
@ -433,8 +437,7 @@ uint32_t LogTags::nameToTag(const char* name) const {
|
|||
// writer lock. We use this call to invent a new deterministically
|
||||
// random tag, unique is cleared if no conflicts. If format is NULL,
|
||||
// we are in readonly mode.
|
||||
uint32_t LogTags::nameToTag_locked(const std::string& name,
|
||||
const char* format,
|
||||
uint32_t LogTags::nameToTag_locked(const std::string& name, const char* format,
|
||||
bool& unique) {
|
||||
key2tag_const_iterator ik;
|
||||
|
||||
|
@ -462,7 +465,7 @@ uint32_t LogTags::nameToTag_locked(const std::string& name,
|
|||
size_t Hash = key2tag.hash_function()(Key);
|
||||
uint32_t Tag = Hash;
|
||||
// This sets an upper limit on the conflics we are allowed to deal with.
|
||||
for (unsigned i = 0; i < 256; ) {
|
||||
for (unsigned i = 0; i < 256;) {
|
||||
tag2name_const_iterator it = tag2name.find(Tag);
|
||||
if (it == tag2name.end()) return Tag;
|
||||
std::string localKey(it->second);
|
||||
|
@ -471,15 +474,14 @@ uint32_t LogTags::nameToTag_locked(const std::string& name,
|
|||
localKey += "+" + iform->second;
|
||||
}
|
||||
unique = !!it->second.compare(localKey);
|
||||
if (!unique) return Tag; // unlikely except in a race
|
||||
if (!unique) return Tag; // unlikely except in a race
|
||||
|
||||
++i;
|
||||
// Algorithm to convert hash to next tag
|
||||
if (i < 32) {
|
||||
Tag = (Hash >> i);
|
||||
// size_t is 32 bits, or upper word zero, rotate
|
||||
if ((sizeof(Hash) <= 4) ||
|
||||
((Hash & (uint64_t(-1LL) << 32)) == 0)) {
|
||||
if ((sizeof(Hash) <= 4) || ((Hash & (uint64_t(-1LL) << 32)) == 0)) {
|
||||
Tag |= Hash << (32 - i);
|
||||
}
|
||||
} else {
|
||||
|
@ -501,7 +503,7 @@ void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) {
|
|||
android::RWLock::AutoRLock readLock(rwlock);
|
||||
|
||||
tag2total_const_iterator itot = tag2total.find(tag);
|
||||
if (itot == tag2total.end()) return; // source is a static entry
|
||||
if (itot == tag2total.end()) return; // source is a static entry
|
||||
|
||||
size_t lastTotal = itot->second;
|
||||
|
||||
|
@ -525,7 +527,7 @@ void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) {
|
|||
__android_log_event_list ctx(TAG_DEF_LOG_TAG);
|
||||
ctx << tag << Name << Format;
|
||||
std::string buffer(ctx);
|
||||
if (buffer.length() <= 0) return; // unlikely
|
||||
if (buffer.length() <= 0) return; // unlikely
|
||||
|
||||
/*
|
||||
* struct {
|
||||
|
@ -562,18 +564,17 @@ void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) {
|
|||
|
||||
android_pmsg_log_header_t pmsgHeader = {
|
||||
.magic = LOGGER_MAGIC,
|
||||
.len = (uint16_t)(sizeof(pmsgHeader) + sizeof(header) +
|
||||
sizeof(outTag) + buffer.length()),
|
||||
.len = (uint16_t)(sizeof(pmsgHeader) + sizeof(header) + sizeof(outTag) +
|
||||
buffer.length()),
|
||||
.uid = (uint16_t)AID_ROOT,
|
||||
.pid = (uint16_t)getpid(),
|
||||
};
|
||||
|
||||
struct iovec Vec[] = {
|
||||
{ (unsigned char*)&pmsgHeader, sizeof(pmsgHeader) },
|
||||
{ (unsigned char*)&header, sizeof(header) },
|
||||
{ (unsigned char*)&outTag, sizeof(outTag) },
|
||||
{ (unsigned char*)const_cast<char*>(buffer.data()), buffer.length() }
|
||||
};
|
||||
struct iovec Vec[] = { { (unsigned char*)&pmsgHeader, sizeof(pmsgHeader) },
|
||||
{ (unsigned char*)&header, sizeof(header) },
|
||||
{ (unsigned char*)&outTag, sizeof(outTag) },
|
||||
{ (unsigned char*)const_cast<char*>(buffer.data()),
|
||||
buffer.length() } };
|
||||
|
||||
tag2uid_const_iterator ut = tag2uid.find(tag);
|
||||
if (ut == tag2uid.end()) {
|
||||
|
@ -582,7 +583,7 @@ void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) {
|
|||
pmsgHeader.uid = (uint16_t)uid;
|
||||
TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
|
||||
} else {
|
||||
for (auto &it : ut->second) {
|
||||
for (auto& it : ut->second) {
|
||||
pmsgHeader.uid = (uint16_t)it;
|
||||
TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
|
||||
}
|
||||
|
@ -590,8 +591,8 @@ void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) {
|
|||
}
|
||||
|
||||
void LogTags::WriteDynamicEventLogTags(uint32_t tag, uid_t uid) {
|
||||
static const int mode = O_WRONLY | O_APPEND |
|
||||
O_CLOEXEC | O_NOFOLLOW | O_BINARY;
|
||||
static const int mode =
|
||||
O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
|
||||
|
||||
int fd = openFile(dynamic_event_log_tags, mode, true);
|
||||
if (fd < 0) return;
|
||||
|
@ -612,8 +613,8 @@ void LogTags::WriteDynamicEventLogTags(uint32_t tag, uid_t uid) {
|
|||
}
|
||||
|
||||
void LogTags::WriteDebugEventLogTags(uint32_t tag, uid_t uid) {
|
||||
static const int mode = O_WRONLY | O_APPEND |
|
||||
O_CLOEXEC | O_NOFOLLOW | O_BINARY;
|
||||
static const int mode =
|
||||
O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
|
||||
|
||||
static bool one = true;
|
||||
int fd = openFile(debug_event_log_tags, mode, one);
|
||||
|
@ -636,16 +637,14 @@ void LogTags::WriteDebugEventLogTags(uint32_t tag, uid_t uid) {
|
|||
}
|
||||
|
||||
// How we maintain some runtime or reboot stickiness
|
||||
void LogTags::WritePersistEventLogTags(uint32_t tag,
|
||||
uid_t uid, const char* source) {
|
||||
void LogTags::WritePersistEventLogTags(uint32_t tag, uid_t uid,
|
||||
const char* source) {
|
||||
// very unlikely
|
||||
bool etc = source && !strcmp(source, system_event_log_tags);
|
||||
if (etc) return;
|
||||
|
||||
bool dynamic = source && !strcmp(source, dynamic_event_log_tags);
|
||||
bool debug = (!dynamic &&
|
||||
source &&
|
||||
!strcmp(source, debug_event_log_tags)) ||
|
||||
bool debug = (!dynamic && source && !strcmp(source, debug_event_log_tags)) ||
|
||||
!__android_log_is_debuggable();
|
||||
|
||||
WritePmsgEventLogTags(tag, uid);
|
||||
|
@ -658,7 +657,7 @@ void LogTags::WritePersistEventLogTags(uint32_t tag,
|
|||
if (itot != tag2total.end()) lastTotal = itot->second;
|
||||
}
|
||||
|
||||
if (lastTotal == 0) { // denotes first time for this one
|
||||
if (lastTotal == 0) { // denotes first time for this one
|
||||
if (!dynamic || !RebuildFileEventLogTags(dynamic_event_log_tags)) {
|
||||
WriteDynamicEventLogTags(tag, uid);
|
||||
}
|
||||
|
@ -694,9 +693,9 @@ uint32_t LogTags::nameToTag(uid_t uid, const char* name, const char* format) {
|
|||
tag2uid_const_iterator ut = tag2uid.find(Tag);
|
||||
if (updateUid) {
|
||||
if ((ut != tag2uid.end()) &&
|
||||
(ut->second.find(uid) == ut->second.end())) {
|
||||
unique = write; // write passthrough to update uid counts
|
||||
if (!write) Tag = emptyTag; // deny read access
|
||||
(ut->second.find(uid) == ut->second.end())) {
|
||||
unique = write; // write passthrough to update uid counts
|
||||
if (!write) Tag = emptyTag; // deny read access
|
||||
}
|
||||
} else {
|
||||
unique = write && (ut != tag2uid.end());
|
||||
|
@ -705,7 +704,7 @@ uint32_t LogTags::nameToTag(uid_t uid, const char* name, const char* format) {
|
|||
}
|
||||
|
||||
if (Tag == emptyTag) return Tag;
|
||||
WritePmsgEventLogTags(Tag, uid); // record references periodically
|
||||
WritePmsgEventLogTags(Tag, uid); // record references periodically
|
||||
if (!unique) return Tag;
|
||||
|
||||
bool updateWrite = false;
|
||||
|
@ -728,7 +727,9 @@ uint32_t LogTags::nameToTag(uid_t uid, const char* name, const char* format) {
|
|||
if (updateUid) {
|
||||
// Add it to the uid list
|
||||
if ((ut == tag2uid.end()) ||
|
||||
(ut->second.find(uid) != ut->second.end())) return Tag;
|
||||
(ut->second.find(uid) != ut->second.end())) {
|
||||
return Tag;
|
||||
}
|
||||
const_cast<uid_list&>(ut->second).emplace(uid);
|
||||
updateWrite = true;
|
||||
} else {
|
||||
|
@ -791,8 +792,7 @@ uint32_t LogTags::nameToTag(uid_t uid, const char* name, const char* format) {
|
|||
return Tag;
|
||||
}
|
||||
|
||||
std::string LogTags::formatEntry(uint32_t tag, uid_t uid,
|
||||
const char* name,
|
||||
std::string LogTags::formatEntry(uint32_t tag, uid_t uid, const char* name,
|
||||
const char* format) {
|
||||
if (!format || !format[0]) {
|
||||
return android::base::StringPrintf("%" PRIu32 "\t%s\n", tag, name);
|
||||
|
@ -802,9 +802,8 @@ std::string LogTags::formatEntry(uint32_t tag, uid_t uid,
|
|||
if (len > strlen(tabs)) len = strlen(tabs);
|
||||
std::string Uid;
|
||||
if (uid != AID_ROOT) Uid = android::base::StringPrintf(" # uid=%u", uid);
|
||||
return android::base::StringPrintf("%" PRIu32 "\t%s%s\t%s%s\n",
|
||||
tag, name, &tabs[len], format,
|
||||
Uid.c_str());
|
||||
return android::base::StringPrintf("%" PRIu32 "\t%s%s\t%s%s\n", tag, name,
|
||||
&tabs[len], format, Uid.c_str());
|
||||
}
|
||||
|
||||
std::string LogTags::formatEntry_locked(uint32_t tag, uid_t uid,
|
||||
|
@ -830,7 +829,7 @@ std::string LogTags::formatEntry_locked(uint32_t tag, uid_t uid,
|
|||
|
||||
// Show all, one for each registered uid (we are group root)
|
||||
std::string ret;
|
||||
for (auto &it : ut->second) {
|
||||
for (auto& it : ut->second) {
|
||||
ret += formatEntry(tag, it, name, format);
|
||||
}
|
||||
return ret;
|
||||
|
@ -841,8 +840,8 @@ std::string LogTags::formatEntry(uint32_t tag, uid_t uid) {
|
|||
return formatEntry_locked(tag, uid);
|
||||
}
|
||||
|
||||
std::string LogTags::formatGetEventTag(uid_t uid,
|
||||
const char* name, const char* format) {
|
||||
std::string LogTags::formatGetEventTag(uid_t uid, const char* name,
|
||||
const char* format) {
|
||||
bool all = name && (name[0] == '*') && !name[1];
|
||||
bool list = !name || all;
|
||||
std::string ret;
|
||||
|
@ -864,7 +863,7 @@ std::string LogTags::formatGetEventTag(uid_t uid,
|
|||
// first uid in list so as to manufacture an accurate reference
|
||||
tag2uid_const_iterator ut = tag2uid.find(tag);
|
||||
if ((ut != tag2uid.end()) &&
|
||||
(ut->second.begin() != ut->second.end())) {
|
||||
(ut->second.begin() != ut->second.end())) {
|
||||
uid = *(ut->second.begin());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#ifndef _LOGD_LOG_TAGS_H__
|
||||
#define _LOGD_LOG_TAGS_H__
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
|
||||
#include <utils/RWLock.h>
|
||||
|
||||
|
@ -35,64 +35,70 @@ class LogTags {
|
|||
|
||||
// key is Name + "+" + Format
|
||||
std::unordered_map<std::string, uint32_t> key2tag;
|
||||
typedef std::unordered_map<std::string, uint32_t>::const_iterator key2tag_const_iterator;
|
||||
typedef std::unordered_map<std::string, uint32_t>::const_iterator
|
||||
key2tag_const_iterator;
|
||||
|
||||
// Allows us to manage access permissions based on uid registrants
|
||||
// Global entries are specifically erased.
|
||||
typedef std::unordered_set<uid_t> uid_list;
|
||||
std::unordered_map<uint32_t, uid_list> tag2uid;
|
||||
typedef std::unordered_map<uint32_t, uid_list>::const_iterator tag2uid_const_iterator;
|
||||
typedef std::unordered_map<uint32_t, uid_list>::const_iterator
|
||||
tag2uid_const_iterator;
|
||||
|
||||
std::unordered_map<uint32_t, std::string> tag2name;
|
||||
typedef std::unordered_map<uint32_t, std::string>::const_iterator tag2name_const_iterator;
|
||||
typedef std::unordered_map<uint32_t, std::string>::const_iterator
|
||||
tag2name_const_iterator;
|
||||
|
||||
std::unordered_map<uint32_t, std::string> tag2format;
|
||||
typedef std::unordered_map<uint32_t, std::string>::const_iterator tag2format_const_iterator;
|
||||
typedef std::unordered_map<uint32_t, std::string>::const_iterator
|
||||
tag2format_const_iterator;
|
||||
|
||||
static const size_t max_per_uid = 256; // Put a cap on the tags per uid
|
||||
static const size_t max_per_uid = 256; // Put a cap on the tags per uid
|
||||
std::unordered_map<uid_t, size_t> uid2count;
|
||||
typedef std::unordered_map<uid_t, size_t>::const_iterator uid2count_const_iterator;
|
||||
typedef std::unordered_map<uid_t, size_t>::const_iterator
|
||||
uid2count_const_iterator;
|
||||
|
||||
// Dynamic entries are assigned
|
||||
std::unordered_map<uint32_t, size_t> tag2total;
|
||||
typedef std::unordered_map<uint32_t, size_t>::const_iterator tag2total_const_iterator;
|
||||
typedef std::unordered_map<uint32_t, size_t>::const_iterator
|
||||
tag2total_const_iterator;
|
||||
|
||||
// emplace unique tag
|
||||
uint32_t nameToTag(uid_t uid, const char* name, const char* format);
|
||||
// find unique or associated tag
|
||||
uint32_t nameToTag_locked(const std::string& name, const char* format, bool &unique);
|
||||
uint32_t nameToTag_locked(const std::string& name, const char* format,
|
||||
bool& unique);
|
||||
|
||||
// Record expected file watermarks to detect corruption.
|
||||
std::unordered_map<std::string, size_t> file2watermark;
|
||||
typedef std::unordered_map<std::string, size_t>::const_iterator file2watermark_const_iterator;
|
||||
typedef std::unordered_map<std::string, size_t>::const_iterator
|
||||
file2watermark_const_iterator;
|
||||
|
||||
void ReadPersistEventLogTags();
|
||||
|
||||
// format helpers
|
||||
// format a single entry, does not need object data
|
||||
static std::string formatEntry(uint32_t tag, uid_t uid,
|
||||
const char* name, const char* format);
|
||||
static std::string formatEntry(uint32_t tag, uid_t uid, const char* name,
|
||||
const char* format);
|
||||
// caller locks, database lookup, authenticate against uid
|
||||
std::string formatEntry_locked(uint32_t tag, uid_t uid,
|
||||
bool authenticate = true);
|
||||
|
||||
bool RebuildFileEventLogTags(const char* filename, bool warn = true);
|
||||
|
||||
void AddEventLogTags(uint32_t tag, uid_t uid,
|
||||
const std::string& Name, const std::string& Format,
|
||||
const char* source = NULL, bool warn = false);
|
||||
void AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
|
||||
const std::string& Format, const char* source = NULL,
|
||||
bool warn = false);
|
||||
|
||||
void WriteDynamicEventLogTags(uint32_t tag, uid_t uid);
|
||||
void WriteDebugEventLogTags(uint32_t tag, uid_t uid);
|
||||
// push tag details to persistent storage
|
||||
void WritePersistEventLogTags(uint32_t tag,
|
||||
uid_t uid = AID_ROOT,
|
||||
void WritePersistEventLogTags(uint32_t tag, uid_t uid = AID_ROOT,
|
||||
const char* source = NULL);
|
||||
|
||||
static const uint32_t emptyTag = uint32_t(-1);
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
static const char system_event_log_tags[];
|
||||
static const char dynamic_event_log_tags[];
|
||||
// Only for userdebug and eng
|
||||
|
@ -111,9 +117,8 @@ public:
|
|||
uint32_t nameToTag(const char* name) const;
|
||||
|
||||
// emplace tag if necessary, provide event-log-tag formated output in string
|
||||
std::string formatGetEventTag(uid_t uid,
|
||||
const char* name,
|
||||
std::string formatGetEventTag(uid_t uid, const char* name,
|
||||
const char* format);
|
||||
};
|
||||
|
||||
#endif // _LOGD_LOG_TAGS_H__
|
||||
#endif // _LOGD_LOG_TAGS_H__
|
||||
|
|
|
@ -19,30 +19,30 @@
|
|||
|
||||
#include "FlushCommand.h"
|
||||
#include "LogBuffer.h"
|
||||
#include "LogTimes.h"
|
||||
#include "LogReader.h"
|
||||
#include "LogTimes.h"
|
||||
|
||||
pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
|
||||
LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client,
|
||||
bool nonBlock, unsigned long tail,
|
||||
unsigned int logMask, pid_t pid,
|
||||
uint64_t start, uint64_t timeout) :
|
||||
mRefCount(1),
|
||||
mRelease(false),
|
||||
mError(false),
|
||||
threadRunning(false),
|
||||
leadingDropped(false),
|
||||
mReader(reader),
|
||||
mLogMask(logMask),
|
||||
mPid(pid),
|
||||
mCount(0),
|
||||
mTail(tail),
|
||||
mIndex(0),
|
||||
mClient(client),
|
||||
mStart(start),
|
||||
mNonBlock(nonBlock),
|
||||
mEnd(LogBufferElement::getCurrentSequence()) {
|
||||
unsigned int logMask, pid_t pid, uint64_t start,
|
||||
uint64_t timeout)
|
||||
: mRefCount(1),
|
||||
mRelease(false),
|
||||
mError(false),
|
||||
threadRunning(false),
|
||||
leadingDropped(false),
|
||||
mReader(reader),
|
||||
mLogMask(logMask),
|
||||
mPid(pid),
|
||||
mCount(0),
|
||||
mTail(tail),
|
||||
mIndex(0),
|
||||
mClient(client),
|
||||
mStart(start),
|
||||
mNonBlock(nonBlock),
|
||||
mEnd(LogBufferElement::getCurrentSequence()) {
|
||||
mTimeout.tv_sec = timeout / NS_PER_SEC;
|
||||
mTimeout.tv_nsec = timeout % NS_PER_SEC;
|
||||
pthread_cond_init(&threadTriggeredCondition, NULL);
|
||||
|
@ -56,8 +56,8 @@ void LogTimeEntry::startReader_Locked(void) {
|
|||
|
||||
if (!pthread_attr_init(&attr)) {
|
||||
if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
|
||||
if (!pthread_create(&mThread, &attr,
|
||||
LogTimeEntry::threadStart, this)) {
|
||||
if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart,
|
||||
this)) {
|
||||
pthread_attr_destroy(&attr);
|
||||
return;
|
||||
}
|
||||
|
@ -71,8 +71,8 @@ void LogTimeEntry::startReader_Locked(void) {
|
|||
decRef_Locked();
|
||||
}
|
||||
|
||||
void LogTimeEntry::threadStop(void *obj) {
|
||||
LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
|
||||
void LogTimeEntry::threadStop(void* obj) {
|
||||
LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
|
||||
|
||||
lock();
|
||||
|
||||
|
@ -80,14 +80,14 @@ void LogTimeEntry::threadStop(void *obj) {
|
|||
me->error_Locked();
|
||||
}
|
||||
|
||||
SocketClient *client = me->mClient;
|
||||
SocketClient* client = me->mClient;
|
||||
|
||||
if (me->isError_Locked()) {
|
||||
LogReader &reader = me->mReader;
|
||||
LastLogTimes × = reader.logbuf().mTimes;
|
||||
LogReader& reader = me->mReader;
|
||||
LastLogTimes& times = reader.logbuf().mTimes;
|
||||
|
||||
LastLogTimes::iterator it = times.begin();
|
||||
while(it != times.end()) {
|
||||
while (it != times.end()) {
|
||||
if (*it == me) {
|
||||
times.erase(it);
|
||||
me->release_nodelete_Locked();
|
||||
|
@ -110,20 +110,20 @@ void LogTimeEntry::threadStop(void *obj) {
|
|||
unlock();
|
||||
}
|
||||
|
||||
void *LogTimeEntry::threadStart(void *obj) {
|
||||
void* LogTimeEntry::threadStart(void* obj) {
|
||||
prctl(PR_SET_NAME, "logd.reader.per");
|
||||
|
||||
LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
|
||||
LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
|
||||
|
||||
pthread_cleanup_push(threadStop, obj);
|
||||
|
||||
SocketClient *client = me->mClient;
|
||||
SocketClient* client = me->mClient;
|
||||
if (!client) {
|
||||
me->error();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LogBuffer &logbuf = me->mReader.logbuf();
|
||||
LogBuffer& logbuf = me->mReader.logbuf();
|
||||
|
||||
bool privileged = FlushCommand::hasReadLogs(client);
|
||||
bool security = FlushCommand::hasSecurityLogs(client);
|
||||
|
@ -135,11 +135,9 @@ void *LogTimeEntry::threadStart(void *obj) {
|
|||
uint64_t start = me->mStart;
|
||||
|
||||
while (me->threadRunning && !me->isError_Locked()) {
|
||||
|
||||
if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
|
||||
if (pthread_cond_timedwait(&me->threadTriggeredCondition,
|
||||
×Lock,
|
||||
&me->mTimeout) == ETIMEDOUT) {
|
||||
×Lock, &me->mTimeout) == ETIMEDOUT) {
|
||||
me->mTimeout.tv_sec = 0;
|
||||
me->mTimeout.tv_nsec = 0;
|
||||
}
|
||||
|
@ -151,10 +149,12 @@ void *LogTimeEntry::threadStart(void *obj) {
|
|||
unlock();
|
||||
|
||||
if (me->mTail) {
|
||||
logbuf.flushTo(client, start, privileged, security, FilterFirstPass, me);
|
||||
logbuf.flushTo(client, start, privileged, security, FilterFirstPass,
|
||||
me);
|
||||
me->leadingDropped = true;
|
||||
}
|
||||
start = logbuf.flushTo(client, start, privileged, security, FilterSecondPass, me);
|
||||
start = logbuf.flushTo(client, start, privileged, security,
|
||||
FilterSecondPass, me);
|
||||
|
||||
lock();
|
||||
|
||||
|
@ -184,8 +184,8 @@ void *LogTimeEntry::threadStart(void *obj) {
|
|||
}
|
||||
|
||||
// A first pass to count the number of elements
|
||||
int LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
|
||||
LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
|
||||
int LogTimeEntry::FilterFirstPass(const LogBufferElement* element, void* obj) {
|
||||
LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
|
||||
|
||||
LogTimeEntry::lock();
|
||||
|
||||
|
@ -201,8 +201,8 @@ int LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
|
|||
me->mStart = element->getSequence();
|
||||
}
|
||||
|
||||
if ((!me->mPid || (me->mPid == element->getPid()))
|
||||
&& (me->isWatching(element->getLogId()))) {
|
||||
if ((!me->mPid || (me->mPid == element->getPid())) &&
|
||||
(me->isWatching(element->getLogId()))) {
|
||||
++me->mCount;
|
||||
}
|
||||
|
||||
|
@ -212,8 +212,8 @@ int LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
|
|||
}
|
||||
|
||||
// A second pass to send the selected elements
|
||||
int LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) {
|
||||
LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
|
||||
int LogTimeEntry::FilterSecondPass(const LogBufferElement* element, void* obj) {
|
||||
LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
|
||||
|
||||
LogTimeEntry::lock();
|
||||
|
||||
|
@ -267,7 +267,7 @@ ok:
|
|||
LogTimeEntry::unlock();
|
||||
return true;
|
||||
}
|
||||
// FALLTHRU
|
||||
// FALLTHRU
|
||||
|
||||
skip:
|
||||
LogTimeEntry::unlock();
|
||||
|
@ -279,7 +279,7 @@ stop:
|
|||
}
|
||||
|
||||
void LogTimeEntry::cleanSkip_Locked(void) {
|
||||
for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1)) {
|
||||
for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t)(i + 1)) {
|
||||
skipAhead[i] = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#define _LOGD_LOG_TIMES_H__
|
||||
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
|
@ -38,9 +38,9 @@ class LogTimeEntry {
|
|||
bool leadingDropped;
|
||||
pthread_cond_t threadTriggeredCondition;
|
||||
pthread_t mThread;
|
||||
LogReader &mReader;
|
||||
static void *threadStart(void *me);
|
||||
static void threadStop(void *me);
|
||||
LogReader& mReader;
|
||||
static void* threadStart(void* me);
|
||||
static void threadStop(void* me);
|
||||
const unsigned int mLogMask;
|
||||
const pid_t mPid;
|
||||
unsigned int skipAhead[LOG_ID_MAX];
|
||||
|
@ -48,20 +48,24 @@ class LogTimeEntry {
|
|||
unsigned long mTail;
|
||||
unsigned long mIndex;
|
||||
|
||||
public:
|
||||
LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock,
|
||||
public:
|
||||
LogTimeEntry(LogReader& reader, SocketClient* client, bool nonBlock,
|
||||
unsigned long tail, unsigned int logMask, pid_t pid,
|
||||
uint64_t start, uint64_t timeout);
|
||||
|
||||
SocketClient *mClient;
|
||||
SocketClient* mClient;
|
||||
uint64_t mStart;
|
||||
struct timespec mTimeout;
|
||||
const bool mNonBlock;
|
||||
const uint64_t mEnd; // only relevant if mNonBlock
|
||||
const uint64_t mEnd; // only relevant if mNonBlock
|
||||
|
||||
// Protect List manipulations
|
||||
static void lock(void) { pthread_mutex_lock(×Lock); }
|
||||
static void unlock(void) { pthread_mutex_unlock(×Lock); }
|
||||
static void lock(void) {
|
||||
pthread_mutex_lock(×Lock);
|
||||
}
|
||||
static void unlock(void) {
|
||||
pthread_mutex_unlock(×Lock);
|
||||
}
|
||||
|
||||
void startReader_Locked(void);
|
||||
|
||||
|
@ -72,7 +76,9 @@ public:
|
|||
pthread_cond_signal(&threadTriggeredCondition);
|
||||
}
|
||||
|
||||
void triggerSkip_Locked(log_id_t id, unsigned int skip) { skipAhead[id] = skip; }
|
||||
void triggerSkip_Locked(log_id_t id, unsigned int skip) {
|
||||
skipAhead[id] = skip;
|
||||
}
|
||||
void cleanSkip_Locked(void);
|
||||
|
||||
// These called after LogTimeEntry removed from list, lock implicitly held
|
||||
|
@ -93,16 +99,28 @@ public:
|
|||
}
|
||||
|
||||
// Called to mark socket in jeopardy
|
||||
void error_Locked(void) { mError = true; }
|
||||
void error(void) { lock(); error_Locked(); unlock(); }
|
||||
void error_Locked(void) {
|
||||
mError = true;
|
||||
}
|
||||
void error(void) {
|
||||
lock();
|
||||
error_Locked();
|
||||
unlock();
|
||||
}
|
||||
|
||||
bool isError_Locked(void) const { return mRelease || mError; }
|
||||
bool isError_Locked(void) const {
|
||||
return mRelease || mError;
|
||||
}
|
||||
|
||||
// Mark Used
|
||||
// Locking implied, grabbed when protection around loop iteration
|
||||
void incRef_Locked(void) { ++mRefCount; }
|
||||
void incRef_Locked(void) {
|
||||
++mRefCount;
|
||||
}
|
||||
|
||||
bool owned_Locked(void) const { return mRefCount != 0; }
|
||||
bool owned_Locked(void) const {
|
||||
return mRefCount != 0;
|
||||
}
|
||||
|
||||
void decRef_Locked(void) {
|
||||
if ((mRefCount && --mRefCount) || !mRelease || threadRunning) {
|
||||
|
@ -111,12 +129,14 @@ public:
|
|||
// No one else is holding a reference to this
|
||||
delete this;
|
||||
}
|
||||
bool isWatching(log_id_t id) { return (mLogMask & (1<<id)) != 0; }
|
||||
bool isWatching(log_id_t id) {
|
||||
return (mLogMask & (1 << id)) != 0;
|
||||
}
|
||||
// flushTo filter callbacks
|
||||
static int FilterFirstPass(const LogBufferElement *element, void *me);
|
||||
static int FilterSecondPass(const LogBufferElement *element, void *me);
|
||||
static int FilterFirstPass(const LogBufferElement* element, void* me);
|
||||
static int FilterSecondPass(const LogBufferElement* element, void* me);
|
||||
};
|
||||
|
||||
typedef std::list<LogTimeEntry *> LastLogTimes;
|
||||
typedef std::list<LogTimeEntry*> LastLogTimes;
|
||||
|
||||
#endif // _LOGD_LOG_TIMES_H__
|
||||
#endif // _LOGD_LOG_TIMES_H__
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/FastStrcmp.h>
|
||||
#include <private/android_logger.h>
|
||||
#include <sysutils/SocketClient.h>
|
||||
#include <utils/FastStrcmp.h>
|
||||
|
||||
// Hijack this header as a common include file used by most all sources
|
||||
// to report some utilities defined here and there.
|
||||
|
@ -30,31 +30,30 @@
|
|||
namespace android {
|
||||
|
||||
// Furnished in main.cpp. Caller must own and free returned value
|
||||
char *uidToName(uid_t uid);
|
||||
void prdebug(const char *fmt, ...) __printflike(1, 2);
|
||||
char* uidToName(uid_t uid);
|
||||
void prdebug(const char* fmt, ...) __printflike(1, 2);
|
||||
|
||||
// Furnished in LogStatistics.cpp.
|
||||
size_t sizesTotal();
|
||||
// Caller must own and free returned value
|
||||
char *pidToName(pid_t pid);
|
||||
char *tidToName(pid_t tid);
|
||||
char* pidToName(pid_t pid);
|
||||
char* tidToName(pid_t tid);
|
||||
|
||||
// Furnished in LogTags.cpp. Thread safe.
|
||||
const char *tagToName(uint32_t tag);
|
||||
const char* tagToName(uint32_t tag);
|
||||
void ReReadEventLogTags();
|
||||
|
||||
// Furnished by LogKlog.cpp.
|
||||
const char* strnstr(const char* s, size_t len, const char* needle);
|
||||
|
||||
}
|
||||
|
||||
// Furnished in LogCommand.cpp
|
||||
bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
|
||||
bool clientHasLogCredentials(SocketClient *cli);
|
||||
bool clientHasLogCredentials(SocketClient* cli);
|
||||
|
||||
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);
|
||||
(id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
|
||||
}
|
||||
|
||||
#endif // _LOGD_LOG_UTILS_H__
|
||||
#endif // _LOGD_LOG_UTILS_H__
|
||||
|
|
|
@ -64,7 +64,7 @@ PruneList::~PruneList() {
|
|||
}
|
||||
}
|
||||
|
||||
int PruneList::init(const char *str) {
|
||||
int PruneList::init(const char* str) {
|
||||
mWorstUidEnabled = true;
|
||||
mWorstPidOfSystemEnabled = true;
|
||||
PruneCollection::iterator it;
|
||||
|
@ -113,13 +113,13 @@ int PruneList::init(const char *str) {
|
|||
mWorstUidEnabled = false;
|
||||
mWorstPidOfSystemEnabled = false;
|
||||
|
||||
for(str = filter.c_str(); *str; ++str) {
|
||||
for (str = filter.c_str(); *str; ++str) {
|
||||
if (isspace(*str)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PruneCollection *list;
|
||||
if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented
|
||||
PruneCollection* list;
|
||||
if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented
|
||||
++str;
|
||||
// special case, translates to worst UID at priority in blacklist
|
||||
if (*str == '!') {
|
||||
|
@ -184,7 +184,7 @@ int PruneList::init(const char *str) {
|
|||
// insert sequentially into list
|
||||
PruneCollection::iterator it = list->begin();
|
||||
while (it != list->end()) {
|
||||
Prune &p = *it;
|
||||
Prune& p = *it;
|
||||
int m = uid - p.mUid;
|
||||
if (m == 0) {
|
||||
if (p.mPid == p.pid_all) {
|
||||
|
@ -198,14 +198,14 @@ int PruneList::init(const char *str) {
|
|||
}
|
||||
if (m <= 0) {
|
||||
if (m < 0) {
|
||||
list->insert(it, Prune(uid,pid));
|
||||
list->insert(it, Prune(uid, pid));
|
||||
}
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (it == list->end()) {
|
||||
list->push_back(Prune(uid,pid));
|
||||
list->push_back(Prune(uid, pid));
|
||||
}
|
||||
if (!*str) {
|
||||
break;
|
||||
|
@ -217,7 +217,7 @@ int PruneList::init(const char *str) {
|
|||
|
||||
std::string PruneList::format() {
|
||||
static const char nice_format[] = " %s";
|
||||
const char *fmt = nice_format + 1;
|
||||
const char* fmt = nice_format + 1;
|
||||
|
||||
std::string string;
|
||||
|
||||
|
@ -250,7 +250,7 @@ std::string PruneList::format() {
|
|||
// If there is scaling issues, resort to a better algorithm than linear
|
||||
// based on these assumptions.
|
||||
|
||||
bool PruneList::naughty(LogBufferElement *element) {
|
||||
bool PruneList::naughty(LogBufferElement* element) {
|
||||
PruneCollection::iterator it;
|
||||
for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
|
||||
if (!(*it).cmp(element)) {
|
||||
|
@ -260,7 +260,7 @@ bool PruneList::naughty(LogBufferElement *element) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool PruneList::nice(LogBufferElement *element) {
|
||||
bool PruneList::nice(LogBufferElement* element) {
|
||||
PruneCollection::iterator it;
|
||||
for (it = mNice.begin(); it != mNice.end(); ++it) {
|
||||
if (!(*it).cmp(element)) {
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <list>
|
||||
#include <string.h>
|
||||
#include <list>
|
||||
|
||||
#include "LogBufferElement.h"
|
||||
|
||||
|
@ -33,16 +33,22 @@ class Prune {
|
|||
const pid_t mPid;
|
||||
int cmp(uid_t uid, pid_t pid) const;
|
||||
|
||||
public:
|
||||
static const uid_t uid_all = (uid_t) -1;
|
||||
static const pid_t pid_all = (pid_t) -1;
|
||||
public:
|
||||
static const uid_t uid_all = (uid_t)-1;
|
||||
static const pid_t pid_all = (pid_t)-1;
|
||||
|
||||
Prune(uid_t uid, pid_t pid);
|
||||
|
||||
uid_t getUid() const { return mUid; }
|
||||
pid_t getPid() const { return mPid; }
|
||||
uid_t getUid() const {
|
||||
return mUid;
|
||||
}
|
||||
pid_t getPid() const {
|
||||
return mPid;
|
||||
}
|
||||
|
||||
int cmp(LogBufferElement *e) const { return cmp(e->getUid(), e->getPid()); }
|
||||
int cmp(LogBufferElement* e) const {
|
||||
return cmp(e->getUid(), e->getPid());
|
||||
}
|
||||
|
||||
std::string format();
|
||||
};
|
||||
|
@ -55,20 +61,28 @@ class PruneList {
|
|||
bool mWorstUidEnabled;
|
||||
bool mWorstPidOfSystemEnabled;
|
||||
|
||||
public:
|
||||
public:
|
||||
PruneList();
|
||||
~PruneList();
|
||||
|
||||
int init(const char *str);
|
||||
int init(const char* str);
|
||||
|
||||
bool naughty(LogBufferElement *element);
|
||||
bool naughty(void) { return !mNaughty.empty(); }
|
||||
bool nice(LogBufferElement *element);
|
||||
bool nice(void) { return !mNice.empty(); }
|
||||
bool worstUidEnabled() const { return mWorstUidEnabled; }
|
||||
bool worstPidOfSystemEnabled() const { return mWorstPidOfSystemEnabled; }
|
||||
bool naughty(LogBufferElement* element);
|
||||
bool naughty(void) {
|
||||
return !mNaughty.empty();
|
||||
}
|
||||
bool nice(LogBufferElement* element);
|
||||
bool nice(void) {
|
||||
return !mNice.empty();
|
||||
}
|
||||
bool worstUidEnabled() const {
|
||||
return mWorstUidEnabled;
|
||||
}
|
||||
bool worstPidOfSystemEnabled() const {
|
||||
return mWorstPidOfSystemEnabled;
|
||||
}
|
||||
|
||||
std::string format();
|
||||
};
|
||||
|
||||
#endif // _LOGD_LOG_WHITE_BLACK_LIST_H__
|
||||
#endif // _LOGD_LOG_WHITE_BLACK_LIST_H__
|
||||
|
|
|
@ -31,8 +31,7 @@
|
|||
* @return
|
||||
* This function returns 0 on success, else -errno.
|
||||
*/
|
||||
static int get_ack(int fd)
|
||||
{
|
||||
static int get_ack(int fd) {
|
||||
int rc;
|
||||
struct audit_message rep;
|
||||
|
||||
|
@ -48,7 +47,7 @@ static int get_ack(int fd)
|
|||
|
||||
if (rep.nlh.nlmsg_type == NLMSG_ERROR) {
|
||||
audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0);
|
||||
rc = ((struct nlmsgerr *)rep.data)->error;
|
||||
rc = ((struct nlmsgerr*)rep.data)->error;
|
||||
if (rc) {
|
||||
return -rc;
|
||||
}
|
||||
|
@ -70,8 +69,7 @@ static int get_ack(int fd)
|
|||
* @return
|
||||
* This function returns a positive sequence number on success, else -errno.
|
||||
*/
|
||||
static int audit_send(int fd, int type, const void *data, size_t size)
|
||||
{
|
||||
static int audit_send(int fd, int type, const void* data, size_t size) {
|
||||
int rc;
|
||||
static int16_t sequence = 0;
|
||||
struct audit_message req;
|
||||
|
@ -123,13 +121,13 @@ static int audit_send(int fd, int type, const void *data, size_t size)
|
|||
/* While failing and its due to interrupts */
|
||||
|
||||
rc = TEMP_FAILURE_RETRY(sendto(fd, &req, req.nlh.nlmsg_len, 0,
|
||||
(struct sockaddr*) &addr, sizeof(addr)));
|
||||
(struct sockaddr*)&addr, sizeof(addr)));
|
||||
|
||||
/* Not all the bytes were sent */
|
||||
if (rc < 0) {
|
||||
rc = -errno;
|
||||
goto out;
|
||||
} else if ((uint32_t) rc != req.nlh.nlmsg_len) {
|
||||
} else if ((uint32_t)rc != req.nlh.nlmsg_len) {
|
||||
rc = -EPROTO;
|
||||
goto out;
|
||||
}
|
||||
|
@ -138,7 +136,7 @@ static int audit_send(int fd, int type, const void *data, size_t size)
|
|||
rc = get_ack(fd);
|
||||
|
||||
/* If the ack failed, return the error, else return the sequence number */
|
||||
rc = (rc == 0) ? (int) sequence : rc;
|
||||
rc = (rc == 0) ? (int)sequence : rc;
|
||||
|
||||
out:
|
||||
/* Don't let sequence roll to negative */
|
||||
|
@ -149,8 +147,7 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
int audit_setup(int fd, pid_t pid)
|
||||
{
|
||||
int audit_setup(int fd, pid_t pid) {
|
||||
int rc;
|
||||
struct audit_message rep;
|
||||
struct audit_status status;
|
||||
|
@ -186,8 +183,7 @@ int audit_setup(int fd, pid_t pid)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int audit_rate_limit(int fd, unsigned rate_limit)
|
||||
{
|
||||
int audit_rate_limit(int fd, unsigned rate_limit) {
|
||||
int rc;
|
||||
struct audit_message rep;
|
||||
struct audit_status status;
|
||||
|
@ -207,13 +203,11 @@ int audit_rate_limit(int fd, unsigned rate_limit)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int audit_open()
|
||||
{
|
||||
int audit_open() {
|
||||
return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
|
||||
}
|
||||
|
||||
int audit_get_reply(int fd, struct audit_message *rep, reply_t block, int peek)
|
||||
{
|
||||
int audit_get_reply(int fd, struct audit_message* rep, reply_t block, int peek) {
|
||||
ssize_t len;
|
||||
int flags;
|
||||
int rc = 0;
|
||||
|
@ -235,7 +229,7 @@ int audit_get_reply(int fd, struct audit_message *rep, reply_t block, int peek)
|
|||
* however, can be returned.
|
||||
*/
|
||||
len = TEMP_FAILURE_RETRY(recvfrom(fd, rep, sizeof(*rep), flags,
|
||||
(struct sockaddr*) &nladdr, &nladdrlen));
|
||||
(struct sockaddr*)&nladdr, &nladdrlen));
|
||||
|
||||
/*
|
||||
* EAGAIN should be re-tried until success or another error manifests.
|
||||
|
@ -266,7 +260,6 @@ int audit_get_reply(int fd, struct audit_message *rep, reply_t block, int peek)
|
|||
return rc;
|
||||
}
|
||||
|
||||
void audit_close(int fd)
|
||||
{
|
||||
void audit_close(int fd) {
|
||||
close(fd);
|
||||
}
|
||||
|
|
|
@ -25,17 +25,14 @@
|
|||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/audit.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define MAX_AUDIT_MESSAGE_LENGTH 8970
|
||||
#define MAX_AUDIT_MESSAGE_LENGTH 8970
|
||||
|
||||
typedef enum {
|
||||
GET_REPLY_BLOCKING = 0,
|
||||
GET_REPLY_NONBLOCKING
|
||||
} reply_t;
|
||||
typedef enum { GET_REPLY_BLOCKING = 0, GET_REPLY_NONBLOCKING } reply_t;
|
||||
|
||||
/* type == AUDIT_SIGNAL_INFO */
|
||||
struct audit_sig_info {
|
||||
|
@ -46,7 +43,7 @@ struct audit_sig_info {
|
|||
|
||||
struct audit_message {
|
||||
struct nlmsghdr nlh;
|
||||
char data[MAX_AUDIT_MESSAGE_LENGTH];
|
||||
char data[MAX_AUDIT_MESSAGE_LENGTH];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -78,7 +75,7 @@ extern void audit_close(int fd);
|
|||
* @return
|
||||
* This function returns 0 on success, else -errno.
|
||||
*/
|
||||
extern int audit_get_reply(int fd, struct audit_message *rep, reply_t block,
|
||||
extern int audit_get_reply(int fd, struct audit_message* rep, reply_t block,
|
||||
int peek);
|
||||
|
||||
/**
|
||||
|
@ -105,7 +102,7 @@ extern int audit_setup(int fd, pid_t pid);
|
|||
/* Guidelines to follow for dynamic rate_limit */
|
||||
#define AUDIT_RATE_LIMIT_DEFAULT 20 /* acceptable burst rate */
|
||||
#define AUDIT_RATE_LIMIT_BURST_DURATION 10 /* number of seconds of burst */
|
||||
#define AUDIT_RATE_LIMIT_MAX 5 /* acceptable sustained rate */
|
||||
#define AUDIT_RATE_LIMIT_MAX 5 /* acceptable sustained rate */
|
||||
|
||||
extern int audit_rate_limit(int fd, unsigned rate_limit);
|
||||
|
||||
|
|
161
logd/main.cpp
161
logd/main.cpp
|
@ -48,17 +48,15 @@
|
|||
#include <utils/threads.h>
|
||||
|
||||
#include "CommandListener.h"
|
||||
#include "LogBuffer.h"
|
||||
#include "LogListener.h"
|
||||
#include "LogAudit.h"
|
||||
#include "LogBuffer.h"
|
||||
#include "LogKlog.h"
|
||||
#include "LogListener.h"
|
||||
#include "LogUtils.h"
|
||||
|
||||
#define KMSG_PRIORITY(PRI) \
|
||||
'<', \
|
||||
'0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
|
||||
'0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, \
|
||||
'>'
|
||||
#define KMSG_PRIORITY(PRI) \
|
||||
'<', '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
|
||||
'0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, '>'
|
||||
|
||||
//
|
||||
// The service is designed to be run by init, it does not respond well
|
||||
|
@ -92,7 +90,8 @@
|
|||
static int drop_privs(bool klogd, bool auditd) {
|
||||
// Tricky, if ro.build.type is "eng" then this is true because of the
|
||||
// side effect that ro.debuggable == 1 as well, else it is false.
|
||||
bool eng = __android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);
|
||||
bool eng =
|
||||
__android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);
|
||||
|
||||
struct sched_param param;
|
||||
memset(¶m, 0, sizeof(param));
|
||||
|
@ -102,7 +101,7 @@ static int drop_privs(bool klogd, bool auditd) {
|
|||
if (!eng) return -1;
|
||||
}
|
||||
|
||||
if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) {
|
||||
if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
|
||||
android::prdebug("failed to set batch scheduler");
|
||||
if (!eng) return -1;
|
||||
}
|
||||
|
@ -122,21 +121,24 @@ static int drop_privs(bool klogd, bool auditd) {
|
|||
if (!eng) return -1;
|
||||
}
|
||||
|
||||
std::unique_ptr<struct _cap_struct, int(*)(void *)> caps(cap_init(), cap_free);
|
||||
std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(),
|
||||
cap_free);
|
||||
if (cap_clear(caps.get()) < 0) return -1;
|
||||
cap_value_t cap_value[] = {
|
||||
CAP_SETGID, // must be first for below
|
||||
klogd ? CAP_SYSLOG : CAP_SETGID,
|
||||
auditd ? CAP_AUDIT_CONTROL : CAP_SETGID
|
||||
};
|
||||
if (cap_set_flag(caps.get(), CAP_PERMITTED,
|
||||
arraysize(cap_value), cap_value,
|
||||
CAP_SET) < 0) return -1;
|
||||
if (cap_set_flag(caps.get(), CAP_EFFECTIVE,
|
||||
arraysize(cap_value), cap_value,
|
||||
CAP_SET) < 0) return -1;
|
||||
cap_value_t cap_value[] = { CAP_SETGID, // must be first for below
|
||||
klogd ? CAP_SYSLOG : CAP_SETGID,
|
||||
auditd ? CAP_AUDIT_CONTROL : CAP_SETGID };
|
||||
if (cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(cap_value), cap_value,
|
||||
CAP_SET) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (cap_set_flag(caps.get(), CAP_EFFECTIVE, arraysize(cap_value), cap_value,
|
||||
CAP_SET) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (cap_set_proc(caps.get()) < 0) {
|
||||
android::prdebug("failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)", errno);
|
||||
android::prdebug(
|
||||
"failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)",
|
||||
errno);
|
||||
if (!eng) return -1;
|
||||
}
|
||||
|
||||
|
@ -157,8 +159,12 @@ static int drop_privs(bool klogd, bool auditd) {
|
|||
if (!eng) return -1;
|
||||
}
|
||||
|
||||
if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) return -1;
|
||||
if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) return -1;
|
||||
if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (cap_set_proc(caps.get()) < 0) {
|
||||
android::prdebug("failed to clear CAP_SETGID (%d)", errno);
|
||||
if (!eng) return -1;
|
||||
|
@ -168,8 +174,8 @@ static int drop_privs(bool klogd, bool auditd) {
|
|||
}
|
||||
|
||||
// Property helper
|
||||
static bool check_flag(const char *prop, const char *flag) {
|
||||
const char *cp = strcasestr(prop, flag);
|
||||
static bool check_flag(const char* prop, const char* flag) {
|
||||
const char* cp = strcasestr(prop, flag);
|
||||
if (!cp) {
|
||||
return false;
|
||||
}
|
||||
|
@ -183,7 +189,7 @@ static bool check_flag(const char *prop, const char *flag) {
|
|||
}
|
||||
|
||||
static int fdDmesg = -1;
|
||||
void android::prdebug(const char *fmt, ...) {
|
||||
void android::prdebug(const char* fmt, ...) {
|
||||
if (fdDmesg < 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -211,14 +217,13 @@ void android::prdebug(const char *fmt, ...) {
|
|||
|
||||
static sem_t uidName;
|
||||
static uid_t uid;
|
||||
static char *name;
|
||||
static char* name;
|
||||
|
||||
static sem_t reinit;
|
||||
static bool reinit_running = false;
|
||||
static LogBuffer *logBuf = NULL;
|
||||
|
||||
static bool package_list_parser_cb(pkg_info *info, void * /* userdata */) {
|
||||
static LogBuffer* logBuf = NULL;
|
||||
|
||||
static bool package_list_parser_cb(pkg_info* info, void* /* userdata */) {
|
||||
bool rc = true;
|
||||
if (info->uid == uid) {
|
||||
name = strdup(info->name);
|
||||
|
@ -230,7 +235,7 @@ static bool package_list_parser_cb(pkg_info *info, void * /* userdata */) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void *reinit_thread_start(void * /*obj*/) {
|
||||
static void* reinit_thread_start(void* /*obj*/) {
|
||||
prctl(PR_SET_NAME, "logd.daemon");
|
||||
set_sched_policy(0, SP_BACKGROUND);
|
||||
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
|
||||
|
@ -243,11 +248,10 @@ static void *reinit_thread_start(void * /*obj*/) {
|
|||
// If we are AID_ROOT, we should drop to AID_LOGD+AID_SYSTEM, if we are
|
||||
// anything else, we have even lesser privileges and accept our fate. Not
|
||||
// worth checking for error returns setting this thread's privileges.
|
||||
(void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
|
||||
(void)setuid(AID_LOGD); // access to everything logd, eg /data/misc/logd
|
||||
(void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
|
||||
(void)setuid(AID_LOGD); // access to everything logd, eg /data/misc/logd
|
||||
|
||||
while (reinit_running && !sem_wait(&reinit) && reinit_running) {
|
||||
|
||||
// uidToName Privileged Worker
|
||||
if (uid) {
|
||||
name = NULL;
|
||||
|
@ -261,8 +265,26 @@ static void *reinit_thread_start(void * /*obj*/) {
|
|||
|
||||
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' };
|
||||
'l',
|
||||
'o',
|
||||
'g',
|
||||
'd',
|
||||
'.',
|
||||
'd',
|
||||
'a',
|
||||
'e',
|
||||
'm',
|
||||
'o',
|
||||
'n',
|
||||
':',
|
||||
' ',
|
||||
'r',
|
||||
'e',
|
||||
'i',
|
||||
'n',
|
||||
'i',
|
||||
't',
|
||||
'\n' };
|
||||
write(fdDmesg, reinit_message, sizeof(reinit_message));
|
||||
}
|
||||
|
||||
|
@ -279,7 +301,7 @@ static void *reinit_thread_start(void * /*obj*/) {
|
|||
|
||||
static sem_t sem_name;
|
||||
|
||||
char *android::uidToName(uid_t u) {
|
||||
char* android::uidToName(uid_t u) {
|
||||
if (!u || !reinit_running) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -292,7 +314,7 @@ char *android::uidToName(uid_t u) {
|
|||
name = NULL;
|
||||
sem_post(&reinit);
|
||||
sem_wait(&uidName);
|
||||
char *ret = name;
|
||||
char* ret = name;
|
||||
|
||||
sem_post(&sem_name);
|
||||
|
||||
|
@ -305,7 +327,7 @@ void reinit_signal_handler(int /*signal*/) {
|
|||
sem_post(&reinit);
|
||||
}
|
||||
|
||||
static void readDmesg(LogAudit *al, LogKlog *kl) {
|
||||
static void readDmesg(LogAudit* al, LogKlog* kl) {
|
||||
if (!al && !kl) {
|
||||
return;
|
||||
}
|
||||
|
@ -315,8 +337,8 @@ static void readDmesg(LogAudit *al, LogKlog *kl) {
|
|||
return;
|
||||
}
|
||||
|
||||
size_t len = rc + 1024; // Margin for additional input race or trailing nul
|
||||
std::unique_ptr<char []> buf(new char[len]);
|
||||
size_t len = rc + 1024; // Margin for additional input race or trailing nul
|
||||
std::unique_ptr<char[]> buf(new char[len]);
|
||||
|
||||
rc = klogctl(KLOG_READ_ALL, buf.get(), len);
|
||||
if (rc <= 0) {
|
||||
|
@ -351,10 +373,8 @@ static int issueReinit() {
|
|||
(void)cap_set_proc(caps);
|
||||
(void)cap_free(caps);
|
||||
|
||||
int sock = TEMP_FAILURE_RETRY(
|
||||
socket_local_client("logd",
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_STREAM));
|
||||
int sock = TEMP_FAILURE_RETRY(socket_local_client(
|
||||
"logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
|
||||
if (sock < 0) return -errno;
|
||||
|
||||
static const char reinitStr[] = "reinit";
|
||||
|
@ -384,7 +404,7 @@ static int issueReinit() {
|
|||
// controlling the user space logger, and for any additional
|
||||
// logging plugins like auditd and restart control. Additional
|
||||
// transitory per-client threads are created for each reader.
|
||||
int main(int argc, char *argv[]) {
|
||||
int main(int argc, char* argv[]) {
|
||||
// issue reinit command. KISS argument parsing.
|
||||
if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
|
||||
return issueReinit();
|
||||
|
@ -397,17 +417,15 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
int fdPmesg = -1;
|
||||
bool klogd = __android_logger_property_get_bool("logd.kernel",
|
||||
BOOL_DEFAULT_TRUE |
|
||||
BOOL_DEFAULT_FLAG_PERSIST |
|
||||
BOOL_DEFAULT_FLAG_ENG |
|
||||
BOOL_DEFAULT_FLAG_SVELTE);
|
||||
bool klogd = __android_logger_property_get_bool(
|
||||
"logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
|
||||
BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
|
||||
if (klogd) {
|
||||
static const char proc_kmsg[] = "/proc/kmsg";
|
||||
fdPmesg = android_get_control_file(proc_kmsg);
|
||||
if (fdPmesg < 0) {
|
||||
fdPmesg = TEMP_FAILURE_RETRY(open(proc_kmsg,
|
||||
O_RDONLY | O_NDELAY | O_CLOEXEC));
|
||||
fdPmesg = TEMP_FAILURE_RETRY(
|
||||
open(proc_kmsg, O_RDONLY | O_NDELAY | O_CLOEXEC));
|
||||
}
|
||||
if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
|
||||
}
|
||||
|
@ -423,8 +441,7 @@ int main(int argc, char *argv[]) {
|
|||
memset(¶m, 0, sizeof(param));
|
||||
pthread_attr_setschedparam(&attr, ¶m);
|
||||
pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
|
||||
if (!pthread_attr_setdetachstate(&attr,
|
||||
PTHREAD_CREATE_DETACHED)) {
|
||||
if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
|
||||
pthread_t thread;
|
||||
reinit_running = true;
|
||||
if (pthread_create(&thread, &attr, reinit_thread_start, NULL)) {
|
||||
|
@ -434,8 +451,8 @@ int main(int argc, char *argv[]) {
|
|||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
|
||||
bool auditd = __android_logger_property_get_bool("ro.logd.auditd",
|
||||
BOOL_DEFAULT_TRUE);
|
||||
bool auditd =
|
||||
__android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE);
|
||||
if (drop_privs(klogd, auditd) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -444,7 +461,7 @@ int main(int argc, char *argv[]) {
|
|||
// socket connection, and as a reader lock on a range of log
|
||||
// entries.
|
||||
|
||||
LastLogTimes *times = new LastLogTimes();
|
||||
LastLogTimes* times = new LastLogTimes();
|
||||
|
||||
// LogBuffer is the object which is responsible for holding all
|
||||
// log entries.
|
||||
|
@ -453,18 +470,17 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
signal(SIGHUP, reinit_signal_handler);
|
||||
|
||||
if (__android_logger_property_get_bool("logd.statistics",
|
||||
BOOL_DEFAULT_TRUE |
|
||||
BOOL_DEFAULT_FLAG_PERSIST |
|
||||
BOOL_DEFAULT_FLAG_ENG |
|
||||
BOOL_DEFAULT_FLAG_SVELTE)) {
|
||||
if (__android_logger_property_get_bool(
|
||||
"logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
|
||||
BOOL_DEFAULT_FLAG_ENG |
|
||||
BOOL_DEFAULT_FLAG_SVELTE)) {
|
||||
logBuf->enableStatistics();
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (reader->startListener()) {
|
||||
exit(1);
|
||||
}
|
||||
|
@ -473,7 +489,7 @@ int main(int argc, char *argv[]) {
|
|||
// 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, reader);
|
||||
// Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
|
||||
if (swl->startListener(600)) {
|
||||
exit(1);
|
||||
|
@ -482,7 +498,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, reader, swl);
|
||||
if (cl->startListener()) {
|
||||
exit(1);
|
||||
}
|
||||
|
@ -491,17 +507,16 @@ int main(int argc, char *argv[]) {
|
|||
// initiated log messages. New log entries are added to LogBuffer
|
||||
// and LogReader is notified to send updates to connected clients.
|
||||
|
||||
LogAudit *al = NULL;
|
||||
LogAudit* al = NULL;
|
||||
if (auditd) {
|
||||
al = new LogAudit(logBuf, reader,
|
||||
__android_logger_property_get_bool(
|
||||
"ro.logd.auditd.dmesg",
|
||||
BOOL_DEFAULT_TRUE)
|
||||
? fdDmesg
|
||||
: -1);
|
||||
"ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
|
||||
? fdDmesg
|
||||
: -1);
|
||||
}
|
||||
|
||||
LogKlog *kl = NULL;
|
||||
LogKlog* kl = NULL;
|
||||
if (klogd) {
|
||||
kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
@ -36,13 +36,11 @@
|
|||
#include <selinux/selinux.h>
|
||||
#endif
|
||||
|
||||
#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_*
|
||||
#include "../LogReader.h" // pickup LOGD_SNDTIMEO
|
||||
#include "../LogReader.h" // pickup LOGD_SNDTIMEO
|
||||
#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_*
|
||||
|
||||
static void send_to_control(char* buf, size_t len)
|
||||
{
|
||||
int sock = socket_local_client("logd",
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
static void send_to_control(char* buf, size_t len) {
|
||||
int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_STREAM);
|
||||
if (sock >= 0) {
|
||||
if (write(sock, buf, strlen(buf) + 1) > 0) {
|
||||
|
@ -54,11 +52,7 @@ static void send_to_control(char* buf, size_t len)
|
|||
len -= ret;
|
||||
buf += ret;
|
||||
|
||||
struct pollfd p = {
|
||||
.fd = sock,
|
||||
.events = POLLIN,
|
||||
.revents = 0
|
||||
};
|
||||
struct pollfd p = {.fd = sock, .events = POLLIN, .revents = 0 };
|
||||
|
||||
ret = poll(&p, 1, 20);
|
||||
if ((ret <= 0) || !(p.revents & POLLIN)) {
|
||||
|
@ -73,25 +67,23 @@ static void send_to_control(char* buf, size_t len)
|
|||
/*
|
||||
* returns statistics
|
||||
*/
|
||||
static void my_android_logger_get_statistics(char *buf, size_t len)
|
||||
{
|
||||
static void my_android_logger_get_statistics(char* buf, size_t len) {
|
||||
snprintf(buf, len, "getStatistics 0 1 2 3 4");
|
||||
send_to_control(buf, len);
|
||||
}
|
||||
|
||||
static void alloc_statistics(char **buffer, size_t *length)
|
||||
{
|
||||
static void alloc_statistics(char** buffer, size_t* length) {
|
||||
size_t len = 8192;
|
||||
char *buf;
|
||||
char* buf;
|
||||
|
||||
for(int retry = 32; (retry >= 0); delete [] buf, --retry) {
|
||||
buf = new char [len];
|
||||
for (int retry = 32; (retry >= 0); delete[] buf, --retry) {
|
||||
buf = new char[len];
|
||||
my_android_logger_get_statistics(buf, len);
|
||||
|
||||
buf[len-1] = '\0';
|
||||
buf[len - 1] = '\0';
|
||||
size_t ret = atol(buf) + 1;
|
||||
if (ret < 4) {
|
||||
delete [] buf;
|
||||
delete[] buf;
|
||||
buf = NULL;
|
||||
break;
|
||||
}
|
||||
|
@ -100,14 +92,13 @@ static void alloc_statistics(char **buffer, size_t *length)
|
|||
if (check) {
|
||||
break;
|
||||
}
|
||||
len += len / 8; // allow for some slop
|
||||
len += len / 8; // allow for some slop
|
||||
}
|
||||
*buffer = buf;
|
||||
*length = len;
|
||||
}
|
||||
|
||||
static char *find_benchmark_spam(char *cp)
|
||||
{
|
||||
static char* find_benchmark_spam(char* cp) {
|
||||
// liblog_benchmarks has been run designed to SPAM. The signature of
|
||||
// a noisiest UID statistics is:
|
||||
//
|
||||
|
@ -115,7 +106,7 @@ static char *find_benchmark_spam(char *cp)
|
|||
// UID PACKAGE BYTES LINES
|
||||
// 0 root 54164 147569
|
||||
//
|
||||
char *benchmark = NULL;
|
||||
char* benchmark = NULL;
|
||||
do {
|
||||
static const char signature[] = "\n0 root ";
|
||||
|
||||
|
@ -129,7 +120,7 @@ static char *find_benchmark_spam(char *cp)
|
|||
}
|
||||
benchmark = cp;
|
||||
#ifdef DEBUG
|
||||
char *end = strstr(benchmark, "\n");
|
||||
char* end = strstr(benchmark, "\n");
|
||||
if (end == NULL) {
|
||||
end = benchmark + strlen(benchmark);
|
||||
}
|
||||
|
@ -145,8 +136,8 @@ static char *find_benchmark_spam(char *cp)
|
|||
}
|
||||
// optional +/- field?
|
||||
if ((*cp == '-') || (*cp == '+')) {
|
||||
while (isdigit(*++cp) ||
|
||||
(*cp == '.') || (*cp == '%') || (*cp == 'X')) {
|
||||
while (isdigit(*++cp) || (*cp == '.') || (*cp == '%') ||
|
||||
(*cp == 'X')) {
|
||||
;
|
||||
}
|
||||
while (isspace(*cp)) {
|
||||
|
@ -169,14 +160,14 @@ static char *find_benchmark_spam(char *cp)
|
|||
|
||||
TEST(logd, statistics) {
|
||||
size_t len;
|
||||
char *buf;
|
||||
char* buf;
|
||||
|
||||
alloc_statistics(&buf, &len);
|
||||
|
||||
ASSERT_TRUE(NULL != buf);
|
||||
|
||||
// remove trailing FF
|
||||
char *cp = buf + len - 1;
|
||||
char* cp = buf + len - 1;
|
||||
*cp = '\0';
|
||||
bool truncated = *--cp != '\f';
|
||||
if (!truncated) {
|
||||
|
@ -197,105 +188,107 @@ TEST(logd, statistics) {
|
|||
|
||||
EXPECT_EQ(0, truncated);
|
||||
|
||||
char *main_logs = strstr(cp, "\nChattiest UIDs in main ");
|
||||
char* main_logs = strstr(cp, "\nChattiest UIDs in main ");
|
||||
EXPECT_TRUE(NULL != main_logs);
|
||||
|
||||
char *radio_logs = strstr(cp, "\nChattiest UIDs in radio ");
|
||||
if (!radio_logs) GTEST_LOG_(INFO) << "Value of: NULL != radio_logs\n"
|
||||
"Actual: false\n"
|
||||
"Expected: false\n";
|
||||
char* radio_logs = strstr(cp, "\nChattiest UIDs in radio ");
|
||||
if (!radio_logs)
|
||||
GTEST_LOG_(INFO) << "Value of: NULL != radio_logs\n"
|
||||
"Actual: false\n"
|
||||
"Expected: false\n";
|
||||
|
||||
char *system_logs = strstr(cp, "\nChattiest UIDs in system ");
|
||||
char* system_logs = strstr(cp, "\nChattiest UIDs in system ");
|
||||
EXPECT_TRUE(NULL != system_logs);
|
||||
|
||||
char *events_logs = strstr(cp, "\nChattiest UIDs in events ");
|
||||
char* events_logs = strstr(cp, "\nChattiest UIDs in events ");
|
||||
EXPECT_TRUE(NULL != events_logs);
|
||||
|
||||
delete [] buf;
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
static void caught_signal(int /* signum */) { }
|
||||
static void caught_signal(int /* signum */) {
|
||||
}
|
||||
|
||||
static void dump_log_msg(const char *prefix,
|
||||
log_msg *msg, unsigned int version, int lid) {
|
||||
static void dump_log_msg(const char* prefix, log_msg* msg, unsigned int version,
|
||||
int lid) {
|
||||
std::cout << std::flush;
|
||||
std::cerr << std::flush;
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
switch(msg->entry.hdr_size) {
|
||||
case 0:
|
||||
version = 1;
|
||||
break;
|
||||
switch (msg->entry.hdr_size) {
|
||||
case 0:
|
||||
version = 1;
|
||||
break;
|
||||
|
||||
case sizeof(msg->entry_v2): /* PLUS case sizeof(msg->entry_v3): */
|
||||
if (version == 0) {
|
||||
version = (msg->entry_v3.lid < LOG_ID_MAX) ? 3 : 2;
|
||||
}
|
||||
break;
|
||||
case sizeof(msg->entry_v2): /* PLUS case sizeof(msg->entry_v3): */
|
||||
if (version == 0) {
|
||||
version = (msg->entry_v3.lid < LOG_ID_MAX) ? 3 : 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case sizeof(msg->entry_v4):
|
||||
if (version == 0) {
|
||||
version = 4;
|
||||
}
|
||||
break;
|
||||
case sizeof(msg->entry_v4):
|
||||
if (version == 0) {
|
||||
version = 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: v%u[%u] ", prefix, version, msg->len());
|
||||
if (version != 1) {
|
||||
fprintf(stderr, "hdr_size=%u ", msg->entry.hdr_size);
|
||||
}
|
||||
fprintf(stderr, "pid=%u tid=%u %u.%09u ",
|
||||
msg->entry.pid, msg->entry.tid, msg->entry.sec, msg->entry.nsec);
|
||||
switch(version) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
fprintf(stderr, "euid=%u ", msg->entry_v2.euid);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
lid = msg->entry.lid;
|
||||
break;
|
||||
fprintf(stderr, "pid=%u tid=%u %u.%09u ", msg->entry.pid, msg->entry.tid,
|
||||
msg->entry.sec, msg->entry.nsec);
|
||||
switch (version) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
fprintf(stderr, "euid=%u ", msg->entry_v2.euid);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
lid = msg->entry.lid;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(lid) {
|
||||
case 0:
|
||||
fprintf(stderr, "lid=main ");
|
||||
break;
|
||||
case 1:
|
||||
fprintf(stderr, "lid=radio ");
|
||||
break;
|
||||
case 2:
|
||||
fprintf(stderr, "lid=events ");
|
||||
break;
|
||||
case 3:
|
||||
fprintf(stderr, "lid=system ");
|
||||
break;
|
||||
case 4:
|
||||
fprintf(stderr, "lid=crash ");
|
||||
break;
|
||||
case 5:
|
||||
fprintf(stderr, "lid=security ");
|
||||
break;
|
||||
case 6:
|
||||
fprintf(stderr, "lid=kernel ");
|
||||
break;
|
||||
default:
|
||||
if (lid >= 0) {
|
||||
fprintf(stderr, "lid=%d ", lid);
|
||||
}
|
||||
switch (lid) {
|
||||
case 0:
|
||||
fprintf(stderr, "lid=main ");
|
||||
break;
|
||||
case 1:
|
||||
fprintf(stderr, "lid=radio ");
|
||||
break;
|
||||
case 2:
|
||||
fprintf(stderr, "lid=events ");
|
||||
break;
|
||||
case 3:
|
||||
fprintf(stderr, "lid=system ");
|
||||
break;
|
||||
case 4:
|
||||
fprintf(stderr, "lid=crash ");
|
||||
break;
|
||||
case 5:
|
||||
fprintf(stderr, "lid=security ");
|
||||
break;
|
||||
case 6:
|
||||
fprintf(stderr, "lid=kernel ");
|
||||
break;
|
||||
default:
|
||||
if (lid >= 0) {
|
||||
fprintf(stderr, "lid=%d ", lid);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int len = msg->entry.len;
|
||||
fprintf(stderr, "msg[%u]={", len);
|
||||
unsigned char *cp = reinterpret_cast<unsigned char *>(msg->msg());
|
||||
unsigned char* cp = reinterpret_cast<unsigned char*>(msg->msg());
|
||||
if (!cp) {
|
||||
static const unsigned char garbage[] = "<INVALID>";
|
||||
cp = const_cast<unsigned char *>(garbage);
|
||||
len = strlen(reinterpret_cast<const char *>(garbage));
|
||||
cp = const_cast<unsigned char*>(garbage);
|
||||
len = strlen(reinterpret_cast<const char*>(garbage));
|
||||
}
|
||||
while(len) {
|
||||
unsigned char *p = cp;
|
||||
while (len) {
|
||||
unsigned char* p = cp;
|
||||
while (*p && (((' ' <= *p) && (*p < 0x7F)) || (*p == '\n'))) {
|
||||
++p;
|
||||
}
|
||||
|
@ -330,8 +323,7 @@ TEST(logd, both) {
|
|||
bool user_logger_available = false;
|
||||
bool user_logger_content = false;
|
||||
|
||||
int fd = socket_local_client("logdr",
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_SEQPACKET);
|
||||
if (fd >= 0) {
|
||||
struct sigaction ignore, old_sigaction;
|
||||
|
@ -360,10 +352,9 @@ TEST(logd, both) {
|
|||
bool kernel_logger_available = false;
|
||||
bool kernel_logger_content = false;
|
||||
|
||||
static const char *loggers[] = {
|
||||
"/dev/log/main", "/dev/log_main",
|
||||
"/dev/log/radio", "/dev/log_radio",
|
||||
"/dev/log/events", "/dev/log_events",
|
||||
static const char* loggers[] = {
|
||||
"/dev/log/main", "/dev/log_main", "/dev/log/radio",
|
||||
"/dev/log_radio", "/dev/log/events", "/dev/log_events",
|
||||
"/dev/log/system", "/dev/log_system",
|
||||
};
|
||||
|
||||
|
@ -389,10 +380,9 @@ TEST(logd, both) {
|
|||
"user %-13s%s\n"
|
||||
"kernel %-13s%s\n"
|
||||
" status %-11s%s\n",
|
||||
(user_logger_available) ? yes : no,
|
||||
(user_logger_content) ? yes : no,
|
||||
(user_logger_available) ? yes : no, (user_logger_content) ? yes : no,
|
||||
(kernel_logger_available) ? yes : no,
|
||||
(kernel_logger_content) ? yes : no,
|
||||
(kernel_logger_content) ? yes : no,
|
||||
(user_logger_available && kernel_logger_available) ? "ERROR" : "ok",
|
||||
(user_logger_content && kernel_logger_content) ? "ERROR" : "ok");
|
||||
|
||||
|
@ -415,39 +405,37 @@ TEST(logd, both) {
|
|||
//
|
||||
TEST(logd, benchmark) {
|
||||
size_t len;
|
||||
char *buf;
|
||||
char* buf;
|
||||
|
||||
alloc_statistics(&buf, &len);
|
||||
bool benchmark_already_run = buf && find_benchmark_spam(buf);
|
||||
delete [] buf;
|
||||
delete[] buf;
|
||||
|
||||
if (benchmark_already_run) {
|
||||
fprintf(stderr, "WARNING: spam already present and too much history\n"
|
||||
" false OK for prune by worst UID check\n");
|
||||
fprintf(stderr,
|
||||
"WARNING: spam already present and too much history\n"
|
||||
" false OK for prune by worst UID check\n");
|
||||
}
|
||||
|
||||
FILE *fp;
|
||||
FILE* fp;
|
||||
|
||||
// Introduce some extreme spam for the worst UID filter
|
||||
ASSERT_TRUE(NULL != (fp = popen(
|
||||
"/data/nativetest/liblog-benchmarks/liblog-benchmarks"
|
||||
" BM_log_maximum_retry"
|
||||
" BM_log_maximum"
|
||||
" BM_clock_overhead"
|
||||
" BM_log_overhead"
|
||||
" BM_log_latency"
|
||||
" BM_log_delay",
|
||||
"r")));
|
||||
ASSERT_TRUE(
|
||||
NULL !=
|
||||
(fp = popen("/data/nativetest/liblog-benchmarks/liblog-benchmarks"
|
||||
" BM_log_maximum_retry"
|
||||
" BM_log_maximum"
|
||||
" BM_clock_overhead"
|
||||
" BM_log_overhead"
|
||||
" BM_log_latency"
|
||||
" BM_log_delay",
|
||||
"r")));
|
||||
|
||||
char buffer[5120];
|
||||
|
||||
static const char *benchmarks[] = {
|
||||
"BM_log_maximum_retry ",
|
||||
"BM_log_maximum ",
|
||||
"BM_clock_overhead ",
|
||||
"BM_log_overhead ",
|
||||
"BM_log_latency ",
|
||||
"BM_log_delay "
|
||||
static const char* benchmarks[] = {
|
||||
"BM_log_maximum_retry ", "BM_log_maximum ", "BM_clock_overhead ",
|
||||
"BM_log_overhead ", "BM_log_latency ", "BM_log_delay "
|
||||
};
|
||||
static const unsigned int log_maximum_retry = 0;
|
||||
static const unsigned int log_maximum = 1;
|
||||
|
@ -462,7 +450,7 @@ TEST(logd, benchmark) {
|
|||
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
for (unsigned i = 0; i < arraysize(ns); ++i) {
|
||||
char *cp = strstr(buffer, benchmarks[i]);
|
||||
char* cp = strstr(buffer, benchmarks[i]);
|
||||
if (!cp) {
|
||||
continue;
|
||||
}
|
||||
|
@ -480,17 +468,18 @@ TEST(logd, benchmark) {
|
|||
return;
|
||||
}
|
||||
|
||||
EXPECT_GE(200000UL, ns[log_maximum_retry]); // 104734 user
|
||||
EXPECT_GE(200000UL, ns[log_maximum_retry]); // 104734 user
|
||||
|
||||
EXPECT_GE(90000UL, ns[log_maximum]); // 46913 user
|
||||
EXPECT_GE(90000UL, ns[log_maximum]); // 46913 user
|
||||
|
||||
EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
|
||||
EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
|
||||
|
||||
EXPECT_GE(250000UL, ns[log_overhead]); // 126886 user
|
||||
EXPECT_GE(250000UL, ns[log_overhead]); // 126886 user
|
||||
|
||||
EXPECT_GE(10000000UL, ns[log_latency]); // 1453559 user space (background cgroup)
|
||||
EXPECT_GE(10000000UL,
|
||||
ns[log_latency]); // 1453559 user space (background cgroup)
|
||||
|
||||
EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
|
||||
EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
|
||||
|
||||
for (unsigned i = 0; i < arraysize(ns); ++i) {
|
||||
EXPECT_NE(0UL, ns[i]);
|
||||
|
@ -503,7 +492,7 @@ TEST(logd, benchmark) {
|
|||
|
||||
ASSERT_TRUE(NULL != buf);
|
||||
|
||||
char *benchmark_statistics_found = find_benchmark_spam(buf);
|
||||
char* benchmark_statistics_found = find_benchmark_spam(buf);
|
||||
ASSERT_TRUE(benchmark_statistics_found != NULL);
|
||||
|
||||
// Check how effective the SPAM filter is, parse out Now size.
|
||||
|
@ -512,13 +501,12 @@ TEST(logd, benchmark) {
|
|||
|
||||
unsigned long nowSpamSize = atol(benchmark_statistics_found);
|
||||
|
||||
delete [] buf;
|
||||
delete[] buf;
|
||||
|
||||
ASSERT_NE(0UL, nowSpamSize);
|
||||
|
||||
// Determine if we have the spam filter enabled
|
||||
int sock = socket_local_client("logd",
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_STREAM);
|
||||
|
||||
ASSERT_TRUE(sock >= 0);
|
||||
|
@ -528,26 +516,27 @@ TEST(logd, benchmark) {
|
|||
char buffer[80];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
read(sock, buffer, sizeof(buffer));
|
||||
char *cp = strchr(buffer, '\n');
|
||||
char* cp = strchr(buffer, '\n');
|
||||
if (!cp || (cp[1] != '~') || (cp[2] != '!')) {
|
||||
close(sock);
|
||||
fprintf(stderr,
|
||||
"WARNING: "
|
||||
"Logger has SPAM filtration turned off \"%s\"\n", buffer);
|
||||
"Logger has SPAM filtration turned off \"%s\"\n",
|
||||
buffer);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
int save_errno = errno;
|
||||
close(sock);
|
||||
FAIL() << "Can not send " << getPruneList << " to logger -- " << strerror(save_errno);
|
||||
FAIL() << "Can not send " << getPruneList << " to logger -- "
|
||||
<< strerror(save_errno);
|
||||
}
|
||||
|
||||
static const unsigned long expected_absolute_minimum_log_size = 65536UL;
|
||||
unsigned long totalSize = expected_absolute_minimum_log_size;
|
||||
static const char getSize[] = {
|
||||
'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ',
|
||||
LOG_ID_MAIN + '0', '\0'
|
||||
};
|
||||
static const char getSize[] = { 'g', 'e', 't', 'L', 'o', 'g',
|
||||
'S', 'i', 'z', 'e', ' ', LOG_ID_MAIN + '0',
|
||||
'\0' };
|
||||
if (write(sock, getSize, sizeof(getSize)) > 0) {
|
||||
char buffer[80];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
@ -556,21 +545,22 @@ TEST(logd, benchmark) {
|
|||
if (totalSize < expected_absolute_minimum_log_size) {
|
||||
fprintf(stderr,
|
||||
"WARNING: "
|
||||
"Logger had unexpected referenced size \"%s\"\n", buffer);
|
||||
"Logger had unexpected referenced size \"%s\"\n",
|
||||
buffer);
|
||||
totalSize = expected_absolute_minimum_log_size;
|
||||
}
|
||||
}
|
||||
close(sock);
|
||||
|
||||
// logd allows excursions to 110% of total size
|
||||
totalSize = (totalSize * 11 ) / 10;
|
||||
totalSize = (totalSize * 11) / 10;
|
||||
|
||||
// 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
|
||||
ASSERT_GT(totalSize, nowSpamSize * 2);
|
||||
}
|
||||
|
||||
// b/26447386 confirm fixed
|
||||
void timeout_negative(const char *command) {
|
||||
void timeout_negative(const char* command) {
|
||||
log_msg msg_wrap, msg_timeout;
|
||||
bool content_wrap = false, content_timeout = false, written = false;
|
||||
unsigned int alarm_wrap = 0, alarm_timeout = 0;
|
||||
|
@ -579,8 +569,7 @@ void timeout_negative(const char *command) {
|
|||
int i = 3;
|
||||
|
||||
while (--i) {
|
||||
int fd = socket_local_client("logdr",
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_SEQPACKET);
|
||||
ASSERT_LT(0, fd);
|
||||
|
||||
|
@ -609,15 +598,16 @@ void timeout_negative(const char *command) {
|
|||
|
||||
// alarm triggers at 133% of the --wrap time out
|
||||
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
|
||||
if (!content_timeout) { // make sure we hit dumpAndClose
|
||||
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
|
||||
if (!content_timeout) { // make sure we hit dumpAndClose
|
||||
content_timeout =
|
||||
recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
|
||||
}
|
||||
|
||||
alarm_timeout = alarm((old_alarm <= 0)
|
||||
? old_alarm
|
||||
: (old_alarm > (1 + 3 - alarm_wrap))
|
||||
? old_alarm - 3 + alarm_wrap
|
||||
: 2);
|
||||
alarm_timeout =
|
||||
alarm((old_alarm <= 0) ? old_alarm
|
||||
: (old_alarm > (1 + 3 - alarm_wrap))
|
||||
? old_alarm - 3 + alarm_wrap
|
||||
: 2);
|
||||
sigaction(SIGALRM, &old_sigaction, NULL);
|
||||
|
||||
close(fd);
|
||||
|
@ -647,7 +637,8 @@ TEST(logd, timeout_no_start) {
|
|||
}
|
||||
|
||||
TEST(logd, timeout_start_epoch) {
|
||||
timeout_negative("dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=0.000000000");
|
||||
timeout_negative(
|
||||
"dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=0.000000000");
|
||||
}
|
||||
|
||||
// b/26447386 refined behavior
|
||||
|
@ -672,18 +663,17 @@ TEST(logd, timeout) {
|
|||
// content providers being active during the test.
|
||||
int i = 5;
|
||||
log_time now(android_log_clockid());
|
||||
now.tv_sec -= 30; // reach back a moderate period of time
|
||||
now.tv_sec -= 30; // reach back a moderate period of time
|
||||
|
||||
while (--i) {
|
||||
int fd = socket_local_client("logdr",
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_SEQPACKET);
|
||||
EXPECT_LT(0, fd);
|
||||
if (fd < 0) _exit(fd);
|
||||
|
||||
std::string ask = android::base::StringPrintf(
|
||||
"dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%"
|
||||
PRIu32 ".%09" PRIu32,
|
||||
"dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%" PRIu32
|
||||
".%09" PRIu32,
|
||||
now.tv_sec, now.tv_nsec);
|
||||
|
||||
struct sigaction ignore, old_sigaction;
|
||||
|
@ -709,15 +699,16 @@ TEST(logd, timeout) {
|
|||
|
||||
// alarm triggers at 133% of the --wrap time out
|
||||
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
|
||||
if (!content_timeout) { // make sure we hit dumpAndClose
|
||||
content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
|
||||
if (!content_timeout) { // make sure we hit dumpAndClose
|
||||
content_timeout =
|
||||
recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
|
||||
}
|
||||
|
||||
alarm_timeout = alarm((old_alarm <= 0)
|
||||
? old_alarm
|
||||
: (old_alarm > (1 + 3 - alarm_wrap))
|
||||
? old_alarm - 3 + alarm_wrap
|
||||
: 2);
|
||||
alarm_timeout =
|
||||
alarm((old_alarm <= 0) ? old_alarm
|
||||
: (old_alarm > (1 + 3 - alarm_wrap))
|
||||
? old_alarm - 3 + alarm_wrap
|
||||
: 2);
|
||||
sigaction(SIGALRM, &old_sigaction, NULL);
|
||||
|
||||
close(fd);
|
||||
|
@ -742,7 +733,7 @@ TEST(logd, timeout) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
now.tv_sec -= 120; // inactive, reach further back!
|
||||
now.tv_sec -= 120; // inactive, reach further back!
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -755,8 +746,8 @@ TEST(logd, timeout) {
|
|||
}
|
||||
|
||||
if (content_wrap || !content_timeout) {
|
||||
fprintf(stderr, "now=%" PRIu32 ".%09" PRIu32 "\n",
|
||||
now.tv_sec, now.tv_nsec);
|
||||
fprintf(stderr, "now=%" PRIu32 ".%09" PRIu32 "\n", now.tv_sec,
|
||||
now.tv_nsec);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(written);
|
||||
|
@ -765,20 +756,22 @@ TEST(logd, timeout) {
|
|||
EXPECT_TRUE(content_timeout);
|
||||
EXPECT_NE(0U, alarm_timeout);
|
||||
|
||||
_exit(!written + content_wrap + alarm_wrap + !content_timeout + !alarm_timeout);
|
||||
_exit(!written + content_wrap + alarm_wrap + !content_timeout +
|
||||
!alarm_timeout);
|
||||
}
|
||||
|
||||
// b/27242723 confirmed fixed
|
||||
TEST(logd, SNDTIMEO) {
|
||||
static const unsigned sndtimeo = LOGD_SNDTIMEO; // <sigh> it has to be done!
|
||||
static const unsigned sndtimeo =
|
||||
LOGD_SNDTIMEO; // <sigh> it has to be done!
|
||||
static const unsigned sleep_time = sndtimeo + 3;
|
||||
static const unsigned alarm_time = sleep_time + 5;
|
||||
|
||||
int fd;
|
||||
|
||||
ASSERT_TRUE((fd = socket_local_client("logdr",
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_SEQPACKET)) > 0);
|
||||
ASSERT_TRUE(
|
||||
(fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_SEQPACKET)) > 0);
|
||||
|
||||
struct sigaction ignore, old_sigaction;
|
||||
memset(&ignore, 0, sizeof(ignore));
|
||||
|
@ -787,7 +780,7 @@ TEST(logd, SNDTIMEO) {
|
|||
sigaction(SIGALRM, &ignore, &old_sigaction);
|
||||
unsigned int old_alarm = alarm(alarm_time);
|
||||
|
||||
static const char ask[] = "stream lids=0,1,2,3,4,5,6"; // all sources
|
||||
static const char ask[] = "stream lids=0,1,2,3,4,5,6"; // all sources
|
||||
bool reader_requested = write(fd, ask, sizeof(ask)) == sizeof(ask);
|
||||
EXPECT_TRUE(reader_requested);
|
||||
|
||||
|
@ -799,7 +792,7 @@ TEST(logd, SNDTIMEO) {
|
|||
dump_log_msg("user", &msg, 3, -1);
|
||||
}
|
||||
|
||||
fprintf (stderr, "Sleep for >%d seconds logd SO_SNDTIMEO ...\n", sndtimeo);
|
||||
fprintf(stderr, "Sleep for >%d seconds logd SO_SNDTIMEO ...\n", sndtimeo);
|
||||
sleep(sleep_time);
|
||||
|
||||
// flush will block if we did not trigger. if it did, last entry returns 0
|
||||
|
@ -828,7 +821,7 @@ TEST(logd, getEventTag_list) {
|
|||
snprintf(buffer, sizeof(buffer), "getEventTag name=*");
|
||||
send_to_control(buffer, sizeof(buffer));
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
char *cp;
|
||||
char* cp;
|
||||
long ret = strtol(buffer, &cp, 10);
|
||||
EXPECT_GT(ret, 4096);
|
||||
#else
|
||||
|
@ -843,7 +836,7 @@ TEST(logd, getEventTag_42) {
|
|||
snprintf(buffer, sizeof(buffer), "getEventTag id=42");
|
||||
send_to_control(buffer, sizeof(buffer));
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
char *cp;
|
||||
char* cp;
|
||||
long ret = strtol(buffer, &cp, 10);
|
||||
EXPECT_GT(ret, 16);
|
||||
EXPECT_TRUE(strstr(buffer, "\t(to life the universe etc|3)") != NULL);
|
||||
|
@ -860,24 +853,23 @@ TEST(logd, getEventTag_newentry) {
|
|||
log_time now(CLOCK_MONOTONIC);
|
||||
char name[64];
|
||||
snprintf(name, sizeof(name), "a%" PRIu64, now.nsec());
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"getEventTag name=%s format=\"(new|1)\"", name);
|
||||
snprintf(buffer, sizeof(buffer), "getEventTag name=%s format=\"(new|1)\"",
|
||||
name);
|
||||
send_to_control(buffer, sizeof(buffer));
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
char *cp;
|
||||
char* cp;
|
||||
long ret = strtol(buffer, &cp, 10);
|
||||
EXPECT_GT(ret, 16);
|
||||
EXPECT_TRUE(strstr(buffer, "\t(new|1)") != NULL);
|
||||
EXPECT_TRUE(strstr(buffer, name) != NULL);
|
||||
// ToDo: also look for this in /data/misc/logd/event-log-tags and
|
||||
// /dev/event-log-tags.
|
||||
// ToDo: also look for this in /data/misc/logd/event-log-tags and
|
||||
// /dev/event-log-tags.
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int32_t get4LE(const char* src)
|
||||
{
|
||||
static inline int32_t get4LE(const char* src) {
|
||||
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
|
||||
}
|
||||
|
||||
|
@ -894,10 +886,12 @@ void __android_log_btwrite_multiple__helper(int count) {
|
|||
if (pid == 0) {
|
||||
// child
|
||||
for (int i = count; i; --i) {
|
||||
ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
|
||||
ASSERT_LT(
|
||||
0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
|
||||
usleep(100);
|
||||
}
|
||||
ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
|
||||
ASSERT_LT(0,
|
||||
__android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
|
||||
usleep(1000000);
|
||||
|
||||
_exit(0);
|
||||
|
@ -907,9 +901,11 @@ void __android_log_btwrite_multiple__helper(int count) {
|
|||
ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
|
||||
ASSERT_EQ(0, info.si_status);
|
||||
|
||||
struct logger_list *logger_list;
|
||||
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
|
||||
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)));
|
||||
struct logger_list* logger_list;
|
||||
ASSERT_TRUE(NULL !=
|
||||
(logger_list = android_logger_list_open(
|
||||
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
|
||||
0, pid)));
|
||||
|
||||
int expected_count = (count < 2) ? count : 2;
|
||||
int expected_chatty_count = (count <= 2) ? 0 : 1;
|
||||
|
@ -926,16 +922,17 @@ void __android_log_btwrite_multiple__helper(int count) {
|
|||
log_msg log_msg;
|
||||
if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
|
||||
|
||||
if ((log_msg.entry.pid != pid) ||
|
||||
(log_msg.entry.len < (4 + 1 + 8)) ||
|
||||
(log_msg.id() != LOG_ID_EVENTS)) continue;
|
||||
if ((log_msg.entry.pid != pid) || (log_msg.entry.len < (4 + 1 + 8)) ||
|
||||
(log_msg.id() != LOG_ID_EVENTS))
|
||||
continue;
|
||||
|
||||
char *eventData = log_msg.msg();
|
||||
char* eventData = log_msg.msg();
|
||||
if (!eventData) continue;
|
||||
|
||||
uint32_t tag = get4LE(eventData);
|
||||
|
||||
if ((eventData[4] == EVENT_TYPE_LONG) && (log_msg.entry.len == (4 + 1 + 8))) {
|
||||
if ((eventData[4] == EVENT_TYPE_LONG) &&
|
||||
(log_msg.entry.len == (4 + 1 + 8))) {
|
||||
if (tag != 0) continue;
|
||||
|
||||
log_time tx(eventData + 4 + 1);
|
||||
|
@ -949,7 +946,7 @@ void __android_log_btwrite_multiple__helper(int count) {
|
|||
++chatty_count;
|
||||
// int len = get4LE(eventData + 4 + 1);
|
||||
log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
|
||||
const char *cp;
|
||||
const char* cp;
|
||||
if ((cp = strstr(eventData + 4 + 1 + 4, " identical "))) {
|
||||
unsigned val = 0;
|
||||
sscanf(cp, " identical %u lines", &val);
|
||||
|
@ -1004,8 +1001,8 @@ static pid_t sepolicy_rate(unsigned rate, unsigned num) {
|
|||
int save_errno = errno;
|
||||
security_context_t context;
|
||||
getcon(&context);
|
||||
fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n",
|
||||
context, strerror(save_errno));
|
||||
fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n", context,
|
||||
strerror(save_errno));
|
||||
freecon(context);
|
||||
_exit(-1);
|
||||
// NOTREACHED
|
||||
|
@ -1052,22 +1049,20 @@ static int count_avc(pid_t pid) {
|
|||
|
||||
if (pid == 0) return count;
|
||||
|
||||
struct logger_list *logger_list;
|
||||
if (!(logger_list = android_logger_list_open(LOG_ID_EVENTS,
|
||||
ANDROID_LOG_RDONLY |
|
||||
ANDROID_LOG_NONBLOCK,
|
||||
0,
|
||||
pid))) return count;
|
||||
struct logger_list* logger_list;
|
||||
if (!(logger_list = android_logger_list_open(
|
||||
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)))
|
||||
return count;
|
||||
for (;;) {
|
||||
log_msg log_msg;
|
||||
|
||||
if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
|
||||
|
||||
if ((log_msg.entry.pid != pid) ||
|
||||
(log_msg.entry.len < (4 + 1 + 8)) ||
|
||||
(log_msg.id() != LOG_ID_EVENTS)) continue;
|
||||
if ((log_msg.entry.pid != pid) || (log_msg.entry.len < (4 + 1 + 8)) ||
|
||||
(log_msg.id() != LOG_ID_EVENTS))
|
||||
continue;
|
||||
|
||||
char *eventData = log_msg.msg();
|
||||
char* eventData = log_msg.msg();
|
||||
if (!eventData) continue;
|
||||
|
||||
uint32_t tag = get4LE(eventData);
|
||||
|
@ -1077,7 +1072,7 @@ static int count_avc(pid_t pid) {
|
|||
|
||||
// int len = get4LE(eventData + 4 + 1);
|
||||
log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
|
||||
const char *cp = strstr(eventData + 4 + 1 + 4, "): avc: denied");
|
||||
const char* cp = strstr(eventData + 4 + 1 + 4, "): avc: denied");
|
||||
if (!cp) continue;
|
||||
|
||||
++count;
|
||||
|
@ -1103,10 +1098,11 @@ TEST(logd, sepolicy_rate_limiter_maximum) {
|
|||
TEST(logd, sepolicy_rate_limiter_sub_burst) {
|
||||
#ifdef __ANDROID__
|
||||
// maximum period below half way between sustainable and burst rate.
|
||||
static const int threshold = ((AUDIT_RATE_LIMIT_BURST_DURATION *
|
||||
(AUDIT_RATE_LIMIT_DEFAULT +
|
||||
AUDIT_RATE_LIMIT_MAX)) +
|
||||
1) / 2;
|
||||
static const int threshold =
|
||||
((AUDIT_RATE_LIMIT_BURST_DURATION *
|
||||
(AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
|
||||
1) /
|
||||
2;
|
||||
static const int rate = (threshold / AUDIT_RATE_LIMIT_BURST_DURATION) - 1;
|
||||
static const int duration = AUDIT_RATE_LIMIT_BURST_DURATION;
|
||||
EXPECT_EQ(rate * duration, count_avc(sepolicy_rate(rate, rate * duration)));
|
||||
|
@ -1118,24 +1114,25 @@ TEST(logd, sepolicy_rate_limiter_sub_burst) {
|
|||
TEST(logd, sepolicy_rate_limiter_spam) {
|
||||
#ifdef __ANDROID__
|
||||
// maximum period of double the maximum burst rate
|
||||
static const int threshold = ((AUDIT_RATE_LIMIT_BURST_DURATION *
|
||||
(AUDIT_RATE_LIMIT_DEFAULT +
|
||||
AUDIT_RATE_LIMIT_MAX)) +
|
||||
1) / 2;
|
||||
static const int threshold =
|
||||
((AUDIT_RATE_LIMIT_BURST_DURATION *
|
||||
(AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
|
||||
1) /
|
||||
2;
|
||||
static const int rate = AUDIT_RATE_LIMIT_DEFAULT * 2;
|
||||
static const int duration = threshold / AUDIT_RATE_LIMIT_DEFAULT;
|
||||
EXPECT_GE(((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) /
|
||||
100, // +15% margin
|
||||
count_avc(sepolicy_rate(rate, rate * duration)));
|
||||
EXPECT_GE(
|
||||
((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) / 100, // +15% margin
|
||||
count_avc(sepolicy_rate(rate, rate * duration)));
|
||||
// give logd another 3 seconds to react to the burst before checking
|
||||
sepolicy_rate(rate, rate * 3);
|
||||
// maximum period at double the maximum burst rate (spam filter kicked in)
|
||||
EXPECT_GE(threshold * 2,
|
||||
count_avc(sepolicy_rate(rate,
|
||||
rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
|
||||
EXPECT_GE(
|
||||
threshold * 2,
|
||||
count_avc(sepolicy_rate(rate, rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
|
||||
// cool down, and check unspammy rate still works
|
||||
sleep(2);
|
||||
EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ to be lost
|
||||
EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ to be lost
|
||||
count_avc(sepolicy_rate(1, AUDIT_RATE_LIMIT_BURST_DURATION)));
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||
|
|
Loading…
Reference in a new issue