android5.1+獲取當前運行的app

         最新更新:因爲不少國產機修改過內核文件,包括proc下文件結構,因此本文章的方法再也不適合用來判斷後臺進程的運行。android

        這段時間作的一個項目,須要獲取當前正在運行的app,android5.0以前可使用getRunningTask獲取,5.0這個方法不可用了,可是提供了getRunningAppProcess也能夠得到。可是自從android5.1之後,Google從安全和隱私方面考慮,也廢棄了這個方法,如今只能返回本身的應用。這段時間一直在研究,在網上也搜尋了好久,諸如,經過反射ActivityManager.RunningAppProcessInfo下的「processState」,或者反射android.app.ActivityThread,或者獲取正在運行的top activity也都是失敗。還有使用UsageState,AccessableService,這些須要用戶手動開啓,不符合項目須要。也找過源代碼研究好比ActivityManagerNative的,系統設置裏的應用管理代碼,也都無功而返。git

     終於在stackOverFlow找個一個大神的回答http://stackoverflow.com/a/32366476。讀取android下proc的文件夾獲取進程的相關信息。雖然以前看到過這個大神的獲取正在運行的進程列表https://github.com/jaredrummler/AndroidProcesses,可是獲取的是列表,不能判斷哪個進程是固然顯示的應用,用於判斷的foreground參數能返回多個true的狀況。這個大神又在回答這個問題放出獲取當前應用的代碼。貼一下代碼:github

 

/** 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");
      String cpuSubsystem;
      String cpuaccctSubsystem;
      
      if (lines.length == 2) {//有的手機裏cgroup包含2行或者3行,咱們取cpu和cpuacct兩行數據
      cpuSubsystem = lines[0];
      cpuaccctSubsystem = lines[1];
      }else if(lines.length==3){
      cpuSubsystem = lines[0];
      cpuaccctSubsystem = lines[2];
      }else {
continue;
}
      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().trim();//不調用trim(),包名後面會帶有亂碼
}

 

      依照大神的代碼,在實際測試中有的手機能返回固然的包名,有的仍是返回null,比照系統文件和代碼分析,發現有的手機裏cgroup包含兩行cpu 和cpuacct,有的則是三行,多了一行memory。因此對代碼稍加改動,上面是改動過的。下面對調用的文件和文件內容解釋一下:安全

1.proc下以數字命名的文件夾,文件夾名便是一個進程的pid,該文件夾下的文件包含這個進程的信息;app

2.cgroup,控制組羣(control groups)的簡寫,是Linux內核的一個功能,用來限制,控制與分離一個進程組羣的資源(如CPU、內存、磁盤輸入輸出等)。cpu:設置cpu的使用率;cpuacct:記錄cpu的統計信息。oop

3.bg_non_interactive,運行cpu的一個分組,另外一分組是apps,當一個應用(進程)便可從apps分組切換到bg_non_interactive,也能夠切換回來。apps分組能夠利用95%的cpu,而bg_non_interactive只能使用大約5%。測試

4.cmdline,顯示內核啓動的命令行。ui

5.oom_score_adj,這個文件的數值用來標記在內存不足的狀況下,啓發式的(不知道怎麼翻譯好==)選擇哪一個進程被殺掉,值從0(從不被殺掉)到1000(老是被殺掉)。spa

相關文章
相關標籤/搜索