Loading updater_sample/AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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> updater_sample/README.md +3 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 ``` Loading updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java +30 −49 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading Loading @@ -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; } /** Loading Loading @@ -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()); }); } Loading @@ -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; } Loading Loading @@ -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}. Loading updater_sample/src/com/example/android/systemupdatersample/services/PrepareStreamingService.java→updater_sample/src/com/example/android/systemupdatersample/services/PrepareUpdateService.java +31 −24 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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. Loading @@ -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 Loading @@ -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. Loading @@ -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) { Loading @@ -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 = Loading Loading @@ -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) Loading Loading @@ -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 { Loading updater_sample/src/com/example/android/systemupdatersample/ui/MainActivity.java +2 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 Loading
updater_sample/AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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>
updater_sample/README.md +3 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 ``` Loading
updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java +30 −49 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading Loading @@ -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; } /** Loading Loading @@ -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()); }); } Loading @@ -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; } Loading Loading @@ -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}. Loading
updater_sample/src/com/example/android/systemupdatersample/services/PrepareStreamingService.java→updater_sample/src/com/example/android/systemupdatersample/services/PrepareUpdateService.java +31 −24 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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. Loading @@ -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 Loading @@ -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. Loading @@ -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) { Loading @@ -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 = Loading Loading @@ -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) Loading Loading @@ -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 { Loading
updater_sample/src/com/example/android/systemupdatersample/ui/MainActivity.java +2 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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