我为我的特定活动设置了一个Android:process =“:XX”,使其在一个单独的进程中运行。 但是当新的活动/进程init时,它将调用我的Application:onCreate(),其中包含一些应用程序级初始化。
我正在考虑通过检查当前进程名称来避免重复初始化。
那么有API吗?
感谢。
答案 0 :(得分: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;
}
}
答案 1 :(得分:25)
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();
}
}
编辑:请注意,此解决方案比通过ActivityManager快得多,但如果用户正在运行Xposed或类似操作,则无效。在这种情况下,您可能希望将ActivityManager解决方案作为后备策略。
答案 2 :(得分: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);
}
}
答案 3 :(得分:4)
我有更有效的方法,你不需要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已经将进程infor发送到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对象。 因此,我们可以轻松高效地获取当前进程名称;
答案 4 :(得分:2)
如果我已正确理解您的问题,您应该可以按照ActivityManager使用this thread。
答案 5 :(得分:2)
首先,获取当前进程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;
}
答案 6 :(得分:2)
在API 28+中,您可以调用Application.getProcessName()
和is just a public wrapper之间的ActivityThread.currentProcessName()
。
在较旧的平台上,只需直接致电ActivityThread.currentProcessName()
。
请注意,在API 18之前,the method was incorrectly called ActivityThread.currentPackageName()
but still in fact returned the process name。
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);
}
}
}
经过测试并正在研究
答案 7 :(得分:1)
ActivityThread class中有一个方法,您可以使用反射来获取当前的processName。你不需要任何循环或技巧。与其他解决方案相比,性能最佳。限制是您只能获得自己的进程名称。这不是什么大问题,因为它涵盖了大多数使用案例。
val activityThreadClass = XposedHelpers.findClass("android.app.ActivityThread", param.classLoader)
val activityThread = XposedHelpers.callStaticMethod(activityThreadClass, "currentActivityThread")
val processName = XposedHelpers.callStaticMethod(activityThreadClass, "currentProcessName")
答案 8 :(得分:1)
自Android Pie(SDK v28)起, Application 类中实际上有一个官方方法:
public static String getProcessName ()
答案 9 :(得分:0)
主进程的父进程应该是合子,这应该是准确的解决方案
答案 10 :(得分:0)
总结使用Kotlin获取进程名称的不同方法:
基于https://stackoverflow.com/a/21389402/3256989( / 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
}
基于https://stackoverflow.com/a/55549556/3256989(来自SDK版本28(Android P)的 ):
fun getProcessName(): String? =
if (VERSION.SDK_INT >= VERSION_CODES.P) Application.getProcessName() else null
基于https://stackoverflow.com/a/45960344/3256989(反射):
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
}
基于https://stackoverflow.com/a/19632382/3256989( 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
}