Reputation: 1477
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.
Upvotes: 53
Views: 49439
Reputation: 42357
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.
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);
}
}
Tested and working on
Upvotes: 36
Reputation: 2400
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
}
Upvotes: 5
Reputation: 2032
Since Android Pie (SDK v28), there is actually an official method for this in the Application class:
public static String getProcessName ()
Upvotes: 2
Reputation: 29
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;
}
Upvotes: 2
Reputation: 1
The main process's father process should be zygote, this should be the accurate solution
Upvotes: 0
Reputation: 1477
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;
}
}
Upvotes: 34
Reputation: 2597
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")
Upvotes: 1
Reputation: 577
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;
Upvotes: 4
Reputation: 30990
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);
}
}
Upvotes: 4
Reputation: 1610
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.
Upvotes: 29
Reputation: 439
If I've understood your question correctly, you should be able to use ActivityManager, as per this thread.
Upvotes: 1