drivers/android/binder/context.rs

Source file repositories/reference/linux-study-clean/drivers/android/binder/context.rs

File Facts

System
Linux kernel
Corpus path
drivers/android/binder/context.rs
Extension
.rs
Size
5505 bytes
Lines
176
Domain
Driver Families
Bucket
drivers/android
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct Manager {
    node: Option<NodeRef>,
    uid: Option<Kuid>,
    all_procs: KVVec<Arc<Process>>,
}

/// There is one context per binder file (/dev/binder, /dev/hwbinder, etc)
#[pin_data]
pub(crate) struct Context {
    #[pin]
    manager: Mutex<Manager>,
    pub(crate) name: CString,
}

impl Context {
    pub(crate) fn new(name: &CStr) -> Result<Arc<Self>> {
        let name = CString::try_from(name)?;
        let ctx = Arc::pin_init(
            try_pin_init!(Context {
                name,
                manager <- kernel::new_mutex!(Manager {
                    all_procs: KVVec::new(),
                    node: None,
                    uid: None,
                }, "Context::manager"),
            }),
            GFP_KERNEL,
        )?;

        CONTEXTS.lock().contexts.push(ctx.clone(), GFP_KERNEL)?;

        Ok(ctx)
    }

    /// Called when the file for this context is unlinked.
    ///
    /// No-op if called twice.
    pub(crate) fn deregister(self: &Arc<Self>) {
        // Safe removal using retain
        CONTEXTS.lock().contexts.retain(|c| !Arc::ptr_eq(c, self));
    }

    pub(crate) fn register_process(self: &Arc<Self>, proc: Arc<Process>) -> Result {
        if !Arc::ptr_eq(self, &proc.ctx) {
            pr_err!("Context::register_process called on the wrong context.");
            return Err(EINVAL);
        }
        self.manager.lock().all_procs.push(proc, GFP_KERNEL)?;
        Ok(())
    }

    pub(crate) fn deregister_process(self: &Arc<Self>, proc: &Arc<Process>) {
        if !Arc::ptr_eq(self, &proc.ctx) {
            pr_err!("Context::deregister_process called on the wrong context.");
            return;
        }
        let mut manager = self.manager.lock();
        manager.all_procs.retain(|p| !Arc::ptr_eq(p, proc));

        // Shrink the vector if it has significant unused capacity to avoid memory waste,
        // but use a conservative strategy to prevent shrink-then-regrow oscillation.
        // Only shrink when length drops below 1/4 of capacity, and shrink to twice the length.
        let len = manager.all_procs.len();
        let cap = manager.all_procs.capacity();
        if len < cap / 4 {
            // Shrink to twice the current length. Ignore allocation failures since this
            // is just an optimization; the vector remains valid even if shrinking fails.
            let _ = manager.all_procs.shrink_to(len * 2, GFP_KERNEL);
        }
    }

    pub(crate) fn set_manager_node(&self, node_ref: NodeRef) -> Result {
        let mut manager = self.manager.lock();
        if manager.node.is_some() {
            pr_warn!("BINDER_SET_CONTEXT_MGR already set");
            return Err(EBUSY);
        }
        security::binder_set_context_mgr(&node_ref.node.owner.cred)?;

        // If the context manager has been set before, ensure that we use the same euid.
        let caller_uid = Kuid::current_euid();
        if let Some(ref uid) = manager.uid {
            if *uid != caller_uid {
                return Err(EPERM);
            }
        }

        manager.node = Some(node_ref);
        manager.uid = Some(caller_uid);
        Ok(())

Annotation

Implementation Notes