有没有办法在Android中获取当前进程名称

Ric*_* Li 29 android

我为我的特定活动设置了一个Android:process =":XX",使其在一个单独的进程中运行.但是当新的活动/进程init时,它将调用我的Application:onCreate(),它包含一些应用程序级初始化.

我正在考虑通过检查当前进程名称来避免重复初始化.

那么有可用的API吗?

谢谢.

Ric*_* Li 27

完整的代码是

    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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 请注意 `manager.getRunningAppProcesses()` 可能会返回 null(而不是像好的设计会要求的空列表)。 (3认同)
  • 它也可能很慢。被警告。 (2认同)

Dav*_*röm 25

ActivityManager解决方案包含一个偷偷摸摸的bug,特别是如果您从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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

编辑:请注意,此解决方案比通过ActivityManager快得多,但如果用户正在运行Xposed或类似操作,则无效.在这种情况下,您可能希望将ActivityManager解决方案作为回退策略.

  • 这很可能是因为您的流程是远程服务.如果调用am.getRunningServices()并遍历RunningServiceInfo对象,您将在info对象的.process字段中的清单中找到您的服务进程以及您为进程提供的名称. (5认同)

Sam*_*Sam 6

从ActivityThread获取

在API 28+,你可以调用Application.getProcessName(),这仅仅是一个公共的包装周围ActivityThread.currentProcessName()

在较旧的平台上,只需ActivityThread.currentProcessName()直接致电即可。

请注意,在API 18之前,该方法被错误地调用,ActivityThread.currentPackageName()但实际上仍然返回了进程

范例程式码

public static String getNameFromActivityThread() {
    if (Build.VERSION.SDK_INT >= 28)
        return Application.getProcessName();
    else {
        // Using the same technique as Application.getProcessName() for older devices
        // Using reflection since ActivityThread is an internal API

        try {
            @SuppressLint("PrivateApi")
            Class<?> activityThread = Class.forName("android.app.ActivityThread");

            // Before API 18, the method was incorrectly named "currentPackageName", but it still returned the process name
            // See https://github.com/aosp-mirror/platform_frameworks_base/commit/b57a50bd16ce25db441da5c1b63d48721bb90687
            String methodName = Build.VERSION.SDK_INT >= 18 ? "currentProcessName" : "currentPackageName";

            Method getProcessName = activityThread.getDeclaredMethod(methodName);
            return (String) getProcessName.invoke(null);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

兼容性

经过测试并致力于

  • 官方模拟器
    • 16
    • 17
    • 18岁
    • 19
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • Q beta 1
  • 真实设备
    • 运行Android 8.1.0的摩托罗拉Moto G5 Plus
    • 运行Android 6.0.1的三星Galaxy S5
    • 索尼Xperia M跑步机Android 7.1.1
    • 运行Sony Android 4.1.2的Sony Xperia M


Mar*_*ouf 5

这是DavidBurström回答的更新.这可以更简洁地写成:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)


ult*_*aon 5

总结使用 Kotlin 获取进程名称的不同方法:

基于/sf/answers/1497258171/ ( /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
        }

Run Code Online (Sandbox Code Playgroud)

基于/sf/answers/3888468951/来自 SDK v.28 (Android P)

  fun getProcessName(): String? = 
    if (VERSION.SDK_INT >= VERSION_CODES.P) Application.getProcessName() else null
Run Code Online (Sandbox Code Playgroud)

基于/sf/answers/3217224111/反射

    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
        }
Run Code Online (Sandbox Code Playgroud)

基于/sf/answers/1374266771/(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
    }
Run Code Online (Sandbox Code Playgroud)