From 674aa6c6110717fdeba3f50a7a6d00dd3eb03886 Mon Sep 17 00:00:00 2001 From: Zhomart Mukhamejanov Date: Fri, 25 May 2018 17:00:11 -0700 Subject: updater_sample: add UpdaterState - Add UpdaterState - atomic class, handles proper state changes. - Remove util.UpdaterStates. Test: compiled and ran on the device Change-Id: I7fa87bbf09f8289632e8de1f26654365f4891700 Signed-off-by: Zhomart Mukhamejanov --- .../android/systemupdatersample/UpdateManager.java | 33 ++++--- .../android/systemupdatersample/UpdaterState.java | 103 +++++++++++++++++++++ .../systemupdatersample/ui/MainActivity.java | 10 +- .../systemupdatersample/util/UpdaterStates.java | 50 ---------- 4 files changed, 128 insertions(+), 68 deletions(-) create mode 100644 updater_sample/src/com/example/android/systemupdatersample/UpdaterState.java delete mode 100644 updater_sample/src/com/example/android/systemupdatersample/util/UpdaterStates.java diff --git a/updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java b/updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java index bf673c2eb..c4c8c9c27 100644 --- a/updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java +++ b/updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java @@ -25,7 +25,6 @@ import com.example.android.systemupdatersample.services.PrepareStreamingService; import com.example.android.systemupdatersample.util.PayloadSpecs; import com.example.android.systemupdatersample.util.UpdateEngineErrorCodes; import com.example.android.systemupdatersample.util.UpdateEngineProperties; -import com.example.android.systemupdatersample.util.UpdaterStates; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.AtomicDouble; @@ -59,7 +58,7 @@ public class UpdateManager { new AtomicInteger(UpdateEngine.UpdateStatusConstants.IDLE); private AtomicInteger mEngineErrorCode = new AtomicInteger(UpdateEngineErrorCodes.UNKNOWN); private AtomicDouble mProgress = new AtomicDouble(0); - private AtomicInteger mState = new AtomicInteger(UpdaterStates.IDLE); + private UpdaterState mUpdaterState = new UpdaterState(UpdaterState.IDLE); private AtomicBoolean mManualSwitchSlotRequired = new AtomicBoolean(true); @@ -111,7 +110,7 @@ public class UpdateManager { /** * Sets SystemUpdaterSample app state change callback. Value of {@code state} will be one - * of the values from {@link UpdaterStates}. + * of the values from {@link UpdaterState}. * * @param onStateChangeCallback a callback with parameter {@code state}. */ @@ -193,8 +192,14 @@ public class UpdateManager { * it also notifies {@link this.mOnStateChangeCallback}. */ private void setUpdaterState(int updaterState) { - int previousState = mState.get(); - mState.set(updaterState); + int previousState = mUpdaterState.get(); + try { + mUpdaterState.set(updaterState); + } catch (UpdaterState.InvalidTransitionException e) { + // Note: invalid state transitions should be handled properly, + // but to make sample app simple, we just throw runtime exception. + throw new RuntimeException("Can't set state " + updaterState, e); + } if (previousState != updaterState) { getOnStateChangeCallback().ifPresent(callback -> callback.accept(updaterState)); } @@ -211,7 +216,7 @@ public class UpdateManager { public void cancelRunningUpdate() { try { mUpdateEngine.cancel(); - setUpdaterState(UpdaterStates.IDLE); + setUpdaterState(UpdaterState.IDLE); } catch (Exception e) { Log.w(TAG, "UpdateEngine failed to stop the ongoing update", e); } @@ -227,7 +232,7 @@ public class UpdateManager { public void resetUpdate() { try { mUpdateEngine.resetStatus(); - setUpdaterState(UpdaterStates.IDLE); + setUpdaterState(UpdaterState.IDLE); } catch (Exception e) { Log.w(TAG, "UpdateEngine failed to reset the update", e); } @@ -241,7 +246,7 @@ public class UpdateManager { */ public void applyUpdate(Context context, UpdateConfig config) { mEngineErrorCode.set(UpdateEngineErrorCodes.UNKNOWN); - setUpdaterState(UpdaterStates.RUNNING); + setUpdaterState(UpdaterState.RUNNING); synchronized (mLock) { // Cleaning up previous update data. @@ -269,7 +274,7 @@ public class UpdateManager { builder.setPayload(mPayloadSpecs.forNonStreaming(config.getUpdatePackageFile())); } catch (IOException e) { Log.e(TAG, "Error creating payload spec", e); - setUpdaterState(UpdaterStates.ERROR); + setUpdaterState(UpdaterState.ERROR); return; } updateEngineApplyPayload(builder.build()); @@ -290,7 +295,7 @@ public class UpdateManager { updateEngineApplyPayload(builder.build()); } else { Log.e(TAG, "PrepareStreamingService failed, result code is " + code); - setUpdaterState(UpdaterStates.ERROR); + setUpdaterState(UpdaterState.ERROR); } }); } @@ -332,7 +337,7 @@ public class UpdateManager { properties.toArray(new String[0])); } catch (Exception e) { Log.e(TAG, "UpdateEngine failed to apply the update", e); - setUpdaterState(UpdaterStates.ERROR); + setUpdaterState(UpdaterState.ERROR); } } @@ -396,9 +401,11 @@ public class UpdateManager { mEngineErrorCode.set(errorCode); if (errorCode == UpdateEngine.ErrorCodeConstants.SUCCESS || errorCode == UpdateEngineErrorCodes.UPDATED_BUT_NOT_ACTIVE) { - setUpdaterState(UpdaterStates.FINISHED); + setUpdaterState(isManualSwitchSlotRequired() + ? UpdaterState.SLOT_SWITCH_REQUIRED + : UpdaterState.REBOOT_REQUIRED); } else if (errorCode != UpdateEngineErrorCodes.USER_CANCELLED) { - setUpdaterState(UpdaterStates.ERROR); + setUpdaterState(UpdaterState.ERROR); } getOnEngineCompleteCallback() diff --git a/updater_sample/src/com/example/android/systemupdatersample/UpdaterState.java b/updater_sample/src/com/example/android/systemupdatersample/UpdaterState.java new file mode 100644 index 000000000..36a90982e --- /dev/null +++ b/updater_sample/src/com/example/android/systemupdatersample/UpdaterState.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.systemupdatersample; + +import android.util.SparseArray; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Controls updater state. + */ +public class UpdaterState { + + public static final int IDLE = 0; + public static final int ERROR = 1; + public static final int RUNNING = 2; + public static final int PAUSED = 3; + public static final int SLOT_SWITCH_REQUIRED = 4; + public static final int REBOOT_REQUIRED = 5; + + private static final SparseArray STATE_MAP = new SparseArray<>(); + + static { + STATE_MAP.put(0, "IDLE"); + STATE_MAP.put(1, "ERROR"); + STATE_MAP.put(2, "RUNNING"); + STATE_MAP.put(3, "PAUSED"); + STATE_MAP.put(4, "SLOT_SWITCH_REQUIRED"); + STATE_MAP.put(5, "REBOOT_REQUIRED"); + } + + /** + * Allowed state transitions. It's a map: key is a state, value is a set of states that + * are allowed to transition to from key. + */ + private static final ImmutableMap> TRANSITIONS = + ImmutableMap.of( + IDLE, ImmutableSet.of(RUNNING), + RUNNING, ImmutableSet.of(ERROR, PAUSED, REBOOT_REQUIRED, SLOT_SWITCH_REQUIRED), + PAUSED, ImmutableSet.of(RUNNING), + SLOT_SWITCH_REQUIRED, ImmutableSet.of(ERROR) + ); + + private AtomicInteger mState; + + public UpdaterState(int state) { + this.mState = new AtomicInteger(state); + } + + /** + * Returns updater state. + */ + public int get() { + return mState.get(); + } + + /** + * Sets the updater state. + * + * @throws InvalidTransitionException if transition is not allowed. + */ + public void set(int newState) throws InvalidTransitionException { + int oldState = mState.get(); + if (!TRANSITIONS.get(oldState).contains(newState)) { + throw new InvalidTransitionException( + "Can't transition from " + oldState + " to " + newState); + } + mState.set(newState); + } + + /** + * Converts status code to status name. + */ + public static String getStateText(int state) { + return STATE_MAP.get(state); + } + + /** + * Defines invalid state transition exception. + */ + public static class InvalidTransitionException extends Exception { + public InvalidTransitionException(String msg) { + super(msg); + } + } +} diff --git a/updater_sample/src/com/example/android/systemupdatersample/ui/MainActivity.java b/updater_sample/src/com/example/android/systemupdatersample/ui/MainActivity.java index 9983fe316..0b571cc81 100644 --- a/updater_sample/src/com/example/android/systemupdatersample/ui/MainActivity.java +++ b/updater_sample/src/com/example/android/systemupdatersample/ui/MainActivity.java @@ -33,11 +33,11 @@ import android.widget.TextView; 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; -import com.example.android.systemupdatersample.util.UpdaterStates; import java.util.List; @@ -192,7 +192,7 @@ public class MainActivity extends Activity { /** * Invoked when SystemUpdaterSample app state changes. * Value of {@code state} will be one of the - * values from {@link UpdaterStates}. + * values from {@link UpdaterState}. */ private void onUpdaterStateChange(int state) { Log.i(TAG, "onUpdaterStateChange invoked state=" + state); @@ -233,8 +233,8 @@ public class MainActivity extends Activity { runOnUiThread(() -> { Log.i(TAG, "Completed - errorCode=" - + UpdateEngineErrorCodes.getCodeName(errorCode) + "/" + errorCode - + " " + completionState); + + UpdateEngineErrorCodes.getCodeName(errorCode) + "/" + errorCode + + " " + completionState); setUiEngineErrorCode(errorCode); if (errorCode == UpdateEngineErrorCodes.UPDATED_BUT_NOT_ACTIVE) { // if update was successfully applied. @@ -323,7 +323,7 @@ public class MainActivity extends Activity { * @param state updater sample state */ private void setUiUpdaterState(int state) { - String stateText = UpdaterStates.getStateText(state); + String stateText = UpdaterState.getStateText(state); mTextViewUpdaterState.setText(stateText + "/" + state); } diff --git a/updater_sample/src/com/example/android/systemupdatersample/util/UpdaterStates.java b/updater_sample/src/com/example/android/systemupdatersample/util/UpdaterStates.java deleted file mode 100644 index fc20a7941..000000000 --- a/updater_sample/src/com/example/android/systemupdatersample/util/UpdaterStates.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.systemupdatersample.util; - -import android.util.SparseArray; - -/** - * SystemUpdaterSample app state. - */ -public class UpdaterStates { - - public static final int IDLE = 0; - public static final int ERROR = 1; - public static final int RUNNING = 2; - public static final int PAUSED = 3; - public static final int FINISHED = 4; - - private static final SparseArray STATE_MAP = new SparseArray<>(); - - static { - STATE_MAP.put(0, "IDLE"); - STATE_MAP.put(1, "ERROR"); - STATE_MAP.put(2, "RUNNING"); - STATE_MAP.put(3, "PAUSED"); - STATE_MAP.put(4, "FINISHED"); - } - - /** - * converts status code to status name - */ - public static String getStateText(int state) { - return STATE_MAP.get(state); - } - - private UpdaterStates() {} -} -- cgit v1.2.3