Merge "Obfuscate visibility of notification-related events."

This commit is contained in:
TreeHugger Robot
2020-02-13 22:46:52 +00:00
committed by Android (Google) Code Review
8 changed files with 106 additions and 39 deletions

View File

@@ -41,6 +41,43 @@ public final class UsageEvents implements Parcelable {
/** @hide */
public static final String INSTANT_APP_CLASS_NAME = "android.instant_class";
/** @hide */
public static final String OBFUSCATED_NOTIFICATION_CHANNEL_ID = "unknown_channel_id";
/**
* Flag: indicates to not obfuscate or hide any usage event data when being queried.
* @hide
*/
public static final int SHOW_ALL_EVENT_DATA = 0x00000000;
/**
* Flag: indicates to obfuscate package and class names for instant apps when querying usage
* events.
* @hide
*/
public static final int OBFUSCATE_INSTANT_APPS = 0x00000001;
/**
* Flag: indicates to hide all {@link Event#SHORTCUT_INVOCATION} events when querying usage
* events.
* @hide
*/
public static final int HIDE_SHORTCUT_EVENTS = 0x00000002;
/**
* Flag: indicates to obfuscate the notification channel id for all notification events,
* such as {@link Event#NOTIFICATION_SEEN} and {@link Event#NOTIFICATION_INTERRUPTION} events,
* when querying usage events.
* @hide
*/
public static final int OBFUSCATE_NOTIFICATION_EVENTS = 0x00000004;
/**
* Flag: indicates to hide all {@link Event#LOCUS_ID_SET} events when querying usage events.
* @hide
*/
public static final int HIDE_LOCUS_EVENTS = 0x00000008;
/**
* An event representing a state change for a component.
*/
@@ -627,6 +664,13 @@ public final class UsageEvents implements Parcelable {
return ret;
}
/** @hide */
public Event getObfuscatedNotificationEvent() {
final Event ret = new Event(this);
ret.mNotificationChannelId = OBFUSCATED_NOTIFICATION_CHANNEL_ID;
return ret;
}
/**
* Returns the locusId for this event if the event is of type {@link #LOCUS_ID_SET},
* otherwise it returns null.

View File

@@ -381,6 +381,8 @@ applications that come with the platform
<permission name="android.permission.REBOOT"/>
<!-- Permission required for access VIBRATOR_STATE. -->
<permission name="android.permission.ACCESS_VIBRATOR_STATE"/>
<!-- Permission required for UsageStatsTest CTS test. -->
<permission name="android.permission.MANAGE_NOTIFICATIONS"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">

View File

@@ -253,7 +253,8 @@
<!-- Permission required for CTS test - ShortcutManagerUsageTest -->
<uses-permission android:name="android.permission.ACCESS_SHORTCUTS"/>
<!-- Permission required for CTS test - UsageStatsTest -->
<!-- Permissions required for CTS test - UsageStatsTest -->
<uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"/>
<!-- Permissions required to test ambient display. -->

View File

@@ -216,17 +216,11 @@ public abstract class UsageStatsManagerInternal {
/**
* Returns the events for the user in the given time period.
*
* @param obfuscateInstantApps whether instant app package names need to be obfuscated in the
* result.
* @param hideShortcutInvocationEvents whether the {@link UsageEvents.Event#SHORTCUT_INVOCATION}
* events need to be excluded from the result.
* @param hideLocusIdEvents whether the {@link UsageEvents.Event#LOCUS_ID_SET}
* events need to be excluded from the result.
*
* @param flags defines the visibility of certain usage events - see flags defined in
* {@link UsageEvents}.
*/
public abstract UsageEvents queryEventsForUser(@UserIdInt int userId, long beginTime,
long endTime, boolean obfuscateInstantApps, boolean hideShortcutInvocationEvents,
boolean hideLocusIdEvents);
long endTime, int flags);
/**
* Used to persist the last time a job was run for this app, in order to make decisions later

View File

@@ -59,7 +59,7 @@ class UsageStatsQueryHelper {
*/
boolean querySince(long sinceTime) {
UsageEvents usageEvents = mUsageStatsManagerInternal.queryEventsForUser(
mUserId, sinceTime, System.currentTimeMillis(), false, false, false);
mUserId, sinceTime, System.currentTimeMillis(), UsageEvents.SHOW_ALL_EVENT_DATA);
if (usageEvents == null) {
return false;
}

