5

In my application I have local service, which needs to be run in separate process. It is specified as

<service android:name=".MyService" android:process=":myservice"></service>

in AndroidManifest.xml. I also subclass Application object and want to detect in it's onCreate method when it is called by ordinary launch and when by myservice launch. The only working solution that I have found is described by

https://stackoverflow.com/a/28907058/2289482

But I don't want to get all running processes on device and iterate over them. I try to use getApplicationInfo().processName from Context, but unfortunately it always return the same String, while the solution in the link above return: myPackage, myPackage:myservice. I don't need processName at the first place, but some good solution to determine when onCreate method is called by ordinary launch and when by myservice launch. May be it can be done by applying some kind of tag or label somewhere, but i didn't find how to do it.

Community
  • 1
  • 1
user2289482
  • 95
  • 1
  • 7
  • The linked mechanism is what everyone is using. This only happens once, when your application is started. Why can't you use this mechanism? – David Wasser Jun 29 '15 at 16:54
  • The linked solution means that we iterate over all running processes on device only to get information about current process. Ordinary app don't request all running processes - this function is needed by custom ProcessManager or some Utility Program. – user2289482 Jul 07 '15 at 10:30

3 Answers3

2

You can use this code to get your process name:

    int myPid = android.os.Process.myPid(); // Get my Process ID
    InputStreamReader reader = null;
    try {
        reader = new InputStreamReader(
                new FileInputStream("/proc/" + myPid + "/cmdline"));
        StringBuilder processName = new StringBuilder();
        int c;
        while ((c = reader.read()) > 0) {
            processName.append((char) c);
        }
        // processName.toString() is my process name!
        Log.v("XXX", "My process name is: " + processName.toString());
    } catch (Exception e) {
        // ignore
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (Exception e) {
                // Ignore
            }
        }
    }
David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • Thank you, this solution is working for me. It is somehow low-level, but it is definitely better than iterating over all running processes of the system. – user2289482 Jul 12 '15 at 08:28
  • 1
    [This answer](http://stackoverflow.com/a/21389402/238753) says this technique doesn't work if the user is running Xposed. Have you run into any problems using this technique in the wild? – Sam Sep 02 '15 at 10:08
  • @Sam we don't have any problems using this technique because we know exactly what devices our users are using, and none of them are using anything other than standard Android. – David Wasser Sep 13 '15 at 20:22
2

From Acra sources. The same way as above answer but presents useful methods

private static final String ACRA_PRIVATE_PROCESS_NAME= ":acra";

/**
 * @return true if the current process is the process running the SenderService.
 *          NB this assumes that your SenderService is configured to used the default ':acra' process.
 */
public static boolean isACRASenderServiceProcess() {
    final String processName = getCurrentProcessName();
    if (ACRA.DEV_LOGGING) log.d(LOG_TAG, "ACRA processName='" + processName + '\'');
    //processName sometimes (or always?) starts with the package name, so we use endsWith instead of equals
    return processName != null && processName.endsWith(ACRA_PRIVATE_PROCESS_NAME);
}

@Nullable
private static String getCurrentProcessName() {
    try {
        return IOUtils.streamToString(new FileInputStream("/proc/self/cmdline")).trim();
    } catch (IOException e) {
        return null;
    }
}

private static final Predicate<String> DEFAULT_FILTER = new Predicate<String>() {
    @Override
    public boolean apply(String s) {
        return true;
    }
};
private static final int NO_LIMIT = -1;

public static final int DEFAULT_BUFFER_SIZE_IN_BYTES = 8192;

/**
 * Reads an InputStream into a string
 *
 * @param input  InputStream to read.
 * @return the String that was read.
 * @throws IOException if the InputStream could not be read.
 */
@NonNull
public static String streamToString(@NonNull InputStream input) throws IOException {
    return streamToString(input, DEFAULT_FILTER, NO_LIMIT);
}

/**
 * Reads an InputStream into a string
 *
 * @param input  InputStream to read.
 * @param filter Predicate that should return false for lines which should be excluded.
 * @param limit the maximum number of lines to read (the last x lines are kept)
 * @return the String that was read.
 * @throws IOException if the InputStream could not be read.
 */
@NonNull
public static String streamToString(@NonNull InputStream input, Predicate<String> filter, int limit) throws IOException {
    final BufferedReader reader = new BufferedReader(new InputStreamReader(input), ACRAConstants.DEFAULT_BUFFER_SIZE_IN_BYTES);
    try {
        String line;
        final List<String> buffer = limit == NO_LIMIT ? new LinkedList<String>() : new BoundedLinkedList<String>(limit);
        while ((line = reader.readLine()) != null) {
            if (filter.apply(line)) {
                buffer.add(line);
            }
        }
        return TextUtils.join("\n", buffer);
    } finally {
        safeClose(reader);
    }
}

/**
 * Closes a Closeable.
 *
 * @param closeable Closeable to close. If closeable is null then method just returns.
 */
public static void safeClose(@Nullable Closeable closeable) {
    if (closeable == null) return;

    try {
        closeable.close();
    } catch (IOException ignored) {
        // We made out best effort to release this resource. Nothing more we can do.
    }
}
Vlad
  • 7,997
  • 3
  • 56
  • 43
1

You can use the next method

@Nullable
public static String getProcessName(Context context) {
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningAppProcessInfo processInfo : activityManager.getRunningAppProcesses()) {
        if (processInfo.pid == android.os.Process.myPid()) {
            return processInfo.processName;
        }
    }
    return null;
}
yoAlex5
  • 29,217
  • 8
  • 193
  • 205