Ответ 1
Если я правильно понял ваш вопрос, вы должны использовать ActivityManager, согласно этот поток.
Я установил Android: process = ": XX" для своей конкретной деятельности, чтобы запустить ее в отдельном процессе. Однако, когда новый процесс/процесс init, он вызовет мое приложение: onCreate(), которое содержит некоторую инициализацию уровня приложения.
Я думаю об избежании инициализации дублирования, проверяя текущее имя процесса.
Так есть ли доступный API?
Спасибо.
Если я правильно понял ваш вопрос, вы должны использовать ActivityManager, согласно этот поток.
Полный код
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;
}
}
Решение 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 в качестве резервной стратегии.
Это обновление для ответа Дэвида Бурстрема. Это можно записать гораздо более кратко:
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);
}
}
У меня более эффективный метод, вам не нужно 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. Таким образом, мы можем легко и эффективно получать текущее имя процесса;
Во-первых, получите текущий процесс 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;
}
Существует метод класс ActivityThread, вы можете использовать отражение, чтобы получить текущее имя процесса. Вам не нужны никакие петли или трюки. Производительность лучше всего сравнить с другим решением. Ограничение - вы можете получить только собственное имя процесса. Это не имеет большого значения, поскольку он охватывает большинство случаев использования.
val activityThreadClass = XposedHelpers.findClass("android.app.ActivityThread", param.classLoader)
val activityThread = XposedHelpers.callStaticMethod(activityThreadClass, "currentActivityThread")
val processName = XposedHelpers.callStaticMethod(activityThreadClass, "currentProcessName")
Основным процессом отца должен быть зигот, это должно быть точное решение
Начиная с Android Pie (SDK v28), в классе Application для этого существует официальный метод:
public static String getProcessName()
Чтобы обернуть различные подходы получения имени процесса с помощью 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
}