mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-08-21 09:25:06 +00:00
Fix for app uninstall
This commit is contained in:
parent
222bd2adf0
commit
b93acb1f99
@ -152,6 +152,14 @@ error_t app_manager_install_path_add(const char* path);
|
|||||||
*/
|
*/
|
||||||
void app_manager_install_path_scan(void);
|
void app_manager_install_path_scan(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uninstalls an app that was registered via app_manager_install_path_scan() (i.e. discovered on
|
||||||
|
* disk, not installed via app_install()). Stops running instances, removes the manifest
|
||||||
|
* registration, and deletes the app directory. Returns ERROR_NOT_FOUND if the app id is not in
|
||||||
|
* the scan registry.
|
||||||
|
*/
|
||||||
|
error_t app_manager_install_path_uninstall(const char* app_id);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/unistd.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
inline bool app_fs_is_directory(const std::string& path) {
|
inline bool app_fs_is_directory(const std::string& path) {
|
||||||
@ -36,6 +37,50 @@ inline bool app_fs_is_file(const std::string& path) {
|
|||||||
|
|
||||||
// Appends the full path of every direct subdirectory of @a path to @a out.
|
// Appends the full path of every direct subdirectory of @a path to @a out.
|
||||||
// No-op (not an error) if @a path can't be opened.
|
// No-op (not an error) if @a path can't be opened.
|
||||||
|
inline bool app_fs_delete_recursively(const std::string& path) {
|
||||||
|
if (path.empty() || path == "/" || path == "." || path == "..") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app_fs_is_directory(path)) {
|
||||||
|
FileMutex file_mutex;
|
||||||
|
file_mutex_get(&file_mutex, path.c_str());
|
||||||
|
file_mutex_lock(&file_mutex);
|
||||||
|
|
||||||
|
DIR* dir = opendir(path.c_str());
|
||||||
|
if (dir == nullptr) {
|
||||||
|
file_mutex_unlock(&file_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = true;
|
||||||
|
struct dirent* entry;
|
||||||
|
while (success && (entry = readdir(dir)) != nullptr) {
|
||||||
|
if (std::strcmp(entry->d_name, ".") == 0 || std::strcmp(entry->d_name, "..") == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
success = app_fs_delete_recursively(path + "/" + entry->d_name);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
file_mutex_unlock(&file_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = rmdir(path.c_str()) == 0;
|
||||||
|
file_mutex_unlock(&file_mutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileMutex file_mutex;
|
||||||
|
file_mutex_get(&file_mutex, path.c_str());
|
||||||
|
file_mutex_lock(&file_mutex);
|
||||||
|
bool result = unlink(path.c_str()) == 0;
|
||||||
|
file_mutex_unlock(&file_mutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
inline void app_fs_list_direct_subdirectories(const std::string& path, std::vector<std::string>& out) {
|
inline void app_fs_list_direct_subdirectories(const std::string& path, std::vector<std::string>& out) {
|
||||||
// Collect child names while the directory lock is held, then release it before classifying
|
// Collect child names while the directory lock is held, then release it before classifying
|
||||||
// each one with app_fs_is_directory() - that function looks up and locks a FileMutex too,
|
// each one with app_fs_is_directory() - that function looks up and locks a FileMutex too,
|
||||||
|
|||||||
@ -66,57 +66,8 @@ bool ensure_directory_recursive(const std::string& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool delete_recursively(const std::string& path) {
|
bool delete_recursively(const std::string& path) {
|
||||||
LOG_D(TAG, "Deleting %s...", path.c_str());
|
LOG_I(TAG, "Deleting %s...", path.c_str());
|
||||||
if (path.empty() || path == "/" || path == "." || path == "..") {
|
return app_fs_delete_recursively(path);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app_fs_is_directory(path)) {
|
|
||||||
LOG_D(TAG, "Deleting dir %s", path.c_str());
|
|
||||||
|
|
||||||
FileMutex file_mutex;
|
|
||||||
file_mutex_get(&file_mutex, path.c_str());
|
|
||||||
file_mutex_lock(&file_mutex);
|
|
||||||
|
|
||||||
DIR* dir = opendir(path.c_str());
|
|
||||||
if (dir == nullptr) {
|
|
||||||
LOG_E(TAG, "Failed to scan directory %s", path.c_str());
|
|
||||||
file_mutex_unlock(&file_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
dirent* entry;
|
|
||||||
while (success && (entry = readdir(dir)) != nullptr) {
|
|
||||||
if (std::strcmp(entry->d_name, ".") == 0 || std::strcmp(entry->d_name, "..") == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
success = delete_recursively(path + "/" + entry->d_name);
|
|
||||||
}
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
file_mutex_unlock(&file_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result = rmdir(path.c_str()) == 0;
|
|
||||||
file_mutex_unlock(&file_mutex);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app_fs_is_file(path)) {
|
|
||||||
LOG_D(TAG, "Deleting file %s", path.c_str());
|
|
||||||
FileMutex mutex {};
|
|
||||||
file_mutex_get(&mutex, path.c_str());
|
|
||||||
file_mutex_lock(&mutex);
|
|
||||||
bool result = remove(path.c_str()) == 0;
|
|
||||||
file_mutex_unlock(&mutex);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_D(TAG, "Deleting done");
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_app_install_directory(std::string& out_path) {
|
bool get_app_install_directory(std::string& out_path) {
|
||||||
@ -277,6 +228,11 @@ error_t uninstall_locked(const std::string& app_id) {
|
|||||||
return ERROR_NOT_FOUND;
|
return ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can't uninstall in-memory apps
|
||||||
|
if (iterator->second->manifest.location.type != APP_LOCATION_PATH) {
|
||||||
|
return ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
stop_all_instances_of(&iterator->second->manifest);
|
stop_all_instances_of(&iterator->second->manifest);
|
||||||
app_manager_remove(app_id.c_str());
|
app_manager_remove(app_id.c_str());
|
||||||
delete_recursively(iterator->second->path);
|
delete_recursively(iterator->second->path);
|
||||||
@ -404,10 +360,20 @@ error_t app_uninstall(const char* app_id) {
|
|||||||
|
|
||||||
auto& registry = install_registry();
|
auto& registry = install_registry();
|
||||||
mutex_lock(®istry.mutex);
|
mutex_lock(®istry.mutex);
|
||||||
error_t result = uninstall_locked(app_id);
|
error_t error = uninstall_locked(app_id);
|
||||||
mutex_unlock(®istry.mutex);
|
mutex_unlock(®istry.mutex);
|
||||||
|
|
||||||
return result;
|
if (error == ERROR_NOT_FOUND) {
|
||||||
|
error = app_manager_install_path_uninstall(app_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error == ERROR_NONE) {
|
||||||
|
LOG_I(TAG, "Uninstalled %s", app_id);
|
||||||
|
} else {
|
||||||
|
LOG_I(TAG, "Uninstalling %s failed: %s", app_id, error_to_string(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#include <app/location.h>
|
||||||
|
#include <app/manager.h>
|
||||||
#include <app/paths.h>
|
#include <app/paths.h>
|
||||||
#include <tactility/paths.h>
|
#include <tactility/paths.h>
|
||||||
|
|
||||||
@ -34,12 +36,17 @@ error_t app_paths_get_user_data_path(const char* app_id, const char* child_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_t app_paths_get_assets_directory(const char* app_id, char* out_path, size_t out_path_size) {
|
error_t app_paths_get_assets_directory(const char* app_id, char* out_path, size_t out_path_size) {
|
||||||
char directory[224];
|
AppManifest manifest;
|
||||||
error_t error = app_paths_get_user_data_directory(app_id, directory, sizeof(directory));
|
error_t error = app_manager_find_manifest(app_id, &manifest);
|
||||||
if (error != ERROR_NONE) {
|
if (error != ERROR_NONE) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
int written = std::snprintf(out_path, out_path_size, "%s/assets", directory);
|
|
||||||
|
if (manifest.location.type != APP_LOCATION_PATH) {
|
||||||
|
return ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
int written = std::snprintf(out_path, out_path_size, "%s/assets", static_cast<const char*>(manifest.location.location));
|
||||||
if (written < 0 || (size_t)written >= out_path_size) {
|
if (written < 0 || (size_t)written >= out_path_size) {
|
||||||
return ERROR_BUFFER_OVERFLOW;
|
return ERROR_BUFFER_OVERFLOW;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -340,4 +340,30 @@ void app_manager_install_path_scan(void) {
|
|||||||
mutex_unlock(®istry.mutex);
|
mutex_unlock(®istry.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error_t app_manager_install_path_uninstall(const char* app_id) {
|
||||||
|
auto& registry = install_path_registry();
|
||||||
|
|
||||||
|
mutex_lock(®istry.mutex);
|
||||||
|
auto iterator = registry.scanned.find(app_id);
|
||||||
|
if (iterator == registry.scanned.end()) {
|
||||||
|
mutex_unlock(®istry.mutex);
|
||||||
|
return ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto path = iterator->second->path;
|
||||||
|
mutex_unlock(®istry.mutex);
|
||||||
|
|
||||||
|
// app_manager_remove takes ledger.mutex internally - call outside registry.mutex
|
||||||
|
// to match the lock ordering in app_manager_install_path_scan().
|
||||||
|
app_manager_remove(app_id);
|
||||||
|
|
||||||
|
mutex_lock(®istry.mutex);
|
||||||
|
registry.scanned.erase(app_id);
|
||||||
|
mutex_unlock(®istry.mutex);
|
||||||
|
|
||||||
|
app_fs_delete_recursively(path);
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@ -40,6 +40,7 @@ const ModuleSymbol app_module_symbols[] = {
|
|||||||
DEFINE_MODULE_SYMBOL(app_manager_get_topmost_app_id),
|
DEFINE_MODULE_SYMBOL(app_manager_get_topmost_app_id),
|
||||||
DEFINE_MODULE_SYMBOL(app_manager_install_path_add),
|
DEFINE_MODULE_SYMBOL(app_manager_install_path_add),
|
||||||
DEFINE_MODULE_SYMBOL(app_manager_install_path_scan),
|
DEFINE_MODULE_SYMBOL(app_manager_install_path_scan),
|
||||||
|
DEFINE_MODULE_SYMBOL(app_manager_install_path_uninstall),
|
||||||
// app/metadata
|
// app/metadata
|
||||||
DEFINE_MODULE_SYMBOL(app_metadata_parse),
|
DEFINE_MODULE_SYMBOL(app_metadata_parse),
|
||||||
// app/paths
|
// app/paths
|
||||||
|
|||||||
@ -152,27 +152,19 @@ void updateApp(Context* ctx) {
|
|||||||
void updateViews(Context* ctx) {
|
void updateViews(Context* ctx) {
|
||||||
lvgl_toolbar_clear_actions(ctx->toolbar);
|
lvgl_toolbar_clear_actions(ctx->toolbar);
|
||||||
auto app_id = ctx->entry.appId.c_str();
|
auto app_id = ctx->entry.appId.c_str();
|
||||||
AppManifest manifest;
|
|
||||||
bool is_installed = app_manager_find_manifest(app_id, &manifest) == ERROR_NONE;
|
|
||||||
ctx->spinner = lvgl_toolbar_add_spinner_action(ctx->toolbar);
|
ctx->spinner = lvgl_toolbar_add_spinner_action(ctx->toolbar);
|
||||||
lv_obj_add_flag(ctx->spinner, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(ctx->spinner, LV_OBJ_FLAG_HIDDEN);
|
||||||
lv_obj_add_flag(ctx->updateLabel, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(ctx->updateLabel, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
char install_path[128];
|
char install_path[128];
|
||||||
if (app_get_install_path(app_id, install_path, sizeof(install_path)) != ERROR_NONE) {
|
bool is_installed = app_get_install_path(app_id, install_path, sizeof(install_path)) == ERROR_NONE
|
||||||
LOG_E(TAG, "Install path not found for %s", app_id);
|
&& file::isFile(std::string(install_path) + "/manifest.properties");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string metadata_path = std::string(install_path) + "/manifest.properties";
|
|
||||||
AppMetadata metadata;
|
|
||||||
if (app_metadata_parse(metadata_path.c_str(), &metadata) != ERROR_NONE) {
|
|
||||||
LOG_E(TAG, "Failed to parse metadata at %s", metadata_path.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_installed) {
|
if (is_installed) {
|
||||||
if (metadata.app_version_code < ctx->entry.appVersionCode) {
|
std::string metadata_path = std::string(install_path) + "/manifest.properties";
|
||||||
|
AppMetadata metadata;
|
||||||
|
if (app_metadata_parse(metadata_path.c_str(), &metadata) == ERROR_NONE
|
||||||
|
&& metadata.app_version_code < ctx->entry.appVersionCode) {
|
||||||
ctx->updateButton = lvgl_toolbar_add_image_button_action(ctx->toolbar, LV_SYMBOL_DOWNLOAD, onUpdatePressed, ctx);
|
ctx->updateButton = lvgl_toolbar_add_image_button_action(ctx->toolbar, LV_SYMBOL_DOWNLOAD, onUpdatePressed, ctx);
|
||||||
lv_obj_remove_flag(ctx->updateLabel, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_remove_flag(ctx->updateLabel, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user