| Crates.io | rsproperties |
| lib.rs | rsproperties |
| version | 0.2.1 |
| created_at | 2025-06-06 08:26:35.680237+00 |
| updated_at | 2025-06-14 12:39:17.292017+00 |
| description | Pure Rust implementation of Android's property system with cross-platform support, real-time monitoring, and Linux emulation |
| homepage | https://github.com/hiking90/rsproperties |
| repository | https://github.com/hiking90/rsproperties |
| max_upload_size | |
| id | 1702710 |
| size | 352,235 |
A pure Rust implementation of Android's property system, providing cross-platform access to Android system properties on both Linux and Android platforms.
This library supports Android versions from Android 9 (API level 28) to Android 16 (API level 36).
Add rsproperties to your Cargo.toml:
[dependencies]
rsproperties = "0.2"
# Optional features
[features]
builder = ["rsproperties/builder"] # Enable property database building
use rsproperties;
// Get property with default value (no initialization needed for default configuration)
let sdk_version: String = rsproperties::get_or("ro.build.version.sdk", "0".to_string());
println!("SDK Version: {}", sdk_version);
// Get property with type parsing and default fallback
let sdk_version: i32 = rsproperties::get_or("ro.build.version.sdk", 0);
let is_debuggable: bool = rsproperties::get_or("ro.debuggable", false);
// Get property with error handling
match rsproperties::get::<String>("ro.build.version.release") {
Ok(version) => println!("Android Version: {}", version),
Err(e) => eprintln!("Failed to get version: {}", e),
}
// Set property (requires property service to be running)
if let Err(e) = rsproperties::set("debug.my_app.enabled", "true") {
eprintln!("Failed to set property: {}", e);
}
use rsproperties;
let system_properties = rsproperties::system_properties();
// Wait for any property change
std::thread::spawn(|| {
if let Some(new_serial) = system_properties.wait_any() {
println!("Properties changed, new serial: {}", new_serial);
}
});
// Wait for specific property change
std::thread::spawn(|| {
if let Ok(Some(prop_index)) = system_properties.find("sys.boot_completed") {
println!("Waiting for boot completion...");
if let Some(_) = system_properties.wait(Some(&prop_index), None) {
println!("System boot completed!");
}
}
});
// Monitor multiple properties
let monitored_props = vec![
"sys.boot_completed",
"dev.bootcomplete",
"service.bootanim.exit"
];
for prop_name in monitored_props {
match system_properties.get_with_result(prop_name) {
Ok(value) => println!("{}: {}", prop_name, value),
Err(_) => println!("{}: <not set>", prop_name),
}
}
Setting properties requires a running property service (like rsproperties-service):
use rsproperties;
// Basic property setting
if let Err(e) = rsproperties::set("debug.my_app.enabled", "true") {
eprintln!("Failed to set property: {}", e);
}
// Set application configuration
rsproperties::set("debug.my_app.log_level", "verbose")?;
rsproperties::set("debug.my_app.port", "8080")?;
// Set system properties (may require elevated permissions)
rsproperties::set("sys.my_service.ready", "1")?;
// Set persistent properties (survive reboots on Android)
rsproperties::set("persist.my_app.config", "production")?;
On Android:
ro.* properties are read-only and cannot be modifiedOn Linux:
rsproperties-service to be running// Debug properties - usually writable by applications
rsproperties::set("debug.my_app.trace", "enabled")?;
rsproperties::set("debug.my_app.verbose", "true")?;
// Vendor properties - device-specific configuration
rsproperties::set("vendor.my_app.hw_config", "v2")?;
// Custom application properties
rsproperties::set("my.company.app.version", "1.2.3")?;
rsproperties::set("my.company.app.api_key", "abc123")?;
// System state properties
rsproperties::set("sys.my_service.status", "running")?;
rsproperties::set("sys.my_service.pid", "1234")?;
use rsproperties::{Result, Error};
fn handle_property_operation() -> Result<()> {
match rsproperties::set("debug.my_app.config", "value") {
Ok(_) => println!("Property set successfully"),
Err(e) => {
eprintln!("Failed to set property: {}", e);
// Error provides context and location information
}
}
Ok(())
}
// Batch property operations with error handling
fn set_app_config() -> Result<()> {
let properties = [
("debug.my_app.enabled", "true"),
("debug.my_app.log_level", "info"),
("debug.my_app.trace", "disabled"),
];
for (key, value) in &properties {
match rsproperties::set(key, value) {
Ok(_) => println!("Set {}: {}", key, value),
Err(e) => {
eprintln!("Failed to set {}: {}", key, e);
return Err(e);
}
}
}
Ok(())
}
Warning: Do not use custom configuration on Android devices. Custom configuration is only intended for Linux environments or development/testing purposes.
use rsproperties::PropertyConfig;
// Configure custom directories
let config = PropertyConfig {
properties_dir: Some("/custom/properties".into()),
socket_dir: Some("/custom/socket".into()),
};
rsproperties::init(config);
// Using the builder pattern
let config = PropertyConfig::builder()
.properties_dir("/my/properties")
.socket_dir("/my/socket")
.build();
rsproperties::init(config);
// Convenience methods
rsproperties::init(PropertyConfig::with_properties_dir("/my/props"));
/dev/__properties__rsproperties-service for full daemon functionalityPropertyConfig - Configuration for property system initializationPropertyConfig::builder() - Builder pattern for configurationPropertyConfig::with_properties_dir() - Create config with only properties directoryPropertyConfig::with_socket_dir() - Create config with only socket directoryPropertyConfig::with_both_dirs() - Create config with both directoriesinit(config) - Initialize the property systemget<T>(name) - Get property value parsed to specified type (returns Err if not found)get_or<T>(name, default) - Get property with default fallback (never fails)set<T>(name, value) - Set property value (requires property service)system_properties() - Get global SystemProperties instanceproperties_dir() - Get the configured properties directorySystemProperties::get_with_result(name) - Get property with error handlingSystemProperties::find(name) - Find property index by nameSystemProperties::wait_any() - Wait for any property changeSystemProperties::wait(index, timeout) - Wait for specific property changesocket_dir() - Get the configured socket directory for property serviceset_socket_dir() > PROPERTY_SERVICE_SOCKET_DIR env var > /dev/socketbuilder feature)SystemProperties::new_area(dir) - Create new property areaSystemProperties::add(name, value) - Add new propertySystemProperties::update(index, value) - Update existing propertySystemProperties::set(name, value) - Set property (create or update)load_properties_from_file() - Load properties from build.prop filesAll operations are thread-safe and can be used concurrently:
use std::thread;
// Multiple threads can safely access properties
let handles: Vec<_> = (0..10).map(|i| {
thread::spawn(move || {
let prop_name = format!("debug.thread.{}", i);
let value: String = rsproperties::get_or(&prop_name, "default".to_string());
println!("Thread {}: {} = {}", i, prop_name, value);
})
}).collect();
for handle in handles {
handle.join().unwrap();
}
builder feature)#[cfg(feature = "builder")]
use rsproperties::{load_properties_from_file, SystemProperties};
use std::collections::HashMap;
use std::path::Path;
// Load properties from Android build.prop files
let mut properties = HashMap::new();
load_properties_from_file(
Path::new("system_build.prop"),
None,
"u:r:init:s0",
&mut properties
)?;
// Create a system properties area for testing or service
let mut system_properties = SystemProperties::new_area(Path::new("./test_props"))?;
// Add loaded properties to the area
for (key, value) in properties {
system_properties.add(&key, &value)?;
}
// Now properties can be read normally
let sdk_version: i32 = rsproperties::get_or("ro.build.version.sdk", 0);
The library exposes Android-compatible constants:
use rsproperties::{PROP_VALUE_MAX, PROP_DIRNAME};
// Maximum property value length (92 bytes for most properties)
assert_eq!(PROP_VALUE_MAX, 92);
// Default Android properties directory
assert_eq!(PROP_DIRNAME, "/dev/__properties__");
The crate includes Android-compatible command-line tools:
getprop.rs - Android-compatible property getter with support for custom directoriessetprop.rs - Android-compatible property setter with validation and error handlingRun examples with:
# Get a property with default value
cargo run --example getprop ro.build.version.sdk 0
# Set a property
cargo run --example setprop debug.my_app.test true
rsproperties-service - Full async property service daemon for Linux environments# Build the library
cargo build
# Build with all features
cargo build --all-features
# Run tests
cargo test
# Build documentation
cargo doc --open
Licensed under the Apache License, Version 2.0. See LICENSE for details.
Contributions are welcome! Please ensure:
cargo testcargo fmtcargo clippy --all-targets --all-featuresThis implementation is based on Android's property system and maintains compatibility with Android's property semantics and behavior.