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

Commit 848bcdc4 authored by Yo Chiang's avatar Yo Chiang
Browse files

DynamicSystemInstallationService: Support remount for DSU guest system

DSU service would try to install a DSU scratch partition if host system
is debuggable.
If the scratch partition failed to install, then skip installing
scratch, as remount support should be optional.
Otherwise if the guest system is non-debuggable, then the scratch
partition would be ignored by guest, which is harmless.
Otherwise the guest system is debuggable, which means the guest system
would be able to do adb remount.

Relax partition allocation status polling rate from 10ms -> 100ms,
because there's no point polling faster than the screen framerate.

Bug: 165925766
Test: TH
Test: Install a DSU system on a debuggable host, reboot into the guest
  system, and guest system can remount.
Change-Id: I9a8255483cc963ebcf7a2909e68ac69371cb369f
parent d15cbc37
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -269,4 +269,16 @@ public class DynamicSystemManager {
            throw new RuntimeException(e.toString());
            throw new RuntimeException(e.toString());
        }
        }
    }
    }

    /**
     * Returns the suggested scratch partition size for overlayFS.
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
    public long suggestScratchSize() {
        try {
            return mService.suggestScratchSize();
        } catch (RemoteException e) {
            throw new RuntimeException(e.toString());
        }
    }
}
}
+5 −0
Original line number Original line Diff line number Diff line
@@ -125,4 +125,9 @@ interface IDynamicSystemService
     *                      valid VBMeta block to retrieve the AVB key from.
     *                      valid VBMeta block to retrieve the AVB key from.
     */
     */
    boolean getAvbPublicKey(out AvbPublicKey dst);
    boolean getAvbPublicKey(out AvbPublicKey dst);

    /**
     * Returns the suggested scratch partition size for overlayFS.
     */
    long suggestScratchSize();
}
}
+64 −5
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Context;
import android.gsi.AvbPublicKey;
import android.gsi.AvbPublicKey;
import android.net.Uri;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.AsyncTask;
import android.os.Build;
import android.os.MemoryFile;
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor;
import android.os.image.DynamicSystemManager;
import android.os.image.DynamicSystemManager;
@@ -51,7 +52,8 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
    private static final long MIN_PROGRESS_TO_PUBLISH = 1 << 27;
    private static final long MIN_PROGRESS_TO_PUBLISH = 1 << 27;


    private static final List<String> UNSUPPORTED_PARTITIONS =
    private static final List<String> UNSUPPORTED_PARTITIONS =
            Arrays.asList("vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other");
            Arrays.asList(
                    "vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other", "scratch");


    private class UnsupportedUrlException extends Exception {
    private class UnsupportedUrlException extends Exception {
        private UnsupportedUrlException(String message) {
        private UnsupportedUrlException(String message) {
@@ -196,6 +198,22 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
                return null;
                return null;
            }
            }


            if (Build.IS_DEBUGGABLE) {
                // If host is debuggable, then install a scratch partition so that we can do
                // adb remount in the guest system.
                try {
                    installScratch();
                } catch (IOException e) {
                    // Failing to install overlayFS scratch shouldn't be fatal.
                    // Just ignore the error and skip installing the scratch partition.
                    Log.w(TAG, e.toString(), e);
                }
                if (isCancelled()) {
                    mDynSystem.remove();
                    return null;
                }
            }

            mDynSystem.finishInstallation();
            mDynSystem.finishInstallation();
        } catch (Exception e) {
        } catch (Exception e) {
            Log.e(TAG, e.toString(), e);
            Log.e(TAG, e.toString(), e);
@@ -302,12 +320,53 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
        }
        }
    }
    }


    private void installUserdata() throws Exception {
    private void installScratch() throws IOException, InterruptedException {
        final long scratchSize = mDynSystem.suggestScratchSize();
        Thread thread = new Thread() {
            @Override
            public void run() {
                mInstallationSession =
                        mDynSystem.createPartition("scratch", scratchSize, /* readOnly= */ false);
            }
        };

        Log.d(TAG, "Creating partition: scratch, size = " + scratchSize);
        thread.start();

        Progress progress = new Progress("scratch", scratchSize, mNumInstalledPartitions++);

        while (thread.isAlive()) {
            if (isCancelled()) {
                return;
            }

            final long installedSize = mDynSystem.getInstallationProgress().bytes_processed;

            if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
                progress.installedSize = installedSize;
                publishProgress(progress);
            }

            Thread.sleep(100);
        }

        if (mInstallationSession == null) {
            throw new IOException(
                    "Failed to start installation with requested size: " + scratchSize);
        }
        // Reset installation session and verify that installation completes successfully.
        mInstallationSession = null;
        if (!mDynSystem.closePartition()) {
            throw new IOException("Failed to complete partition installation: scratch");
        }
    }

    private void installUserdata() throws IOException, InterruptedException {
        Thread thread = new Thread(() -> {
        Thread thread = new Thread(() -> {
            mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false);
            mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false);
        });
        });


        Log.d(TAG, "Creating partition: userdata");
        Log.d(TAG, "Creating partition: userdata, size = " + mUserdataSize);
        thread.start();
        thread.start();


        Progress progress = new Progress("userdata", mUserdataSize, mNumInstalledPartitions++);
        Progress progress = new Progress("userdata", mUserdataSize, mNumInstalledPartitions++);
@@ -324,7 +383,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
                publishProgress(progress);
                publishProgress(progress);
            }
            }


            Thread.sleep(10);
            Thread.sleep(100);
        }
        }


        if (mInstallationSession == null) {
        if (mInstallationSession == null) {
@@ -445,7 +504,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
                return;
                return;
            }
            }


            Thread.sleep(10);
            Thread.sleep(100);
        }
        }


        if (mInstallationSession == null) {
        if (mInstallationSession == null) {
+5 −0
Original line number Original line Diff line number Diff line
@@ -236,4 +236,9 @@ public class DynamicSystemService extends IDynamicSystemService.Stub {
            throw new RuntimeException(e.toString());
            throw new RuntimeException(e.toString());
        }
        }
    }
    }

    @Override
    public long suggestScratchSize() throws RemoteException {
        return getGsiService().suggestScratchSize();
    }
}
}