android5.1+获取当前运行的app(Android5.1-也支持)
2016-05-19 13:32
417 查看
判断App位于前台或者后台的6种方法:
https://github.com/wenmingvs/AndroidProcess
做一个项目时,需要获取当前正在显示的应用app(正在运行的应用进程等),android5.0-之前可以使用getRunningTask获取,5.0这个方法不可用了,但是提供了getRunningAppProcess也可以获得。但是自从android5.1+以后,Google从安全和隐私方面考虑,也废弃了getRunningAppProcess方法,getRunningAppProcess方法现在只能返回本应用(当前应用信息-1个应用进程)。
通过这段时间的研究和在网上搜集的资料发现有很多的解决办法,但都有一定缺陷或执行失败;诸如,通过反射ActivityManager.RunningAppProcessInfo下的“processState”,或者反射android.app.ActivityThread,或者获取正在运行的top activity也都是失败。还有使用UsageState,AccessableService,这些需要用户手动开启,用户体验效果差,不符合项目需要。也找过源代码研究比如ActivityManagerNative的,系统设置里的应用管理代码,也都无功而返。
终在stackOverFlow找到一个大神的回答http://stackoverflow.com/a/32366476。读取android系统(Linux)下proc的文件夹可以获取进程的相关信息。虽然之前看到过这个大神获取了正在运行的进程列表https://github.com/jaredrummler/AndroidProcesses,但是获取的是列表,不能判断哪一个进程是当前正在显示的应用,用于判断的foreground参数能返回多个true的情况。大神解决了这个问题放出了获取当前正在显示app包名等信息。
贴一下代码:
package com.dengqiong.mobilesafe.engine.processes;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
/**
*
* @author dengqiong
* @e-mail 377384249@qq.com
* @version 2016年5月20日
*/
public class ForegroundProcess {
}
依照大神的代码,在实际测试中有的手机能返回当前正在显示的应用app的包名,有的还是返回null,比照系统文件和代码分析,发现有的手机里cgroup包含两行cpu 和cpuacct,有的则是三行,多了一行memory。所以对代码稍加改动,上面是改动过的。下面对调用的文件和文件内容解释一下:
1.proc下以数字命名的文件夹,文件夹名即是一个进程的pid,该文件夹下的文件包含这个进程的信息;
2.cgroup,控制组群(control groups)的简写,是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如CPU、内存、磁盘输入输出等)。cpu:设置cpu的使用率;cpuacct:记录cpu的统计信息。
3.bg_non_interactive,运行cpu的一个分组,另一分组是apps,当一个应用(进程)即可从apps分组切换到bg_non_interactive,也可以切换回来。apps分组可以利用95%的cpu,而bg_non_interactive只能使用大约5%。
4.cmdline,显示内核启动的命令行。
5.oom_score_adj,这个文件的数值用来标记在内存不足的情况下,启发式的。选择哪个进程被杀掉,值从0(从不被杀掉)到1000(总是被杀掉)。
https://github.com/wenmingvs/AndroidProcess
做一个项目时,需要获取当前正在显示的应用app(正在运行的应用进程等),android5.0-之前可以使用getRunningTask获取,5.0这个方法不可用了,但是提供了getRunningAppProcess也可以获得。但是自从android5.1+以后,Google从安全和隐私方面考虑,也废弃了getRunningAppProcess方法,getRunningAppProcess方法现在只能返回本应用(当前应用信息-1个应用进程)。
通过这段时间的研究和在网上搜集的资料发现有很多的解决办法,但都有一定缺陷或执行失败;诸如,通过反射ActivityManager.RunningAppProcessInfo下的“processState”,或者反射android.app.ActivityThread,或者获取正在运行的top activity也都是失败。还有使用UsageState,AccessableService,这些需要用户手动开启,用户体验效果差,不符合项目需要。也找过源代码研究比如ActivityManagerNative的,系统设置里的应用管理代码,也都无功而返。
终在stackOverFlow找到一个大神的回答http://stackoverflow.com/a/32366476。读取android系统(Linux)下proc的文件夹可以获取进程的相关信息。虽然之前看到过这个大神获取了正在运行的进程列表https://github.com/jaredrummler/AndroidProcesses,但是获取的是列表,不能判断哪一个进程是当前正在显示的应用,用于判断的foreground参数能返回多个true的情况。大神解决了这个问题放出了获取当前正在显示app包名等信息。
贴一下代码:
package com.dengqiong.mobilesafe.engine.processes;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
/**
*
* @author dengqiong
* @e-mail 377384249@qq.com
* @version 2016年5月20日
*/
public class ForegroundProcess {
public static final int AID_APP = 10000; 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(),包名后会带有乱码 }
}
依照大神的代码,在实际测试中有的手机能返回当前正在显示的应用app的包名,有的还是返回null,比照系统文件和代码分析,发现有的手机里cgroup包含两行cpu 和cpuacct,有的则是三行,多了一行memory。所以对代码稍加改动,上面是改动过的。下面对调用的文件和文件内容解释一下:
1.proc下以数字命名的文件夹,文件夹名即是一个进程的pid,该文件夹下的文件包含这个进程的信息;
2.cgroup,控制组群(control groups)的简写,是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如CPU、内存、磁盘输入输出等)。cpu:设置cpu的使用率;cpuacct:记录cpu的统计信息。
3.bg_non_interactive,运行cpu的一个分组,另一分组是apps,当一个应用(进程)即可从apps分组切换到bg_non_interactive,也可以切换回来。apps分组可以利用95%的cpu,而bg_non_interactive只能使用大约5%。
4.cmdline,显示内核启动的命令行。
5.oom_score_adj,这个文件的数值用来标记在内存不足的情况下,启发式的。选择哪个进程被杀掉,值从0(从不被杀掉)到1000(总是被杀掉)。
相关文章推荐
- Android深入理解dp,px,以及density。
- Cocos2d-x教程-Box2D 物理引擎
- Android Studio 快捷键 for Mac OS X
- Android WebView的Js对象注入漏洞解决方案
- Objective-C UITextField 禁止粘贴
- Ubuntu 重置unity
- Android——BaseAdapter相关
- 目前常用的cocoapods第三方库
- Android开发资料
- 打开SDKManager提示failed to execute tools\android.bat
- Android ORM 框架之 greenDAO 使用
- Android学习笔记二十七:连接Wifi
- cocos2dx在C++层屏蔽emoji表情
- iOS - 将Unity导出的Xcode工程导入到另一个Xcode项目, 及常见报错的解决方法
- Android4.4 以太网和DHCP启动过程介绍
- iOS代码调试(一)
- Android开发笔记(一百零二)统计图表
- Error: duplicate files during packaging of APK D:\eclipse\workspace\YC_SafeHelpe r_Community\build\o
- Android更改语言模式
- Android开发Handler源码分析