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

Commit 63470d1b authored by Yi-yo Chiang's avatar Yi-yo Chiang Committed by Automerger Merge Worker
Browse files

Merge "DSU installation service: Add event log tags" am: 172f4ac3 am: 5cc5036f

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2028284

Change-Id: Ib89281420bb29cc06d2bcda0e322ef7e74ee58be
parents 4d46a146 5cc5036f
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -22,6 +22,9 @@ android_app {
    defaults: ["platform_app_defaults"],

    srcs: ["src/**/*.java"],
    static_libs: [
        "DynamicSystemInstallationService-logtags",
    ],
    resource_dirs: ["res"],

    certificate: "platform",
@@ -32,3 +35,8 @@ android_app {
        enabled: false,
    },
}

java_library {
    name: "DynamicSystemInstallationService-logtags",
    srcs: ["src/**/*.logtags"],
}
+71 −25
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import android.os.RemoteException;
import android.os.image.DynamicSystemClient;
import android.os.image.DynamicSystemManager;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
import android.widget.Toast;

@@ -103,6 +104,36 @@ public class DynamicSystemInstallationService extends Service
    private static final String NOTIFICATION_CHANNEL_ID = "com.android.dynsystem";
    private static final int NOTIFICATION_ID = 1;

    /*
     * Event log tags
     */
    private static final int EVENT_DSU_PROGRESS_UPDATE = 120000;
    private static final int EVENT_DSU_INSTALL_COMPLETE = 120001;
    private static final int EVENT_DSU_INSTALL_FAILED = 120002;

    protected static void logEventProgressUpdate(
            String partition,
            long installedSize,
            long partitionSize,
            int partitionNumber,
            int totalPartitionNumber) {
        EventLog.writeEvent(
                EVENT_DSU_PROGRESS_UPDATE,
                partition,
                installedSize,
                partitionSize,
                partitionNumber,
                totalPartitionNumber);
    }

    protected static void logEventComplete() {
        EventLog.writeEvent(EVENT_DSU_INSTALL_COMPLETE);
    }

    protected static void logEventFailed(String cause) {
        EventLog.writeEvent(EVENT_DSU_INSTALL_FAILED, cause);
    }

    /*
     * IPC
     */
@@ -132,15 +163,10 @@ public class DynamicSystemInstallationService extends Service
    private DynamicSystemManager mDynSystem;
    private NotificationManager mNM;

    private int mNumInstalledPartitions;

    private String mCurrentPartitionName;
    private long mCurrentPartitionSize;
    private long mCurrentPartitionInstalledSize;

    // This is for testing only now
    private boolean mEnableWhenCompleted;

    private InstallationAsyncTask.Progress mInstallTaskProgress;
    private InstallationAsyncTask mInstallTask;


