fix files directory handling: use internal storage and add exception handling
- Use internal files dir instead of external (fixes scoped storage permissions) - Pass files directory from Android context via JNI instead of hardcoding - Add exception handling in ScanAppsDirectory to prevent crashes on permission errors - Use std::error_code overload of fs::exists() to avoid throwing on access denial Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -585,80 +585,94 @@ bool AppManager::DownloadFile(const std::string& url, const std::string& dest_pa
|
||||
void AppManager::ScanAppsDirectory() {
|
||||
std::string apps_dir = m_data_root + "/apps";
|
||||
|
||||
if (!fs::exists(apps_dir)) {
|
||||
try {
|
||||
if (!fs::exists(apps_dir)) {
|
||||
return;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR("Cannot access apps directory: %s", e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("Scanning apps directory: %s", apps_dir.c_str());
|
||||
|
||||
for (const auto& entry : fs::directory_iterator(apps_dir)) {
|
||||
if (!entry.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string package_id = entry.path().filename().string();
|
||||
|
||||
// Skip if already registered
|
||||
if (m_installed_apps.find(package_id) != m_installed_apps.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for manifest.json in direct folder or package/ subfolder
|
||||
std::string manifest_path = entry.path().string() + "/manifest.json";
|
||||
std::string manifest_path_pkg = entry.path().string() + "/package/manifest.json";
|
||||
|
||||
std::string actual_manifest;
|
||||
std::string app_base_path;
|
||||
|
||||
if (fs::exists(manifest_path)) {
|
||||
actual_manifest = manifest_path;
|
||||
app_base_path = entry.path().string();
|
||||
} else if (fs::exists(manifest_path_pkg)) {
|
||||
actual_manifest = manifest_path_pkg;
|
||||
app_base_path = entry.path().string() + "/package";
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse manifest
|
||||
std::ifstream mf(actual_manifest);
|
||||
if (!mf) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
json j;
|
||||
mf >> j;
|
||||
|
||||
InstalledApp app;
|
||||
app.package_id = j.value("id", package_id);
|
||||
app.name = j.value("name", package_id);
|
||||
app.version_name = j.value("version", "1.0.0");
|
||||
app.version_code = j.value("version_code", 1);
|
||||
app.install_path = entry.path().string();
|
||||
app.entry_point = j.value("entry", "main.rml");
|
||||
app.icon_path = j.value("icon", "");
|
||||
app.is_system_app = false;
|
||||
|
||||
if (j.contains("developer")) {
|
||||
app.developer_name = j["developer"].value("name", "");
|
||||
}
|
||||
|
||||
if (j.contains("permissions") && j["permissions"].is_array()) {
|
||||
for (const auto& perm : j["permissions"]) {
|
||||
app.permissions.push_back(perm.get<std::string>());
|
||||
try {
|
||||
for (const auto& entry : fs::directory_iterator(apps_dir)) {
|
||||
try {
|
||||
if (!entry.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string package_id = entry.path().filename().string();
|
||||
|
||||
// Skip if already registered
|
||||
if (m_installed_apps.find(package_id) != m_installed_apps.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for manifest.json in direct folder or package/ subfolder
|
||||
std::string manifest_path = entry.path().string() + "/manifest.json";
|
||||
std::string manifest_path_pkg = entry.path().string() + "/package/manifest.json";
|
||||
|
||||
std::string actual_manifest;
|
||||
std::string app_base_path;
|
||||
|
||||
// Use error_code overload to avoid exceptions on permission errors
|
||||
std::error_code ec;
|
||||
if (fs::exists(manifest_path, ec) && !ec) {
|
||||
actual_manifest = manifest_path;
|
||||
app_base_path = entry.path().string();
|
||||
} else if (fs::exists(manifest_path_pkg, ec) && !ec) {
|
||||
actual_manifest = manifest_path_pkg;
|
||||
app_base_path = entry.path().string() + "/package";
|
||||
} else {
|
||||
if (ec) {
|
||||
LOG_WARN("Cannot access %s: %s", package_id.c_str(), ec.message().c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse manifest
|
||||
std::ifstream mf(actual_manifest);
|
||||
if (!mf) {
|
||||
continue;
|
||||
}
|
||||
|
||||
json j;
|
||||
mf >> j;
|
||||
|
||||
InstalledApp app;
|
||||
app.package_id = j.value("id", package_id);
|
||||
app.name = j.value("name", package_id);
|
||||
app.version_name = j.value("version", "1.0.0");
|
||||
app.version_code = j.value("version_code", 1);
|
||||
app.install_path = entry.path().string();
|
||||
app.entry_point = j.value("entry", "main.rml");
|
||||
app.icon_path = j.value("icon", "");
|
||||
app.is_system_app = false;
|
||||
|
||||
if (j.contains("developer")) {
|
||||
app.developer_name = j["developer"].value("name", "");
|
||||
}
|
||||
|
||||
if (j.contains("permissions") && j["permissions"].is_array()) {
|
||||
for (const auto& perm : j["permissions"]) {
|
||||
app.permissions.push_back(perm.get<std::string>());
|
||||
}
|
||||
}
|
||||
|
||||
app.installed_at = std::chrono::system_clock::now();
|
||||
app.updated_at = std::chrono::system_clock::now();
|
||||
|
||||
m_installed_apps[app.package_id] = app;
|
||||
LOG_INFO("Discovered app: %s (%s)", app.name.c_str(), app.package_id.c_str());
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
LOG_WARN("Error processing app entry: %s", e.what());
|
||||
}
|
||||
|
||||
app.installed_at = std::chrono::system_clock::now();
|
||||
app.updated_at = std::chrono::system_clock::now();
|
||||
|
||||
m_installed_apps[app.package_id] = app;
|
||||
LOG_INFO("Discovered app: %s (%s)", app.name.c_str(), app.package_id.c_str());
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
LOG_WARN("Failed to parse manifest for %s: %s", package_id.c_str(), e.what());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR("Error scanning apps directory: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#include <mosis/sandbox/crypto_api.h>
|
||||
#include <mosis/sandbox/virtual_fs.h>
|
||||
|
||||
// External function to get files directory from JNI
|
||||
extern const std::string& GetFilesDir();
|
||||
|
||||
// Global state for Lua access
|
||||
static Rml::Context* g_context = nullptr;
|
||||
static Rml::ElementDocument* g_document = nullptr;
|
||||
@@ -500,9 +503,15 @@ void Kernel::main_loop()
|
||||
Logger::Log("RmlUi Lua bindings initialized");
|
||||
|
||||
// Initialize app management system
|
||||
// TODO: Get data root from Android context (for now use a placeholder)
|
||||
std::string data_root = "/data/data/com.omixlab.mosis/files";
|
||||
// Get files directory from Android context (set via JNI)
|
||||
std::string data_root = GetFilesDir();
|
||||
if (data_root.empty()) {
|
||||
// Fallback if not set (shouldn't happen in normal operation)
|
||||
data_root = "/data/data/com.omixlab.mosis/files";
|
||||
Logger::Log("Warning: Files directory not set, using fallback");
|
||||
}
|
||||
g_data_root = data_root; // Store for sandbox switching
|
||||
Logger::Log("Using data root: " + data_root);
|
||||
m_app_manager = std::make_unique<mosis::AppManager>(data_root);
|
||||
m_update_service = std::make_unique<mosis::UpdateService>(
|
||||
m_app_manager.get(), "https://portal.mosis.dev/api/v1");
|
||||
|
||||
@@ -83,4 +83,22 @@ Java_com_omixlab_mosis_NativeService_setAssetManager(JNIEnv *env, jobject thiz,
|
||||
jobject asset_manager)
|
||||
{
|
||||
AssetsManager::Init(AAssetManager_fromJava(env, asset_manager));
|
||||
}
|
||||
|
||||
// Global storage for files directory path
|
||||
static std::string g_files_dir;
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_omixlab_mosis_NativeService_setFilesDir(JNIEnv *env, jobject thiz,
|
||||
jstring files_dir)
|
||||
{
|
||||
const char* path = env->GetStringUTFChars(files_dir, nullptr);
|
||||
g_files_dir = path;
|
||||
env->ReleaseStringUTFChars(files_dir, path);
|
||||
LOG_INFO("Files directory set to: %s", g_files_dir.c_str());
|
||||
}
|
||||
|
||||
const std::string& GetFilesDir() {
|
||||
return g_files_dir;
|
||||
}
|
||||
@@ -19,6 +19,7 @@ class NativeService : Service() {
|
||||
}
|
||||
external fun getBinderNative(): IBinder
|
||||
external fun setAssetManager(assetManager: AssetManager)
|
||||
external fun setFilesDir(filesDir: String)
|
||||
|
||||
override fun onBind(intent: Intent): IBinder {
|
||||
return getBinderNative()
|
||||
@@ -27,6 +28,9 @@ class NativeService : Service() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
setAssetManager(assets)
|
||||
// Use internal files dir - more reliable access in service processes
|
||||
// For debugging, use: adb shell run-as com.omixlab.mosis ls files/
|
||||
setFilesDir(filesDir.absolutePath)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
|
||||
Reference in New Issue
Block a user