Android6.0以上获取前台进程的方法

 
 

原文地址:http://www.jianshu.com/p/43078a0c18e5

今天遇到个问题, 使用action为“Android.media.action.IMAGE_CAPTURE“打不开Android6.0系统的小米4手机照相机, 问题是你不知道到底是否启动了相机。 我试了很多种方法, 最终只想到一个土办法:点击拍照按钮后延迟1秒判断是否执行了onStop函数或自己是否前台进程,方法很low也可能误判。(PS:从自己app打开照相机后会执行onPause-onStop函数)但在尝试的过程中学到不少东西, 可以分享一下:        目前没找到6.0版本获取top activity的方法, google把我能想到的路都封死了。 因为这是个漏洞,假设钓鱼app监听打开支付宝、微信输入密码的activity时,覆盖一模一样的界面就可以盗取你的机密信息了。 1、 Android5.0以下的方法在5.0及后续版本不再有效。

List tasks = am.getRunningTasks(1);

if (tasks != null && !tasks.isEmpty()) {

ComponentName componentName = tasks.get(0).topActivity;

if (componentName != null) {

return componentName.getClassName();

}

}

2、尝试ActivityManager的getRunningAppProcesses方法,但从Andriod5.1版本后只能拿到自己的进程信息, 所以此路不通;

3、使用UsageStatsManager类验证, 但它需要系统权限, 实际使用场景下很难被授权, 此路不通;

4、思路:在Android Runtime运行dumpsys meminfo , 拿到输出并截取前台进程, 但是拿不到top activity, 可以做个测试手段。

在cmd窗口执行adb shell dumpsys meminfo 后输出所有运行进程的信息,能明显的看出那个是前台进程。 但在Android运行时报无DUMP权限, 这是系统签名才能执行的操作。

373663 kB:      0 kB: Foreground

265450 kB:      0 kB: com.android.browser (pid 9131 / activities)

30164 kB:      0 kB: com.miui.securitycenter.remote (pid 3191)

28803 kB:      0 kB: com.miui.networkassistant.deamon (pid 3125)

[java] view plain copy 在CODE上查看代码片派生到我的代码片

do_exec("dumpsys meminfo ");

String do_exec(String cmd) {

String s = "/n";

try {

Process p = Runtime.getRuntime().exec(cmd);

BufferedReader in = new BufferedReader(

new InputStreamReader(p.getInputStream()));

String line = null;

while ((line = in.readLine()) != null) {

s += line + "/n";

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return s;

}

5、hook AMS, 能够监听到打开照相机的action,但无法确定是否启动了照相机。 原理是只能hook ActivityManagerNative类,是ActivityManagerService的代理对象,运行在app当前进程;无法hook AMS的本地对象(运行在system_server进程)。

6、尝试打开手机proc目录下进程id目录下的cmdline文件, 部分机型能够看到包名。如果是前台进程,那么oom_score_adj文件内容为0;否则不是0。 而cmdline文件中是对应的包名。  因为Linux限制打开其它进程的文件,无法读取其它进程目录下的cmdline和oom_adj文件, 但可以了解一下Linux命令。

[java] view plain copy 在CODE上查看代码片派生到我的代码片

private String getForegroundApp() {

File[] files = new File("/proc").listFiles();

String foregroundProcess = null;

int i = 0;

for (File file : files) {

i++;

Log.d("brycegao", "proc file:" + file.getName()

+ ", loop:" + i);

if (file.isFile()) {

continue;

}

int pid;

Log.d("brycegao", "proc filename:" + file.getName());

try {

pid = Integer.parseInt(file.getName());

} catch (NumberFormatException e) {

continue;

}

try {

//读取进程名称

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

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

Log.d("brycegao", "adj1111:" + oomAdj + ",pkg:" + cmdline);

if (oomAdj.equalsIgnoreCase("0")) {

//前台进程

Log.d("brycegao", "adj:" + oomAdj + ",pkg:" + cmdline);

} else {

continue;

}

if (cmdline.contains("systemui")

|| cmdline.contains("/")) {

continue;

}

foregroundProcess = cmdline;

} catch (IOException e) {

e.printStackTrace();

}

}

return foregroundProcess;

}

[java] view plain copy 在CODE上查看代码片派生到我的代码片

private 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();

}

7、尝试使用linux 的ps命令、grep命令和cat命令, 惊讶的发现使用cat可以查看其它进程目录下的文件!!! 对上面方法稍作改变,就能得到前台进程的名称了, 注意前台进程是多个。 下面的示例代码只取一个前台进程名称, 其实应该是个ArrayList,懒的优化了、只说原理。 其实就是将打开文件的操作改成用cat查看, 这样就不会出现权限问题了。

[java] view plain copy 在CODE上查看代码片派生到我的代码片

private String getForegroundApp() {

File[] files = new File("/proc").listFiles();

String foregroundProcess = "";

int i = 0;

for (File file : files) {

i++;

Log.d("brycegao", "proc file:" + file.getName()

+ ", loop:" + i);

if (file.isFile()) {

continue;

}

int pid;

Log.d("brycegao", "proc filename:" + file.getName());

try {

pid = Integer.parseInt(file.getName());

} catch (NumberFormatException e) {

continue;

}

try {

//读取进程名称

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

String oomAdj = do_exec(String.format("cat /proc/%d/oom_adj", pid));

Log.d("brycegao", "adj1111:" + oomAdj + ",pkg:" + cmdline);

if (oomAdj.equalsIgnoreCase("0")) {

//前台进程

Log.d("brycegao", "adj:" + oomAdj + ",pkg:" + cmdline);

} else {

continue;

}

if (cmdline.contains("systemui")

|| cmdline.contains("/")) {

continue;

}

foregroundProcess = cmdline;

} catch (Exception e) {

e.printStackTrace();

}

}

Log.d("brycegao", "forgroud process:" + foregroundProcess);

return foregroundProcess;

}

第7个方法算是个黑科技了, 能拿到Android手机的前台进程名称(注意:前台进程可以是多个), 但无法判断当前正在显示的是哪个进程以及top activity。。。。

http://blog.csdn.net/brycegao321/article/details/53414019

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值