获取前台应用包名 终极解决方案

来源:互联网 发布:淘宝博库图书专营店 编辑:程序博客网 时间:2024/06/07 07:07

       获取前台应用包名,在5.0.1的系统版本号可以通过系统提供的方法去获取前台包名,网上也有很多代码,这里就不重复贴代码了。以下贴出一个链接分享,其中还包括了获取系统pid 与uid的方式间接判断前台包名的方法。


       还有一篇是一个老外发现的方法,不过此方法还是不靠谱,本人亲测5.0.1以上的系统完美解决此问题。但是。。。但是。。。  5.0以下的系统是没有提供pid的,所以也不能做到通用,最后还是pass。


下面贴出实现代码:


/** * Created by zhu on 2016/6/15. */public class SuperRunningPackage {    /** 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() {        Log.e("PKG","VersionCode:"+Build.VERSION.SDK_INT);        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;                for (int i = 0; i < lines.length; i++) {                    Log.e("PKG",lines[i]);                }                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 if(lines.length == 5){//6.0系统                    cpuSubsystem = lines[2];                    cpuaccctSubsystem = lines[4];                }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();    }}



注意:此博文中只支持到6.0以下,6.0 还要多加一项判断,6.0读出有5项,应该多加以下代码的判断才能支持6.0:

else if(lines.length == 5){//6.0系统       cpuSubsystem = lines[2];       cpuaccctSubsystem = lines[4];}


一下也分享一个牛人的分析:http://caizhitao.com/2015/09/29/get-top-package-name/


       那既然从系统的运行配置文件中可以获取,那是否能从 linux 命令中的top 或者其他的命令获取到关键的参数呢?   答案是肯定的,那就是 ps命令, 以下是一篇对ps命令的介绍,注意红色标注 


-->>P show scheduling policy, either bg or fg are common, but also un and er for failures to get policy


大概意思就是说这个会列出系统调度列表,如果是系统的话,那是不是就说明能够得到界面的调度呢?


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

—————————————————————————————————————————————————————————————————————————————

Android shell tricks: ps

If you ever played around with the adb shell you may have found that the ps utility, which lists process lists, is not as verbose as you would expect it to be. And, to make things worse, there’s no inline help or man entries. Here’s the ps utility usage line: ps -t -x -P -p -c [pid|name].

Android shell tricks: ps

  • -t show threads, comes up with threads in the list
  • -x shows time, user time and system time in seconds
  • -P show scheduling policy, either bg or fg are common, but also un and er for failures to get policy
  • -p show priorities, niceness level
  • -c show CPU (may not be available prior to Android 4.x) involved
  • [pid] filter by PID if numeric, or…
  • [name] …filter by process name

Android’s core toolbox (shell utilities) are more primitive than the ones you may be used to. Notice how each argument needs to be separated and you can’t just -txPc it all, the command line argument parser is non-complex.

It’s a pity how command line arguments are not shown. If you need something that’s not available by the stock ps shell utility, try manually combing through the /proc directory. For the command line one would do cat /proc/<pid>/cmdline.

—————————————————————————————————————————————————————————————————————————————

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++




好以上都是猜测,下面就开始一步步的进行测试。



         首先我们在cmd命令行模式输入 : adb shell  ps 输出一下信息。





      然后能很清晰的看见各种包名而且都是系统正在运行中的,按照老外的说明如果 -p 参数可以列出前台进程调度的话,如果我们在切换程序或者对出时包名列表都会有变化。

以下是输入 adb shell ps -p 后输出的信息:







         仔细观察你会发现u0开头的都是我们正常程序的包名,而且在程序切换到后台以后,这个列表是有变化的,随便启动一个自己安装的应用,列表也刚好出现那个应用。在此大家应该就已经知道怎么写了,这里也提供一下实现思路:


1、命令行获取控制台输出流

2、找出每行输出的 u0开通的信息获取包名

3、用一个列表存入,与每次获取的当前列表项与上一次列表项对比,如果旧的列表不存在此包名,那就证明这个包就是启动项了,如果没有就不做任何操作。


    

项目GitHub地址 : https://github.com/popboyking/RunningTop



1 0
原创粉丝点击