Android6.0获取前台进程名称的方法
2017-08-09 10:12
1181 查看
今天遇到个问题, 使用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及后续版本不再有效。[java] view plain copyList<ActivityManager.RunningTaskInfo> 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 copydo_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类,是ActivityManagerNative(参考Android 插件化原理解析——Hook机制之AMS&PMS)的代理对象,运行在app当前进程;无法hook AMS的本地对象(运行在system_server进程)。
6、尝试打开手机proc目录下进程id目录下的cmdline文件, 部分机型能够看到包名。如果是前台进程,那么oom_score_adj文件内容为0;否则不是0。 而cmdline文件中是对应的包名。 因为Linux限制打开其它进程的文件,无法读取其它进程目录下的cmdline和oom_adj文件, 但可以了解一下linux命令。[java] view plain copyprivate 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_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 copyprivate 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 copyprivate 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。。。。
8、 在cmd窗口输入adb shell dumpsys activity 后回车, mFocusedActivity后就是前台进程(有包名和activity名称);在Android里执行该语句需要android.permission.DUMP权限,这是系统权限,一般app拿不到的。
dump出的数据很多, 有兴趣的同学可以试试。 其实我们只要mFocusedActivity这一行数据, 添加grep命令即可:adb shell dumpsys activity | grep mFocusedActivity
参考:Android内存管理篇 - adj的概念与进程adj级别控制
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 copydo_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类,是ActivityManagerNative(参考Android 插件化原理解析——Hook机制之AMS&PMS)的代理对象,运行在app当前进程;无法hook AMS的本地对象(运行在system_server进程)。
6、尝试打开手机proc目录下进程id目录下的cmdline文件, 部分机型能够看到包名。如果是前台进程,那么oom_score_adj文件内容为0;否则不是0。 而cmdline文件中是对应的包名。 因为Linux限制打开其它进程的文件,无法读取其它进程目录下的cmdline和oom_adj文件, 但可以了解一下linux命令。[java] view plain copyprivate 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_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 copyprivate 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 copyprivate 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。。。。
8、 在cmd窗口输入adb shell dumpsys activity 后回车, mFocusedActivity后就是前台进程(有包名和activity名称);在Android里执行该语句需要android.permission.DUMP权限,这是系统权限,一般app拿不到的。
dump出的数据很多, 有兴趣的同学可以试试。 其实我们只要mFocusedActivity这一行数据, 添加grep命令即可:adb shell dumpsys activity | grep mFocusedActivity
参考:Android内存管理篇 - adj的概念与进程adj级别控制
相关文章推荐
- Android6.0以上获取前台进程的方法
- Android6.0获取进程和进程数目的方法
- Android6.0获取进程和进程数目的方法:
- Python获取系统所有进程PID及进程名称的方法示例
- 遍历获取ASP.NET页面控件的名称及值 后台调用前台javascript方法报错:“缺少对象”的解决方法 xml与DataSet的互转换类
- Android获取前台进程的方法
- 根据进程名称获取进程pid,结束进程,执行exe文件
- 通过进程名称获取进程ID、通过子进程ID获取其父进程ID及通过进程ID获取进程名称
- android 获取某个class里的所有成员变量和静态变量的名称方法
- 织梦dedecms获取当前栏目路径及栏目名称的方法
- C获取自身进程名称
- 菜鸟学习Spring——60s利用JoinPoint获取参数的值和方法名称
- 使用Java8获取方法参数名称
- shell 获取脚步名称方法
- Java获取系统信息(cpu,内存,硬盘,进程等)的相关方法
- 学习笔记(二)C#获取当前正在执行的代码的命名空间、类、方法的名称
- java反射获取方法名称,参数类型
- C++获取当前进程的进程号方法
- linux下获取进程绝对路径的方法
- .net环境获取数据表名称集合的方法