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
This commit is contained in:
David Anderson
2019-04-03 17:24:18 -07:00
parent ef68fc5a6d
commit f55f5d83de

View File

@@ -52,10 +52,12 @@ public class PasswordSlotManager {
// This maps each used password slot to the OS image that created it. Password slots are // 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 // 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. // 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() { public PasswordSlotManager() {
mSlotMap = loadSlotMap();
} }
@VisibleForTesting @VisibleForTesting
@@ -74,6 +76,11 @@ public class PasswordSlotManager {
* @throws RuntimeException * @throws RuntimeException
*/ */
public void refreshActiveSlots(Set<Integer> activeSlots) 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. // Update which slots are owned by the current image.
final HashSet<Integer> slotsToDelete = new HashSet<Integer>(); final HashSet<Integer> slotsToDelete = new HashSet<Integer>();
for (Map.Entry<Integer, String> entry : mSlotMap.entrySet()) { for (Map.Entry<Integer, String> entry : mSlotMap.entrySet()) {
@@ -100,6 +107,7 @@ public class PasswordSlotManager {
* @throws RuntimeException * @throws RuntimeException
*/ */
public void markSlotInUse(int slot) throws RuntimeException { public void markSlotInUse(int slot) throws RuntimeException {
ensureSlotMapLoaded();
if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) { if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) {
throw new RuntimeException("password slot " + slot + " is not available"); throw new RuntimeException("password slot " + slot + " is not available");
} }
@@ -113,6 +121,7 @@ public class PasswordSlotManager {
* @throws RuntimeException * @throws RuntimeException
*/ */
public void markSlotDeleted(int slot) throws RuntimeException { public void markSlotDeleted(int slot) throws RuntimeException {
ensureSlotMapLoaded();
if (mSlotMap.containsKey(slot) && mSlotMap.get(slot) != getMode()) { if (mSlotMap.containsKey(slot) && mSlotMap.get(slot) != getMode()) {
throw new RuntimeException("password slot " + slot + " cannot be deleted"); throw new RuntimeException("password slot " + slot + " cannot be deleted");
} }
@@ -126,6 +135,7 @@ public class PasswordSlotManager {
* @return Integer set of all used slots. * @return Integer set of all used slots.
*/ */
public Set<Integer> getUsedSlots() { public Set<Integer> getUsedSlots() {
ensureSlotMapLoaded();
return Collections.unmodifiableSet(mSlotMap.keySet()); return Collections.unmodifiableSet(mSlotMap.keySet());
} }
@@ -167,8 +177,21 @@ public class PasswordSlotManager {
return new HashMap<Integer, String>(); return new HashMap<Integer, String>();
} }
private void ensureSlotMapLoaded() {
if (mSlotMap == null) {
mSlotMap = loadSlotMap();
if (mActiveSlots != null) {
refreshActiveSlots(mActiveSlots);
mActiveSlots = null;
}
}
}
@VisibleForTesting @VisibleForTesting
protected void saveSlotMap(OutputStream stream) throws IOException { protected void saveSlotMap(OutputStream stream) throws IOException {
if (mSlotMap == null) {
return;
}
final Properties props = new Properties(); final Properties props = new Properties();
for (Map.Entry<Integer, String> entry : mSlotMap.entrySet()) { for (Map.Entry<Integer, String> entry : mSlotMap.entrySet()) {
props.setProperty(entry.getKey().toString(), entry.getValue()); props.setProperty(entry.getKey().toString(), entry.getValue());
@@ -177,6 +200,9 @@ public class PasswordSlotManager {
} }
private void saveSlotMap() { private void saveSlotMap() {
if (mSlotMap == null) {
return;
}
if (!getSlotMapFile().getParentFile().exists()) { if (!getSlotMapFile().getParentFile().exists()) {
Slog.w(TAG, "Not saving slot map, " + getSlotMapDir() + " does not exist"); Slog.w(TAG, "Not saving slot map, " + getSlotMapDir() + " does not exist");
return; return;