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

Commit bc077753 authored by Zhomart Mukhamejanov's avatar Zhomart Mukhamejanov
Browse files

Add PrepareUpdateService.

It's moved from PrepareStreamingService intent service.
Now PrepareUpdateService takes an UpdateConfig and
builds PayloadSpec for UpdateEngine for both streaming
and non-streaming update.

It allows us to do all preparations in intent service's
thread, without blocking UI.

We will also add checksum verification to
PrepareUpdateService.

Test: device, junit
Bug: 77150191
Change-Id: I15c0bc58e3238bea6ea1c4f13063575e2def89c1
Merged-In: Iea69acd9aa41e17538c26aff60f7598093ca7744
parent c456aab7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".services.PrepareStreamingService"/>
        <service android:name=".services.PrepareUpdateService"/>
    </application>

</manifest>
+3 −3
Original line number Diff line number Diff line
@@ -220,7 +220,7 @@ privileged system app, so it's granted the required permissions to access
- [x] Add Sample app update state (separate from update_engine status)
- [x] Add smart update completion detection using onStatusUpdate
- [x] Add pause/resume demo
- [x] Verify system partition checksum for package
- [-] Verify system partition checksum for package


## Running tests
@@ -235,8 +235,8 @@ privileged system app, so it's granted the required permissions to access
5. Run a test file
   ```
   adb shell am instrument \
     -w com.example.android.systemupdatersample.tests/android.support.test.runner.AndroidJUnitRunner \
     -c com.example.android.systemupdatersample.util.PayloadSpecsTest
     -w -e class com.example.android.systemupdatersample.UpdateManagerTest#applyUpdate_appliesPayloadToUpdateEngine \
     com.example.android.systemupdatersample.tests/android.support.test.runner.AndroidJUnitRunner
   ```


+30 −49
Original line number Diff line number Diff line
@@ -17,19 +17,18 @@
package com.example.android.systemupdatersample;

import android.content.Context;
import android.os.Handler;
import android.os.UpdateEngine;
import android.os.UpdateEngineCallback;
import android.util.Log;

