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

Commit 4dc65d31 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by android-build-merger
Browse files

Merge "Unlock should always wait for pending PRE_BOOT." into nyc-dev

am: 89fa73fd

* commit '89fa73fd':
  Unlock should always wait for pending PRE_BOOT.

Change-Id: I0043da18fabef2c5c916a2e5562d9e613c2b057c
parents 091fba44 89fa73fd
Loading
Loading
Loading
Loading
+96 −23
Original line number Diff line number Diff line
@@ -20,9 +20,12 @@ import android.annotation.Nullable;
import android.content.Intent;
import android.os.Bundle;
import android.os.IProgressListener;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.MathUtils;

import com.android.internal.annotations.GuardedBy;

/**
 * Tracks and reports progress of a single task to a {@link IProgressListener}.
 * The reported progress of a task ranges from 0-100, but the task can be
@@ -44,33 +47,67 @@ import android.util.MathUtils;
 * }
 * </pre>
 *
 * This class is not thread safe.
 *
 * @hide
 */
public class ProgressReporter {
    public static final ProgressReporter NO_OP = new ProgressReporter(0, null);
    private static final int STATE_INIT = 0;
    private static final int STATE_STARTED = 1;
    private static final int STATE_FINISHED = 2;

    private final int mId;
    private final IProgressListener mListener;

    private Bundle mExtras = new Bundle();
    @GuardedBy("this")
    private final RemoteCallbackList<IProgressListener> mListeners = new RemoteCallbackList<>();

    @GuardedBy("this")
    private int mState = STATE_INIT;
    @GuardedBy("this")
    private int mProgress = 0;
    @GuardedBy("this")
    private Bundle mExtras = new Bundle();

    /**
     * Current segment range: first element is starting progress of this
     * segment, second element is length of segment.
     */
    @GuardedBy("this")
    private int[] mSegmentRange = new int[] { 0, 100 };

