Skip to content

Commit

Permalink
Fix update failure when rebooting during installation
Browse files Browse the repository at this point in the history
This commit resolves the issue where the update action on the UF Server
 would become stuck in the updating state if the device rebooted during
 the update installation process, preventing the deployment of the same
 artifact file to the target again.
UF-849

Signed-off-by: Saeed Rezaee <saeed.rezaee@kynetics.it>
  • Loading branch information
SaeedRe committed May 2, 2024
1 parent 0c0d4e3 commit a15997b
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import android.os.Environment
import android.os.SystemClock
import android.os.SystemProperties
import android.util.Log
import com.kynetics.uf.android.BuildConfig
Expand Down Expand Up @@ -226,6 +227,7 @@ class CurrentUpdateState(context: Context) {
.remove(UPDATE_IS_STARTED_KEY)
.remove(PENDING_AB_REBOOT_SHAREDPREFERENCES_KEY)
.remove(UPDATE_STARTED_IN_VERSION)
.remove(DEVICE_BOOT_DATE_WHEN_UPDATE_STARTED_KEY)
.apply()
}

Expand All @@ -252,6 +254,36 @@ class CurrentUpdateState(context: Context) {
}
}

/**
* Returns the date-time that the device was booted in seconds.
*
* Note: This function should not be called when device is booting up.
* Because the current time is not reliable until the device is fully booted and connected to the network.
* @return the boot time in seconds since epoch.
* */
private fun getBootDateInSeconds(): Long {
return (System.currentTimeMillis() - SystemClock.elapsedRealtime()) / 1000
}

fun storeDeviceBootDate() {
sharedPreferences.edit()
.putLong(DEVICE_BOOT_DATE_WHEN_UPDATE_STARTED_KEY, getBootDateInSeconds())
.apply()
}

private fun getDeviceBootDateStoredInPreferences(): Long {
return sharedPreferences.getLong(DEVICE_BOOT_DATE_WHEN_UPDATE_STARTED_KEY, 0)
}

fun isDeviceRebootedAfterUpdateStarted(): Boolean {
val currentBootDate = getBootDateInSeconds() / 10
val previousBootDate = getDeviceBootDateStoredInPreferences() / 10
if (previousBootDate == 0L) {
return false
}
return currentBootDate != previousBootDate
}

fun parseLastLogFile(): List<String> {
return try {
val lastLogFile = File(RECOVERY_CACHE, LAST_LOG_FILE_NAME)
Expand All @@ -269,6 +301,7 @@ class CurrentUpdateState(context: Context) {
private const val PENDING_AB_SHAREDPREFERENCES_KEY = "PENDING_AB_OTA_KEY"
private const val PENDING_AB_REBOOT_SHAREDPREFERENCES_KEY = "PENDING_AB_REBOOT_OTA_KEY"
private const val UPDATE_STARTED_IN_VERSION = "UPDATE_START_VERSION_KEY"
private const val DEVICE_BOOT_DATE_WHEN_UPDATE_STARTED_KEY = "DEVICE_BOOT_DATE_WHEN_UPDATE_STARTED"
private const val TAG = "CurrentUpdateState"
private val SHARED_PREFERENCES_FILE_NAME = "CURRENT_UPDATE_STATE"
private val APK_DISTRIBUTION_REPORT_SUCCESS_KEY = "APK_DISTRIBUTION_REPORT_SUCCESS"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ internal object ABOtaInstaller : OtaInstaller {
val abInstallationPending = currentUpdateState.isABInstallationPending(artifact)
val isDeviceFailedToRebootOrUFServiceCrashed =
currentUpdateState.isDeviceFailedToRebootOrUFServiceCrashed()

val deviceRebootedWhileUpdating = currentUpdateState.isDeviceRebootedAfterUpdateStarted()
return when {
abInstallationPending && isDeviceFailedToRebootOrUFServiceCrashed -> {
abInstallationPending && !deviceRebootedWhileUpdating &&
isDeviceFailedToRebootOrUFServiceCrashed -> {
updateEngine.bind(
MyUpdateEngineCallback(
context,
Expand All @@ -135,7 +136,7 @@ internal object ABOtaInstaller : OtaInstaller {
)
installationResult(updateStatus, messenger, artifact)
}
abInstallationPending -> {
abInstallationPending && !isDeviceFailedToRebootOrUFServiceCrashed -> {
val result = currentUpdateState.lastABInstallationResult()
val message = "Installation result of Ota named ${artifact.filename} is " +
if (result is CurrentUpdateState.InstallationResult.Success) "success" else "failure"
Expand Down Expand Up @@ -169,6 +170,7 @@ internal object ABOtaInstaller : OtaInstaller {
updateStatus, currentUpdateState
)
)
currentUpdateState.storeDeviceBootDate()
currentUpdateState.addPendingABInstallation(artifact)
currentUpdateState.addUFServiceVersionThatStartedTheUpdate()
messenger.sendMessageToServer(
Expand Down

0 comments on commit a15997b

Please sign in to comment.