Is there a way to get current process name in Android
AndroidAndroid Problem Overview
I set an Android:process=":XX" for my particular activity to make it run in a separate process. However when the new activity/process init, it will call my Application:onCreate() which contains some application level initialization.
I'm thinking of avoiding duplication initialization by checking current process name.
So is there an API available?
Thanks.
Android Solutions
Solution 1 - Android
Full code is
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;
}
}
Solution 2 - Android
The ActivityManager solution contains a sneaky bug, particularly if you check your own process name from your Application object. Sometimes, the list returned from getRunningAppProcesses simply doesn't contain your own process, raising a peculiar existential issue.
The way I solve this is
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: Please notice that this solution is much faster than going through the ActivityManager but does not work if the user is running Xposed or similar. In that case you might want to do the ActivityManager solution as a fallback strategy.
Solution 3 - Android
Get it from ActivityThread
In API 28+, you can call Application.getProcessName()
, which is just a public wrapper around ActivityThread.currentProcessName()
.
On older platforms, just call ActivityThread.currentProcessName()
directly.
Note that prior to API 18, the method was incorrectly called ActivityThread.currentPackageName()
but still in fact returned the process name.
Example code
public static String getProcessName() {
if (Build.VERSION.SDK_INT >= 28)
return Application.getProcessName();
// 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);
}
}
Compatibility
Tested and working on
-
Official emulator
- 16
- 17
- 18
- 19
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- Q beta 1
-
Real devices
- Motorola Moto G5 Plus running Android 8.1.0
- Samsung Galaxy S5 running Android 6.0.1
- Sony Xperia M running stock Android 7.1.1
- Sony Xperia M running Sony Android 4.1.2
Solution 4 - Android
This is an update to David Burström's answer. This can be written far more concisely as:
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);
}
}
Solution 5 - Android
I have more efficient method, you don't need IPC to ActivityManagerService and poll the Running process, or read the file.You can call this method from your custom Application class;
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 is already send the process infor to ActivityThread when process is start.(ActivityThread.main-->attach()-->IActivityManager.attachApplication--IPC-->ActivityManagerService-->ApplicationThread.bindApplication)
ApplicationThread:
public final void bindApplication(String processName,***) {
//***
AppBindData data = new AppBindData();
data.processName = processName;
//**
}
When we called getProcessName, it will finally deliver to AppBindData object. So we can easily and efficient get current process name;
Solution 6 - Android
To wrap up different approaches of getting process name using Kotlin:
Based on the 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
}
Based on https://stackoverflow.com/a/55549556/3256989 (from SDK v.28 (Android P)):
fun getProcessName(): String? =
if (VERSION.SDK_INT >= VERSION_CODES.P) Application.getProcessName() else null
Based on https://stackoverflow.com/a/45960344/3256989 (reflection):
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
}
Based on 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
}
Solution 7 - Android
First, get the current process pid. Second, list all processes of running. Finally, if it has equal pid, it's ok, or it's false.
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;
}
Solution 8 - Android
Since Android Pie (SDK v28), there is actually an official method for this in the Application class:
public static String getProcessName ()
Solution 9 - Android
If I've understood your question correctly, you should be able to use ActivityManager, as per this thread.
Solution 10 - Android
There is a method in ActivityThread class, You may use reflection to get the current processName. You don't need any loop or tricks. The performance is best compares to other solution. The limitation is you can only get your own process name. It's not a big deal since it covers most usage cases.
val activityThreadClass = XposedHelpers.findClass("android.app.ActivityThread", param.classLoader)
val activityThread = XposedHelpers.callStaticMethod(activityThreadClass, "currentActivityThread")
val processName = XposedHelpers.callStaticMethod(activityThreadClass, "currentProcessName")
Solution 11 - Android
The main process's father process should be zygote, this should be the accurate solution
- first judge the process's name from /proc/pid/cmdline which should equal to package name
- judge the process's father whether Zygote(why do this? because some APP have different processes with same name)