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

Commit 9cd8b7c1 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Multi-user optimizations." into tm-dev am: 1d23f37e

parents 5b193628 1d23f37e
Loading
Loading
Loading
Loading
+38 −8
Original line number Diff line number Diff line
@@ -164,6 +164,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
@@ -633,8 +634,8 @@ public final class Settings implements Watchable, Snappable {
                runtimePermissionsPersistence, new Consumer<Integer>() {
            @Override
            public void accept(Integer userId) {
                mRuntimePermissionsPersistence.writeStateForUser(userId,
                        mPermissionDataProvider, mPackages, mSharedUsers, mHandler, mLock);
                mRuntimePermissionsPersistence.writeStateForUser(userId, mPermissionDataProvider,
                        mPackages, mSharedUsers, mHandler, mLock, /*sync=*/false);
            }
        });
        mPermissionDataProvider = permissionDataProvider;
@@ -5292,7 +5293,7 @@ public final class Settings implements Watchable, Snappable {
    public void writePermissionStateForUserLPr(int userId, boolean sync) {
        if (sync) {
            mRuntimePermissionsPersistence.writeStateForUser(userId, mPermissionDataProvider,
                    mPackages, mSharedUsers, /*handler=*/null, mLock);
                    mPackages, mSharedUsers, /*handler=*/null, mLock, /*sync=*/true);
        } else {
            mRuntimePermissionsPersistence.writeStateForUserAsync(userId);
        }
@@ -5370,12 +5371,17 @@ public final class Settings implements Watchable, Snappable {
    }

    private static final class RuntimePermissionPersistence {
        private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 200;
        // 200-400ms delay to avoid monopolizing PMS lock when written for multiple users.
        private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 300;
        private static final double WRITE_PERMISSIONS_DELAY_JITTER = 0.3;

        private static final long MAX_WRITE_PERMISSIONS_DELAY_MILLIS = 2000;

        private static final int UPGRADE_VERSION = -1;
        private static final int INITIAL_VERSION = 0;

        private static final Random sRandom = new Random();

        private String mExtendedFingerprint;

        @GuardedBy("mPersistenceLock")
@@ -5396,6 +5402,11 @@ public final class Settings implements Watchable, Snappable {
        // The mapping keys are user ids.
        private final SparseLongArray mLastNotWrittenMutationTimesMillis = new SparseLongArray();

        @GuardedBy("mLock")
        // Tracking the mutations that haven't yet been written to legacy state.
        // This avoids unnecessary work when writing settings for multiple users.
        private boolean mIsLegacyPermissionStateStale = false;

        @GuardedBy("mLock")
        // The mapping keys are user ids.
        private final SparseIntArray mVersions = new SparseIntArray();
@@ -5472,9 +5483,22 @@ public final class Settings implements Watchable, Snappable {
            return PackagePartitions.FINGERPRINT + "?pc_version=" + version;
        }

        private static long uniformRandom(double low, double high) {
            double mag = high - low;
            return (long) (sRandom.nextDouble() * mag + low);
        }

        private static long nextWritePermissionDelayMillis() {
            final long delay = WRITE_PERMISSIONS_DELAY_MILLIS;
            final double jitter = WRITE_PERMISSIONS_DELAY_JITTER;
            return delay + uniformRandom(-jitter * delay, jitter * delay);
        }

        public void writeStateForUserAsync(int userId) {
            synchronized (mLock) {
                mIsLegacyPermissionStateStale = true;
                final long currentTimeMillis = SystemClock.uptimeMillis();
                final long writePermissionDelayMillis = nextWritePermissionDelayMillis();

                if (mWriteScheduled.get(userId)) {
                    mAsyncHandler.removeMessages(userId);
@@ -5493,7 +5517,7 @@ public final class Settings implements Watchable, Snappable {
                    // Hold off a bit more as settings are frequently changing.
                    final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis
                            + MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0);
                    final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS,
                    final long writeDelayMillis = Math.min(writePermissionDelayMillis,
                            maxDelayMillis);

                    Message message = mAsyncHandler.obtainMessage(userId);
@@ -5501,7 +5525,7 @@ public final class Settings implements Watchable, Snappable {
                } else {
                    mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);
                    Message message = mAsyncHandler.obtainMessage(userId);
                    mAsyncHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);
                    mAsyncHandler.sendMessageDelayed(message, writePermissionDelayMillis);
                    mWriteScheduled.put(userId, true);
                }
            }
@@ -5511,21 +5535,27 @@ public final class Settings implements Watchable, Snappable {
                legacyPermissionDataProvider,
                @NonNull WatchedArrayMap<String, ? extends PackageStateInternal> packageStates,
                @NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers,
                @Nullable Handler pmHandler, @NonNull Object pmLock) {
                @Nullable Handler pmHandler, @NonNull Object pmLock,
                boolean sync) {
            final int version;
            final String fingerprint;
            final boolean isLegacyPermissionStateStale;
            synchronized (mLock) {
                mAsyncHandler.removeMessages(userId);
                mWriteScheduled.delete(userId);

                version = mVersions.get(userId, INITIAL_VERSION);
                fingerprint = mFingerprints.get(userId);
                isLegacyPermissionStateStale = mIsLegacyPermissionStateStale;
                mIsLegacyPermissionStateStale = false;
            }

            Runnable writer = () -> {
                final RuntimePermissionsState runtimePermissions;
                synchronized (pmLock) {
                    if (sync || isLegacyPermissionStateStale) {
                        legacyPermissionDataProvider.writeLegacyPermissionStateTEMP();
                    }

                    Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
                            new ArrayMap<>();