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

Commit e5f3a978 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Rust binder rpc test & service implementation for trusty" into main am:...

Merge "Rust binder rpc test & service implementation for trusty" into main am: 4ff02d09 am: 361a8a0e

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/2876734



Change-Id: I04c802f97126e5ce15b36ac3c52623aec257a6e9
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 78ecde5c 361a8a0e
Loading
Loading
Loading
Loading
+174 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.
 */

use binder::{Interface, ParcelFileDescriptor, SpIBinder, Status, StatusCode, Strong};
use binder_rpc_test_aidl::aidl::IBinderRpcCallback::IBinderRpcCallback;
use binder_rpc_test_aidl::aidl::IBinderRpcSession::IBinderRpcSession;
use binder_rpc_test_aidl::aidl::IBinderRpcTest::IBinderRpcTest;
use std::sync::Mutex;

static G_NUM: Mutex<i32> = Mutex::new(0);

#[derive(Debug, Default)]
pub struct MyBinderRpcSession {
    name: String,
}

impl MyBinderRpcSession {
    pub fn new(name: &str) -> Self {
        Self::increment_instance_count();
        Self { name: name.to_string() }
    }

    pub fn get_instance_count() -> i32 {
        *G_NUM.lock().unwrap()
    }

    fn increment_instance_count() {
        *G_NUM.lock().unwrap() += 1;
    }

    fn decrement_instance_count() {
        *G_NUM.lock().unwrap() -= 1;
    }
}

impl Drop for MyBinderRpcSession {
    fn drop(&mut self) {
        MyBinderRpcSession::decrement_instance_count();
    }
}

impl Interface for MyBinderRpcSession {}

impl IBinderRpcSession for MyBinderRpcSession {
    fn getName(&self) -> Result<String, Status> {
        Ok(self.name.clone())
    }
}

