mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-06-07 19:01:54 -07:00
Preload extmainapps
This commit is contained in:
@@ -15,6 +15,7 @@ typedef struct {
|
||||
const size_t stack_size;
|
||||
const Icon* icon;
|
||||
const FlipperApplicationFlag flags;
|
||||
void* preload;
|
||||
} FlipperApplication;
|
||||
|
||||
typedef void (*FlipperOnStartHook)(void);
|
||||
@@ -24,32 +25,32 @@ extern const char* FLIPPER_AUTORUN_APP_NAME;
|
||||
/* Services list
|
||||
* Spawned on startup
|
||||
*/
|
||||
extern const FlipperApplication FLIPPER_SERVICES[];
|
||||
extern FlipperApplication FLIPPER_SERVICES[];
|
||||
extern const size_t FLIPPER_SERVICES_COUNT;
|
||||
|
||||
/* Apps list
|
||||
* Spawned by loader
|
||||
*/
|
||||
extern const FlipperApplication FLIPPER_APPS[];
|
||||
extern FlipperApplication FLIPPER_APPS[];
|
||||
extern const size_t FLIPPER_APPS_COUNT;
|
||||
|
||||
/* On system start hooks
|
||||
* Called by loader, after OS initialization complete
|
||||
*/
|
||||
extern const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[];
|
||||
extern FlipperOnStartHook FLIPPER_ON_SYSTEM_START[];
|
||||
extern const size_t FLIPPER_ON_SYSTEM_START_COUNT;
|
||||
|
||||
/* System apps
|
||||
* Can only be spawned by loader by name
|
||||
*/
|
||||
extern const FlipperApplication FLIPPER_SYSTEM_APPS[];
|
||||
extern FlipperApplication FLIPPER_SYSTEM_APPS[];
|
||||
extern const size_t FLIPPER_SYSTEM_APPS_COUNT;
|
||||
|
||||
/* Separate scene app holder
|
||||
* Spawned by loader
|
||||
*/
|
||||
extern const FlipperApplication FLIPPER_SCENE;
|
||||
extern const FlipperApplication FLIPPER_SCENE_APPS[];
|
||||
extern FlipperApplication FLIPPER_SCENE_APPS[];
|
||||
extern const size_t FLIPPER_SCENE_APPS_COUNT;
|
||||
|
||||
extern const FlipperApplication FLIPPER_ARCHIVE;
|
||||
@@ -57,5 +58,5 @@ extern const FlipperApplication FLIPPER_ARCHIVE;
|
||||
/* Settings list
|
||||
* Spawned by loader
|
||||
*/
|
||||
extern const FlipperApplication FLIPPER_SETTINGS_APPS[];
|
||||
extern FlipperApplication FLIPPER_SETTINGS_APPS[];
|
||||
extern const size_t FLIPPER_SETTINGS_APPS_COUNT;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "loader.h"
|
||||
#include "loader_i.h"
|
||||
#include "loader_menu.h"
|
||||
#include "loader_preload.h"
|
||||
#include <applications.h>
|
||||
#include <furi_hal.h>
|
||||
#include <core/dangerous_defines.h>
|
||||
@@ -147,29 +148,38 @@ static Loader* loader_alloc() {
|
||||
loader->app.insomniac = false;
|
||||
ExtMainAppList_init(loader->ext_main_apps);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FuriString* path = furi_string_alloc();
|
||||
FuriString* name = furi_string_alloc();
|
||||
Stream* stream = file_stream_alloc(storage);
|
||||
if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
while(stream_read_line(stream, path)) {
|
||||
furi_string_replace_all(path, "\r", "");
|
||||
furi_string_replace_all(path, "\n", "");
|
||||
const Icon* icon;
|
||||
if(!loader_menu_load_fap_meta(storage, path, name, &icon)) continue;
|
||||
ExtMainAppList_push_back(
|
||||
loader->ext_main_apps,
|
||||
(ExtMainApp){
|
||||
.name = strdup(furi_string_get_cstr(name)),
|
||||
.path = strdup(furi_string_get_cstr(path)),
|
||||
.icon = icon});
|
||||
if(furi_hal_is_normal_boot()) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) {
|
||||
if(FLIPPER_APPS[i].app != NULL) continue;
|
||||
if(storage_common_exists(storage, FLIPPER_APPS[i].appid)) {
|
||||
void* preload = loader_preload(storage, FLIPPER_APPS[i].appid);
|
||||
FLIPPER_APPS[i].preload = preload;
|
||||
}
|
||||
}
|
||||
FuriString* path = furi_string_alloc();
|
||||
FuriString* name = furi_string_alloc();
|
||||
Stream* stream = file_stream_alloc(storage);
|
||||
if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
while(stream_read_line(stream, path)) {
|
||||
furi_string_replace_all(path, "\r", "");
|
||||
furi_string_replace_all(path, "\n", "");
|
||||
const Icon* icon;
|
||||
if(!loader_menu_load_fap_meta(storage, path, name, &icon)) continue;
|
||||
ExtMainAppList_push_back(
|
||||
loader->ext_main_apps,
|
||||
(ExtMainApp){
|
||||
.name = strdup(furi_string_get_cstr(name)),
|
||||
.path = strdup(furi_string_get_cstr(path)),
|
||||
.icon = icon});
|
||||
}
|
||||
}
|
||||
file_stream_close(stream);
|
||||
stream_free(stream);
|
||||
furi_string_free(name);
|
||||
furi_string_free(path);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
file_stream_close(stream);
|
||||
stream_free(stream);
|
||||
furi_string_free(name);
|
||||
furi_string_free(path);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
return loader;
|
||||
}
|
||||
|
||||
@@ -214,6 +224,10 @@ static void
|
||||
FURI_LOG_I(TAG, "Starting %s", app->name);
|
||||
|
||||
if(app->app == NULL) {
|
||||
if(app->preload != NULL) {
|
||||
loader_preload_start(app->preload, app->appid);
|
||||
return;
|
||||
}
|
||||
args = app->appid;
|
||||
app = loader_find_application_by_name_in_list(
|
||||
FAP_LOADER_APP_NAME, FLIPPER_APPS, FLIPPER_APPS_COUNT);
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <loader/firmware_api/firmware_api.h>
|
||||
#include <furi_hal.h>
|
||||
#include <toolbox/path.h>
|
||||
|
||||
#define TAG "Preload"
|
||||
|
||||
void* loader_preload(Storage* storage, const char* path) {
|
||||
FlipperApplication* app = flipper_application_alloc(storage, firmware_api_interface);
|
||||
size_t start = furi_get_tick();
|
||||
|
||||
FURI_LOG_I(TAG, "Loading %s", path);
|
||||
|
||||
FlipperApplicationPreloadStatus preload_res = flipper_application_preload(app, path);
|
||||
if(preload_res != FlipperApplicationPreloadStatusSuccess) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Mapping");
|
||||
FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(app);
|
||||
if(load_status != FlipperApplicationLoadStatusSuccess) {
|
||||
const char* err_msg = flipper_application_load_status_to_string(load_status);
|
||||
FURI_LOG_E(TAG, "Failed to map to memory %s: %s", path, err_msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Loaded in %ums", (size_t)(furi_get_tick() - start));
|
||||
return app;
|
||||
}
|
||||
|
||||
void loader_preload_start(void* _app, const char* path) {
|
||||
FlipperApplication* app = _app;
|
||||
FURI_LOG_I(TAG, "Starting app");
|
||||
|
||||
FuriThread* thread = flipper_application_spawn(app, NULL);
|
||||
|
||||
/* This flag is set by the debugger - to break on app start */
|
||||
if(furi_hal_debug_is_gdb_session_active()) {
|
||||
FURI_LOG_W(TAG, "Triggering BP for debugger");
|
||||
/* After hitting this, you can set breakpoints in your .fap's code
|
||||
* Note that you have to toggle breakpoints that were set before */
|
||||
__asm volatile("bkpt 0");
|
||||
}
|
||||
|
||||
FuriString* app_name = furi_string_alloc();
|
||||
path_extract_filename_no_ext(path, app_name);
|
||||
furi_thread_set_appid(thread, furi_string_get_cstr(app_name));
|
||||
furi_string_free(app_name);
|
||||
|
||||
furi_thread_start(thread);
|
||||
furi_thread_join(thread);
|
||||
|
||||
flipper_application_despawn(app);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <storage/storage.h>
|
||||
|
||||
void* loader_preload(Storage* storage, const char* path);
|
||||
void loader_preload_start(void* app, const char* path);
|
||||
@@ -945,6 +945,7 @@ Function,-,finitel,int,long double
|
||||
Function,-,fiprintf,int,"FILE*, const char*, ..."
|
||||
Function,-,fiscanf,int,"FILE*, const char*, ..."
|
||||
Function,+,flipper_application_alloc,FlipperApplication*,"Storage*, const ElfApiInterface*"
|
||||
Function,+,flipper_application_despawn,void,FlipperApplication*
|
||||
Function,+,flipper_application_free,void,FlipperApplication*
|
||||
Function,+,flipper_application_get_manifest,const FlipperApplicationManifest*,FlipperApplication*
|
||||
Function,+,flipper_application_is_plugin,_Bool,FlipperApplication*
|
||||
|
||||
|
@@ -236,6 +236,15 @@ FuriThread* flipper_application_spawn(FlipperApplication* app, void* args) {
|
||||
return app->thread;
|
||||
}
|
||||
|
||||
void flipper_application_despawn(FlipperApplication* app) {
|
||||
furi_check(app->thread != NULL);
|
||||
furi_check(!flipper_application_is_plugin(app));
|
||||
|
||||
furi_thread_join(app->thread);
|
||||
furi_thread_free(app->thread);
|
||||
app->thread = NULL;
|
||||
}
|
||||
|
||||
static const char* preload_status_strings[] = {
|
||||
[FlipperApplicationPreloadStatusSuccess] = "Success",
|
||||
[FlipperApplicationPreloadStatusUnspecifiedError] = "Unknown error",
|
||||
@@ -289,4 +298,4 @@ const FlipperAppPluginDescriptor*
|
||||
lib_descriptor->ep_api_version);
|
||||
|
||||
return lib_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,14 +107,19 @@ FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplicatio
|
||||
|
||||
/**
|
||||
* @brief Create application thread at entry point address, using app name and
|
||||
* stack size from metadata. Returned thread isn't started yet.
|
||||
* Can be only called once for application instance.
|
||||
* stack size from metadata. Returned thread isn't started yet.
|
||||
* @param app Applicaiton pointer
|
||||
* @param args Object to pass to app's entry point
|
||||
* @return Created thread
|
||||
*/
|
||||
FuriThread* flipper_application_spawn(FlipperApplication* app, void* args);
|
||||
|
||||
/**
|
||||
* @brief Cleanup application in order to re-spawn later.
|
||||
* @param app Applicaiton pointer
|
||||
*/
|
||||
void flipper_application_despawn(FlipperApplication* app);
|
||||
|
||||
/**
|
||||
* @brief Check if application is a plugin (not a runnable standalone app)
|
||||
* @param app Application pointer
|
||||
|
||||
@@ -395,7 +395,7 @@ class ApplicationsCGenerator:
|
||||
map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype))
|
||||
)
|
||||
entry_type, entry_block = self.APP_TYPE_MAP[apptype]
|
||||
contents.append(f"const {entry_type} {entry_block}[] = {{")
|
||||
contents.append(f"{entry_type} {entry_block}[] = {{")
|
||||
apps = self.buildset.get_apps_of_type(apptype)
|
||||
if apptype is FlipperAppType.APP:
|
||||
apps += self.buildset.get_apps_of_type(FlipperAppType.EXTMAINAPP)
|
||||
|
||||
Reference in New Issue
Block a user