Plugin Lifecycle¶
Overview¶
Understanding the plugin lifecycle is crucial for developing robust Movian plugins. This document details the complete lifecycle from plugin discovery through execution and cleanup, including state transitions, error handling, and resource management.
Lifecycle Phases¶
1. Discovery Phase¶
The plugin manager discovers plugins through multiple sources:
Repository Scanning¶
// From plugins.c - plugin_load_repo()
static int plugin_load_repo(void) {
// Fetch plugin metadata from remote repository
// Parse plugin list and create plugin entries
// Update plugin availability status
}
Installed Plugin Scanning¶
// From plugins.c - plugin_load_installed()
static void plugin_load_installed(void) {
// Scan installedplugins directory
// Load plugin.json from each ZIP file
// Create plugin entries for installed plugins
}
Development Plugin Loading¶
// From plugins.c - plugins_init()
void plugins_init(char **devplugs) {
// Load development plugins from specified paths
// Enable debug mode and bypass security restrictions
}
2. Installation Phase¶
When a user chooses to install a plugin:
Download Process¶
// From plugins.c - plugin_install()
static int plugin_install(plugin_t *pl, const char *package) {
// 1. Download plugin package from repository
// 2. Validate ZIP file format
// 3. Save to installedplugins directory
// 4. Load and validate plugin.json
// 5. Update plugin state
}
Validation Steps¶
- Package Integrity: Verify ZIP file format and structure
- Manifest Validation: Parse and validate plugin.json
- Compatibility Check: Verify Movian version requirements
- Security Check: Validate against blacklist
- Dependency Resolution: Check for required components
3. Loading Phase¶
Plugin loading occurs during Movian startup or on-demand:
Context Creation¶
// From ecmascript.c - es_context_create()
static es_context_t *es_context_create(const char *id, int flags,
const char *url, const char *storage) {
// 1. Create ECMAScript execution context
// 2. Initialize memory management
// 3. Set up security sandbox
// 4. Configure debug settings
}
Environment Setup¶
// From ecmascript.c - es_create_env()
static void es_create_env(es_context_t *ec, const char *loaddir,
const char *storage) {
// 1. Create global objects and APIs
// 2. Set up module resolution system
// 3. Configure plugin-specific paths
// 4. Initialize core JavaScript modules
}
Code Compilation and Execution¶
// From ecmascript.c - ecmascript_plugin_load()
int ecmascript_plugin_load(const char *id, const char *url,
char *errbuf, size_t errlen,
int version, const char *manifest, int flags) {
// 1. Create plugin execution context
// 2. Set up Plugin global object
// 3. Load API compatibility layer (if needed)
// 4. Compile and execute main plugin file
}
4. Execution Phase¶
During execution, plugins interact with Movian's systems:
Service Registration¶
Plugins typically register services during initialization:
// Example plugin service registration
var service = require('movian/service');
service.create("My Video Service", "myservice:", {
title: "My Video Service",
icon: Plugin.path + "icon.png"
});
Resource Management¶
The ECMAScript runtime tracks plugin resources:
// From ecmascript.c - es_resource_create()
void *es_resource_create(es_context_t *ec, const es_resource_class_t *erc,
int permanent) {
// Create and link resource to plugin context
// Track for automatic cleanup
}
5. Unloading Phase¶
Plugin unloading can occur due to: - User uninstallation - Plugin errors - Movian shutdown - Plugin reload during development
Resource Cleanup¶
// From ecmascript.c - ecmascript_plugin_unload()
void ecmascript_plugin_unload(const char *id) {
// 1. Find plugin context by ID
// 2. Destroy all permanent resources
// 3. Clean up volatile resources
// 4. Release ECMAScript context
}
View Cleanup¶
// From plugins.c - plugin_unload_views()
static void plugin_unload_views(plugin_t *pl) {
// Remove all registered view components
// Clean up UI integration points
}
State Diagram¶
stateDiagram-v2
[*] --> Discovered: Repository scan
Discovered --> Downloading: User install
Downloading --> Downloaded: Download complete
Downloaded --> Installing: Validation passed
Installing --> Installed: Installation success
Installed --> Loading: Movian startup
Loading --> Loaded: Context created
Loaded --> Running: Code execution
Running --> Suspended: Context suspend
Suspended --> Running: Context resume
Running --> Unloading: Plugin stop
Unloading --> Installed: Cleanup complete
Installed --> Removing: User uninstall
Removing --> [*]: Removal complete
Downloading --> Discovered: Download failed
Installing --> Discovered: Install failed
Loading --> Installed: Load failed
Loaded --> Installed: Execution failed
Error Handling¶
Compilation Errors¶
When JavaScript compilation fails:
// From ecmascript.c - es_load_and_compile()
static int es_load_and_compile(es_context_t *ec, const char *path,
duk_context *ctx) {
if(duk_pcompile(ctx, 0)) {
TRACE(TRACE_ERROR, rstr_get(ec->ec_id),
"Unable to compile %s -- %s", path,
duk_safe_to_string(ctx, -1));
return -1;
}
}
Runtime Errors¶
Runtime exceptions are caught and logged:
// From ecmascript.c - es_dump_err_ex()
void es_dump_err_ex(duk_context *ctx, const char *native_func,
const char *native_file, int native_line) {
// Extract error information
// Log error with stack trace
// Include native callsite information
}
Recovery Mechanisms¶
- Graceful Degradation: Core Movian functionality continues
- Error Reporting: Detailed error messages for debugging
- Automatic Cleanup: Resources automatically released on failure
- Retry Logic: Failed plugins can be reloaded
Memory Management¶
Context Memory Tracking¶
Each plugin context tracks memory usage:
// From ecmascript.c - es_mem_alloc()
static void *es_mem_alloc(void *udata, duk_size_t size) {
es_context_t *ec = udata;
void *p = malloc(size);
if(p != NULL) {
ec->ec_mem_active += arch_malloc_size(p);
ec->ec_mem_peak = MAX(ec->ec_mem_peak, ec->ec_mem_active);
}
return p;
}
Resource Lifecycle¶
Resources are categorized by lifecycle:
Permanent Resources¶
- Persist for the entire plugin lifetime
- Services, settings, persistent UI components
- Cleaned up only during plugin unload
Volatile Resources¶
- Temporary objects with shorter lifespans
- HTTP requests, temporary UI elements
- Automatically cleaned up during garbage collection
Garbage Collection¶
The ECMAScript runtime performs periodic garbage collection:
// From ecmascript.c - es_context_end()
void es_context_end(es_context_t *ec, int do_gc, duk_context *ctx) {
if(do_gc)
duk_gc(ec->ec_duk, 0);
// Additional cleanup logic
}
Threading Model¶
Context Threading¶
Each plugin context can use multiple threads: - Main Thread: Primary execution thread - Worker Threads: Background processing - Suspended Threads: Paused execution contexts
Thread Safety¶
// From ecmascript.c - es_context_begin()
duk_context *es_context_begin(es_context_t *ec) {
atomic_inc(&ec->ec_refcount);
hts_mutex_lock(&ec->ec_mutex);
// Thread-safe context access
}
Context Suspension¶
Plugins can suspend execution for asynchronous operations:
// From ecmascript.c - es_context_suspend()
void es_context_suspend(es_context_t *ec, duk_context *ctx,
duk_thread_state *state) {
duk_suspend(ctx, state);
hts_mutex_unlock(&ec->ec_mutex);
}
Development Lifecycle¶
Development Mode¶
Development plugins have special handling: - Hot Reload: Automatic reloading on file changes - Enhanced Debugging: Detailed execution traces - Relaxed Security: Bypass certain restrictions
Debug Features¶
// Debug mode enables additional logging
if(ec->ec_debug) {
es_debug(ec, "Module %s loaded from %s", id, path);
}
Reload Mechanism¶
// From plugins.c - plugins_reload_dev_plugin()
void plugins_reload_dev_plugin(void) {
// Reload all development plugins
// Preserve state where possible
// Update UI to reflect changes
}
Auto-Installation Lifecycle¶
File Type Detection¶
Plugins can be automatically installed based on file magic:
// From plugins.c - plugin_probe_for_autoinstall()
void plugin_probe_for_autoinstall(fa_handle_t *fh, const uint8_t *buf,
size_t len, const char *url) {
// Check file magic against plugin triggers
// Automatically install matching plugin
}
URI Pattern Matching¶
Plugins can be triggered by URI patterns:
// From plugins.c - plugin_check_prefix_for_autoinstall()
int plugin_check_prefix_for_autoinstall(const char *uri) {
// Check URI against registered prefixes
// Install plugin if pattern matches
}
Performance Considerations¶
Lazy Loading¶
Plugins are loaded on-demand to improve startup time: - Repository plugins loaded when browsing - Installed plugins loaded during startup - Development plugins loaded immediately
Context Reuse¶
ECMAScript contexts can be reused for efficiency: - Thread contexts cached between executions - Memory pools maintained for common operations - Compilation results cached when possible
Resource Optimization¶
- Memory Limits: Configurable per-plugin memory limits
- Execution Timeouts: Prevent runaway plugin execution
- Resource Pooling: Reuse common resources across plugins
Best Practices¶
Plugin Development¶
- Proper Initialization: Handle all initialization errors gracefully
- Resource Cleanup: Always clean up resources in error paths
- Error Handling: Provide meaningful error messages
- Memory Efficiency: Avoid memory leaks and excessive allocation
Lifecycle Management¶
- State Tracking: Maintain clear plugin state
- Dependency Management: Handle missing dependencies gracefully
- Version Compatibility: Test across Movian versions
- Performance Monitoring: Monitor resource usage
Debugging¶
- Enable Debug Mode: Use debug flags during development
- Log Strategically: Add logging at key lifecycle points
- Test Error Paths: Verify error handling works correctly
- Monitor Resources: Track memory and resource usage
This comprehensive lifecycle management ensures plugins integrate seamlessly with Movian while maintaining system stability and performance.
API Version Impact¶
The plugin lifecycle differs slightly based on API version:
API v2 (Modern)¶
// Immediate execution with CommonJS modules
var service = require('movian/service');
var page = require('movian/page');
service.create("My Service", "myservice:", "video", true);
new page.Route("myservice:start", function(page) {
// Page handler
});
Characteristics:
- Module system with require()
- Global Plugin and Core objects
- Native performance
- Modern ECMAScript features
API v1 (Legacy - Emulated)¶
// Global objects available immediately
var service = plugin.createService("My Service", "myservice:", "video", true);
plugin.addURI("myservice:start", function(page) {
// Page handler
});
Characteristics:
- Global showtime and plugin objects
- No module system
- Emulation layer overhead
- Deprecated (but still supported)
Recommendation: Use API v2 for new plugins. See API Versions and Migration Guide for more information.