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

Commit e11bcc6c authored by Howard Chen's avatar Howard Chen
Browse files

Replace copy-on-write PDB with an empty one

This is follow-up for aosp/1549486. It replaces the copy-on-write PDB
with an empty PDB created by the gsid because exposing the real PDB
in the DSU mode is unnecessary. The empty PDB will triggers formatting
during boot. To support this, we replace all OutputStream operations
with FileChannel operations backed by a RandomAccessFile to avoid
the backing file to be truncated during formatting. This also simplify
the current implementation which mixes OutputStream and FileChannel.
We appened a FileChannel.force() to FileChannel operations because the
PDB can be a raw block or a backing file on a file system. The force
method can make sure the file system cache is flushed.

Bug: 175852148
Test: vts-tradefed run vts -m vts_kernel_net_tests
Test: gts-tradefed run gts -m GtsOemLockServiceTestCases -t com.google.android.oemlock.gts.OemLockServiceTest
Test: cts-tradefed run cts -m CtsPermission2TestCases -t android.permission2.cts.PrivappPermissionsTest

Change-Id: I9aaa2193a3c7a93988590276cdbdf1a21f230cb3
parent 7a2f9c06
Loading
Loading
Loading
Loading
+41 −82
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.FileUtils;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -45,6 +44,7 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
@@ -131,13 +131,13 @@ public class PersistentDataBlockService extends SystemService {
    private static final String FLASH_LOCK_UNLOCKED = "0";

    private final Context mContext;
    private final String mDataBlockFile;
    private final boolean mIsRunningDSU;
    private final Object mLock = new Object();
    private final CountDownLatch mInitDoneSignal = new CountDownLatch(1);

    private int mAllowedUid = -1;
    private long mBlockDeviceSize;
    private String mDataBlockFile;

    @GuardedBy("mLock")
    private boolean mIsWritable = true;
@@ -145,8 +145,12 @@ public class PersistentDataBlockService extends SystemService {
    public PersistentDataBlockService(Context context) {
        super(context);
        mContext = context;
        mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
        mIsRunningDSU = SystemProperties.getBoolean(GSI_RUNNING_PROP, false);
        if (mIsRunningDSU) {
            mDataBlockFile = GSI_SANDBOX;
        } else {
            mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
        }
        mBlockDeviceSize = -1; // Load lazily
    }

@@ -260,9 +264,13 @@ public class PersistentDataBlockService extends SystemService {
    private long getBlockDeviceSize() {
        synchronized (mLock) {
            if (mBlockDeviceSize == -1) {
                if (mIsRunningDSU) {
                    mBlockDeviceSize = MAX_DATA_BLOCK_SIZE;
                } else {
                    mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile);
                }
            }
        }

        return mBlockDeviceSize;
    }
@@ -290,40 +298,30 @@ public class PersistentDataBlockService extends SystemService {
        return true;
    }

    private FileOutputStream getBlockOutputStream() throws IOException {
        if (!mIsRunningDSU) {
            return new FileOutputStream(new File(mDataBlockFile));
        } else {
            File sandbox = new File(GSI_SANDBOX);
            File realpdb = new File(SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP));
            if (!sandbox.exists()) {
                FileUtils.copy(realpdb, sandbox);
                mDataBlockFile = GSI_SANDBOX;
            }
            Slog.i(TAG, "PersistentDataBlock copy-on-write");
            return new FileOutputStream(sandbox);
        }
    private FileChannel getBlockOutputChannel() throws IOException {
        return new RandomAccessFile(mDataBlockFile, "rw").getChannel();
    }

    private boolean computeAndWriteDigestLocked() {
        byte[] digest = computeDigestLocked(null);
        if (digest != null) {
            DataOutputStream outputStream;
            FileChannel channel;
            try {
                outputStream = new DataOutputStream(getBlockOutputStream());
                channel = getBlockOutputChannel();
            } catch (IOException e) {
                Slog.e(TAG, "partition not available?", e);
                return false;
            }

            try {
                outputStream.write(digest, 0, DIGEST_SIZE_BYTES);
                outputStream.flush();
                ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES);
                buf.put(digest);
                buf.flip();
                channel.write(buf);
                channel.force(true);
            } catch (IOException e) {
                Slog.e(TAG, "failed to write block checksum", e);
                return false;
            } finally {
                IoUtils.closeQuietly(outputStream);
            }
            return true;
        } else {
@@ -374,25 +372,18 @@ public class PersistentDataBlockService extends SystemService {
    }

    private void formatPartitionLocked(boolean setOemUnlockEnabled) {
        DataOutputStream outputStream;
        try {
            outputStream = new DataOutputStream(getBlockOutputStream());
        } catch (IOException e) {
            Slog.e(TAG, "partition not available?", e);
            return;
        }

        byte[] data = new byte[DIGEST_SIZE_BYTES];
        try {
            outputStream.write(data, 0, DIGEST_SIZE_BYTES);
            outputStream.writeInt(PARTITION_TYPE_MARKER);
            outputStream.writeInt(0); // data size
            outputStream.flush();
            FileChannel channel = getBlockOutputChannel();
            ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES + HEADER_SIZE);
            buf.put(new byte[DIGEST_SIZE_BYTES]);
            buf.putInt(PARTITION_TYPE_MARKER);
            buf.putInt(0);
            channel.write(buf);
            channel.force(true);
        } catch (IOException e) {
            Slog.e(TAG, "failed to format block", e);
            return;
        } finally {
            IoUtils.closeQuietly(outputStream);
        }

        doSetOemUnlockEnabledLocked(setOemUnlockEnabled);
@@ -400,16 +391,9 @@ public class PersistentDataBlockService extends SystemService {
    }

    private void doSetOemUnlockEnabledLocked(boolean enabled) {
        FileOutputStream outputStream;
        try {
            outputStream = getBlockOutputStream();
        } catch (IOException e) {
            Slog.e(TAG, "partition not available", e);
            return;
        }

        try {
            FileChannel channel = outputStream.getChannel();
            FileChannel channel = getBlockOutputChannel();

            channel.position(getBlockDeviceSize() - 1);

@@ -417,13 +401,12 @@ public class PersistentDataBlockService extends SystemService {
            data.put(enabled ? (byte) 1 : (byte) 0);
            data.flip();
            channel.write(data);
            outputStream.flush();
            channel.force(true);
        } catch (IOException e) {
            Slog.e(TAG, "unable to access persistent partition", e);
            return;
        } finally {
            SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
            IoUtils.closeQuietly(outputStream);
        }
    }

@@ -477,35 +460,32 @@ public class PersistentDataBlockService extends SystemService {
                return (int) -maxBlockSize;
            }

            DataOutputStream outputStream;
            FileChannel channel;
            try {
                outputStream = new DataOutputStream(getBlockOutputStream());
                channel = getBlockOutputChannel();
            } catch (IOException e) {
                Slog.e(TAG, "partition not available?", e);
               return -1;
            }

            ByteBuffer headerAndData = ByteBuffer.allocate(data.length + HEADER_SIZE);
            ByteBuffer headerAndData = ByteBuffer.allocate(
                                           data.length + HEADER_SIZE + DIGEST_SIZE_BYTES);
            headerAndData.put(new byte[DIGEST_SIZE_BYTES]);
            headerAndData.putInt(PARTITION_TYPE_MARKER);
            headerAndData.putInt(data.length);
            headerAndData.put(data);

            headerAndData.flip();
            synchronized (mLock) {
                if (!mIsWritable) {
                    IoUtils.closeQuietly(outputStream);
                    return -1;
                }

                try {
                    byte[] checksum = new byte[DIGEST_SIZE_BYTES];
                    outputStream.write(checksum, 0, DIGEST_SIZE_BYTES);
                    outputStream.write(headerAndData.array());
                    outputStream.flush();
                    channel.write(headerAndData);
                    channel.force(true);
                } catch (IOException e) {
                    Slog.e(TAG, "failed writing to the persistent data block", e);
                    return -1;
                } finally {
                    IoUtils.closeQuietly(outputStream);
                }

                if (computeAndWriteDigestLocked()) {
@@ -565,17 +545,6 @@ public class PersistentDataBlockService extends SystemService {
        public void wipe() {
            enforceOemUnlockWritePermission();

            if (mIsRunningDSU) {
                File sandbox = new File(GSI_SANDBOX);
                if (sandbox.exists()) {
                    if (sandbox.delete()) {
                        mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
                    } else {
                        Slog.e(TAG, "Failed to wipe sandbox persistent data block");
                    }
                }
                return;
            }
            synchronized (mLock) {
                int ret = nativeWipe(mDataBlockFile);

@@ -733,28 +702,18 @@ public class PersistentDataBlockService extends SystemService {
        }

        private void writeDataBuffer(long offset, ByteBuffer dataBuffer) {
            FileOutputStream outputStream;
            try {
                outputStream = getBlockOutputStream();
            } catch (IOException e) {
                Slog.e(TAG, "partition not available", e);
                return;
            }
            synchronized (mLock) {
                if (!mIsWritable) {
                    IoUtils.closeQuietly(outputStream);
                    return;
                }
                try {
                    FileChannel channel = outputStream.getChannel();
                    FileChannel channel = getBlockOutputChannel();
                    channel.position(offset);
                    channel.write(dataBuffer);
                    outputStream.flush();
                    channel.force(true);
                } catch (IOException e) {
                    Slog.e(TAG, "unable to access persistent partition", e);
                    return;
                } finally {
                    IoUtils.closeQuietly(outputStream);
                }

                computeAndWriteDigestLocked();