Подтвердить что ты не робот

Есть ли способ получить имя текущего процесса в Android

Я установил Android: process = ": XX" для своей конкретной деятельности, чтобы запустить ее в отдельном процессе. Однако, когда новый процесс/процесс init, он вызовет мое приложение: onCreate(), которое содержит некоторую инициализацию уровня приложения.

Я думаю об избежании инициализации дублирования, проверяя текущее имя процесса.

Так есть ли доступный API?

Спасибо.

4b9b3361

Ответ 1

Если я правильно понял ваш вопрос, вы должны использовать ActivityManager, согласно этот поток.

Ответ 2

Полный код

    String currentProcName = "";
    int pid = android.os.Process.myPid();
    ActivityManager manager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningAppProcessInfo processInfo : manager.getRunningAppProcesses())
    {
        if (processInfo.pid == pid)
        {
            currentProcName = processInfo.processName;
            return;
        }
    }

Ответ 3

Решение ActivityManager содержит скрытую ошибку, особенно если вы проверяете свое собственное имя процесса из вашего объекта Application. Иногда список, возвращенный из getRunningAppProcesses, просто не содержит вашего собственного процесса, создавая особую экзистенциальную проблему.

Как я решаю это,

    BufferedReader cmdlineReader = null;
    try {
        cmdlineReader = new BufferedReader(new InputStreamReader(
            new FileInputStream(
                "/proc/" + android.os.Process.myPid() + "/cmdline"),
            "iso-8859-1"));
        int c;
        StringBuilder processName = new StringBuilder();
        while ((c = cmdlineReader.read()) > 0) {
            processName.append((char) c);
        }
        return processName.toString();
    } finally {
        if (cmdlineReader != null) {
            cmdlineReader.close();
        }
    }

EDIT: обратите внимание, что это решение намного быстрее, чем через ActivityManager, но не работает, если пользователь запускает Xposed или аналогичный. В этом случае вы можете сделать решение ActivityManager в качестве резервной стратегии.

Ответ 4

Это обновление для ответа Дэвида Бурстрема. Это можно записать гораздо более кратко:

public String get() {
  final File cmdline = new File("/proc/" + android.os.Process.myPid() + "/cmdline");
  try (BufferedReader reader = new BufferedReader(new FileReader(cmdline))) {
    return reader.readLine();
  } catch (IOException e) {
    throw new RuntimeException(e);
  }
}

Ответ 5

У меня более эффективный метод, вам не нужно IPC для ActivityManagerService и опросить процесс выполнения или прочитать файл. Вы можете вызвать этот метод из своего пользовательского класса Application;

 private String getProcessName(Application app) {
    String processName = null;
    try {
        Field loadedApkField = app.getClass().getField("mLoadedApk");
        loadedApkField.setAccessible(true);
        Object loadedApk = loadedApkField.get(app);

        Field activityThreadField = loadedApk.getClass().getDeclaredField("mActivityThread");
        activityThreadField.setAccessible(true);
        Object activityThread = activityThreadField.get(loadedApk);

        Method getProcessName = activityThread.getClass().getDeclaredMethod("getProcessName", null);
        processName = (String) getProcessName.invoke(activityThread, null);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return processName;
}

ActivityManagerService уже отправляет информацию о процессе в ActivityThread, когда процесс запускается. (ActivityThread.main → attach() → IActivityManager.attachApplication - IPC → ActivityManagerService → ApplicationThread.bindApplication)

ApplicationThread:
public final void bindApplication(String processName,***) {
    //***
    AppBindData data = new AppBindData();
    data.processName = processName;
    //**
}

Когда мы вызываем getProcessName, он, наконец, доставляет объект AppBindData. Таким образом, мы можем легко и эффективно получать текущее имя процесса;

Ответ 6

Во-первых, получите текущий процесс pid. Во-вторых, перечислите все процессы запуска. Наконец, если у него одинаковый pid, все в порядке или неверно.

public static String getProcessName(Context context) {
    int pid = android.os.Process.myPid();
    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> infos = manager.getRunningAppProcesses();
    if (infos != null) {
        for (ActivityManager.RunningAppProcessInfo processInfo : infos) {
            if (processInfo.pid == pid) {
                return processInfo.processName;
            }
        }
    }
    return null;
}

Ответ 7

Существует метод класс ActivityThread, вы можете использовать отражение, чтобы получить текущее имя процесса. Вам не нужны никакие петли или трюки. Производительность лучше всего сравнить с другим решением. Ограничение - вы можете получить только собственное имя процесса. Это не имеет большого значения, поскольку он охватывает большинство случаев использования.

    val activityThreadClass = XposedHelpers.findClass("android.app.ActivityThread", param.classLoader)
    val activityThread = XposedHelpers.callStaticMethod(activityThreadClass, "currentActivityThread")
    val processName = XposedHelpers.callStaticMethod(activityThreadClass, "currentProcessName")

Ответ 8

Основным процессом отца должен быть зигот, это должно быть точное решение

  1. сначала оцените имя процесса из /proc/pid/cmdline, которое должно совпадать с именем пакета
  2. судить отец ли Zygote (почему это? потому что некоторые приложения имеют разные процессы с одинаковым именем)

Ответ 9

Начиная с Android Pie (SDK v28), в классе Application для этого существует официальный метод:

public static String getProcessName()

Посмотреть документы

Ответ 10

Чтобы обернуть различные подходы получения имени процесса с помощью Kotlin:

На основании fooobar.com/info/238393/... (/proc/pid/cmdline):

    fun getProcessName(): String? =
        try {
            FileInputStream("/proc/${Process.myPid()}/cmdline")
                .buffered()
                .readBytes()
                .filter { it > 0 }
                .toByteArray()
                .inputStream()
                .reader(Charsets.ISO_8859_1)
                .use { it.readText() }
        } catch (e: Throwable) {
            null
        }

На основе fooobar.com/info/238393/... (из SDK v.28 (Android P)):

  fun getProcessName(): String? = 
    if (VERSION.SDK_INT >= VERSION_CODES.P) Application.getProcessName() else null

На основании fooobar.com/info/238393/... (отражение):

    fun getProcessName(): String? =
        try {
            val loadedApkField = application.javaClass.getField("mLoadedApk")
            loadedApkField.isAccessible = true
            val loadedApk = loadedApkField.get(application)

            val activityThreadField = loadedApk.javaClass.getDeclaredField("mActivityThread")
            activityThreadField.isAccessible = true
            val activityThread = activityThreadField.get(loadedApk)

            val getProcessName = activityThread.javaClass.getDeclaredMethod("getProcessName")
            getProcessName.invoke(activityThread) as String
        } catch (e: Throwable) {
            null
        }

На основе fooobar.com/info/238393/... (ActivityManager):

    fun getProcessName(): String? {
        val pid = Process.myPid()
        val manager = appContext.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
        return manager?.runningAppProcesses?.filterNotNull()?.firstOrNull { it.pid == pid }?.processName
    }