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

Commit 157fbcfb authored by Varun Shah's avatar Varun Shah
Browse files

Update deletion conditions for a package's UsageStats.

If a profile owner is defined for a specific user, do not delete usage
stats for a package on package deletion.

Bug: 197399948
Test: atest UserUsageStatsServiceTest
Test: atest UsageStatsTest [all]
Change-Id: I94a8e3dfca8ef4c7616f77944d61726e06043b85
Merged-In: I94a8e3dfca8ef4c7616f77944d61726e06043b85
parent 5b663962
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.app.admin;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
@@ -76,6 +77,13 @@ public abstract class DevicePolicyManagerInternal {
    public abstract void addOnCrossProfileWidgetProvidersChangeListener(
            OnCrossProfileWidgetProvidersChangeListener listener);

    /**
     * @param userHandle the handle of the user whose profile owner is being fetched.
     * @return the configured supervision app if it exists and is the device owner or policy owner.
     */
    public abstract @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(
            @NonNull UserHandle userHandle);

    /**
     * Checks if an app with given uid is an active device owner of its user.
     *
+7 −0
Original line number Diff line number Diff line
@@ -12643,6 +12643,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            }
        }
        @Override
        public @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(
                @NonNull UserHandle userHandle) {
            return DevicePolicyManagerService.this.getProfileOwnerOrDeviceOwnerSupervisionComponent(
                    userHandle);
        }
        @Override
        public boolean isActiveDeviceOwner(int uid) {
            return isDeviceOwner(new CallerIdentity(uid, null, null));
+1 −1
Original line number Diff line number Diff line
@@ -72,7 +72,7 @@ public class UserUsageStatsServiceTest {
        HashMap<String, Long> installedPkgs = new HashMap<>();
        installedPkgs.put(TEST_PACKAGE_NAME, System.currentTimeMillis());

        mService.init(System.currentTimeMillis(), installedPkgs);
        mService.init(System.currentTimeMillis(), installedPkgs, true);
    }

    @After
+21 −5
Original line number Diff line number Diff line
@@ -380,6 +380,7 @@ public class UsageStatsService extends SystemService implements
        if (userId == UserHandle.USER_SYSTEM) {
            UsageStatsIdleService.scheduleUpdateMappingsJob(getContext());
        }
        final boolean deleteObsoleteData = shouldDeleteObsoleteData(UserHandle.of(userId));
        synchronized (mLock) {
            // This should be safe to add this early. Other than reportEventOrAddToQueue, every
            // other user grabs the lock before accessing
@@ -402,7 +403,7 @@ public class UsageStatsService extends SystemService implements
            boolean needToFlush = !pendingEvents.isEmpty();

            initializeUserUsageStatsServiceLocked(userId, System.currentTimeMillis(),
                    installedPackages);
                    installedPackages, deleteObsoleteData);
            final UserUsageStatsService userService = getUserUsageStatsServiceLocked(userId);
            if (userService == null) {
                Slog.i(TAG, "Attempted to unlock stopped or removed user " + userId);
@@ -596,13 +597,13 @@ public class UsageStatsService extends SystemService implements
     * when the user is initially unlocked.
     */
    private void initializeUserUsageStatsServiceLocked(int userId, long currentTimeMillis,
            HashMap<String, Long> installedPackages) {
            HashMap<String, Long> installedPackages, boolean deleteObsoleteData) {
        final File usageStatsDir = new File(Environment.getDataSystemCeDirectory(userId),
                "usagestats");
        final UserUsageStatsService service = new UserUsageStatsService(getContext(), userId,
                usageStatsDir, this);
        try {
            service.init(currentTimeMillis, installedPackages);
            service.init(currentTimeMillis, installedPackages, deleteObsoleteData);
            mUserState.put(userId, service);
        } catch (Exception e) {
            if (mUserManager.isUserUnlocked(userId)) {
@@ -1165,6 +1166,10 @@ public class UsageStatsService extends SystemService implements
     * Called by the Binder stub.
     */
    private boolean updatePackageMappingsData() {
        // don't update the mappings if a profile user is defined
        if (!shouldDeleteObsoleteData(UserHandle.SYSTEM)) {
            return true; // return true so job scheduler doesn't reschedule the job
        }
        // fetch the installed packages outside the lock so it doesn't block package manager.
        final HashMap<String, Long> installedPkgs = getInstalledPackages(UserHandle.USER_SYSTEM);
        synchronized (mLock) {
@@ -1309,6 +1314,13 @@ public class UsageStatsService extends SystemService implements
        }
    }

    private boolean shouldDeleteObsoleteData(UserHandle userHandle) {
        final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
        // If a profile owner is not defined for the given user, obsolete data should be deleted
        return dpmInternal == null
                || dpmInternal.getProfileOwnerOrDeviceOwnerSupervisionComponent(userHandle) == null;
    }

    private String buildFullToken(String packageName, String token) {
        final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1);
        sb.append(packageName);
@@ -2532,8 +2544,12 @@ public class UsageStatsService extends SystemService implements
    private class MyPackageMonitor extends PackageMonitor {
        @Override
        public void onPackageRemoved(String packageName, int uid) {
            mHandler.obtainMessage(MSG_PACKAGE_REMOVED, getChangingUserId(), 0, packageName)
            final int changingUserId = getChangingUserId();
            // Only remove the package's data if a profile owner is not defined for the user
            if (shouldDeleteObsoleteData(UserHandle.of(changingUserId))) {
                mHandler.obtainMessage(MSG_PACKAGE_REMOVED, changingUserId, 0, packageName)
                        .sendToTarget();
            }
            super.onPackageRemoved(packageName, uid);
        }
    }
+6 −4
Original line number Diff line number Diff line
@@ -115,8 +115,9 @@ class UserUsageStatsService {
        mSystemTimeSnapshot = System.currentTimeMillis();
    }

    void init(final long currentTimeMillis, HashMap<String, Long> installedPackages) {
        readPackageMappingsLocked(installedPackages);
    void init(final long currentTimeMillis, HashMap<String, Long> installedPackages,
            boolean deleteObsoleteData) {
        readPackageMappingsLocked(installedPackages, deleteObsoleteData);
        mDatabase.init(currentTimeMillis);
        if (mDatabase.wasUpgradePerformed()) {
            mDatabase.prunePackagesDataOnUpgrade(installedPackages);
@@ -180,12 +181,13 @@ class UserUsageStatsService {
        return mDatabase.onPackageRemoved(packageName, timeRemoved);
    }

    private void readPackageMappingsLocked(HashMap<String, Long> installedPackages) {
    private void readPackageMappingsLocked(HashMap<String, Long> installedPackages,
            boolean deleteObsoleteData) {
        mDatabase.readMappingsLocked();
        // Package mappings for the system user are updated after 24 hours via a job scheduled by
        // UsageStatsIdleService to ensure restored data is not lost on first boot. Additionally,
        // this makes user service initialization a little quicker on subsequent boots.
        if (mUserId != UserHandle.USER_SYSTEM) {
        if (mUserId != UserHandle.USER_SYSTEM && deleteObsoleteData) {
            updatePackageMappingsLocked(installedPackages);
        }
    }