Toybox combines the most common Linux command line utilities together into a single BSD-licensed executable that's simple, small, fast, reasonably standards-compliant, and powerful enough to turn Android into a development environment. See the links on the left for details.
2.1 Ps -A 显示的进程名
ps -A 和 ps -e 执行的是同一个动作,都是显示所有进程。
-A All
-e Synonym for -A
下面是 ps -A 的一个示例输出。
# ps -A
USER PID PPID VSZ RSS WCHAN ADDR S NAME
root 1 0 13001184 14608 do_epoll_+ 0 S init
root 2 0 0 0 kthreadd 0 S [kthreadd]
root 3 2 0 0 rescuer_t+ 0 I [rcu_gp]
...
logd 278 1 13036024 7516 __do_sys_+ 0 S logd
lmkd 279 1 13060480 7372 do_epoll_+ 0 S lmkd
system 1383 1 13504456 60264 do_epoll_+ 0 S surfaceflinger
...
u0_a150 5280 1105 16943368 103628 do_freeze+ 0 S com.android.mms
u0_a190 5334 1105 16966004 134128 do_freeze+ 0 S com.android.permissioncontroller
u0_a37 5352 1105 16778080 100784 do_freeze+ 0 S com.android.providers.calendar
// String fields (-1 is procpid->str, rest are str+offset[1-slot])
{"TTY", "Controlling terminal", -8, -2},
{"WCHAN", "Wait location in kernel", -6, -3},
{"LABEL", "Security label", -30, -4},
{"COMM", "EXE filename (/proc/PID/exe)", -27, -5},
{"NAME", "Process name (PID's argv[0])", -27, -7},
{"COMMAND", "EXE path (/proc/PID/exe)", -27, -5},
{"CMDLINE", "Command line (argv[])", -27, -6},
{"ARGS", "CMDLINE minus initial path", -27, -6},
{"CMD", "Thread name (/proc/TID/stat:2)", -15, -1},
Process name 按照上述的注释,可以理解为 argv[0] 指向的字符串。这个数据从 /proc/[pid]/cmdline 文件节点读出,但需要经过一些特殊的处理。
[/external/toybox/toys/posix/ps.c]
struct {char *name; // Path under /proc/$PID directorylonglong bits; // Only fetch extra data if an -o field is displaying it
} fetch[] = {
// sources for procpid->offset[] data
{"fd/", _PS_TTY}, {"wchan", _PS_WCHAN}, {"attr/current", _PS_LABEL},
{"exe", _PS_COMMAND|_PS_COMM}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_NAME},
{"", _PS_NAME}
};
(2) comm %s
The filename of the executable, in parentheses.
Strings longer than TASK_COMM_LEN (16) characters
(including the terminating null byte) are silently
truncated. This is visible whether or not the
executable is swapped out.
Exec 执行之后,zygote 的进程名和主线程名均会被设置为 app_process64,也即可执行文件的名称。不过 main 函数内部会对它们进行修改,通过 setArgv0 函数。
[/frameworks/base/core/jni/AndroidRuntime.cpp]
voidAndroidRuntime::setArgv0(constchar* argv0, bool setProcName){
// Set the kernel's task name, for as much of the name as we can fit.// The kernel's TASK_COMM_LEN minus one for the terminating NUL == 15.if (setProcName) {
int len = strlen(argv0);
if (len < 15) {
pthread_setname_np(pthread_self(), argv0);
} else {
pthread_setname_np(pthread_self(), argv0 + len - 15);
}
}
// Directly change the memory pointed to by argv[0].memset(mArgBlockStart, 0, mArgBlockLength);
strlcpy(mArgBlockStart, argv0, mArgBlockLength);
// Let bionic know that we just did that, because __progname points// into argv[0] (https://issuetracker.google.com/152893281).setprogname(mArgBlockStart);
}
voidSetThreadName(constchar* thread_name){
bool hasAt = false;
bool hasDot = false;
constchar* s = thread_name;
while (*s) {
if (*s == '.') {
hasDot = true;
} elseif (*s == '@') {
hasAt = true;
}
s++;
}
int len = s - thread_name;
if (len < 15 || hasAt || !hasDot) {
s = thread_name;
} else {
s = thread_name + len - 15;
}
#if defined(__linux__) || defined(_WIN32)// pthread_setname_np fails rather than truncating long strings.char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded in the kernel.strncpy(buf, s, sizeof(buf)-1);
buf[sizeof(buf)-1] = '\0';
errno = pthread_setname_np(pthread_self(), buf);
if (errno != 0) {
PLOG(WARNING) << "Unable to set the name of current thread to '" << buf << "'";
}
#else// __APPLE__pthread_setname_np(thread_name);
#endif
}
// Make it easier to debug audit logs by setting the main thread's name to the// nice name rather than "app_process".if (nice_name.has_value()) {
SetThreadName(nice_name.value());
} elseif (is_system_server) {
SetThreadName("system_server");
}
不过需要注意的是,这个 SetThreadName 只会修改 task_struct.comm,而不会修改 tlsPtr_.name。因此如果我们将这个线程看作 pthread,那么它的名称就是包名;可是如果我们将它看作 ART thread,那么它的名称就是"main"。
staticvoidDumpCmdLine(std::ostream& os){
#if defined(__linux__)// Show the original command line, and the current command line too if it's changed.// On Android, /proc/self/cmdline will have been rewritten to something like "system_server".// Note: The string "Cmd line:" is chosen to match the format used by debuggerd.
std::string current_cmd_line;
if (android::base::ReadFileToString("/proc/self/cmdline", ¤t_cmd_line)) {
current_cmd_line.resize(current_cmd_line.find_last_not_of('\0') + 1); // trim trailing '\0's
std::replace(current_cmd_line.begin(), current_cmd_line.end(), '\0', ' ');
os << "Cmd line: " << current_cmd_line << "\n";
constchar* stashed_cmd_line = GetCmdLine();
if (stashed_cmd_line != nullptr && current_cmd_line != stashed_cmd_line
&& strcmp(stashed_cmd_line, "<unset>") != 0) {
os << "Original command line: " << stashed_cmd_line << "\n";
}
}
#else
os << "Cmd line: " << GetCmdLine();
#endif
}
std::vector<std::string> get_command_line(pid_t pid){
std::vector<std::string> result;
std::string cmdline;
android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid), &cmdline);
auto it = cmdline.cbegin();
while (it != cmdline.cend()) {
// string::iterator is a wrapped type, not a raw char*.auto terminator = std::find(it, cmdline.cend(), '\0');
result.emplace_back(it, terminator);
it = std::find_if(terminator, cmdline.cend(), [](char c) { return c != '\0'; });
}
if (result.empty()) {
result.emplace_back("<unknown>");
}
return result;
}