Узнать идентификатор запущенного процесса по имени пакета
Я работаю над сценарием, в котором мне нужно предоставить PID моего приложения. Я могу перечислить все процессы с их PID, выполнив следующую команду, и смог увидеть запись моего приложения.
adb shell ps
Это дает мне огромный список процессов. И мне нужна единственная запись (которую я могу дополнительно предоставить другой команде), поэтому я хочу отфильтровать эти результаты по имени пакета. Команда grep не работает на моей машине с Windows. Также попробовал следующую команду, но это не помогло.
имя оболочки adb ps:my_app_package
3 ответа
Начиная с Android 7.0, самый простой способ узнать идентификатор процесса по имени пакета - использовать 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
В Android до 7.0 люди использовали ps
команда, а затем проанализировал свой вывод с помощью встроенного фильтра comm
значение (которое для приложений Android - это последние 15 символов имени пакета) или grep
команда. comm
Фильтр не работал, если последние 15 символов имени начинались с цифры и grep
не был включен по умолчанию до Android 4.2. Но даже после того, как была найдена правильная технологическая линия, PID
значение еще необходимо извлечь.
Было несколько способов сделать это. Вот как можно найти процесс и извлечь PID с помощью одного sed
команда:
adb shell "ps | sed -n 's/^[^ ]* *\([0-9]*\).* my\.app\.package$/\1/p'"
Опять проблема в том, что sed
был не включен по умолчанию до Android 6.0.
Но если вам нужно использовать старое устройство, вы всегда можете использовать следующее решение, не зависящее от версии Android. Он не использует никаких внешних команд - только встроенные модули оболочки Android:
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.
Вместо того, чтобы использовать 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. технически отвечает на вопрос "Узнать идентификатор запущенного процесса по имени процесса", а не "Узнать идентификатор запущенного процесса по имени пакета". Разница незначительна и проявляется в переименовании процессов через атрибут android:process в<activity>
тег.
Я боюсь, что правильное решение является немного более вовлечено, и вы можете прочитать в обходной Android - студия сделала, чтобы найти истинное имя процесса здесь. Вы увидите соответствующий сценарий оболочки для версий до Android Oreo в разделеresolveLegacyPid
, а также resolveApplicationId
для Android Oreo+:
/** * 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; }); }