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

Commit c346d8f1 authored by David Anderson's avatar David Anderson
Browse files

Load /metadata/password_slots/slot_map lazily.

This fixes a 6ms regression in SystemServerTiming_MakeLockSettingsServiceReady, since the slot map is only needed when adding or removing a PIN.

Bug: 128334055
Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/locksettings
Test: atest PasswordSlotManagerTests
Test: atest google/perf/boottime/boottime-test
Test: PIN unlocks device after booting into GSI
Change-Id: Ib2e0c05575d07496792188716b962ca622df28e6
Merged-In: Ib2e0c05575d07496792188716b962ca622df28e6
parent 902e8227
Loading
Loading
Loading
Loading
+28 −2
Original line number Diff line number Diff line
@@ -52,10 +52,12 @@ public class PasswordSlotManager {
    // This maps each used password slot to the OS image that created it. Password slots are
    // integer keys/indices into secure storage. The OS image is recorded as a string. The factory
    // image is "host" and GSIs are "gsi<N>" where N >= 1.
    private final Map<Integer, String> mSlotMap;
    private Map<Integer, String> mSlotMap;

    // Cache the active slots until loadSlotMap() is called.
    private Set<Integer> mActiveSlots;

    public PasswordSlotManager() {
        mSlotMap = loadSlotMap();
    }

    @VisibleForTesting
@@ -74,6 +76,11 @@ public class PasswordSlotManager {
     * @throws RuntimeException
     */
    public void refreshActiveSlots(Set<Integer> activeSlots) throws RuntimeException {
        if (mSlotMap == null) {
            mActiveSlots = new HashSet<Integer>(activeSlots);
            return;
        }

        // Update which slots are owned by the current image.
        final HashSet<Integer> slotsToDelete = new HashSet<Integer>();
        for (Map.Entry<Integer, String> entry : mSlotMap.entrySet()) {
@@ -100,6 +107,7 @@ public class PasswordSlotManager {
     * @throws RuntimeException
     */
    public void markSlotInUse(int slot) throws RuntimeException {
        ensureSlotMapLoaded();
        if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) {
            throw new RuntimeException("password slot " + slot + " is not available");
        }
@@ -113,6 +121,7 @@ public class PasswordSlotManager {
     * @throws RuntimeException
     */
    public void markSlotDeleted(int slot) throws RuntimeException {
        ensureSlotMapLoaded();
        if (mSlotMap.containsKey(slot) && mSlotMap.get(slot) != getMode()) {
            throw new RuntimeException("password slot " + slot + " cannot be deleted");
        }
@@ -126,6 +135,7 @@ public class PasswordSlotManager {
     * @return Integer set of all used slots.
     */
    public Set<Integer> getUsedSlots() {
        ensureSlotMapLoaded();
        return Collections.unmodifiableSet(mSlotMap.keySet());
    }

@@ -167,8 +177,21 @@ public class PasswordSlotManager {
        return new HashMap<Integer, String>();
    }

    private void ensureSlotMapLoaded() {
        if (mSlotMap == null) {
            mSlotMap = loadSlotMap();
            if (mActiveSlots != null) {
                refreshActiveSlots(mActiveSlots);
                mActiveSlots = null;
            }
        }
    }

    @VisibleForTesting
    protected void saveSlotMap(OutputStream stream) throws IOException {
        if (mSlotMap == null) {
            return;
        }
        final Properties props = new Properties();
        for (Map.Entry<Integer, String> entry : mSlotMap.entrySet()) {
            props.setProperty(entry.getKey().toString(), entry.getValue());
@@ -177,6 +200,9 @@ public class PasswordSlotManager {
    }

    private void saveSlotMap() {
        if (mSlotMap == null) {
            return;
        }
        if (!getSlotMapFile().getParentFile().exists()) {
            Slog.w(TAG, "Not saving slot map, " + getSlotMapDir() + " does not exist");
            return;