Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 08db397a authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "usb4-lib" into main

* changes:
  libs/usb4: Refactor UserId and tests
  Add //libs/usb4 implementation from vendor/google
parents 4e47859d 22d025b6
Loading
Loading
Loading
Loading

libs/usb4/Android.bp

0 → 100644
+67 −0
Original line number Diff line number Diff line
// Copyright (C) 2025 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package {
    default_applicable_licenses: ["Android-Apache-2.0"],
    default_team: "trendy_team_desktop_connectivity",
}

rust_library {
    name: "libusb4_policies",
    crate_name: "usb4_policies",
    crate_root: "src/policy/lib.rs",
    rustlibs: [
        "libuevent-framework",
        "libanyhow",
        "liblogger",
        "liblog_rust",
        "libkobject_uevent",
        "libtokio",
    ],
    host_supported: true,
}

rust_test_host {
    name: "usb4_policies_test",
    crate_name: "usb4_policies_test",
    srcs: ["tests/lib.rs"],
    rustlibs: [
        "libusb4_policies",
        "libtempfile",
        "libkobject_uevent",
        "libtokio",
        "liblogger",
        "liblog_rust",
        "libuevent-framework",
        "libenv_logger",
    ],
    test_suites: ["general-tests"],
    auto_gen_config: true,
    test_options: {
        unit_test: true,
    },
}

rust_ffi_shared {
    name: "libusb4_policies_jni",
    crate_name: "usb4_policies_jni",
    srcs: ["src/bindings/lib.rs"],
    rustlibs: [
        "libonce_cell",
        "libjni",
        "liblogger",
        "liblog_rust",
        "libusb4_policies",
    ],
}

libs/usb4/OWNERS

0 → 100644
+4 −0
Original line number Diff line number Diff line
include /services/usb/OWNERS

abhishekpandit@google.com
danielgeorgem@google.com
+39 −0
Original line number Diff line number Diff line
// Copyright (C) 2025 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

rust_defaults {
    name: "libuevent-framework_defaults",
    rustlibs: [
        "liblogger",
        "liblog_rust",
        "libanyhow",
        "libnix",
        "libkobject_uevent",
        "libtokio",
    ],
    proc_macros: [
        "libasync_trait",
    ],
}

rust_library {
    name: "libuevent-framework",
    crate_name: "uevent",
    crate_root: "src/lib.rs",
    defaults: [
        "libuevent-framework_defaults",
    ],
    host_supported: true,
    vendor_available: true,
}
+17 −0
Original line number Diff line number Diff line
// Copyright (C) 2025 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Uevent utils

pub mod netlink;
+137 −0
Original line number Diff line number Diff line
// Copyright (C) 2025 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Read kernel Uevents through netlink
//!

use anyhow::{anyhow, bail, Context, Result};
use kobject_uevent;
use nix::poll;
use nix::sys::socket;
use tokio::io::unix::AsyncFd;

use async_trait::async_trait;
use std::os::fd::{AsFd, AsRawFd, OwnedFd};

// ueventd uses buffer size of 16M by default - but we go with 1MB buffer.
// If the consumer of this library is really slow to dequeue packets we risk
// buffer overflow and missing events. Since USB HAL is the only consumer which
// is relatively lightweight and should be dequeuing events at a faster pace the
// 1MB should not be a concern here.
const UEVENT_BUF_SIZE: usize = 1024 * 1024;

fn create_socket() -> Result<OwnedFd> {
    let addr = socket::NetlinkAddr::new(0, 0xffffffff);
    let s = socket::socket(
        socket::AddressFamily::Netlink,
        socket::SockType::Datagram,
        socket::SockFlag::SOCK_NONBLOCK | socket::SockFlag::SOCK_CLOEXEC,
        socket::SockProtocol::NetlinkKObjectUEvent,
    )?;
    socket::setsockopt(&s, socket::sockopt::RcvBuf, &UEVENT_BUF_SIZE)?;
    socket::setsockopt(&s, socket::sockopt::PassCred, &true)?;
    socket::bind(s.as_raw_fd(), &addr)?;

    Ok(s)
}

/// Socket for listening on KObject Uevents
pub struct NetlinkKObjectUEventSocket {
    fd: OwnedFd,
}

impl NetlinkKObjectUEventSocket {
    /// Create a listener on NetLink for kernel events.
    pub fn create() -> Result<Self> {
        let fd = create_socket()?;
        Ok(Self { fd })
    }

    /// Wait for one or more kernel events to appear on the NetLink
    fn wait(&self) -> Result<()> {
        loop {
            let mut fds = [poll::PollFd::new(self.fd.as_fd(), poll::PollFlags::POLLIN)];
            // TODO - creating epoll fd in create() and using epoll_wait() might be faster than poll()?
            let nr = poll::poll(&mut fds, poll::PollTimeout::NONE)?;
            // TODO - check will this condition ever occur - may be because of spurious wakeup?
            if nr == 0 {
                continue;
            }
            // Fetch returned event which caused this wakeup.
            let revents = fds[0].revents().context("Invalid revents found")?;
            if revents.contains(poll::PollFlags::POLLIN) {
                break;
            }
        }
        Ok(())
    }

    /// Wait and read uevent.
    pub fn read(&self) -> Result<kobject_uevent::UEvent> {
        self.wait()?;
        let mut buffer = [0u8; UEVENT_BUF_SIZE];
        // TODO - use recvmsg and validate credentials
        let count = socket::recv(self.fd.as_raw_fd(), &mut buffer, socket::MsgFlags::empty())?;
        if count == 0 {
            bail!("Netlink socket recv return 0 bytes");
        }
        kobject_uevent::UEvent::from_netlink_packet(&buffer[0..count]).map_err(|e| anyhow!("{e}"))
    }
}

/// Asynchronous UEvent socket operations.
#[async_trait]
pub trait AsyncUEventSocket: Send + Sync {
    /// Waits for data from netlink socket and returns parsed uevent from read data.
    async fn read(&self) -> Result<kobject_uevent::UEvent>;
}

/// Asynchronous implementation of uevent socket listener.
pub struct AsyncNetlinkKObjectUEventSocket {
    afd: AsyncFd<OwnedFd>,
}

impl AsyncNetlinkKObjectUEventSocket {
    /// Create async listener on netlink socket for uevents.
    pub fn create() -> Result<Self> {
        let fd = create_socket()?;
        let afd = AsyncFd::new(fd)?;

        Ok(Self { afd })
    }
}
#[async_trait]
impl AsyncUEventSocket for AsyncNetlinkKObjectUEventSocket {
    /// Waits for data from netlink socket and returns parsed uevent from read data.
    async fn read(&self) -> Result<kobject_uevent::UEvent> {
        let mut buffer = [0u8; UEVENT_BUF_SIZE];

        loop {
            let mut guard = self.afd.readable().await?;

            if let Ok(result) = guard.try_io(|inner| {
                Ok(socket::recv(inner.as_raw_fd(), &mut buffer, socket::MsgFlags::empty())?)
            }) {
                let bytes_read = result?;

                if bytes_read == 0 {
                    bail!("Netlink socket read returned 0 bytes");
                }

                return kobject_uevent::UEvent::from_netlink_packet(&buffer[0..bytes_read])
                    .map_err(|e| anyhow!("{e}"));
            }
        }
    }
}
Loading