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

Commit 3061f0b6 authored by Anton Potapov's avatar Anton Potapov Committed by Android (Google) Code Review
Browse files

Merge "Post UserTracker callbacks to background" into main

parents 1c083f69 f726ce4f
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -203,7 +203,6 @@ import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

@@ -2440,7 +2439,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                        handleDevicePolicyManagerStateChanged(msg.arg1);
                        break;
                    case MSG_USER_SWITCHING:
                        handleUserSwitching(msg.arg1, (CountDownLatch) msg.obj);
                        handleUserSwitching(msg.arg1, (Runnable) msg.obj);
                        break;
                    case MSG_USER_SWITCH_COMPLETE:
                        handleUserSwitchComplete(msg.arg1);
@@ -2741,10 +2740,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    }

    private final UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() {

        @Override
        public void onUserChanging(int newUser, Context userContext, CountDownLatch latch) {
        public void onUserChanging(int newUser, @NonNull Context userContext,
                @NonNull Runnable resultCallback) {
            mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
                    newUser, 0, latch));
                    newUser, 0, resultCallback));
        }

        @Override
@@ -3575,7 +3576,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
     * Handle {@link #MSG_USER_SWITCHING}
     */
    @VisibleForTesting
    void handleUserSwitching(int userId, CountDownLatch latch) {
    void handleUserSwitching(int userId, Runnable resultCallback) {
        mLogger.logUserSwitching(userId, "from UserTracker");
        Assert.isMainThread();
        clearBiometricRecognized();
@@ -3589,7 +3590,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                cb.onUserSwitching(userId);
            }
        }
        latch.countDown();
        resultCallback.run();
    }

    /**
+6 −7
Original line number Diff line number Diff line
@@ -117,7 +117,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.function.Supplier;

@@ -492,9 +491,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
            notifySystemUiStateFlags(mSysUiState.getFlags());

            notifyConnectionChanged();
            if (mLatchForOnUserChanging != null) {
                mLatchForOnUserChanging.countDown();
                mLatchForOnUserChanging = null;
            if (mDoneUserChanging != null) {
                mDoneUserChanging.run();
                mDoneUserChanging = null;
            }
        }

@@ -550,14 +549,14 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
        }
    };

    private CountDownLatch mLatchForOnUserChanging;
    private Runnable mDoneUserChanging;
    private final UserTracker.Callback mUserChangedCallback =
            new UserTracker.Callback() {
                @Override
                public void onUserChanging(int newUser, @NonNull Context userContext,
                        CountDownLatch latch) {
                        @NonNull Runnable resultCallback) {
                    mConnectionBackoffAttempts = 0;
                    mLatchForOnUserChanging = latch;
                    mDoneUserChanging = resultCallback;
                    internalConnectToCurrentUser("User changed");
                }
            };
+6 −7
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.systemui.settings
import android.content.Context
import android.content.pm.UserInfo
import android.os.UserHandle
import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executor

/**
@@ -68,8 +67,8 @@ interface UserTracker : UserContentResolverProvider, UserContextProvider {
    interface Callback {

        /**
         * Same as {@link onUserChanging(Int, Context, CountDownLatch)} but the latch will be
         * auto-decremented after the completion of this method.
         * Same as {@link onUserChanging(Int, Context, Runnable)} but the callback will be
         * called automatically after the completion of this method.
         */
        fun onUserChanging(newUser: Int, userContext: Context) {}

