diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index 2af7e00f9128..38d851eb76aa 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -41,6 +41,10 @@ import java.util.Arrays; import java.util.Enumeration; import java.util.List; import java.util.Locale; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -51,8 +55,8 @@ class InstallationAsyncTask extends AsyncTask { private static final String TAG = "InstallationAsyncTask"; 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 int MAX_SHARED_MEMORY_SIZE = 8 << 20; // 8MiB + private static final int DEFAULT_SHARED_MEMORY_SIZE = 512 << 10; // 512KiB private static final String SHARED_MEMORY_SIZE_PROP = "dynamic_system.data_transfer.shared_memory.size"; @@ -488,7 +492,7 @@ class InstallationAsyncTask extends AsyncTask { installWritablePartition("userdata", mUserdataSize); } - private void installImages() throws IOException, ImageValidationException { + private void installImages() throws ExecutionException, IOException, ImageValidationException { if (mStream != null) { if (mIsZip) { installStreamingZipUpdate(); @@ -500,7 +504,8 @@ class InstallationAsyncTask extends AsyncTask { } } - private void installStreamingGzUpdate() throws IOException, ImageValidationException { + private void installStreamingGzUpdate() + throws ExecutionException, IOException, ImageValidationException { Log.d(TAG, "To install a streaming GZ update"); installImage("system", mSystemSize, new GZIPInputStream(mStream)); } @@ -528,7 +533,8 @@ class InstallationAsyncTask extends AsyncTask { return total; } - private void installStreamingZipUpdate() throws IOException, ImageValidationException { + private void installStreamingZipUpdate() + throws ExecutionException, IOException, ImageValidationException { Log.d(TAG, "To install a streaming ZIP update"); ZipInputStream zis = new ZipInputStream(mStream); @@ -548,7 +554,8 @@ class InstallationAsyncTask extends AsyncTask { } } - private void installLocalZipUpdate() throws IOException, ImageValidationException { + private void installLocalZipUpdate() + throws ExecutionException, IOException, ImageValidationException { Log.d(TAG, "To install a local ZIP update"); Enumeration entries = mZipFile.entries(); @@ -569,7 +576,7 @@ class InstallationAsyncTask extends AsyncTask { } private void installImageFromAnEntry(ZipEntry entry, InputStream is) - throws IOException, ImageValidationException { + throws ExecutionException, IOException, ImageValidationException { String name = entry.getName(); Log.d(TAG, "ZipEntry: " + name); @@ -581,7 +588,7 @@ class InstallationAsyncTask extends AsyncTask { } private void installImage(String partitionName, long uncompressedSize, InputStream is) - throws IOException, ImageValidationException { + throws ExecutionException, IOException, ImageValidationException { SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is)); @@ -637,27 +644,51 @@ class InstallationAsyncTask extends AsyncTask { long prevInstalledSize = 0; long installedSize = 0; byte[] bytes = new byte[memoryFile.length()]; - int numBytesRead; + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future submitPromise = null; + + while (true) { + final int numBytesRead = sis.read(bytes, 0, bytes.length); + + if (submitPromise != null) { + // Wait until the previous submit task is complete. + while (true) { + try { + if (!submitPromise.get()) { + throw new IOException("Failed submitFromAshmem() to DynamicSystem"); + } + break; + } catch (InterruptedException e) { + // Ignore. + } + } + + // Publish the progress of the previous submit task. + if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) { + publishProgress(installedSize); + prevInstalledSize = installedSize; + } + } + + // Ensure the previous submit task (submitPromise) is complete before exiting the loop. + if (numBytesRead < 0) { + break; + } - while ((numBytesRead = sis.read(bytes, 0, bytes.length)) != -1) { if (isCancelled()) { return; } memoryFile.writeBytes(bytes, 0, 0, numBytesRead); + submitPromise = + executor.submit(() -> mInstallationSession.submitFromAshmem(numBytesRead)); - if (!mInstallationSession.submitFromAshmem(numBytesRead)) { - throw new IOException("Failed write() to DynamicSystem"); - } - + // Even though we update the bytes counter here, the actual progress is updated only + // after the submit task (submitPromise) is complete. installedSize += numBytesRead; - - if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) { - publishProgress(installedSize); - prevInstalledSize = installedSize; - } } + // Ensure a 100% mark is published. if (prevInstalledSize != partitionSize) { publishProgress(partitionSize); }