From 649c198cf3c5c3c436d2d66f8bd25213770f607c Mon Sep 17 00:00:00 2001 From: Howard Chen Date: Wed, 23 Dec 2020 15:55:59 +0800 Subject: [PATCH 1/2] Support PersistentDataBlockService in DSU Currently the PersistentDataBlockService does not start when running a Dynamic System Update. This CL adds a sandbox-mode PersistentDataBlockService when running a DSU for the test_harness environment. Bug: 175852148 Bug: 175078763 Test: gsi_tool install & \ finish the vts_kernel_net_tests w/o suspension 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 Test: atest com.android.server.devicepolicy.DevicePolicyManagerTest Test: atest com.android.server.devicepolicy.FactoryResetProtectionPolicyTest Test: atest com.android.cts.devicepolicy.MixedDeviceOwnerTest#testFactoryResetProtectionPolicy Test: atest com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testFactoryResetProtectionPolicy Test: atest LockSettingsStorageTests Test: atest frameworks/base/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java Change-Id: I0547d757cf023443d9a00bec962db3f2aad3ff04 --- .../server/PersistentDataBlockService.java | 40 +++++++++++++++---- .../java/com/android/server/SystemServer.java | 5 +-- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java index 00d8b0f1bed4d..7bbd116d9a5a8 100644 --- a/services/core/java/com/android/server/PersistentDataBlockService.java +++ b/services/core/java/com/android/server/PersistentDataBlockService.java @@ -37,6 +37,7 @@ import com.android.internal.annotations.GuardedBy; import libcore.io.IoUtils; +import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; @@ -44,6 +45,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.security.MessageDigest; @@ -103,6 +105,8 @@ import java.util.concurrent.TimeUnit; public class PersistentDataBlockService extends SystemService { private static final String TAG = PersistentDataBlockService.class.getSimpleName(); + private static final String GSI_RUNNING_PROP = "ro.gsid.image_running"; + private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst"; private static final int HEADER_SIZE = 8; // Magic number to mark block device as adhering to the format consumed by this service @@ -128,6 +132,7 @@ public class PersistentDataBlockService extends SystemService { 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); @@ -141,6 +146,7 @@ public class PersistentDataBlockService extends SystemService { super(context); mContext = context; mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP); + mIsRunningDSU = SystemProperties.getBoolean(GSI_RUNNING_PROP, false); mBlockDeviceSize = -1; // Load lazily } @@ -284,14 +290,22 @@ public class PersistentDataBlockService extends SystemService { return true; } + private OutputStream getBlockOutputStream() throws IOException { + if (mIsRunningDSU) { + Slog.i(TAG, "data is read-only when running a DSU"); + return new ByteArrayOutputStream(); + } else { + return new FileOutputStream(new File(mDataBlockFile)); + } + } + private boolean computeAndWriteDigestLocked() { byte[] digest = computeDigestLocked(null); if (digest != null) { DataOutputStream outputStream; try { - outputStream = new DataOutputStream( - new FileOutputStream(new File(mDataBlockFile))); - } catch (FileNotFoundException e) { + outputStream = new DataOutputStream(getBlockOutputStream()); + } catch (IOException e) { Slog.e(TAG, "partition not available?", e); return false; } @@ -356,8 +370,8 @@ public class PersistentDataBlockService extends SystemService { private void formatPartitionLocked(boolean setOemUnlockEnabled) { DataOutputStream outputStream; try { - outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile))); - } catch (FileNotFoundException e) { + outputStream = new DataOutputStream(getBlockOutputStream()); + } catch (IOException e) { Slog.e(TAG, "partition not available?", e); return; } @@ -381,6 +395,10 @@ public class PersistentDataBlockService extends SystemService { private void doSetOemUnlockEnabledLocked(boolean enabled) { FileOutputStream outputStream; + if (mIsRunningDSU) { + Slog.i(TAG, "data is read-only when running a DSU"); + return; + } try { outputStream = new FileOutputStream(new File(mDataBlockFile)); } catch (FileNotFoundException e) { @@ -459,8 +477,8 @@ public class PersistentDataBlockService extends SystemService { DataOutputStream outputStream; try { - outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile))); - } catch (FileNotFoundException e) { + outputStream = new DataOutputStream(getBlockOutputStream()); + } catch (IOException e) { Slog.e(TAG, "partition not available?", e); return -1; } @@ -545,6 +563,10 @@ public class PersistentDataBlockService extends SystemService { public void wipe() { enforceOemUnlockWritePermission(); + if (mIsRunningDSU) { + Slog.i(TAG, "data is read-only when running a DSU"); + return; + } synchronized (mLock) { int ret = nativeWipe(mDataBlockFile); @@ -703,6 +725,10 @@ public class PersistentDataBlockService extends SystemService { private void writeDataBuffer(long offset, ByteBuffer dataBuffer) { FileOutputStream outputStream; + if (mIsRunningDSU) { + Slog.i(TAG, "data is read-only when running a DSU"); + return; + } try { outputStream = new FileOutputStream(new File(mDataBlockFile)); } catch (FileNotFoundException e) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index a6a99f232ef45..7db0615339f07 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -331,8 +331,6 @@ public final class SystemServer { private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file"; private static final String BLOCK_MAP_FILE = "/cache/recovery/block.map"; - private static final String GSI_RUNNING_PROP = "ro.gsid.image_running"; - // maximum number of binder threads used for system_server // will be higher than the system default private static final int sMaxBinderThreads = 31; @@ -1441,8 +1439,7 @@ public final class SystemServer { t.traceEnd(); final boolean hasPdb = !SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals(""); - final boolean hasGsi = SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0; - if (hasPdb && !hasGsi) { + if (hasPdb) { t.traceBegin("StartPersistentDataBlock"); mSystemServiceManager.startService(PersistentDataBlockService.class); t.traceEnd(); From e827aec67096f1f7b0ccde8d250a0271a2c39c59 Mon Sep 17 00:00:00 2001 From: Howard Chen Date: Fri, 25 Dec 2020 17:32:07 +0800 Subject: [PATCH 2/2] Support copy-on-write persistent data block when running a DSU The persistent data block is protected when running a DSU. This CL adds a copy-on-write scratchpad for the persistent data block and let the test environment to have an emulated writable pdb service. Bug: 175852148 Test: gsi_tool install & pass the 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: I8af15775dbc5f8c570bd4eb4faec5036b7b43ebc --- .../server/PersistentDataBlockService.java | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java index 7bbd116d9a5a8..351e616b433b5 100644 --- a/services/core/java/com/android/server/PersistentDataBlockService.java +++ b/services/core/java/com/android/server/PersistentDataBlockService.java @@ -23,6 +23,7 @@ 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; @@ -37,7 +38,6 @@ import com.android.internal.annotations.GuardedBy; import libcore.io.IoUtils; -import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; @@ -45,7 +45,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.security.MessageDigest; @@ -105,6 +104,7 @@ import java.util.concurrent.TimeUnit; public class PersistentDataBlockService extends SystemService { private static final String TAG = PersistentDataBlockService.class.getSimpleName(); + private static final String GSI_SANDBOX = "/data/gsi_persistent_data"; private static final String GSI_RUNNING_PROP = "ro.gsid.image_running"; private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst"; @@ -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; @@ -290,12 +290,18 @@ public class PersistentDataBlockService extends SystemService { return true; } - private OutputStream getBlockOutputStream() throws IOException { - if (mIsRunningDSU) { - Slog.i(TAG, "data is read-only when running a DSU"); - return new ByteArrayOutputStream(); - } else { + 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); } } @@ -395,13 +401,9 @@ public class PersistentDataBlockService extends SystemService { private void doSetOemUnlockEnabledLocked(boolean enabled) { FileOutputStream outputStream; - if (mIsRunningDSU) { - Slog.i(TAG, "data is read-only when running a DSU"); - return; - } try { - outputStream = new FileOutputStream(new File(mDataBlockFile)); - } catch (FileNotFoundException e) { + outputStream = getBlockOutputStream(); + } catch (IOException e) { Slog.e(TAG, "partition not available", e); return; } @@ -564,7 +566,14 @@ public class PersistentDataBlockService extends SystemService { enforceOemUnlockWritePermission(); if (mIsRunningDSU) { - Slog.i(TAG, "data is read-only when running a DSU"); + 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) { @@ -725,13 +734,9 @@ public class PersistentDataBlockService extends SystemService { private void writeDataBuffer(long offset, ByteBuffer dataBuffer) { FileOutputStream outputStream; - if (mIsRunningDSU) { - Slog.i(TAG, "data is read-only when running a DSU"); - return; - } try { - outputStream = new FileOutputStream(new File(mDataBlockFile)); - } catch (FileNotFoundException e) { + outputStream = getBlockOutputStream(); + } catch (IOException e) { Slog.e(TAG, "partition not available", e); return; }