impl IBinderRpcTest for MyBinderRpcSession {
    fn sendString(&self, _: &str) -> Result<(), Status> {
        todo!()
    }
    fn doubleString(&self, _s: &str) -> Result<String, Status> {
        todo!()
    }
    fn getClientPort(&self) -> Result<i32, Status> {
        todo!()
    }
    fn countBinders(&self) -> Result<Vec<i32>, Status> {
        todo!()
    }
    fn getNullBinder(&self) -> Result<SpIBinder, Status> {
        todo!()
    }
    fn pingMe(&self, _binder: &SpIBinder) -> Result<i32, Status> {
        todo!()
    }
    fn repeatBinder(&self, _binder: Option<&SpIBinder>) -> Result<Option<SpIBinder>, Status> {
        todo!()
    }
    fn holdBinder(&self, _binder: Option<&SpIBinder>) -> Result<(), Status> {
        todo!()
    }
    fn getHeldBinder(&self) -> Result<Option<SpIBinder>, Status> {
        todo!()
    }
    fn nestMe(
        &self,
        binder: &Strong<(dyn IBinderRpcTest + 'static)>,
        count: i32,
    ) -> Result<(), Status> {
        if count < 0 {
            Ok(())
        } else {
            binder.nestMe(binder, count - 1)
        }
    }
    fn alwaysGiveMeTheSameBinder(&self) -> Result<SpIBinder, Status> {
        todo!()
    }
    fn openSession(
        &self,
        _name: &str,
    ) -> Result<Strong<(dyn IBinderRpcSession + 'static)>, Status> {
        todo!()
    }
    fn getNumOpenSessions(&self) -> Result<i32, Status> {
        todo!()
    }
    fn lock(&self) -> Result<(), Status> {
        todo!()
    }
    fn unlockInMsAsync(&self, _: i32) -> Result<(), Status> {
        todo!()
    }
    fn lockUnlock(&self) -> Result<(), Status> {
        todo!()
    }
    fn sleepMs(&self, _: i32) -> Result<(), Status> {
        todo!()
    }
    fn sleepMsAsync(&self, _: i32) -> Result<(), Status> {
        todo!()
    }
    fn doCallback(
        &self,
        _: &Strong<(dyn IBinderRpcCallback + 'static)>,
        _: bool,
        _: bool,
        _: &str,
    ) -> Result<(), Status> {
        todo!()
    }
    fn doCallbackAsync(
        &self,
        _: &Strong<(dyn IBinderRpcCallback + 'static)>,
        _: bool,
        _: bool,
        _: &str,
    ) -> Result<(), Status> {
        todo!()
    }
    fn die(&self, _: bool) -> Result<(), Status> {
        Err(Status::from(StatusCode::UNKNOWN_TRANSACTION))
    }
    fn scheduleShutdown(&self) -> Result<(), Status> {
        todo!()
    }
    fn useKernelBinderCallingId(&self) -> Result<(), Status> {
        todo!()
    }
    fn echoAsFile(&self, _: &str) -> Result<ParcelFileDescriptor, Status> {
        todo!()
    }
    fn concatFiles(&self, _: &[ParcelFileDescriptor]) -> Result<ParcelFileDescriptor, Status> {
        todo!()
    }
    fn blockingSendFdOneway(&self, _: &ParcelFileDescriptor) -> Result<(), Status> {
        todo!()
    }
    fn blockingRecvFd(&self) -> Result<ParcelFileDescriptor, Status> {
        todo!()
    }
    fn blockingSendIntOneway(&self, _: i32) -> Result<(), Status> {
        todo!()
    }
    fn blockingRecvInt(&self) -> Result<i32, Status> {
        todo!()
    }
}
+32 −0
Original line number Diff line number Diff line
# Copyright (C) 2023 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.
#

LOCAL_DIR := $(GET_LOCAL_DIR)
LIBBINDER_DIR := $(LOCAL_DIR)/../../../..

MODULE := $(LOCAL_DIR)

MODULE_SRCS := $(LOCAL_DIR)/lib.rs

MODULE_CRATE_NAME := binder_rpc_test_session

MODULE_LIBRARY_DEPS += \
	$(LIBBINDER_DIR)/trusty/rust \
	$(LIBBINDER_DIR)/trusty/rust/rpcbinder \
	$(LOCAL_DIR)/../aidl \
	$(call FIND_CRATE,log) \
	trusty/user/base/lib/trusty-std \

include make/library.mk
+184 −10
Original line number Diff line number Diff line
@@ -15,8 +15,11 @@
 */
#![cfg(test)]

use binder::{IBinder, Strong};
use binder_rpc_test_aidl::aidl::IBinderRpcTest::IBinderRpcTest;
use binder::{BinderFeatures, IBinder, Status, StatusCode, Strong};
use binder_rpc_test_aidl::aidl::IBinderRpcSession::{BnBinderRpcSession, IBinderRpcSession};
use binder_rpc_test_aidl::aidl::IBinderRpcTest::{BnBinderRpcTest, IBinderRpcTest};
use binder_rpc_test_session::MyBinderRpcSession;
use libc::{clock_gettime, CLOCK_REALTIME};
use rpcbinder::RpcSession;
use trusty_std::ffi::{CString, FallibleCString};

@@ -25,19 +28,190 @@ test::init!();
const SERVICE_PORT: &str = "com.android.trusty.binderRpcTestService.V1";
const RUST_SERVICE_PORT: &str = "com.android.trusty.rust.binderRpcTestService.V1";

macro_rules! service_test {
    ($c_name:ident, $rust_name:ident, $body:expr) => {
        #[test]
        fn $c_name() {
            $body(get_service(SERVICE_PORT))
        }
        #[test]
        fn $rust_name() {
            $body(get_service(RUST_SERVICE_PORT))
        }
    };
}

fn get_service(port: &str) -> Strong<dyn IBinderRpcTest> {
    let port = CString::try_new(port).expect("Failed to allocate port name");
    RpcSession::new().setup_trusty_client(port.as_c_str()).expect("Failed to create session")
}

#[test]
fn ping() {
    let srv = get_service(SERVICE_PORT);
    assert_eq!(srv.as_binder().ping_binder(), Ok(()));
fn expect_sessions(expected: i32, srv: &Strong<dyn IBinderRpcTest>) {
    let count = srv.getNumOpenSessions();
    assert!(count.is_ok());
    assert_eq!(expected, count.unwrap());
}

#[test]
fn ping_rust() {
    let srv = get_service(RUST_SERVICE_PORT);
fn get_time_ns() -> u64 {
    let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };

    // Safety: Passing valid pointer to variable ts which lives past end of call
    assert_eq!(unsafe { clock_gettime(CLOCK_REALTIME, &mut ts) }, 0);

    ts.tv_sec as u64 * 1_000_000_000u64 + ts.tv_nsec as u64
}

fn get_time_ms() -> u64 {
    get_time_ns() / 1_000_000u64
}

// ----------

service_test! {ping, ping_rust, |srv: Strong<dyn IBinderRpcTest>| {
    assert_eq!(srv.as_binder().ping_binder(), Ok(()));
}}

service_test! {send_something_oneway, send_something_oneway_rust, |srv: Strong<dyn IBinderRpcTest>| {
    assert_eq!(srv.sendString("Foo"), Ok(()));
}}

service_test! {send_and_get_result_back, send_and_get_result_back_rust, |srv: Strong<dyn IBinderRpcTest>| {
    assert_eq!(srv.doubleString("Foo"), Ok(String::from("FooFoo")));
}}

service_test! {send_and_get_result_back_big, send_and_get_result_back_big_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let single_len = 512;
    let single = "a".repeat(single_len);
    assert_eq!(srv.doubleString(&single), Ok(String::from(single.clone() + &single)));
}}

service_test! {invalid_null_binder_return, invalid_null_binder_return_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let binder = srv.getNullBinder();
    assert!(binder == Err(Status::from(StatusCode::UNEXPECTED_NULL)) || binder == Err(Status::from(StatusCode::UNKNOWN_TRANSACTION)));
}}

service_test! {call_me_back, call_me_back_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let binder =
        BnBinderRpcSession::new_binder(MyBinderRpcSession::new("Foo"), BinderFeatures::default())
            .as_binder();
    let result = srv.pingMe(&binder);
    assert_eq!(result, Ok(0));
}}

service_test! {repeat_binder, repeat_binder_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let in_binder =
        BnBinderRpcSession::new_binder(MyBinderRpcSession::new("Foo"), BinderFeatures::default())
            .as_binder();
    let result = srv.repeatBinder(Some(&in_binder));
    assert_eq!(result.unwrap().unwrap(), in_binder);
}}

service_test! {repeat_their_binder, repeat_their_binder_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let session = srv.openSession("Test");
    assert!(session.is_ok());

    let in_binder = session.unwrap().as_binder();
    let out_binder = srv.repeatBinder(Some(&in_binder));
    assert_eq!(out_binder.unwrap().unwrap(), in_binder);
}}

service_test! {hold_binder, hold_binder_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let name = "Foo";

    let binder =
        BnBinderRpcSession::new_binder(MyBinderRpcSession::new(name), BinderFeatures::default())
            .as_binder();
    assert!(srv.holdBinder(Some(&binder)).is_ok());

    let held = srv.getHeldBinder();
    assert!(held.is_ok());
    let held = held.unwrap();
    assert!(held.is_some());
    let held = held.unwrap();
    assert_eq!(binder, held);

    let session = held.into_interface::<dyn IBinderRpcSession>();
    assert!(session.is_ok());

    let session_name = session.unwrap().getName();
    assert!(session_name.is_ok());
    let session_name = session_name.unwrap();
    assert_eq!(session_name, name);

    assert!(srv.holdBinder(None).is_ok());
}}

service_test! {nested_transactions, nested_transactions_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let binder =
        BnBinderRpcTest::new_binder(MyBinderRpcSession::new("Nest"), BinderFeatures::default());
    assert!(srv.nestMe(&binder, 10).is_ok());
}}

service_test! {same_binder_equality, same_binder_equality_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let a = srv.alwaysGiveMeTheSameBinder();
    assert!(a.is_ok());

    let b = srv.alwaysGiveMeTheSameBinder();
    assert!(b.is_ok());

    assert_eq!(a.unwrap(), b.unwrap());
}}

service_test! {single_session, single_session_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let session = srv.openSession("aoeu");
    assert!(session.is_ok());
    let session = session.unwrap();
    let name = session.getName();
    assert!(name.is_ok());
    assert_eq!(name.unwrap(), "aoeu");

    let count = srv.getNumOpenSessions();
    assert!(count.is_ok());
    assert_eq!(count.unwrap(), 1);

    drop(session);
    let count = srv.getNumOpenSessions();
    assert!(count.is_ok());
    assert_eq!(count.unwrap(), 0);
}}

service_test! {many_session, many_session_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let mut sessions = Vec::new();

    for i in 0..15 {
        expect_sessions(i, &srv);

        let session = srv.openSession(&(i.to_string()));
        assert!(session.is_ok());
        sessions.push(session.unwrap());
    }

    expect_sessions(sessions.len() as i32, &srv);

    for i in 0..sessions.len() {
        let name = sessions[i].getName();
        assert!(name.is_ok());
        assert_eq!(name.unwrap(), i.to_string());
    }

    expect_sessions(sessions.len() as i32, &srv);

    while !sessions.is_empty() {
        sessions.pop();

        expect_sessions(sessions.len() as i32, &srv);
    }

    expect_sessions(0, &srv);
}}

service_test! {one_way_call_does_not_wait, one_way_call_does_not_wait_rust, |srv: Strong<dyn IBinderRpcTest>| {
    let really_long_time_ms = 100;
    let sleep_ms = really_long_time_ms * 5;

    let before = get_time_ms();
    let _ = srv.sleepMsAsync(sleep_ms);
    let after = get_time_ms();

    assert!(after < before + really_long_time_ms as u64);
}}
+1 −1
Original line number Diff line number Diff line
{
    "uuid": "91eed949-8a9e-4569-9c83-5935fb624025",
    "app_name": "rust_binder_rpc_test",
    "min_heap": 16384,
    "min_heap": 32768,
    "min_stack": 16384,
    "mgmt_flags": {
        "non_critical_app": true
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ MODULE_LIBRARY_DEPS += \
	$(LIBBINDER_DIR)/trusty/rust \
	$(LIBBINDER_DIR)/trusty/rust/rpcbinder \
	$(LOCAL_DIR)/aidl \
	$(LOCAL_DIR)/binder_rpc_test_session \
	$(call FIND_CRATE,log) \
	trusty/user/base/lib/trusty-std \

MODULE_RUST_TESTS := true
Loading