我正在编写一个脚本,我需要在其中提供我的应用程序的 PID。我可以通过以下命令列出所有进程及其 PID,并且可以看到我的应用程序的条目。
adb 外壳 ps
这给了我一个巨大的进程列表。而且我需要一个条目(我可以进一步提供给另一个命令),所以我想用包名过滤这个结果。grep 命令在我的 Windows 机器上不起作用。还尝试了以下命令,但没有帮助。
adb shell ps 名称:my_app_package
从 Android 7.0 开始,通过包名找出进程 ID 的最简单方法是使用pidof
命令:
usage: pidof [-s] [-o omitpid[,omitpid...]] [NAME]...
Print the PIDs of all processes with the given names.
-s single shot, only return one pid.
-o omit PID(s)
像这样运行它:
adb shell pidof my.app.package
在 7.0 之前的 Android 中,人们使用ps
命令,然后使用内置的按comm
值过滤器(对于 android 应用程序是包名称的最后 15 个字符)或grep
命令来解析其输出。如果名称的comm
最后 15 个字符以数字开头并且在grep
Android 4.2 之前默认不包含 ,则过滤器不起作用。但即使在找到合适的工艺线之后,PID
仍需要提取该值。
有多种方法可以做到这一点。以下是如何使用单个sed
命令完成查找进程和提取 PID 的方法:
adb shell "ps | sed -n 's/^[^ ]* *\([0-9]*\).* my\.app\.package$/\1/p'"
同样的问题是sed
直到 Android 6.0 才默认包含它。
但如果您必须使用较旧的设备,您始终可以使用以下 Android 版本独立解决方案。它不使用任何外部命令 - 只是 Android shell 内置:
adb shell "for p in /proc/[0-9]*; do [[ $(<$p/cmdline) = my.app.package ]] && echo ${p##*/}; done"
寻找 PID 的最常见原因是在其他命令中使用它,例如kill
. 假设我们有多个logcat
正在运行的实例,我们希望一次优雅地完成它们。只需将最后一个命令中的echo
替换为:kill -2
adb shell "for p in /proc/[0-9]*; do [[ $(<$p/cmdline) = logcat ]] && kill -2 ${p##*/}; done"
如果从 Linux/OSX shell 运行命令,请替换"
为。'
代替使用adb shell ps
,先进入adb shell
再使用ps
。
一步步:
连接设备(或仿真器)时输入adb shell
命令。
(命令行前缀将shell@android:/ $
在执行此命令之后。)
输入ps | grep <package_name_to_be_filtered>
(即ps | grep com.google
)。
C:> adb shell
shell@android:/ $ ps | grep com.google
u0_a64 3353 2467 903744 52904 ffffffff 00000000 S com.google.process.location
u0_a64 3426 2467 893964 49452 ffffffff 00000000 S com.google.process.gapps
ps 显示的进程可以限制为属于任何给定用户的进程,方法是通过 grep(用于搜索文本的过滤器)管道输出。例如,属于用户名为 adam 的用户的进程可以显示如下:
ps -ef | grep adam
-e 选项生成有关当前运行的每个进程的信息列表。-f 选项生成的列表包含的每个进程的信息项比 -l 选项少。
Alex P. 的回答在技术上回答了“按进程名称查找正在运行的进程 ID ”的问题,而不是“按包名称查找正在运行的进程 ID ”的问题。<activity>
区别是微妙的,并且通过标签中的“android:process”属性体现在进程重命名中。
我担心正确的解决方案会涉及更多内容,您可以阅读 Android Studio 为在此处找到真正的进程名称所做的解决方法。您将在 下看到适用于 pre-Android OreoresolveLegacyPid
和resolveApplicationId
适用于 Android Oreo+ 的相关 shell 脚本:
/** * Asynchronously resolves to the application ID. The application ID is the package name that is * ultimately given to the application on the device, which usually comes from the manifest. * Note that this may be different from {@link ClientData#getClientDescription()} or * {@link ClientData#getPackageName()} due to the manifest containing a process rename XML * option via "android:process". * * <p>When the manifest option is specified, the two aforementioned {@link ClientData }methods * will return the process name, not the application ID. Therefore, this method guarantees the * application ID if it's possible to resolve. Only if it's not possible will this fall back to * using the process name instead. */ private void resolveApplicationId(@NotNull Process process) { myResolverExecutor.execute(() -> { String command = String.format(Locale.US, "stat -c %%u /proc/%d | xargs -n 1 cmd package list packages --uid", process.getPid()); CollectingOutputReceiver receiver = new CollectingOutputReceiver(); try { myIDevice.executeShellCommand(command, receiver); } catch (IOException | TimeoutException | AdbCommandRejectedException | ShellCommandUnresponsiveException e) { Logger.getInstance(Device.class).warn("Could not resolve application ID", e); return; } String output = receiver.getOutput(); if (output.isEmpty()) { return; } Matcher m = PACKAGE_NAME_PATTERN.matcher(output); while (m.find()) { process.addApplicationId(m.group(1)); } }); } @NotNull private Future<Void> resolveLegacyPid(@NotNull String applicationId) { return myResolverExecutor.submit( () -> { // This shell command tries to retrieve the PID associated with a given application ID. // To achieve this goal, it does the following: // // 1) Gets the user name (e.g. u0_a01) using run-as with the application ID and // the whoami command. // 2) Runs the ps command under the application ID to get a list of all running // processes running under the user associated with the given application ID. // The output of ps looks something like: "<user> <pid> ..." // 3) The output of ps is piped into grep/tr/cut to parse out the second parameter, // of each line, which is the PID of each process. // 4) The PID is then used in the readlink command to follow the symbolic links of // the symlinked exe file under the PID's /proc directory. // 5) If the symlink resolves to any of the 32 or 64 bit zygote process, the PID is // printed to the console, serving as the output of the script. String command = String.format( "uid=`run-as %s whoami` && " + "for pid in `run-as %s ps | grep -o \"$uid[[:space:]]\\{1,\\}[[:digit:]]\\{1,\\}\" | tr -s ' ' ' ' | cut -d ' ' -f2`; do " + " if [[ `run-as %s readlink /proc/$pid/exe` == /system/bin/app_process* ]]; then " + " echo $pid; " + " fi; " + "done", applicationId, applicationId, applicationId); CollectingOutputReceiver receiver = new CollectingOutputReceiver(); myIDevice.executeShellCommand(command, receiver); String output = receiver.getOutput(); if (output.isEmpty()) { return null; } String[] lines = output.split("\n"); // We only handle the first return value for now. try { for (String line : lines) { int pid = Integer.parseInt(line.trim()); myPidToProcess.computeIfPresent(pid, (ignored, process) -> { process.addApplicationId(applicationId); return process; }); } } catch (NumberFormatException ignored) { } return null; }); }