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

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

Use Ashmem to reduce buffer copies

Use android.os.MemoryFile to allocate Ashmem and use gsid.setAshmem and
gsid.commitGsiChunkFromAshmem to submit data.

Bug: 138976291
Test: adb shell am start-activity \
    -n com.android.dynsystem/com.android.dynsystem.VerificationActivity \
    -a android.os.image.action.START_INSTALL \
    -d file:///storage/emulated/0/Download/system.raw.gz \
    --el KEY_SYSTEM_SIZE $(du -b system.raw|cut -f1) \
    --el KEY_USERDATA_SIZE 8589934592

Change-Id: I6df718a8cc3f4e5835c9d20d0bf5bf8bb0daee22
Merged-In: I6df718a8cc3f4e5835c9d20d0bf5bf8bb0daee22
parent c44ee158
Loading
Loading
Loading
Loading
+23 −5
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
import android.gsi.GsiProgress;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;

/**
@@ -52,21 +53,38 @@ public class DynamicSystemManager {
    /** The DynamicSystemManager.Session represents a started session for the installation. */
    public class Session {
        private Session() {}

        /**
         * Write a chunk of the DynamicSystem system image
         * Set the file descriptor that points to a ashmem which will be used
         * to fetch data during the submitFromAshmem.
         *
         * @return {@code true} if the call succeeds. {@code false} if there is any native runtime
         *     error.
         * @param ashmem fd that points to a ashmem
         * @param size size of the ashmem file
         */
        @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
        public boolean write(byte[] buf) {
        public boolean setAshmem(ParcelFileDescriptor ashmem, long size) {
            try {
                return mService.write(buf);
                return mService.setAshmem(ashmem, size);
            } catch (RemoteException e) {
                throw new RuntimeException(e.toString());
            }
        }

        /**
         * Submit bytes to the DSU partition from the ashmem previously set with
         * setAshmem.
         *
         * @param size Number of bytes
         * @return true on success, false otherwise.
         */
        @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
        public boolean submitFromAshmem(int size) {
            try {
                return mService.submitFromAshmem(size);
            } catch (RemoteException e) {
                throw new RuntimeException(e.toString());
            }
        }
        /**
         * Finish write and make device to boot into the it after reboot.
         *
+13 −3
Original line number Diff line number Diff line
@@ -79,10 +79,20 @@ interface IDynamicSystemService
    boolean setEnable(boolean enable, boolean oneShot);

    /**
     * Write a chunk of the DynamicSystem system image
     * Set the file descriptor that points to a ashmem which will be used
     * to fetch data during the submitFromAshmem.
     *
     * @return true if the call succeeds
     * @param fd            fd that points to a ashmem
     * @param size          size of the ashmem file
     */
    boolean write(in byte[] buf);
    boolean setAshmem(in ParcelFileDescriptor fd, long size);

    /**
     * Submit bytes to the DSU partition from the ashmem previously set with
     * setAshmem.
     *
     * @param bytes         number of bytes that can be read from stream.
     * @return              true on success, false otherwise.
     */
    boolean submitFromAshmem(long bytes);
}
+10 −13
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.content.Context;
import android.gsi.GsiProgress;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import android.os.image.DynamicSystemManager;
import android.util.Log;
import android.webkit.URLUtil;
@@ -28,11 +30,9 @@ import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.Locale;
import java.util.zip.GZIPInputStream;


class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {

    private static final String TAG = "InstallationAsyncTask";
@@ -125,28 +125,26 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
                Thread.sleep(10);
            }


            if (mInstallationSession == null) {
                throw new IOException("Failed to start installation with requested size: "
                throw new IOException(
                        "Failed to start installation with requested size: "
                                + (mSystemSize + mUserdataSize));
            }

            installedSize = mUserdataSize;

            MemoryFile memoryFile = new MemoryFile("dsu", READ_BUFFER_SIZE);
            byte[] bytes = new byte[READ_BUFFER_SIZE];

            mInstallationSession.setAshmem(
                    new ParcelFileDescriptor(memoryFile.getFileDescriptor()), READ_BUFFER_SIZE);
            int numBytesRead;

            Log.d(TAG, "Start installation loop");
            while ((numBytesRead = mStream.read(bytes, 0, READ_BUFFER_SIZE)) != -1) {
                memoryFile.writeBytes(bytes, 0, 0, numBytesRead);
                if (isCancelled()) {
                    break;
                }

                byte[] writeBuffer = numBytesRead == READ_BUFFER_SIZE
                        ? bytes : Arrays.copyOf(bytes, numBytesRead);

                if (!mInstallationSession.write(writeBuffer)) {
                if (!mInstallationSession.submitFromAshmem(numBytesRead)) {
                    throw new IOException("Failed write() to DynamicSystem");
                }

@@ -157,7 +155,6 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
                    reportedInstalledSize = installedSize;
                }
            }

            return null;

        } catch (Exception e) {
+16 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.gsi.IGsid;
import android.os.Environment;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -195,7 +196,20 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
    }

    @Override
    public boolean write(byte[] buf) throws RemoteException {
        return getGsiService().commitGsiChunkFromMemory(buf);
    public boolean setAshmem(ParcelFileDescriptor ashmem, long size) {
        try {
            return getGsiService().setGsiAshmem(ashmem, size);
        } catch (RemoteException e) {
            throw new RuntimeException(e.toString());
        }
    }

    @Override
    public boolean submitFromAshmem(long size) {
        try {
            return getGsiService().commitGsiChunkFromAshmem(size);
        } catch (RemoteException e) {
            throw new RuntimeException(e.toString());
        }
    }
}