use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
use crate::binder::SIBinder;
use crate::error::Result;
#[derive(Clone)]
struct RegisteredService {
name: String,
binder: SIBinder,
has_clients: bool,
registered: bool,
}
struct Inner {
services: HashMap<String, RegisteredService>,
}
pub struct LazyServiceRegistrar {
inner: Mutex<Inner>,
force_persist: AtomicBool,
}
impl LazyServiceRegistrar {
pub fn new() -> Self {
Self {
inner: Mutex::new(Inner {
services: HashMap::new(),
}),
force_persist: AtomicBool::new(false),
}
}
pub fn register_service(&self, name: &str, binder: SIBinder) -> Result<()> {
let mut inner = self.inner.lock().expect("lazy_service inner poisoned");
inner.services.insert(
name.to_string(),
RegisteredService {
name: name.to_string(),
binder,
has_clients: true, registered: true,
},
);
Ok(())
}
pub fn force_persist(&self, persist: bool) {
self.force_persist.store(persist, Ordering::Release);
}
pub fn is_force_persisted(&self) -> bool {
self.force_persist.load(Ordering::Acquire)
}
pub fn on_clients(&self, name: &str, has_clients: bool) -> bool {
let mut inner = self.inner.lock().expect("lazy_service inner poisoned");
if let Some(entry) = inner.services.get_mut(name) {
entry.has_clients = has_clients;
true
} else {
false
}
}
pub fn try_unregister(&self) -> bool {
if self.force_persist.load(Ordering::Acquire) {
return false;
}
let mut inner = self.inner.lock().expect("lazy_service inner poisoned");
let mut any_eligible = false;
for entry in inner.services.values_mut() {
if !entry.has_clients && entry.registered {
entry.registered = false;
any_eligible = true;
}
}
any_eligible
}
pub fn re_register(&self) {
let mut inner = self.inner.lock().expect("lazy_service inner poisoned");
for entry in inner.services.values_mut() {
if !entry.registered {
entry.registered = true;
entry.has_clients = true;
}
}
}
pub fn snapshot(&self) -> Vec<(String, bool, bool)> {
let inner = self.inner.lock().expect("lazy_service inner poisoned");
inner
.services
.values()
.map(|e| (e.name.clone(), e.has_clients, e.registered))
.collect()
}
pub fn registered_count(&self) -> usize {
let inner = self.inner.lock().expect("lazy_service inner poisoned");
inner.services.values().filter(|e| e.registered).count()
}
pub fn binder_for(&self, name: &str) -> Option<SIBinder> {
let inner = self.inner.lock().expect("lazy_service inner poisoned");
inner.services.get(name).map(|e| e.binder.clone())
}
}
impl Default for LazyServiceRegistrar {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::binder::Stability;
use crate::native::Binder;
use crate::{Interface, Parcel, Remotable, Result as RsResult, TransactionCode};
struct Dummy;
impl Remotable for Dummy {
fn descriptor() -> &'static str {
"test.lazy_service.Dummy"
}
fn on_transact(&self, _: TransactionCode, _: &mut Parcel, _: &mut Parcel) -> RsResult<()> {
Ok(())
}
fn on_dump(&self, _: &mut dyn std::io::Write, _: &[String]) -> RsResult<()> {
Ok(())
}
}
fn fresh_binder() -> SIBinder {
let b = Binder::new_with_stability(Dummy, Stability::Local);
Interface::as_binder(&b)
}
#[test]
fn register_records_entry() {
let reg = LazyServiceRegistrar::new();
reg.register_service("foo", fresh_binder()).unwrap();
let snap = reg.snapshot();
assert_eq!(snap.len(), 1);
assert_eq!(snap[0].0, "foo");
assert!(snap[0].2, "registered=true after register_service");
assert_eq!(reg.registered_count(), 1);
}
#[test]
fn try_unregister_only_flips_clientless_entries() {
let reg = LazyServiceRegistrar::new();
reg.register_service("a", fresh_binder()).unwrap();
reg.register_service("b", fresh_binder()).unwrap();
reg.on_clients("b", false);
assert!(reg.try_unregister(), "any eligible -> true");
let snap = reg.snapshot();
let a = snap.iter().find(|(n, _, _)| n == "a").unwrap();
let b = snap.iter().find(|(n, _, _)| n == "b").unwrap();
assert!(a.2, "`a` still has clients, stays registered");
assert!(!b.2, "`b` clientless and unregistered");
assert_eq!(reg.registered_count(), 1);
}
#[test]
fn force_persist_blocks_unregister() {
let reg = LazyServiceRegistrar::new();
reg.register_service("x", fresh_binder()).unwrap();
reg.on_clients("x", false);
reg.force_persist(true);
assert!(reg.is_force_persisted());
assert!(!reg.try_unregister(), "force_persist blocks");
let snap = reg.snapshot();
assert!(snap[0].2, "still registered");
}
#[test]
fn re_register_restores_state_and_resets_clients() {
let reg = LazyServiceRegistrar::new();
reg.register_service("z", fresh_binder()).unwrap();
reg.on_clients("z", false);
reg.try_unregister();
assert_eq!(reg.registered_count(), 0);
reg.re_register();
assert_eq!(reg.registered_count(), 1);
assert!(!reg.try_unregister());
}
#[test]
fn on_clients_for_unknown_service_is_silent() {
let reg = LazyServiceRegistrar::new();
assert!(!reg.on_clients("nope", true));
}
#[test]
fn register_same_name_replaces() {
let reg = LazyServiceRegistrar::new();
let first = fresh_binder();
let second = fresh_binder();
reg.register_service("dup", first.clone()).unwrap();
reg.register_service("dup", second.clone()).unwrap();
let got = reg.binder_for("dup").unwrap();
assert!(
std::sync::Arc::ptr_eq(got.as_arc(), second.as_arc()),
"second register_service wins"
);
}
}