@@ -78,12 +77,12 @@ interface UserTracker : UserContentResolverProvider, UserContextProvider {
         * Override this method to run things while the screen is frozen for the user switch.
         * Please use {@link #onUserChanged} if the task doesn't need to push the unfreezing of the
         * screen further. Please be aware that code executed in this callback will lengthen the
         * user switch duration. When overriding this method, countDown() MUST be called on the
         * latch once execution is complete.
         * user switch duration. When overriding this method, resultCallback#run() MUST be called
         * once the  execution is complete.
         */
        fun onUserChanging(newUser: Int, userContext: Context, latch: CountDownLatch) {
        fun onUserChanging(newUser: Int, userContext: Context, resultCallback: Runnable) {
            onUserChanging(newUser, userContext)
            latch.countDown()
            resultCallback.run()
        }

        /**
+73 −7
Original line number Diff line number Diff line
@@ -33,11 +33,22 @@ import androidx.annotation.GuardedBy
import androidx.annotation.WorkerThread
import com.android.systemui.Dumpable
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.util.Assert
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import java.io.PrintWriter
import java.lang.ref.WeakReference
import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executor
import javax.inject.Provider
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

@@ -58,20 +69,26 @@ import kotlin.reflect.KProperty
 */
open class UserTrackerImpl internal constructor(
    private val context: Context,
    private val featureFlagsProvider: Provider<FeatureFlagsClassic>,
    private val userManager: UserManager,
    private val iActivityManager: IActivityManager,
    private val dumpManager: DumpManager,
    private val backgroundHandler: Handler
    private val appScope: CoroutineScope,
    private val backgroundContext: CoroutineDispatcher,
    private val backgroundHandler: Handler,
) : UserTracker, Dumpable, BroadcastReceiver() {

    companion object {
        private const val TAG = "UserTrackerImpl"
        private const val USER_CHANGE_THRESHOLD = 5L * 1000 // 5 sec
    }

    var initialized = false
        private set

    private val mutex = Any()
    private val isBackgroundUserSwitchEnabled: Boolean get() =
        featureFlagsProvider.get().isEnabled(Flags.USER_TRACKER_BACKGROUND_CALLBACKS)

    override var userId: Int by SynchronizedDelegate(context.userId)
        protected set
@@ -103,6 +120,10 @@ open class UserTrackerImpl internal constructor(
    @GuardedBy("callbacks")
    private val callbacks: MutableList<DataItem> = ArrayList()

    private var beforeUserSwitchingJob: Job? = null
    private var userSwitchingJob: Job? = null
    private var afterUserSwitchingJob: Job? = null

    open fun initialize(startingUser: Int) {
        if (initialized) {
            return
@@ -119,7 +140,7 @@ open class UserTrackerImpl internal constructor(
            addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED)
            addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED)
        }
        context.registerReceiverForAllUsers(this, filter, null /* permission */, backgroundHandler)
        context.registerReceiverForAllUsers(this, filter, null, backgroundHandler)

        registerUserSwitchObserver()

@@ -162,17 +183,40 @@ open class UserTrackerImpl internal constructor(
    private fun registerUserSwitchObserver() {
        iActivityManager.registerUserSwitchObserver(object : UserSwitchObserver() {
            override fun onBeforeUserSwitching(newUserId: Int) {
                if (isBackgroundUserSwitchEnabled) {
                    beforeUserSwitchingJob?.cancel()
                    beforeUserSwitchingJob = appScope.launch(backgroundContext) {
                        handleBeforeUserSwitching(newUserId)
                    }
                } else {
                    handleBeforeUserSwitching(newUserId)
                }
            }

            override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) {
                if (isBackgroundUserSwitchEnabled) {
                    userSwitchingJob?.cancel()
                    userSwitchingJob = appScope.launch(backgroundContext) {
                        handleUserSwitchingCoroutines(newUserId) {
                            reply?.sendResult(null)
                        }
                    }
                } else {
                    handleUserSwitching(newUserId)
                    reply?.sendResult(null)
                }
            }

            override fun onUserSwitchComplete(newUserId: Int) {
                if (isBackgroundUserSwitchEnabled) {
                    afterUserSwitchingJob?.cancel()
                    afterUserSwitchingJob = appScope.launch(backgroundContext) {
                        handleUserSwitchComplete(newUserId)
                    }
                } else {
                    handleUserSwitchComplete(newUserId)
                }
            }
        }, TAG)
    }

@@ -195,7 +239,7 @@ open class UserTrackerImpl internal constructor(
            val callback = it.callback.get()
            if (callback != null) {
                it.executor.execute {
                    callback.onUserChanging(userId, userContext, latch)
                    callback.onUserChanging(userId, userContext) { latch.countDown() }
                }
            } else {
                latch.countDown()
@@ -204,6 +248,28 @@ open class UserTrackerImpl internal constructor(
        latch.await()
    }

    @WorkerThread
    protected open suspend fun handleUserSwitchingCoroutines(newUserId: Int, onDone: () -> Unit) =
            coroutineScope {
                Assert.isNotMainThread()
                Log.i(TAG, "Switching to user $newUserId")

                for (callbackDataItem in synchronized(callbacks) { callbacks.toList() }) {
                    val callback: UserTracker.Callback = callbackDataItem.callback.get() ?: continue
                    launch(callbackDataItem.executor.asCoroutineDispatcher()) {
                        val mutex = Mutex(true)
                        val thresholdLogJob = launch(backgroundContext) {
                            delay(USER_CHANGE_THRESHOLD)
                            Log.e(TAG, "Failed to finish $callback in time")
                        }
                        callback.onUserChanging(userId, userContext) { mutex.unlock() }
                        mutex.lock()
                        thresholdLogJob.cancel()
                    }.join()
                }
                onDone()
            }

    @WorkerThread
    protected open fun handleUserSwitchComplete(newUserId: Int) {
        Assert.isNotMainThread()
+12 −2
Original line number Diff line number Diff line
@@ -25,8 +25,10 @@ import android.os.UserManager;

import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.DisplayTrackerImpl;
import com.android.systemui.settings.UserContentResolverProvider;
@@ -42,6 +44,11 @@ import dagger.Provides;
import dagger.multibindings.ClassKey;
import dagger.multibindings.IntoMap;

import javax.inject.Provider;

import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.CoroutineScope;

/**
 * Dagger Module for classes found within the com.android.systemui.settings package.
 */
@@ -60,14 +67,17 @@ public abstract class MultiUserUtilsModule {
    @Provides
    static UserTracker provideUserTracker(
            Context context,
            Provider<FeatureFlagsClassic> featureFlagsProvider,
            UserManager userManager,
            IActivityManager iActivityManager,
            DumpManager dumpManager,
            @Application CoroutineScope appScope,
            @Background CoroutineDispatcher backgroundDispatcher,
            @Background Handler handler
    ) {
        int startingUser = ActivityManager.getCurrentUser();
        UserTrackerImpl tracker = new UserTrackerImpl(context, userManager, iActivityManager,
                dumpManager, handler);
        UserTrackerImpl tracker = new UserTrackerImpl(context, featureFlagsProvider, userManager,
                iActivityManager, dumpManager, appScope, backgroundDispatcher, handler);
        tracker.initialize(startingUser);
        return tracker;
    }
Loading