1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! Rust Binder NDK interop tests
18 
19 use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTest::{
20     BnBinderRustNdkInteropTest, IBinderRustNdkInteropTest,
21 };
22 use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::IBinderRustNdkInteropTestOther;
23 use ::IBinderRustNdkInteropTest::binder::{self, BinderFeatures, Interface, StatusCode};
24 use std::ffi::CStr;
25 use std::os::raw::{c_char, c_int};
26 
27 /// Look up the provided AIDL service and call its echo method.
28 ///
29 /// # Safety
30 ///
31 /// service_name must be a valid, non-null C-style string (nul-terminated).
32 #[no_mangle]
rust_call_ndk(service_name: *const c_char) -> c_int33 pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int {
34     // SAFETY: Our caller promises that service_name is a valid C string.
35     let service_name = unsafe { CStr::from_ptr(service_name) }.to_str().unwrap();
36 
37     // The Rust class descriptor pointer will not match the NDK one, but the
38     // descriptor strings match so this needs to still associate.
39     let service: binder::Strong<dyn IBinderRustNdkInteropTest> =
40         match binder::get_interface(service_name) {
41             Err(e) => {
42                 eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
43                 return StatusCode::NAME_NOT_FOUND as c_int;
44             }
45             Ok(service) => service,
46         };
47 
48     match service.echo("testing") {
49         Ok(s) => {
50             if s != "testing" {
51                 return StatusCode::BAD_VALUE as c_int;
52             }
53         }
54         Err(e) => return e.into(),
55     }
56 
57     // Try using the binder service through the wrong interface type
58     let wrong_service: Result<binder::Strong<dyn IBinderRustNdkInteropTestOther>, StatusCode> =
59         binder::get_interface(service_name);
60     match wrong_service {
61         Err(StatusCode::BAD_TYPE) => {}
62         Err(e) => {
63             eprintln!("Trying to use a service via the wrong interface errored with unexpected error {:?}", e);
64             return e as c_int;
65         }
66         Ok(_) => {
67             eprintln!("We should not be allowed to use a service via the wrong interface");
68             return StatusCode::BAD_TYPE as c_int;
69         }
70     }
71 
72     StatusCode::OK as c_int
73 }
74 
75 struct Service;
76 
77 impl Interface for Service {}
78 
79 impl IBinderRustNdkInteropTest for Service {
echo(&self, s: &str) -> binder::Result<String>80     fn echo(&self, s: &str) -> binder::Result<String> {
81         Ok(s.to_string())
82     }
83 }
84 
85 /// Start the interop Echo test service with the given service name.
86 ///
87 /// # Safety
88 ///
89 /// service_name must be a valid, non-null C-style string (nul-terminated).
90 #[no_mangle]
rust_start_service(service_name: *const c_char) -> c_int91 pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int {
92     // SAFETY: Our caller promises that service_name is a valid C string.
93     let service_name = unsafe { CStr::from_ptr(service_name) }.to_str().unwrap();
94     let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default());
95     match binder::add_service(service_name, service.as_binder()) {
96         Ok(_) => StatusCode::OK as c_int,
97         Err(e) => e as c_int,
98     }
99 }
100