import com.example.android.systemupdatersample.services.PrepareStreamingService;
import com.example.android.systemupdatersample.util.PayloadSpecs;
import com.example.android.systemupdatersample.services.PrepareUpdateService;
import com.example.android.systemupdatersample.util.UpdateEngineErrorCodes;
import com.example.android.systemupdatersample.util.UpdateEngineProperties;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.AtomicDouble;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -50,11 +49,10 @@ public class UpdateManager {
    private static final String TAG = "UpdateManager";

    /** HTTP Header: User-Agent; it will be sent to the server when streaming the payload. */
    private static final String HTTP_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    static final String HTTP_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            + "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";

    private final UpdateEngine mUpdateEngine;
    private final PayloadSpecs mPayloadSpecs;

    private AtomicInteger mUpdateEngineStatus =
            new AtomicInteger(UpdateEngine.UpdateStatusConstants.IDLE);
@@ -84,9 +82,15 @@ public class UpdateManager {
    private final UpdateManager.UpdateEngineCallbackImpl
            mUpdateEngineCallback = new UpdateManager.UpdateEngineCallbackImpl();

    public UpdateManager(UpdateEngine updateEngine, PayloadSpecs payloadSpecs) {
    private final Handler mHandler;

    /**
     * @param updateEngine UpdateEngine instance.
     * @param handler      Handler for {@link PrepareUpdateService} intent service.
     */
    public UpdateManager(UpdateEngine updateEngine, Handler handler) {
        this.mUpdateEngine = updateEngine;
        this.mPayloadSpecs = payloadSpecs;
        this.mHandler = handler;
    }

    /**
@@ -293,45 +297,17 @@ public class UpdateManager {
            mManualSwitchSlotRequired.set(false);
        }

        if (config.getInstallType() == UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING) {
            applyAbNonStreamingUpdate(config);
        } else {
            applyAbStreamingUpdate(context, config);
        }
    }

    private void applyAbNonStreamingUpdate(UpdateConfig config)
            throws UpdaterState.InvalidTransitionException {
        UpdateData.Builder builder = UpdateData.builder()
                .setExtraProperties(prepareExtraProperties(config));

        try {
            builder.setPayload(mPayloadSpecs.forNonStreaming(config.getUpdatePackageFile()));
        } catch (IOException e) {
            Log.e(TAG, "Error creating payload spec", e);
            setUpdaterState(UpdaterState.ERROR);
            return;
        }
        updateEngineApplyPayload(builder.build());
    }

    private void applyAbStreamingUpdate(Context context, UpdateConfig config) {
        UpdateData.Builder builder = UpdateData.builder()
                .setExtraProperties(prepareExtraProperties(config));

        Log.d(TAG, "Starting PrepareStreamingService");
        PrepareStreamingService.startService(context, config, (code, payloadSpec) -> {
            if (code == PrepareStreamingService.RESULT_CODE_SUCCESS) {
                builder.setPayload(payloadSpec);
                builder.addExtraProperty("USER_AGENT=" + HTTP_USER_AGENT);
                config.getAbConfig()
                        .getAuthorization()
                        .ifPresent(s -> builder.addExtraProperty("AUTHORIZATION=" + s));
                updateEngineApplyPayload(builder.build());
            } else {
                Log.e(TAG, "PrepareStreamingService failed, result code is " + code);
        Log.d(TAG, "Starting PrepareUpdateService");
        PrepareUpdateService.startService(context, config, mHandler, (code, payloadSpec) -> {
            if (code != PrepareUpdateService.RESULT_CODE_SUCCESS) {
                Log.e(TAG, "PrepareUpdateService failed, result code is " + code);
                setUpdaterStateSilent(UpdaterState.ERROR);
                return;
            }
            updateEngineApplyPayload(UpdateData.builder()
                    .setExtraProperties(prepareExtraProperties(config))
                    .setPayload(payloadSpec)
                    .build());
        });
    }

@@ -343,6 +319,12 @@ public class UpdateManager {
            // User will enable it manually by clicking "Switch Slot" button on the screen.
            extraProperties.add(UpdateEngineProperties.PROPERTY_DISABLE_SWITCH_SLOT_ON_REBOOT);
        }
        if (config.getInstallType() == UpdateConfig.AB_INSTALL_TYPE_STREAMING) {
            extraProperties.add("USER_AGENT=" + HTTP_USER_AGENT);
            config.getAbConfig()
                    .getAuthorization()
                    .ifPresent(s -> extraProperties.add("AUTHORIZATION=" + s));
        }
        return extraProperties;
    }

@@ -555,7 +537,6 @@ public class UpdateManager {
    }

    /**
     *
     * Contains update data - PayloadSpec and extra properties list.
     *
     * <p>{@code mPayload} contains url, offset and size to {@code PAYLOAD_BINARY_FILE_NAME}.
+31 −24
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.RecoverySystem;
import android.os.ResultReceiver;
import android.os.UpdateEngine;
import android.util.Log;

import com.example.android.systemupdatersample.PayloadSpec;
@@ -49,10 +50,10 @@ import java.util.Optional;
 * without downloading the whole package. And it constructs {@link PayloadSpec}.
 * All this work required to install streaming A/B updates.
 *
 * PrepareStreamingService runs on it's own thread. It will notify activity
 * PrepareUpdateService runs on it's own thread. It will notify activity
 * using interface {@link UpdateResultCallback} when update is ready to install.
 */
public class PrepareStreamingService extends IntentService {
public class PrepareUpdateService extends IntentService {

    /**
     * UpdateResultCallback result codes.
@@ -61,22 +62,27 @@ public class PrepareStreamingService extends IntentService {
    public static final int RESULT_CODE_ERROR = 1;

    /**
     * This interface is used to send results from {@link PrepareStreamingService} to
     * Extra params that will be sent to IntentService.
     */
    public static final String EXTRA_PARAM_CONFIG = "config";
    public static final String EXTRA_PARAM_RESULT_RECEIVER = "result-receiver";

    /**
     * This interface is used to send results from {@link PrepareUpdateService} to
     * {@code MainActivity}.
     */
    public interface UpdateResultCallback {

        /**
         * Invoked when files are downloaded and payload spec is constructed.
         *
         * @param resultCode result code, values are defined in {@link PrepareStreamingService}
         * @param resultCode  result code, values are defined in {@link PrepareUpdateService}
         * @param payloadSpec prepared payload spec for streaming update
         */
        void onReceiveResult(int resultCode, PayloadSpec payloadSpec);
    }

    /**
     * Starts PrepareStreamingService.
     * Starts PrepareUpdateService.
     *
     * @param context        application context
     * @param config         update config
@@ -84,26 +90,21 @@ public class PrepareStreamingService extends IntentService {
     */
    public static void startService(Context context,
            UpdateConfig config,
            Handler handler,
            UpdateResultCallback resultCallback) {
        Log.d(TAG, "Starting PrepareStreamingService");
        ResultReceiver receiver = new CallbackResultReceiver(new Handler(), resultCallback);
        Intent intent = new Intent(context, PrepareStreamingService.class);
        Log.d(TAG, "Starting PrepareUpdateService");
        ResultReceiver receiver = new CallbackResultReceiver(handler, resultCallback);
        Intent intent = new Intent(context, PrepareUpdateService.class);
        intent.putExtra(EXTRA_PARAM_CONFIG, config);
        intent.putExtra(EXTRA_PARAM_RESULT_RECEIVER, receiver);
        context.startService(intent);
    }

    public PrepareStreamingService() {
    public PrepareUpdateService() {
        super(TAG);
    }

    private static final String TAG = "PrepareStreamingService";

    /**
     * Extra params that will be sent from Activity to IntentService.
     */
    private static final String EXTRA_PARAM_CONFIG = "config";
    private static final String EXTRA_PARAM_RESULT_RECEIVER = "result-receiver";
    private static final String TAG = "PrepareUpdateService";

    /**
     * The files that should be downloaded before streaming.
@@ -117,6 +118,7 @@ public class PrepareStreamingService extends IntentService {
            );

    private final PayloadSpecs mPayloadSpecs = new PayloadSpecs();
    private final UpdateEngine mUpdateEngine = new UpdateEngine();

    @Override
    protected void onHandleIntent(Intent intent) {
@@ -142,6 +144,10 @@ public class PrepareStreamingService extends IntentService {
    private PayloadSpec execute(UpdateConfig config)
            throws IOException, PreparationFailedException {

        if (config.getInstallType() == UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING) {
            return mPayloadSpecs.forNonStreaming(config.getUpdatePackageFile());
        }

        downloadPreStreamingFiles(config, OTA_PACKAGE_DIR);

        Optional<UpdateConfig.PackageFile> payloadBinary =
@@ -176,6 +182,7 @@ public class PrepareStreamingService extends IntentService {
     * Downloads files defined in {@link UpdateConfig#getAbConfig()}
     * and exists in {@code PRE_STREAMING_FILES_SET}, and put them
     * in directory {@code dir}.
     *
     * @throws IOException when can't download a file
     */
    private void downloadPreStreamingFiles(UpdateConfig config, String dir)
@@ -212,7 +219,7 @@ public class PrepareStreamingService extends IntentService {
    }

    /**
     * Used by {@link PrepareStreamingService} to pass {@link PayloadSpec}
     * Used by {@link PrepareUpdateService} to pass {@link PayloadSpec}
     * to {@link UpdateResultCallback#onReceiveResult}.
     */
    private static class CallbackResultReceiver extends ResultReceiver {
+2 −2
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.AlertDialog;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.UpdateEngine;
import android.util.Log;
import android.view.View;
@@ -34,7 +35,6 @@ import com.example.android.systemupdatersample.R;
import com.example.android.systemupdatersample.UpdateConfig;
import com.example.android.systemupdatersample.UpdateManager;
import com.example.android.systemupdatersample.UpdaterState;
import com.example.android.systemupdatersample.util.PayloadSpecs;
import com.example.android.systemupdatersample.util.UpdateConfigs;
import com.example.android.systemupdatersample.util.UpdateEngineErrorCodes;
import com.example.android.systemupdatersample.util.UpdateEngineStatuses;
@@ -67,7 +67,7 @@ public class MainActivity extends Activity {
    private List<UpdateConfig> mConfigs;

    private final UpdateManager mUpdateManager =
            new UpdateManager(new UpdateEngine(), new PayloadSpecs());
            new UpdateManager(new UpdateEngine(), new Handler());

    @Override
    protected void onCreate(Bundle savedInstanceState) {
Loading