View File

@@ -19,9 +19,9 @@ package com.android.server.people.data;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
@@ -189,7 +189,7 @@ public final class UsageStatsQueryHelperTest {
private void addUsageEvents(UsageEvents.Event... events) {
UsageEvents usageEvents = new UsageEvents(Arrays.asList(events), new String[]{});
when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(),
anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(usageEvents);
eq(UsageEvents.SHOW_ALL_EVENT_DATA))).thenReturn(usageEvents);
}
private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {

View File

@@ -500,6 +500,19 @@ public class UsageStatsService extends SystemService implements
== PackageManager.PERMISSION_GRANTED);
}
/**
* Obfuscate both {@link UsageEvents.Event#NOTIFICATION_SEEN} and
* {@link UsageEvents.Event#NOTIFICATION_INTERRUPTION} events if the provided calling uid does
* not hold the {@link android.Manifest.permission.MANAGE_NOTIFICATIONS} permission.
*/
private boolean shouldObfuscateNotificationEvents(int callingPid, int callingUid) {
if (callingUid == Process.SYSTEM_UID) {
return false;
}
return !(getContext().checkPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS,
callingPid, callingUid) == PackageManager.PERMISSION_GRANTED);
}
private static void deleteRecursively(File f) {
File[] files = f.listFiles();
if (files != null) {
@@ -1038,9 +1051,7 @@ public class UsageStatsService extends SystemService implements
/**
* Called by the Binder stub.
*/
UsageEvents queryEvents(int userId, long beginTime, long endTime,
boolean shouldObfuscateInstantApps, boolean shouldHideShortcutInvocationEvents,
boolean shouldHideLocusIdEvents) {
UsageEvents queryEvents(int userId, long beginTime, long endTime, int flags) {
synchronized (mLock) {
if (!mUserUnlockedStates.get(userId)) {
Slog.w(TAG, "Failed to query events for locked user " + userId);
@@ -1051,8 +1062,7 @@ public class UsageStatsService extends SystemService implements
if (service == null) {
return null; // user was stopped or removed
}
return service.queryEvents(beginTime, endTime, shouldObfuscateInstantApps,
shouldHideShortcutInvocationEvents, shouldHideLocusIdEvents);
return service.queryEvents(beginTime, endTime, flags);
}
}
@@ -1475,10 +1485,15 @@ public class UsageStatsService extends SystemService implements
try {
final boolean hideShortcutInvocationEvents = shouldHideShortcutInvocationEvents(
userId, callingPackage, callingPid, callingUid);
boolean shouldHideLocusIdEvents = shouldHideLocusIdEvents(callingPid, callingUid);
return UsageStatsService.this.queryEvents(userId, beginTime, endTime,
obfuscateInstantApps, hideShortcutInvocationEvents,
shouldHideLocusIdEvents);
final boolean hideLocusIdEvents = shouldHideLocusIdEvents(callingPid, callingUid);
final boolean obfuscateNotificationEvents = shouldObfuscateNotificationEvents(
callingPid, callingUid);
int flags = UsageEvents.SHOW_ALL_EVENT_DATA;
if (obfuscateInstantApps) flags |= UsageEvents.OBFUSCATE_INSTANT_APPS;
if (hideShortcutInvocationEvents) flags |= UsageEvents.HIDE_SHORTCUT_EVENTS;
if (hideLocusIdEvents) flags |= UsageEvents.HIDE_LOCUS_EVENTS;
if (obfuscateNotificationEvents) flags |= UsageEvents.OBFUSCATE_NOTIFICATION_EVENTS;
return UsageStatsService.this.queryEvents(userId, beginTime, endTime, flags);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1525,10 +1540,15 @@ public class UsageStatsService extends SystemService implements
try {
final boolean hideShortcutInvocationEvents = shouldHideShortcutInvocationEvents(
userId, callingPackage, callingPid, callingUid);
boolean shouldHideLocusIdEvents = shouldHideLocusIdEvents(callingPid, callingUid);
return UsageStatsService.this.queryEvents(userId, beginTime, endTime,
obfuscateInstantApps, hideShortcutInvocationEvents,
shouldHideLocusIdEvents);
final boolean obfuscateNotificationEvents = shouldObfuscateNotificationEvents(
callingPid, callingUid);
boolean hideLocusIdEvents = shouldHideLocusIdEvents(callingPid, callingUid);
int flags = UsageEvents.SHOW_ALL_EVENT_DATA;
if (obfuscateInstantApps) flags |= UsageEvents.OBFUSCATE_INSTANT_APPS;
if (hideShortcutInvocationEvents) flags |= UsageEvents.HIDE_SHORTCUT_EVENTS;
if (hideLocusIdEvents) flags |= UsageEvents.HIDE_LOCUS_EVENTS;
if (obfuscateNotificationEvents) flags |= UsageEvents.OBFUSCATE_NOTIFICATION_EVENTS;
return UsageStatsService.this.queryEvents(userId, beginTime, endTime, flags);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2144,12 +2164,8 @@ public class UsageStatsService extends SystemService implements
}
@Override
public UsageEvents queryEventsForUser(int userId, long beginTime, long endTime,
boolean obfuscateInstantApps, boolean shouldHideShortcutInvocationEvents,
boolean shouldHideLocusIdEvents) {
return UsageStatsService.this.queryEvents(
userId, beginTime, endTime, obfuscateInstantApps,
shouldHideShortcutInvocationEvents, shouldHideLocusIdEvents);
public UsageEvents queryEventsForUser(int userId, long beginTime, long endTime, int flags) {
return UsageStatsService.this.queryEvents(userId, beginTime, endTime, flags);
}
@Override

View File

@@ -18,6 +18,10 @@ package com.android.server.usage;
import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
import static android.app.usage.UsageEvents.Event.DEVICE_STARTUP;
import static android.app.usage.UsageEvents.HIDE_LOCUS_EVENTS;
import static android.app.usage.UsageEvents.HIDE_SHORTCUT_EVENTS;
import static android.app.usage.UsageEvents.OBFUSCATE_INSTANT_APPS;
import static android.app.usage.UsageEvents.OBFUSCATE_NOTIFICATION_EVENTS;
import static android.app.usage.UsageStatsManager.INTERVAL_BEST;
import static android.app.usage.UsageStatsManager.INTERVAL_COUNT;
import static android.app.usage.UsageStatsManager.INTERVAL_DAILY;
@@ -481,8 +485,7 @@ class UserUsageStatsService {
return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner);
}
UsageEvents queryEvents(final long beginTime, final long endTime, boolean obfuscateInstantApps,
boolean hideShortcutInvocationEvents, boolean hideLocusIdEvents) {
UsageEvents queryEvents(final long beginTime, final long endTime, int flags) {
if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) {
return null;
}
@@ -500,15 +503,22 @@ class UserUsageStatsService {
}
Event event = stats.events.get(i);
if (hideShortcutInvocationEvents
&& event.mEventType == Event.SHORTCUT_INVOCATION) {
final int eventType = event.mEventType;
if (eventType == Event.SHORTCUT_INVOCATION
&& (flags & HIDE_SHORTCUT_EVENTS) == HIDE_SHORTCUT_EVENTS) {
continue;
}
if (hideLocusIdEvents
&& event.mEventType == Event.LOCUS_ID_SET) {
if (eventType == Event.LOCUS_ID_SET
&& (flags & HIDE_LOCUS_EVENTS) == HIDE_LOCUS_EVENTS) {
continue;
}
if (obfuscateInstantApps) {
if ((eventType == Event.NOTIFICATION_SEEN
|| eventType == Event.NOTIFICATION_INTERRUPTION)
&& (flags & OBFUSCATE_NOTIFICATION_EVENTS)
== OBFUSCATE_NOTIFICATION_EVENTS) {
event = event.getObfuscatedNotificationEvent();
}
if ((flags & OBFUSCATE_INSTANT_APPS) == OBFUSCATE_INSTANT_APPS) {
event = event.getObfuscatedIfInstantApp();
}
if (event.mPackage != null) {