From 6287488399d7d14f2091bd84bf4a4c6175dd4894 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Sat, 19 Mar 2022 16:51:40 +0800 Subject: [PATCH 1/2] dynsystem: Enlarge default shared memory size and allow size override This modest adjustment 8KiB -> 64KiB significantly boosts the DSU installation time: * physical device: 2m34s -> 45s * virtual device: 46s -> 30s Also make the shared memory size customizable for fine-tuning. Bug: 225310919 Test: start a Dynamic System installation and check its execution time. Change-Id: I0418ba19c3824d31feafce54a71c054061d010e8 --- .../dynsystem/InstallationAsyncTask.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index b439f8421b738..998aeeab4b474 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -23,9 +23,11 @@ import android.os.AsyncTask; import android.os.Build; import android.os.MemoryFile; import android.os.ParcelFileDescriptor; +import android.os.SystemProperties; import android.os.image.DynamicSystemManager; import android.service.persistentdata.PersistentDataBlockManager; import android.util.Log; +import android.util.Range; import android.webkit.URLUtil; import org.json.JSONException; @@ -48,7 +50,12 @@ class InstallationAsyncTask extends AsyncTask { private static final String TAG = "InstallationAsyncTask"; - private static final int READ_BUFFER_SIZE = 1 << 13; + private static final int MIN_SHARED_MEMORY_SIZE = 8 << 10; // 8KiB + private static final int MAX_SHARED_MEMORY_SIZE = 1024 << 10; // 1MiB + private static final int DEFAULT_SHARED_MEMORY_SIZE = 64 << 10; // 64KiB + private static final String SHARED_MEMORY_SIZE_PROP = + "dynamic_system.data_transfer.shared_memory.size"; + private static final long MIN_PROGRESS_TO_PUBLISH = 1 << 27; private static final List UNSUPPORTED_PARTITIONS = @@ -131,6 +138,7 @@ class InstallationAsyncTask extends AsyncTask { void onResult(int resultCode, Throwable detail); } + private final int mSharedMemorySize; private final String mUrl; private final String mDsuSlot; private final String mPublicKey; @@ -164,6 +172,11 @@ class InstallationAsyncTask extends AsyncTask { Context context, DynamicSystemManager dynSystem, ProgressListener listener) { + mSharedMemorySize = + Range.create(MIN_SHARED_MEMORY_SIZE, MAX_SHARED_MEMORY_SIZE) + .clamp( + SystemProperties.getInt( + SHARED_MEMORY_SIZE_PROP, DEFAULT_SHARED_MEMORY_SIZE)); mUrl = url; mDsuSlot = dsuSlot; mPublicKey = publicKey; @@ -541,10 +554,10 @@ class InstallationAsyncTask extends AsyncTask { Log.d(TAG, "Start installing: " + partitionName); - MemoryFile memoryFile = new MemoryFile("dsu_" + partitionName, READ_BUFFER_SIZE); + MemoryFile memoryFile = new MemoryFile("dsu_" + partitionName, mSharedMemorySize); ParcelFileDescriptor pfd = new ParcelFileDescriptor(memoryFile.getFileDescriptor()); - mInstallationSession.setAshmem(pfd, READ_BUFFER_SIZE); + mInstallationSession.setAshmem(pfd, memoryFile.length()); mPartitionName = partitionName; mPartitionSize = partitionSize; @@ -553,10 +566,10 @@ class InstallationAsyncTask extends AsyncTask { long prevInstalledSize = 0; long installedSize = 0; - byte[] bytes = new byte[READ_BUFFER_SIZE]; + byte[] bytes = new byte[memoryFile.length()]; int numBytesRead; - while ((numBytesRead = sis.read(bytes, 0, READ_BUFFER_SIZE)) != -1) { + while ((numBytesRead = sis.read(bytes, 0, bytes.length)) != -1) { if (isCancelled()) { return; } From 9b4f3eaf17e3200fe77a7b094abb6a7a5f7a854f Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Sun, 20 Mar 2022 16:49:32 +0800 Subject: [PATCH 2/2] dynsystem.SparseInputStream: Implement read(buf, off, len) InstallationAsyncTask calls SparseInputStream.read(buf, off, len), however SparseInputStream didn't override that method, so the method actually fallbacks to the default implementation, which is a for-loop calling read() (single byte). This is a significant performance hit. This modest fix boosts the DSU installation time significantly: * physical device: 45s -> 15s * virtual device: 30s -> 7s Bug: 225310919 Test: start a Dynamic System installation Change-Id: I5a61dc2e9554719aece43491b813f6647b4bcc65 --- .../android/dynsystem/SparseInputStream.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java index 4117d0f07e0f4..7d2326693a174 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java @@ -133,36 +133,32 @@ public class SparseInputStream extends InputStream { return mLeft == 0; } - /** - * It overrides the InputStream.read(byte[] buf) - */ - public int read(byte[] buf) throws IOException { + @Override + public int read(byte[] buf, int off, int len) throws IOException { if (!mIsSparse) { - return mIn.read(buf); + return mIn.read(buf, off, len); } if (prepareChunk()) return -1; int n = -1; switch (mCur.mChunkType) { case SparseChunk.RAW: - n = mIn.read(buf, 0, (int) min(mLeft, buf.length)); + n = mIn.read(buf, off, (int) min(mLeft, len)); mLeft -= n; return n; case SparseChunk.DONTCARE: - n = (int) min(mLeft, buf.length); - Arrays.fill(buf, 0, n - 1, (byte) 0); + n = (int) min(mLeft, len); + Arrays.fill(buf, off, off + n, (byte) 0); mLeft -= n; return n; case SparseChunk.FILL: // The FILL type is rarely used, so use a simple implmentation. - return super.read(buf); + return super.read(buf, off, len); default: throw new IOException("Unsupported Chunk:" + mCur.toString()); } } - /** - * It overrides the InputStream.read() - */ + @Override public int read() throws IOException { if (!mIsSparse) { return mIn.read();