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

Commit 2515cd5c authored by Eric Biggers's avatar Eric Biggers
Browse files

Clean up the LockSettingsStorage file methods

For file paths, consistently use File instead of String, and don't use
ambiguous variable names like 'name' and 'key'.  Remove unnecessary
conversions to absolute paths, as the paths are all absolute already.

Consistently use 'data' when referring to a file's data, instead of
'hash', 'stored', or 'value'.

Don't catch exceptions from deleteFile(), as it doesn't throw
exceptions.

Remove the DEBUG field, as it's hardcoded to false, and it only enabled
the printing of two messages which were redundant with each other.

Test: atest com.android.server.locksettings
Change-Id: If0dd16d8c16015d129bda75e93600e60a1341f82
parent 01a1f52f
Loading
Loading
Loading
Loading
+63 −78
Original line number Diff line number Diff line
@@ -70,7 +70,6 @@ class LockSettingsStorage extends WatchableImpl {

    private static final String TAG = "LockSettingsStorage";
    private static final String TABLE = "locksettings";
    private static final boolean DEBUG = false;

    private static final String COLUMN_KEY = "name";
    private static final String COLUMN_USERID = "user";
@@ -83,11 +82,10 @@ class LockSettingsStorage extends WatchableImpl {
            COLUMN_KEY, COLUMN_VALUE
    };

    private static final String SYSTEM_DIRECTORY = "/system/";
    private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key";

    private static final String REBOOT_ESCROW_FILE = "reboot.escrow.key";
    private static final String REBOOT_ESCROW_SERVER_BLOB = "reboot.escrow.server.blob.key";
    private static final String REBOOT_ESCROW_SERVER_BLOB_FILE = "reboot.escrow.server.blob.key";

    private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/";

@@ -225,13 +223,7 @@ class LockSettingsStorage extends WatchableImpl {
    }

    public void removeChildProfileLock(int userId) {
        if (DEBUG)
            Slog.e(TAG, "Remove child profile lock for user: " + userId);
        try {
        deleteFile(getChildProfileLockFile(userId));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void writeChildProfileLock(int userId, byte[] lock) {
@@ -263,39 +255,39 @@ class LockSettingsStorage extends WatchableImpl {
    }

    public void writeRebootEscrowServerBlob(byte[] serverBlob) {
        writeFile(getRebootEscrowServerBlob(), serverBlob);
        writeFile(getRebootEscrowServerBlobFile(), serverBlob);
    }

    public byte[] readRebootEscrowServerBlob() {
        return readFile(getRebootEscrowServerBlob());
        return readFile(getRebootEscrowServerBlobFile());
    }

    public boolean hasRebootEscrowServerBlob() {
        return hasFile(getRebootEscrowServerBlob());
        return hasFile(getRebootEscrowServerBlobFile());
    }

    public void removeRebootEscrowServerBlob() {
        deleteFile(getRebootEscrowServerBlob());
        deleteFile(getRebootEscrowServerBlobFile());
    }

    private boolean hasFile(String name) {
        byte[] contents = readFile(name);
    private boolean hasFile(File path) {
        byte[] contents = readFile(path);
        return contents != null && contents.length > 0;
    }

    private byte[] readFile(String name) {
    private byte[] readFile(File path) {
        int version;
        synchronized (mCache) {
            if (mCache.hasFile(name)) {
                return mCache.peekFile(name);
            if (mCache.hasFile(path)) {
                return mCache.peekFile(path);
            }
            version = mCache.getVersion();
        }

        byte[] stored = null;
        try (RandomAccessFile raf = new RandomAccessFile(name, "r")) {
            stored = new byte[(int) raf.length()];
            raf.readFully(stored, 0, stored.length);
        byte[] data = null;
        try (RandomAccessFile raf = new RandomAccessFile(path, "r")) {
            data = new byte[(int) raf.length()];
            raf.readFully(data, 0, data.length);
            raf.close();
        } catch (FileNotFoundException suppressed) {
            // readFile() is also called by hasFile() to check the existence of files, in this
@@ -303,8 +295,8 @@ class LockSettingsStorage extends WatchableImpl {
        } catch (IOException e) {
            Slog.e(TAG, "Cannot read file " + e);
        }
        mCache.putFileIfUnchanged(name, stored, version);
        return stored;
        mCache.putFileIfUnchanged(path, data, version);
        return data;
    }

    private void fsyncDirectory(File directory) {
@@ -318,23 +310,21 @@ class LockSettingsStorage extends WatchableImpl {
        }
    }

    private void writeFile(String name, byte[] hash) {
    private void writeFile(File path, byte[] data) {
        synchronized (mFileWriteLock) {
            RandomAccessFile raf = null;
            try {
                // Write the hash to file, requiring each write to be synchronized to the
                // Write the data to the file, requiring each write to be synchronized to the
                // underlying storage device immediately to avoid data loss in case of power loss.
                // This also ensures future secdiscard operation on the file succeeds since the
                // file would have been allocated on flash.
                raf = new RandomAccessFile(name, "rws");
                // Truncate the file if pattern is null, to clear the lock
                if (hash == null || hash.length == 0) {
                raf = new RandomAccessFile(path, "rws");
                // Truncate the file if the data is empty.
                if (data == null || data.length == 0) {
                    raf.setLength(0);
                } else {
                    raf.write(hash, 0, hash.length);
                    raf.write(data, 0, data.length);
                }
                raf.close();
                fsyncDirectory((new File(name)).getAbsoluteFile().getParentFile());
                fsyncDirectory(path.getParentFile());
            } catch (IOException e) {
                Slog.e(TAG, "Error writing to file " + e);
            } finally {
@@ -346,70 +336,66 @@ class LockSettingsStorage extends WatchableImpl {
                    }
                }
            }
            mCache.putFile(name, hash);
            mCache.putFile(path, data);
            dispatchChange(this);
        }
    }

    private void deleteFile(String name) {
        if (DEBUG) Slog.e(TAG, "Delete file " + name);
    private void deleteFile(File path) {
        synchronized (mFileWriteLock) {
            File file = new File(name);
            if (file.exists()) {
                file.delete();
                mCache.putFile(name, null);
            if (path.exists()) {
                path.delete();
                mCache.putFile(path, null);
            }
            dispatchChange(this);
        }
    }

    @VisibleForTesting
    String getChildProfileLockFile(int userId) {
        return getLockCredentialFilePathForUser(userId, CHILD_PROFILE_LOCK_FILE);
    File getChildProfileLockFile(int userId) {
        return getLockCredentialFileForUser(userId, CHILD_PROFILE_LOCK_FILE);
    }

    @VisibleForTesting
    String getRebootEscrowFile(int userId) {
        return getLockCredentialFilePathForUser(userId, REBOOT_ESCROW_FILE);
    File getRebootEscrowFile(int userId) {
        return getLockCredentialFileForUser(userId, REBOOT_ESCROW_FILE);
    }

    @VisibleForTesting
    String getRebootEscrowServerBlob() {
    File getRebootEscrowServerBlobFile() {
        // There is a single copy of server blob for all users.
        return getLockCredentialFilePathForUser(UserHandle.USER_SYSTEM, REBOOT_ESCROW_SERVER_BLOB);
        return getLockCredentialFileForUser(UserHandle.USER_SYSTEM, REBOOT_ESCROW_SERVER_BLOB_FILE);
    }

    private String getLockCredentialFilePathForUser(int userId, String basename) {
        String dataSystemDirectory = Environment.getDataDirectory().getAbsolutePath() +
                        SYSTEM_DIRECTORY;
    private File getLockCredentialFileForUser(int userId, String fileName) {
        if (userId == 0) {
            // Leave it in the same place for user 0
            return dataSystemDirectory + basename;
            // The files for user 0 are stored directly in /data/system, since this is where they
            // originally were, and they haven't been moved yet.
            return new File(Environment.getDataSystemDirectory(), fileName);
        } else {
            return new File(Environment.getUserSystemDirectory(userId), basename).getAbsolutePath();
            return new File(Environment.getUserSystemDirectory(userId), fileName);
        }
    }

    public void writeSyntheticPasswordState(int userId, long handle, String name, byte[] data) {
        ensureSyntheticPasswordDirectoryForUser(userId);
        writeFile(getSynthenticPasswordStateFilePathForUser(userId, handle, name), data);
        writeFile(getSyntheticPasswordStateFileForUser(userId, handle, name), data);
    }

    public byte[] readSyntheticPasswordState(int userId, long handle, String name) {
        return readFile(getSynthenticPasswordStateFilePathForUser(userId, handle, name));
        return readFile(getSyntheticPasswordStateFileForUser(userId, handle, name));
    }

    public void deleteSyntheticPasswordState(int userId, long handle, String name) {
        String path = getSynthenticPasswordStateFilePathForUser(userId, handle, name);
        File file = new File(path);
        if (file.exists()) {
        File path = getSyntheticPasswordStateFileForUser(userId, handle, name);
        if (path.exists()) {
            try (RandomAccessFile raf = new RandomAccessFile(path, "rws")) {
                final int fileSize = (int) raf.length();
                raf.write(new byte[fileSize]);
            } catch (Exception e) {
                Slog.w(TAG, "Failed to zeroize " + path, e);
            } finally {
                file.delete();
                path.delete();
                dispatchChange(this);
            }
            mCache.putFile(path, null);
@@ -458,12 +444,9 @@ class LockSettingsStorage extends WatchableImpl {
        }
    }

    @VisibleForTesting
    protected String getSynthenticPasswordStateFilePathForUser(int userId, long handle,
            String name) {
        final File baseDir = getSyntheticPasswordDirectoryForUser(userId);
        final String baseName = formatSimple("%016x.%s", handle, name);
        return new File(baseDir, baseName).getAbsolutePath();
    private File getSyntheticPasswordStateFileForUser(int userId, long handle, String name) {
        String fileName = formatSimple("%016x.%s", handle, name);
        return new File(getSyntheticPasswordDirectoryForUser(userId), fileName);
    }

    public void removeUser(int userId) {
@@ -489,7 +472,7 @@ class LockSettingsStorage extends WatchableImpl {
            // The directory itself will be deleted as part of user deletion operation by the
            // framework, so only need to purge cache here.
            //TODO: (b/34600579) invoke secdiscardable
            mCache.purgePath(spStateDir.getAbsolutePath());
            mCache.purgePath(spStateDir);
        } finally {
            db.endTransaction();
        }
@@ -670,7 +653,7 @@ class LockSettingsStorage extends WatchableImpl {
        final UserManager um = UserManager.get(mContext);
        for (UserInfo user : um.getUsers()) {
            File userPath = getSyntheticPasswordDirectoryForUser(user.id);
            pw.println(String.format("User %d [%s]:", user.id, userPath.getAbsolutePath()));
            pw.println(String.format("User %d [%s]:", user.id, userPath));
            pw.increaseIndent();
            File[] files = userPath.listFiles();
            if (files != null) {
@@ -783,20 +766,21 @@ class LockSettingsStorage extends WatchableImpl {
            remove(CacheKey.TYPE_KEY_VALUE, key, userId);
        }

        byte[] peekFile(String fileName) {
            return copyOf((byte[]) peek(CacheKey.TYPE_FILE, fileName, -1 /* userId */));
        byte[] peekFile(File path) {
            return copyOf((byte[]) peek(CacheKey.TYPE_FILE, path.toString(), -1 /* userId */));
        }

        boolean hasFile(String fileName) {
            return contains(CacheKey.TYPE_FILE, fileName, -1 /* userId */);
        boolean hasFile(File path) {
            return contains(CacheKey.TYPE_FILE, path.toString(), -1 /* userId */);
        }

        void putFile(String key, byte[] value) {
            put(CacheKey.TYPE_FILE, key, copyOf(value), -1 /* userId */);
        void putFile(File path, byte[] data) {
            put(CacheKey.TYPE_FILE, path.toString(), copyOf(data), -1 /* userId */);
        }

        void putFileIfUnchanged(String key, byte[] value, int version) {
            putIfUnchanged(CacheKey.TYPE_FILE, key, copyOf(value), -1 /* userId */, version);
        void putFileIfUnchanged(File path, byte[] data, int version) {
            putIfUnchanged(CacheKey.TYPE_FILE, path.toString(), copyOf(data), -1 /* userId */,
                    version);
        }

        void setFetched(int userId) {
@@ -854,10 +838,11 @@ class LockSettingsStorage extends WatchableImpl {
            return data != null ? Arrays.copyOf(data, data.length) : null;
        }

        synchronized void purgePath(String path) {
        synchronized void purgePath(File path) {
            final String pathStr = path.toString();
            for (int i = mCache.size() - 1; i >= 0; i--) {
                CacheKey entry = mCache.keyAt(i);
                if (entry.type == CacheKey.TYPE_FILE && entry.key.startsWith(path)) {
                if (entry.type == CacheKey.TYPE_FILE && entry.key.startsWith(pathStr)) {
                    mCache.removeAt(i);
                }
            }
+12 −19
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ import java.util.Arrays;

public class LockSettingsStorageTestable extends LockSettingsStorage {

    public File mStorageDir;
    public final File mStorageDir;
    public PersistentDataBlockManagerInternal mPersistentDataBlockManager;
    private byte[] mPersistentData;

@@ -64,25 +64,23 @@ public class LockSettingsStorageTestable extends LockSettingsStorage {
    }

    @Override
    String getChildProfileLockFile(int userId) {
        return makeDirs(mStorageDir,
                super.getChildProfileLockFile(userId)).getAbsolutePath();
    File getChildProfileLockFile(int userId) {
        return remapToStorageDir(super.getChildProfileLockFile(userId));
    }

    @Override
    String getRebootEscrowServerBlob() {
        return makeDirs(mStorageDir, super.getRebootEscrowServerBlob()).getAbsolutePath();
    File getRebootEscrowServerBlobFile() {
        return remapToStorageDir(super.getRebootEscrowServerBlobFile());
    }

    @Override
    String getRebootEscrowFile(int userId) {
        return makeDirs(mStorageDir, super.getRebootEscrowFile(userId)).getAbsolutePath();
    File getRebootEscrowFile(int userId) {
        return remapToStorageDir(super.getRebootEscrowFile(userId));
    }

    @Override
    protected File getSyntheticPasswordDirectoryForUser(int userId) {
        return makeDirs(mStorageDir, super.getSyntheticPasswordDirectoryForUser(
                userId).getAbsolutePath());
        return remapToStorageDir(super.getSyntheticPasswordDirectoryForUser(userId));
    }

    @Override
@@ -90,14 +88,9 @@ public class LockSettingsStorageTestable extends LockSettingsStorage {
        return mPersistentDataBlockManager;
    }

    private File makeDirs(File baseDir, String filePath) {
        File path = new File(filePath);
        if (path.getParent() == null) {
            return new File(baseDir, filePath);
        } else {
            File mappedDir = new File(baseDir, path.getParent());
            mappedDir.mkdirs();
            return new File(mappedDir, path.getName());
        }
    private File remapToStorageDir(File origPath) {
        File mappedPath = new File(mStorageDir, origPath.toString());
        mappedPath.getParentFile().mkdirs();
        return mappedPath;
    }
}
+5 −4
Original line number Diff line number Diff line
@@ -304,14 +304,15 @@ public class LockSettingsStorageTests {
    public void testFileLocation_Owner() {
        LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext());

        assertEquals("/data/system/gatekeeper.profile.key", storage.getChildProfileLockFile(0));
        assertEquals(new File("/data/system/gatekeeper.profile.key"),
                storage.getChildProfileLockFile(0));
    }

    @Test
    public void testFileLocation_SecondaryUser() {
        LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext());

        assertEquals("/data/system/users/1/gatekeeper.profile.key",
        assertEquals(new File("/data/system/users/1/gatekeeper.profile.key"),
                storage.getChildProfileLockFile(1));
    }

@@ -319,7 +320,7 @@ public class LockSettingsStorageTests {
    public void testFileLocation_ProfileToSecondary() {
        LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext());

        assertEquals("/data/system/users/2/gatekeeper.profile.key",
        assertEquals(new File("/data/system/users/2/gatekeeper.profile.key"),
                storage.getChildProfileLockFile(2));
    }

@@ -327,7 +328,7 @@ public class LockSettingsStorageTests {
    public void testFileLocation_ProfileToOwner() {
        LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext());

        assertEquals("/data/system/users/3/gatekeeper.profile.key",
        assertEquals(new File("/data/system/users/3/gatekeeper.profile.key"),
                storage.getChildProfileLockFile(3));
    }