| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- #include "flipper_application.h"
- #include "elf/elf_file.h"
- #include <notification/notification_messages.h>
- #include "application_assets.h"
- #include <m-list.h>
- #define TAG "Fap"
- struct FlipperApplication {
- ELFDebugInfo state;
- FlipperApplicationManifest manifest;
- ELFFile* elf;
- FuriThread* thread;
- void* ep_thread_args;
- };
- /********************** Debugger access to loader state **********************/
- LIST_DEF(FlipperApplicationList, const FlipperApplication*, M_POD_OPLIST);
- FlipperApplicationList_t flipper_application_loaded_app_list = {0};
- static bool flipper_application_loaded_app_list_initialized = false;
- static void flipper_application_list_add_app(const FlipperApplication* app) {
- furi_assert(app);
- if(!flipper_application_loaded_app_list_initialized) {
- FlipperApplicationList_init(flipper_application_loaded_app_list);
- flipper_application_loaded_app_list_initialized = true;
- }
- FlipperApplicationList_push_back(flipper_application_loaded_app_list, app);
- }
- static void flipper_application_list_remove_app(const FlipperApplication* app) {
- furi_assert(flipper_application_loaded_app_list_initialized);
- furi_assert(app);
- FlipperApplicationList_it_t it;
- for(FlipperApplicationList_it(it, flipper_application_loaded_app_list);
- !FlipperApplicationList_end_p(it);
- FlipperApplicationList_next(it)) {
- if(*FlipperApplicationList_ref(it) == app) {
- FlipperApplicationList_remove(flipper_application_loaded_app_list, it);
- break;
- }
- }
- }
- /*****************************************************************************/
- FlipperApplication*
- flipper_application_alloc(Storage* storage, const ElfApiInterface* api_interface) {
- FlipperApplication* app = malloc(sizeof(FlipperApplication));
- app->elf = elf_file_alloc(storage, api_interface);
- app->thread = NULL;
- app->ep_thread_args = NULL;
- return app;
- }
- bool flipper_application_is_plugin(FlipperApplication* app) {
- return app->manifest.stack_size == 0;
- }
- void flipper_application_free(FlipperApplication* app) {
- furi_assert(app);
- if(app->thread) {
- furi_thread_join(app->thread);
- furi_thread_free(app->thread);
- }
- if(app->state.entry) {
- flipper_application_list_remove_app(app);
- }
- elf_file_clear_debug_info(&app->state);
- if(elf_file_is_init_complete(app->elf)) {
- elf_file_call_fini(app->elf);
- }
- elf_file_free(app->elf);
- free(app);
- }
- static FlipperApplicationPreloadStatus
- flipper_application_validate_manifest(FlipperApplication* app) {
- if(!flipper_application_manifest_is_valid(&app->manifest)) {
- return FlipperApplicationPreloadStatusInvalidManifest;
- }
- if(!flipper_application_manifest_is_target_compatible(&app->manifest)) {
- return FlipperApplicationPreloadStatusTargetMismatch;
- }
- if(!flipper_application_manifest_is_compatible(
- &app->manifest, elf_file_get_api_interface(app->elf))) {
- return FlipperApplicationPreloadStatusApiMismatch;
- }
- return FlipperApplicationPreloadStatusSuccess;
- }
- static bool flipper_application_process_manifest_section(
- File* file,
- size_t offset,
- size_t size,
- void* context) {
- FlipperApplicationManifest* manifest = context;
- if(size < sizeof(FlipperApplicationManifest)) {
- return false;
- }
- if(manifest == NULL) {
- return true;
- }
- return storage_file_seek(file, offset, true) &&
- storage_file_read(file, manifest, size) == size;
- }
- // we can't use const char* as context because we will lose the const qualifier
- typedef struct {
- const char* path;
- } FlipperApplicationPreloadAssetsContext;
- static bool flipper_application_process_assets_section(
- File* file,
- size_t offset,
- size_t size,
- void* context) {
- FlipperApplicationPreloadAssetsContext* preload_context = context;
- return flipper_application_assets_load(file, preload_context->path, offset, size);
- }
- static FlipperApplicationPreloadStatus
- flipper_application_load(FlipperApplication* app, const char* path, bool load_full) {
- if(!elf_file_open(app->elf, path)) {
- return FlipperApplicationPreloadStatusInvalidFile;
- }
- // if we are loading full file
- if(load_full) {
- // load section table
- if(!elf_file_load_section_table(app->elf)) {
- return FlipperApplicationPreloadStatusInvalidFile;
- }
- // load assets section
- FlipperApplicationPreloadAssetsContext preload_context = {.path = path};
- if(elf_process_section(
- app->elf,
- ".fapassets",
- flipper_application_process_assets_section,
- &preload_context) == ElfProcessSectionResultCannotProcess) {
- return FlipperApplicationPreloadStatusInvalidFile;
- }
- }
- // load manifest section
- if(elf_process_section(
- app->elf, ".fapmeta", flipper_application_process_manifest_section, &app->manifest) !=
- ElfProcessSectionResultSuccess) {
- return FlipperApplicationPreloadStatusInvalidFile;
- }
- return flipper_application_validate_manifest(app);
- }
- /* Parse headers, load manifest */
- FlipperApplicationPreloadStatus
- flipper_application_preload_manifest(FlipperApplication* app, const char* path) {
- return flipper_application_load(app, path, false);
- }
- /* Parse headers, load full file */
- FlipperApplicationPreloadStatus
- flipper_application_preload(FlipperApplication* app, const char* path) {
- return flipper_application_load(app, path, true);
- }
- const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplication* app) {
- return &app->manifest;
- }
- FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app) {
- ELFFileLoadStatus status = elf_file_load_sections(app->elf);
- switch(status) {
- case ELFFileLoadStatusSuccess:
- elf_file_init_debug_info(app->elf, &app->state);
- flipper_application_list_add_app(app);
- return FlipperApplicationLoadStatusSuccess;
- case ELFFileLoadStatusNoFreeMemory:
- return FlipperApplicationLoadStatusNoFreeMemory;
- case ELFFileLoadStatusMissingImports:
- return FlipperApplicationLoadStatusMissingImports;
- default:
- return FlipperApplicationLoadStatusUnspecifiedError;
- }
- }
- static int32_t flipper_application_thread(void* context) {
- furi_assert(context);
- FlipperApplication* app = (FlipperApplication*)context;
- elf_file_call_init(app->elf);
- FlipperApplicationEntryPoint entry_point = elf_file_get_entry_point(app->elf);
- int32_t ret_code = entry_point(app->ep_thread_args);
- elf_file_call_fini(app->elf);
- // wait until all notifications from RAM are completed
- NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
- const NotificationSequence sequence_empty = {
- NULL,
- };
- notification_message_block(notifications, &sequence_empty);
- furi_record_close(RECORD_NOTIFICATION);
- return ret_code;
- }
- FuriThread* flipper_application_spawn(FlipperApplication* app, void* args) {
- furi_check(app->thread == NULL);
- furi_check(!flipper_application_is_plugin(app));
- app->ep_thread_args = args;
- const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app);
- app->thread = furi_thread_alloc_ex(
- manifest->name, manifest->stack_size, flipper_application_thread, app);
- return app->thread;
- }
- static const char* preload_status_strings[] = {
- [FlipperApplicationPreloadStatusSuccess] = "Success",
- [FlipperApplicationPreloadStatusUnspecifiedError] = "Unknown error",
- [FlipperApplicationPreloadStatusInvalidFile] = "Invalid file",
- [FlipperApplicationPreloadStatusInvalidManifest] = "Invalid file manifest",
- [FlipperApplicationPreloadStatusApiMismatch] = "API version mismatch",
- [FlipperApplicationPreloadStatusTargetMismatch] = "Hardware target mismatch",
- };
- static const char* load_status_strings[] = {
- [FlipperApplicationLoadStatusSuccess] = "Success",
- [FlipperApplicationLoadStatusUnspecifiedError] = "Unknown error",
- [FlipperApplicationLoadStatusNoFreeMemory] = "Out of memory",
- [FlipperApplicationLoadStatusMissingImports] = "Found unsatisfied imports",
- };
- const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status) {
- if(status >= COUNT_OF(preload_status_strings) || preload_status_strings[status] == NULL) {
- return "Unknown error";
- }
- return preload_status_strings[status];
- }
- const char* flipper_application_load_status_to_string(FlipperApplicationLoadStatus status) {
- if(status >= COUNT_OF(load_status_strings) || load_status_strings[status] == NULL) {
- return "Unknown error";
- }
- return load_status_strings[status];
- }
- const FlipperAppPluginDescriptor*
- flipper_application_plugin_get_descriptor(FlipperApplication* app) {
- if(!flipper_application_is_plugin(app)) {
- return NULL;
- }
- if(!elf_file_is_init_complete(app->elf)) {
- elf_file_call_init(app->elf);
- }
- typedef const FlipperAppPluginDescriptor* (*get_lib_descriptor_t)(void);
- get_lib_descriptor_t lib_ep = elf_file_get_entry_point(app->elf);
- furi_check(lib_ep);
- const FlipperAppPluginDescriptor* lib_descriptor = lib_ep();
- FURI_LOG_D(
- TAG,
- "Library for %s, API v. %lu loaded",
- lib_descriptor->appid,
- lib_descriptor->ep_api_version);
- return lib_descriptor;
- }
|