Android获取前台进程包名

在Android L之前,通过getRunningTasks()和getRunningAppProcesses()可获取前台进程包名,但在L之后权限受限。由于REAL_GET_TASKS权限仅系统应用可用,第三方应用需借助usage statistics API来获取前台包名,利用该API找出最近活跃的app作为前台进程。

在Android L之前的版本,获取前台进程基本上是用下面两种方法:(现在都已失效)

方法一:getRunningTasks()

这种方法不仅可以获取前台进程包名,还可以获取前台activity名。

public String getForegroundActivity() {
    ActivityManager mActivityManager =
        (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
        if (mActivityManager.getRunningTasks(1) == null) {
            Log.e(TAG, "running task is null, ams is abnormal!!!");
            return null;
        }
        ActivityManager.RunningTaskInfo mRunningTask =
                    mActivityManager.getRunningTasks(1).get(0);
        if (mRunningTask == null) {
            Log.e(TAG, "failed to get RunningTaskInfo");
            return null;
        }
 
        String pkgName = mRunningTask.topActivity.getPackageName();
        //String activityName =  mRunningTask.topActivity.getClassName();
        return pkgName;
}

方法二:getRunningAppProcesses()

这种方法只能获取前台包名。

    public String getForegroundApp(Context context) {
        ActivityManager am =
            (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningAppProcesInfo> lr = am.getRunningAppProcesses();
        if (lr == null) {
            return null;
        }
 
        for (RunningAppProcessInfo ra : lr) {
            if (ra.importance == RunningAppProcessInfo.IMPORTANCE_VISIBLE
                || ra.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                return ra.processName;
            }
        }
 
        return null;
    }

 在Android L上,google收紧了这两个API的权限,只能获取自身的包名,无法获取其他应用的包名。具体原因就是下面这个权限检查方法:

    private boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
        boolean allowed = checkPermission(android.Manifest.permission.REAL_GET_TASKS,
                callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
        if (!allowed) {
            if (checkPermission(android.Manifest.permission.GET_TASKS,
                    callingPid, callingUid) == PackageManager.PERMISSION_GRANTED) {
                // Temporary compatibility: some existing apps on the system image may
                // still be requesting the old permission and not switched to the new
                // one; if so, we'll still allow them full access.  This means we need
                // to see if they are holding the old permission and are a system app.
                try {
                    if (AppGlobals.getPackageManager().isUidPrivileged(callingUid)) {
                        allowed = true;
                        Slog.w(TAG, caller + ": caller " + callingUid
                                + " is using old GET_TASKS but privileged; allowing");
                    }
                } catch (RemoteException e) {
                }
            }
        }
        if (!allowed) {
            Slog.w(TAG, caller + ": caller " + callingUid
                    + " does not hold REAL_GET_TASKS; limiting output");
        }
        return allowed;
}

很明显,只有两种情况可以通过该权限检查:

  • 拥有REAL_GET_TASKS权限授权
  • 拥有GET_TASKS权限授权,同时自己是privileged app,也就是安装在/system/priv-app/下的app

查看frameworks/base/core/res/AndroidManifest.xml可知,REAL_GET_TASKS只有系统签名的app可以申请,第三方app申请了也白搭。

    <!-- @deprecated No longer enforced. -->
    <permission android:name="android.permission.GET_TASKS"
        android:permissionGroup="android.permission-group.APP_INFO"
        android:protectionLevel="normal"
        android:label="@string/permlab_getTasks"
        android:description="@string/permdesc_getTasks" />
 
    <!-- New version of GET_TASKS that apps can request, since GET_TASKS doesn't really
         give access to task information.  We need this new one because there are
         many existing apps that use add libraries and such that have validation
         code to ensure the app has requested the GET_TASKS permission by seeing
         if it has been granted the permission...  if it hasn't, it kills the app
         with a message about being upset.  So we need to have it continue to look
         like the app is getting that permission, even though it will never be
         checked, and new privileged apps can now request this one for real access.
         @hide
         @SystemApi -->
    <permission android:name="android.permission.REAL_GET_TASKS"
        android:permissionGroup="android.permission-group.APP_INFO"
        android:protectionLevel="signature|system"
        android:label="@string/permlab_getTasks"
        android:description="@string/permdesc_getTasks" />

那么,在Android L之后,还有没有方法可以获取到前台包名呢?答案是肯定的,用usage statistics API。这个API本来是系统用来统计app使用情况的,包含了每个app最近一次被使用的时间。我们只需要找出距离现在时间最短的那个app,就是当前在前台的app

    private String getForegroundApp(Context context) {
        UsageStatsManager usageStatsManager = 
            (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
        long ts = System.currentTimeMillis();
        List<UsageStats> queryUsageStats =
            usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, 0, ts);
        UsageEvents usageEvents = usageStatsManager.queryEvents(isInit ? 0 : ts-5000, ts);
        if (usageEvents == null) {
            return null;
        }


        UsageEvents.Event event = new UsageEvents.Event();
        UsageEvents.Event lastEvent = null;
        while (usageEvents.getNextEvent(event)) {
            // if from notification bar, class name will be null
            if (event.getPackageName() == null || event.getClassName() == null) {
                continue;
            }

            if (lastEvent == null || lastEvent.getTimeStamp() < event.getTimeStamp()) {
                lastEvent = event;
            }
        }

        if (lastEvent == null) {
            return null;
        }
        return lastEvent.getPackageName();
    }
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值