mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2026-10-01 02:07:55 +00:00
Loader: relaunch app after reboot
This commit is contained in:
@@ -88,6 +88,7 @@ struct Desktop {
|
||||
bool in_transition;
|
||||
bool app_running;
|
||||
bool locked;
|
||||
bool pending_launch_done;
|
||||
};
|
||||
|
||||
void desktop_lock(Desktop* desktop);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <applications.h>
|
||||
#include <assets_icons.h>
|
||||
#include <loader/loader.h>
|
||||
#include <loader/loader_pending.h>
|
||||
|
||||
#include "../desktop_i.h"
|
||||
#include "../views/desktop_events.h"
|
||||
@@ -110,6 +111,24 @@ void desktop_scene_main_on_enter(void* context) {
|
||||
desktop_main_set_callback(main_view, desktop_scene_main_callback, desktop);
|
||||
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdMain);
|
||||
|
||||
if(!desktop->pending_launch_done) {
|
||||
desktop->pending_launch_done = true;
|
||||
|
||||
FuriString* pending_name = furi_string_alloc();
|
||||
FuriString* pending_args = furi_string_alloc();
|
||||
|
||||
if(loader_pending_launch_take(pending_name, pending_args)) {
|
||||
FURI_LOG_I(TAG, "Starting pending app: %s", furi_string_get_cstr(pending_name));
|
||||
loader_start_detached_with_gui_error(
|
||||
desktop->loader,
|
||||
furi_string_get_cstr(pending_name),
|
||||
furi_string_empty(pending_args) ? NULL : furi_string_get_cstr(pending_args));
|
||||
}
|
||||
|
||||
furi_string_free(pending_args);
|
||||
furi_string_free(pending_name);
|
||||
}
|
||||
}
|
||||
|
||||
bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "loader.h"
|
||||
#include "loader_i.h"
|
||||
#include "loader_pending.h"
|
||||
#include <applications.h>
|
||||
#include <storage/storage.h>
|
||||
#include <furi_hal.h>
|
||||
@@ -98,6 +99,7 @@ static void loader_dialog_prepare_and_show(DialogsApp* dialogs, const LoaderErro
|
||||
static void loader_show_gui_error(
|
||||
LoaderMessageLoaderStatusResult status,
|
||||
const char* name,
|
||||
const char* args,
|
||||
FuriString* error_message) {
|
||||
furi_check(name);
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
@@ -150,13 +152,14 @@ static void loader_show_gui_error(
|
||||
message, "Error: Out of Memory", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_message_set_text(
|
||||
message,
|
||||
"Not enough RAM to run the\napp. Please reboot the device",
|
||||
"Not enough free RAM.\nReboot and run the app?",
|
||||
64,
|
||||
13,
|
||||
AlignCenter,
|
||||
AlignTop);
|
||||
dialog_message_set_buttons(message, NULL, NULL, "Reboot");
|
||||
if(dialog_message_show(dialogs, message) == DialogMessageButtonRight) {
|
||||
loader_pending_launch_save(name, args);
|
||||
furi_hal_power_reset();
|
||||
}
|
||||
break;
|
||||
@@ -204,7 +207,7 @@ LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const
|
||||
FuriString* error_message = furi_string_alloc();
|
||||
LoaderMessageLoaderStatusResult result =
|
||||
loader_start_internal(loader, name, args, error_message);
|
||||
loader_show_gui_error(result, name, error_message);
|
||||
loader_show_gui_error(result, name, args, error_message);
|
||||
furi_string_free(error_message);
|
||||
return result.value;
|
||||
}
|
||||
@@ -633,6 +636,18 @@ static LoaderMessageLoaderStatusResult loader_start_external_app(
|
||||
break;
|
||||
}
|
||||
|
||||
const FlipperApplicationManifest* run_manifest =
|
||||
flipper_application_get_manifest(loader->app.fap);
|
||||
if(memmgr_heap_get_max_free_block() < ((size_t)run_manifest->stack_size + 1024)) {
|
||||
result.value = loader_make_status_error(
|
||||
LoaderStatusErrorInternal,
|
||||
error_message,
|
||||
"Load failed, %s: no memory for stack",
|
||||
path);
|
||||
result.error = LoaderStatusErrorOutOfMemory;
|
||||
break;
|
||||
}
|
||||
|
||||
loader->app.thread = flipper_application_alloc_thread(loader->app.fap, args);
|
||||
FuriString* app_name = furi_string_alloc();
|
||||
path_extract_filename_no_ext(path, app_name);
|
||||
@@ -991,7 +1006,7 @@ static bool loader_do_deferred_launch(Loader* loader, LoaderDeferredLaunchRecord
|
||||
}
|
||||
|
||||
if(record->flags & LoaderDeferredLaunchFlagGui)
|
||||
loader_show_gui_error(result, app_name_str, error_message);
|
||||
loader_show_gui_error(result, app_name_str, app_args, error_message);
|
||||
|
||||
loader_do_next_deferred_launch_if_available(loader);
|
||||
} while(false);
|
||||
@@ -1102,7 +1117,8 @@ int32_t loader_srv(void* p) {
|
||||
FuriString* error_message = furi_string_alloc();
|
||||
LoaderMessageLoaderStatusResult status = loader_do_start_by_name(
|
||||
loader, message.start.name, message.start.args, error_message); //-V595
|
||||
loader_show_gui_error(status, message.start.name, error_message);
|
||||
loader_show_gui_error(
|
||||
status, message.start.name, message.start.args, error_message);
|
||||
if(status.value != LoaderStatusOk) loader_do_emit_queue_empty_event(loader);
|
||||
if(message.start.name) free((void*)message.start.name);
|
||||
if(message.start.args) free((void*)message.start.args);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "loader_pending.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <saved_struct.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define TAG "LoaderPending"
|
||||
|
||||
#define LOADER_PENDING_PATH INT_PATH(".loader.pending")
|
||||
#define LOADER_PENDING_MAGIC (0x4C)
|
||||
#define LOADER_PENDING_VERSION (1)
|
||||
|
||||
typedef struct {
|
||||
char name_or_path[128];
|
||||
char args[128];
|
||||
} LoaderPendingLaunch;
|
||||
|
||||
bool loader_pending_launch_save(const char* name_or_path, const char* args) {
|
||||
furi_check(name_or_path);
|
||||
|
||||
LoaderPendingLaunch pending = {0};
|
||||
|
||||
if(strlcpy(pending.name_or_path, name_or_path, sizeof(pending.name_or_path)) >=
|
||||
sizeof(pending.name_or_path)) {
|
||||
FURI_LOG_E(TAG, "Name does not fit: %s", name_or_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(args && strlcpy(pending.args, args, sizeof(pending.args)) >= sizeof(pending.args)) {
|
||||
FURI_LOG_E(TAG, "Args do not fit: %s", args);
|
||||
return false;
|
||||
}
|
||||
|
||||
return saved_struct_save(
|
||||
LOADER_PENDING_PATH,
|
||||
&pending,
|
||||
sizeof(pending),
|
||||
LOADER_PENDING_MAGIC,
|
||||
LOADER_PENDING_VERSION);
|
||||
}
|
||||
|
||||
bool loader_pending_launch_take(FuriString* name_or_path, FuriString* args) {
|
||||
furi_check(name_or_path);
|
||||
furi_check(args);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
bool taken = false;
|
||||
|
||||
if(storage_file_exists(storage, LOADER_PENDING_PATH)) {
|
||||
LoaderPendingLaunch pending;
|
||||
bool loaded = saved_struct_load(
|
||||
LOADER_PENDING_PATH,
|
||||
&pending,
|
||||
sizeof(pending),
|
||||
LOADER_PENDING_MAGIC,
|
||||
LOADER_PENDING_VERSION);
|
||||
|
||||
storage_simply_remove(storage, LOADER_PENDING_PATH);
|
||||
|
||||
if(loaded) {
|
||||
pending.name_or_path[sizeof(pending.name_or_path) - 1] = '\0';
|
||||
pending.args[sizeof(pending.args) - 1] = '\0';
|
||||
|
||||
if(pending.name_or_path[0] != '\0') {
|
||||
furi_string_set_str(name_or_path, pending.name_or_path);
|
||||
furi_string_set_str(args, pending.args);
|
||||
taken = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return taken;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
bool loader_pending_launch_save(const char* name_or_path, const char* args);
|
||||
|
||||
bool loader_pending_launch_take(FuriString* name_or_path, FuriString* args);
|
||||
Reference in New Issue
Block a user