diff --git a/BUILD.gn b/BUILD.gn index 9fa6e5521da112791e4bb7cd957dd37c715d337a..c8431695cac7147ba0a2d0cad79bd258b6b6b277 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -47,6 +47,9 @@ group("ipc_components") { "//foundation/communication/ipc/interfaces/innerkits/libdbinder:libdbinder", "//foundation/communication/ipc/ipc/native/src/core:ipc_common", ] + if (target_cpu == "arm64") { + deps += [ "//foundation/communication/ipc/interfaces/innerkits/rust:rust_ipc_component" ] + } } else { deps = [ "//foundation/communication/ipc/interfaces/innerkits/c:rpc" ] } diff --git a/interfaces/innerkits/rust/BUILD.gn b/interfaces/innerkits/rust/BUILD.gn index badc4edc24981168e4d3ad7f92a598b4964aade6..03119ab2d4f2106597a452692dc53ab25dcf4633 100644 --- a/interfaces/innerkits/rust/BUILD.gn +++ b/interfaces/innerkits/rust/BUILD.gn @@ -27,6 +27,7 @@ ohos_rust_shared_library("ipc_rust") { "src/lib.rs", "src/parcel/mod.rs", "src/parcel/parcelable.rs", + "src/parcel/types.rs", ] deps = [ ":ipc_c" ] @@ -54,11 +55,7 @@ ohos_shared_library("ipc_c") { configs = [ ":libipc_c_private_config" ] - deps = [ - "$SUBSYSTEM_DIR/interfaces/innerkits/ipc_single:ipc_single", - "//base/security/access_token/interfaces/innerkits/nativetoken:libnativetoken", - "//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc", - ] + deps = [ "$SUBSYSTEM_DIR/interfaces/innerkits/ipc_single:ipc_single" ] external_deps = [ "c_utils:utils", @@ -73,9 +70,5 @@ ohos_shared_library("ipc_c") { } group("rust_ipc_component") { - deps = [ - ":ipc_rust", - "$SUBSYSTEM_DIR/interfaces/innerkits/rust/tests/client:rust_ipc_test_client", - "$SUBSYSTEM_DIR/interfaces/innerkits/rust/tests/server:rust_ipc_test_server", - ] + deps = [ ":ipc_rust" ] } diff --git a/interfaces/innerkits/rust/src/errors.rs b/interfaces/innerkits/rust/src/errors.rs index 63588f362aa82e9026a32b5dd68c3540cb23bb58..29e0892a8af5b1c0f034da823ca70f2b1f95a200 100644 --- a/interfaces/innerkits/rust/src/errors.rs +++ b/interfaces/innerkits/rust/src/errors.rs @@ -16,6 +16,7 @@ /// IPC specific Result, error is i32 type pub type Result = std::result::Result; +/// Generate a rust ipc Result by ret and val arguments. pub fn result_status(ret: bool, val: T) -> Result { if ret { Ok(val) diff --git a/interfaces/innerkits/rust/src/ipc/macros.rs b/interfaces/innerkits/rust/src/ipc/macros.rs index f634be7776691726780640ecd37e87a144da7879..2096d1a65d4961651ebcc99f5bf9a30a00dab0cf 100644 --- a/interfaces/innerkits/rust/src/ipc/macros.rs +++ b/interfaces/innerkits/rust/src/ipc/macros.rs @@ -13,6 +13,7 @@ * limitations under the License. */ +/// This macro can define a rust IPC proxy and stub releations. #[macro_export] macro_rules! define_remote_object { { @@ -37,28 +38,33 @@ macro_rules! define_remote_object { }, } } => { + /// IPC proxy type pub struct $proxy { remote: $crate::RemoteObj, $($item_name: $item_type,)* } impl $proxy { + /// Create proxy object by RemoteObj fn from_remote_object(remote: RemoteObj) -> $crate::Result { Ok(Self {remote, $($item_name: $item_init),* }) } - + + /// Get proxy object descriptor #[allow(dead_code)] - fn get_descriptor() -> &'static str { + pub fn get_descriptor() -> &'static str { $descriptor } } impl $crate::IRemoteBroker for $proxy { + /// Get RemoteObje object from proxy fn as_object(&self) -> Option<$crate::RemoteObj> { Some(self.remote.clone()) } } + /// IPC stub type pub struct $stub(Box); impl $stub { @@ -70,10 +76,12 @@ macro_rules! define_remote_object { } impl $crate::IRemoteStub for $stub { + /// Get stub object descriptor fn get_descriptor() -> &'static str { $descriptor } + /// Callback to deal IPC request for this stub fn on_remote_request(&self, code: u32, data: &$crate::BorrowedMsgParcel, reply: &mut $crate::BorrowedMsgParcel) -> i32 { // For example, "self.0" is "Box", "*self.0" is "dyn ITest" @@ -90,7 +98,7 @@ macro_rules! define_remote_object { } impl $crate::FromRemoteObj for dyn $remote_broker { - // For example, convert RemoteObj to RemoteObjRef + /// For example, convert RemoteObj to RemoteObjRef fn from(object: $crate::RemoteObj) -> $crate::Result<$crate::RemoteObjRef> { Ok($crate::RemoteObjRef::new(Box::new($proxy::from_remote_object(object)?))) } diff --git a/interfaces/innerkits/rust/src/ipc/mod.rs b/interfaces/innerkits/rust/src/ipc/mod.rs index 6e9f23352a016e9db53fc4a0bca4ad94ba4e77b6..e94b8234db7c238262cd5b8b187fa604b54a5cc0 100644 --- a/interfaces/innerkits/rust/src/ipc/mod.rs +++ b/interfaces/innerkits/rust/src/ipc/mod.rs @@ -26,39 +26,45 @@ pub use crate::RemoteObj; /// Like C++ IRemoteObject class, define function for both proxy and stub object pub trait IRemoteObj { - // IPC request + /// Send a IPC request to remote service fn send_request(&self, code: u32, data: &MsgParcel, is_async: bool) -> Result; - // Death Recipient + /// Add a death recipient fn add_death_recipient(&self, recipient: &mut DeathRecipient) -> bool; + + /// Remove a death recipient fn remove_death_recipient(&self, recipient: &mut DeathRecipient) -> bool; } -// Like C++ IPCObjectStub class, define function for stub object only, like on_remote_request(). +/// Like C++ IPCObjectStub class, define function for stub object only, like on_remote_request(). pub trait IRemoteStub: Send + Sync { + /// Get object descriptor of this stub fn get_descriptor() -> &'static str; + /// Callback for deal IPC request fn on_remote_request(&self, code: u32, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> i32; } -// Like C++ IRemoteBroker class +/// Like C++ IRemoteBroker class pub trait IRemoteBroker: Send + Sync { - // Convert self to RemoteObject + /// Convert self to RemoteObject fn as_object(&self) -> Option { panic!("This is not a RemoteObject.") } } -// Define function which how to convert a RemoteObj to RemoteObjRef, the later contains a -// dynamic trait object: IRemoteObject. For example, "dyn ITest" should implements this trait +/// Define function which how to convert a RemoteObj to RemoteObjRef, the later contains a +/// dynamic trait object: IRemoteObject. For example, "dyn ITest" should implements this trait pub trait FromRemoteObj: IRemoteBroker { + /// Convert a RemoteObj to RemoteObjeRef fn from(object: RemoteObj) -> Result>; } -// Strong reference for "dyn IRemoteBroker" object, for example T is "dyn ITest" +/// Strong reference for "dyn IRemoteBroker" object, for example T is "dyn ITest" pub struct RemoteObjRef(Box); impl RemoteObjRef { + /// Create a RemoteObjRef object pub fn new(object: Box) -> Self { Self(object) } diff --git a/interfaces/innerkits/rust/src/ipc/remote_obj.rs b/interfaces/innerkits/rust/src/ipc/remote_obj.rs index c9b1c3741336797ef90760879aace0f5922e3bf8..753c1f6997bdb78a1bdad1a844168a4f8f7b730d 100644 --- a/interfaces/innerkits/rust/src/ipc/remote_obj.rs +++ b/interfaces/innerkits/rust/src/ipc/remote_obj.rs @@ -13,6 +13,8 @@ * limitations under the License. */ +//! Implement of RemoteObj type, which represent a C++ IRemoteObject. + use std::ptr; use crate::{ ipc_binding, IRemoteObj, DeathRecipient, Result, @@ -34,6 +36,7 @@ pub struct RemoteObj(ptr::NonNull); impl RemoteObj { /// Create an `RemoteObj` wrapper object from a raw `CRemoteObject` pointer. + /// # Safety pub unsafe fn from_raw(obj: *mut CRemoteObject) -> Option { if obj.is_null() { None @@ -44,7 +47,6 @@ impl RemoteObj { /// Extract a raw `CRemoteObject` pointer from this wrapper. /// # Safety - /// TODO pub unsafe fn as_inner(&self) -> *mut CRemoteObject { self.0.as_ptr() } @@ -52,7 +54,7 @@ impl RemoteObj { impl IRemoteObj for RemoteObj { fn send_request(&self, code: u32, data: &MsgParcel, is_async: bool) -> Result { - // SAFETY: TODO + // SAFETY: unsafe { let mut reply = MsgParcel::new().expect("create reply MsgParcel not success"); let result = ipc_binding::RemoteObjectSendRequest(self.as_inner(), code, data.as_raw(), @@ -85,7 +87,7 @@ impl Serialize for RemoteObj { let ret = unsafe { ipc_binding::CParcelWriteRemoteObject(parcel.as_mut_raw(), self.as_inner()) }; - if ret == true { + if ret { Ok(()) } else { Err(-1) diff --git a/interfaces/innerkits/rust/src/ipc/remote_obj/death_recipient.rs b/interfaces/innerkits/rust/src/ipc/remote_obj/death_recipient.rs index 04cb38d5481e3ec5e32dcf5d408367886a4ff290..52362e88d80cf86a524388a8d5bcd5a1caa7673a 100644 --- a/interfaces/innerkits/rust/src/ipc/remote_obj/death_recipient.rs +++ b/interfaces/innerkits/rust/src/ipc/remote_obj/death_recipient.rs @@ -15,6 +15,7 @@ use super::*; +/// This type represent a rust DeathRecipient which like C++ DethRecipient. #[repr(C)] pub struct DeathRecipient { native: *mut CDeathRecipient, @@ -22,6 +23,7 @@ pub struct DeathRecipient { } impl DeathRecipient { + /// Create a rust DeathRecipient object with a death recipient callback. pub fn new(callback: F) -> Option where F: Fn() + Send + Sync + 'static, @@ -69,7 +71,7 @@ impl DeathRecipient { { if !callback.is_null() { println!("death recipient on destroy"); - Box::from_raw(callback as *mut F); + drop(Box::from_raw(callback as *mut F)); } } } diff --git a/interfaces/innerkits/rust/src/ipc/remote_stub.rs b/interfaces/innerkits/rust/src/ipc/remote_stub.rs index effbbd3797ad80050f7153e5e2e8987cbf7cde63..8962e83d050ce10084cffc05a7d2847246033214 100644 --- a/interfaces/innerkits/rust/src/ipc/remote_stub.rs +++ b/interfaces/innerkits/rust/src/ipc/remote_stub.rs @@ -27,7 +27,7 @@ pub struct RemoteStub { } impl RemoteStub { - // create a RemoteStub object + /// Create a RemoteStub object pub fn new(rust: T) -> Option { let rust = Box::into_raw(Box::new(rust)); let descripor = CString::new(T::get_descriptor()).expect("descripor must be valid!"); @@ -91,7 +91,7 @@ impl RemoteStub { let rust_object: &T = &*(object as *const T); rust_object.on_remote_request(code, &data, &mut reply) }; - return res; + res } unsafe extern "C" fn on_destroy(user_data: *mut c_void) { diff --git a/interfaces/innerkits/rust/src/ipc_binding.rs b/interfaces/innerkits/rust/src/ipc_binding.rs index 2a0c7086e53c614d652ffcd47446e1a927205d4e..100034560a0415cb1e8981de95199f00d249321d 100644 --- a/interfaces/innerkits/rust/src/ipc_binding.rs +++ b/interfaces/innerkits/rust/src/ipc_binding.rs @@ -81,7 +81,6 @@ extern "C" { pub fn CreateDeathRecipient(onDeathRecipient: OnDeathRecipientCb, onDestroy: OnDeathRecipientDestroyCb, userData: *const c_void) -> *mut CDeathRecipient; - pub fn DeathRecipientIncStrongRef(recipient: *mut CDeathRecipient); pub fn DeathRecipientDecStrongRef(recipient: *mut CDeathRecipient); pub fn AddDeathRecipient(object: *mut CRemoteObject, recipient: *mut CDeathRecipient) -> bool; pub fn RemoveDeathRecipient(object: *mut CRemoteObject, recipient: *mut CDeathRecipient) -> bool; @@ -114,8 +113,8 @@ extern "C" { allocator: OnCParcelBytesAllocator) -> bool; pub fn CParcelWriteRemoteObject(parcel: *mut CParcel, object: *mut CRemoteObject) -> bool; pub fn CParcelReadRemoteObject(parcel: *const CParcel) -> *mut CRemoteObject; - pub fn CParcelWriteBuffer(parcel: *mut CParcel, value: *const c_void, len: i32) -> bool; - pub fn CParcelReadBuffer(parcel: *const CParcel, value: *mut c_void, allocator: OnCParcelBytesAllocator) -> bool; + pub fn CParcelWriteBuffer(parcel: *mut CParcel, value: *const u8, len: u32) -> bool; + pub fn CParcelReadBuffer(parcel: *const CParcel, value: *mut u8, len: u32) -> bool; pub fn CParcelWriteFileDescriptor(parcel: *mut CParcel, fd: i32) -> bool; pub fn CParcelReadFileDescriptor(parcel: *const CParcel, fd: *mut i32) -> bool; pub fn CParcelGetDataSize(parcel: *const CParcel) -> u32; @@ -134,7 +133,6 @@ extern "C" { pub fn GetContextManager() -> *mut CRemoteObject; pub fn JoinWorkThread(); pub fn StopWorkThread(); - pub fn InitTokenId(); pub fn GetCallingTokenId() -> u64; pub fn GetFirstToekenId() -> u64; pub fn GetSelfToekenId() -> u64; diff --git a/interfaces/innerkits/rust/src/lib.rs b/interfaces/innerkits/rust/src/lib.rs index 0d7ec0f286196e97832898d0cf2a5e314a3a1aff..a58e74c5a3600d1d258c74175ff43542b28e7ef3 100644 --- a/interfaces/innerkits/rust/src/lib.rs +++ b/interfaces/innerkits/rust/src/lib.rs @@ -13,11 +13,13 @@ * limitations under the License. */ +//! Safe Rust interface to OHOS IPC/RPC + mod ipc_binding; -pub mod errors; -pub mod ipc; -pub mod parcel; -pub mod process; +mod errors; +mod ipc; +mod parcel; +mod process; // Export types of this crate pub use crate::errors::{Result, result_status}; @@ -26,17 +28,19 @@ pub use crate::ipc::{ remote_obj::RemoteObj, remote_obj::death_recipient::DeathRecipient, remote_stub::RemoteStub, }; pub use crate::parcel::{MsgParcel, BorrowedMsgParcel, IMsgParcel, - parcelable::{Serialize, Deserialize, SerOption, DeSerOption, SerArray, DeArray}, + parcelable::{Serialize, Deserialize, SerOption, DeOption}, }; + +// pub use crate::parcel::{SerArray, DeArray}; + pub use crate::parcel::types::{ interface_token::InterfaceToken, file_desc::FileDesc, string16::String16 }; pub use crate::process::{ - add_service, get_service, init_access_token, join_work_thread, stop_work_thread, + add_service, get_service, join_work_thread, stop_work_thread, get_calling_uid, get_calling_token_id, get_first_token_id, get_self_token_id, get_calling_pid, - get_calling_uid, }; /// First request code available for user IPC request(inclusive) diff --git a/interfaces/innerkits/rust/src/parcel/mod.rs b/interfaces/innerkits/rust/src/parcel/mod.rs index 604b27cdc1b886ea5a0b65ba40a04adbc57cf411..3c6e9c85d90415df85970ad57fb86e5377050230 100644 --- a/interfaces/innerkits/rust/src/parcel/mod.rs +++ b/interfaces/innerkits/rust/src/parcel/mod.rs @@ -19,86 +19,132 @@ pub mod types; use crate::{ipc_binding, Result}; use crate::ipc_binding::{CParcel}; use std::marker::PhantomData; -use std::mem::ManuallyDrop; +use std::mem::{ManuallyDrop,MaybeUninit}; use std::ops::{Drop}; use std::ptr::{NonNull}; use crate::AsRawPtr; use crate::parcel::parcelable::{Serialize, Deserialize}; + /// This trait implements the common function for MsgParcel /// and BorrowedMsgParcel pub trait IMsgParcel: AsRawPtr { + /// Get current data size in parcel fn get_data_size(&self) -> u32 { unsafe { ipc_binding::CParcelGetDataSize(self.as_raw()) } } + /// Set current data size in parcel fn set_data_size(&mut self, new_size: u32) -> bool { unsafe { ipc_binding::CParcelSetDataSize(self.as_mut_raw(), new_size) } } + /// Get current data capacity in parcel fn get_data_capacity(&self) -> u32 { unsafe { ipc_binding::CParcelGetDataCapacity(self.as_raw()) } } + /// Set current data capacity in parcel fn set_data_capacity(&mut self, new_size: u32) -> bool { unsafe { ipc_binding::CParcelSetDataCapacity(self.as_mut_raw(), new_size) } } + /// Get maximum capacity in parcel fn get_max_capacity(&self) -> u32 { unsafe { ipc_binding::CParcelGetMaxCapacity(self.as_raw()) } } + /// Set maximum capacity in parcel fn set_max_capacity(&mut self, new_size: u32) -> bool { unsafe { ipc_binding::CParcelSetMaxCapacity(self.as_mut_raw(), new_size) } } + /// Get current writalbe bytes in parcel fn get_writable_bytes(&self) -> u32 { unsafe { ipc_binding::CParcelGetWritableBytes(self.as_raw()) } } + /// Get current readable bytes in parcel fn get_readable_bytes(&self) -> u32 { unsafe { ipc_binding::CParcelGetReadableBytes(self.as_raw()) } } + /// Get current read position of parcel fn get_read_position(&self) -> u32 { unsafe { ipc_binding::CParcelGetReadPosition(self.as_raw()) } } + /// Get current write position of parcel fn get_write_position(&self) -> u32 { unsafe { ipc_binding::CParcelGetWritePosition(self.as_raw()) } } + /// Rewind the read position to a new position of parcel fn rewind_read(&mut self, new_pos: u32) -> bool { unsafe { ipc_binding::CParcelRewindRead(self.as_mut_raw(), new_pos) } } + /// Rewind the write position to a new position of parcel fn rewind_write(&mut self, new_pos: u32) -> bool { unsafe { ipc_binding::CParcelRewindWrite(self.as_mut_raw(), new_pos) } } + + /// Write a bytes stream into parcel + fn write_buffer(&mut self, data: &[u8]) -> bool { + // SAFETY: + unsafe { + ipc_binding::CParcelWriteBuffer(self.as_mut_raw(), + data.as_ptr(), data.len() as u32) + } + } + + /// Read a sized bytes stream from parcel + fn read_buffer(&self, len: u32) -> Result> { + let mut buffer: Vec> = Vec::with_capacity(len as usize); + // SAFETY: this is safe because the vector contains MaybeUninit elements which can be uninitialized + unsafe{ + buffer.set_len(len as usize); + } + + let ok_status = unsafe { + ipc_binding::CParcelReadBuffer( + self.as_raw(), + buffer.as_mut_ptr() as *mut u8, + len + ) + }; + // SAFETY: MaybeUninit has been initialized, this should be safe + // since MaybeUninit should have same layout as inner type + unsafe fn transmute_vec(v: Vec>) -> Vec { + std::mem::transmute(v) + } + let buffer = unsafe { transmute_vec(buffer) }; + if ok_status { Ok(buffer) } else { Err(-1) } + } } /// Container for a message (data and object references) that can be sent @@ -115,6 +161,7 @@ unsafe impl Send for MsgParcel {} impl IMsgParcel for MsgParcel {} impl MsgParcel { + /// Create a MsgParcel object pub fn new() -> Option { let cparcel: *mut CParcel = unsafe { ipc_binding::CParcelObtain() @@ -123,10 +170,12 @@ impl MsgParcel { NonNull::new(cparcel).map(|x| MsgParcel{ptr: x}) } + /// # Safety pub unsafe fn from_raw(ptr: *mut CParcel) -> Option { NonNull::new(ptr).map(|ptr| Self { ptr }) } + /// Get a raw CParcel pointer and MsgParcel dropped its ownership pub fn into_raw(self) -> *mut CParcel { let ptr = self.ptr.as_ptr(); let _ = ManuallyDrop::new(self); @@ -189,7 +238,7 @@ impl<'a> IMsgParcel for BorrowedMsgParcel<'a> {} impl<'a> BorrowedMsgParcel<'a> { - /// # Safety: + /// # Safety /// /// `*mut CParcel` must be a valid pointer pub unsafe fn from_raw(ptr: *mut CParcel) -> Option> { @@ -223,20 +272,24 @@ unsafe impl<'a> AsRawPtr for BorrowedMsgParcel<'a> { } impl MsgParcel { + /// Read a data object which implements the Deserialize trait from MsgParcel pub fn read(&self) -> Result { self.borrowed_ref().read() } + /// Write a data object which implements the Serialize trait to MsgParcel pub fn write(&mut self, parcelable: &S) -> Result<()> { self.borrowed().write(parcelable) } } impl<'a> BorrowedMsgParcel<'a> { + /// Read a data object which implements the Deserialize trait from BorrowedMsgParcel pub fn read(&self) -> Result { D::deserialize(self) } + /// Write a data object which implements the Serialize trait to BorrowedMsgParcel pub fn write(&mut self, parcelable: &S) -> Result<()> { parcelable.serialize(self) } diff --git a/interfaces/innerkits/rust/src/parcel/parcelable.rs b/interfaces/innerkits/rust/src/parcel/parcelable.rs index be9d86a835a706f876392b390472a8c9e8a03970..3841f274395e48baecddbfc04314abc423e6a8eb 100644 --- a/interfaces/innerkits/rust/src/parcel/parcelable.rs +++ b/interfaces/innerkits/rust/src/parcel/parcelable.rs @@ -18,12 +18,6 @@ use std::mem::MaybeUninit; use std::ffi::c_void; use std::ptr; -// Internal use -pub(crate) trait Parcelable { - fn marshalling(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()>; - fn unmarshalling(parcel: &BorrowedMsgParcel<'_>) -> Result<()>; -} - /// Implement `Serialize` trait to serialize a custom MsgParcel. /// /// # Example: @@ -38,6 +32,7 @@ pub(crate) trait Parcelable { /// } /// ``` pub trait Serialize { + /// Serialize Self to BorrowedMsgParcel fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()>; } @@ -63,8 +58,9 @@ pub trait Deserialize: Sized { pub const NULL_FLAG : i32 = 0; pub const NON_NULL_FLAG : i32 = 1; -// DOC TODO +/// Define trait function for Option which T must implements the trait Serialize. pub trait SerOption: Serialize { + /// Serialize the Option fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> Result<(), > { if let Some(inner) = this { parcel.write(&NON_NULL_FLAG)?; @@ -75,8 +71,9 @@ pub trait SerOption: Serialize { } } -// DOC TODO -pub trait DeSerOption: Deserialize { +/// Define trait function for Option which T must implements the trait Deserialize. +pub trait DeOption: Deserialize { + /// Deserialize the Option fn de_option(parcel: &BorrowedMsgParcel<'_>) -> Result> { let null: i32 = parcel.read()?; if null == NULL_FLAG { @@ -133,12 +130,133 @@ unsafe extern "C" fn allocate_vec( true } -// DOC TODO -pub trait SerArray: Serialize + Sized { - fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> ; -} -// DOC TODO -pub trait DeArray: Deserialize { - fn de_array(parcel: &BorrowedMsgParcel<'_>) -> Result>>; -} \ No newline at end of file + +// /// Helper trait for types that can be serialized as arrays. +// /// Defaults to calling Serialize::serialize() manually for every element, +// /// but can be overridden for custom implementations like `writeByteArray`. +// // Until specialization is stabilized in Rust, we need this to be a separate +// // trait because it's the only way to have a default implementation for a method. +// // We want the default implementation for most types, but an override for +// // a few special ones like `readByteArray` for `u8`. +// pub trait SerArray: Serialize + Sized { +// fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { +// let ret = unsafe { +// // SAFETY: Safe FFI, slice will always be a safe pointer to pass. +// ipc_binding::CparcelWriteParcelableArray( +// parcel.as_mut_raw(), +// slice.as_ptr() as *const c_void, +// slice.len().try_into().or(Err(-1))?, +// ser_element::, +// ) +// }; +// result_status::<()>(ret, ()) +// } +// } + +// /// Callback to serialize an element of a generic parcelable array. +// /// +// /// Safety: We are relying on binder_ndk to not overrun our slice. As long as it +// /// doesn't provide an index larger than the length of the original slice in +// /// serialize_array, this operation is safe. The index provided is zero-based. +// unsafe extern "C" fn ser_element( +// parcel: *mut ipc_binding::CParcel, +// array: *const c_void, +// index: c_ulong, +// ) -> bool { +// // c_ulong and usize are the same, but we need the explicitly sized version +// // so the function signature matches what bindgen generates. +// let index = index as usize; + +// let slice: &[T] = std::slice::from_raw_parts(array.cast(), index+1); + +// let mut parcel = match BorrowedMsgParcel::from_raw(parcel) { +// None => return false, +// Some(p) => p, +// }; + +// slice[index].serialize(&mut parcel) +// .err() +// .unwrap_or(false) +// } + +// /// Helper trait for types that can be deserialized as arrays. +// /// Defaults to calling Deserialize::deserialize() manually for every element, +// /// but can be overridden for custom implementations like `readByteArray`. +// pub trait DeArray: Deserialize { +// /// Deserialize an array of type from the given parcel. +// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> Result>> { +// let mut vec: Option>> = None; +// let ok_status = unsafe { +// // SAFETY: Safe FFI, vec is the correct opaque type expected by +// // allocate_vec and de_element. +// ipc_binding::CparcelReadParcelableArray( +// parcel.as_raw(), +// &mut vec as *mut _ as *mut c_void, +// allocate_vec::, +// de_element::, +// ) +// }; + +// if ok_status{ +// let vec: Option> = unsafe { +// // SAFETY: We are assuming that the C-API correctly initialized every +// // element of the vector by now, so we know that all the +// // MaybeUninits are now properly initialized. We can transmute from +// // Vec> to Vec because MaybeUninit has the same +// // alignment and size as T, so the pointer to the vector allocation +// // will be compatible. +// std::mem::transmute(vec) +// }; +// Ok(vec) +// }else{ +// Err(-1) +// } + + +// } +// } + +// /// Callback to deserialize a parcelable element. +// /// +// /// The opaque array data pointer must be a mutable pointer to an +// /// `Option>>` with at least enough elements for `index` to be valid +// /// (zero-based). +// unsafe extern "C" fn de_element( +// parcel: *const ipc_binding::CParcel, +// array: *mut c_void, +// index: c_ulong, +// ) -> bool { +// // c_ulong and usize are the same, but we need the explicitly sized version +// // so the function signature matches what bindgen generates. +// let index = index as usize; + +// let vec = &mut *(array as *mut Option>>); +// let vec = match vec { +// Some(v) => v, +// None => return false, +// }; +// let parcel = match BorrowedMsgParcel::from_raw(parcel as *mut _) { +// None => return false, +// Some(p) => p, +// }; +// let element = match parcel.read() { +// Ok(e) => e, +// Err(code) => return false, +// }; +// ptr::write(vec[index].as_mut_ptr(), element); +// true +// } + +// /// Safety: All elements in the vector must be properly initialized. +// unsafe fn vec_assume_init(vec: Vec>) -> Vec { +// // We can convert from Vec> to Vec because MaybeUninit +// // has the same alignment and size as T, so the pointer to the vector +// // allocation will be compatible. +// let mut vec = std::mem::ManuallyDrop::new(vec); +// Vec::from_raw_parts( +// vec.as_mut_ptr().cast(), +// vec.len(), +// vec.capacity(), +// ) +// } \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types.rs b/interfaces/innerkits/rust/src/parcel/types.rs index 6fef9f90cd2a0950a87475ac4e1f8e78f485aea2..9b59034445c6be75dd968eecc50490db3dd34170 100644 --- a/interfaces/innerkits/rust/src/parcel/types.rs +++ b/interfaces/innerkits/rust/src/parcel/types.rs @@ -21,5 +21,11 @@ pub mod strings; pub mod interface_token; pub mod string16; pub mod file_desc; +pub mod boxt; +// pub mod const_array; +// pub mod slices; +// pub mod vector; -use crate::parcel::parcelable::*; \ No newline at end of file +use crate::parcel::parcelable::*; +use std::ffi::{c_char, c_void}; +use crate::{ipc_binding, BorrowedMsgParcel, AsRawPtr, result_status, Result, SerOption, DeOption}; \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/bool.rs b/interfaces/innerkits/rust/src/parcel/types/bool.rs index 36c8b464b892a2c6c3e58ac4b525ea1467c1b999..842c7aa062320ab7d349daefb4fcbea530cac766 100644 --- a/interfaces/innerkits/rust/src/parcel/types/bool.rs +++ b/interfaces/innerkits/rust/src/parcel/types/bool.rs @@ -14,7 +14,6 @@ */ use super::*; -use crate::{ipc_binding, BorrowedMsgParcel, AsRawPtr, result_status, Result}; impl Serialize for bool { fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { diff --git a/interfaces/innerkits/rust/src/parcel/types/boxt.rs b/interfaces/innerkits/rust/src/parcel/types/boxt.rs new file mode 100644 index 0000000000000000000000000000000000000000..5c6f2d62f4ad378c3a6b247f247cec8a842382f0 --- /dev/null +++ b/interfaces/innerkits/rust/src/parcel/types/boxt.rs @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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 super::*; + +impl Serialize for Box { + fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { + Serialize::serialize(&**self, parcel) + } +} + +impl Deserialize for Box { + fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> Result { + Deserialize::deserialize(parcel).map(Box::new) + } +} + +impl SerOption for Box { + fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { + SerOption::ser_option(this.map(|inner| &**inner), parcel) + } +} + +impl DeOption for Box { + fn de_option(parcel: &BorrowedMsgParcel<'_>) -> Result> { + DeOption::de_option(parcel).map(|t| t.map(Box::new)) + } +} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/bytes.rs b/interfaces/innerkits/rust/src/parcel/types/bytes.rs deleted file mode 100644 index d39d17c496107497cf951dbe05a19f3fd208e8d4..0000000000000000000000000000000000000000 --- a/interfaces/innerkits/rust/src/parcel/types/bytes.rs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * 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 super::*; - -impl Serialize for &[u8] { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ret = unsafe { - ipc_binding::CParcelWriteBuffer( - parcel.as_mut_raw(), - self.as_ptr() as *const void, - self.len().try_into().unwrap() - ) - }; - result_status::<()>(ret, ()) -} - -impl Deserialize for Vec { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> Result { - let mut vec: Option> = None; - let status = unsafe { - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - ipc_binding::CParcelReadBuffer( - parcel.as_raw(), - &mut vec as *mut _ as *mut c_void, - allocate_vec_with_buffer:: - ) - }; - - if status { - vec.transpose() - }else{ - Err(-1) - } - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/const_array.rs b/interfaces/innerkits/rust/src/parcel/types/const_array.rs new file mode 100644 index 0000000000000000000000000000000000000000..8b4b2876230348b66c5729d58c7b10fd65a21d65 --- /dev/null +++ b/interfaces/innerkits/rust/src/parcel/types/const_array.rs @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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 super::*; + + impl Serialize for [T; N] { + fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { + // forwards to T::serialize_array. + SerArray::ser_array(self, parcel) + } +} + +impl SerOption for [T; N] { + fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { + SerOption::ser_option(this.map(|arr| &arr[..]), parcel) + } +} + +impl SerArray for [T; N] {} + +impl Deserialize for [T; N] { + fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> Result { + let vec = DeArray::de_array(parcel) + .transpose() + .unwrap_or(Err(-1))?; + vec.try_into().or(Err(-1)) + } +} + +impl DeOption for [T; N] { + fn de_option(parcel: &BorrowedMsgParcel<'_>) -> Result> { + let vec = DeArray::de_array(parcel)?; + vec.map(|v| v.try_into().or(Err(-1))).transpose() + } +} + +impl DeArray for [T; N] {} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/file_desc.rs b/interfaces/innerkits/rust/src/parcel/types/file_desc.rs index 3fa2b19a6a8844881fe870028e1f3c521d3713b2..b07e80c939083d7aa324b547af4ea5eb8f793605 100644 --- a/interfaces/innerkits/rust/src/parcel/types/file_desc.rs +++ b/interfaces/innerkits/rust/src/parcel/types/file_desc.rs @@ -24,6 +24,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; pub struct FileDesc(File); impl FileDesc { + /// Create a FileDesc object with rust File object. pub fn new(file: File) -> Self { Self(file) } @@ -90,7 +91,7 @@ impl SerOption for FileDesc { } } -impl DeSerOption for FileDesc { +impl DeOption for FileDesc { fn de_option(parcel: &BorrowedMsgParcel<'_>) -> Result> { let mut fd = -1i32; let ok_status = unsafe { diff --git a/interfaces/innerkits/rust/src/parcel/types/integer.rs b/interfaces/innerkits/rust/src/parcel/types/integer.rs index 93592cfc198fd6cffb100491fab30e94d2dbbe2d..0c2b6f3964fd9435e1e398f94cad827c093cbd0e 100644 --- a/interfaces/innerkits/rust/src/parcel/types/integer.rs +++ b/interfaces/innerkits/rust/src/parcel/types/integer.rs @@ -51,7 +51,6 @@ impl Deserialize for u8 { } } - /// i16 && u16 impl Serialize for i16 { fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { @@ -74,6 +73,55 @@ impl Deserialize for i16 { } } +// impl SerArray for i16 { +// fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { +// let ret = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // If the slice is > 0 length, `slice.as_ptr()` will be a +// // valid pointer to an array of elements of type `$ty`. If the slice +// // length is 0, `slice.as_ptr()` may be dangling, but this is safe +// // since the pointer is not dereferenced if the length parameter is +// // 0. +// ipc_binding::CParcelWriteInt16Array( +// parcel.as_mut_raw(), +// slice.as_ptr(), +// slice.len() +// ) +// }; +// result_status::<()>(ret, ()) +// } +// } + +// impl DeArray for i16 { +// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> Result>> { +// let mut vec: Option>> = None; +// let ok_status = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // `allocate_vec` expects the opaque pointer to +// // be of type `*mut Option>>`, so `&mut vec` is +// // correct for it. +// ipc_binding::CParcelReadInt16Array( +// parcel.as_raw(), +// &mut vec as *mut _ as *mut c_void, +// allocate_vec_with_buffer, +// ) +// }; +// if ok_status{ +// let vec: Option> = unsafe { +// // SAFETY: We are assuming that the NDK correctly +// // initialized every element of the vector by now, so we +// // know that all the MaybeUninits are now properly +// // initialized. +// vec.map(|vec| vec_assume_init(vec)) +// }; +// Ok(vec) +// }else{ +// Err(-1) +// } + +// } +// } + impl Serialize for u16 { fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { (*self as i16).serialize(parcel) @@ -86,6 +134,54 @@ impl Deserialize for u16 { } } +// impl SerArray for u16 { +// fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { +// let ret = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // If the slice is > 0 length, `slice.as_ptr()` will be a +// // valid pointer to an array of elements of type `$ty`. If the slice +// // length is 0, `slice.as_ptr()` may be dangling, but this is safe +// // since the pointer is not dereferenced if the length parameter is +// // 0. +// ipc_binding::CParcelWriteInt16Array( +// parcel.as_mut_raw(), +// slice.as_ptr() as *const i16, +// slice.len() +// ) +// }; +// result_status::<()>(ret, ()) +// } +// } + +// impl DeArray for u16 { +// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> Result>> { +// let mut vec: Option>> = None; +// let ok_status = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // `allocate_vec` expects the opaque pointer to +// // be of type `*mut Option>>`, so `&mut vec` is +// // correct for it. +// ipc_binding::CParcelReadInt16Array( +// parcel.as_raw(), +// &mut vec as *mut _ as *mut c_void, +// allocate_vec_with_buffer, +// ) +// }; +// if ok_status{ +// let vec: Option> = unsafe { +// // SAFETY: We are assuming that the NDK correctly +// // initialized every element of the vector by now, so we +// // know that all the MaybeUninits are now properly +// // initialized. +// vec.map(|vec| vec_assume_init(vec)) +// }; +// Ok(vec) +// }else{ +// Err(-1) +// } + +// } +// } /// i32 && u32 impl Serialize for i32 { @@ -109,6 +205,55 @@ impl Deserialize for i32 { } } +// impl SerArray for i32 { +// fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { +// let ret = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // If the slice is > 0 length, `slice.as_ptr()` will be a +// // valid pointer to an array of elements of type `$ty`. If the slice +// // length is 0, `slice.as_ptr()` may be dangling, but this is safe +// // since the pointer is not dereferenced if the length parameter is +// // 0. +// ipc_binding::CParcelWriteInt32Array( +// parcel.as_mut_raw(), +// slice.as_ptr(), +// slice.len() +// ) +// }; +// result_status::<()>(ret, ()) +// } +// } + +// impl DeArray for i32 { +// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> Result>> { +// let mut vec: Option>> = None; +// let ok_status = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // `allocate_vec` expects the opaque pointer to +// // be of type `*mut Option>>`, so `&mut vec` is +// // correct for it. +// ipc_binding::CParcelReadInt32Array( +// parcel.as_raw(), +// &mut vec as *mut _ as *mut c_void, +// allocate_vec_with_buffer, +// ) +// }; +// if ok_status{ +// let vec: Option> = unsafe { +// // SAFETY: We are assuming that the NDK correctly +// // initialized every element of the vector by now, so we +// // know that all the MaybeUninits are now properly +// // initialized. +// vec.map(|vec| vec_assume_init(vec)) +// }; +// Ok(vec) +// }else{ +// Err(-1) +// } + +// } +// } + impl Serialize for u32 { fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { (*self as i32).serialize(parcel) @@ -121,6 +266,55 @@ impl Deserialize for u32 { } } +// impl SerArray for u32 { +// fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { +// let ret = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // If the slice is > 0 length, `slice.as_ptr()` will be a +// // valid pointer to an array of elements of type `$ty`. If the slice +// // length is 0, `slice.as_ptr()` may be dangling, but this is safe +// // since the pointer is not dereferenced if the length parameter is +// // 0. +// ipc_binding::CParcelWriteInt32Array( +// parcel.as_mut_raw(), +// slice.as_ptr() as *const i32, +// slice.len().try_into().or(Err(-1)?, +// ) +// }; +// result_status::<()>(ret, ()) +// } +// } + +// impl DeArray for u32 { +// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> Result>> { +// let mut vec: Option>> = None; +// let ok_status = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // `allocate_vec` expects the opaque pointer to +// // be of type `*mut Option>>`, so `&mut vec` is +// // correct for it. +// ipc_binding::CParcelReadInt32Array( +// parcel.as_raw(), +// &mut vec as *mut _ as *mut c_void, +// allocate_vec_with_buffer, +// ) +// }; +// if ok_status{ +// let vec: Option> = unsafe { +// // SAFETY: We are assuming that the NDK correctly +// // initialized every element of the vector by now, so we +// // know that all the MaybeUninits are now properly +// // initialized. +// vec.map(|vec| vec_assume_init(vec)) +// }; +// Ok(vec) +// }else{ +// Err(-1) +// } + +// } +// } + /// i64 && u64 impl Serialize for i64 { fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { @@ -143,6 +337,55 @@ impl Deserialize for i64 { } } +// impl SerArray for i64 { +// fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { +// let ret = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // If the slice is > 0 length, `slice.as_ptr()` will be a +// // valid pointer to an array of elements of type `$ty`. If the slice +// // length is 0, `slice.as_ptr()` may be dangling, but this is safe +// // since the pointer is not dereferenced if the length parameter is +// // 0. +// ipc_binding::CParcelWriteInt64Array( +// parcel.as_mut_raw(), +// slice.as_ptr() as *const i64, +// slice.len() +// ) +// }; +// result_status::<()>(ret, ()) +// } +// } + +// impl DeArray for i64 { +// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> Result>> { +// let mut vec: Option>> = None; +// let ok_status = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // `allocate_vec` expects the opaque pointer to +// // be of type `*mut Option>>`, so `&mut vec` is +// // correct for it. +// ipc_binding::CParcelReadInt64Array( +// parcel.as_raw(), +// &mut vec as *mut _ as *mut c_void, +// allocate_vec_with_buffer, +// ) +// }; +// if ok_status{ +// let vec: Option> = unsafe { +// // SAFETY: We are assuming that the NDK correctly +// // initialized every element of the vector by now, so we +// // know that all the MaybeUninits are now properly +// // initialized. +// vec.map(|vec| vec_assume_init(vec)) +// }; +// Ok(vec) +// }else{ +// Err(-1) +// } + +// } +// } + impl Serialize for u64 { fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { (*self as i64).serialize(parcel) @@ -155,7 +398,54 @@ impl Deserialize for u64 { } } +// impl SerArray for u64 { +// fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { +// let ret = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // If the slice is > 0 length, `slice.as_ptr()` will be a +// // valid pointer to an array of elements of type `$ty`. If the slice +// // length is 0, `slice.as_ptr()` may be dangling, but this is safe +// // since the pointer is not dereferenced if the length parameter is +// // 0. +// ipc_binding::CParcelWriteInt64Array( +// parcel.as_mut_raw(), +// slice.as_ptr() as *const i64, +// slice.len() +// ) +// }; +// result_status::<()>(ret, ()) +// } +// } +// impl DeArray for u64 { +// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> Result>> { +// let mut vec: Option>> = None; +// let ok_status = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // `allocate_vec` expects the opaque pointer to +// // be of type `*mut Option>>`, so `&mut vec` is +// // correct for it. +// ipc_binding::CParcelReadInt64Array( +// parcel.as_raw(), +// &mut vec as *mut _ as *mut c_void, +// allocate_vec_with_buffer, +// ) +// }; +// if ok_status{ +// let vec: Option> = unsafe { +// // SAFETY: We are assuming that the NDK correctly +// // initialized every element of the vector by now, so we +// // know that all the MaybeUninits are now properly +// // initialized. +// vec.map(|vec| vec_assume_init(vec)) +// }; +// Ok(vec) +// }else{ +// Err(-1) +// } + +// } +// } /// f32 impl Serialize for f32 { @@ -179,6 +469,53 @@ impl Deserialize for f32 { } } +// impl SerArray for f32 { +// fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { +// let ret = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // If the slice is > 0 length, `slice.as_ptr()` will be a +// // valid pointer to an array of elements of type `$ty`. If the slice +// // length is 0, `slice.as_ptr()` may be dangling, but this is safe +// // since the pointer is not dereferenced if the length parameter is +// // 0. +// ipc_binding::CParcelWriteFloatArray( +// parcel.as_mut_raw(), +// slice.as_ptr(), +// slice.len().try_into().or(Err(-1)?, +// ) +// }; +// result_status::<()>(ret, ()) +// } +// } + +// impl DeArray for f32 { +// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> Result>> { +// let mut vec: Option>> = None; +// let ok_status = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // `allocate_vec` expects the opaque pointer to +// // be of type `*mut Option>>`, so `&mut vec` is +// // correct for it. +// ipc_binding::CParcelReadFloatArray( +// parcel.as_raw(), +// &mut vec as *mut _ as *mut c_void, +// allocate_vec_with_buffer, +// ) +// }; +// if ok_status{ +// let vec: Option> = unsafe { +// // SAFETY: We are assuming that the NDK correctly +// // initialized every element of the vector by now, so we +// // know that all the MaybeUninits are now properly +// // initialized. +// vec.map(|vec| vec_assume_init(vec)) +// }; +// Ok(vec) +// }else{ +// Err(-1) +// } +// } +// } /// f64 impl Serialize for f64 { @@ -201,3 +538,51 @@ impl Deserialize for f64 { result_status::(ret, val) } } + +// impl SerArray for f64 { +// fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { +// let ret = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // If the slice is > 0 length, `slice.as_ptr()` will be a +// // valid pointer to an array of elements of type `$ty`. If the slice +// // length is 0, `slice.as_ptr()` may be dangling, but this is safe +// // since the pointer is not dereferenced if the length parameter is +// // 0. +// ipc_binding::CParcelWriteDoubleArray( +// parcel.as_mut_raw(), +// slice.as_ptr(), +// slice.len() +// ) +// }; +// result_status::<()>(ret, ()) +// } +// } + +// impl DeArray for f64 { +// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> Result>> { +// let mut vec: Option>> = None; +// let ok_status = unsafe { +// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` +// // `allocate_vec` expects the opaque pointer to +// // be of type `*mut Option>>`, so `&mut vec` is +// // correct for it. +// ipc_binding::CParcelReadDoubleArray( +// parcel.as_raw(), +// &mut vec as *mut _ as *mut c_void, +// allocate_vec_with_buffer, +// ) +// }; +// if ok_status{ +// let vec: Option> = unsafe { +// // SAFETY: We are assuming that the NDK correctly +// // initialized every element of the vector by now, so we +// // know that all the MaybeUninits are now properly +// // initialized. +// vec.map(|vec| vec_assume_init(vec)) +// }; +// Ok(vec) +// }else{ +// Err(-1) +// } +// } +// } \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/interface_token.rs b/interfaces/innerkits/rust/src/parcel/types/interface_token.rs index 5ef938345288d30a5922f6254634ff47a4ea4c53..35000fcb17d4a0cfe6bd82feb9fd0c3b1c046373 100644 --- a/interfaces/innerkits/rust/src/parcel/types/interface_token.rs +++ b/interfaces/innerkits/rust/src/parcel/types/interface_token.rs @@ -15,16 +15,18 @@ use super::*; use crate::{ipc_binding, BorrowedMsgParcel, Result, AsRawPtr, result_status}; -use std::ffi::{c_char, c_void}; use std::convert::TryInto; +/// InterfaceToken packed a String type which transfered with C++ std::u16string. pub struct InterfaceToken(String); impl InterfaceToken { + /// Create a InterfaceToken object by Rust String pub fn new(value: &str) -> Self { Self(String::from(value)) } + /// Get packed String of InterfaceToken pub fn get_token(&self) -> String { String::from(&self.0) } diff --git a/interfaces/innerkits/rust/src/parcel/types/option.rs b/interfaces/innerkits/rust/src/parcel/types/option.rs index ab3755a6fd051a4dc5e46c502acfdbb3bad69faf..748927a477b985ab80f10f5249f777868d83d867 100644 --- a/interfaces/innerkits/rust/src/parcel/types/option.rs +++ b/interfaces/innerkits/rust/src/parcel/types/option.rs @@ -14,7 +14,6 @@ */ use super::*; -use crate::{BorrowedMsgParcel, Result, SerOption, DeSerOption}; impl Serialize for Option { fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { @@ -22,8 +21,11 @@ impl Serialize for Option { } } -impl Deserialize for Option { +impl Deserialize for Option { fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> Result { - DeSerOption::de_option(parcel) + DeOption::de_option(parcel) } } + +// impl DeArray for Option {} +// impl SerArray for Option {} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/slices.rs b/interfaces/innerkits/rust/src/parcel/types/slices.rs index 8f29ad3fd9004a04cfcfcd6fd0c1a22b11b3b51f..cf98af9cd2e527ffeab5cf730681f8fa099d4c04 100644 --- a/interfaces/innerkits/rust/src/parcel/types/slices.rs +++ b/interfaces/innerkits/rust/src/parcel/types/slices.rs @@ -13,4 +13,22 @@ * limitations under the License. */ -// TODO \ No newline at end of file +use super::*; +use crate::{ipc_binding, BorrowedMsgParcel, AsRawPtr, result_status, Result}; + + +impl Serialize for [T] { + fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { + SerArray::ser_array(self, parcel) + } +} + +impl SerOption for [T] { + fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { + if let Some(v) = this { + SerArray::ser_array(v, parcel) + } else { + parcel.write(&-1i32) + } + } +} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/string16.rs b/interfaces/innerkits/rust/src/parcel/types/string16.rs index 88e1995b81b0ccc74fc45cc131cd50ddf720a1f9..a36ea4b7ef5125cf5a219c71a49c9bc5ad20ff3f 100644 --- a/interfaces/innerkits/rust/src/parcel/types/string16.rs +++ b/interfaces/innerkits/rust/src/parcel/types/string16.rs @@ -15,16 +15,18 @@ use super::*; use crate::{ipc_binding, BorrowedMsgParcel, Result, result_status, AsRawPtr}; -use std::ffi::{c_char, c_void}; use std::convert::TryInto; +/// String16 packed a String type which transfered with C++ std::u16string. pub struct String16(String); impl String16 { + /// Create a String16 object with rust String pub fn new(value: &str) -> Self { Self(String::from(value)) } + /// Get packed String of String16 pub fn get_string(&self) -> String { String::from(&self.0) } diff --git a/interfaces/innerkits/rust/src/parcel/types/strings.rs b/interfaces/innerkits/rust/src/parcel/types/strings.rs index fc32e869257f3b9c835d134cb0f7e6fa82df2930..16605dde85d48c4bf6b8b0b55e52f571c709b24e 100644 --- a/interfaces/innerkits/rust/src/parcel/types/strings.rs +++ b/interfaces/innerkits/rust/src/parcel/types/strings.rs @@ -20,7 +20,6 @@ use crate::{ }; use std::ptr; use std::convert::TryInto; -use std::ffi::{c_char, c_void}; impl SerOption for str { fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { diff --git a/interfaces/innerkits/rust/src/parcel/types/vector.rs b/interfaces/innerkits/rust/src/parcel/types/vector.rs index 5b27a97d5635fefb7c25708aae6a7702c086442f..c9a0151f42780e68205aaaf13378735a1851dfca 100644 --- a/interfaces/innerkits/rust/src/parcel/types/vector.rs +++ b/interfaces/innerkits/rust/src/parcel/types/vector.rs @@ -15,4 +15,29 @@ use super::*; -// TODO \ No newline at end of file + +impl Serialize for Vec { + fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { + SerArray::ser_array(&self[..], parcel) + } +} + +impl SerOption for Vec { + fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> { + SerOption::ser_option(this.map(Vec::as_slice), parcel) + } +} + +impl Deserialize for Vec { + fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> Result { + DeArray::de_array(parcel) + .transpose() + .unwrap_or(Err(-1)) + } +} + +impl DeOption for Vec { + fn de_option(parcel: &BorrowedMsgParcel<'_>) -> Result> { + DeArray::de_array(parcel) + } +} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/process.rs b/interfaces/innerkits/rust/src/process.rs index f29ba9a419e319acae98488b75c495b286545610..ed32bcf8b8f9f560e3452302008d3d2d7c5dff75 100644 --- a/interfaces/innerkits/rust/src/process.rs +++ b/interfaces/innerkits/rust/src/process.rs @@ -26,35 +26,38 @@ fn get_samgr() -> Option } } +/// Add a service to samgr pub fn add_service(service: &RemoteObj, said: i32) -> Result<()> { let samgr = get_samgr().expect("samgr is not null"); let mut data = MsgParcel::new().expect("MsgParcel is not null"); - let _ = data.write(&InterfaceToken::new("ohos.samgr.accessToken"))?; - let _ = data.write(&said)?; - let _ = data.write(service)?; - let _ = data.write(&false)?; - let _ = data.write(&0)?; - let _ = data.write(&String16::new(""))?; - let _ = data.write(&String16::new(""))?; + data.write(&InterfaceToken::new("ohos.samgr.accessToken"))?; + data.write(&said)?; + data.write(service)?; + data.write(&false)?; + data.write(&0)?; + data.write(&String16::new(""))?; + data.write(&String16::new(""))?; let reply = samgr.send_request(3, &data, false)?; - let replyValue: i32 = reply.read()?; - println!("register service result: {}", replyValue); - if replyValue == 0 { Ok(())} else { Err(replyValue) } + let reply_value: i32 = reply.read()?; + println!("register service result: {}", reply_value); + if reply_value == 0 { Ok(())} else { Err(reply_value) } } +/// Get a service proxy from samgr pub fn get_service(said: i32) -> Result { let samgr = get_samgr().expect("samgr is not null"); let mut data = MsgParcel::new().expect("MsgParcel is not null"); - let _ = data.write(&InterfaceToken::new("ohos.samgr.accessToken"))?; - let _ = data.write(&said)?; + data.write(&InterfaceToken::new("ohos.samgr.accessToken"))?; + data.write(&said)?; let reply = samgr.send_request(2, &data, false)?; let remote: RemoteObj = reply.read()?; println!("get service success"); Ok(remote) } +/// Make current thread join to the IPC/RPC work thread pool pub fn join_work_thread() { unsafe { @@ -62,6 +65,7 @@ pub fn join_work_thread() } } +/// Exit current thread from IPC/RPC work thread pool pub fn stop_work_thread() { unsafe { @@ -69,13 +73,7 @@ pub fn stop_work_thread() } } -pub fn init_access_token() -{ - unsafe { - ipc_binding::InitTokenId(); - } -} - +/// Get calling token ID of caller pub fn get_calling_token_id() -> u64 { unsafe { @@ -83,6 +81,7 @@ pub fn get_calling_token_id() -> u64 } } +/// Get first calling token ID of caller pub fn get_first_token_id() -> u64 { unsafe { @@ -90,6 +89,7 @@ pub fn get_first_token_id() -> u64 } } +/// Get self token id of current process pub fn get_self_token_id() -> u64 { unsafe { @@ -97,6 +97,7 @@ pub fn get_self_token_id() -> u64 } } +/// Get calling process id of caller pub fn get_calling_pid() -> u64 { unsafe { @@ -104,6 +105,7 @@ pub fn get_calling_pid() -> u64 } } +/// Get calling user id of caller pub fn get_calling_uid() -> u64 { unsafe { diff --git a/interfaces/innerkits/rust/tests/server/src/main.rs b/interfaces/innerkits/rust/tests/server/src/main.rs deleted file mode 100644 index 9915b72b090c806198c09fd0b8a920e8057ea2c6..0000000000000000000000000000000000000000 --- a/interfaces/innerkits/rust/tests/server/src/main.rs +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * 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. - */ - -extern crate ipc_rust; -extern crate test_ipc_service; - -use ipc_rust::{ - IRemoteBroker, join_work_thread, FileDesc, InterfaceToken, Result, - add_service, init_access_token, get_calling_token_id, get_first_token_id, - get_calling_pid, get_calling_uid, -}; -use test_ipc_service::{ITest, TestStub, IPC_TEST_SERVICE_ID}; -use std::io::{Read, Seek, SeekFrom}; -use std::fs::File; - -pub struct TestService; - -impl ITest for TestService { - fn echo_str(&self, value: &str) -> String { - println!("TestService echo_str: {}", value); - String::from(value) - } - - fn request_concurent(&self, is_async: bool) -> bool { - println!("TestService request_concurent: {}", is_async); - true - } - - fn pass_file(&self, fd: FileDesc) -> String { - let mut info = String::new(); - let mut file = File::from(fd); - file.seek(SeekFrom::Start(0)); - file.read_to_string(&mut info).expect("The string cannot be read"); - println!("file content: {}", info); - info - } - - fn echo_interface_token(&self, token: &InterfaceToken) -> Result { - Ok(InterfaceToken::new(&token.get_token())) - } - - fn echo_calling_info(&self) -> Result<(u64, u64, u64, u64)> { - let token_id = get_calling_token_id(); - let first_token_id = get_first_token_id(); - let pid = get_calling_pid(); - let uid = get_calling_uid(); - println!("{}, {}, {}, {}", token_id, first_token_id, pid, uid); - Ok((token_id, first_token_id, pid, uid)) - } -} - -impl IRemoteBroker for TestService {} - -fn main() { - init_access_token(); - // create stub - let service = TestStub::new_remote_stub(TestService).expect("create TestService success"); - add_service(&service.as_object().expect("get ITest service failed"), - IPC_TEST_SERVICE_ID); - println!("join to ipc work thread"); - join_work_thread(); -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/tests/service.rs b/interfaces/innerkits/rust/tests/service.rs deleted file mode 100644 index 8871086188b0814c57be9fe84d24bccb374fe5d5..0000000000000000000000000000000000000000 --- a/interfaces/innerkits/rust/tests/service.rs +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * 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. - */ - -extern crate ipc_rust; - -// Import types -use ipc_rust::{IRemoteBroker, RemoteStub, define_remote_object}; -use ipc_rust::{MsgParcel, BorrowedMsgParcel}; - -pub trait ITest: IRemoteBroker { - fn hello(&self, greeting: &str) -> String; -} - -fn on_remote_request(stub: &dyn ITest, code: u32, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> i32 { - match code { - 1 => { - println!("TestStub hello: {}", stub.hello("hello")); - 0 - } - _ => -1 - } -} - -define_remote_object!( - ITest["ohos.ipc.test"] { - stub: TestStub(on_remote_request), - proxy: TestProxy, - } -); - -// Make RemoteStub object can call ITest function directly. -impl ITest for RemoteStub { - fn hello(&self, greeting: &str) -> String { - // self will be convert to TestStub automatic because RemoteStub - // implement the Deref trait - self.0.hello(greeting) - } -} - -impl ITest for TestProxy { - fn hello(&self, _greeting: &str) -> String { - let data = MsgParcel::new().expect("MsgParcel should success"); - let reply = - self.remote.send_request(1, &data, false); - match reply { - Ok(reply) => { - println!("send hello ipc request success"); - } - Err(error) => { - println!("send hello ipc request fail: {}", error); - } - }; - String::from("hello") - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/tests/service/src/lib.rs b/interfaces/innerkits/rust/tests/service/src/lib.rs deleted file mode 100644 index 696e9d9f1ee14681565f8c0e95ef0e04e30e9dd2..0000000000000000000000000000000000000000 --- a/interfaces/innerkits/rust/tests/service/src/lib.rs +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * 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. - */ - -extern crate ipc_rust; - -// Import types -// use std::convert::{TryFrom, TryInto}; -use ipc_rust::{ - IRemoteBroker, IRemoteObj, RemoteStub, Result, - RemoteObj, define_remote_object, FIRST_CALL_TRANSACTION -}; -use ipc_rust::{ - MsgParcel, BorrowedMsgParcel, FileDesc, InterfaceToken, -}; - -pub const IPC_TEST_SERVICE_ID: i32 = 1118; - -pub enum ITestCode { - CodeEchoStr = FIRST_CALL_TRANSACTION, - CodeRequestConcurrent = 2, - CodePassFd = 3, - CodeInterfaceToekn = 4, - CodeCallingInfo = 5, -} - -pub trait ITest: IRemoteBroker { - fn echo_str(&self, value: &str) -> String; - fn request_concurent(&self, is_async: bool) -> bool; - fn pass_file(&self, fd: FileDesc) -> String; - fn echo_interface_token(&self, token: &InterfaceToken) -> Result; - fn echo_calling_info(&self) -> Result<(u64, u64, u64, u64)>; -} - -fn on_remote_request(stub: &dyn ITest, code: u32, data: &BorrowedMsgParcel, - reply: &mut BorrowedMsgParcel) -> Result<()> { - println!("on_remote_reuqest in Rust TestStub, code: {}", code); - match code { - 1 => { - let value: String = data.read().expect("should have a string"); - let value = stub.echo_str(&value); - reply.write(&value); - Ok(()) - } - 2 => { - stub.request_concurent(true); - Ok(()) - } - 3 => { - let fd: FileDesc = data.read().expect("should have a fd"); - let value = stub.pass_file(fd); - reply.write(&value); - Ok(()) - } - 4 => { - let token: InterfaceToken = data.read().expect("should have a interface token"); - let value = stub.echo_interface_token(&token).expect("service deal echo token failed"); - reply.write(&value).expect("write echo token result failed"); - Ok(()) - } - 5 => { - let (token_id, first_token_id, pid, uid) = stub.echo_calling_info()?; - reply.write(&token_id).expect("write token id failed"); - reply.write(&first_token_id).expect("write first token id failed"); - reply.write(&pid).expect("write pid failed"); - reply.write(&uid).expect("write uid failed"); - Ok(()) - } - _ => Err(-1) - } -} - -define_remote_object!( - ITest["ohos.ipc.test"] { - stub: TestStub(on_remote_request), - proxy: TestProxy, - } -); - -// Make RemoteStub object can call ITest function directly. -impl ITest for RemoteStub { - fn echo_str(&self, value: &str) -> String { - // self will be convert to TestStub automatic because RemoteStub - // implement the Deref trait - self.0.echo_str(value) - } - - fn request_concurent(&self, is_async: bool) -> bool { - self.0.request_concurent(is_async) - } - - fn pass_file(&self, fd: FileDesc) -> String { - self.0.pass_file(fd) - } - - fn echo_interface_token(&self, token: &InterfaceToken) -> Result { - self.0.echo_interface_token(token) - } - - fn echo_calling_info(&self) -> Result<(u64, u64, u64, u64)> { - self.0.echo_calling_info() - } -} - -impl ITest for TestProxy { - fn echo_str(&self, value: &str) -> String { - let mut data = MsgParcel::new().expect("MsgParcel should success"); - data.write(value); - let reply = - self.remote.send_request(ITestCode::CodeEchoStr as u32, &data, false); - match reply { - Ok(reply) => { - let echo_value: String = reply.read().expect("need reply value"); - echo_value - } - Err(_) => { - String::from("Error") - } - } - } - - fn request_concurent(&self, is_async: bool) -> bool { - let mut data = MsgParcel::new().expect("MsgParcel should success"); - let reply = - self.remote.send_request(ITestCode::CodeRequestConcurrent as u32, &data, is_async); - match reply { - Ok(_) => true, - Err(_) => false - } - } - - fn pass_file(&self, fd: FileDesc) -> String { - let mut data = MsgParcel::new().expect("MsgParcel should success"); - data.write(&fd).expect("write fd should success"); - let reply = - self.remote.send_request(ITestCode::CodePassFd as u32, &data, false); - match reply { - Ok(reply) => { - let echo_value: String = reply.read().expect("need reply value"); - echo_value - } - Err(_) => { - String::from("Error") - } - } - } - - fn echo_interface_token(&self, token: &InterfaceToken) -> Result { - let mut data = MsgParcel::new().expect("MsgParcel should success"); - data.write(token).expect("write token should success"); - let reply = self.remote.send_request(ITestCode::CodeInterfaceToekn as u32, - &data, false)?; - let echo_value: InterfaceToken = reply.read().expect("need reply token"); - Ok(echo_value) - } - - fn echo_calling_info(&self) -> Result<(u64, u64, u64, u64)> { - let mut data = MsgParcel::new().expect("MsgParcel should success"); - let reply = self.remote.send_request(ITestCode::CodeCallingInfo as u32, - &data, false)?; - let token_id: u64 = reply.read().expect("need reply calling token id"); - let first_token_id: u64 = reply.read().expect("need reply first calling token id"); - let pid: u64 = reply.read().expect("need reply calling pid"); - let uid: u64 = reply.read().expect("need reply calling uid"); - Ok((token_id, first_token_id, pid, uid)) - } -} \ No newline at end of file diff --git a/ipc/native/src/c_wrapper/include/c_parcel.h b/ipc/native/src/c_wrapper/include/c_parcel.h index 821157dac69ba5338f7b13809dfb93dffa30872f..cfca8f412596c607853120389c30f90cc8015a03 100644 --- a/ipc/native/src/c_wrapper/include/c_parcel.h +++ b/ipc/native/src/c_wrapper/include/c_parcel.h @@ -59,6 +59,8 @@ bool CParcelWriteRemoteObject(CParcel *parcel, const CRemoteObject *object); CRemoteObject *CParcelReadRemoteObject(const CParcel *parcel); bool CParcelWriteFileDescriptor(CParcel *parcel, int32_t fd); bool CParcelReadFileDescriptor(const CParcel *parcel, int32_t *fd); +bool CParcelWriteBuffer(CParcel *parcel, const uint8_t *buffer, uint32_t len); +bool CParcelReadBuffer(const CParcel *parcel, uint8_t *value, uint32_t len); uint32_t CParcelGetDataSize(const CParcel *parcel); bool CParcelSetDataSize(CParcel *parcel, uint32_t new_size); diff --git a/ipc/native/src/c_wrapper/include/c_process.h b/ipc/native/src/c_wrapper/include/c_process.h index c61d24602daad7d787fb13f146a6b0d01ecb1775..7a7585e587184ddead58c6ed46cec0fbe8cffbad 100644 --- a/ipc/native/src/c_wrapper/include/c_process.h +++ b/ipc/native/src/c_wrapper/include/c_process.h @@ -27,7 +27,6 @@ CRemoteObject *GetContextManager(void); void JoinWorkThread(void); void StopWorkThread(void); -void InitTokenId(void); uint64_t GetCallingTokenId(void); uint64_t GetFirstToekenId(void); uint64_t GetSelfToekenId(void); diff --git a/ipc/native/src/c_wrapper/source/c_parcel.cpp b/ipc/native/src/c_wrapper/source/c_parcel.cpp index 8c6d5ca8c55632761b005c66d48b8b0a197ef444..5e2b4705c56c9af15828f0a7449dc228932beea5 100644 --- a/ipc/native/src/c_wrapper/source/c_parcel.cpp +++ b/ipc/native/src/c_wrapper/source/c_parcel.cpp @@ -274,7 +274,7 @@ bool CParcelReadString16(const CParcel *parcel, void *stringData, OnCParcelBytes } std::string value = Str16ToStr8(u16string); if (u16string.length() != 0 && value.length() == 0) { - printf("%s: u16string len: %u, string len: %u\n", __func__, u16string.length(), value.length()); + printf("%s: u16string len: %lu, string len: %lu\n", __func__, u16string.length(), value.length()); return false; } char *buffer = nullptr; @@ -315,7 +315,7 @@ bool CParcelReadInterfaceToken(const CParcel *parcel, void *token, OnCParcelByte std::u16string u16string = parcel->parcel_->ReadInterfaceToken(); std::string value = Str16ToStr8(u16string); if (u16string.length() != 0 && value.length() == 0) { - printf("%s: u16string len: %u, string len: %u\n", __func__, u16string.length(), value.length()); + printf("%s: u16string len: %lu, string len: %lu\n", __func__, u16string.length(), value.length()); return false; } printf("%s: c read interface token: %s\n", __func__, value.c_str()); @@ -386,6 +386,35 @@ bool CParcelReadFileDescriptor(const CParcel *parcel, int32_t *fd) return (*fd < 0) ? false : true; } +bool CParcelWriteBuffer(CParcel *parcel, const uint8_t *buffer, uint32_t len) +{ + if (!IsValidParcel(parcel, __func__)) { + return false; + } + if (buffer == nullptr) { + printf("%s: buffer is null: %d\n", __func__, len); + return false; + } + return parcel->parcel_->WriteBuffer(buffer, len); +} + +bool CParcelReadBuffer(const CParcel *parcel, uint8_t *value, uint32_t len) +{ + if (!IsValidParcel(parcel, __func__) || value == nullptr) { + return false; + } + const uint8_t *data = parcel->parcel_->ReadBuffer(len); + if (data == nullptr) { + printf("%s: read buffer failed\n", __func__); + return false; + } + if (len > 0 && memcpy_s(value, len, data, len) != EOK) { + printf("%s: copy buffer failed\n", __func__); + return false; + } + return true; +} + uint32_t CParcelGetDataSize(const CParcel *parcel) { if (!IsValidParcel(parcel, __func__)) { diff --git a/ipc/native/src/c_wrapper/source/c_process.cpp b/ipc/native/src/c_wrapper/source/c_process.cpp index 2d44173ade38789af14bf40e99e5a98441a1aa53..605675618f41e9ba5fb3070197e45853322bd562 100644 --- a/ipc/native/src/c_wrapper/source/c_process.cpp +++ b/ipc/native/src/c_wrapper/source/c_process.cpp @@ -15,8 +15,6 @@ #include "c_process.h" -#include -#include #include "c_remote_object_internal.h" #include "ipc_skeleton.h" @@ -48,23 +46,6 @@ void StopWorkThread(void) IPCSkeleton::StopWorkThread(); } -void InitTokenId(void) -{ - uint64_t tokenId; - NativeTokenInfoParams infoInstance = { - .dcapsNum = 0, - .permsNum = 0, - .aclsNum = 0, - .dcaps = NULL, - .perms = NULL, - .acls = NULL, - .processName = "com.ipc.test", - .aplStr = "normal", - }; - tokenId = GetAccessTokenId(&infoInstance); - SetSelfTokenID(tokenId); -} - uint64_t GetCallingTokenId(void) { return IPCSkeleton::GetCallingFullTokenID(); diff --git a/ipc/native/src/c_wrapper/source/c_remote_object.cpp b/ipc/native/src/c_wrapper/source/c_remote_object.cpp index 4cc976b78b13a32d295ee3a12ea91cfc2e1feb12..d19ab96db9ab1644eef93a2b2734f1a8363e4509 100644 --- a/ipc/native/src/c_wrapper/source/c_remote_object.cpp +++ b/ipc/native/src/c_wrapper/source/c_remote_object.cpp @@ -163,7 +163,7 @@ bool RemoteObjectLessThan(const CRemoteObject *lhs, const CRemoteObject *rhs) int RemoteObjectSendRequest(const CRemoteObject *object, uint32_t code, const CParcel *data, CParcel *reply, bool isAsync) { - if (!IsValidRemoteObject(object, __func__) || data == nullptr) { + if (!IsValidRemoteObject(object, __func__) || data == nullptr || reply == nullptr) { printf("%s: object and data must be not null\n", __func__); return -EINVAL; } @@ -180,7 +180,7 @@ CDeathRecipient *CreateDeathRecipient(OnDeathRecipientCb onDeathRecipient, } CDeathRecipient *recipient = new (std::nothrow) CDeathRecipient(onDeathRecipient, onDestroy, userData); - if (userData == nullptr) { + if (recipient == nullptr) { printf("%s: create CDeathRecipient object failed\n", __func__); return nullptr; } diff --git a/ipc/native/test/BUILD.gn b/ipc/native/test/BUILD.gn index 7b510763745fe57f1f6a48d999e6315f022630d7..3e9d32519218b29864baa3b380f5a0406102e2c3 100644 --- a/ipc/native/test/BUILD.gn +++ b/ipc/native/test/BUILD.gn @@ -18,5 +18,8 @@ import("//build/test.gni") group("unittest") { testonly = true deps = [ "unittest/common:unittest" ] + if (target_cpu == "arm64") { + deps += [ "unittest/rust:unittest" ] + } } ############################################################################### diff --git a/ipc/native/test/unittest/common/BUILD.gn b/ipc/native/test/unittest/common/BUILD.gn index fc4357ffd23eaff1f772521283e0161589afc7cf..0df7e8e98d73c60712e2b5e2b405e903afa06802 100644 --- a/ipc/native/test/unittest/common/BUILD.gn +++ b/ipc/native/test/unittest/common/BUILD.gn @@ -334,6 +334,42 @@ ohos_unittest("RPCFeatureUnitTest") { "//foundation/communication/ipc/test/resource/ipc/ohos_test.xml" } +if (target_cpu == "arm64") { + ohos_unittest("IPCCInterfaceUnitTest") { + module_out_path = MODULE_OUTPUT_PATH + + include_dirs = [ + "//commonlibrary/c_utils/base/include", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core/include", + "//foundation/communication/ipc/ipc/native/src/c_wrapper/include", + ] + + sources = [ + "ipc_c_message_parcel_unittest.cpp", + "ipc_c_process_unittest.cpp", + "ipc_c_remote_object_unittest.cpp", + ] + + configs = [ + "$SUBSYSTEM_DIR:ipc_util_config", + "$IPC_TEST_ROOT:ipc_test_config", + ] + + deps = [ + "//base/security/access_token/interfaces/innerkits/nativetoken:libnativetoken", + "//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc", + "//foundation/communication/ipc/interfaces/innerkits/rust:ipc_c", + "//third_party/googletest:gmock_main", + "//third_party/googletest:gtest_main", + ] + + external_deps = [ "c_utils:utils" ] + + resource_config_file = + "//foundation/communication/ipc/test/resource/ipc/ohos_test.xml" + } +} + ############################################################################### group("unittest") { testonly = true @@ -347,6 +383,9 @@ group("unittest") { ":InvokerFactoryTest", ":RPCFeatureUnitTest", ] + if (target_cpu == "arm64") { + deps += [ ":IPCCInterfaceUnitTest" ] + } if (support_jsapi) { deps += [ ":IPCNapiUnitTest" ] } diff --git a/ipc/native/test/unittest/common/ipc_c_message_parcel_unittest.cpp b/ipc/native/test/unittest/common/ipc_c_message_parcel_unittest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83fc6d15e3b45f0ce842299f9b7bb7b78cfb05a6 --- /dev/null +++ b/ipc/native/test/unittest/common/ipc_c_message_parcel_unittest.cpp @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include + +#include +#include "c_parcel.h" +#include "c_parcel_internal.h" + +using namespace testing::ext; +using namespace OHOS; + +static const int NUMBER_CONSTANT = 100; +static const float FLOAT_CONSTANT = 1.1; +static const char *STRING_CONSTATN = "HELLO"; + +class IpcCMessageParcelUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void IpcCMessageParcelUnitTest::SetUpTestCase() +{} + +void IpcCMessageParcelUnitTest::TearDownTestCase() +{} + +void IpcCMessageParcelUnitTest::SetUp() +{} + +void IpcCMessageParcelUnitTest::TearDown() +{} + +static bool CParcelBytesAllocatorOk(void *stringData, char **buffer, int32_t len) +{ + if (buffer == nullptr || len < 0) { + return false; + } + *buffer = (char *)malloc(len); + if (*buffer == nullptr) { + return false; + } + void **ptr = reinterpret_cast(stringData); + if (ptr != nullptr) { + *ptr = *buffer; + } + return true; +} + +static bool CParcelBytesAllocatorErr(void *stringData, char **buffer, int32_t len) +{ + (void)stringData; + (void)buffer; + (void)len; + return false; +} + +/** + * @tc.name: CParcelRefCount + * @tc.desc: Verify the CParcel reference count functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelRefCount, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + RefBase *ref = static_cast(parcel); + EXPECT_EQ(ref->GetSptrRefCount(), 1); + CParcelIncStrongRef(parcel); + EXPECT_EQ(ref->GetSptrRefCount(), 2); + CParcelDecStrongRef(parcel); + EXPECT_EQ(ref->GetSptrRefCount(), 1); + CParcelIncStrongRef(nullptr); + CParcelDecStrongRef(nullptr); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelBool + * @tc.desc: Verify the CParcel for bool type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelBool, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + EXPECT_EQ(CParcelWriteBool(nullptr, true), false); + EXPECT_EQ(CParcelWriteBool(parcel, false), true); + EXPECT_EQ(CParcelWriteBool(parcel, true), true); + bool bool_val = true; + EXPECT_EQ(CParcelReadBool(nullptr, &bool_val), false); + EXPECT_EQ(CParcelReadBool(parcel, nullptr), false); + EXPECT_EQ(CParcelReadBool(parcel, &bool_val), true); + EXPECT_EQ(bool_val, false); + EXPECT_EQ(CParcelReadBool(parcel, &bool_val), true); + EXPECT_EQ(bool_val, true); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelInt8 + * @tc.desc: Verify the CParcel for int8_t type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelInt8, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + int8_t int8_val = static_cast(NUMBER_CONSTANT); + EXPECT_EQ(CParcelWriteInt8(nullptr, int8_val), false); + EXPECT_EQ(CParcelWriteInt8(parcel, int8_val), true); + EXPECT_EQ(CParcelReadInt8(nullptr, &int8_val), false); + EXPECT_EQ(CParcelReadInt8(parcel, nullptr), false); + EXPECT_EQ(CParcelReadInt8(parcel, &int8_val), true); + EXPECT_EQ(int8_val, static_cast(NUMBER_CONSTANT)); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelInt16 + * @tc.desc: Verify the CParcel for int16_t type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelInt16, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + int16_t int16_val = static_cast(NUMBER_CONSTANT); + EXPECT_EQ(CParcelWriteInt16(nullptr, int16_val), false); + EXPECT_EQ(CParcelWriteInt16(parcel, int16_val), true); + EXPECT_EQ(CParcelReadInt16(nullptr, &int16_val), false); + EXPECT_EQ(CParcelReadInt16(parcel, nullptr), false); + EXPECT_EQ(CParcelReadInt16(parcel, &int16_val), true); + EXPECT_EQ(int16_val, static_cast(NUMBER_CONSTANT)); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelInt32 + * @tc.desc: Verify the CParcel for int32_t type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelInt32, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + int32_t int32_val = static_cast(NUMBER_CONSTANT); + EXPECT_EQ(CParcelWriteInt32(nullptr, int32_val), false); + EXPECT_EQ(CParcelWriteInt32(parcel, int32_val), true); + EXPECT_EQ(CParcelReadInt32(nullptr, &int32_val), false); + EXPECT_EQ(CParcelReadInt32(parcel, nullptr), false); + EXPECT_EQ(CParcelReadInt32(parcel, &int32_val), true); + EXPECT_EQ(int32_val, static_cast(NUMBER_CONSTANT)); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelInt64 + * @tc.desc: Verify the CParcel for int32_t type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelInt64, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + int64_t int64_val = static_cast(NUMBER_CONSTANT); + EXPECT_EQ(CParcelWriteInt64(nullptr, int64_val), false); + EXPECT_EQ(CParcelWriteInt64(parcel, int64_val), true); + EXPECT_EQ(CParcelReadInt64(nullptr, &int64_val), false); + EXPECT_EQ(CParcelReadInt64(parcel, nullptr), false); + EXPECT_EQ(CParcelReadInt64(parcel, &int64_val), true); + EXPECT_EQ(int64_val, static_cast(NUMBER_CONSTANT)); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelFloat + * @tc.desc: Verify the CParcel for float type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelFloat, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + float float_val = static_cast(FLOAT_CONSTANT); + EXPECT_EQ(CParcelWriteFloat(nullptr, float_val), false); + EXPECT_EQ(CParcelWriteFloat(parcel, float_val), true); + EXPECT_EQ(CParcelReadFloat(nullptr, &float_val), false); + EXPECT_EQ(CParcelReadFloat(parcel, nullptr), false); + EXPECT_EQ(CParcelReadFloat(parcel, &float_val), true); + EXPECT_TRUE(abs(float_val - static_cast(FLOAT_CONSTANT)) < 0.0001); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelDouble + * @tc.desc: Verify the CParcel for double type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelDouble, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + double double_val = static_cast(FLOAT_CONSTANT); + EXPECT_EQ(CParcelWriteDouble(nullptr, double_val), false); + EXPECT_EQ(CParcelWriteDouble(parcel, double_val), true); + EXPECT_EQ(CParcelReadDouble(nullptr, &double_val), false); + EXPECT_EQ(CParcelReadDouble(parcel, nullptr), false); + EXPECT_EQ(CParcelReadDouble(parcel, &double_val), true); + EXPECT_TRUE(abs(double_val - static_cast(FLOAT_CONSTANT)) < 0.0001); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelString001 + * @tc.desc: Verify the CParcel for string type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelString001, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + void *data = nullptr; + EXPECT_EQ(CParcelReadString(parcel, reinterpret_cast(&data), CParcelBytesAllocatorOk), false); + + EXPECT_EQ(CParcelWriteString(nullptr, STRING_CONSTATN, strlen(STRING_CONSTATN)), false); + EXPECT_EQ(CParcelWriteString(parcel, nullptr, strlen(STRING_CONSTATN)), false); + EXPECT_EQ(CParcelWriteString(parcel, STRING_CONSTATN, -1), false); + EXPECT_EQ(CParcelWriteString(parcel, STRING_CONSTATN, strlen(STRING_CONSTATN)), true); + EXPECT_EQ(CParcelWriteString(parcel, nullptr, -1), true); + + EXPECT_EQ(CParcelReadString(nullptr, reinterpret_cast(&data), nullptr), false); + EXPECT_EQ(CParcelReadString(parcel, reinterpret_cast(&data), CParcelBytesAllocatorOk), true); + EXPECT_EQ(strncmp((reinterpret_cast(data)), STRING_CONSTATN, strlen(STRING_CONSTATN)), 0); + if (data != nullptr) { + free(data); + } + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelString002 + * @tc.desc: Verify the CParcel for string type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelString002, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + EXPECT_EQ(CParcelWriteString(parcel, STRING_CONSTATN, strlen(STRING_CONSTATN)), true); + void *data = nullptr; + EXPECT_EQ(CParcelReadString(parcel, reinterpret_cast(&data), CParcelBytesAllocatorErr), false); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelString16001 + * @tc.desc: Verify the CParcel for string16 type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelString16001, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + void *data = nullptr; + EXPECT_EQ(CParcelReadString16(parcel, reinterpret_cast(&data), CParcelBytesAllocatorOk), false); + + EXPECT_EQ(CParcelWriteString16(nullptr, STRING_CONSTATN, strlen(STRING_CONSTATN)), false); + EXPECT_EQ(CParcelWriteString16(parcel, nullptr, strlen(STRING_CONSTATN)), false); + EXPECT_EQ(CParcelWriteString16(parcel, STRING_CONSTATN, -1), false); + EXPECT_EQ(CParcelWriteString16(parcel, STRING_CONSTATN, strlen(STRING_CONSTATN)), true); + EXPECT_EQ(CParcelWriteString16(parcel, nullptr, -1), true); + + EXPECT_EQ(CParcelReadString16(nullptr, reinterpret_cast(&data), nullptr), false); + EXPECT_EQ(CParcelReadString16(parcel, reinterpret_cast(&data), CParcelBytesAllocatorOk), true); + EXPECT_EQ(strncmp((reinterpret_cast(data)), STRING_CONSTATN, strlen(STRING_CONSTATN)), 0); + if (data != nullptr) { + free(data); + } + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelString16002 + * @tc.desc: Verify the CParcel for string16 type functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelString16002, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + EXPECT_EQ(CParcelWriteString16(parcel, STRING_CONSTATN, strlen(STRING_CONSTATN)), true); + void *data = nullptr; + EXPECT_EQ(CParcelReadString16(parcel, reinterpret_cast(&data), CParcelBytesAllocatorErr), false); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelInterfaceToken001 + * @tc.desc: Verify the CParcel for interface token functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelInterfaceToken001, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + void *data = nullptr; + + EXPECT_EQ(CParcelWriteInterfaceToken(nullptr, STRING_CONSTATN, strlen(STRING_CONSTATN)), false); + EXPECT_EQ(CParcelWriteInterfaceToken(parcel, nullptr, strlen(STRING_CONSTATN)), false); + EXPECT_EQ(CParcelWriteInterfaceToken(parcel, STRING_CONSTATN, strlen(STRING_CONSTATN)), true); + + EXPECT_EQ(CParcelReadInterfaceToken(nullptr, reinterpret_cast(&data), nullptr), false); + EXPECT_EQ(CParcelReadInterfaceToken(parcel, reinterpret_cast(&data), CParcelBytesAllocatorOk), true); + EXPECT_EQ(strncmp((reinterpret_cast(data)), STRING_CONSTATN, strlen(STRING_CONSTATN)), 0); + if (data != nullptr) { + free(data); + } + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelInterfaceToken002 + * @tc.desc: Verify the CParcel for interface token functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelInterfaceToken002, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + EXPECT_EQ(CParcelWriteInterfaceToken(parcel, STRING_CONSTATN, strlen(STRING_CONSTATN)), true); + void *data = nullptr; + EXPECT_EQ(CParcelReadInterfaceToken(parcel, reinterpret_cast(&data), CParcelBytesAllocatorErr), false); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelFileDescriptor + * @tc.desc: Verify the CParcel for file descriptor functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelFileDescriptor, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + + int32_t fd = open("/dev/null", O_RDONLY); + EXPECT_TRUE(fd >= 0); + EXPECT_EQ(CParcelWriteFileDescriptor(nullptr, fd), false); + EXPECT_EQ(CParcelWriteFileDescriptor(parcel, fd), true); + + int32_t ret_fd; + EXPECT_EQ(CParcelReadFileDescriptor(nullptr, &ret_fd), false); + EXPECT_EQ(CParcelReadFileDescriptor(parcel, nullptr), false); + EXPECT_EQ(CParcelReadFileDescriptor(parcel, &ret_fd), true); + EXPECT_TRUE(ret_fd > 0); + close(fd); + close(ret_fd); + // destroy the CParcel object + CParcelDecStrongRef(parcel); +} + +/** + * @tc.name: CParcelDataInfoNullCheck + * @tc.desc: Verify the CParcel data info null check + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelDataInfoNullCheck, TestSize.Level1) +{ + EXPECT_EQ(CParcelGetDataSize(nullptr), 0); + EXPECT_EQ(CParcelSetDataSize(nullptr, 0), false); + EXPECT_EQ(CParcelGetDataCapacity(nullptr), 0); + EXPECT_EQ(CParcelSetDataCapacity(nullptr, 0), false); + EXPECT_EQ(CParcelGetMaxCapacity(nullptr), 0); + EXPECT_EQ(CParcelSetMaxCapacity(nullptr, 0), false); + EXPECT_EQ(CParcelGetWritableBytes(nullptr), 0); + EXPECT_EQ(CParcelGetReadableBytes(nullptr), 0); + EXPECT_EQ(CParcelGetReadPosition(nullptr), 0); + EXPECT_EQ(CParcelGetWritePosition(nullptr), 0); + EXPECT_EQ(CParcelRewindRead(nullptr, 0), false); + EXPECT_EQ(CParcelRewindWrite(nullptr, 0), false); +} + +/** + * @tc.name: CParcelDataInfo + * @tc.desc: Verify the CParcel data info functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCMessageParcelUnitTest, CParcelDataInfo, TestSize.Level1) +{ + CParcel *parcel = CParcelObtain(); + EXPECT_NE(parcel, nullptr); + + uint32_t maxCapacity = CParcelGetMaxCapacity(parcel); + EXPECT_TRUE(maxCapacity > 0); + EXPECT_TRUE(CParcelSetMaxCapacity(parcel, maxCapacity + 1)); + EXPECT_EQ(CParcelGetMaxCapacity(parcel), maxCapacity + 1); + EXPECT_EQ(CParcelGetDataSize(parcel), 0); + EXPECT_EQ(CParcelGetDataCapacity(parcel), 0); + EXPECT_EQ(CParcelGetWritableBytes(parcel), 0); + EXPECT_EQ(CParcelGetReadableBytes(parcel), 0); + EXPECT_EQ(CParcelGetReadPosition(parcel), 0); + EXPECT_EQ(CParcelGetWritePosition(parcel), 0); + + EXPECT_TRUE(CParcelWriteInt32(parcel, 0)); + uint32_t dataSize = CParcelGetDataSize(parcel); + EXPECT_TRUE(dataSize > 0); + EXPECT_TRUE(CParcelGetDataCapacity(parcel) > 0); + EXPECT_TRUE(CParcelGetWritableBytes(parcel) > 0); + EXPECT_TRUE(CParcelGetReadableBytes(parcel) > 0); + EXPECT_TRUE(CParcelGetReadPosition(parcel) == 0); + EXPECT_TRUE(CParcelGetWritePosition(parcel) > 0); + + int32_t value; + EXPECT_TRUE(CParcelReadInt32(parcel, &value)); + EXPECT_EQ(CParcelGetReadableBytes(parcel), 0); + EXPECT_TRUE(CParcelGetReadPosition(parcel) > 0); + + EXPECT_TRUE(CParcelSetDataSize(parcel, dataSize - 1)); + EXPECT_TRUE(CParcelSetDataCapacity(parcel, dataSize + 1)); + EXPECT_TRUE(CParcelRewindRead(parcel, 0)); + EXPECT_TRUE(CParcelRewindWrite(parcel, 0)); + EXPECT_EQ(CParcelGetDataSize(parcel), 0); + EXPECT_TRUE(CParcelGetDataCapacity(parcel) > 0); + EXPECT_TRUE(CParcelGetWritableBytes(parcel) > 0); + EXPECT_TRUE(CParcelGetReadableBytes(parcel) == 0); + EXPECT_TRUE(CParcelGetReadPosition(parcel) == 0); + EXPECT_TRUE(CParcelGetWritePosition(parcel) == 0); + + CParcelDecStrongRef(parcel); +} \ No newline at end of file diff --git a/ipc/native/test/unittest/common/ipc_c_process_unittest.cpp b/ipc/native/test/unittest/common/ipc_c_process_unittest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd17e8e37849265627e92d61a8227e3291db44c2 --- /dev/null +++ b/ipc/native/test/unittest/common/ipc_c_process_unittest.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include + +#include +#include +#include +#include "c_process.h" + +using namespace testing::ext; + +class IpcCProcessUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void IpcCProcessUnitTest::SetUpTestCase() +{} + +void IpcCProcessUnitTest::TearDownTestCase() +{} + +void IpcCProcessUnitTest::SetUp() +{} + +void IpcCProcessUnitTest::TearDown() +{} + +static void InitTokenId(void) +{ + uint64_t tokenId; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, + .permsNum = 0, + .aclsNum = 0, + .dcaps = NULL, + .perms = NULL, + .acls = NULL, + .processName = "com.ipc.test", + .aplStr = "normal", + }; + tokenId = GetAccessTokenId(&infoInstance); + SetSelfTokenID(tokenId); +} + +/** + * @tc.name: CProcessCallingInfo + * @tc.desc: Verify the CProcess calling info functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCProcessUnitTest, CProcessCallingInfo, TestSize.Level1) +{ + InitTokenId(); + uint64_t selfTokenId = GetSelfToekenId(); + EXPECT_EQ(GetCallingTokenId(), selfTokenId); + EXPECT_EQ(GetFirstToekenId(), 0); + EXPECT_EQ(GetCallingPid(), static_cast(getpid())); + EXPECT_EQ(GetCallingUid(), static_cast(getuid())); +} \ No newline at end of file diff --git a/ipc/native/test/unittest/common/ipc_c_remote_object_unittest.cpp b/ipc/native/test/unittest/common/ipc_c_remote_object_unittest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c10741487a790d78b4aa46095d0fa53d82cb9e5c --- /dev/null +++ b/ipc/native/test/unittest/common/ipc_c_remote_object_unittest.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include + +#include "c_process.h" +#include "c_remote_object.h" +#include "c_remote_object_internal.h" + +using namespace testing::ext; +using namespace OHOS; + +static const uint32_t DUMP_CODE = 1598311760; +static const char *SERVICE_NAME = "ohos.ipc.test"; + +class IpcCRemoteObjectUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void IpcCRemoteObjectUnitTest::SetUpTestCase() +{} + +void IpcCRemoteObjectUnitTest::TearDownTestCase() +{} + +void IpcCRemoteObjectUnitTest::SetUp() +{} + +void IpcCRemoteObjectUnitTest::TearDown() +{} + +static int OnRemoteRequest(const CRemoteObject *stub, int code, const CParcel *data, CParcel *reply) +{ + (void)stub; + (void)code; + (void)data; + (void)reply; + return 0; +} + +static void OnRemoteObjectDestroy(const void *userData) +{ + (void)userData; +} + +static void OnDeathRecipient(const void *userData) +{ + (void)userData; +} + +static void OnDeathRecipientDestroy(const void *userData) +{ + (void)userData; +} + +/** + * @tc.name: CRemoteObjectRefCount + * @tc.desc: Verify the CRemoteObject reference count functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCRemoteObjectUnitTest, CRemoteObjectRefCount, TestSize.Level1) +{ + CRemoteObject *remote = CreateRemoteStub(nullptr, OnRemoteRequest, OnRemoteObjectDestroy, nullptr); + EXPECT_EQ(remote, nullptr); + remote = CreateRemoteStub(SERVICE_NAME, OnRemoteRequest, OnRemoteObjectDestroy, nullptr); + EXPECT_NE(remote, nullptr); + RefBase *ref = static_cast(remote); + EXPECT_EQ(ref->GetSptrRefCount(), 1); + RemoteObjectIncStrongRef(remote); + EXPECT_EQ(ref->GetSptrRefCount(), 2); + RemoteObjectDecStrongRef(remote); + EXPECT_EQ(ref->GetSptrRefCount(), 1); + RemoteObjectIncStrongRef(nullptr); + RemoteObjectDecStrongRef(nullptr); + // destroy the CRemoteObject object + RemoteObjectDecStrongRef(remote); +} + +/** + * @tc.name: CRemoteObjectUserData + * @tc.desc: Verify the CRemoteObject user data function + * @tc.type: FUNC + */ +HWTEST_F(IpcCRemoteObjectUnitTest, CRemoteObjectUserData, TestSize.Level1) +{ + EXPECT_EQ(RemoteObjectGetUserData(nullptr), nullptr); + int8_t userData; + CRemoteObject *remote = CreateRemoteStub(SERVICE_NAME, OnRemoteRequest, OnRemoteObjectDestroy, &userData); + EXPECT_NE(remote, nullptr); + EXPECT_EQ(RemoteObjectGetUserData(remote), &userData); + // destroy the CRemoteObject object + RemoteObjectDecStrongRef(remote); +} + +/** + * @tc.name: CRemoteObjectCompare + * @tc.desc: Verify the CRemoteObject less than function + * @tc.type: FUNC + */ +HWTEST_F(IpcCRemoteObjectUnitTest, CRemoteObjectCompare, TestSize.Level1) +{ + int8_t userData; + CRemoteObject *remote = CreateRemoteStub(SERVICE_NAME, OnRemoteRequest, OnRemoteObjectDestroy, &userData); + EXPECT_NE(remote, nullptr); + EXPECT_FALSE(RemoteObjectLessThan(nullptr, remote)); + EXPECT_FALSE(RemoteObjectLessThan(remote, nullptr)); + CRemoteObject *samgr1 = GetContextManager(); + EXPECT_NE(samgr1, nullptr); + CRemoteObject *samgr2 = GetContextManager(); + EXPECT_NE(samgr2, nullptr); + EXPECT_FALSE(RemoteObjectLessThan(samgr1, samgr2)); + EXPECT_FALSE(RemoteObjectLessThan(samgr2, samgr1)); + CRemoteObjectHolder *samgr = static_cast(samgr1); + CRemoteObjectHolder *holder = static_cast(remote); + if (samgr->remote_.GetRefPtr() < holder->remote_.GetRefPtr()) { + EXPECT_TRUE(RemoteObjectLessThan(samgr1, remote)); + } else { + EXPECT_FALSE(RemoteObjectLessThan(samgr1, remote)); + } + // destroy the CRemoteObject object + RemoteObjectDecStrongRef(remote); + RemoteObjectDecStrongRef(samgr1); + RemoteObjectDecStrongRef(samgr2); +} + +/** + * @tc.name: CRemoteObjectSendRequest + * @tc.desc: Verify the CRemoteObject sendRequest function + * @tc.type: FUNC + */ +HWTEST_F(IpcCRemoteObjectUnitTest, CRemoteObjectSendRequest, TestSize.Level1) +{ + CRemoteObject *samgr = GetContextManager(); + EXPECT_NE(samgr, nullptr); + CParcel *data = CParcelObtain(); + EXPECT_NE(data, nullptr); + CParcel *reply = CParcelObtain(); + EXPECT_NE(reply, nullptr); + EXPECT_NE(RemoteObjectSendRequest(nullptr, DUMP_CODE, data, reply, true), 0); + EXPECT_NE(RemoteObjectSendRequest(samgr, DUMP_CODE, nullptr, reply, true), 0); + EXPECT_NE(RemoteObjectSendRequest(samgr, DUMP_CODE, data, nullptr, true), 0); + EXPECT_EQ(RemoteObjectSendRequest(samgr, DUMP_CODE, data, reply, true), 0); + // destroy the CRemoteObject and CParcel object + RemoteObjectDecStrongRef(samgr); + CParcelDecStrongRef(data); + CParcelDecStrongRef(reply); +} + +/** + * @tc.name: CDeathRecipientRefCount + * @tc.desc: Verify the CDeathRecipient reference count function + * @tc.type: FUNC + */ +HWTEST_F(IpcCRemoteObjectUnitTest, CDeathRecipientRefCount, TestSize.Level1) +{ + int8_t userData; + CDeathRecipient *recipient = CreateDeathRecipient(nullptr, + OnDeathRecipientDestroy, &userData); + EXPECT_EQ(recipient, nullptr); + recipient = CreateDeathRecipient(OnDeathRecipient, nullptr, &userData); + EXPECT_EQ(recipient, nullptr); + recipient = CreateDeathRecipient(OnDeathRecipient, OnDeathRecipientDestroy, nullptr); + EXPECT_EQ(recipient, nullptr); + recipient = CreateDeathRecipient(OnDeathRecipient, OnDeathRecipientDestroy, &userData); + EXPECT_NE(recipient, nullptr); + + RefBase *ref = static_cast(recipient); + EXPECT_EQ(ref->GetSptrRefCount(), 1); + DeathRecipientIncStrongRef(recipient); + EXPECT_EQ(ref->GetSptrRefCount(), 2); + DeathRecipientDecStrongRef(recipient); + EXPECT_EQ(ref->GetSptrRefCount(), 1); + DeathRecipientIncStrongRef(nullptr); + DeathRecipientDecStrongRef(nullptr); + // destroy the CDeathRecipient object + DeathRecipientDecStrongRef(recipient); +} + +/** + * @tc.name: CDeathRecipientStub + * @tc.desc: Verify the CDeathRecipient as stub functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCRemoteObjectUnitTest, CDeathRecipientStub, TestSize.Level1) +{ + int8_t userData; + CDeathRecipient *recipient = CreateDeathRecipient(OnDeathRecipient, OnDeathRecipientDestroy, &userData); + EXPECT_NE(recipient, nullptr); + CRemoteObject *remote = CreateRemoteStub(SERVICE_NAME, OnRemoteRequest, OnRemoteObjectDestroy, &userData); + EXPECT_NE(remote, nullptr); + EXPECT_FALSE(AddDeathRecipient(remote, recipient)); + EXPECT_FALSE(RemoveDeathRecipient(remote, recipient)); + + // destroy the CDeathRecipient object + DeathRecipientDecStrongRef(recipient); + RemoteObjectDecStrongRef(remote); +} + +/** + * @tc.name: CDeathRecipient + * @tc.desc: Verify the CDeathRecipient functions + * @tc.type: FUNC + */ +HWTEST_F(IpcCRemoteObjectUnitTest, CDeathRecipient, TestSize.Level1) +{ + int8_t userData; + CDeathRecipient *recipient = CreateDeathRecipient(OnDeathRecipient, OnDeathRecipientDestroy, &userData); + EXPECT_NE(recipient, nullptr); + CRemoteObject *samgr = GetContextManager(); + EXPECT_NE(samgr, nullptr); + + EXPECT_FALSE(AddDeathRecipient(nullptr, recipient)); + EXPECT_FALSE(AddDeathRecipient(samgr, nullptr)); + EXPECT_FALSE(RemoveDeathRecipient(nullptr, recipient)); + EXPECT_FALSE(RemoveDeathRecipient(samgr, nullptr)); + + EXPECT_TRUE(AddDeathRecipient(samgr, recipient)); + EXPECT_TRUE(RemoveDeathRecipient(samgr, recipient)); + // destroy the CDeathRecipient object + DeathRecipientDecStrongRef(recipient); + RemoteObjectDecStrongRef(samgr); +} \ No newline at end of file diff --git a/ipc/native/test/unittest/rust/BUILD.gn b/ipc/native/test/unittest/rust/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..654cfd0d17eb7ca2d989355682bf37729ece8f0f --- /dev/null +++ b/ipc/native/test/unittest/rust/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright (C) 2022 Huawei Device Co., Ltd. +# 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. + +import("//build/test.gni") + +#################################group######################################### + +group("unittest") { + testonly = true + deps = [ + "client:rust_ipc_test_client", + "server:rust_ipc_test_server", + ] +} +############################################################################### diff --git a/interfaces/innerkits/rust/tests/client/BUILD.gn b/ipc/native/test/unittest/rust/client/BUILD.gn similarity index 71% rename from interfaces/innerkits/rust/tests/client/BUILD.gn rename to ipc/native/test/unittest/rust/client/BUILD.gn index 1c1741a091f74f0bc73203da171ba3fd54416499..75e9fc6aa6d686b3359983e31c8c07d2c858aba8 100644 --- a/interfaces/innerkits/rust/tests/client/BUILD.gn +++ b/ipc/native/test/unittest/rust/client/BUILD.gn @@ -9,19 +9,24 @@ # 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. +# limitations under the License. -import("//build/ohos.gni") +import("//build/test.gni") SUBSYSTEM_DIR = "//foundation/communication/ipc" +MODULE_OUTPUT_PATH = "ipc" -ohos_rust_test("rust_ipc_test_client") { +ohos_rust_unittest("rust_ipc_test_client") { + module_out_path = MODULE_OUTPUT_PATH sources = [ "src/main.rs" ] deps = [ "$SUBSYSTEM_DIR/interfaces/innerkits/rust:ipc_rust", - "$SUBSYSTEM_DIR/interfaces/innerkits/rust/tests/service:test_ipc_service", + "$SUBSYSTEM_DIR/ipc/native/test/unittest/rust/service:test_ipc_service", ] + resource_config_file = + "//foundation/communication/ipc/test/resource/ipc/ohos_test.xml" + subsystem_name = "communication" part_name = "ipc" } diff --git a/interfaces/innerkits/rust/tests/client/src/main.rs b/ipc/native/test/unittest/rust/client/src/main.rs similarity index 72% rename from interfaces/innerkits/rust/tests/client/src/main.rs rename to ipc/native/test/unittest/rust/client/src/main.rs index d73d94b322d9255fa8f636ec46faf8d2a1b2a200..b3451fa42b480fd7570289302b86aa51f3c58c0c 100644 --- a/interfaces/innerkits/rust/tests/client/src/main.rs +++ b/ipc/native/test/unittest/rust/client/src/main.rs @@ -18,15 +18,14 @@ extern crate test_ipc_service; use std::thread; use std::time::Duration; -use std::io::Write; +use std::io::{Read, SeekFrom, Seek}; use ipc_rust::{ FromRemoteObj, DeathRecipient, IRemoteObj, FileDesc, RemoteObjRef, - MsgParcel, String16, InterfaceToken, get_service, init_access_token, - get_first_token_id, get_self_token_id, get_calling_pid, get_calling_uid, - IMsgParcel, + MsgParcel, String16, InterfaceToken, get_service, get_first_token_id, + get_self_token_id, get_calling_pid, get_calling_uid, IMsgParcel, }; -use test_ipc_service::{ITest, IPC_TEST_SERVICE_ID}; -use std::fs::OpenOptions; +use test_ipc_service::{ITest, TestProxy, IPC_TEST_SERVICE_ID, IFoo, init_access_token}; +use std::fs::File; fn get_test_service() -> RemoteObjRef { @@ -47,21 +46,6 @@ fn test_add_access_token() { init_access_token(); } -#[test] -fn test_ipc_request() { - let remote = get_test_service(); - assert_eq!(remote.echo_str("hello"), "hello"); -} - -#[test] -fn test_request_concurrent() { - let remote = get_test_service(); - for _i in 1..=5 { - assert!(remote.request_concurent(false)); - assert!(remote.request_concurent(true)); - } -} - #[test] fn test_death_recipient_001() { let object = get_service(IPC_TEST_SERVICE_ID).expect("get itest service failed"); @@ -225,15 +209,84 @@ fn test_calling_info() { } #[test] -fn test_parcel_fd() { +fn test_sync_request() { let remote = get_test_service(); + let value = remote.test_sync_transaction(2019, 0).expect("should return reverse value"); + assert_eq!(value, 9102); +} - let path = "/data/test_fd"; - let mut value = OpenOptions::new().read(true) - .write(true) - .create(true) - .open(path).expect("create data failed"); - let file_content = "Rust IPC Pass FD"; - write!(value, "{}", file_content); - assert_eq!(remote.pass_file(FileDesc::new(value)), file_content); +#[test] +fn test_async_request() { + let remote = get_test_service(); + remote.test_async_transaction(2019, 0).expect("should return reverse value"); +} + +#[test] +fn test_ping_service() { + let remote = get_test_service(); + let descriptor = String16::new(TestProxy::get_descriptor()); + remote.test_ping_service(&descriptor).expect("should success"); +} + +#[test] +fn test_fd() { + let remote = get_test_service(); + let fd: FileDesc = remote.test_transact_fd().expect("should return valied fd"); + let mut info = String::new(); + let mut file = File::from(fd); + file.seek(SeekFrom::Start(0)); + file.read_to_string(&mut info).expect("The string cannot be read"); + println!("file content: {}", info); + assert_eq!(info, "Sever write!\n"); +} + +#[test] +fn test_loop_request() { + let remote = get_test_service(); + // start loop test, test times is 1000 + let mut value = String::new(); + for _i in 1..=1000 { + value.push_str("0123456789abcdefghijklmnopqrstuvwxyz~!@#$%^&*()_+{}?/[]<>-='|~"); + let len = remote.test_transact_string(&value).expect("should return value length"); + assert_eq!(value.len() as i32, len); + } +} + +#[test] +fn test_remote_obj() { + let remote = get_test_service(); + let remote = remote.test_get_foo_service().expect("should return valid RemoteObj"); + ::from(remote).expect( + "convert foo service should success"); +} + +#[test] +fn test_parcel_buffer(){ + let u8_slice = [1u8;100]; + let u8_slice = &u8_slice[..]; + let mut parcel = MsgParcel::new().expect("create MsgParcel failed"); + let res = parcel.write_buffer(u8_slice); + assert_eq!(res, true); + let u8_vec: Vec = parcel.read_buffer(100).expect("read buffer failed"); + assert_eq!(u8_vec, u8_slice); +} + +#[test] +fn test_parcel_buffer_other(){ + let u8_slice = [1u8;100]; + let u8_slice = &u8_slice[..]; + let mut parcel = MsgParcel::new().expect("create MsgParcel failed"); + let res = parcel.write_buffer(u8_slice); + assert_eq!(res, true); + let u8_vec = parcel.read_buffer(0).expect("read zero length buffer failed"); + assert_eq!(u8_vec.len() as i32, 0); +} + +#[test] +fn test_parcel_ref(){ + let s = "hello".to_string(); + let mut parcel = MsgParcel::new().expect("create MsgParcel failed"); + parcel.write(&s).expect("write false failed"); + let res: String = parcel.read().expect("read str failed"); + assert_eq!(res, s); } \ No newline at end of file diff --git a/interfaces/innerkits/rust/tests/server/BUILD.gn b/ipc/native/test/unittest/rust/server/BUILD.gn similarity index 91% rename from interfaces/innerkits/rust/tests/server/BUILD.gn rename to ipc/native/test/unittest/rust/server/BUILD.gn index 06d62422cfab1f04193f0c3ed030c9eabecf3d9a..b328a4ea8c1b6a336fae382454bf79ac3c8abbdb 100644 --- a/interfaces/innerkits/rust/tests/server/BUILD.gn +++ b/ipc/native/test/unittest/rust/server/BUILD.gn @@ -9,7 +9,7 @@ # 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. +# limitations under the License. import("//build/ohos.gni") @@ -19,7 +19,7 @@ ohos_rust_executable("rust_ipc_test_server") { sources = [ "src/main.rs" ] deps = [ "$SUBSYSTEM_DIR/interfaces/innerkits/rust:ipc_rust", - "$SUBSYSTEM_DIR/interfaces/innerkits/rust/tests/service:test_ipc_service", + "$SUBSYSTEM_DIR/ipc/native/test/unittest/rust/service:test_ipc_service", ] subsystem_name = "communication" diff --git a/ipc/native/test/unittest/rust/server/src/main.rs b/ipc/native/test/unittest/rust/server/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..fa215e6b9af4416658f93161ae43a2007b79de2e --- /dev/null +++ b/ipc/native/test/unittest/rust/server/src/main.rs @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +//! IPC test server + +extern crate ipc_rust; +extern crate test_ipc_service; + +use ipc_rust::{ + IRemoteBroker, join_work_thread, FileDesc, InterfaceToken, Result, + add_service, get_calling_token_id, get_first_token_id, get_calling_pid, + get_calling_uid, String16, RemoteObj, IRemoteStub, +}; +use test_ipc_service::{ITest, TestStub, IPC_TEST_SERVICE_ID, reverse, IFoo, FooStub, init_access_token}; +use std::io::Write; +use std::fs::OpenOptions; +use std::{thread, time}; + +/// FooService type +pub struct FooService; + +impl IFoo for FooService { +} + +impl IRemoteBroker for FooService { +} + +/// test.ipc.ITestService type +pub struct TestService; + +impl ITest for TestService { + fn test_sync_transaction(&self, value: i32, delay_time: i32) -> Result { + if delay_time > 0 { + thread::sleep(time::Duration::from_millis(delay_time as u64)); + } + Ok(reverse(value)) + } + + fn test_async_transaction(&self, _value: i32, delay_time: i32) -> Result<()> { + if delay_time > 0 { + thread::sleep(time::Duration::from_millis(delay_time as u64)); + } + Ok(()) + } + + fn test_ping_service(&self, service_name: &String16) -> Result<()> { + let name = service_name.get_string(); + println!("test_ping_service recv service name: {}", name); + if name == TestStub::get_descriptor() { + Ok(()) + } else { + Err(-1) + } + } + + fn test_transact_fd(&self) -> Result { + let path = "/data/test.txt"; + let mut value = OpenOptions::new().read(true) + .write(true) + .create(true) + .open(path).expect("create /data/test.txt failed"); + let file_content = "Sever write!\n"; + write!(value, "{}", file_content).expect("write file success"); + Ok(FileDesc::new(value)) + } + + fn test_transact_string(&self, value: &str) -> Result { + Ok(value.len() as i32) + } + + fn test_get_foo_service(&self) -> Result { + let service = FooStub::new_remote_stub(FooService).expect("create FooService success"); + Ok(service.as_object().expect("get a RemoteObj success")) + } + + fn echo_interface_token(&self, token: &InterfaceToken) -> Result { + Ok(InterfaceToken::new(&token.get_token())) + } + + fn echo_calling_info(&self) -> Result<(u64, u64, u64, u64)> { + let token_id = get_calling_token_id(); + let first_token_id = get_first_token_id(); + let pid = get_calling_pid(); + let uid = get_calling_uid(); + println!("{}, {}, {}, {}", token_id, first_token_id, pid, uid); + Ok((token_id, first_token_id, pid, uid)) + } +} + +impl IRemoteBroker for TestService {} + +fn main() { + init_access_token(); + // create stub + let service = TestStub::new_remote_stub(TestService).expect("create TestService success"); + add_service(&service.as_object().expect("get ITest service failed"), + IPC_TEST_SERVICE_ID).expect("add server to samgr failed"); + println!("join to ipc work thread"); + join_work_thread(); +} \ No newline at end of file diff --git a/interfaces/innerkits/rust/tests/service/BUILD.gn b/ipc/native/test/unittest/rust/service/BUILD.gn similarity index 72% rename from interfaces/innerkits/rust/tests/service/BUILD.gn rename to ipc/native/test/unittest/rust/service/BUILD.gn index 3ba9f0005f237aa0b10e114a8dc25daa70c014cc..e12382bab72b8e63bbe90e64026fb186128c460b 100644 --- a/interfaces/innerkits/rust/tests/service/BUILD.gn +++ b/ipc/native/test/unittest/rust/service/BUILD.gn @@ -16,9 +16,16 @@ import("//build/ohos.gni") SUBSYSTEM_DIR = "//foundation/communication/ipc" ohos_rust_shared_library("test_ipc_service") { - sources = [ "src/lib.rs" ] + sources = [ + "src/access_token.rs", + "src/lib.rs", + ] - deps = [ "$SUBSYSTEM_DIR/interfaces/innerkits/rust:ipc_rust" ] + deps = [ + "$SUBSYSTEM_DIR/interfaces/innerkits/rust:ipc_rust", + "//base/security/access_token/interfaces/innerkits/nativetoken:libnativetoken", + "//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc", + ] crate_name = "test_ipc_service" crate_type = "dylib" diff --git a/ipc/native/test/unittest/rust/service/src/access_token.rs b/ipc/native/test/unittest/rust/service/src/access_token.rs new file mode 100644 index 0000000000000000000000000000000000000000..355cfaec207a8e2ff7c0f0ffa2a5be15509d5407 --- /dev/null +++ b/ipc/native/test/unittest/rust/service/src/access_token.rs @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +//! This crate implements the accesstoken init function FFI binding. + +use std::ptr; +use std::ffi::c_char; + +#[repr(C)] +struct TokenInfoParams { + dcaps_num: i32, + perms_num: i32, + acls_num: i32, + dcaps: *const *const c_char, + perms: *const *const c_char, + acls: *const *const c_char, + process_name: *const c_char, + apl_str: *const c_char, +} + +extern "C" { + fn GetAccessTokenId(tokenInfo: *mut TokenInfoParams) -> u64; + fn SetSelfTokenID(tokenID: u64) -> i32; +} + +/// Init access token ID for current process +pub fn init_access_token() +{ + let mut param = TokenInfoParams { + dcaps_num: 0, + perms_num: 0, + acls_num: 0, + dcaps: ptr::null(), + perms: ptr::null(), + acls: ptr::null(), + process_name: "com.ipc.test".as_ptr(), + apl_str: "normal".as_ptr(), + }; + + unsafe { + let token_id = GetAccessTokenId(&mut param as *mut TokenInfoParams); + SetSelfTokenID(token_id); + } +} \ No newline at end of file diff --git a/ipc/native/test/unittest/rust/service/src/lib.rs b/ipc/native/test/unittest/rust/service/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..5c3bdbef2db4d7fb8981eba9abdacdc0b813f35c --- /dev/null +++ b/ipc/native/test/unittest/rust/service/src/lib.rs @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +//! This create implement the IPC proxy and stub for "test.ipc.ITestService" + +extern crate ipc_rust; + +mod access_token; + +use ipc_rust::{ + IRemoteBroker, IRemoteObj, RemoteStub, Result, + RemoteObj, define_remote_object, FIRST_CALL_TRANSACTION +}; +use ipc_rust::{ + MsgParcel, BorrowedMsgParcel, FileDesc, InterfaceToken, String16, +}; +pub use access_token::init_access_token; + +/// Reverse a i32 value, for example reverse 2019 to 9102 +pub fn reverse(mut value: i32) -> i32 { + let mut result = 0; + let decimal = 10; + + while value != 0 { + result = result * decimal + value % decimal; + value /= decimal; + } + result +} + +/// SA ID for "test.ipc.ITestService" +pub const IPC_TEST_SERVICE_ID: i32 = 1118; + +/// Function code of ITestService +pub enum ITestCode { + /// Sync transaction code + CodeSyncTransaction = FIRST_CALL_TRANSACTION, + /// Async transaction code + CodeAsyncTransaction, + /// Ping transaction code + CodePingService, + /// Get FooService IPC object transaction code + CodeGetFooService, + /// Transaction file descriptor code + CodeTransactFd, + /// Transaction string code + CodeTransactString, + /// Transaction Interface token code + CodeInterfaceToekn, + /// Transaction calling infomation code + CodeCallingInfo, +} + +/// Function between proxy and stub of ITestService +pub trait ITest: IRemoteBroker { + /// Test sync transaction + fn test_sync_transaction(&self, value: i32, delay_time: i32) -> Result; + /// Test async transaction + fn test_async_transaction(&self, value: i32, delay_time: i32) -> Result<()>; + /// Test ping service transaction + fn test_ping_service(&self, service_name: &String16) -> Result<()>; + /// Test file descriptor transaction + fn test_transact_fd(&self) -> Result; + /// Test string transaction + fn test_transact_string(&self, value: &str) -> Result; + /// Test get foo service IPC object transaction + fn test_get_foo_service(&self) -> Result; + /// Test interface token transaction + fn echo_interface_token(&self, token: &InterfaceToken) -> Result; + /// Test calling infomation transaction + fn echo_calling_info(&self) -> Result<(u64, u64, u64, u64)>; +} + +fn on_itest_remote_request(stub: &dyn ITest, code: u32, data: &BorrowedMsgParcel, + reply: &mut BorrowedMsgParcel) -> Result<()> { + println!("on_remote_reuqest in Rust TestStub, code: {}", code); + match code { + 1 => { + let value: i32 = data.read().expect("should a value"); + let delay_time: i32 = data.read().expect("should a delay time"); + let ret = stub.test_sync_transaction(value, delay_time)?; + reply.write(&ret)?; + Ok(()) + } + 2 => { + let value: i32 = data.read().expect("should a value"); + let delay_time: i32 = data.read().expect("should a delay time"); + stub.test_async_transaction(value, delay_time)?; + Ok(()) + } + 3 => { + let service_name: String16 = data.read().expect("should a service name"); + stub.test_ping_service(&service_name)?; + Ok(()) + } + 4 => { + let service = stub.test_get_foo_service()?; + reply.write(&service)?; + Ok(()) + } + 5 => { + let fd = stub.test_transact_fd()?; + reply.write(&fd).expect("should write fd success"); + Ok(()) + } + 6 => { + let value: String = data.read()?; + let len = stub.test_transact_string(&value)?; + reply.write(&len)?; + Ok(()) + } + 7 => { + let token: InterfaceToken = data.read().expect("should have a interface token"); + let value = stub.echo_interface_token(&token).expect("service deal echo token failed"); + reply.write(&value).expect("write echo token result failed"); + Ok(()) + } + 8 => { + let (token_id, first_token_id, pid, uid) = stub.echo_calling_info()?; + reply.write(&token_id).expect("write token id failed"); + reply.write(&first_token_id).expect("write first token id failed"); + reply.write(&pid).expect("write pid failed"); + reply.write(&uid).expect("write uid failed"); + Ok(()) + } + _ => Err(-1) + } +} + +define_remote_object!( + ITest["test.ipc.ITestService"] { + stub: TestStub(on_itest_remote_request), + proxy: TestProxy, + } +); + +// Make RemoteStub object can call ITest function directly. +impl ITest for RemoteStub { + fn test_sync_transaction(&self, value: i32, delay_time: i32) -> Result { + self.0.test_sync_transaction(value, delay_time) + } + + fn test_async_transaction(&self, value: i32, delay_time: i32) -> Result<()> { + self.0.test_async_transaction(value, delay_time) + } + + fn test_ping_service(&self, service_name: &String16) -> Result<()> { + self.0.test_ping_service(service_name) + } + + fn test_transact_fd(&self) -> Result { + self.0.test_transact_fd() + } + + fn test_transact_string(&self, value: &str) -> Result { + self.0.test_transact_string(value) + } + + fn test_get_foo_service(&self) -> Result { + self.0.test_get_foo_service() + } + + fn echo_interface_token(&self, token: &InterfaceToken) -> Result { + self.0.echo_interface_token(token) + } + + fn echo_calling_info(&self) -> Result<(u64, u64, u64, u64)> { + self.0.echo_calling_info() + } +} + +impl ITest for TestProxy { + fn test_sync_transaction(&self, value: i32, delay_time: i32) -> Result { + let mut data = MsgParcel::new().expect("MsgParcel should success"); + data.write(&value)?; + data.write(&delay_time)?; + let reply = self.remote.send_request(ITestCode::CodeSyncTransaction as u32, + &data, false)?; + let ret: i32 = reply.read().expect("need reply i32"); + Ok(ret) + } + + fn test_async_transaction(&self, value: i32, delay_time: i32) -> Result<()> { + let mut data = MsgParcel::new().expect("MsgParcel should success"); + data.write(&value)?; + data.write(&delay_time)?; + let _reply = self.remote.send_request(ITestCode::CodeAsyncTransaction as u32, + &data, true)?; + Ok(()) + } + + fn test_ping_service(&self, service_name: &String16) -> Result<()> { + let mut data = MsgParcel::new().expect("MsgParcel should success"); + data.write(service_name)?; + let _reply = self.remote.send_request(ITestCode::CodePingService as u32, + &data, false)?; + Ok(()) + } + + fn test_transact_fd(&self) -> Result { + let data = MsgParcel::new().expect("MsgParcel should success"); + let reply = self.remote.send_request(ITestCode::CodeTransactFd as u32, + &data, false)?; + let fd: FileDesc = reply.read()?; + Ok(fd) + } + + fn test_transact_string(&self, value: &str) -> Result { + let mut data = MsgParcel::new().expect("MsgParcel should success"); + data.write(value).expect("should write string success"); + let reply = self.remote.send_request(ITestCode::CodeTransactString as u32, + &data, false)?; + let len: i32 = reply.read()?; + Ok(len) + } + + fn test_get_foo_service(&self) -> Result { + let data = MsgParcel::new().expect("MsgParcel should success"); + let reply = self.remote.send_request(ITestCode::CodeGetFooService as u32, + &data, false)?; + let service: RemoteObj = reply.read()?; + Ok(service) + } + + fn echo_interface_token(&self, token: &InterfaceToken) -> Result { + let mut data = MsgParcel::new().expect("MsgParcel should success"); + data.write(token).expect("write token should success"); + let reply = self.remote.send_request(ITestCode::CodeInterfaceToekn as u32, + &data, false)?; + let echo_value: InterfaceToken = reply.read().expect("need reply token"); + Ok(echo_value) + } + + fn echo_calling_info(&self) -> Result<(u64, u64, u64, u64)> { + let data = MsgParcel::new().expect("MsgParcel should success"); + let reply = self.remote.send_request(ITestCode::CodeCallingInfo as u32, + &data, false)?; + let token_id: u64 = reply.read().expect("need reply calling token id"); + let first_token_id: u64 = reply.read().expect("need reply first calling token id"); + let pid: u64 = reply.read().expect("need reply calling pid"); + let uid: u64 = reply.read().expect("need reply calling uid"); + Ok((token_id, first_token_id, pid, uid)) + } +} + +/// Interface trait for FooService +pub trait IFoo: IRemoteBroker { +} + +fn on_foo_remote_request(_stub: &dyn IFoo, _code: u32, _data: &BorrowedMsgParcel, + _reply: &mut BorrowedMsgParcel) -> Result<()> { + Ok(()) +} + +impl IFoo for RemoteStub { +} + +impl IFoo for FooProxy { +} + +define_remote_object!( + IFoo["ohos.ipc.test.foo"] { + stub: FooStub(on_foo_remote_request), + proxy: FooProxy, + } +); \ No newline at end of file diff --git a/ipc/test/auxiliary/native/BUILD.gn b/ipc/test/auxiliary/native/BUILD.gn index 235fa1be1ef643495d855a05ff025185dce45cac..51e06f3700ce79972e5d5d92bf7df8b9113cc075 100644 --- a/ipc/test/auxiliary/native/BUILD.gn +++ b/ipc/test/auxiliary/native/BUILD.gn @@ -61,7 +61,11 @@ ohos_executable("ipc_server_test") { "$IPC_TEST_ROOT:ipc_test_config", ] - deps = [ ":ipc_test_helper" ] + deps = [ + ":ipc_test_helper", + "//base/security/access_token/interfaces/innerkits/nativetoken:libnativetoken", + "//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc", + ] external_deps = [ "c_utils:utils", @@ -82,7 +86,11 @@ ohos_executable("ipc_client_test") { "$IPC_TEST_ROOT:ipc_test_config", ] - deps = [ ":ipc_test_helper" ] + deps = [ + ":ipc_test_helper", + "//base/security/access_token/interfaces/innerkits/nativetoken:libnativetoken", + "//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc", + ] external_deps = [ "c_utils:utils", @@ -142,7 +150,11 @@ ohos_executable("ipc_server_test_extra") { "$IPC_TEST_ROOT:ipc_test_config", ] - deps = [ ":ipc_test_helper_extra" ] + deps = [ + ":ipc_test_helper_extra", + "//base/security/access_token/interfaces/innerkits/nativetoken:libnativetoken", + "//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc", + ] external_deps = [ "c_utils:utils", diff --git a/ipc/test/auxiliary/native/src/main_client.cpp b/ipc/test/auxiliary/native/src/main_client.cpp index 87efcc16b671b6a19cde43efaa18d4fdea6594aa..470880f5f8aadb0fe83c8d1a82011936ba1778a3 100644 --- a/ipc/test/auxiliary/native/src/main_client.cpp +++ b/ipc/test/auxiliary/native/src/main_client.cpp @@ -26,11 +26,30 @@ #include "test_service_skeleton.h" #include "if_system_ability_manager.h" #include "log_tags.h" +#include +#include using namespace OHOS; using namespace OHOS::HiviewDFX; static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCTestClient" }; +static void InitTokenId(void) +{ + uint64_t tokenId; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, + .permsNum = 0, + .aclsNum = 0, + .dcaps = NULL, + .perms = NULL, + .acls = NULL, + .processName = "com.ipc.test", + .aplStr = "normal", + }; + tokenId = GetAccessTokenId(&infoInstance); + SetSelfTokenID(tokenId); +} + std::vector GetArgvOptions(int argc, char **argv) { std::vector argvOptions; @@ -42,6 +61,7 @@ std::vector GetArgvOptions(int argc, char **argv) int main(int argc, char *argv[]) { + InitTokenId(); int result = 0; TestCommand commandId = TestCommand::TEST_CMD_SYNC_TRANS; if (argc > 1) { diff --git a/ipc/test/auxiliary/native/src/main_server.cpp b/ipc/test/auxiliary/native/src/main_server.cpp index d8f5312260c88ae6a7081a3f767b8e0f9d436db9..bd3ccb677a817d32be85a90b7cbd27765335e7ae 100644 --- a/ipc/test/auxiliary/native/src/main_server.cpp +++ b/ipc/test/auxiliary/native/src/main_server.cpp @@ -17,14 +17,34 @@ #include "ipc_skeleton.h" #include "test_service.h" #include "log_tags.h" +#include +#include using namespace OHOS; using namespace OHOS::HiviewDFX; [[maybe_unused]]static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "IPCTestServer" }; +static void InitTokenId(void) +{ + uint64_t tokenId; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, + .permsNum = 0, + .aclsNum = 0, + .dcaps = NULL, + .perms = NULL, + .acls = NULL, + .processName = "com.ipc.test", + .aplStr = "normal", + }; + tokenId = GetAccessTokenId(&infoInstance); + SetSelfTokenID(tokenId); +} + int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) { + InitTokenId(); TestService::Instantiate(); ZLOGD(LABEL, "call StartThreadPool"); IPCSkeleton::JoinWorkThread();