Android获取前台进程包名

在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();
    }

猜你喜欢

转载自blog.csdn.net/turkeycock/article/details/50765576