Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - How to detect when 3d party app is starting

I'm currently developing an app for tablets which will show commercials in stores. I need to add a password protection for the settings application. To achieve this I need to detect that the settings app is started in a background service. For devices with Android below API 21 this can be done with getRunningTasks(). Unfortunately this method is deprecated now. I tried achieving my goal with this answer, but things aren't working as I need. I'm trying to listen for V/WindowManager( 740): Adding window Window{1f4535ef u0 com.android.settings/com.android.settings.Settings} at 9 of 16 (before Window{e14eed2 u0 Starting com.android.settings}) but I can't see it as an output. I'm using the code from the answer I referenced above. Instead of Toasting it I'm printing it in the logcat.

Can you tell me how my goal can be achieved for android versions above API 21? I know it is possible because apps like Smart AppLock does it. Thanks in advance!

like image 778
dephinera Avatar asked Sep 12 '15 08:09

dephinera


People also ask

How do you detect when an Android app goes to the background and come back to the foreground?

The onPause() and onResume() methods are called when the application is brought to the background and into the foreground again. However, they are also called when the application is started for the first time and before it is killed. You can read more in Activity.

What is Restrict background activity?

Android 10 (API level 29) and higher place restrictions on when apps can start activities when the app is running in the background. These restrictions help minimize interruptions for the user and keep the user more in control of what's shown on their screen.

What is physical activity permission on Android?

Physical activity recognition permission. ACTIVITY_RECOGNITION runtime permission for apps that need to detect the user's step count or classify the user's physical activity, such as walking, biking, or moving in a vehicle. This is designed to give users visibility of how device sensor data is used in Settings.


1 Answers

It currently is not possible to get the foreground app on Android 5.1.1+ unless you are granted the system level permission android.permission.PACKAGE_USAGE_STATS. Note that several major vendors have removed the system activity that grants access to the UsageStats API from their devices. This means that apps on those devices can never acquire the necessary permission. This may change with a system update.

You mentioned that Smart Lock (App Protector) can detect the current foreground activity on Android M. The first time you open Smart Lock (or similar apps) you are prompted to grant the PACKAGE_USAGE_STATS permission. So we can conclude that they are relying on UsageStatsManager to get the foreground application.

I have tried finding a workaround (hack) to get the foreground app on Android M without a system level permission. Please read and try out my script in my answer here: Android 5.1.1 and above - getRunningAppProcesses() returns my application package only


Logcat

Unless you have root permission, reading the logcat to get the foreground application will not work. Reading the logcat since Jelly Bean only returns log messages from your application only.


Useful links:

How to check if "android.permission.PACKAGE_USAGE_STATS" permission is given?

How to use UsageStatsManager?

https://code.google.com/p/android-developer-preview/issues/detail?id=2347


Edit:

After digging through Android source I wrote the following code to get the foreground app on Android M without any permissions. I have only tested it on a Nexus 9 running the latest developer preview. Please copy and paste the code into a class in your project and test it out by calling the static method getForegroundApp():

/** first app user */
public static final int AID_APP = 10000;

/** offset for uid ranges for each user */
public static final int AID_USER = 100000;

public static String getForegroundApp() {
  File[] files = new File("/proc").listFiles();
  int lowestOomScore = Integer.MAX_VALUE;
  String foregroundProcess = null;

  for (File file : files) {
    if (!file.isDirectory()) {
      continue;
    }

    int pid;
    try {
      pid = Integer.parseInt(file.getName());
    } catch (NumberFormatException e) {
      continue;
    }

    try {
      String cgroup = read(String.format("/proc/%d/cgroup", pid));

      String[] lines = cgroup.split("\n");

      if (lines.length != 2) {
        continue;
      }

      String cpuSubsystem = lines[0];
      String cpuaccctSubsystem = lines[1];

      if (!cpuaccctSubsystem.endsWith(Integer.toString(pid))) {
        // not an application process
        continue;
      }

      if (cpuSubsystem.endsWith("bg_non_interactive")) {
        // background policy
        continue;
      }

      String cmdline = read(String.format("/proc/%d/cmdline", pid));

      if (cmdline.contains("com.android.systemui")) {
        continue;
      }

      int uid = Integer.parseInt(
          cpuaccctSubsystem.split(":")[2].split("/")[1].replace("uid_", ""));
      if (uid >= 1000 && uid <= 1038) {
        // system process
        continue;
      }

      int appId = uid - AID_APP;
      int userId = 0;
      // loop until we get the correct user id.
      // 100000 is the offset for each user.
      while (appId > AID_USER) {
        appId -= AID_USER;
        userId++;
      }

      if (appId < 0) {
        continue;
      }

      // u{user_id}_a{app_id} is used on API 17+ for multiple user account support.
      // String uidName = String.format("u%d_a%d", userId, appId);

      File oomScoreAdj = new File(String.format("/proc/%d/oom_score_adj", pid));
      if (oomScoreAdj.canRead()) {
        int oomAdj = Integer.parseInt(read(oomScoreAdj.getAbsolutePath()));
        if (oomAdj != 0) {
          continue;
        }
      }

      int oomscore = Integer.parseInt(read(String.format("/proc/%d/oom_score", pid)));
      if (oomscore < lowestOomScore) {
        lowestOomScore = oomscore;
        foregroundProcess = cmdline;
      }

    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  return foregroundProcess;
}

private static String read(String path) throws IOException {
  StringBuilder output = new StringBuilder();
  BufferedReader reader = new BufferedReader(new FileReader(path));
  output.append(reader.readLine());
  for (String line = reader.readLine(); line != null; line = reader.readLine()) {
    output.append('\n').append(line);
  }
  reader.close();
  return output.toString();
}
like image 196
Jared Rummler Avatar answered Oct 19 '22 06:10

Jared Rummler