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

Android-如何检测3d party应用程序何时启动,android,password-protection,android-5.1.1-lollipop,Android,Password Protection,Android 5.1.1 Lollipop,我目前正在为平板电脑开发一个应用程序,可以在商店里播放商业广告。我需要为设置应用程序添加密码保护。要实现这一点,我需要检测设置应用程序是否在后台服务中启动。对于API 21以下的Android设备,可以使用。不幸的是,这种方法现在已被弃用。我试着用它来实现我的目标,但事情并没有按我需要的那样进行。我正在尝试侦听V/WindowManager(740):在16个窗口中的9个(在窗口{e14eed2 u0 Starting com.android.settings}之前)添加窗口{1f4535ef

我目前正在为平板电脑开发一个应用程序,可以在商店里播放商业广告。我需要为设置应用程序添加密码保护。要实现这一点,我需要检测设置应用程序是否在后台服务中启动。对于API 21以下的Android设备,可以使用。不幸的是,这种方法现在已被弃用。我试着用它来实现我的目标,但事情并没有按我需要的那样进行。我正在尝试侦听
V/WindowManager(740):在16个窗口中的9个(在窗口{e14eed2 u0 Starting com.android.settings}之前)添加窗口{1f4535ef u0 com.android.settings/com.android.settings}
,但我无法将其视为输出。我使用的代码来自我上面提到的答案。我没有烤它,而是把它打印在日志上


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

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

您提到可以在Android M上检测当前前台活动。首次打开智能锁(或类似应用程序)时,系统会提示您授予
软件包使用情况统计
权限。因此,我们可以得出这样的结论:他们正在依赖于获得前景应用

我试图找到一个解决方法(黑客),在没有系统级许可的情况下在安卓M上获得前台应用程序。请在这里阅读并试用我的答案中的脚本:


Logcat

除非您具有root权限,否则读取logcat以获取前台应用程序将不起作用。读取logcat,因为Jelly Bean只从应用程序返回日志消息


有用的链接:


编辑: 在挖掘了安卓源代码之后,我编写了以下代码,以便在安卓M上无需任何权限即可获得前台应用程序。我只在运行最新开发者预览版的Nexus9上测试过它。请将代码复制并粘贴到项目中的一个类中,并通过调用静态方法
getForegroundApp()
对其进行测试:

/**第一个应用程序用户*/
公共静态最终int AID_APP=10000;
/**每个用户的uid范围的偏移量*/
公共静态最终用户=100000;
公共静态字符串getForegroundApp(){
File[]files=新文件(“/proc”).listFiles();
int LowesToomCore=整数.MAX_值;
字符串foregroundProcess=null;
用于(文件:文件){
如果(!file.isDirectory()){
继续;
}
int-pid;
试一试{
pid=Integer.parseInt(file.getName());
}捕获(数字格式){
继续;
}
试一试{
String cgroup=read(String.format(“/proc/%d/cgroup”,pid));
字符串[]行=cgroup.split(“\n”);
如果(lines.length!=2){
继续;
}
字符串cpuSubsystem=行[0];
字符串cpuaccctSubsystem=行[1];
if(!cpuaccctSubsystem.endsWith(Integer.toString(pid))){
//不是申请过程
继续;
}
if(cpuSubsystem.endsWith(“bg\u非交互式”)){
//背景政策
继续;
}
String cmdline=read(String.format(“/proc/%d/cmdline”,pid));
if(cmdline.contains(“com.android.systemui”)){
继续;
}
int uid=Integer.parseInt(
cpuaccctSubsystem.split(“:”[2]。split(“/”[1]。替换(“uid_)”,“”);
如果(uid>=1000&&uid-AID\u用户){
appId-=辅助用户;
用户ID++;
}
if(appId<0){
继续;
}
//u{user_id}{app_id}在API 17+上用于多用户帐户支持。
//String uidName=String.format(“u%d\u a%d”,userId,appId);
File oomScoreAdj=新文件(String.format(“/proc/%d/oom\u score\u adj”,pid));
if(oomScoreAdj.canRead()){
int oomAdj=Integer.parseInt(读取(oomScoreAdj.getAbsolutePath());
如果(oomAdj!=0){
继续;
}
}
int oomscore=Integer.parseInt(读取(String.format(“/proc/%d/oom_score”,pid));
if(oomscore
感谢您的详细回答。我很欣赏你的工作。您提供的代码适用于Android 5.1.1,但不幸的是,并非所有应用程序都适用。getGoregroundApp()为设置应用程序返回null。在Nexus 5上测试。@崩溃ID有趣。如果您获得
com.android.settings
的pid,并检查文件(/proc/[pid])是否存在,它会说它不存在,即使它存在。调查…@Crash ID-您是否可以评论Jared Rummler提出的解决方案不适用于哪种应用程序?@Jared/@Crash-ID。据我所知,它似乎工作得很好。它是否保证能在所有用户安装的应用程序上工作?@blueether当selinux强制执行时,它不会在系统应用程序上工作。您应该改用UsageStatsManager。@Jared。谢谢你的回复,谢谢你精彩的回答。自上一篇博文(Ma)以来运行了更多实验后
/** 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();
}