Merge "logd: add missing static to CompressionEngine"
diff --git a/adb/client/transport_mdns.cpp b/adb/client/transport_mdns.cpp
index 9db2453..9611212 100644
--- a/adb/client/transport_mdns.cpp
+++ b/adb/client/transport_mdns.cpp
@@ -680,6 +680,13 @@
std::optional<MdnsInfo> mdns_get_connect_service_info(std::string_view name) {
CHECK(!name.empty());
+ // only adb server creates these registries
+ if (!ResolvedService::sAdbTransportServices && !ResolvedService::sAdbSecureConnectServices) {
+ return std::nullopt;
+ }
+ CHECK(ResolvedService::sAdbTransportServices);
+ CHECK(ResolvedService::sAdbSecureConnectServices);
+
auto mdns_instance = mdns::mdns_parse_instance_name(name);
if (!mdns_instance.has_value()) {
D("Failed to parse mDNS name [%s]", name.data());
diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h
index a7687af..4806b08 100644
--- a/libmodprobe/include/modprobe/modprobe.h
+++ b/libmodprobe/include/modprobe/modprobe.h
@@ -36,7 +36,7 @@
std::vector<std::string>* post_dependencies);
void ResetModuleCount() { module_count_ = 0; }
int GetModuleCount() { return module_count_; }
- void EnableBlacklist(bool enable);
+ void EnableBlocklist(bool enable);
void EnableVerbose(bool enable);
private:
@@ -55,7 +55,7 @@
bool ParseSoftdepCallback(const std::vector<std::string>& args);
bool ParseLoadCallback(const std::vector<std::string>& args);
bool ParseOptionsCallback(const std::vector<std::string>& args);
- bool ParseBlacklistCallback(const std::vector<std::string>& args);
+ bool ParseBlocklistCallback(const std::vector<std::string>& args);
void ParseKernelCmdlineOptions();
void ParseCfg(const std::string& cfg, std::function<bool(const std::vector<std::string>&)> f);
@@ -65,8 +65,8 @@
std::vector<std::pair<std::string, std::string>> module_post_softdep_;
std::vector<std::string> module_load_;
std::unordered_map<std::string, std::string> module_options_;
- std::set<std::string> module_blacklist_;
+ std::set<std::string> module_blocklist_;
std::unordered_set<std::string> module_loaded_;
int module_count_ = 0;
- bool blacklist_enabled = false;
+ bool blocklist_enabled = false;
};
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index d193796..5a6ae8b 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -194,17 +194,17 @@
return true;
}
-bool Modprobe::ParseBlacklistCallback(const std::vector<std::string>& args) {
+bool Modprobe::ParseBlocklistCallback(const std::vector<std::string>& args) {
auto it = args.begin();
const std::string& type = *it++;
- if (type != "blacklist") {
- LOG(ERROR) << "non-blacklist line encountered in modules.blacklist";
+ if (type != "blocklist") {
+ LOG(ERROR) << "non-blocklist line encountered in modules.blocklist";
return false;
}
if (args.size() != 2) {
- LOG(ERROR) << "lines in modules.blacklist must have exactly 2 entries, not " << args.size();
+ LOG(ERROR) << "lines in modules.blocklist must have exactly 2 entries, not " << args.size();
return false;
}
@@ -214,7 +214,7 @@
if (canonical_name.empty()) {
return false;
}
- this->module_blacklist_.emplace(canonical_name);
+ this->module_blocklist_.emplace(canonical_name);
return true;
}
@@ -331,16 +331,16 @@
auto options_callback = std::bind(&Modprobe::ParseOptionsCallback, this, _1);
ParseCfg(base_path + "/modules.options", options_callback);
- auto blacklist_callback = std::bind(&Modprobe::ParseBlacklistCallback, this, _1);
- ParseCfg(base_path + "/modules.blacklist", blacklist_callback);
+ auto blocklist_callback = std::bind(&Modprobe::ParseBlocklistCallback, this, _1);
+ ParseCfg(base_path + "/modules.blocklist", blocklist_callback);
}
ParseKernelCmdlineOptions();
android::base::SetMinimumLogSeverity(android::base::INFO);
}
-void Modprobe::EnableBlacklist(bool enable) {
- blacklist_enabled = enable;
+void Modprobe::EnableBlocklist(bool enable) {
+ blocklist_enabled = enable;
}
void Modprobe::EnableVerbose(bool enable) {
diff --git a/libmodprobe/libmodprobe_ext.cpp b/libmodprobe/libmodprobe_ext.cpp
index 6589708..fb1f5e7 100644
--- a/libmodprobe/libmodprobe_ext.cpp
+++ b/libmodprobe/libmodprobe_ext.cpp
@@ -35,7 +35,7 @@
android::base::unique_fd fd(
TEMP_FAILURE_RETRY(open(path_name.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
if (fd == -1) {
- LOG(ERROR) << "Could not open module '" << path_name << "'";
+ PLOG(ERROR) << "Could not open module '" << path_name << "'";
return false;
}
@@ -49,7 +49,7 @@
options = options + " " + parameters;
}
- LOG(INFO) << "Loading module " << path_name << " with args \"" << options << "\"";
+ LOG(INFO) << "Loading module " << path_name << " with args '" << options << "'";
int ret = syscall(__NR_finit_module, fd.get(), options.c_str(), 0);
if (ret != 0) {
if (errno == EEXIST) {
@@ -57,7 +57,7 @@
module_loaded_.emplace(canonical_name);
return true;
}
- LOG(ERROR) << "Failed to insmod '" << path_name << "' with args '" << options << "'";
+ PLOG(ERROR) << "Failed to insmod '" << path_name << "' with args '" << options << "'";
return false;
}
@@ -80,8 +80,8 @@
bool Modprobe::ModuleExists(const std::string& module_name) {
struct stat fileStat;
- if (blacklist_enabled && module_blacklist_.count(module_name)) {
- LOG(INFO) << "module " << module_name << " is blacklisted";
+ if (blocklist_enabled && module_blocklist_.count(module_name)) {
+ LOG(INFO) << "module " << module_name << " is blocklisted";
return false;
}
auto deps = GetDependencies(module_name);
diff --git a/libmodprobe/libmodprobe_ext_test.cpp b/libmodprobe/libmodprobe_ext_test.cpp
index 9ee5ba7..e79bfaf 100644
--- a/libmodprobe/libmodprobe_ext_test.cpp
+++ b/libmodprobe/libmodprobe_ext_test.cpp
@@ -72,7 +72,7 @@
bool Modprobe::ModuleExists(const std::string& module_name) {
auto deps = GetDependencies(module_name);
- if (blacklist_enabled && module_blacklist_.count(module_name)) {
+ if (blocklist_enabled && module_blocklist_.count(module_name)) {
return false;
}
if (deps.empty()) {
diff --git a/libmodprobe/libmodprobe_test.cpp b/libmodprobe/libmodprobe_test.cpp
index eea0abd..5919c49 100644
--- a/libmodprobe/libmodprobe_test.cpp
+++ b/libmodprobe/libmodprobe_test.cpp
@@ -113,9 +113,9 @@
"options test9.ko param_x=1 param_y=2 param_z=3\n"
"options test100.ko param_1=1\n";
- const std::string modules_blacklist =
- "blacklist test9.ko\n"
- "blacklist test3.ko\n";
+ const std::string modules_blocklist =
+ "blocklist test9.ko\n"
+ "blocklist test3.ko\n";
const std::string modules_load =
"test4.ko\n"
@@ -139,7 +139,7 @@
0600, getuid(), getgid()));
ASSERT_TRUE(android::base::WriteStringToFile(modules_load, dir_path + "/modules.load", 0600,
getuid(), getgid()));
- ASSERT_TRUE(android::base::WriteStringToFile(modules_blacklist, dir_path + "/modules.blacklist",
+ ASSERT_TRUE(android::base::WriteStringToFile(modules_blocklist, dir_path + "/modules.blocklist",
0600, getuid(), getgid()));
for (auto i = test_modules.begin(); i != test_modules.end(); ++i) {
@@ -176,6 +176,6 @@
EXPECT_TRUE(modules_loaded == expected_after_remove);
- m.EnableBlacklist(true);
+ m.EnableBlocklist(true);
EXPECT_FALSE(m.LoadWithAliases("test4", true));
}
diff --git a/llkd/README.md b/llkd/README.md
index 191f988..6f92f14 100644
--- a/llkd/README.md
+++ b/llkd/README.md
@@ -1,199 +1,237 @@
-Android Live-LocK Daemon
-========================
+<!--
+Project: /_project.yaml
+Book: /_book.yaml
-Introduction
-------------
+{% include "_versions.html" %}
+-->
-Android Live-LocK Daemon (llkd) is used to catch kernel deadlocks and mitigate.
+<!--
+ Copyright 2020 The Android Open Source Project
-Code is structured to allow integration into another service as either as part
-of the main loop, or spun off as a thread should that be necessary. A default
-standalone implementation is provided by llkd component.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
-The 'C' interface from libllkd component is thus:
+ http://www.apache.org/licenses/LICENSE-2.0
- #include "llkd.h"
- bool llkInit(const char* threadname) /* return true if enabled */
- unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
-If a threadname is provided, a thread will be automatically spawned, otherwise
-caller must call llkCheckMilliseconds in its main loop. Function will return
-the period of time before the next expected call to this handler.
+# Android Live-LocK Daemon (llkd)
-Operations
-----------
+Android 10 <!-- {{ androidQVersionNumber }} --> includes the Android Live-LocK Daemon
+(`llkd`), which is designed to catch and mitigate kernel deadlocks. The `llkd`
+component provides a default standalone implementation, but you can
+alternatively integrate the `llkd` code into another service, either as part of
+the main loop or as a separate thread.
-There are two detection scenarios. Persistent D or Z state, and persistent
+## Detection scenarios <!-- {:#detection-scenarios} -->
+
+The `llkd` has two detection scenarios: Persistent D or Z state, and persistent
stack signature.
-If a thread is in D or Z state with no forward progress for longer than
-ro.llk.timeout_ms, or ro.llk.[D|Z].timeout_ms, kill the process or parent
-process respectively. If another scan shows the same process continues to
-exist, then have a confirmed live-lock condition and need to panic. Panic
-the kernel in a manner to provide the greatest bugreporting details as to the
-condition. Add a alarm self watchdog should llkd ever get locked up that is
-double the expected time to flow through the mainloop. Sampling is every
-ro.llk_sample_ms.
+### Persistent D or Z state <!-- {:#persistent-d-or-z-state} -->
-For usedebug releases only, persistent stack signature checking is enabled.
-If a thread in any state but Z, has a persistent listed ro.llk.stack kernel
-symbol always being reported, even if there is forward scheduling progress, for
-longer than ro.llk.timeout_ms, or ro.llk.stack.timeout_ms, then issue a kill
-to the process. If another scan shows the same process continues to exist,
-then have a confirmed live-lock condition and need to panic. There is no
-ABA detection since forward scheduling progress is allowed, thus the condition
-for the symbols are:
+If a thread is in D (uninterruptible sleep) or Z (zombie) state with no forward
+progress for longer than `ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms`, the
+`llkd` kills the process (or parent process). If a subsequent scan shows the
+same process continues to exist, the `llkd` confirms a live-lock condition and
+panics the kernel in a manner that provides the most detailed bug report for the
+condition.
-- Check is looking for " __symbol__+0x" or " __symbol__.cfi+0x" in
- /proc/__pid__/stack.
-- The __symbol__ should be rare and short lived enough that on a typical
- system the function is seen at most only once in a sample over the timeout
- period of ro.llk.stack.timeout_ms, samples occur every ro.llk.check_ms. This
- can be the only way to prevent a false trigger as there is no ABA protection.
-- Persistent continuously when the live lock condition exists.
-- Should be just below the function that is calling the lock that could
- contend, because if the lock is below or in the symbol function, the
- symbol will show in all affected processes, not just the one that
- caused the lockup.
+The `llkd` includes a self watchdog that alarms if `llkd` locks up; watchdog is
+double the expected time to flow through the mainloop and sampling is every
+`ro.llk_sample_ms`.
-Default will not monitor init, or [kthreadd] and all that [kthreadd] spawns.
-This reduces the effectiveness of llkd by limiting its coverage. If there is
-value in covering [kthreadd] spawned threads, the requirement will be that
-the drivers not remain in a persistent 'D' state, or that they have mechanisms
-to recover the thread should it be killed externally (this is good driver
-coding hygiene, a common request to add such to publicly reviewed kernel.org
-maintained drivers). For instance use wait_event_interruptible() instead of
-wait_event(). The blacklists can be adjusted accordingly if these
-conditions are met to cover kernel components. For the stack symbol checking,
-there is an additional process blacklist so that we do not incide sepolicy
-violations on services that block ptrace operations.
+### Persistent stack signature <!-- {:#persistent-stack-signature} -->
-An accompanying gTest set have been added, and will setup a persistent D or Z
-process, with and without forward progress, but not in a live-lock state
-because that would require a buggy kernel, or a module or kernel modification
-to stimulate. The test will check that llkd will mitigate first by killing
-the appropriate process. D state is setup by vfork() waiting for exec() in
-child process. Z state is setup by fork() and an un-waited for child process.
-Should be noted that both of these conditions should never happen on Android
-on purpose, and llkd effectively sweeps up processes that create these
-conditions. If the test can, it will reconfigure llkd to expedite the test
-duration by adjusting the ro.llk.* Android properties. Tests run the D state
-with some scheduling progress to ensure that ABA checking prevents false
-triggers. If 100% reliable ABA on platform, then ro.llk.killtest can be
-set to false; however this will result in some of the unit tests to panic
-kernel instead of deal with more graceful kill operation.
+For userdebug releases, the `llkd` can detect kernel live-locks using persistent
+stack signature checking. If a thread in any state except Z has a persistent
+listed `ro.llk.stack` kernel symbol that is reported for longer than
+`ro.llk.timeout_ms` or `ro.llk.stack.timeout_ms`, the `llkd` kills the process
+(even if there is forward scheduling progress). If a subsequent scan shows the
+same process continues to exist, the `llkd` confirms a live-lock condition and
+panics the kernel in a manner that provides the most detailed bug report for the
+condition.
-Android Properties
-------------------
+Note: Because forward scheduling progress is allowed, the `llkd` does not
+perform [ABA detection](https://en.wikipedia.org/wiki/ABA_problem){:.external}.
-The following are the Android Properties llkd respond to.
-*prop*_ms named properties are in milliseconds.
-Properties that use comma (*,*) separator for lists, use a leading separator to
-preserve default and add or subtract entries with (*optional*) plus (*+*) and
-minus (*-*) prefixes respectively.
-For these lists, the string "*false*" is synonymous with an *empty* list,
-and *blank* or *missing* resorts to the specified *default* value.
+The `lldk` check persists continuously when the live lock condition exists and
+looks for the composed strings `" symbol+0x"` or `" symbol.cfi+0x"` in the
+`/proc/pid/stack` file on Linux. The list of symbols is in `ro.llk.stack` and
+defaults to the comma-separated list of
+"`cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable`".
-#### ro.config.low_ram
-device is configured with limited memory.
+Symbols should be rare and short-lived enough that on a typical system the
+function is seen only once in a sample over the timeout period of
+`ro.llk.stack.timeout_ms` (samples occur every `ro.llk.check_ms`). Due to lack
+of ABA protection, this is the only way to prevent a false trigger. The symbol
+function must appear below the function calling the lock that could contend. If
+the lock is below or in the symbol function, the symbol appears in all affected
+processes, not just the one that caused the lockup.
-#### ro.debuggable
-device is configured for userdebug or eng build.
+## Coverage <!-- {:#coverage} -->
-#### ro.llk.sysrq_t
-default not ro.config.low_ram, or ro.debuggable if property is "eng".
-if true do sysrq t (dump all threads).
+The default implementation of `llkd` does not monitor `init`, `[kthreadd]`, or
+`[kthreadd]` spawns. For the `llkd` to cover `[kthreadd]`-spawned threads:
-#### ro.llk.enable
-default false, allow live-lock daemon to be enabled.
+* Drivers must not remain in a persistent D state,
-#### llk.enable
-default ro.llk.enable, and evaluated for eng.
+OR
-#### ro.khungtask.enable
-default false, allow [khungtask] daemon to be enabled.
+* Drivers must have mechanisms to recover the thread should it be killed
+ externally. For example, use `wait_event_interruptible()` instead of
+ `wait_event()`.
-#### khungtask.enable
-default ro.khungtask.enable and evaluated for eng.
+If one of the above conditions is met, the `llkd` ignorelist can be adjusted to
+cover kernel components. Stack symbol checking involves an additional process
+ignore list to prevent sepolicy violations on services that block `ptrace`
+operations.
-#### ro.llk.mlockall
-default false, enable call to mlockall().
+## Android properties <!-- {:#android-properties} -->
-#### ro.khungtask.timeout
-default value 12 minutes, [khungtask] maximum timelimit.
+The `llkd` responds to several Android properties (listed below).
-#### ro.llk.timeout_ms
-default 10 minutes, D or Z maximum timelimit, double this value and it sets
-the alarm watchdog for llkd.
+* Properties named `prop_ms` are in milliseconds.
+* Properties that use comma (,) separator for lists use a leading separator to
+ preserve the default entry, then add or subtract entries with optional plus
+ (+) and minus (-) prefixes respectively. For these lists, the string "false"
+ is synonymous with an empty list, and blank or missing entries resort to the
+ specified default value.
-#### ro.llk.D.timeout_ms
-default ro.llk.timeout_ms, D maximum timelimit.
+### ro.config.low_ram <!-- {:#ro-config-low-ram} -->
-#### ro.llk.Z.timeout_ms
-default ro.llk.timeout_ms, Z maximum timelimit.
+Device is configured with limited memory.
-#### ro.llk.stack.timeout_ms
-default ro.llk.timeout_ms,
-checking for persistent stack symbols maximum timelimit.
-Only active on userdebug or eng builds.
+### ro.debuggable <!-- {:#ro-debuggable} -->
-#### ro.llk.check_ms
-default 2 minutes samples of threads for D or Z.
+Device is configured for userdebug or eng build.
-#### ro.llk.stack
-default cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
-comma separated list of kernel symbols.
-Look for kernel stack symbols that if ever persistently present can
-indicate a subsystem is locked up.
-Beware, check does not on purpose do forward scheduling ABA except by polling
-every ro.llk_check_ms over the period ro.llk.stack.timeout_ms, so stack symbol
-should be exceptionally rare and fleeting.
-One must be convinced that it is virtually *impossible* for symbol to show up
-persistently in all samples of the stack.
-Again, looks for a match for either " **symbol**+0x" or " **symbol**.cfi+0x"
-in stack expansion.
-Only available on userdebug or eng builds, limited privileges due to security
-concerns on user builds prevents this checking.
+### ro.llk.sysrq_t <!-- {:#ro-llk-sysrq-t} -->
-#### ro.llk.blacklist.process
-default 0,1,2 (kernel, init and [kthreadd]) plus process names
-init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd,
-[watchdogd],[watchdogd/0],...,[watchdogd/***get_nprocs**-1*].
-Do not watch these processes. A process can be comm, cmdline or pid reference.
-NB: automated default here can be larger than the current maximum property
-size of 92.
-NB: false is a very very very unlikely process to want to blacklist.
+If property is "eng", the default is not `ro.config.low_ram` or `ro.debuggable`.
+If true, dump all threads (`sysrq t`).
-#### ro.llk.blacklist.parent
-default 0,2,adbd&[setsid] (kernel, [kthreadd] and adbd *only for zombie setsid*).
-Do not watch processes that have this parent.
-An ampersand (*&*) separator is used to specify that the parent is ignored
-only in combination with the target child process.
-Ampersand was selected because it is never part of a process name,
-however a setprop in the shell requires it to be escaped or quoted;
-init rc file where this is normally specified does not have this issue.
-A parent or target processes can be specified as comm, cmdline or pid reference.
+### ro.llk.enable <!-- {:#ro-llk-enable} -->
-#### ro.llk.blacklist.uid
-default *empty* or false, comma separated list of uid numbers or names.
-Do not watch processes that match this uid.
+Allow live-lock daemon to be enabled. Default is false.
-#### ro.llk.blacklist.process.stack
-default process names init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd.
-This subset of processes are not monitored for live lock stack signatures.
-Also prevents the sepolicy violation associated with processes that block
-ptrace, as these can not be checked anyways.
-Only active on userdebug and eng builds.
+### llk.enable <!-- {:#llk-enable} -->
-Architectural Concerns
-----------------------
+Evaluated for eng builds. Default is `ro.llk.enable`.
-- built-in [khungtask] daemon is too generic and trips on driver code that
- sits around in D state too much. To switch to S instead makes the task(s)
- killable, so the drivers should be able to resurrect them if needed.
-- Properties are limited to 92 characters.
-- Create kernel module and associated gTest to actually test panic.
-- Create gTest to test out blacklist (ro.llk.blacklist.*properties* generally
- not be inputs). Could require more test-only interfaces to libllkd.
-- Speed up gTest using something else than ro.llk.*properties*, which should
- not be inputs as they should be baked into the product.
+### ro.khungtask.enable <!-- {:#ro-khungtask-enable} -->
+
+Allow `[khungtask]` daemon to be enabled. Default is false.
+
+### khungtask.enable <!-- {:#khungtask-enable} -->
+
+Evaluated for eng builds. Default is `ro.khungtask.enable`.
+
+### ro.llk.mlockall <!-- {:#ro-llk-mlockall} -->
+
+Enable call to `mlockall()`. Default is false.
+
+### ro.khungtask.timeout <!-- {:#ro-khungtask-timeout} -->
+
+`[khungtask]` maximum time limit. Default is 12 minutes.
+
+### ro.llk.timeout_ms <!-- {:#ro-llk-timeout-ms} -->
+
+D or Z maximum time limit. Default is 10 minutes. Double this value to set the
+alarm watchdog for `llkd`.
+
+### ro.llk.D.timeout_ms <!-- {:#ro-llk-D-timeout-ms} -->
+
+D maximum time limit. Default is `ro.llk.timeout_ms`.
+
+### ro.llk.Z.timeout_ms <!-- {:#ro-llk-Z-timeout-ms} -->
+
+Z maximum time limit. Default is `ro.llk.timeout_ms`.
+
+### ro.llk.stack.timeout_ms <!-- {:#ro-llk-stack-timeout-ms} -->
+
+Checks for persistent stack symbols maximum time limit. Default is
+`ro.llk.timeout_ms`. **Active only on userdebug or eng builds**.
+
+### ro.llk.check_ms <!-- {:#ro-llk-check-ms} -->
+
+Samples of threads for D or Z. Default is two minutes.
+
+### ro.llk.stack <!-- {:#ro-llk-stack} -->
+
+Checks for kernel stack symbols that if persistently present can indicate a
+subsystem is locked up. Default is
+`cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable`
+comma-separated list of kernel symbols. The check doesn't do forward scheduling
+ABA except by polling every `ro.llk_check_ms` over the period
+`ro.llk.stack.timeout_ms`, so stack symbols should be exceptionally rare and
+fleeting (it is highly unlikely for a symbol to show up persistently in all
+samples of the stack). Checks for a match for `" symbol+0x"` or
+`" symbol.cfi+0x"` in stack expansion. **Available only on userdebug or eng
+builds**; security concerns on user builds result in limited privileges that
+prevent this check.
+
+### ro.llk.ignorelist.process <!-- {:#ro-llk-ignorelist-process} -->
+
+The `llkd` does not watch the specified processes. Default is `0,1,2` (`kernel`,
+`init`, and `[kthreadd]`) plus process names
+`init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]`.
+A process can be a `comm`, `cmdline`, or `pid` reference. An automated default
+can be larger than the current maximum property size of 92.
+
+Note: `false` is an extremely unlikely process to want to ignore.
+
+### ro.llk.ignorelist.parent <!-- {:#ro-llk-ignorelist-parent} -->
+
+The `llkd` does not watch processes that have the specified parent(s). Default
+is `0,2,adbd&[setsid]` (`kernel`, `[kthreadd]`, and `adbd` only for zombie
+`setsid`). An ampersand (&) separator specifies that the parent is ignored only
+in combination with the target child process. Ampersand was selected because it
+is never part of a process name; however, a `setprop` in the shell requires the
+ampersand to be escaped or quoted, although the `init rc` file where this is
+normally specified does not have this issue. A parent or target process can be a
+`comm`, `cmdline`, or `pid` reference.
+
+### ro.llk.ignorelist.uid <!-- {:#ro-llk-ignorelist-uid} -->
+
+The `llkd` does not watch processes that match the specified uid(s).
+Comma-separated list of uid numbers or names. Default is empty or false.
+
+### ro.llk.ignorelist.process.stack <!-- {:#ro-llk-ignorelist-process-stack} -->
+
+The `llkd` does not monitor the specified subset of processes for live lock stack
+signatures. Default is process names
+`init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd`. Prevents the sepolicy
+violation associated with processes that block `ptrace` (as these can't be
+checked). **Active only on userdebug and eng builds**. For details on build
+types, refer to [Building Android](/setup/build/building#choose-a-target).
+
+## Architectural concerns <!-- {:#architectural-concerns} -->
+
+* Properties are limited to 92 characters. However, this is not limited for
+ defaults defined in the `include/llkd.h` file in the sources.
+* The built-in `[khungtask]` daemon is too generic and trips on driver code that
+ sits around in D state too much. Switching drivers to sleep, or S state,
+ would make task(s) killable, and need to be resurrectable by drivers on an
+ as-need basis.
+
+## Library interface (optional) <!-- {:#library-interface-optional} -->
+
+You can optionally incorporate the `llkd` into another privileged daemon using
+the following C interface from the `libllkd` component:
+
+```
+#include "llkd.h"
+bool llkInit(const char* threadname) /* return true if enabled */
+unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
+```
+
+If a threadname is provided, a thread automatically spawns, otherwise the caller
+must call `llkCheckMilliseconds` in its main loop. The function returns the
+period of time before the next expected call to this handler.
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
index 3586ca1..4b20a56 100644
--- a/llkd/include/llkd.h
+++ b/llkd/include/llkd.h
@@ -30,37 +30,37 @@
unsigned llkCheckMilliseconds(void);
/* clang-format off */
-#define LLK_ENABLE_WRITEABLE_PROPERTY "llk.enable"
-#define LLK_ENABLE_PROPERTY "ro." LLK_ENABLE_WRITEABLE_PROPERTY
-#define LLK_ENABLE_DEFAULT false /* "eng" and userdebug true */
-#define KHT_ENABLE_WRITEABLE_PROPERTY "khungtask.enable"
-#define KHT_ENABLE_PROPERTY "ro." KHT_ENABLE_WRITEABLE_PROPERTY
-#define LLK_ENABLE_SYSRQ_T_PROPERTY "ro.llk.sysrq_t"
-#define LLK_ENABLE_SYSRQ_T_DEFAULT true
-#define LLK_MLOCKALL_PROPERTY "ro.llk.mlockall"
-#define LLK_MLOCKALL_DEFAULT true
-#define LLK_KILLTEST_PROPERTY "ro.llk.killtest"
-#define LLK_KILLTEST_DEFAULT true
-#define LLK_TIMEOUT_MS_PROPERTY "ro.llk.timeout_ms"
-#define KHT_TIMEOUT_PROPERTY "ro.khungtask.timeout"
-#define LLK_D_TIMEOUT_MS_PROPERTY "ro.llk.D.timeout_ms"
-#define LLK_Z_TIMEOUT_MS_PROPERTY "ro.llk.Z.timeout_ms"
-#define LLK_STACK_TIMEOUT_MS_PROPERTY "ro.llk.stack.timeout_ms"
-#define LLK_CHECK_MS_PROPERTY "ro.llk.check_ms"
+#define LLK_ENABLE_WRITEABLE_PROPERTY "llk.enable"
+#define LLK_ENABLE_PROPERTY "ro." LLK_ENABLE_WRITEABLE_PROPERTY
+#define LLK_ENABLE_DEFAULT false /* "eng" and userdebug true */
+#define KHT_ENABLE_WRITEABLE_PROPERTY "khungtask.enable"
+#define KHT_ENABLE_PROPERTY "ro." KHT_ENABLE_WRITEABLE_PROPERTY
+#define LLK_ENABLE_SYSRQ_T_PROPERTY "ro.llk.sysrq_t"
+#define LLK_ENABLE_SYSRQ_T_DEFAULT true
+#define LLK_MLOCKALL_PROPERTY "ro.llk.mlockall"
+#define LLK_MLOCKALL_DEFAULT true
+#define LLK_KILLTEST_PROPERTY "ro.llk.killtest"
+#define LLK_KILLTEST_DEFAULT true
+#define LLK_TIMEOUT_MS_PROPERTY "ro.llk.timeout_ms"
+#define KHT_TIMEOUT_PROPERTY "ro.khungtask.timeout"
+#define LLK_D_TIMEOUT_MS_PROPERTY "ro.llk.D.timeout_ms"
+#define LLK_Z_TIMEOUT_MS_PROPERTY "ro.llk.Z.timeout_ms"
+#define LLK_STACK_TIMEOUT_MS_PROPERTY "ro.llk.stack.timeout_ms"
+#define LLK_CHECK_MS_PROPERTY "ro.llk.check_ms"
/* LLK_CHECK_MS_DEFAULT = actual timeout_ms / LLK_CHECKS_PER_TIMEOUT_DEFAULT */
-#define LLK_CHECKS_PER_TIMEOUT_DEFAULT 5
-#define LLK_CHECK_STACK_PROPERTY "ro.llk.stack"
-#define LLK_CHECK_STACK_DEFAULT \
+#define LLK_CHECKS_PER_TIMEOUT_DEFAULT 5
+#define LLK_CHECK_STACK_PROPERTY "ro.llk.stack"
+#define LLK_CHECK_STACK_DEFAULT \
"cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable"
-#define LLK_BLACKLIST_PROCESS_PROPERTY "ro.llk.blacklist.process"
-#define LLK_BLACKLIST_PROCESS_DEFAULT \
+#define LLK_IGNORELIST_PROCESS_PROPERTY "ro.llk.ignorelist.process"
+#define LLK_IGNORELIST_PROCESS_DEFAULT \
"0,1,2,init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd,[watchdogd],[watchdogd/0]"
-#define LLK_BLACKLIST_PARENT_PROPERTY "ro.llk.blacklist.parent"
-#define LLK_BLACKLIST_PARENT_DEFAULT "0,2,[kthreadd],adbd&[setsid]"
-#define LLK_BLACKLIST_UID_PROPERTY "ro.llk.blacklist.uid"
-#define LLK_BLACKLIST_UID_DEFAULT ""
-#define LLK_BLACKLIST_STACK_PROPERTY "ro.llk.blacklist.process.stack"
-#define LLK_BLACKLIST_STACK_DEFAULT "init,lmkd.llkd,llkd,keystore,ueventd,apexd"
+#define LLK_IGNORELIST_PARENT_PROPERTY "ro.llk.ignorelist.parent"
+#define LLK_IGNORELIST_PARENT_DEFAULT "0,2,[kthreadd],adbd&[setsid]"
+#define LLK_IGNORELIST_UID_PROPERTY "ro.llk.ignorelist.uid"
+#define LLK_IGNORELIST_UID_DEFAULT ""
+#define LLK_IGNORELIST_STACK_PROPERTY "ro.llk.ignorelist.process.stack"
+#define LLK_IGNORELIST_STACK_DEFAULT "init,lmkd.llkd,llkd,keystore,ueventd,apexd"
/* clang-format on */
__END_DECLS
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index 8ad9900..a24d900 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -98,26 +98,26 @@
std::unordered_set<std::string> llkCheckStackSymbols;
#endif
-// Blacklist variables, initialized with comma separated lists of high false
+// Ignorelist variables, initialized with comma separated lists of high false
// positive and/or dangerous references, e.g. without self restart, for pid,
// ppid, name and uid:
// list of pids, or tids or names to skip. kernel pid (0), init pid (1),
// [kthreadd] pid (2), ourselves, "init", "[kthreadd]", "lmkd", "llkd" or
// combinations of watchdogd in kernel and user space.
-std::unordered_set<std::string> llkBlacklistProcess;
+std::unordered_set<std::string> llkIgnorelistProcess;
// list of parent pids, comm or cmdline names to skip. default:
// kernel pid (0), [kthreadd] (2), or ourselves, enforced and implied
-std::unordered_set<std::string> llkBlacklistParent;
+std::unordered_set<std::string> llkIgnorelistParent;
// list of parent and target processes to skip. default:
// adbd *and* [setsid]
-std::unordered_map<std::string, std::unordered_set<std::string>> llkBlacklistParentAndChild;
+std::unordered_map<std::string, std::unordered_set<std::string>> llkIgnorelistParentAndChild;
// list of uids, and uid names, to skip, default nothing
-std::unordered_set<std::string> llkBlacklistUid;
+std::unordered_set<std::string> llkIgnorelistUid;
#ifdef __PTRACE_ENABLED__
// list of names to skip stack checking. "init", "lmkd", "llkd", "keystore" or
// "logd" (if not userdebug).
-std::unordered_set<std::string> llkBlacklistStack;
+std::unordered_set<std::string> llkIgnorelistStack;
#endif
class dir {
@@ -626,9 +626,9 @@
return flag ? "true" : "false";
}
-std::string llkFormat(const std::unordered_set<std::string>& blacklist) {
+std::string llkFormat(const std::unordered_set<std::string>& ignorelist) {
std::string ret;
- for (const auto& entry : blacklist) {
+ for (const auto& entry : ignorelist) {
if (!ret.empty()) ret += ",";
ret += entry;
}
@@ -636,10 +636,10 @@
}
std::string llkFormat(
- const std::unordered_map<std::string, std::unordered_set<std::string>>& blacklist,
+ const std::unordered_map<std::string, std::unordered_set<std::string>>& ignorelist,
bool leading_comma = false) {
std::string ret;
- for (const auto& entry : blacklist) {
+ for (const auto& entry : ignorelist) {
for (const auto& target : entry.second) {
if (leading_comma || !ret.empty()) ret += ",";
ret += entry.first + "&" + target;
@@ -699,61 +699,61 @@
}
bool llkSkipName(const std::string& name,
- const std::unordered_set<std::string>& blacklist = llkBlacklistProcess) {
- if (name.empty() || blacklist.empty()) return false;
+ const std::unordered_set<std::string>& ignorelist = llkIgnorelistProcess) {
+ if (name.empty() || ignorelist.empty()) return false;
- return blacklist.find(name) != blacklist.end();
+ return ignorelist.find(name) != ignorelist.end();
}
bool llkSkipProc(proc* procp,
- const std::unordered_set<std::string>& blacklist = llkBlacklistProcess) {
+ const std::unordered_set<std::string>& ignorelist = llkIgnorelistProcess) {
if (!procp) return false;
- if (llkSkipName(std::to_string(procp->pid), blacklist)) return true;
- if (llkSkipName(procp->getComm(), blacklist)) return true;
- if (llkSkipName(procp->getCmdline(), blacklist)) return true;
- if (llkSkipName(android::base::Basename(procp->getCmdline()), blacklist)) return true;
+ if (llkSkipName(std::to_string(procp->pid), ignorelist)) return true;
+ if (llkSkipName(procp->getComm(), ignorelist)) return true;
+ if (llkSkipName(procp->getCmdline(), ignorelist)) return true;
+ if (llkSkipName(android::base::Basename(procp->getCmdline()), ignorelist)) return true;
return false;
}
const std::unordered_set<std::string>& llkSkipName(
const std::string& name,
- const std::unordered_map<std::string, std::unordered_set<std::string>>& blacklist) {
+ const std::unordered_map<std::string, std::unordered_set<std::string>>& ignorelist) {
static const std::unordered_set<std::string> empty;
- if (name.empty() || blacklist.empty()) return empty;
- auto found = blacklist.find(name);
- if (found == blacklist.end()) return empty;
+ if (name.empty() || ignorelist.empty()) return empty;
+ auto found = ignorelist.find(name);
+ if (found == ignorelist.end()) return empty;
return found->second;
}
bool llkSkipPproc(proc* pprocp, proc* procp,
const std::unordered_map<std::string, std::unordered_set<std::string>>&
- blacklist = llkBlacklistParentAndChild) {
- if (!pprocp || !procp || blacklist.empty()) return false;
- if (llkSkipProc(procp, llkSkipName(std::to_string(pprocp->pid), blacklist))) return true;
- if (llkSkipProc(procp, llkSkipName(pprocp->getComm(), blacklist))) return true;
- if (llkSkipProc(procp, llkSkipName(pprocp->getCmdline(), blacklist))) return true;
+ ignorelist = llkIgnorelistParentAndChild) {
+ if (!pprocp || !procp || ignorelist.empty()) return false;
+ if (llkSkipProc(procp, llkSkipName(std::to_string(pprocp->pid), ignorelist))) return true;
+ if (llkSkipProc(procp, llkSkipName(pprocp->getComm(), ignorelist))) return true;
+ if (llkSkipProc(procp, llkSkipName(pprocp->getCmdline(), ignorelist))) return true;
return llkSkipProc(procp,
- llkSkipName(android::base::Basename(pprocp->getCmdline()), blacklist));
+ llkSkipName(android::base::Basename(pprocp->getCmdline()), ignorelist));
}
bool llkSkipPid(pid_t pid) {
- return llkSkipName(std::to_string(pid), llkBlacklistProcess);
+ return llkSkipName(std::to_string(pid), llkIgnorelistProcess);
}
bool llkSkipPpid(pid_t ppid) {
- return llkSkipName(std::to_string(ppid), llkBlacklistParent);
+ return llkSkipName(std::to_string(ppid), llkIgnorelistParent);
}
bool llkSkipUid(uid_t uid) {
// Match by number?
- if (llkSkipName(std::to_string(uid), llkBlacklistUid)) {
+ if (llkSkipName(std::to_string(uid), llkIgnorelistUid)) {
return true;
}
// Match by name?
auto pwd = ::getpwuid(uid);
return (pwd != nullptr) && __predict_true(pwd->pw_name != nullptr) &&
- __predict_true(pwd->pw_name[0] != '\0') && llkSkipName(pwd->pw_name, llkBlacklistUid);
+ __predict_true(pwd->pw_name[0] != '\0') && llkSkipName(pwd->pw_name, llkIgnorelistUid);
}
bool getValidTidDir(dirent* dp, std::string* piddir) {
@@ -811,7 +811,7 @@
}
// Don't check process that are known to block ptrace, save sepolicy noise.
- if (llkSkipProc(procp, llkBlacklistStack)) return false;
+ if (llkSkipProc(procp, llkIgnorelistStack)) return false;
auto kernel_stack = ReadFile(piddir + "/stack");
if (kernel_stack.empty()) {
LOG(VERBOSE) << piddir << "/stack empty comm=" << procp->getComm()
@@ -917,12 +917,12 @@
<< LLK_CHECK_MS_PROPERTY "=" << llkFormat(llkCheckMs) << "\n"
#ifdef __PTRACE_ENABLED__
<< LLK_CHECK_STACK_PROPERTY "=" << llkFormat(llkCheckStackSymbols) << "\n"
- << LLK_BLACKLIST_STACK_PROPERTY "=" << llkFormat(llkBlacklistStack) << "\n"
+ << LLK_IGNORELIST_STACK_PROPERTY "=" << llkFormat(llkIgnorelistStack) << "\n"
#endif
- << LLK_BLACKLIST_PROCESS_PROPERTY "=" << llkFormat(llkBlacklistProcess) << "\n"
- << LLK_BLACKLIST_PARENT_PROPERTY "=" << llkFormat(llkBlacklistParent)
- << llkFormat(llkBlacklistParentAndChild, true) << "\n"
- << LLK_BLACKLIST_UID_PROPERTY "=" << llkFormat(llkBlacklistUid);
+ << LLK_IGNORELIST_PROCESS_PROPERTY "=" << llkFormat(llkIgnorelistProcess) << "\n"
+ << LLK_IGNORELIST_PARENT_PROPERTY "=" << llkFormat(llkIgnorelistParent)
+ << llkFormat(llkIgnorelistParentAndChild, true) << "\n"
+ << LLK_IGNORELIST_UID_PROPERTY "=" << llkFormat(llkIgnorelistUid);
}
void* llkThread(void* obj) {
@@ -932,14 +932,14 @@
std::string name = std::to_string(::gettid());
if (!llkSkipName(name)) {
- llkBlacklistProcess.emplace(name);
+ llkIgnorelistProcess.emplace(name);
}
name = static_cast<const char*>(obj);
prctl(PR_SET_NAME, name.c_str());
if (__predict_false(!llkSkipName(name))) {
- llkBlacklistProcess.insert(name);
+ llkIgnorelistProcess.insert(name);
}
- // No longer modifying llkBlacklistProcess.
+ // No longer modifying llkIgnorelistProcess.
llkRunning = true;
llkLogConfig();
while (llkRunning) {
@@ -1122,12 +1122,12 @@
}
if (pprocp) {
if (llkSkipPproc(pprocp, procp)) break;
- if (llkSkipProc(pprocp, llkBlacklistParent)) break;
+ if (llkSkipProc(pprocp, llkIgnorelistParent)) break;
} else {
- if (llkSkipName(std::to_string(ppid), llkBlacklistParent)) break;
+ if (llkSkipName(std::to_string(ppid), llkIgnorelistParent)) break;
}
- if ((llkBlacklistUid.size() != 0) && llkSkipUid(procp->getUid())) {
+ if ((llkIgnorelistUid.size() != 0) && llkSkipUid(procp->getUid())) {
continue;
}
@@ -1320,29 +1320,29 @@
if (debuggable) {
llkCheckStackSymbols = llkSplit(LLK_CHECK_STACK_PROPERTY, LLK_CHECK_STACK_DEFAULT);
}
- std::string defaultBlacklistStack(LLK_BLACKLIST_STACK_DEFAULT);
- if (!debuggable) defaultBlacklistStack += ",logd,/system/bin/logd";
- llkBlacklistStack = llkSplit(LLK_BLACKLIST_STACK_PROPERTY, defaultBlacklistStack);
+ std::string defaultIgnorelistStack(LLK_IGNORELIST_STACK_DEFAULT);
+ if (!debuggable) defaultIgnorelistStack += ",logd,/system/bin/logd";
+ llkIgnorelistStack = llkSplit(LLK_IGNORELIST_STACK_PROPERTY, defaultIgnorelistStack);
#endif
- std::string defaultBlacklistProcess(
- std::to_string(kernelPid) + "," + std::to_string(initPid) + "," +
- std::to_string(kthreaddPid) + "," + std::to_string(::getpid()) + "," +
- std::to_string(::gettid()) + "," LLK_BLACKLIST_PROCESS_DEFAULT);
+ std::string defaultIgnorelistProcess(
+ std::to_string(kernelPid) + "," + std::to_string(initPid) + "," +
+ std::to_string(kthreaddPid) + "," + std::to_string(::getpid()) + "," +
+ std::to_string(::gettid()) + "," LLK_IGNORELIST_PROCESS_DEFAULT);
if (threadname) {
- defaultBlacklistProcess += ","s + threadname;
+ defaultIgnorelistProcess += ","s + threadname;
}
for (int cpu = 1; cpu < get_nprocs_conf(); ++cpu) {
- defaultBlacklistProcess += ",[watchdog/" + std::to_string(cpu) + "]";
+ defaultIgnorelistProcess += ",[watchdog/" + std::to_string(cpu) + "]";
}
- llkBlacklistProcess = llkSplit(LLK_BLACKLIST_PROCESS_PROPERTY, defaultBlacklistProcess);
+ llkIgnorelistProcess = llkSplit(LLK_IGNORELIST_PROCESS_PROPERTY, defaultIgnorelistProcess);
if (!llkSkipName("[khungtaskd]")) { // ALWAYS ignore as special
- llkBlacklistProcess.emplace("[khungtaskd]");
+ llkIgnorelistProcess.emplace("[khungtaskd]");
}
- llkBlacklistParent = llkSplit(LLK_BLACKLIST_PARENT_PROPERTY,
- std::to_string(kernelPid) + "," + std::to_string(kthreaddPid) +
- "," LLK_BLACKLIST_PARENT_DEFAULT);
- // derive llkBlacklistParentAndChild by moving entries with '&' from above
- for (auto it = llkBlacklistParent.begin(); it != llkBlacklistParent.end();) {
+ llkIgnorelistParent = llkSplit(LLK_IGNORELIST_PARENT_PROPERTY,
+ std::to_string(kernelPid) + "," + std::to_string(kthreaddPid) +
+ "," LLK_IGNORELIST_PARENT_DEFAULT);
+ // derive llkIgnorelistParentAndChild by moving entries with '&' from above
+ for (auto it = llkIgnorelistParent.begin(); it != llkIgnorelistParent.end();) {
auto pos = it->find('&');
if (pos == std::string::npos) {
++it;
@@ -1350,18 +1350,18 @@
}
auto parent = it->substr(0, pos);
auto child = it->substr(pos + 1);
- it = llkBlacklistParent.erase(it);
+ it = llkIgnorelistParent.erase(it);
- auto found = llkBlacklistParentAndChild.find(parent);
- if (found == llkBlacklistParentAndChild.end()) {
- llkBlacklistParentAndChild.emplace(std::make_pair(
+ auto found = llkIgnorelistParentAndChild.find(parent);
+ if (found == llkIgnorelistParentAndChild.end()) {
+ llkIgnorelistParentAndChild.emplace(std::make_pair(
std::move(parent), std::unordered_set<std::string>({std::move(child)})));
} else {
found->second.emplace(std::move(child));
}
}
- llkBlacklistUid = llkSplit(LLK_BLACKLIST_UID_PROPERTY, LLK_BLACKLIST_UID_DEFAULT);
+ llkIgnorelistUid = llkSplit(LLK_IGNORELIST_UID_PROPERTY, LLK_IGNORELIST_UID_DEFAULT);
// internal watchdog
::signal(SIGALRM, llkAlarmHandler);
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 0056c80..cf98dad 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -333,14 +333,14 @@
This can individually control each buffer's size with -b.
-S, --statistics Output statistics.
--pid can be used to provide pid specific stats.
- -p, --prune Print prune white and ~black list. Service is specified as UID,
- UID/PID or /PID. Weighed for quicker pruning if prefix with ~,
- otherwise weighed for longevity if unadorned. All other pruning
- activity is oldest first. Special case ~! represents an automatic
- quicker pruning for the noisiest UID as determined by the current
- statistics.
- -P, --prune='<list> ...' Set prune white and ~black list, using same format as listed above.
- Must be quoted.
+ -p, --prune Print prune rules. Each rule is specified as UID, UID/PID or /PID. A
+ '~' prefix indicates that elements matching the rule should be pruned
+ with higher priority otherwise they're pruned with lower priority. All
+ other pruning activity is oldest first. Special case ~! represents an
+ automatic pruning for the noisiest UID as determined by the current
+ statistics. Special case ~1000/! represents pruning of the worst PID
+ within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
+ -P, --prune='<list> ...' Set prune rules, using same format as listed above. Must be quoted.
Filtering:
-s Set default filter to silent. Equivalent to filterspec '*:S'
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index a2daeb0..61aa938 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -1301,7 +1301,7 @@
}
#endif
-static bool get_white_black(char** list) {
+static bool get_prune_rules(char** list) {
FILE* fp = popen(logcat_executable " -p 2>/dev/null", "r");
if (fp == NULL) {
fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n");
@@ -1334,7 +1334,7 @@
return *list != NULL;
}
-static bool set_white_black(const char* list) {
+static bool set_prune_rules(const char* list) {
char buffer[BIG_BUFFER];
snprintf(buffer, sizeof(buffer), logcat_executable " -P '%s' 2>&1",
list ? list : "");
@@ -1363,28 +1363,28 @@
return pclose(fp) == 0;
}
-TEST(logcat, white_black_adjust) {
+TEST(logcat, prune_rules_adjust) {
char* list = NULL;
char* adjust = NULL;
- get_white_black(&list);
+ get_prune_rules(&list);
static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30";
- ASSERT_EQ(true, set_white_black(adjustment));
- ASSERT_EQ(true, get_white_black(&adjust));
+ ASSERT_EQ(true, set_prune_rules(adjustment));
+ ASSERT_EQ(true, get_prune_rules(&adjust));
EXPECT_STREQ(adjustment, adjust);
free(adjust);
adjust = NULL;
static const char adjustment2[] = "300/20 300/21 2000 ~1000";
- ASSERT_EQ(true, set_white_black(adjustment2));
- ASSERT_EQ(true, get_white_black(&adjust));
+ ASSERT_EQ(true, set_prune_rules(adjustment2));
+ ASSERT_EQ(true, get_prune_rules(&adjust));
EXPECT_STREQ(adjustment2, adjust);
free(adjust);
adjust = NULL;
- ASSERT_EQ(true, set_white_black(list));
- get_white_black(&adjust);
+ ASSERT_EQ(true, set_prune_rules(list));
+ get_prune_rules(&adjust);
EXPECT_STREQ(list ? list : "", adjust ? adjust : "");
free(adjust);
adjust = NULL;
diff --git a/logd/Android.bp b/logd/Android.bp
index e0a1168..036cb7e 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -58,8 +58,8 @@
"LogReaderThread.cpp",
"LogBufferElement.cpp",
"LogStatistics.cpp",
- "LogWhiteBlackList.cpp",
"LogTags.cpp",
+ "PruneList.cpp",
"SerializedFlushToState.cpp",
"SerializedLogBuffer.cpp",
"SerializedLogChunk.cpp",
diff --git a/logd/ChattyLogBuffer.cpp b/logd/ChattyLogBuffer.cpp
index c213448..fd183e4 100644
--- a/logd/ChattyLogBuffer.cpp
+++ b/logd/ChattyLogBuffer.cpp
@@ -298,33 +298,37 @@
// invariably move the logs value down faster as less chatty sources would be
// expired in the noise.
//
-// The first loop performs blacklisting and worst offender pruning. Falling
-// through when there are no notable worst offenders and have not hit the
-// region lock preventing further worst offender pruning. This loop also looks
-// after managing the chatty log entries and merging to help provide
-// statistical basis for blame. The chatty entries are not a notification of
-// how much logs you may have, but instead represent how much logs you would
-// have had in a virtual log buffer that is extended to cover all the in-memory
-// logs without loss. They last much longer than the represented pruned logs
-// since they get multiplied by the gains in the non-chatty log sources.
+// The first pass prunes elements that match 3 possible rules:
+// 1) A high priority prune rule, for example ~100/20, which indicates elements from UID 100 and PID
+// 20 should be pruned in this first pass.
+// 2) The default chatty pruning rule, ~!. This rule sums the total size spent on log messages for
+// each UID this log buffer. If the highest sum consumes more than 12.5% of the log buffer, then
+// these elements from that UID are pruned.
+// 3) The default AID_SYSTEM pruning rule, ~1000/!. This rule is a special case to 2), if
+// AID_SYSTEM is the top consumer of the log buffer, then this rule sums the total size spent on
+// log messages for each PID in AID_SYSTEM in this log buffer and prunes elements from the PID
+// with the highest sum.
+// This pass reevaluates the sums for rules 2) and 3) for every log message pruned. It creates
+// 'chatty' entries for the elements that it prunes and merges related chatty entries together. It
+// completes when one of three conditions have been met:
+// 1) The requested element count has been pruned.
+// 2) There are no elements that match any of these rules.
+// 3) A reader is referencing the oldest element that would match these rules.
//
-// The second loop get complicated because an algorithm of watermarks and
-// history is maintained to reduce the order and keep processing time
-// down to a minimum at scale. These algorithms can be costly in the face
-// of larger log buffers, or severly limited processing time granted to a
-// background task at lowest priority.
+// The second pass prunes elements starting from the beginning of the log. It skips elements that
+// match any low priority prune rules. It completes when one of three conditions have been met:
+// 1) The requested element count has been pruned.
+// 2) All elements except those mwatching low priority prune rules have been pruned.
+// 3) A reader is referencing the oldest element that would match these rules.
//
-// This second loop does straight-up expiration from the end of the logs
-// (again, remember for the specified log buffer id) but does some whitelist
-// preservation. Thus whitelist is a Hail Mary low priority, blacklists and
-// spam filtration all take priority. This second loop also checks if a region
-// lock is causing us to buffer too much in the logs to help the reader(s),
-// and will tell the slowest reader thread to skip log entries, and if
-// persistent and hits a further threshold, kill the reader thread.
+// The final pass only happens if there are any low priority prune rules and if the first two passes
+// were unable to prune the requested number of elements. It prunes elements all starting from the
+// beginning of the log, regardless of if they match any low priority prune rules.
//
-// The third thread is optional, and only gets hit if there was a whitelist
-// and more needs to be pruned against the backstop of the region lock.
-//
+// If the requested number of logs was unable to be pruned, KickReader() is called to mitigate the
+// situation before the next call to Prune() and the function returns false. Otherwise, if the
+// requested number of logs or all logs present in the buffer are pruned, in the case of Clear(),
+// it returns true.
bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
LogReaderThread* oldest = nullptr;
bool clearAll = pruneRows == ULONG_MAX;
@@ -370,8 +374,8 @@
return true;
}
- // prune by worst offenders; by blacklist, UID, and by PID of system UID
- bool hasBlacklist = (id != LOG_ID_SECURITY) && prune_->naughty();
+ // First prune pass.
+ bool check_high_priority = id != LOG_ID_SECURITY && prune_->HasHighPriorityPruneRules();
while (!clearAll && (pruneRows > 0)) {
// recalculate the worst offender on every batched pass
int worst = -1; // not valid for uid() or getKey()
@@ -379,7 +383,7 @@
size_t second_worst_sizes = 0;
pid_t worstPid = 0; // POSIX guarantees PID != 0
- if (worstUidEnabledForLogid(id) && prune_->worstUidEnabled()) {
+ if (worstUidEnabledForLogid(id) && prune_->worst_uid_enabled()) {
// Calculate threshold as 12.5% of available storage
size_t threshold = max_size(id) / 8;
@@ -389,14 +393,14 @@
} else {
stats()->WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
- if (worst == AID_SYSTEM && prune_->worstPidOfSystemEnabled()) {
+ if (worst == AID_SYSTEM && prune_->worst_pid_of_system_enabled()) {
stats()->WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
}
}
}
- // skip if we have neither worst nor naughty filters
- if ((worst == -1) && !hasBlacklist) {
+ // skip if we have neither a worst UID or high priority prune rules
+ if (worst == -1 && !check_high_priority) {
break;
}
@@ -464,7 +468,7 @@
int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element.GetTag()
: element.uid();
- if (hasBlacklist && prune_->naughty(&element)) {
+ if (check_high_priority && prune_->IsHighPriority(&element)) {
last.clear(&element);
it = Erase(it);
if (dropped) {
@@ -557,15 +561,17 @@
}
last.clear();
- if (!kick || !prune_->worstUidEnabled()) {
+ if (!kick || !prune_->worst_uid_enabled()) {
break; // the following loop will ask bad clients to skip/drop
}
}
- bool whitelist = false;
- bool hasWhitelist = (id != LOG_ID_SECURITY) && prune_->nice() && !clearAll;
+ // Second prune pass.
+ bool skipped_low_priority_prune = false;
+ bool check_low_priority =
+ id != LOG_ID_SECURITY && prune_->HasLowPriorityPruneRules() && !clearAll;
it = GetOldest(id);
- while ((pruneRows > 0) && (it != logs().end())) {
+ while (pruneRows > 0 && it != logs().end()) {
LogBufferElement& element = *it;
if (element.log_id() != id) {
@@ -574,13 +580,12 @@
}
if (oldest && oldest->start() <= element.sequence()) {
- if (!whitelist) KickReader(oldest, id, pruneRows);
+ if (!skipped_low_priority_prune) KickReader(oldest, id, pruneRows);
break;
}
- if (hasWhitelist && !element.dropped_count() && prune_->nice(&element)) {
- // WhiteListed
- whitelist = true;
+ if (check_low_priority && !element.dropped_count() && prune_->IsLowPriority(&element)) {
+ skipped_low_priority_prune = true;
it++;
continue;
}
@@ -589,10 +594,10 @@
pruneRows--;
}
- // Do not save the whitelist if we are reader range limited
- if (whitelist && (pruneRows > 0)) {
+ // Third prune pass.
+ if (skipped_low_priority_prune && pruneRows > 0) {
it = GetOldest(id);
- while ((it != logs().end()) && (pruneRows > 0)) {
+ while (it != logs().end() && pruneRows > 0) {
LogBufferElement& element = *it;
if (element.log_id() != id) {
diff --git a/logd/ChattyLogBuffer.h b/logd/ChattyLogBuffer.h
index 6f60272..ce3dc7b 100644
--- a/logd/ChattyLogBuffer.h
+++ b/logd/ChattyLogBuffer.h
@@ -33,8 +33,8 @@
#include "LogReaderThread.h"
#include "LogStatistics.h"
#include "LogTags.h"
-#include "LogWhiteBlackList.h"
#include "LogWriter.h"
+#include "PruneList.h"
#include "SimpleLogBuffer.h"
#include "rwlock.h"
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 39c5490..2eeb0d9 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -215,15 +215,13 @@
return 0;
}
-int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli,
- int /*argc*/, char** /*argv*/) {
+int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli, int, char**) {
setname();
- cli->sendMsg(PackageString(prune()->format()).c_str());
+ cli->sendMsg(PackageString(prune()->Format()).c_str());
return 0;
}
-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");
@@ -238,15 +236,12 @@
str += argv[i];
}
- int ret = prune()->init(str.c_str());
-
- if (ret) {
+ if (!prune()->Init(str.c_str())) {
cli->sendMsg("Invalid");
return 0;
}
cli->sendMsg("success");
-
return 0;
}
@@ -301,7 +296,7 @@
LOG(INFO) << "logd reinit";
buf()->Init();
- prune()->init(nullptr);
+ prune()->Init(nullptr);
// This only works on userdebug and eng devices to re-read the
// /data/misc/logd/event-log-tags file right after /data is mounted.
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index a55a393..c3080ab 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -23,7 +23,7 @@
#include "LogListener.h"
#include "LogStatistics.h"
#include "LogTags.h"
-#include "LogWhiteBlackList.h"
+#include "PruneList.h"
class CommandListener : public FrameworkListener {
public:
diff --git a/logd/LogBufferTest.h b/logd/LogBufferTest.h
index 235f5ac..5d57ad1 100644
--- a/logd/LogBufferTest.h
+++ b/logd/LogBufferTest.h
@@ -25,7 +25,7 @@
#include "LogReaderList.h"
#include "LogStatistics.h"
#include "LogTags.h"
-#include "LogWhiteBlackList.h"
+#include "PruneList.h"
#include "SerializedLogBuffer.h"
#include "SimpleLogBuffer.h"
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 1ea87a9..dbdf7fd 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -665,10 +665,9 @@
((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]))) ||
- // blacklist
+ // ignore
((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen)) ||
- ((size == warningLen) &&
- !fastcmp<strncasecmp>(tag, warning, warningLen)) ||
+ ((size == warningLen) && !fastcmp<strncasecmp>(tag, warning, warningLen)) ||
((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen)) ||
((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
p = start;
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
deleted file mode 100644
index 88a3bdc..0000000
--- a/logd/LogWhiteBlackList.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <ctype.h>
-
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-
-#include "LogWhiteBlackList.h"
-
-Prune::Prune(uid_t uid, pid_t pid) : mUid(uid), mPid(pid) {
-}
-
-int Prune::cmp(uid_t uid, pid_t pid) const {
- if ((mUid == uid_all) || (mUid == uid)) {
- if (mPid == pid_all) {
- return 0;
- }
- return pid - mPid;
- }
- return uid - mUid;
-}
-
-std::string Prune::format() {
- if (mUid != uid_all) {
- if (mPid != pid_all) {
- return android::base::StringPrintf("%u/%u", mUid, mPid);
- }
- return android::base::StringPrintf("%u", mUid);
- }
- if (mPid != pid_all) {
- return android::base::StringPrintf("/%u", mPid);
- }
- // NB: mPid == pid_all can not happen if mUid == uid_all
- return std::string("/");
-}
-
-PruneList::PruneList() {
- init(nullptr);
-}
-
-PruneList::~PruneList() {
- PruneCollection::iterator it;
- for (it = mNice.begin(); it != mNice.end();) {
- it = mNice.erase(it);
- }
- for (it = mNaughty.begin(); it != mNaughty.end();) {
- it = mNaughty.erase(it);
- }
-}
-
-int PruneList::init(const char* str) {
- mWorstUidEnabled = true;
- mWorstPidOfSystemEnabled = true;
- PruneCollection::iterator it;
- for (it = mNice.begin(); it != mNice.end();) {
- it = mNice.erase(it);
- }
- for (it = mNaughty.begin(); it != mNaughty.end();) {
- it = mNaughty.erase(it);
- }
-
- // default here means take ro.logd.filter, persist.logd.filter then
- // internal default in that order.
- if (str && !strcmp(str, "default")) {
- str = nullptr;
- }
- if (str && !strcmp(str, "disable")) {
- str = "";
- }
-
- std::string filter;
-
- if (str) {
- filter = str;
- } else {
- filter = android::base::GetProperty("ro.logd.filter", "default");
- auto persist_filter = android::base::GetProperty("persist.logd.filter", "default");
- // default here means take ro.logd.filter
- if (persist_filter != "default") {
- filter = persist_filter;
- }
- }
-
- // default here means take internal default.
- if (filter == "default") {
- // See README.property for description of filter format
- filter = "~! ~1000/!";
- }
- if (filter == "disable") {
- filter = "";
- }
-
- mWorstUidEnabled = false;
- mWorstPidOfSystemEnabled = false;
-
- for (str = filter.c_str(); *str; ++str) {
- if (isspace(*str)) {
- continue;
- }
-
- PruneCollection* list;
- if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented
- ++str;
- // special case, translates to worst UID at priority in blacklist
- if (*str == '!') {
- mWorstUidEnabled = true;
- ++str;
- if (!*str) {
- break;
- }
- if (!isspace(*str)) {
- return 1;
- }
- continue;
- }
- // special case, translated to worst PID of System at priority
- static const char worstPid[] = "1000/!";
- if (!strncmp(str, worstPid, sizeof(worstPid) - 1)) {
- mWorstPidOfSystemEnabled = true;
- str += sizeof(worstPid) - 1;
- if (!*str) {
- break;
- }
- if (!isspace(*str)) {
- return 1;
- }
- continue;
- }
- if (!*str) {
- return 1;
- }
- list = &mNaughty;
- } else {
- list = &mNice;
- }
-
- uid_t uid = Prune::uid_all;
- if (isdigit(*str)) {
- uid = 0;
- do {
- uid = uid * 10 + *str++ - '0';
- } while (isdigit(*str));
- }
-
- pid_t pid = Prune::pid_all;
- if (*str == '/') {
- ++str;
- if (isdigit(*str)) {
- pid = 0;
- do {
- pid = pid * 10 + *str++ - '0';
- } while (isdigit(*str));
- }
- }
-
- if ((uid == Prune::uid_all) && (pid == Prune::pid_all)) {
- return 1;
- }
-
- if (*str && !isspace(*str)) {
- return 1;
- }
-
- // insert sequentially into list
- PruneCollection::iterator it = list->begin();
- while (it != list->end()) {
- Prune& p = *it;
- int m = uid - p.mUid;
- if (m == 0) {
- if (p.mPid == p.pid_all) {
- break;
- }
- if ((pid == p.pid_all) && (p.mPid != p.pid_all)) {
- it = list->erase(it);
- continue;
- }
- m = pid - p.mPid;
- }
- if (m <= 0) {
- if (m < 0) {
- list->insert(it, Prune(uid, pid));
- }
- break;
- }
- ++it;
- }
- if (it == list->end()) {
- list->push_back(Prune(uid, pid));
- }
- if (!*str) {
- break;
- }
- }
-
- return 0;
-}
-
-std::string PruneList::format() {
- static const char nice_format[] = " %s";
- const char* fmt = nice_format + 1;
-
- std::string string;
-
- if (mWorstUidEnabled) {
- string = "~!";
- fmt = nice_format;
- if (mWorstPidOfSystemEnabled) {
- string += " ~1000/!";
- }
- }
-
- PruneCollection::iterator it;
-
- for (it = mNice.begin(); it != mNice.end(); ++it) {
- string += android::base::StringPrintf(fmt, (*it).format().c_str());
- fmt = nice_format;
- }
-
- static const char naughty_format[] = " ~%s";
- fmt = naughty_format + (*fmt != ' ');
- for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
- string += android::base::StringPrintf(fmt, (*it).format().c_str());
- fmt = naughty_format;
- }
-
- return string;
-}
-
-// ToDo: Lists are in sorted order, Prune->cmp() returns + or -
-// If there is scaling issues, resort to a better algorithm than linear
-// based on these assumptions.
-
-bool PruneList::naughty(LogBufferElement* element) {
- PruneCollection::iterator it;
- for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
- if (!(*it).cmp(element)) {
- return true;
- }
- }
- return false;
-}
-
-bool PruneList::nice(LogBufferElement* element) {
- PruneCollection::iterator it;
- for (it = mNice.begin(); it != mNice.end(); ++it) {
- if (!(*it).cmp(element)) {
- return true;
- }
- }
- return false;
-}
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
deleted file mode 100644
index 447ab87..0000000
--- a/logd/LogWhiteBlackList.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <sys/types.h>
-
-#include <string.h>
-#include <list>
-
-#include "LogBufferElement.h"
-
-class Prune {
- friend class PruneList;
-
- const uid_t mUid;
- 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;
-
- Prune(uid_t uid, pid_t pid);
-
- uid_t getUid() const {
- return mUid;
- }
- pid_t getPid() const {
- return mPid;
- }
-
- int cmp(LogBufferElement* e) const { return cmp(e->uid(), e->pid()); }
-
- std::string format();
-};
-
-typedef std::list<Prune> PruneCollection;
-
-class PruneList {
- PruneCollection mNaughty;
- PruneCollection mNice;
- bool mWorstUidEnabled;
- bool mWorstPidOfSystemEnabled;
-
- public:
- PruneList();
- ~PruneList();
-
- 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;
- }
-
- std::string format();
-};
diff --git a/logd/PruneList.cpp b/logd/PruneList.cpp
new file mode 100644
index 0000000..c3859f3
--- /dev/null
+++ b/logd/PruneList.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PruneList.h"
+
+#include <ctype.h>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+bool Prune::Matches(LogBufferElement* element) const {
+ return (uid_ == UID_ALL || uid_ == element->uid()) &&
+ (pid_ == PID_ALL || pid_ == element->pid());
+}
+
+std::string Prune::Format() const {
+ if (uid_ != UID_ALL) {
+ if (pid_ != PID_ALL) {
+ return android::base::StringPrintf("%u/%u", uid_, pid_);
+ }
+ return android::base::StringPrintf("%u", uid_);
+ }
+ if (pid_ != PID_ALL) {
+ return android::base::StringPrintf("/%u", pid_);
+ }
+ // NB: pid_ == PID_ALL can not happen if uid_ == UID_ALL
+ return std::string("/");
+}
+
+PruneList::PruneList() {
+ Init(nullptr);
+}
+
+bool PruneList::Init(const char* str) {
+ high_priority_prune_.clear();
+ low_priority_prune_.clear();
+
+ // default here means take ro.logd.filter, persist.logd.filter then internal default in order.
+ if (str && !strcmp(str, "default")) {
+ str = nullptr;
+ }
+ if (str && !strcmp(str, "disable")) {
+ str = "";
+ }
+
+ std::string filter;
+
+ if (str) {
+ filter = str;
+ } else {
+ filter = android::base::GetProperty("ro.logd.filter", "default");
+ auto persist_filter = android::base::GetProperty("persist.logd.filter", "default");
+ // default here means take ro.logd.filter
+ if (persist_filter != "default") {
+ filter = persist_filter;
+ }
+ }
+
+ // default here means take internal default.
+ if (filter == "default") {
+ filter = "~! ~1000/!";
+ }
+ if (filter == "disable") {
+ filter = "";
+ }
+
+ worst_uid_enabled_ = false;
+ worst_pid_of_system_enabled_ = false;
+
+ for (str = filter.c_str(); *str; ++str) {
+ if (isspace(*str)) {
+ continue;
+ }
+
+ std::list<Prune>* list;
+ if (*str == '~' || *str == '!') { // ~ supported, ! undocumented
+ ++str;
+ // special case, prune the worst UID of those using at least 1/8th of the buffer.
+ if (*str == '!') {
+ worst_uid_enabled_ = true;
+ ++str;
+ if (!*str) {
+ break;
+ }
+ if (!isspace(*str)) {
+ LOG(ERROR) << "Nothing expected after '~!', but found '" << str << "'";
+ return false;
+ }
+ continue;
+ }
+ // special case, translated to worst PID of System at priority
+ static const char WORST_SYSTEM_PID[] = "1000/!";
+ if (!strncmp(str, WORST_SYSTEM_PID, sizeof(WORST_SYSTEM_PID) - 1)) {
+ worst_pid_of_system_enabled_ = true;
+ str += sizeof(WORST_SYSTEM_PID) - 1;
+ if (!*str) {
+ break;
+ }
+ if (!isspace(*str)) {
+ LOG(ERROR) << "Nothing expected after '~1000/!', but found '" << str << "'";
+ return false;
+ }
+ continue;
+ }
+ if (!*str) {
+ LOG(ERROR) << "Expected UID or PID after '~', but found nothing";
+ return false;
+ }
+ list = &high_priority_prune_;
+ } else {
+ list = &low_priority_prune_;
+ }
+
+ uid_t uid = Prune::UID_ALL;
+ if (isdigit(*str)) {
+ uid = 0;
+ do {
+ uid = uid * 10 + *str++ - '0';
+ } while (isdigit(*str));
+ }
+
+ pid_t pid = Prune::PID_ALL;
+ if (*str == '/') {
+ ++str;
+ if (isdigit(*str)) {
+ pid = 0;
+ do {
+ pid = pid * 10 + *str++ - '0';
+ } while (isdigit(*str));
+ }
+ }
+
+ if (uid == Prune::UID_ALL && pid == Prune::PID_ALL) {
+ LOG(ERROR) << "Expected UID/PID combination, but found none";
+ return false;
+ }
+
+ if (*str && !isspace(*str)) {
+ LOG(ERROR) << "Nothing expected after UID/PID combination, but found '" << str << "'";
+ return false;
+ }
+
+ list->emplace_back(uid, pid);
+ if (!*str) {
+ break;
+ }
+ }
+
+ return true;
+}
+
+std::string PruneList::Format() const {
+ std::vector<std::string> prune_rules;
+
+ if (worst_uid_enabled_) {
+ prune_rules.emplace_back("~!");
+ }
+ if (worst_pid_of_system_enabled_) {
+ prune_rules.emplace_back("~1000/!");
+ }
+ for (const auto& rule : low_priority_prune_) {
+ prune_rules.emplace_back(rule.Format());
+ }
+ for (const auto& rule : high_priority_prune_) {
+ prune_rules.emplace_back("~" + rule.Format());
+ }
+ return android::base::Join(prune_rules, " ");
+}
+
+bool PruneList::IsHighPriority(LogBufferElement* element) const {
+ for (const auto& rule : high_priority_prune_) {
+ if (rule.Matches(element)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PruneList::IsLowPriority(LogBufferElement* element) const {
+ for (const auto& rule : low_priority_prune_) {
+ if (rule.Matches(element)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/logd/PruneList.h b/logd/PruneList.h
new file mode 100644
index 0000000..94de5c5
--- /dev/null
+++ b/logd/PruneList.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <list>
+
+#include "LogBufferElement.h"
+
+class Prune {
+ 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_(uid), pid_(pid) {}
+
+ bool Matches(LogBufferElement* element) const;
+ std::string Format() const;
+
+ uid_t uid() const { return uid_; }
+ pid_t pid() const { return pid_; }
+
+ private:
+ const uid_t uid_;
+ const pid_t pid_;
+};
+
+class PruneList {
+ public:
+ PruneList();
+
+ bool Init(const char* str);
+ std::string Format() const;
+
+ bool IsHighPriority(LogBufferElement* element) const;
+ bool IsLowPriority(LogBufferElement* element) const;
+
+ bool HasHighPriorityPruneRules() const { return !high_priority_prune_.empty(); }
+ bool HasLowPriorityPruneRules() const { return !low_priority_prune_.empty(); }
+
+ bool worst_uid_enabled() const { return worst_uid_enabled_; }
+ bool worst_pid_of_system_enabled() const { return worst_pid_of_system_enabled_; }
+
+ private:
+ std::list<Prune> high_priority_prune_;
+ std::list<Prune> low_priority_prune_;
+
+ bool worst_uid_enabled_;
+ bool worst_pid_of_system_enabled_;
+};
diff --git a/logd/README.property b/logd/README.property
index 6a9369a..ab9c4d4 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -65,8 +65,8 @@
- number - support multipliers (K or M) for convenience. Range is limited
to between 64K and 256M for log buffer sizes. Individual log buffer ids
such as main, system, ... override global default.
-- Pruning filter is of form of a space-separated list of [~][UID][/PID]
- references, where '~' prefix means to blacklist otherwise whitelist. For
- blacklisting, UID or PID may be a '!' to instead reference the chattiest
- client, with the restriction that the PID must be in the UID group 1000
- (system or AID_SYSTEM).
+- Pruning filter rules are specified as UID, UID/PID or /PID. A '~' prefix indicates that elements
+ matching the rule should be pruned with higher priority otherwise they're pruned with lower
+ priority. All other pruning activity is oldest first. Special case ~! represents an automatic
+ pruning for the noisiest UID as determined by the current statistics. Special case ~1000/!
+ represents pruning of the worst PID within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp
index b576ddf..a7a1792 100644
--- a/logd/fuzz/log_buffer_log_fuzzer.cpp
+++ b/logd/fuzz/log_buffer_log_fuzzer.cpp
@@ -97,7 +97,7 @@
size_t data_left = size;
const uint8_t** pdata = &data;
- prune_list.init(nullptr);
+ prune_list.Init(nullptr);
// We want to get pruning code to get called.
log_id_for_each(i) { log_buffer->SetSize(i, 10000); }
diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp
index 1b5f54e..3ffa74e 100644
--- a/toolbox/modprobe.cpp
+++ b/toolbox/modprobe.cpp
@@ -36,7 +36,7 @@
std::cerr << " modprobe [-alrqvsDb] [-d DIR] MODULE [symbol=value][...]" << std::endl;
std::cerr << std::endl;
std::cerr << "Options:" << std::endl;
- std::cerr << " -b: Apply blacklist to module names too" << std::endl;
+ std::cerr << " -b: Apply blocklist to module names too" << std::endl;
std::cerr << " -d: Load modules from DIR, option may be used multiple times" << std::endl;
std::cerr << " -D: Print dependencies for modules only, do not load";
std::cerr << " -h: Print this help" << std::endl;
@@ -59,7 +59,7 @@
std::string module_parameters;
std::vector<std::string> mod_dirs;
modprobe_mode mode = AddModulesMode;
- bool blacklist = false;
+ bool blocklist = false;
bool verbose = false;
int rv = EXIT_SUCCESS;
@@ -72,7 +72,7 @@
check_mode();
break;
case 'b':
- blacklist = true;
+ blocklist = true;
break;
case 'd':
mod_dirs.emplace_back(optarg);
@@ -151,8 +151,8 @@
Modprobe m(mod_dirs);
m.EnableVerbose(verbose);
- if (blacklist) {
- m.EnableBlacklist(true);
+ if (blocklist) {
+ m.EnableBlocklist(true);
}
for (const auto& module : modules) {