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

Commit 309fad06 authored by Yi-yo Chiang's avatar Yi-yo Chiang Committed by Gerrit Code Review
Browse files

Merge "DSU service: Pipeline the installation task to improve performance"

parents 301fddda 8d629110
Loading
Loading
Loading
Loading
+50 −19
Original line number Diff line number Diff line
@@ -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<String, Long, Throwable> {
    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<String, Long, Throwable> {
        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<String, Long, Throwable> {
        }
    }

    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<String, Long, Throwable> {
        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<String, Long, Throwable> {
        }
    }

    private void installLocalZipUpdate() throws IOException, ImageValidationException {
    private void installLocalZipUpdate()
            throws ExecutionException, IOException, ImageValidationException {
        Log.d(TAG, "To install a local ZIP update");

        Enumeration<? extends ZipEntry> entries = mZipFile.entries();
@@ -569,7 +576,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
    }

    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<String, Long, Throwable> {
    }

    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<String, Long, Throwable> {
        long prevInstalledSize = 0;
        long installedSize = 0;
        byte[] bytes = new byte[memoryFile.length()];
        int numBytesRead;
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Boolean> submitPromise = null;

        while ((numBytesRead = sis.read(bytes, 0, bytes.length)) != -1) {
            if (isCancelled()) {
                return;
            }
        while (true) {
            final int numBytesRead = sis.read(bytes, 0, bytes.length);

            memoryFile.writeBytes(bytes, 0, 0, numBytesRead);

            if (!mInstallationSession.submitFromAshmem(numBytesRead)) {
                throw new IOException("Failed write() to DynamicSystem");
            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.
                    }
                }

            installedSize += numBytesRead;

                // 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;
            }

            if (isCancelled()) {
                return;
            }

            memoryFile.writeBytes(bytes, 0, 0, numBytesRead);
            submitPromise =
                    executor.submit(() -> mInstallationSession.submitFromAshmem(numBytesRead));

            // Even though we update the bytes counter here, the actual progress is updated only
            // after the submit task (submitPromise) is complete.
            installedSize += numBytesRead;
        }

        // Ensure a 100% mark is published.
        if (prevInstalledSize != partitionSize) {
            publishProgress(partitionSize);
        }