Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a315202 authored by Varun Shah's avatar Varun Shah
Browse files

Move usage stats data to credential encrypted storage.

Move all of the usage stats data from the regular system storage to
the system CE (credential encrypted) storage.

All events being reported while the user is locked will be stored
in memory and will be processed via the handler after the user is
unlocked. All of these events reported will regularly be persisted to
system DE storage to ensure important events are not lost.
Any query requests will be ignored while the user is locked.

Two new usage events have been added: one to indicate the user has been
unlocked and the other to indicate the user has been stopped.

Also updated documentation for APIs in UsageStatsManager to reflect the
new behavior in R when the user is locked.

Bug: 135484470
Test: atest android.app.usage.UsageStatsTest#testDataIsInCe
Test: atest android.app.usage.cts.UsageStatsTest#testUserUnlockedEventExists
Test: atest android.app.usage.cts.UsageStatsTest
Test: atest UsageStatsDatabaseTest
Change-Id: I18da1a9354b6686472972c5f2304e4c19e28307f
parent ce81d325
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -275,11 +275,25 @@ public final class UsageEvents implements Parcelable {
         */
        public static final int DEVICE_STARTUP = 27;

        /**
         * An event type denoting that a user has been unlocked for the first time. This event
         * mainly indicates when the user's credential encrypted storage was first accessible.
         * @hide
         */
        public static final int USER_UNLOCKED = 28;

        /**
         * An event type denoting that a user has been stopped. This typically happens when the
         * system is being turned off or when users are being switched.
         * @hide
         */
        public static final int USER_STOPPED = 29;

        /**
         * Keep in sync with the greatest event type value.
         * @hide
         */
        public static final int MAX_EVENT_TYPE = 27;
        public static final int MAX_EVENT_TYPE = 29;

        /** @hide */
        public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
+16 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.content.pm.ParceledListSlice;
import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;

import java.lang.annotation.Retention;
@@ -290,6 +291,9 @@ public final class UsageStatsManager {
     * </p>
     *
     * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
     * <em>Note: Starting from {@link android.os.Build.VERSION_CODES#R Android R}, if the user's
     * device is not in an unlocked state (as defined by {@link UserManager#isUserUnlocked()}),
     * then {@code null} will be returned.</em>
     *
     * @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.
@@ -324,6 +328,9 @@ public final class UsageStatsManager {
     * 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>
     * <em>Note: Starting from {@link android.os.Build.VERSION_CODES#R Android R}, if the user's
     * device is not in an unlocked state (as defined by {@link UserManager#isUserUnlocked()}),
     * then {@code null} will be returned.</em>
     *
     * @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.
@@ -362,6 +369,9 @@ public final class UsageStatsManager {
     * </ul>
     *
     * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
     * <em>Note: Starting from {@link android.os.Build.VERSION_CODES#R Android R}, if the user's
     * device is not in an unlocked state (as defined by {@link UserManager#isUserUnlocked()}),
     * then {@code null} will be returned.</em>
     *
     * @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.
@@ -395,6 +405,9 @@ 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>
     * <em>Note: Starting from {@link android.os.Build.VERSION_CODES#R Android R}, if the user's
     * device is not in an unlocked state (as defined by {@link UserManager#isUserUnlocked()}),
     * then {@code null} will be returned.</em>
     *
     * @param beginTime The inclusive beginning of the range of events to include in the results.
     *                 Defined in terms of "Unix time", see
@@ -418,6 +431,9 @@ public final class UsageStatsManager {

    /**
     * Like {@link #queryEvents(long, long)}, but only returns events for the calling package.
     * <em>Note: Starting from {@link android.os.Build.VERSION_CODES#R Android R}, if the user's
     * device is not in an unlocked state (as defined by {@link UserManager#isUserUnlocked()}),
     * then {@code null} will be returned.</em>
     *
     * @param beginTime The inclusive beginning of the range of events to include in the results.
     *                 Defined in terms of "Unix time", see
+21 −5
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.content.ComponentName;
import android.content.res.Configuration;
import android.os.UserHandle;
import android.os.UserManager;

import java.util.List;
import java.util.Set;
@@ -33,7 +34,10 @@ import java.util.Set;
public abstract class UsageStatsManagerInternal {

    /**
     * Reports an event to the UsageStatsManager.
     * Reports an event to the UsageStatsManager. <br/>
     * <em>Note: Starting from {@link android.os.Build.VERSION_CODES#R Android R}, if the user's
     * device is not in an unlocked state (as defined by {@link UserManager#isUserUnlocked()}),
     * then this event will be added to a queue and processed once the device is unlocked.</em>
     *
     * @param component The component for which this event occurred.
     * @param userId The user id to which the component belongs to.
@@ -48,7 +52,10 @@ public abstract class UsageStatsManagerInternal {
            int instanceId, ComponentName taskRoot);

    /**
     * Reports an event to the UsageStatsManager.
     * Reports an event to the UsageStatsManager. <br/>
     * <em>Note: Starting from {@link android.os.Build.VERSION_CODES#R Android R}, if the user's
     * device is not in an unlocked state (as defined by {@link UserManager#isUserUnlocked()}),
     * then this event will be added to a queue and processed once the device is unlocked.</em>
     *
     * @param packageName The package for which this event occurred.
     * @param userId The user id to which the component belongs to.
@@ -58,14 +65,20 @@ public abstract class UsageStatsManagerInternal {
    public abstract void reportEvent(String packageName, @UserIdInt int userId, int eventType);

    /**
     * Reports a configuration change to the UsageStatsManager.
     * Reports a configuration change to the UsageStatsManager. <br/>
     * <em>Note: Starting from {@link android.os.Build.VERSION_CODES#R Android R}, if the user's
     * device is not in an unlocked state (as defined by {@link UserManager#isUserUnlocked()}),
     * then this event will be added to a queue and processed once the device is unlocked.</em>
     *
     * @param config The new device configuration.
     */
    public abstract void reportConfigurationChange(Configuration config, @UserIdInt int userId);

    /**
     * Reports that an application has posted an interruptive notification.
     * Reports that an application has posted an interruptive notification. <br/>
     * <em>Note: Starting from {@link android.os.Build.VERSION_CODES#R Android R}, if the user's
     * device is not in an unlocked state (as defined by {@link UserManager#isUserUnlocked()}),
     * then this event will be added to a queue and processed once the device is unlocked.</em>
     *
     * @param packageName The package name of the app that posted the notification
     * @param channelId The ID of the NotificationChannel to which the notification was posted
@@ -75,7 +88,10 @@ public abstract class UsageStatsManagerInternal {
            @UserIdInt int userId);

    /**
     * Reports that an action equivalent to a ShortcutInfo is taken by the user.
     * Reports that an action equivalent to a ShortcutInfo is taken by the user. <br/>
     * <em>Note: Starting from {@link android.os.Build.VERSION_CODES#R Android R}, if the user's
     * device is not in an unlocked state (as defined by {@link UserManager#isUserUnlocked()}),
     * then this event will be added to a queue and processed once the device is unlocked.</em>
     *
     * @param packageName The package name of the shortcut publisher
     * @param shortcutId The ID of the shortcut in question
+2 −0
Original line number Diff line number Diff line
@@ -114,4 +114,6 @@ message IntervalStatsProto {
  repeated UsageStats packages = 20;
  repeated Configuration configurations = 21;
  repeated Event event_log = 22;

  repeated Event pending_events = 23; // TODO: move to usagestatsservice_v2.proto
}
+12 −0
Original line number Diff line number Diff line
@@ -34,7 +34,10 @@ import static org.junit.Assert.fail;

import android.app.usage.UsageEvents.Event;
import android.os.Parcel;
import android.os.UserHandle;
import android.support.test.uiautomator.UiDevice;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

@@ -120,6 +123,15 @@ public class UsageStatsTest {
        assertEquals(left.getTotalTimeInForeground(), 11);
    }

    @Test
    public void testDataIsInCe() throws Exception {
        final int userId = UserHandle.myUserId();
        final String expectedPath = "/data/system_ce/" + userId + "/usagestats";
        final String actualPath = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
                .executeShellCommand("dumpsys usagestats stats-directory " + userId).trim();
        assertEquals(expectedPath, actualPath);
    }

    @Test
    public void testParcelable() {
        left.mPackageName = "com.test";
Loading