Skip to main content

starnix_kernel_runner/
serve_protocols.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::Container;
6use anyhow::{Context as _, Error};
7use fidl::endpoints::{ControlHandle, RequestStream, ServerEnd};
8use fuchsia_async::{
9    DurationExt, {self as fasync},
10};
11use futures::channel::oneshot;
12use futures::{
13    AsyncReadExt, AsyncWriteExt, Future, FutureExt, StreamExt, TryFutureExt, TryStreamExt, pin_mut,
14    select,
15};
16use starnix_core::execution::{create_init_child_process, execute_task_with_prerun_result};
17use starnix_core::fs::devpts::create_main_and_replica;
18use starnix_core::fs::fuchsia::create_fuchsia_pipe;
19use starnix_core::task::dynamic_thread_spawner::SpawnRequestBuilder;
20use starnix_core::task::{CurrentTask, ExitStatus, Kernel, LockedAndTask, ProcessEntryRef};
21use starnix_core::vfs::buffers::{VecInputBuffer, VecOutputBuffer};
22use starnix_core::vfs::file_server::serve_file_at;
23use starnix_core::vfs::socket::VsockSocket;
24use starnix_core::vfs::{FdFlags, FileHandle};
25use starnix_logging::{log_error, log_warn};
26use starnix_modules_framebuffer::Framebuffer;
27use starnix_sync::{Locked, Unlocked};
28use starnix_task_command::TaskCommand;
29use starnix_uapi::auth::Credentials;
30use starnix_uapi::errors::Errno;
31use starnix_uapi::open_flags::OpenFlags;
32use starnix_uapi::signals::UncheckedSignal;
33use starnix_uapi::{errno, error, uapi};
34use std::ffi::CString;
35use std::ops::DerefMut;
36use {
37    fidl_fuchsia_component_runner as frunner, fidl_fuchsia_element as felement,
38    fidl_fuchsia_io as fio, fidl_fuchsia_memory_attribution as fattribution,
39    fidl_fuchsia_posix as fposix, fidl_fuchsia_starnix_binder as fbinder,
40    fidl_fuchsia_starnix_container as fstarcontainer,
41};
42
43use super::start_component;
44
45pub fn expose_root(
46    locked: &mut Locked<Unlocked>,
47    system_task: &CurrentTask,
48    server_end: ServerEnd<fio::DirectoryMarker>,
49) -> Result<(), Error> {
50    let root_file = system_task.open_file(locked, "/".into(), OpenFlags::RDONLY)?;
51    serve_file_at(server_end.into_channel().into(), system_task, &root_file, Credentials::root())?;
52    Ok(())
53}
54
55pub async fn serve_component_runner(
56    request_stream: frunner::ComponentRunnerRequestStream,
57    system_task: &CurrentTask,
58) -> Result<(), Error> {
59    request_stream
60        .try_for_each_concurrent(None, |event| async {
61            match event {
62                frunner::ComponentRunnerRequest::Start { start_info, controller, .. } => {
63                    if let Err(e) = start_component(start_info, controller, system_task).await {
64                        log_error!("failed to start component: {:?}", e);
65                    }
66                }
67                frunner::ComponentRunnerRequest::_UnknownMethod { ordinal, .. } => {
68                    log_warn!("Unknown ComponentRunner request: {ordinal}");
69                }
70            }
71            Ok(())
72        })
73        .await
74        .map_err(Error::from)
75}
76
77fn to_winsize(window_size: Option<fstarcontainer::ConsoleWindowSize>) -> uapi::winsize {
78    window_size
79        .map(|window_size| uapi::winsize {
80            ws_row: window_size.rows,
81            ws_col: window_size.cols,
82            ws_xpixel: window_size.x_pixels,
83            ws_ypixel: window_size.y_pixels,
84        })
85        .unwrap_or(uapi::winsize::default())
86}
87
88async fn spawn_console(
89    kernel: &Kernel,
90    payload: fstarcontainer::ControllerSpawnConsoleRequest,
91) -> Result<Result<u8, fstarcontainer::SpawnConsoleError>, Error> {
92    if let (Some(console_in), Some(console_out), Some(binary_path)) =
93        (payload.console_in, payload.console_out, payload.binary_path)
94    {
95        let binary_path = CString::new(binary_path)?;
96        let argv = payload
97            .argv
98            .unwrap_or(vec![])
99            .into_iter()
100            .map(CString::new)
101            .collect::<Result<Vec<_>, _>>()?;
102        let environ = payload
103            .environ
104            .unwrap_or(vec![])
105            .into_iter()
106            .map(CString::new)
107            .collect::<Result<Vec<_>, _>>()?;
108        let window_size = to_winsize(payload.window_size);
109        let current_task = create_init_child_process(
110            kernel.kthreads.unlocked_for_async().deref_mut(),
111            &kernel.weak_self.upgrade().expect("Kernel must still be alive"),
112            TaskCommand::new(binary_path.as_bytes()),
113            Credentials::with_ids(0, 0),
114            None,
115        )?;
116        let (sender, receiver) = oneshot::channel();
117        let pty = execute_task_with_prerun_result(
118            kernel.kthreads.unlocked_for_async().deref_mut(),
119            current_task,
120            move |locked, current_task| {
121                let executable = current_task.open_file(
122                    locked,
123                    binary_path.as_bytes().into(),
124                    OpenFlags::RDONLY,
125                )?;
126                current_task.exec(locked, executable, binary_path, argv, environ)?;
127                let (pty, pts) = create_main_and_replica(locked, &current_task, window_size)?;
128                let fd_flags = FdFlags::empty();
129                assert_eq!(0, current_task.add_file(locked, pts.clone(), fd_flags)?.raw());
130                assert_eq!(1, current_task.add_file(locked, pts.clone(), fd_flags)?.raw());
131                assert_eq!(2, current_task.add_file(locked, pts, fd_flags)?.raw());
132                Ok(pty)
133            },
134            move |result| {
135                let _ = match result {
136                    Ok(ExitStatus::Exit(exit_code)) => sender.send(Ok(exit_code)),
137                    _ => sender.send(Err(fstarcontainer::SpawnConsoleError::Canceled)),
138                };
139            },
140            None,
141        )?;
142        let _ = forward_to_pty(kernel, console_in, console_out, pty).map_err(|e| {
143            log_error!("failed to forward to terminal {:?}", e);
144        });
145
146        Ok(receiver.await?)
147    } else {
148        Ok(Err(fstarcontainer::SpawnConsoleError::InvalidArgs))
149    }
150}
151
152pub async fn serve_container_controller(
153    request_stream: fstarcontainer::ControllerRequestStream,
154    system_task: &CurrentTask,
155) -> Result<(), Error> {
156    request_stream
157        .map_err(Error::from)
158        .try_for_each_concurrent(None, |event| async {
159            match event {
160                fstarcontainer::ControllerRequest::VsockConnect {
161                    payload:
162                        fstarcontainer::ControllerVsockConnectRequest { port, bridge_socket, .. },
163                    ..
164                } => {
165                    let Some(port) = port else {
166                        log_warn!("vsock connection missing port");
167                        return Ok(());
168                    };
169                    let Some(bridge_socket) = bridge_socket else {
170                        log_warn!("vsock connection missing bridge_socket");
171                        return Ok(());
172                    };
173                    connect_to_vsock(port, bridge_socket, system_task).await.unwrap_or_else(|e| {
174                        log_error!("failed to connect to vsock {:?}", e);
175                    });
176                }
177                fstarcontainer::ControllerRequest::SpawnConsole { payload, responder } => {
178                    responder.send(spawn_console(system_task.kernel(), payload).await?)?;
179                }
180                fstarcontainer::ControllerRequest::GetVmoReferences { payload, responder } => {
181                    if let Some(koid) = payload.koid {
182                        let thread_groups = system_task
183                            .kernel()
184                            .pids
185                            .read()
186                            .get_thread_groups()
187                            .collect::<Vec<_>>();
188                        let mut results = vec![];
189                        for thread_group in thread_groups {
190                            if let Some(leader) =
191                                system_task.get_task(thread_group.leader).upgrade()
192                            {
193                                let fds = leader.files.get_all_fds();
194                                for fd in fds {
195                                    if let Ok(file) = leader.files.get(fd) {
196                                        if let Ok(memory) = file.get_memory(
197                                            system_task
198                                                .kernel()
199                                                .kthreads
200                                                .unlocked_for_async()
201                                                .deref_mut(),
202                                            system_task,
203                                            None,
204                                            starnix_core::mm::ProtectionFlags::READ,
205                                        ) {
206                                            let memory_koid = memory
207                                                .info()
208                                                .expect("Failed to get memory info")
209                                                .koid;
210                                            if memory_koid.raw_koid() == koid {
211                                                let process_name = thread_group
212                                                    .process
213                                                    .get_name()
214                                                    .unwrap_or_default();
215                                                results.push(fstarcontainer::VmoReference {
216                                                    process_name: Some(process_name.to_string()),
217                                                    pid: Some(leader.get_pid() as u64),
218                                                    fd: Some(fd.raw()),
219                                                    koid: Some(koid),
220                                                    ..Default::default()
221                                                });
222                                            }
223                                        }
224                                    }
225                                }
226                            }
227                        }
228                        let _ =
229                            responder.send(&fstarcontainer::ControllerGetVmoReferencesResponse {
230                                references: Some(results),
231                                ..Default::default()
232                            });
233                    }
234                }
235                fstarcontainer::ControllerRequest::GetJobHandle { responder } => {
236                    let _result = responder.send(fstarcontainer::ControllerGetJobHandleResponse {
237                        job: Some(
238                            fuchsia_runtime::job_default()
239                                .duplicate(zx::Rights::SAME_RIGHTS)
240                                .expect("Failed to dup handle"),
241                        ),
242                        ..Default::default()
243                    });
244                }
245                fstarcontainer::ControllerRequest::SendSignal {
246                    payload:
247                        fstarcontainer::ControllerSendSignalRequest {
248                            pid: Some(pid),
249                            signal: Some(signal),
250                            ..
251                        },
252                    responder,
253                } => {
254                    let pids = system_task.kernel().pids.read();
255                    if let Some(ProcessEntryRef::Process(target_thread_group)) =
256                        pids.get_process(pid)
257                    {
258                        #[allow(
259                            clippy::undocumented_unsafe_blocks,
260                            reason = "Force documented unsafe blocks in Starnix"
261                        )]
262                        match unsafe {
263                            target_thread_group.send_signal_unchecked_debug(
264                                system_task,
265                                UncheckedSignal::new(signal),
266                            )
267                        } {
268                            Ok(_) => {
269                                let _result = responder.send(Ok(()));
270                            }
271                            Err(_) => {
272                                let _result =
273                                    responder.send(Err(fstarcontainer::SignalError::InvalidSignal));
274                            }
275                        };
276                    } else {
277                        let _result =
278                            responder.send(Err(fstarcontainer::SignalError::InvalidTarget));
279                    };
280                }
281                // The request did not contain both a signal and a target pid.
282                fstarcontainer::ControllerRequest::SendSignal { responder, .. } => {
283                    log_error!("malformed SendSignal request");
284                    let _result = responder.send(Err(fstarcontainer::SignalError::InvalidTarget));
285                }
286                fstarcontainer::ControllerRequest::SetSyscallLogFilter { payload, responder } => {
287                    if let Some(process_name) = payload.process_name {
288                        system_task.kernel().add_syscall_log_filter(&process_name);
289                        let _ = responder.send(Ok(()));
290                    } else {
291                        let _ = responder.send(Err(
292                            fstarcontainer::SetSyscallLogFilterError::MissingProcessName,
293                        ));
294                    }
295                }
296                fstarcontainer::ControllerRequest::ClearSyscallLogFilters { responder } => {
297                    system_task.kernel().clear_syscall_log_filters();
298                    let _ = responder.send();
299                }
300                fstarcontainer::ControllerRequest::_UnknownMethod { .. } => (),
301            }
302            Ok(())
303        })
304        .await
305}
306
307async fn connect_to_vsock(
308    port: u32,
309    bridge_socket: fidl::Socket,
310    system_task: &CurrentTask,
311) -> Result<(), Error> {
312    let socket = loop {
313        if let Ok(socket) = system_task.kernel().default_abstract_vsock_namespace.lookup(&port) {
314            break socket;
315        };
316        fasync::Timer::new(fasync::MonotonicDuration::from_millis(100).after_now()).await;
317    };
318
319    let pipe = create_fuchsia_pipe(
320        system_task.kernel().kthreads.unlocked_for_async().deref_mut(),
321        system_task,
322        bridge_socket,
323        OpenFlags::RDWR | OpenFlags::NONBLOCK,
324    )?;
325    socket.downcast_socket::<VsockSocket>().unwrap().remote_connection(
326        system_task.kernel().kthreads.unlocked_for_async().deref_mut(),
327        &socket,
328        system_task,
329        pipe,
330    )?;
331
332    Ok(())
333}
334
335fn forward_to_pty(
336    kernel: &Kernel,
337    console_in: fidl::Socket,
338    console_out: fidl::Socket,
339    pty: FileHandle,
340) -> Result<(), Error> {
341    // Matches fuchsia.io.Transfer capacity, somewhat arbitrarily.
342    const BUFFER_CAPACITY: usize = 8192;
343
344    let mut rx = fuchsia_async::Socket::from_socket(console_in);
345    let mut tx = fuchsia_async::Socket::from_socket(console_out);
346    let pty_sink = pty.clone();
347    let closure = async move |locked_and_task: LockedAndTask<'_>| {
348        let _result: Result<(), Error> = (async || {
349            let mut buffer = vec![0u8; BUFFER_CAPACITY];
350            loop {
351                let bytes = rx.read(&mut buffer[..]).await?;
352                if bytes == 0 {
353                    return Ok(());
354                }
355                pty_sink.write(
356                    &mut locked_and_task.unlocked(),
357                    locked_and_task.current_task(),
358                    &mut VecInputBuffer::new(&buffer[..bytes]),
359                )?;
360            }
361        })()
362        .await;
363    };
364    let req = SpawnRequestBuilder::new()
365        .with_debug_name("forward-to-pty-in")
366        .with_async_closure(closure)
367        .build();
368    kernel.kthreads.spawner().spawn_from_request(req);
369
370    let pty_source = pty;
371    let closure = move |locked: &mut Locked<Unlocked>, current_task: &CurrentTask| {
372        let _result: Result<(), Error> =
373            fasync::LocalExecutor::default().run_singlethreaded(async {
374                let mut buffer = VecOutputBuffer::new(BUFFER_CAPACITY);
375                loop {
376                    buffer.reset();
377                    let bytes = pty_source.read(locked, current_task, &mut buffer)?;
378                    if bytes == 0 {
379                        return Ok(());
380                    }
381                    tx.write_all(buffer.data()).await?;
382                }
383            });
384    };
385    let req = SpawnRequestBuilder::new()
386        .with_debug_name("forward-to-pty-out")
387        .with_sync_closure(closure)
388        .build();
389    kernel.kthreads.spawner().spawn_from_request(req);
390
391    Ok(())
392}
393
394pub async fn serve_graphical_presenter(
395    mut request_stream: felement::GraphicalPresenterRequestStream,
396    kernel: &Kernel,
397) -> Result<(), Error> {
398    while let Some(request) = request_stream.next().await {
399        match request.context("reading graphical presenter request")? {
400            felement::GraphicalPresenterRequest::PresentView {
401                view_spec,
402                annotation_controller: _,
403                view_controller_request: _,
404                responder,
405            } => match view_spec.viewport_creation_token {
406                Some(token) => {
407                    let fb = Framebuffer::get(kernel).context("getting framebuffer from kernel")?;
408                    fb.present_view(token);
409                    let _ = responder.send(Ok(()));
410                }
411                None => {
412                    let _ = responder.send(Err(felement::PresentViewError::InvalidArgs));
413                }
414            },
415        }
416    }
417    Ok(())
418}
419
420/// Serves the memory attribution provider for the Kernel ELF component.
421pub fn serve_memory_attribution_provider_elfkernel(
422    mut request_stream: fattribution::ProviderRequestStream,
423    container: &Container,
424) -> impl Future<Output = Result<(), Error>> {
425    let observer = container.new_memory_attribution_observer(request_stream.control_handle());
426    async move {
427        while let Some(event) = request_stream.try_next().await? {
428            match event {
429                fattribution::ProviderRequest::Get { responder } => {
430                    observer.next(responder);
431                }
432                fattribution::ProviderRequest::_UnknownMethod {
433                    ordinal, control_handle, ..
434                } => {
435                    log_error!("Invalid request to AttributionProvider: {ordinal}");
436                    control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
437                }
438            }
439        }
440        Ok(())
441    }
442}
443
444/// Serves the memory attribution provider for the Container component.
445pub fn serve_memory_attribution_provider_container(
446    mut request_stream: fattribution::ProviderRequestStream,
447    kernel: &Kernel,
448) -> impl Future<Output = ()> + use<> {
449    let observer = kernel.new_memory_attribution_observer(request_stream.control_handle());
450    async move {
451        while let Some(event) = request_stream
452            .try_next()
453            .await
454            .inspect_err(|err| {
455                log_warn!("Error while serving container memory attribution: {:?}", err)
456            })
457            .ok()
458            .flatten()
459        {
460            match event {
461                fattribution::ProviderRequest::Get { responder } => {
462                    observer.next(responder);
463                }
464                fattribution::ProviderRequest::_UnknownMethod {
465                    ordinal, control_handle, ..
466                } => {
467                    log_error!("Invalid request to AttributionProvider: {ordinal}");
468                    control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
469                }
470            }
471        }
472    }
473}
474
475async fn select_first<O>(f1: impl Future<Output = O>, f2: impl Future<Output = O>) -> O {
476    let f1 = f1.fuse();
477    let f2 = f2.fuse();
478    pin_mut!(f1, f2);
479    select! {
480        f1 = f1 => f1,
481        f2 = f2 => f2,
482    }
483}
484
485/// Serve the LutexController protocol.
486pub async fn serve_lutex_controller(
487    request_stream: fbinder::LutexControllerRequestStream,
488    current_task: &CurrentTask,
489) -> Result<(), Error> {
490    let kernel = current_task.kernel();
491    request_stream
492        .map_err(Error::from)
493        .try_for_each_concurrent(None, |event| async move {
494            match event {
495                fbinder::LutexControllerRequest::WaitBitset { payload, responder } => {
496                    let deadline_and_receiver = (|| {
497                        let mut unlocked = kernel.kthreads.unlocked_for_async();
498                        let vmo = payload.vmo.ok_or_else(|| errno!(EINVAL))?;
499                        let offset = payload.offset.ok_or_else(|| errno!(EINVAL))?;
500                        let value = payload.value.ok_or_else(|| errno!(EINVAL))?;
501                        let mask = payload.mask.unwrap_or(u32::MAX);
502                        let deadline = payload.deadline.map(zx::MonotonicInstant::from_nanos);
503                        kernel
504                            .shared_futexes
505                            .external_wait(&mut unlocked, vmo.into(), offset, value, mask)
506                            .map(|(event, receiver)| (deadline, event, receiver))
507                    })();
508                    let result = match deadline_and_receiver {
509                        Ok((deadline, event, receiver)) => {
510                            // We construct a specific `wait_fut` to explicitly bind the lifecycle
511                            // of the `event` to the duration of this wait operation. If the FIDL
512                            // client disconnects (or the future is otherwise dropped/cancelled),
513                            // the `event` is immediately dropped. This zeros the strong reference
514                            // count on the `InterruptibleEvent`, signaling to the `FutexTable`
515                            // that this external waiter is now stale and should be garbage
516                            // collected on its next cleanup pass.
517                            let wait_fut = async move {
518                                let _event = event;
519                                let receiver = receiver.map_err(|_| errno!(EINTR));
520                                if let Some(deadline) = deadline {
521                                    let timer =
522                                        fasync::Timer::new(deadline).map(|_| error!(ETIMEDOUT));
523                                    select_first(timer, receiver).await
524                                } else {
525                                    receiver.await
526                                }
527                            };
528                            wait_fut.await
529                        }
530                        Err(e) => Err(e),
531                    };
532                    let result = result.map_err(|e: Errno| {
533                        fposix::Errno::from_primitive(e.code.error_code() as i32)
534                            .unwrap_or(fposix::Errno::Einval)
535                    });
536                    responder
537                        .send(result)
538                        .context("Unable to send LutexControllerRequest::WaitBitset response")?;
539                }
540                fbinder::LutexControllerRequest::WakeBitset { payload, responder } => {
541                    let result = (|| {
542                        let mut unlocked = kernel.kthreads.unlocked_for_async();
543                        let vmo = payload.vmo.ok_or_else(|| errno!(EINVAL))?;
544                        let offset = payload.offset.ok_or_else(|| errno!(EINVAL))?;
545                        let count = payload.count.ok_or_else(|| errno!(EINVAL))?;
546                        let mask = payload.mask.unwrap_or(u32::MAX);
547                        kernel.shared_futexes.external_wake(
548                            &mut unlocked,
549                            vmo.into(),
550                            offset,
551                            count as usize,
552                            mask,
553                        )
554                    })();
555                    let result = result
556                        .map(|count| fbinder::WakeResponse {
557                            count: Some(count as u64),
558                            ..fbinder::WakeResponse::default()
559                        })
560                        .map_err(|e: Errno| {
561                            fposix::Errno::from_primitive(e.code.error_code() as i32)
562                                .unwrap_or(fposix::Errno::Einval)
563                        });
564                    responder
565                        .send(result)
566                        .context("Unable to send LutexControllerRequest::WakeBitset response")?;
567                }
568                fbinder::LutexControllerRequest::_UnknownMethod { ordinal, .. } => {
569                    log_warn!("Unknown LutexController ordinal: {}", ordinal);
570                }
571            }
572            Ok(())
573        })
574        .await
575        .context("failed fbinder::LutexController request")
576}
577
578#[cfg(test)]
579mod tests {
580    use super::*;
581    use assert_matches::assert_matches;
582    use fidl::HandleBased;
583    use starnix_core::testing::*;
584    use {fidl_fuchsia_posix as fposix, zx};
585
586    #[fuchsia::test]
587    async fn lutex_controller_test() {
588        spawn_kernel_and_run(async |mut _locked, current_task| {
589            let (sender, receiver) = oneshot::channel::<()>();
590            current_task.kernel.kthreads.spawn_future(
591                {
592                    let kernel = current_task.kernel.clone();
593                    move || async move {
594                        let (lutex_controller, stream) = fidl::endpoints::create_proxy_and_stream::<
595                            fbinder::LutexControllerMarker,
596                        >();
597
598                        // Spawn the server
599                        let server_fut =
600                            serve_lutex_controller(stream, kernel.kthreads.system_task());
601
602                        let client_fut = async move {
603                            const VMO_SIZE: usize = 4 * 1024;
604                            let vmo = zx::Vmo::create(VMO_SIZE as u64).expect("Vmo::create");
605                            // Wait on an incorrect value.
606                            let wait = lutex_controller
607                                .wait_bitset(fbinder::WaitBitsetRequest {
608                                    vmo: Some(
609                                        vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
610                                            .expect("duplicate vmo"),
611                                    ),
612                                    offset: Some(0),
613                                    value: Some(1),
614                                    ..Default::default()
615                                })
616                                .await
617                                .expect("got_answer");
618                            assert_matches!(wait, Err(fposix::Errno::Eagain));
619
620                            // Wait with a timeout
621                            let wait = lutex_controller
622                                .wait_bitset(fbinder::WaitBitsetRequest {
623                                    vmo: Some(
624                                        vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
625                                            .expect("duplicate vmo"),
626                                    ),
627                                    offset: Some(0),
628                                    value: Some(0),
629                                    deadline: Some(0),
630                                    ..Default::default()
631                                })
632                                .await
633                                .expect("got_answer");
634                            assert_matches!(wait, Err(fposix::Errno::Etimedout));
635
636                            let mut wait = Box::pin(
637                                lutex_controller.wait_bitset(fbinder::WaitBitsetRequest {
638                                    vmo: Some(
639                                        vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
640                                            .expect("duplicate vmo"),
641                                    ),
642                                    offset: Some(0),
643                                    value: Some(0),
644                                    deadline: None,
645                                    ..Default::default()
646                                }),
647                            );
648                            // The wait is correct, the future should stay pending until a wake.
649                            assert!(futures::poll!(&mut wait).is_pending());
650
651                            let waken_up: fbinder::WakeResponse = lutex_controller
652                                .wake_bitset(fbinder::WakeBitsetRequest {
653                                    vmo: Some(
654                                        vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)
655                                            .expect("duplicate vmo"),
656                                    ),
657                                    offset: Some(0),
658                                    count: Some(1),
659                                    mask: None,
660                                    ..Default::default()
661                                })
662                                .await
663                                .expect("wake_answer")
664                                .expect("wake_response");
665                            assert_eq!(waken_up.count, Some(1));
666
667                            // The wait should now return.
668                            assert!(wait.await.expect("await_answer").is_ok());
669                        };
670
671                        let (server_res, _) = futures::join!(server_fut, client_fut);
672                        server_res.expect("server failed");
673                        let _ = sender.send(());
674                    }
675                },
676                "lutex_controller_test",
677            );
678            receiver.await.expect("test failed");
679        })
680        .await;
681    }
682}