@@ -203,17 +229,21 @@ public class DynamicSystemInstallationService extends Service

    @Override
    public void onProgressUpdate(InstallationAsyncTask.Progress progress) {
        mCurrentPartitionName = progress.partitionName;
        mCurrentPartitionSize = progress.partitionSize;
        mCurrentPartitionInstalledSize = progress.installedSize;
        mNumInstalledPartitions = progress.numInstalledPartitions;

        logEventProgressUpdate(
                progress.partitionName,
                progress.installedSize,
                progress.partitionSize,
                progress.partitionNumber,
                progress.totalPartitionNumber);

        mInstallTaskProgress = progress;
        postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null);
    }

    @Override
    public void onResult(int result, Throwable detail) {
        if (result == RESULT_OK) {
            logEventComplete();
            postStatus(STATUS_READY, CAUSE_INSTALL_COMPLETED, null);

            // For testing: enable DSU and restart the device when install completed
@@ -223,6 +253,12 @@ public class DynamicSystemInstallationService extends Service
            return;
        }

        if (result == RESULT_CANCELLED) {
            logEventFailed("Dynamic System installation task is canceled by the user.");
        } else {
            logEventFailed("error: " + detail);
        }

        boolean removeNotification = false;
        switch (result) {
            case RESULT_CANCELLED:
@@ -251,16 +287,20 @@ public class DynamicSystemInstallationService extends Service
    private void executeInstallCommand(Intent intent) {
        if (!verifyRequest(intent)) {
            Log.e(TAG, "Verification failed. Did you use VerificationActivity?");
            logEventFailed("VerificationActivity");
            return;
        }

        if (mInstallTask != null) {
            Log.e(TAG, "There is already an installation task running");
            logEventFailed("There is already an ongoing installation task.");
            return;
        }

        if (isInDynamicSystem()) {
            Log.e(TAG, "We are already running in DynamicSystem");
            logEventFailed(
                    "Cannot start a Dynamic System installation task within a Dynamic System.");
            return;
        }

@@ -445,19 +485,22 @@ public class DynamicSystemInstallationService extends Service
            case STATUS_IN_PROGRESS:
                builder.setContentText(getString(R.string.notification_install_inprogress));

                if (mInstallTaskProgress != null) {
                    int max = 1024;
                    int progress = 0;

                int currentMax = max >> (mNumInstalledPartitions + 1);
                    int currentMax = max >> mInstallTaskProgress.partitionNumber;
                    progress = max - currentMax * 2;

                long currentProgress = (mCurrentPartitionInstalledSize >> 20) * currentMax
                        / Math.max(mCurrentPartitionSize >> 20, 1);
                    long currentProgress =
                            (mInstallTaskProgress.installedSize >> 20)
                                    * currentMax
                                    / Math.max(mInstallTaskProgress.partitionSize >> 20, 1);

                    progress += (int) currentProgress;

                    builder.setProgress(max, progress, false);

                }
                builder.addAction(new Notification.Action.Builder(
                        null, getString(R.string.notification_action_cancel),
                        createPendingIntent(ACTION_CANCEL_INSTALL)).build());
@@ -563,13 +606,13 @@ public class DynamicSystemInstallationService extends Service

        StringBuilder msg = new StringBuilder();
        msg.append("status: " + statusString + ", cause: " + causeString);
        if (status == STATUS_IN_PROGRESS) {
        if (status == STATUS_IN_PROGRESS && mInstallTaskProgress != null) {
            msg.append(
                    String.format(
                            ", partition name: %s, progress: %d/%d",
                            mCurrentPartitionName,
                            mCurrentPartitionInstalledSize,
                            mCurrentPartitionSize));
                            mInstallTaskProgress.partitionName,
                            mInstallTaskProgress.installedSize,
                            mInstallTaskProgress.partitionSize));
        }
        if (detail != null) {
            msg.append(", detail: " + detail);
@@ -594,7 +637,10 @@ public class DynamicSystemInstallationService extends Service
        Bundle bundle = new Bundle();

        // TODO: send more info to the clients
        bundle.putLong(DynamicSystemClient.KEY_INSTALLED_SIZE, mCurrentPartitionInstalledSize);
        if (mInstallTaskProgress != null) {
            bundle.putLong(
                    DynamicSystemClient.KEY_INSTALLED_SIZE, mInstallTaskProgress.installedSize);
        }

        if (detail != null) {
            bundle.putSerializable(DynamicSystemClient.KEY_EXCEPTION_DETAIL,
+7 −0
Original line number Diff line number Diff line
# See system/logging/logcat/event.logtags for a description of the format of this file.

option java_package com.android.dynsystem

120000 dsu_progress_update (partition|3),(installed_size|2|5),(partition_size|2|5),(partition_number|1|5),(total_partition_number|1|5)
120001 dsu_install_complete
120002 dsu_install_failed (cause|3)
+90 −37
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

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

    private static final String TAG = "InstallationAsyncTask";

@@ -106,14 +106,22 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog

    static class Progress {
        public final String partitionName;
        public final long installedSize;
        public final long partitionSize;
        public final int numInstalledPartitions;
        public long installedSize;

        Progress(String partitionName, long partitionSize, int numInstalledPartitions) {
        public final int partitionNumber;
        public final int totalPartitionNumber;

        Progress(
                String partitionName,
                long installedSize,
                long partitionSize,
                int partitionNumber,
                int totalPartitionNumber) {
            this.partitionName = partitionName;
            this.installedSize = installedSize;
            this.partitionSize = partitionSize;
            this.numInstalledPartitions = numInstalledPartitions;
            this.partitionNumber = partitionNumber;
            this.totalPartitionNumber = totalPartitionNumber;
        }
    }

@@ -139,7 +147,10 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
    private boolean mIsZip;
    private boolean mIsCompleted;

    private int mNumInstalledPartitions;
    private String mPartitionName;
    private long mPartitionSize;
    private int mPartitionNumber;
    private int mTotalPartitionNumber;

    private InputStream mStream;
    private ZipFile mZipFile;
@@ -175,11 +186,15 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
    protected Throwable doInBackground(String... voids) {
        Log.d(TAG, "Start doInBackground(), URL: " + mUrl);

        final boolean wantScratchPartition = Build.IS_DEBUGGABLE;
        try {
            // call DynamicSystemManager to cleanup stuff
            mDynSystem.remove();

            verifyAndPrepare();
            if (wantScratchPartition) {
                ++mTotalPartitionNumber;
            }

            mDynSystem.startInstallation(mDsuSlot);

@@ -198,7 +213,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
                return null;
            }

            if (Build.IS_DEBUGGABLE) {
            if (wantScratchPartition) {
                // If host is debuggable, then install a scratch partition so that we can do
                // adb remount in the guest system.
                try {
@@ -262,9 +277,14 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
    }

    @Override
    protected void onProgressUpdate(Progress... values) {
        Progress progress = values[0];
        mListener.onProgressUpdate(progress);
    protected void onProgressUpdate(Long... installedSize) {
        mListener.onProgressUpdate(
                new Progress(
                        mPartitionName,
                        installedSize[0],
                        mPartitionSize,
                        mPartitionNumber,
                        mTotalPartitionNumber));
    }

    private void verifyAndPrepare() throws Exception {
@@ -281,12 +301,16 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
            throw new UnsupportedFormatException(
                String.format(Locale.US, "Unsupported file format: %s", mUrl));
        }
        // At least two partitions, {system, userdata}
        mTotalPartitionNumber = 2;

        if (mIsNetworkUrl) {
            mStream = new URL(mUrl).openStream();
        } else if (URLUtil.isFileUrl(mUrl)) {
            if (mIsZip) {
                mZipFile = new ZipFile(new File(new URL(mUrl).toURI()));
                // {*.img in zip} + {userdata}
                mTotalPartitionNumber = calculateNumberOfImagesInLocalZip(mZipFile) + 1;
            } else {
                mStream = new URL(mUrl).openStream();
            }
@@ -333,9 +357,13 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
            }
        };

        thread.start();
        Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++);
        mPartitionName = partitionName;
        mPartitionSize = partitionSize;
        ++mPartitionNumber;
        publishProgress(/* installedSize = */ 0L);

        long prevInstalledSize = 0;
        thread.start();
        while (thread.isAlive()) {
            if (isCancelled()) {
                return;
@@ -343,9 +371,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog

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

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

            try {
@@ -392,14 +420,42 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
        installImage("system", mSystemSize, new GZIPInputStream(mStream));
    }

    private boolean shouldInstallEntry(String name) {
        if (!name.endsWith(".img")) {
            return false;
        }
        String partitionName = name.substring(0, name.length() - 4);
        if (UNSUPPORTED_PARTITIONS.contains(partitionName)) {
            return false;
        }
        return true;
    }

    private int calculateNumberOfImagesInLocalZip(ZipFile zipFile) {
        int total = 0;
        Enumeration<? extends ZipEntry> entries = zipFile.entries();
        while (entries.hasMoreElements()) {
            ZipEntry entry = entries.nextElement();
            if (shouldInstallEntry(entry.getName())) {
                ++total;
            }
        }
        return total;
    }

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

        ZipInputStream zis = new ZipInputStream(mStream);
        ZipEntry zipEntry = null;
        ZipEntry entry = null;

        while ((zipEntry = zis.getNextEntry()) != null) {
            installImageFromAnEntry(zipEntry, zis);
        while ((entry = zis.getNextEntry()) != null) {
            String name = entry.getName();
            if (shouldInstallEntry(name)) {
                installImageFromAnEntry(entry, zis);
            } else {
                Log.d(TAG, name + " installation is not supported, skip it.");
            }

            if (isCancelled()) {
                break;
@@ -414,7 +470,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog

        while (entries.hasMoreElements()) {
            ZipEntry entry = entries.nextElement();
            String name = entry.getName();
            if (shouldInstallEntry(name)) {
                installImageFromAnEntry(entry, mZipFile.getInputStream(entry));
            } else {
                Log.d(TAG, name + " installation is not supported, skip it.");
            }

            if (isCancelled()) {
                break;
@@ -422,28 +483,16 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
        }
    }

    private boolean installImageFromAnEntry(ZipEntry entry, InputStream is)
    private void installImageFromAnEntry(ZipEntry entry, InputStream is)
            throws IOException, ImageValidationException {
        String name = entry.getName();

        Log.d(TAG, "ZipEntry: " + name);

        if (!name.endsWith(".img")) {
            return false;
        }

        String partitionName = name.substring(0, name.length() - 4);

        if (UNSUPPORTED_PARTITIONS.contains(partitionName)) {
            Log.d(TAG, name + " installation is not supported, skip it.");
            return false;
        }

        long uncompressedSize = entry.getSize();

        installImage(partitionName, uncompressedSize, is);

        return true;
    }

    private void installImage(String partitionName, long uncompressedSize, InputStream is)
@@ -497,8 +546,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog

        mInstallationSession.setAshmem(pfd, READ_BUFFER_SIZE);

        Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++);
        mPartitionName = partitionName;
        mPartitionSize = partitionSize;
        ++mPartitionNumber;
        publishProgress(/* installedSize = */ 0L);

        long prevInstalledSize = 0;
        long installedSize = 0;
        byte[] bytes = new byte[READ_BUFFER_SIZE];
        int numBytesRead;
@@ -516,9 +569,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog

            installedSize += numBytesRead;

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