mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-22 20:43:07 +00:00
[FL-2578] Updater fixes related to /int handling (#1359)
* Updater fixes related to /int handling updater: performing factory reset on update, checking for LFS free space before updating, fixed improper error handling on backup/restore operations, rebalanced update stage weights for better progress visuals scripts: added CLI output validation for selfupdate.py storage: added pointer validation in storage_int_common_fs_info desktop: fixed crash on rendering invalid slideshows * Typo fix * rpc: Updated protobuf to 0.9 * rpc: removed updater status conversion Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
4a1695ba1c
commit
b95cd2df14
13 changed files with 76 additions and 38 deletions
|
@ -12,6 +12,7 @@
|
|||
struct Slideshow {
|
||||
Icon icon;
|
||||
uint32_t current_frame;
|
||||
bool loaded;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
@ -34,6 +35,7 @@ _Static_assert(sizeof(SlideshowFrameHeader) == 2, "Incorrect SlideshowFrameHeade
|
|||
|
||||
Slideshow* slideshow_alloc() {
|
||||
Slideshow* ret = malloc(sizeof(Slideshow));
|
||||
ret->loaded = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -52,7 +54,7 @@ void slideshow_free(Slideshow* slideshow) {
|
|||
bool slideshow_load(Slideshow* slideshow, const char* fspath) {
|
||||
Storage* storage = furi_record_open("storage");
|
||||
File* slideshow_file = storage_file_alloc(storage);
|
||||
bool load_success = false;
|
||||
slideshow->loaded = false;
|
||||
do {
|
||||
if(!storage_file_open(slideshow_file, fspath, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
break;
|
||||
|
@ -80,12 +82,16 @@ bool slideshow_load(Slideshow* slideshow, const char* fspath) {
|
|||
frame_header.size) {
|
||||
break;
|
||||
}
|
||||
load_success = (frame_idx + 1) == header.frame_count;
|
||||
slideshow->loaded = (frame_idx + 1) == header.frame_count;
|
||||
}
|
||||
} while(false);
|
||||
storage_file_free(slideshow_file);
|
||||
furi_record_close("storage");
|
||||
return load_success;
|
||||
return slideshow->loaded;
|
||||
}
|
||||
|
||||
bool slideshow_is_loaded(Slideshow* slideshow) {
|
||||
return slideshow->loaded;
|
||||
}
|
||||
|
||||
bool slideshow_advance(Slideshow* slideshow) {
|
||||
|
|
|
@ -8,6 +8,7 @@ Slideshow* slideshow_alloc();
|
|||
|
||||
void slideshow_free(Slideshow* slideshow);
|
||||
bool slideshow_load(Slideshow* slideshow, const char* fspath);
|
||||
bool slideshow_is_loaded(Slideshow* slideshow);
|
||||
void slideshow_goback(Slideshow* slideshow);
|
||||
bool slideshow_advance(Slideshow* slideshow);
|
||||
void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y);
|
||||
|
|
|
@ -21,7 +21,9 @@ static void desktop_view_slideshow_draw(Canvas* canvas, void* model) {
|
|||
DesktopSlideshowViewModel* m = model;
|
||||
|
||||
canvas_clear(canvas);
|
||||
if(slideshow_is_loaded(m->slideshow)) {
|
||||
slideshow_draw(m->slideshow, canvas, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static bool desktop_view_slideshow_input(InputEvent* event, void* context) {
|
||||
|
|
|
@ -277,10 +277,6 @@ static void rpc_system_system_update_request_process(const PB_Main* request, voi
|
|||
|
||||
UpdatePrepareResult update_prepare_result =
|
||||
update_operation_prepare(request->content.system_update_request.update_manifest);
|
||||
/* RPC enum does not have such entry; setting to closest one */
|
||||
if(update_prepare_result == UpdatePrepareResultOutdatedManifestVersion) {
|
||||
update_prepare_result = UpdatePrepareResultManifestInvalid;
|
||||
}
|
||||
|
||||
PB_Main* response = malloc(sizeof(PB_Main));
|
||||
response->command_id = request->command_id;
|
||||
|
|
|
@ -655,11 +655,13 @@ static FS_Error storage_int_common_fs_info(
|
|||
lfs_t* lfs = lfs_get_from_storage(storage);
|
||||
LFSData* lfs_data = lfs_data_get_from_storage(storage);
|
||||
|
||||
if(total_space) {
|
||||
*total_space = lfs_data->config.block_size * lfs_data->config.block_count;
|
||||
}
|
||||
|
||||
lfs_ssize_t result = lfs_fs_size(lfs);
|
||||
if(result >= 0) {
|
||||
*free_space = *total_space - (result * lfs_data->config.block_size);
|
||||
if(free_space && (result >= 0)) {
|
||||
*free_space = (lfs_data->config.block_count - result) * lfs_data->config.block_size;
|
||||
}
|
||||
|
||||
return storage_int_parse_error(result);
|
||||
|
|
|
@ -44,17 +44,17 @@ static const UpdateTaskStageGroupMap update_task_stage_progress[] = {
|
|||
[UpdateTaskStageReadManifest] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 5),
|
||||
[UpdateTaskStageLfsBackup] = STAGE_DEF(UpdateTaskStageGroupPreUpdate, 15),
|
||||
|
||||
[UpdateTaskStageRadioImageValidate] = STAGE_DEF(UpdateTaskStageGroupRadio, 10),
|
||||
[UpdateTaskStageRadioErase] = STAGE_DEF(UpdateTaskStageGroupRadio, 50),
|
||||
[UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 90),
|
||||
[UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 15),
|
||||
[UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 60),
|
||||
[UpdateTaskStageRadioImageValidate] = STAGE_DEF(UpdateTaskStageGroupRadio, 15),
|
||||
[UpdateTaskStageRadioErase] = STAGE_DEF(UpdateTaskStageGroupRadio, 60),
|
||||
[UpdateTaskStageRadioWrite] = STAGE_DEF(UpdateTaskStageGroupRadio, 80),
|
||||
[UpdateTaskStageRadioInstall] = STAGE_DEF(UpdateTaskStageGroupRadio, 60),
|
||||
[UpdateTaskStageRadioBusy] = STAGE_DEF(UpdateTaskStageGroupRadio, 80),
|
||||
|
||||
[UpdateTaskStageOBValidation] = STAGE_DEF(UpdateTaskStageGroupOptionBytes, 10),
|
||||
|
||||
[UpdateTaskStageValidateDFUImage] = STAGE_DEF(UpdateTaskStageGroupFirmware, 100),
|
||||
[UpdateTaskStageValidateDFUImage] = STAGE_DEF(UpdateTaskStageGroupFirmware, 50),
|
||||
[UpdateTaskStageFlashWrite] = STAGE_DEF(UpdateTaskStageGroupFirmware, 200),
|
||||
[UpdateTaskStageFlashValidate] = STAGE_DEF(UpdateTaskStageGroupFirmware, 50),
|
||||
[UpdateTaskStageFlashValidate] = STAGE_DEF(UpdateTaskStageGroupFirmware, 30),
|
||||
|
||||
[UpdateTaskStageLfsRestore] = STAGE_DEF(UpdateTaskStageGroupPostUpdate, 30),
|
||||
|
||||
|
@ -214,6 +214,7 @@ UpdateTask* update_task_alloc() {
|
|||
update_task->storage = furi_record_open("storage");
|
||||
update_task->file = storage_file_alloc(update_task->storage);
|
||||
update_task->status_change_cb = NULL;
|
||||
update_task->boot_mode = furi_hal_rtc_get_boot_mode();
|
||||
string_init(update_task->update_path);
|
||||
|
||||
FuriThread* thread = update_task->thread = furi_thread_alloc();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define UPDATE_TASK_NOERR 0
|
||||
#define UPDATE_TASK_FAILED -1
|
||||
|
@ -14,6 +15,7 @@ typedef struct UpdateTask {
|
|||
File* file;
|
||||
updateProgressCb status_change_cb;
|
||||
void* status_change_cb_state;
|
||||
FuriHalRtcBootMode boot_mode;
|
||||
} UpdateTask;
|
||||
|
||||
void update_task_set_progress(UpdateTask* update_task, UpdateTaskStage stage, uint8_t progress);
|
||||
|
|
|
@ -67,7 +67,6 @@ static bool update_task_post_update(UpdateTask* update_task) {
|
|||
string_get_cstr(update_task->update_path), LFS_BACKUP_DEFAULT_FILENAME, file_path);
|
||||
|
||||
update_task_set_progress(update_task, UpdateTaskStageLfsRestore, 0);
|
||||
update_operation_disarm();
|
||||
|
||||
CHECK_RESULT(lfs_backup_unpack(update_task->storage, string_get_cstr(file_path)));
|
||||
|
||||
|
@ -117,17 +116,17 @@ static bool update_task_post_update(UpdateTask* update_task) {
|
|||
int32_t update_task_worker_backup_restore(void* context) {
|
||||
furi_assert(context);
|
||||
UpdateTask* update_task = context;
|
||||
bool success = false;
|
||||
|
||||
FuriHalRtcBootMode boot_mode = furi_hal_rtc_get_boot_mode();
|
||||
FuriHalRtcBootMode boot_mode = update_task->boot_mode;
|
||||
if((boot_mode != FuriHalRtcBootModePreUpdate) && (boot_mode != FuriHalRtcBootModePostUpdate)) {
|
||||
/* no idea how we got here. Clear to normal boot */
|
||||
update_operation_disarm();
|
||||
/* no idea how we got here. Do nothing */
|
||||
return UPDATE_TASK_NOERR;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
do {
|
||||
if(!update_task_parse_manifest(update_task)) {
|
||||
return UPDATE_TASK_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Waiting for BT service to 'start', so we don't race for boot mode flag */
|
||||
|
@ -138,7 +137,11 @@ int32_t update_task_worker_backup_restore(void* context) {
|
|||
success = update_task_pre_update(update_task);
|
||||
} else if(boot_mode == FuriHalRtcBootModePostUpdate) {
|
||||
success = update_task_post_update(update_task);
|
||||
if(success) {
|
||||
update_operation_disarm();
|
||||
}
|
||||
}
|
||||
} while(false);
|
||||
|
||||
if(!success) {
|
||||
update_task_set_progress(update_task, UpdateTaskStageError, 0);
|
||||
|
|
|
@ -340,6 +340,8 @@ int32_t update_task_worker_flash_writer(void* context) {
|
|||
}
|
||||
|
||||
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate);
|
||||
// Format LFS before restoring backup on next boot
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset);
|
||||
|
||||
update_task_set_progress(update_task, UpdateTaskStageCompleted, 100);
|
||||
success = true;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e3d9cdb66ce789f84f6f8e0bdd6d022187964425
|
||||
Subproject commit 6c1b8ae66a85bcd7e79e993a0b5573c38c302db5
|
|
@ -12,6 +12,8 @@
|
|||
#define UPDATE_ROOT_DIR "/ext" UPDATE_DIR_DEFAULT_REL_PATH
|
||||
#define UPDATE_PREFIX "/ext" UPDATE_DIR_DEFAULT_REL_PATH "/"
|
||||
#define UPDATE_SUFFIX "/" UPDATE_MANIFEST_DEFAULT_NAME
|
||||
/* Need at least 4 free LFS pages before update */
|
||||
#define UPDATE_MIN_INT_FREE_SPACE 4 * 4 * 1024
|
||||
|
||||
static const char* update_prepare_result_descr[] = {
|
||||
[UpdatePrepareResultOK] = "OK",
|
||||
|
@ -22,6 +24,7 @@ static const char* update_prepare_result_descr[] = {
|
|||
[UpdatePrepareResultStageIntegrityError] = "Corrupted Stage2 loader",
|
||||
[UpdatePrepareResultManifestPointerError] = "Failed to create update pointer file",
|
||||
[UpdatePrepareResultOutdatedManifestVersion] = "Update package is too old",
|
||||
[UpdatePrepareResultIntFull] = "Need more free space in internal storage",
|
||||
};
|
||||
|
||||
const char* update_operation_describe_preparation_result(const UpdatePrepareResult value) {
|
||||
|
@ -133,15 +136,22 @@ static bool update_operation_persist_manifest_path(Storage* storage, const char*
|
|||
}
|
||||
|
||||
UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) {
|
||||
UpdatePrepareResult result = UpdatePrepareResultManifestFolderNotFound;
|
||||
UpdatePrepareResult result = UpdatePrepareResultIntFull;
|
||||
Storage* storage = furi_record_open("storage");
|
||||
UpdateManifest* manifest = update_manifest_alloc();
|
||||
File* file = storage_file_alloc(storage);
|
||||
|
||||
uint64_t free_int_space;
|
||||
string_t stage_path;
|
||||
string_init(stage_path);
|
||||
do {
|
||||
if((storage_common_fs_info(storage, "/int", NULL, &free_int_space) != FSE_OK) ||
|
||||
(free_int_space < UPDATE_MIN_INT_FREE_SPACE)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(storage_common_stat(storage, manifest_file_path, NULL) != FSE_OK) {
|
||||
result = UpdatePrepareResultManifestFolderNotFound;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ typedef enum {
|
|||
UpdatePrepareResultManifestPointerError,
|
||||
UpdatePrepareResultTargetMismatch,
|
||||
UpdatePrepareResultOutdatedManifestVersion,
|
||||
UpdatePrepareResultIntFull,
|
||||
UpdatePrepareResultUnspecifiedError,
|
||||
} UpdatePrepareResult;
|
||||
|
||||
const char* update_operation_describe_preparation_result(const UpdatePrepareResult value);
|
||||
|
|
|
@ -76,12 +76,15 @@ class Main(App):
|
|||
manifest_name, pkg_name = manifest_path.parts[-1], manifest_path.parts[-2]
|
||||
|
||||
pkg_dir_name = self.args.pkg_dir_name or pkg_name
|
||||
flipper_update_path = f"/ext/update/{pkg_dir_name}"
|
||||
update_root = "/ext/update"
|
||||
flipper_update_path = f"{update_root}/{pkg_dir_name}"
|
||||
|
||||
self.logger.info(f'Installing "{pkg_name}" from {flipper_update_path}')
|
||||
# if not os.path.exists(self.args.manifest_path):
|
||||
# self.logger.error("Error: package not found")
|
||||
if not self.mkdir_on_storage(storage, flipper_update_path):
|
||||
if not self.mkdir_on_storage(
|
||||
storage, update_root
|
||||
) or not self.mkdir_on_storage(storage, flipper_update_path):
|
||||
self.logger.error(f"Error: cannot create {storage.last_error}")
|
||||
return -2
|
||||
|
||||
|
@ -99,6 +102,14 @@ class Main(App):
|
|||
storage.send_and_wait_eol(
|
||||
f"update install {flipper_update_path}/{manifest_name}\r"
|
||||
)
|
||||
result = storage.read.until(storage.CLI_EOL)
|
||||
if not b"Verifying" in result:
|
||||
self.logger.error(f"Unexpected response: {result.decode('ascii')}")
|
||||
return -4
|
||||
result = storage.read.until(storage.CLI_EOL)
|
||||
if not result.startswith(b"OK"):
|
||||
self.logger.error(result.decode("ascii"))
|
||||
return -5
|
||||
break
|
||||
return 0
|
||||
finally:
|
||||
|
|
Loading…
Reference in a new issue