Merge "logcat: filter based on UID"
This commit is contained in:
commit
71de690f60
2 changed files with 106 additions and 0 deletions
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
|
@ -358,6 +359,10 @@ Filtering:
|
|||
-T '<time>' Print the lines since specified time (not imply -d).
|
||||
count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
|
||||
'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format.
|
||||
--uid=<uids> Only display log messages from UIDs present in the comma separate list
|
||||
<uids>. No name look-up is performed, so UIDs must be provided as
|
||||
numeric values. This option is only useful for the 'root', 'log', and
|
||||
'system' users since only those users can view logs from other users.
|
||||
)init");
|
||||
|
||||
fprintf(stderr, "\nfilterspecs are a series of \n"
|
||||
|
|
@ -535,6 +540,7 @@ int Logcat::Run(int argc, char** argv) {
|
|||
size_t pid = 0;
|
||||
bool got_t = false;
|
||||
unsigned id_mask = 0;
|
||||
std::set<uid_t> uids;
|
||||
|
||||
if (argc == 2 && !strcmp(argv[1], "--help")) {
|
||||
show_help();
|
||||
|
|
@ -554,6 +560,7 @@ int Logcat::Run(int argc, char** argv) {
|
|||
static const char id_str[] = "id";
|
||||
static const char wrap_str[] = "wrap";
|
||||
static const char print_str[] = "print";
|
||||
static const char uid_str[] = "uid";
|
||||
// clang-format off
|
||||
static const struct option long_options[] = {
|
||||
{ "binary", no_argument, nullptr, 'B' },
|
||||
|
|
@ -581,6 +588,7 @@ int Logcat::Run(int argc, char** argv) {
|
|||
{ "statistics", no_argument, nullptr, 'S' },
|
||||
// hidden and undocumented reserved alias for -t
|
||||
{ "tail", required_argument, nullptr, 't' },
|
||||
{ uid_str, required_argument, nullptr, 0 },
|
||||
// support, but ignore and do not document, the optional argument
|
||||
{ wrap_str, optional_argument, nullptr, 0 },
|
||||
{ nullptr, 0, nullptr, 0 }
|
||||
|
|
@ -631,6 +639,17 @@ int Logcat::Run(int argc, char** argv) {
|
|||
if (long_options[option_index].name == id_str) {
|
||||
setId = (optarg && optarg[0]) ? optarg : nullptr;
|
||||
}
|
||||
if (long_options[option_index].name == uid_str) {
|
||||
auto uid_strings = Split(optarg, delimiters);
|
||||
for (const auto& uid_string : uid_strings) {
|
||||
uid_t uid;
|
||||
if (!ParseUint(uid_string, &uid)) {
|
||||
error(EXIT_FAILURE, 0, "Unable to parse UID '%s'", uid_string.c_str());
|
||||
}
|
||||
uids.emplace(uid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
|
@ -1164,6 +1183,10 @@ If you have enabled significant logging, look into using the -G option to increa
|
|||
LOG_ID_MAX);
|
||||
}
|
||||
|
||||
if (!uids.empty() && uids.count(log_msg.entry.uid) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PrintDividers(log_msg.id(), printDividers);
|
||||
|
||||
if (print_binary_) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -28,10 +29,12 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/macros.h>
|
||||
#include <android-base/parseint.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
|
@ -1748,3 +1751,83 @@ TEST(logcat, invalid_buffer) {
|
|||
|
||||
ASSERT_TRUE(android::base::StartsWith(output, "unknown buffer foo\n"));
|
||||
}
|
||||
|
||||
static void SniffUid(const std::string& line, uid_t& uid) {
|
||||
auto uid_regex = std::regex{"\\S+\\s+\\S+\\s+(\\S+).*"};
|
||||
|
||||
auto trimmed_line = android::base::Trim(line);
|
||||
|
||||
std::smatch match_results;
|
||||
ASSERT_TRUE(std::regex_match(trimmed_line, match_results, uid_regex))
|
||||
<< "Unable to find UID in line '" << trimmed_line << "'";
|
||||
auto uid_string = match_results[1];
|
||||
if (!android::base::ParseUint(uid_string, &uid)) {
|
||||
auto pwd = getpwnam(uid_string.str().c_str());
|
||||
ASSERT_NE(nullptr, pwd) << "uid '" << uid_string << "' in line '" << trimmed_line << "'";
|
||||
uid = pwd->pw_uid;
|
||||
}
|
||||
}
|
||||
|
||||
static void UidsInLog(std::optional<std::vector<uid_t>> filter_uid, std::map<uid_t, size_t>& uids) {
|
||||
std::string command;
|
||||
if (filter_uid) {
|
||||
std::vector<std::string> uid_strings;
|
||||
for (const auto& uid : *filter_uid) {
|
||||
uid_strings.emplace_back(std::to_string(uid));
|
||||
}
|
||||
command = android::base::StringPrintf(logcat_executable
|
||||
" -v uid -b all -d 2>/dev/null --uid=%s",
|
||||
android::base::Join(uid_strings, ",").c_str());
|
||||
} else {
|
||||
command = logcat_executable " -v uid -b all -d 2>/dev/null";
|
||||
}
|
||||
auto fp = std::unique_ptr<FILE, decltype(&pclose)>(popen(command.c_str(), "r"), pclose);
|
||||
ASSERT_NE(nullptr, fp);
|
||||
|
||||
char buffer[BIG_BUFFER];
|
||||
while (fgets(buffer, sizeof(buffer), fp.get())) {
|
||||
// Ignore dividers, e.g. '--------- beginning of radio'
|
||||
if (android::base::StartsWith(buffer, "---------")) {
|
||||
continue;
|
||||
}
|
||||
uid_t uid;
|
||||
SniffUid(buffer, uid);
|
||||
uids[uid]++;
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<uid_t> TopTwoInMap(const std::map<uid_t, size_t>& uids) {
|
||||
std::pair<uid_t, size_t> top = {0, 0};
|
||||
std::pair<uid_t, size_t> second = {0, 0};
|
||||
for (const auto& [uid, count] : uids) {
|
||||
if (count > top.second) {
|
||||
top = second;
|
||||
top = {uid, count};
|
||||
} else if (count > second.second) {
|
||||
second = {uid, count};
|
||||
}
|
||||
}
|
||||
return {top.first, second.first};
|
||||
}
|
||||
|
||||
TEST(logcat, uid_filter) {
|
||||
std::map<uid_t, size_t> uids;
|
||||
UidsInLog({}, uids);
|
||||
|
||||
ASSERT_GT(uids.size(), 2U);
|
||||
auto top_uids = TopTwoInMap(uids);
|
||||
|
||||
// Test filtering with --uid=<top uid>
|
||||
std::map<uid_t, size_t> uids_only_top;
|
||||
std::vector<uid_t> top_uid = {top_uids[0]};
|
||||
UidsInLog(top_uid, uids_only_top);
|
||||
|
||||
EXPECT_EQ(1U, uids_only_top.size());
|
||||
|
||||
// Test filtering with --uid=<top uid>,<2nd top uid>
|
||||
std::map<uid_t, size_t> uids_only_top2;
|
||||
std::vector<uid_t> top2_uids = {top_uids[0], top_uids[1]};
|
||||
UidsInLog(top2_uids, uids_only_top2);
|
||||
|
||||
EXPECT_EQ(2U, uids_only_top2.size());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue