Android - 如何检测3d party应用程序何时启动

时间:2015-09-12 08:49:44

标签: android password-protection android-5.1.1-lollipop

我目前正在开发一款适用于平板电脑的应用,可以在商店中展示广告。我需要为设置应用程序添加密码保护。为此,我需要检测设置应用程序是在后台服务中启动的。对于Android版本低于API 21的设备,可以使用getRunningTasks()完成此操作。不幸的是,此方法现已弃用。我尝试用this answer来实现我的目标,但事情并没有按照我的需要运作。我试图听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}),但我无法将其视为输出。我使用上面引用的答案中的代码。而不是烘烤它我在logcat中打印它。

你能告诉我如何在API 21以上的Android版本上实现我的目标吗?我知道这是可能的,因为像Smart AppLock这样的应用程序可以实现。提前谢谢!

1 个答案:

答案 0 :(得分:7)

除非您被授予系统级权限android.permission.PACKAGE_USAGE_STATS,否则目前无法在Android 5.1.1+上获取前台应用。请注意,几个主要供应商已删除了允许从其设备访问UsageStats API的系统活动。这意味着这些设备上的应用程序永远无法获得必要的权限。这可能会随系统更新而改变。

您提到Smart Lock (App Protector)可以检测Android M上的当前前台活动。首次打开Smart Lock(或类似应用)时,系统会提示您授予PACKAGE_USAGE_STATS权限。因此,我们可以得出结论,他们依靠UsageStatsManager来获取前台应用程序。

我尝试在没有系统级权限的情况下找到解决方法(hack)来获取Android M上的前台应用。请在我的答案中阅读并试用我的脚本:Android 5.1.1 and above - getRunningAppProcesses() returns my application package only

<强> logcat的

除非您拥有root权限,否则读取logcat以获取前台应用程序将无效。从Jelly Bean开始读取logcat只返回来自应用程序的日志消息。

有用的链接:

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

修改

在挖掘Android源代码后,我编写了以下代码,以便在没有任何权限的情况下在Android M上获取前台应用。我只在运行最新开发者预览版的Nexus 9上测试过它。请将代码复制并粘贴到项目中的类中,并通过调用静态方法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();
}