blob: c0b52aef990463cb3309235ac7b8aa213e695c9b [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::{builtin::capability::BuiltinCapability, capability::*},
anyhow::Error,
async_trait::async_trait,
cm_rust::CapabilityName,
fidl_fuchsia_kernel as fkernel,
fuchsia_runtime::job_default,
fuchsia_zircon as zx,
futures::prelude::*,
lazy_static::lazy_static,
std::sync::Arc,
};
lazy_static! {
pub static ref ROOT_JOB_CAPABILITY_NAME: CapabilityName = "fuchsia.kernel.RootJob".into();
pub static ref ROOT_JOB_FOR_INSPECT_CAPABILITY_NAME: CapabilityName =
"fuchsia.kernel.RootJobForInspect".into();
}
/// An implementation of the `fuchsia.kernel.RootJob` protocol.
pub struct RootJob {
capability_name: &'static CapabilityName,
rights: zx::Rights,
}
impl RootJob {
pub fn new(capability_name: &'static CapabilityName, rights: zx::Rights) -> Arc<Self> {
Arc::new(Self { capability_name, rights })
}
}
#[async_trait]
impl BuiltinCapability for RootJob {
const NAME: &'static str = "RootJob";
type Marker = fkernel::RootJobMarker;
async fn serve(
self: Arc<Self>,
mut stream: fkernel::RootJobRequestStream,
) -> Result<(), Error> {
let job = job_default();
while let Some(fkernel::RootJobRequest::Get { responder }) = stream.try_next().await? {
responder.send(job.duplicate(self.rights)?)?;
}
Ok(())
}
fn matches_routed_capability(&self, capability: &InternalCapability) -> bool {
capability.matches_protocol(self.capability_name)
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::model::hooks::{Event, EventPayload, Hooks},
fidl::endpoints::ClientEnd,
fuchsia_async as fasync,
fuchsia_zircon::AsHandleRef,
fuchsia_zircon_sys as sys,
futures::lock::Mutex,
moniker::AbsoluteMoniker,
std::path::PathBuf,
};
#[fasync::run_singlethreaded(test)]
async fn has_correct_rights() -> Result<(), Error> {
let root_job = RootJob::new(&ROOT_JOB_CAPABILITY_NAME, zx::Rights::TRANSFER);
let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<fkernel::RootJobMarker>()?;
fasync::Task::local(
root_job.serve(stream).unwrap_or_else(|err| panic!("Error serving root job: {}", err)),
)
.detach();
let root_job = proxy.get().await?;
let info = zx::Handle::from(root_job).basic_info()?;
assert_eq!(info.rights, zx::Rights::TRANSFER);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn can_connect() -> Result<(), Error> {
let root_job = RootJob::new(&ROOT_JOB_CAPABILITY_NAME, zx::Rights::SAME_RIGHTS);
let hooks = Hooks::new(None);
hooks.install(root_job.hooks()).await;
let provider = Arc::new(Mutex::new(None));
let source = CapabilitySource::Builtin {
capability: InternalCapability::Protocol(ROOT_JOB_CAPABILITY_NAME.clone()),
};
let event = Event::new_for_test(
AbsoluteMoniker::root(),
"fuchsia-pkg://root",
Ok(EventPayload::CapabilityRouted { source, capability_provider: provider.clone() }),
);
hooks.dispatch(&event).await?;
let (client, mut server) = zx::Channel::create()?;
if let Some(provider) = provider.lock().await.take() {
provider.open(0, 0, PathBuf::new(), &mut server).await?;
}
let client = ClientEnd::<fkernel::RootJobMarker>::new(client)
.into_proxy()
.expect("Failed to create proxy");
let handle = client.get().await?;
assert_ne!(handle.raw_handle(), sys::ZX_HANDLE_INVALID);
Ok(())
}
}