    /**
     * Create a new task with the given identifier whose progress will be
     * reported to the given listener.
     */
    public ProgressReporter(int id, @Nullable IProgressListener listener) {
    public ProgressReporter(int id) {
        mId = id;
        mListener = listener;
    }

    /**
     * Add given listener to watch for progress events. The current state will
     * be immediately dispatched to the given listener.
     */
    public void addListener(@Nullable IProgressListener listener) {
        if (listener == null) return;
        synchronized (this) {
            mListeners.register(listener);
            switch (mState) {
                case STATE_INIT:
                    // Nothing has happened yet
                    break;
                case STATE_STARTED:
                    try {
                        listener.onStarted(mId, null);
                        listener.onProgress(mId, mProgress, mExtras);
                    } catch (RemoteException ignored) {
                    }
                    break;
                case STATE_FINISHED:
                    try {
                        listener.onFinished(mId, null);
                    } catch (RemoteException ignored) {
                    }
                    break;
            }
        }
    }

    /**
@@ -102,6 +139,10 @@ public class ProgressReporter {
     * Set the fractional progress of the currently active segment.
     */
    public void setProgress(int n, int m, @Nullable CharSequence title) {
        synchronized (this) {
            if (mState != STATE_STARTED) {
                throw new IllegalStateException("Must be started to change progress");
            }
            mProgress = mSegmentRange[0]
                    + MathUtils.constrain((n * mSegmentRange[1]) / m, 0, mSegmentRange[1]);
            if (title != null) {
@@ -109,6 +150,7 @@ public class ProgressReporter {
            }
            notifyProgress(mId, mProgress, mExtras);
        }
    }

    /**
     * Start a new inner segment that will contribute the given range towards
@@ -116,18 +158,22 @@ public class ProgressReporter {
     * {@link #endSegment(int[])} when finished.
     */
    public int[] startSegment(int size) {
        synchronized (this) {
            final int[] lastRange = mSegmentRange;
            mSegmentRange = new int[] { mProgress, (size * mSegmentRange[1] / 100) };
            return lastRange;
        }
    }

    /**
     * End the current segment.
     */
    public void endSegment(int[] lastRange) {
        synchronized (this) {
            mProgress = mSegmentRange[0] + mSegmentRange[1];
            mSegmentRange = lastRange;
        }
    }

    int getProgress() {
        return mProgress;
@@ -137,28 +183,55 @@ public class ProgressReporter {
        return mSegmentRange;
    }

    /**
     * Report this entire task as being started.
     */
    public void start() {
        synchronized (this) {
            mState = STATE_STARTED;
            notifyStarted(mId, null);
            notifyProgress(mId, mProgress, mExtras);
        }
    }

    /**
     * Report this entire task as being finished.
     */
    public void finish() {
        synchronized (this) {
            mState = STATE_FINISHED;
            notifyFinished(mId, null);
            mListeners.kill();
        }
    }

    private void notifyStarted(int id, Bundle extras) {
        for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) {
            try {
                mListeners.getBroadcastItem(i).onStarted(id, extras);
            } catch (RemoteException ignored) {
            }
        }
        mListeners.finishBroadcast();
    }

    private void notifyProgress(int id, int progress, Bundle extras) {
        if (mListener != null) {
        for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) {
            try {
                mListener.onProgress(id, progress, extras);
                mListeners.getBroadcastItem(i).onProgress(id, progress, extras);
            } catch (RemoteException ignored) {
            }
        }
        mListeners.finishBroadcast();
    }

    public void notifyFinished(int id, Bundle extras) {
        if (mListener != null) {
    private void notifyFinished(int id, Bundle extras) {
        for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) {
            try {
                mListener.onFinished(id, extras);
                mListeners.getBroadcastItem(i).onFinished(id, extras);
            } catch (RemoteException ignored) {
            }
        }
        mListeners.finishBroadcast();
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@ public class ProgressReporterTest extends TestCase {
    @Override
    protected void setUp() throws Exception {
        super.setUp();
        r = new ProgressReporter(0, null);
        r = new ProgressReporter(0);
    }

    private void assertProgress(int expected) {
+1 −1
Original line number Diff line number Diff line
@@ -20676,7 +20676,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    @Override
    public boolean unlockUser(int userId, byte[] token, byte[] secret, IProgressListener listener) {
        return mUserController.unlockUser(userId, token, secret, new ProgressReporter(0, listener));
        return mUserController.unlockUser(userId, token, secret, listener);
    }
    @Override
+35 −27
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.IProgressListener;
import android.os.IRemoteCallback;
import android.os.IUserManager;
import android.os.Process;
@@ -83,7 +84,6 @@ import android.util.SparseIntArray;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ProgressReporter;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerService;
@@ -260,7 +260,7 @@ final class UserController {
     * Step from {@link UserState#STATE_RUNNING_LOCKED} to
     * {@link UserState#STATE_RUNNING_UNLOCKING}.
     */
    void finishUserUnlocking(final UserState uss, final ProgressReporter progress) {
    private void finishUserUnlocking(final UserState uss) {
        final int userId = uss.mHandle.getIdentifier();
        synchronized (mService) {
            // Bail if we ended up with a stale user
@@ -270,10 +270,13 @@ final class UserController {
            if (!isUserKeyUnlocked(userId)) return;

            if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
                uss.mUnlockProgress.start();

                // Prepare app storage before we go any further
                progress.setProgress(5, mService.mContext.getString(R.string.android_start_title));
                uss.mUnlockProgress.setProgress(5,
                        mService.mContext.getString(R.string.android_start_title));
                mUserManager.onBeforeUnlockUser(userId);
                progress.setProgress(20);
                uss.mUnlockProgress.setProgress(20);

                // Dispatch unlocked to system services
                mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0));
@@ -306,15 +309,15 @@ final class UserController {
                // Send PRE_BOOT broadcasts if fingerprint changed
                final UserInfo info = getUserInfo(userId);
                if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) {
                    progress.startSegment(80);
                    new PreBootBroadcaster(mService, userId, progress) {
                    uss.mUnlockProgress.startSegment(80);
                    new PreBootBroadcaster(mService, userId, uss.mUnlockProgress) {
                        @Override
                        public void onFinished() {
                            finishUserUnlocked(uss, progress);
                            finishUserUnlocked(uss);
                        }
                    }.sendNext();
                } else {
                    finishUserUnlocked(uss, progress);
                    finishUserUnlocked(uss);
                }
            }
        }
@@ -324,15 +327,15 @@ final class UserController {
     * Step from {@link UserState#STATE_RUNNING_UNLOCKING} to
     * {@link UserState#STATE_RUNNING_UNLOCKED}.
     */
    void finishUserUnlocked(UserState uss, ProgressReporter progress) {
    private void finishUserUnlocked(UserState uss) {
        try {
            finishUserUnlockedInternal(uss);
        } finally {
            progress.finish();
            uss.mUnlockProgress.finish();
        }
    }

    void finishUserUnlockedInternal(UserState uss) {
    private void finishUserUnlockedInternal(UserState uss) {
        final int userId = uss.mHandle.getIdentifier();
        synchronized (mService) {
            // Bail if we ended up with a stale user
@@ -860,7 +863,7 @@ final class UserController {
        return result;
    }

    boolean unlockUser(final int userId, byte[] token, byte[] secret, ProgressReporter progress) {
    boolean unlockUser(final int userId, byte[] token, byte[] secret, IProgressListener listener) {
        if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
                != PackageManager.PERMISSION_GRANTED) {
            String msg = "Permission Denial: unlockUser() from pid="
@@ -873,7 +876,7 @@ final class UserController {

        final long binderToken = Binder.clearCallingIdentity();
        try {
            return unlockUserCleared(userId, token, secret, progress);
            return unlockUserCleared(userId, token, secret, listener);
        } finally {
            Binder.restoreCallingIdentity(binderToken);
        }
@@ -887,23 +890,29 @@ final class UserController {
     */
    boolean maybeUnlockUser(final int userId) {
        // Try unlocking storage using empty token
        return unlockUserCleared(userId, null, null, ProgressReporter.NO_OP);
        return unlockUserCleared(userId, null, null, null);
    }

    private static void notifyFinished(int userId, IProgressListener listener) {
        if (listener == null) return;
        try {
            listener.onFinished(userId, null);
        } catch (RemoteException ignored) {
        }
    }

    boolean unlockUserCleared(final int userId, byte[] token, byte[] secret,
            ProgressReporter progress) {
            IProgressListener listener) {
        final UserState uss;
        synchronized (mService) {
            // Bail if already running unlocked, or if not running at all
            final UserState uss = mStartedUsers.get(userId);
            // Bail if user isn't actually running, otherwise register the given
            // listener to watch for unlock progress
            uss = mStartedUsers.get(userId);
            if (uss == null) {
                progress.finish();
                notifyFinished(userId, listener);
                return false;
            }
            switch (uss.state) {
                case STATE_RUNNING_UNLOCKING:
                case STATE_RUNNING_UNLOCKED:
                    progress.finish();
                    return true;
            } else {
                uss.mUnlockProgress.addListener(listener);
            }
        }

@@ -914,14 +923,13 @@ final class UserController {
                mountService.unlockUserKey(userId, userInfo.serialNumber, token, secret);
            } catch (RemoteException | RuntimeException e) {
                Slog.w(TAG, "Failed to unlock: " + e.getMessage());
                progress.finish();
                notifyFinished(userId, listener);
                return false;
            }
        }

        synchronized (mService) {
            final UserState uss = mStartedUsers.get(userId);
            finishUserUnlocking(uss, progress);
            finishUserUnlocking(uss);

            // We just unlocked a user, so let's now attempt to unlock any
            // managed profiles under that user.
+7 −3
Original line number Diff line number Diff line
@@ -16,9 +16,6 @@

package com.android.server.am;

import java.io.PrintWriter;
import java.util.ArrayList;

import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -28,6 +25,11 @@ import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;

import com.android.internal.util.ProgressReporter;

import java.io.PrintWriter;
import java.util.ArrayList;

public final class UserState {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "UserState" : TAG_AM;

@@ -47,6 +49,7 @@ public final class UserState {
    public final UserHandle mHandle;
    public final ArrayList<IStopUserCallback> mStopCallbacks
            = new ArrayList<IStopUserCallback>();
    public final ProgressReporter mUnlockProgress;

    public int state = STATE_BOOTING;
    public int lastState = STATE_BOOTING;
@@ -61,6 +64,7 @@ public final class UserState {

    public UserState(UserHandle handle) {
        mHandle = handle;
        mUnlockProgress = new ProgressReporter(handle.getIdentifier());
    }

    public boolean setState(int oldState, int newState) {