android当前进程运行时间,Android获取当前运行的App进程

三种方式概述及对比

getRunningTasks方法

在Android5.0以前,系统允许我们通过ActivityManager的getRunningTasks()函数,直接获取当前运行的App。

这种方法唯一的问题就是过时了,在5.0以上不能使用。

USAGE_STATS_SERVICE方法

从Android5.0以后,系统为了安全起见,开始重重设限,要求我们通过用户手动授权的方式,获得USAGE_STATS_SERVICE的访问权限,才能读到数据。

但是,这种方式有两个问题:

1.要求用户手动授权,不能自动运行。

2.在碎片化系统中表现不一,有的系统无法给出权限,例如Android电视就无法真正获取权限。

系统proc文件夹方法

原理:Android系统在管理进程时,通过low memory killer机制来定时找出oom_score评分高出阈值的进程,进行回收,那么反过来考虑,oom_score值最低的,且oom_adj值为0的进程(0为前台进程的adj值),就是很可能是当前的前台进程了。

这种方式可以静默运行,但是也有两个问题:

1.获取的其实是进程名,默认进程名为App的包名,但是开发者可以自定义进程名,所以你可能拿不到App的包名。

2.获取的结果并不精准,因为评分最低的不一定是当前显示的App,还有可能是某个进程优先级很高的后台服务,我们可能需要维护一个黑名单,在代码中屏蔽掉这个名单上的所有后台服务。

getRunningTasks

在Android4.X的时代,获取当前运行的App非常简单:

ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

ComponentName cn = activityManager.getRunningTasks(1).get(0).topActivity;

String pkg = cn.getPackageName();

USAGE_STATS_SERVICE

从Android 5.0LOLLIPOP起,为了提升安全性,系统禁用了getRunningTasks,改为通过USAGE_STATS_SERVICE来获取当前运行的App:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

UsageStatsManager m = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);

if (m != null) {

long now = System.currentTimeMillis();

//获取60秒之内的应用数据

List stats = m.queryUsageStats(UsageStatsManager.INTERVAL_BEST, now - 60 * 1000, now);

Log.i(TAG, "Running app number in last 60 seconds : " + stats.size());

String topActivity = "";

//取得最近运行的一个app,即当前运行的app

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

int j = 0;

for (int i = 0; i < stats.size(); i++) {

if (stats.get(i).getLastTimeUsed() > stats.get(j).getLastTimeUsed()) {

j = i;

}

topActivity = stats.get(j).getPackageName();

Log.i(TAG, "top running app is : "+topActivity);

}

}

return stats.size();

}

}

这需要用户手动授权,调起系统授权页面“有权查看使用情况的应用”

f3aea648dfbb

系统页面授权

代码如下:

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

if (!hasPermission()) {

startActivityForResult(

new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS),

MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS);

}

}

}

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

if (requestCode == MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS) {

if (!hasPermission()) {

Toast.makeText(this,"未能开启部分App权限!",Toast.LENGTH_SHORT).show();

}

}

}

//检测用户是否对本app开启了“Apps with usage access”权限

private boolean hasPermission() {

AppOpsManager appOps = (AppOpsManager)

getSystemService(Context.APP_OPS_SERVICE);

int mode = 0;

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {

mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,

android.os.Process.myUid(), getPackageName());

}

return mode == AppOpsManager.MODE_ALLOWED;

}

private static final int MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS = 1101;

通过系统proc文件夹读取

通过读取系统proc文件夹,找到所有进程列表,然后利用oom_adj文件,判断出当前正在使用的进程。

代码如下:

//5.0以上,没有usage state权限

public static final int AID_APP = 10000;

public static final int AID_USER = 100000;

/**

* 5.0以上,没有usage state权限

* @return

*/

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.XXX.xxx")){

continue;

}

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(),包名后会带有乱码

}

引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值