Preload extmainapps

This commit is contained in:
Willy-JL
2023-05-28 00:27:58 +01:00
parent d325a1a43e
commit fc56e39075
8 changed files with 121 additions and 31 deletions
+7 -6
View File
@@ -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;
+35 -21
View File
@@ -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);
+1
View File
@@ -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*
1 entry status name type params
945 Function - fiprintf int FILE*, const char*, ...
946 Function - fiscanf int FILE*, const char*, ...
947 Function + flipper_application_alloc FlipperApplication* Storage*, const ElfApiInterface*
948 Function + flipper_application_despawn void FlipperApplication*
949 Function + flipper_application_free void FlipperApplication*
950 Function + flipper_application_get_manifest const FlipperApplicationManifest* FlipperApplication*
951 Function + flipper_application_is_plugin _Bool FlipperApplication*
+10 -1
View File
@@ -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
+1 -1
View File
@@ -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)