diff options
| author | 2018-03-03 01:32:21 +0000 | |
|---|---|---|
| committer | 2018-03-03 01:32:21 +0000 | |
| commit | c0fe0626f6b9676ef1fde7c2f9a42f3922683b5d (patch) | |
| tree | f7c0f24ceea01c4736be6292c8593526ab73d850 | |
| parent | b93a014cc8ba9c87ad84bafcb4013d2bd83eedc5 (diff) | |
| parent | 217ccda8ac8f38137882a0f9fefeac8e53dc4ed6 (diff) | |
Merge "An api to query usage events for the caller"
5 files changed, 114 insertions, 4 deletions
diff --git a/api/current.txt b/api/current.txt index 50d601d52105..df2e5bc5bcf7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -7445,6 +7445,7 @@ package android.app.usage { method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long); method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long); method public android.app.usage.UsageEvents queryEvents(long, long); + method public android.app.usage.UsageEvents queryEventsForSelf(long, long); method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long); field public static final int INTERVAL_BEST = 4; // 0x4 field public static final int INTERVAL_DAILY = 0; // 0x0 diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index e72b84d24802..fff1a00c585e 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -32,6 +32,7 @@ interface IUsageStatsManager { ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime, String callingPackage); UsageEvents queryEvents(long beginTime, long endTime, String callingPackage); + UsageEvents queryEventsForPackage(long beginTime, long endTime, String callingPackage); void setAppInactive(String packageName, boolean inactive, int userId); boolean isAppInactive(String packageName, int userId); void whitelistAppTemporarily(String packageName, long duration, int userId); diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 5a57b067f2c4..5f9fa43203da 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -52,10 +52,13 @@ import java.util.Map; * </pre> * A request for data in the middle of a time interval will include that interval. * <p/> - * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS. - * However, declaring the permission implies intention to use the API and the user of the device - * still needs to grant permission through the Settings application. - * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS} + * <b>NOTE:</b> Most methods on this API require the permission + * android.permission.PACKAGE_USAGE_STATS. However, declaring the permission implies intention to + * use the API and the user of the device still needs to grant permission through the Settings + * application. + * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS}. + * Methods which only return the information for the calling package do not require this permission. + * E.g. {@link #getAppStandbyBucket()} and {@link #queryEventsForSelf(long, long)}. */ @SystemService(Context.USAGE_STATS_SERVICE) public final class UsageStatsManager { @@ -206,6 +209,8 @@ public final class UsageStatsManager { * 2014 - com.example.charlie * </pre> * + * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> + * * @param intervalType The time interval by which the stats are aggregated. * @param beginTime The inclusive beginning of the range of stats to include in the results. * @param endTime The exclusive end of the range of stats to include in the results. @@ -235,6 +240,7 @@ public final class UsageStatsManager { * Gets the hardware configurations the device was in for the given time range, aggregated by * the specified interval. The results are ordered as in * {@link #queryUsageStats(int, long, long)}. + * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> * * @param intervalType The time interval by which the stats are aggregated. * @param beginTime The inclusive beginning of the range of stats to include in the results. @@ -259,6 +265,7 @@ public final class UsageStatsManager { /** * Query for events in the given time range. Events are only kept by the system for a few * days. + * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> * * @param beginTime The inclusive beginning of the range of events to include in the results. * @param endTime The exclusive end of the range of events to include in the results. @@ -278,9 +285,32 @@ public final class UsageStatsManager { } /** + * Like {@link #queryEvents(long, long)}, but only returns events for the calling package. + * + * @param beginTime The inclusive beginning of the range of events to include in the results. + * @param endTime The exclusive end of the range of events to include in the results. + * @return A {@link UsageEvents} object. + * + * @see #queryEvents(long, long) + */ + public UsageEvents queryEventsForSelf(long beginTime, long endTime) { + try { + final UsageEvents events = mService.queryEventsForPackage(beginTime, endTime, + mContext.getOpPackageName()); + if (events != null) { + return events; + } + } catch (RemoteException e) { + // fallthrough + } + return sEmptyResults; + } + + /** * A convenience method that queries for all stats in the given range (using the best interval * for that range), merges the resulting data, and keys it by package name. * See {@link #queryUsageStats(int, long, long)}. + * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> * * @param beginTime The inclusive beginning of the range of stats to include in the results. * @param endTime The exclusive end of the range of stats to include in the results. diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 69b2c63efc18..a30257890c3c 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -465,6 +465,23 @@ public class UsageStatsService extends SystemService implements } } + /** + * Called by the Binder stub. + */ + UsageEvents queryEventsForPackage(int userId, long beginTime, long endTime, + String packageName) { + synchronized (mLock) { + final long timeNow = checkAndGetTimeLocked(); + if (!validRange(timeNow, beginTime, endTime)) { + return null; + } + + final UserUsageStatsService service = + getUserDataAndInitializeIfNeededLocked(userId, timeNow); + return service.queryEventsForPackage(beginTime, endTime, packageName); + } + } + private static boolean validRange(long currentTime, long beginTime, long endTime) { return beginTime <= currentTime && beginTime < endTime; } @@ -661,6 +678,26 @@ public class UsageStatsService extends SystemService implements } @Override + public UsageEvents queryEventsForPackage(long beginTime, long endTime, + String callingPackage) { + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getUserId(callingUid); + + if (mPackageManagerInternal.getPackageUid(callingPackage, PackageManager.MATCH_ANY_USER, + callingUserId) != callingUid) { + throw new SecurityException("Calling uid " + callingPackage + " cannot query events" + + "for package " + callingPackage); + } + final long token = Binder.clearCallingIdentity(); + try { + return UsageStatsService.this.queryEventsForPackage(callingUserId, beginTime, + endTime, callingPackage); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override public boolean isAppInactive(String packageName, int userId) { try { userId = ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(), diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 7f060b3093e9..29c5ee862aaf 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -355,6 +355,47 @@ class UserUsageStatsService { return new UsageEvents(results, table); } + UsageEvents queryEventsForPackage(final long beginTime, final long endTime, + final String packageName) { + final ArraySet<String> names = new ArraySet<>(); + names.add(packageName); + final List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY, + beginTime, endTime, (stats, mutable, accumulatedResult) -> { + if (stats.events == null) { + return; + } + + final int startIndex = stats.events.closestIndexOnOrAfter(beginTime); + if (startIndex < 0) { + return; + } + + final int size = stats.events.size(); + for (int i = startIndex; i < size; i++) { + if (stats.events.keyAt(i) >= endTime) { + return; + } + + final UsageEvents.Event event = stats.events.valueAt(i); + if (!packageName.equals(event.mPackage)) { + continue; + } + if (event.mClass != null) { + names.add(event.mClass); + } + accumulatedResult.add(event); + } + }); + + if (results == null || results.isEmpty()) { + return null; + } + + final String[] table = names.toArray(new String[names.size()]); + Arrays.sort(table); + return new UsageEvents(results, table); + } + void persistActiveStats() { if (mStatsChanged) { Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk"); |