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

Commit 08be74fa authored by Michael Wachenschwanz's avatar Michael Wachenschwanz
Browse files

Populate null UsageStats event task root fields with known data

It is possible for an activity's task root to be reported as null to
UsageStats during a destry. Use past known data to populate the fields.

Change-Id: Id20c809580e854ca9075444957bd10a338087e3d
Fixes: 123404490
Test: atest cts/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java#testSuddenDestroy
parent f6cce018
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -465,8 +465,6 @@ public final class UsageStats implements Parcelable {
                mActivities.put(instanceId, eventType);
                break;
            case ACTIVITY_STOPPED:
                mActivities.put(instanceId, eventType);
                break;
            case ACTIVITY_DESTROYED:
                // remove activity from the map.
                mActivities.delete(instanceId);
+0 −22
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@
 */
package com.android.server.usage;

import static android.app.usage.UsageEvents.Event.ACTIVITY_DESTROYED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_PAUSED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
@@ -302,27 +301,6 @@ public class IntervalStats {
                UsageStats usageStats = packageStats.valueAt(i);
                usageStats.update(null, timeStamp, eventType, instanceId);
            }
        } else if (eventType == ACTIVITY_DESTROYED) {
            UsageStats usageStats = packageStats.get(packageName);
            if (usageStats != null) {
                // If previous event is not ACTIVITY_STOPPED, convert ACTIVITY_DESTROYED
                // to ACTIVITY_STOPPED and add to event list.
                // Otherwise do not add anything to event list. (Because we want to save space
                // and we do not want a ACTIVITY_STOPPED followed by
                // ACTIVITY_DESTROYED in event list).
                final int index = usageStats.mActivities.indexOfKey(instanceId);
                if (index >= 0) {
                    final int type = usageStats.mActivities.valueAt(index);
                    if (type != ACTIVITY_STOPPED) {
                        Event event = new Event(ACTIVITY_STOPPED, timeStamp);
                        event.mPackage = packageName;
                        event.mClass = className;
                        event.mInstanceId = instanceId;
                        addEvent(event);
                    }
                }
                usageStats.update(className, timeStamp, ACTIVITY_DESTROYED, instanceId);
            }
        } else {
            UsageStats usageStats = getOrCreateUsageStats(packageName);
            usageStats.update(className, timeStamp, eventType, instanceId);
+74 −42
Original line number Diff line number Diff line
@@ -145,8 +145,16 @@ public class UsageStatsService extends SystemService implements
    AppTimeLimitController mAppTimeLimit;

    final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray();
    final SparseArray<String> mVisibleActivities = new SparseArray();
    final SparseArray<ActivityData> mVisibleActivities = new SparseArray();

    private static class ActivityData {
        private final String mTaskRootPackage;
        private final String mTaskRootClass;
        private ActivityData(String taskRootPackage, String taskRootClass) {
            mTaskRootPackage = taskRootPackage;
            mTaskRootClass = taskRootClass;
        }
    }

    private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener =
            new UsageStatsManagerInternal.AppIdleStateChangeListener() {
@@ -464,47 +472,57 @@ public class UsageStatsService extends SystemService implements
            final long elapsedRealtime = SystemClock.elapsedRealtime();
            convertToSystemTimeLocked(event);

            if (event.getPackageName() != null
                    && mPackageManagerInternal.isPackageEphemeral(userId, event.getPackageName())) {
            if (event.mPackage != null
                    && mPackageManagerInternal.isPackageEphemeral(userId, event.mPackage)) {
                event.mFlags |= Event.FLAG_IS_PACKAGE_INSTANT_APP;
            }

            final UserUsageStatsService service =
                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
            service.reportEvent(event);

            mAppStandby.reportEvent(event, elapsedRealtime, userId);

            String packageName;

            switch (event.mEventType) {
                case Event.ACTIVITY_RESUMED:
                    // check if this activity has already been resumed
                    if (mVisibleActivities.get(event.mInstanceId) != null) break;
                    mVisibleActivities.put(event.mInstanceId,
                            new ActivityData(event.mTaskRootPackage, event.mTaskRootClass));
                    try {
                        switch(mUsageSource) {
                            case USAGE_SOURCE_CURRENT_ACTIVITY:
                    packageName = event.getPackageName();
                                mAppTimeLimit.noteUsageStart(event.mPackage, userId);
                                break;
                            case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
                            default:
                    packageName = event.getTaskRootPackageName();
                    if (packageName == null) {
                        packageName = event.getPackageName();
                    }
                                mAppTimeLimit.noteUsageStart(event.mTaskRootPackage, userId);
                                break;
                        }

            switch (event.mEventType) {
                case Event.ACTIVITY_RESUMED:
                    synchronized (mVisibleActivities) {
                        // check if this activity has already been resumed
                        if (mVisibleActivities.get(event.mInstanceId) != null) break;
                        mVisibleActivities.put(event.mInstanceId, event.getClassName());
                        try {
                            mAppTimeLimit.noteUsageStart(packageName, userId);
                    } catch (IllegalArgumentException iae) {
                        Slog.e(TAG, "Failed to note usage start", iae);
                    }
                    break;
                case Event.ACTIVITY_PAUSED:
                    if (event.mTaskRootPackage == null) {
                        // Task Root info is missing. Repair the event based on previous data
                        final ActivityData prevData = mVisibleActivities.get(event.mInstanceId);
                        if (prevData == null) {
                            Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage
                                    + "/" + event.mClass + " event : " + event.mEventType
                                    + " instanceId : " + event.mInstanceId + ")");
                        } else {
                            event.mTaskRootPackage = prevData.mTaskRootPackage;
                            event.mTaskRootClass = prevData.mTaskRootClass;
                        }
                    }
                    break;
                case Event.ACTIVITY_STOPPED:
                case Event.ACTIVITY_DESTROYED:
                    // Treat activity destroys like activity stops.
                    event.mEventType = Event.ACTIVITY_STOPPED;
                    // Fallthrough
                case Event.ACTIVITY_STOPPED:
                    final ActivityData prevData =
                            mVisibleActivities.removeReturnOld(event.mInstanceId);
                    if (prevData == null) {
                        // The activity stop was already handled.
                        return;
                    }

                    ArraySet<String> tokens;
                    synchronized (mUsageReporters) {
                        tokens = mUsageReporters.removeReturnOld(event.mInstanceId);
@@ -517,7 +535,7 @@ public class UsageStatsService extends SystemService implements
                                final String token = tokens.valueAt(i);
                                try {
                                    mAppTimeLimit.noteUsageStop(
                                            buildFullToken(event.getPackageName(), token), userId);
                                            buildFullToken(event.mPackage, token), userId);
                                } catch (IllegalArgumentException iae) {
                                    Slog.w(TAG, "Failed to stop usage for during reporter death: "
                                            + iae);
@@ -525,18 +543,32 @@ public class UsageStatsService extends SystemService implements
                            }
                        }
                    }

                    synchronized (mVisibleActivities) {
                        if (mVisibleActivities.removeReturnOld(event.mInstanceId) != null) {
                    if (event.mTaskRootPackage == null) {
                        // Task Root info is missing. Repair the event based on previous data
                        event.mTaskRootPackage = prevData.mTaskRootPackage;
                        event.mTaskRootClass = prevData.mTaskRootClass;
                    }
                    try {
                                mAppTimeLimit.noteUsageStop(packageName, userId);
                        switch(mUsageSource) {
                            case USAGE_SOURCE_CURRENT_ACTIVITY:
                                mAppTimeLimit.noteUsageStop(event.mPackage, userId);
                                break;
                            case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
                            default:
                                mAppTimeLimit.noteUsageStop(event.mTaskRootPackage, userId);
                                break;
                        }
                    } catch (IllegalArgumentException iae) {
                        Slog.w(TAG, "Failed to note usage stop", iae);
                    }
                        }
                    }
                    break;
            }

            final UserUsageStatsService service =
                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
            service.reportEvent(event);

            mAppStandby.reportEvent(event, elapsedRealtime, userId);
        }
    }