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

Commit 4c72df04 authored by Fyodor Kupolov's avatar Fyodor Kupolov
Browse files

Fix StrictMode I/O violations

onBeforeUnlockUser now happens on a worker thread that allows I/O.
In addition to that STATE_RUNNING_UNLOCKING is only set after
onBeforeUnlockUser. Otherwise non-DBA processes would be able to start
before unlocking completes (causing b/68995913)

Recents are now loaded on a worker thread

Bug: 68872660
Bug: 68871386
Test: UserControllerTest
Test: Tested on marlin/walleye (+factory reset)
Test: create/start work profile. create/start guest user
Change-Id: I4694dfa0bd523de33f0e600f2db22d02610b535c
parent c8e3c7c8
Loading
Loading
Loading
Loading
+25 −13
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemServiceManager;
import com.android.server.pm.UserManagerService;
@@ -355,27 +356,35 @@ class UserController implements Handler.Callback {
        // Only keep marching forward if user is actually unlocked
        if (!StorageManager.isUserKeyUnlocked(userId)) return;
        synchronized (mLock) {
            // Bail if we ended up with a stale user
            if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;

            // Do not proceed if unexpected state
            if (!uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
            // Do not proceed if unexpected state or a stale user
            if (mStartedUsers.get(userId) != uss || uss.state != STATE_RUNNING_LOCKED) {
                return;
            }
        }
        mInjector.getUserManagerInternal().setUserState(userId, uss.state);
        uss.mUnlockProgress.start();

        // Prepare app storage before we go any further
        uss.mUnlockProgress.setProgress(5,
                    mInjector.getContext().getString(R.string.android_start_title));

        // Call onBeforeUnlockUser on a worker thread that allows disk I/O
        FgThread.getHandler().post(() -> {
            mInjector.getUserManager().onBeforeUnlockUser(userId);
            synchronized (mLock) {
                // Do not proceed if unexpected state
                if (!uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
                    return;
                }
            }
            mInjector.getUserManagerInternal().setUserState(userId, uss.state);

            uss.mUnlockProgress.setProgress(20);

            // Dispatch unlocked to system services; when fully dispatched,
            // that calls through to the next "unlocked" phase
            mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
                    .sendToTarget();
        });
    }

    /**
@@ -1819,7 +1828,10 @@ class UserController implements Handler.Callback {
            case SYSTEM_USER_UNLOCK_MSG:
                final int userId = msg.arg1;
                mInjector.getSystemServiceManager().unlockUser(userId);
                // Loads recents on a worker thread that allows disk I/O
                FgThread.getHandler().post(() -> {
                    mInjector.loadUserRecents(userId);
                });
                if (userId == UserHandle.USER_SYSTEM) {
                    mInjector.startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
                }