Add sandbox API integration for RmlUi Lua state

- Register sandbox APIs (timer, JSON, crypto, VFS) into RmlUi's Lua state
- Add switchAppSandbox() function for context switching between apps
- Update goHome() to reset sandbox context when returning home
- Fix icon loading for third-party apps (handle full paths vs relative)
- Mirror changes between Android service (kernel.cpp) and desktop designer

This enables third-party apps to use sandbox APIs when running in RmlUi.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-19 15:49:35 +01:00
parent ea44f0bba4
commit cb86d52705
3 changed files with 213 additions and 8 deletions

View File

@@ -21,6 +21,12 @@
#include <fstream>
#include <filesystem>
// Sandbox API includes for RmlUi integration
#include <mosis/sandbox/timer_manager.h>
#include <mosis/sandbox/json_api.h>
#include <mosis/sandbox/crypto_api.h>
#include <mosis/sandbox/virtual_fs.h>
// Global state for Lua access
static Rml::Context* g_context = nullptr;
static Rml::ElementDocument* g_document = nullptr;
@@ -28,6 +34,15 @@ static mosis::AppManager* g_app_manager = nullptr;
static mosis::UpdateService* g_update_service = nullptr;
static mosis::LuaSandboxManager* g_sandbox_manager = nullptr;
// RmlUi sandbox state - APIs registered into RmlUi's Lua state
static std::unique_ptr<mosis::TimerManager> g_rmlui_timer_manager;
static std::unique_ptr<mosis::VirtualFS> g_rmlui_vfs;
static std::string g_current_app_id = "com.mosis.home";
static std::string g_data_root;
// Forward declarations
static void SwitchAppSandbox(const std::string& app_id, const std::string& app_data_path);
using namespace aidl::com::omixlab::mosis;
using namespace aidl::android::hardware;
@@ -268,7 +283,7 @@ static int LuaGoHome(lua_State* L)
Logger::Log("goHome called - returning to home screen");
// Stop any running third-party app
// Stop any running third-party app in the legacy sandbox manager
if (g_sandbox_manager) {
auto running_apps = g_sandbox_manager->GetRunningApps();
for (const auto& app_id : running_apps) {
@@ -280,6 +295,9 @@ static int LuaGoHome(lua_State* L)
}
}
// Switch sandbox context back to home screen
SwitchAppSandbox("com.mosis.home", g_data_root);
// Load home screen
const char* home_path = "apps/home/home.rml";
@@ -307,6 +325,113 @@ static int LuaGoHome(lua_State* L)
return 1;
}
// Register sandbox APIs (timer, json, crypto, fs) into RmlUi's Lua state
static void RegisterSandboxAPIs(lua_State* L)
{
Logger::Log("Registering sandbox APIs...");
// Register timer API
if (g_rmlui_timer_manager) {
mosis::RegisterTimerAPI(L, g_rmlui_timer_manager.get(), g_current_app_id);
Logger::Log(" Timer API registered");
}
// Register JSON API
mosis::RegisterJsonAPI(L, mosis::JsonLimits{});
Logger::Log(" JSON API registered");
// Register crypto API
mosis::RegisterCryptoAPI(L);
Logger::Log(" Crypto API registered");
// Register virtual filesystem API
if (g_rmlui_vfs) {
mosis::RegisterVirtualFS(L, g_rmlui_vfs.get());
Logger::Log(" VirtualFS API registered");
}
Logger::Log("All sandbox APIs registered");
}
// Unregister sandbox APIs (for clean switch between apps)
static void UnregisterSandboxAPIs(lua_State* L)
{
// Clear timer globals
lua_pushnil(L);
lua_setglobal(L, "setTimeout");
lua_pushnil(L);
lua_setglobal(L, "clearTimeout");
lua_pushnil(L);
lua_setglobal(L, "setInterval");
lua_pushnil(L);
lua_setglobal(L, "clearInterval");
// Clear json global
lua_pushnil(L);
lua_setglobal(L, "json");
// Clear crypto global
lua_pushnil(L);
lua_setglobal(L, "crypto");
// Clear fs global
lua_pushnil(L);
lua_setglobal(L, "fs");
Logger::Log("Sandbox APIs unregistered");
}
// Switch sandbox context to a different app
static void SwitchAppSandbox(const std::string& app_id, const std::string& app_data_path)
{
lua_State* L = Rml::Lua::Interpreter::GetLuaState();
// Clear timers for current app
if (g_rmlui_timer_manager) {
g_rmlui_timer_manager->ClearAppTimers(g_current_app_id);
Logger::Log(std::format("Timers cleared for {}", g_current_app_id));
}
// Unregister current APIs
UnregisterSandboxAPIs(L);
// Update current app ID
g_current_app_id = app_id;
// Create new VirtualFS for the app
std::string vfs_path = app_data_path.empty() ?
(g_data_root + "/sandbox_data") :
(app_data_path + "/sandbox_data");
std::filesystem::create_directories(vfs_path);
g_rmlui_vfs = std::make_unique<mosis::VirtualFS>(
app_id,
vfs_path,
mosis::VirtualFSLimits{}
);
Logger::Log(std::format("VirtualFS created for {} at {}", app_id, vfs_path));
// Register APIs for new app
RegisterSandboxAPIs(L);
}
// Lua function to switch sandbox context for a third-party app
// Called before loading an app's UI: switchAppSandbox(app_id, install_path)
static int LuaSwitchAppSandbox(lua_State* L)
{
const char* app_id = luaL_checkstring(L, 1);
const char* install_path = luaL_checkstring(L, 2);
Logger::Log(std::format("Switching sandbox to app: {} at {}", app_id, install_path));
SwitchAppSandbox(app_id, install_path);
lua_pushboolean(L, true);
return 1;
}
// Register Lua functions for navigation
static void RegisterLuaFunctions(const std::string& current_app_id, bool is_system_app)
{
@@ -315,13 +440,18 @@ static void RegisterLuaFunctions(const std::string& current_app_id, bool is_syst
lua_setglobal(L, "loadScreen");
lua_pushcfunction(L, LuaGoHome);
lua_setglobal(L, "goHome");
Logger::Log("Registered Lua loadScreen and goHome functions");
lua_pushcfunction(L, LuaSwitchAppSandbox);
lua_setglobal(L, "switchAppSandbox");
Logger::Log("Registered Lua loadScreen, goHome, and switchAppSandbox functions");
// Register app management APIs
if (g_app_manager && g_update_service) {
mosis::RegisterAppAPIs(L, g_app_manager, g_update_service, current_app_id, is_system_app);
Logger::Log("Registered Lua app management APIs");
}
// Initialize and register sandbox APIs
RegisterSandboxAPIs(L);
}
void Kernel::main_loop()
@@ -362,6 +492,7 @@ void Kernel::main_loop()
// 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";
g_data_root = data_root; // Store for sandbox switching
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");
@@ -372,6 +503,14 @@ void Kernel::main_loop()
g_sandbox_manager = m_sandbox_manager.get();
Logger::Log("App management system initialized");
// Initialize RmlUi sandbox state (timer manager and VFS for home screen)
g_rmlui_timer_manager = std::make_unique<mosis::TimerManager>();
std::string home_sandbox_path = data_root + "/sandbox_data";
std::filesystem::create_directories(home_sandbox_path);
g_rmlui_vfs = std::make_unique<mosis::VirtualFS>(
"com.mosis.home", home_sandbox_path, mosis::VirtualFSLimits{});
Logger::Log("RmlUi sandbox initialized");
// Start background update checks (every 24 hours)
m_update_service->Start(std::chrono::hours(24));
@@ -415,11 +554,16 @@ void Kernel::main_loop()
m_tasks.clear();
}
// Update sandbox timers for running apps
// Update sandbox timers for running apps (legacy sandbox manager)
if (m_sandbox_manager) {
m_sandbox_manager->UpdateTimers();
}
// Update RmlUi sandbox timers (for UI-based apps)
if (g_rmlui_timer_manager) {
g_rmlui_timer_manager->ProcessTimers();
}
m_render_target->bind();
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);