提交 268e9ce6 编写于 作者: F fanxiaoyu

Adjust rust ipc implements.

Signed-off-by: Nfanxiaoyu <fanxiaoyu3@huawei.com>
上级 fa0668cf
......@@ -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" ]
}
......
......@@ -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" ]
}
......@@ -16,6 +16,7 @@
/// IPC specific Result, error is i32 type
pub type Result<T> = std::result::Result<T, i32>;
/// Generate a rust ipc Result by ret and val arguments.
pub fn result_status<T>(ret: bool, val: T) -> Result<T> {
if ret {
Ok(val)
......
......@@ -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<Self> {
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<dyn $remote_broker + Sync + Send>);
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<dyn ITest>", "*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<dyn ITest>
/// For example, convert RemoteObj to RemoteObjRef<dyn ITest>
fn from(object: $crate::RemoteObj) -> $crate::Result<$crate::RemoteObjRef<dyn $remote_broker>> {
Ok($crate::RemoteObjRef::new(Box::new($proxy::from_remote_object(object)?)))
}
......
......@@ -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<MsgParcel>;
// 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<RemoteObj> {
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<RemoteObjRef<Self>>;
}
// 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<T: FromRemoteObj + ?Sized>(Box<T>);
impl<T: FromRemoteObj + ?Sized> RemoteObjRef<T> {
/// Create a RemoteObjRef object
pub fn new(object: Box<T>) -> Self {
Self(object)
}
......
......@@ -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<CRemoteObject>);
impl RemoteObj {
/// Create an `RemoteObj` wrapper object from a raw `CRemoteObject` pointer.
/// # Safety
pub unsafe fn from_raw(obj: *mut CRemoteObject) -> Option<RemoteObj> {
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<MsgParcel> {
// 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)
......
......@@ -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<F>(callback: F) -> Option<DeathRecipient>
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));
}
}
}
......
......@@ -27,7 +27,7 @@ pub struct RemoteStub<T: IRemoteStub> {
}
impl<T: IRemoteStub> RemoteStub<T> {
// create a RemoteStub object
/// Create a RemoteStub object
pub fn new(rust: T) -> Option<Self> {
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<T: IRemoteStub> RemoteStub<T> {
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) {
......
......@@ -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;
......
......@@ -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)
......
......@@ -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<CParcel> {
/// 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<Vec<u8>> {
let mut buffer: Vec<MaybeUninit<u8>> = 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<std::mem::MaybeUninit<u8>>) -> Vec<u8> {
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<Self> {
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<MsgParcel> {
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<BorrowedMsgParcel<'a>> {
......@@ -223,20 +272,24 @@ unsafe impl<'a> AsRawPtr<CParcel> for BorrowedMsgParcel<'a> {
}
impl MsgParcel {
/// Read a data object which implements the Deserialize trait from MsgParcel
pub fn read<D: Deserialize>(&self) -> Result<D> {
self.borrowed_ref().read()
}
/// Write a data object which implements the Serialize trait to MsgParcel
pub fn write<S: Serialize + ?Sized>(&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<D: Deserialize>(&self) -> Result<D> {
D::deserialize(self)
}
/// Write a data object which implements the Serialize trait to BorrowedMsgParcel
pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
parcelable.serialize(self)
}
......
......@@ -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<T> which T must implements the trait Serialize.
pub trait SerOption: Serialize {
/// Serialize the Option<T>
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<T> which T must implements the trait Deserialize.
pub trait DeOption: Deserialize {
/// Deserialize the Option<T>
fn de_option(parcel: &BorrowedMsgParcel<'_>) -> Result<Option<Self>> {
let null: i32 = parcel.read()?;
if null == NULL_FLAG {
......@@ -133,12 +130,133 @@ unsafe extern "C" fn allocate_vec<T>(
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<Option<Vec<Self>>>;
}
\ 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::<Self>,
// )
// };
// 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<T: Serialize>(
// 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<Option<Vec<Self>>> {
// let mut vec: Option<Vec<MaybeUninit<Self>>> = 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::<Self>,
// de_element::<Self>,
// )
// };
// if ok_status{
// let vec: Option<Vec<Self>> = 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<MaybeUninit<T>> to Vec<T> because MaybeUninit<T> 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<Vec<MaybeUninit<T>>>` with at least enough elements for `index` to be valid
// /// (zero-based).
// unsafe extern "C" fn de_element<T: Deserialize>(
// 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<Vec<MaybeUninit<T>>>);
// 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<T>(vec: Vec<MaybeUninit<T>>) -> Vec<T> {
// // We can convert from Vec<MaybeUninit<T>> to Vec<T> because MaybeUninit<T>
// // 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
......@@ -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::*;
use std::ffi::{c_char, c_void};
use crate::{ipc_binding, BorrowedMsgParcel, AsRawPtr, result_status, Result, SerOption, DeOption};
\ No newline at end of file
......@@ -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<()> {
......
......@@ -15,35 +15,26 @@
use super::*;
impl Serialize for &[u8] {
impl<T: Serialize> Serialize for Box<T> {
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, ())
Serialize::serialize(&**self, parcel)
}
}
impl Deserialize for Vec<u8> {
impl<T: Deserialize> Deserialize for Box<T> {
fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> Result<Self> {
let mut vec: Option<Vec<u8>> = 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::<u8>
)
};
Deserialize::deserialize(parcel).map(Box::new)
}
}
if status {
vec.transpose()
}else{
Err(-1)
impl<T: SerOption> SerOption for Box<T> {
fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> {
SerOption::ser_option(this.map(|inner| &**inner), parcel)
}
}
impl<T: DeOption> DeOption for Box<T> {
fn de_option(parcel: &BorrowedMsgParcel<'_>) -> Result<Option<Self>> {
DeOption::de_option(parcel).map(|t| t.map(Box::new))
}
}
\ No newline at end of file
......@@ -13,55 +13,37 @@
* limitations under the License.
*/
extern crate ipc_rust;
use super::*;
// 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;
impl<T: SerArray, const N: usize> Serialize for [T; N] {
fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> {
// forwards to T::serialize_array.
SerArray::ser_array(self, parcel)
}
}
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
impl<T: SerArray, const N: usize> SerOption for [T; N] {
fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> {
SerOption::ser_option(this.map(|arr| &arr[..]), parcel)
}
}
define_remote_object!(
ITest["ohos.ipc.test"] {
stub: TestStub(on_remote_request),
proxy: TestProxy,
}
);
impl<T: SerArray, const N: usize> SerArray for [T; N] {}
// Make RemoteStub<TestStub> object can call ITest function directly.
impl ITest for RemoteStub<TestStub> {
fn hello(&self, greeting: &str) -> String {
// self will be convert to TestStub automatic because RemoteStub<TestStub>
// implement the Deref trait
self.0.hello(greeting)
impl<T: DeArray, const N: usize> Deserialize for [T; N] {
fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> Result<Self> {
let vec = DeArray::de_array(parcel)
.transpose()
.unwrap_or(Err(-1))?;
vec.try_into().or(Err(-1))
}
}
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")
impl<T: DeArray, const N: usize> DeOption for [T; N] {
fn de_option(parcel: &BorrowedMsgParcel<'_>) -> Result<Option<Self>> {
let vec = DeArray::de_array(parcel)?;
vec.map(|v| v.try_into().or(Err(-1))).transpose()
}
}
impl<T: DeArray, const N: usize> DeArray for [T; N] {}
\ No newline at end of file
......@@ -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<Option<Self>> {
let mut fd = -1i32;
let ok_status = unsafe {
......
......@@ -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<Option<Vec<Self>>> {
// let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
// let ok_status = unsafe {
// // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
// // `allocate_vec<T>` expects the opaque pointer to
// // be of type `*mut Option<Vec<MaybeUninit<T>>>`, 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<Vec<Self>> = 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<Option<Vec<Self>>> {
// let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
// let ok_status = unsafe {
// // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
// // `allocate_vec<T>` expects the opaque pointer to
// // be of type `*mut Option<Vec<MaybeUninit<T>>>`, 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<Vec<Self>> = 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<Option<Vec<Self>>> {
// let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
// let ok_status = unsafe {
// // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
// // `allocate_vec<T>` expects the opaque pointer to
// // be of type `*mut Option<Vec<MaybeUninit<T>>>`, 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<Vec<Self>> = 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<Option<Vec<Self>>> {
// let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
// let ok_status = unsafe {
// // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
// // `allocate_vec<T>` expects the opaque pointer to
// // be of type `*mut Option<Vec<MaybeUninit<T>>>`, 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<Vec<Self>> = 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<Option<Vec<Self>>> {
// let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
// let ok_status = unsafe {
// // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
// // `allocate_vec<T>` expects the opaque pointer to
// // be of type `*mut Option<Vec<MaybeUninit<T>>>`, 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<Vec<Self>> = 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<Option<Vec<Self>>> {
// let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
// let ok_status = unsafe {
// // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
// // `allocate_vec<T>` expects the opaque pointer to
// // be of type `*mut Option<Vec<MaybeUninit<T>>>`, 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<Vec<Self>> = 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<Option<Vec<Self>>> {
// let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
// let ok_status = unsafe {
// // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
// // `allocate_vec<T>` expects the opaque pointer to
// // be of type `*mut Option<Vec<MaybeUninit<T>>>`, 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<Vec<Self>> = 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::<f64>(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<Option<Vec<Self>>> {
// let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
// let ok_status = unsafe {
// // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
// // `allocate_vec<T>` expects the opaque pointer to
// // be of type `*mut Option<Vec<MaybeUninit<T>>>`, 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<Vec<Self>> = 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
......@@ -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)
}
......
......@@ -14,7 +14,6 @@
*/
use super::*;
use crate::{BorrowedMsgParcel, Result, SerOption, DeSerOption};
impl<T: SerOption> Serialize for Option<T> {
fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> {
......@@ -22,8 +21,11 @@ impl<T: SerOption> Serialize for Option<T> {
}
}
impl<T: DeSerOption> Deserialize for Option<T> {
impl<T: DeOption> Deserialize for Option<T> {
fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> Result<Self> {
DeSerOption::de_option(parcel)
DeOption::de_option(parcel)
}
}
// impl<T: DeOption> DeArray for Option<T> {}
// impl<T: SerOption> SerArray for Option<T> {}
\ No newline at end of file
......@@ -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<T: SerArray> Serialize for [T] {
fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> {
SerArray::ser_array(self, parcel)
}
}
impl<T: SerArray> 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
......@@ -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)
}
......
......@@ -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<()> {
......
......@@ -15,4 +15,29 @@
use super::*;
// TODO
\ No newline at end of file
impl<T: SerArray> Serialize for Vec<T> {
fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> {
SerArray::ser_array(&self[..], parcel)
}
}
impl<T: SerArray> SerOption for Vec<T> {
fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> Result<()> {
SerOption::ser_option(this.map(Vec::as_slice), parcel)
}
}
impl<T: DeArray> Deserialize for Vec<T> {
fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> Result<Self> {
DeArray::de_array(parcel)
.transpose()
.unwrap_or(Err(-1))
}
}
impl<T: DeArray> DeOption for Vec<T> {
fn de_option(parcel: &BorrowedMsgParcel<'_>) -> Result<Option<Self>> {
DeArray::de_array(parcel)
}
}
\ No newline at end of file
......@@ -26,35 +26,38 @@ fn get_samgr() -> Option<RemoteObj>
}
}
/// 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<RemoteObj>
{
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 {
......
......@@ -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);
......
......@@ -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);
......
......@@ -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__)) {
......
......@@ -15,8 +15,6 @@
#include "c_process.h"
#include <nativetoken_kit.h>
#include <token_setproc.h>
#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();
......
......@@ -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;
}
......
......@@ -18,5 +18,8 @@ import("//build/test.gni")
group("unittest") {
testonly = true
deps = [ "unittest/common:unittest" ]
if (target_cpu == "arm64") {
deps += [ "unittest/rust:unittest" ]
}
}
###############################################################################
......@@ -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" ]
}
......
/*
* 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 <gtest/gtest.h>
#include <refbase.h>
#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<void **>(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<RefBase *>(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<int8_t>(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<int8_t>(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<int16_t>(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<int16_t>(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<int32_t>(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<int32_t>(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<int64_t>(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<int64_t>(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>(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>(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<double>(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<double>(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<void *>(&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<void *>(&data), nullptr), false);
EXPECT_EQ(CParcelReadString(parcel, reinterpret_cast<void *>(&data), CParcelBytesAllocatorOk), true);
EXPECT_EQ(strncmp((reinterpret_cast<char *>(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<void *>(&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<void *>(&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<void *>(&data), nullptr), false);
EXPECT_EQ(CParcelReadString16(parcel, reinterpret_cast<void *>(&data), CParcelBytesAllocatorOk), true);
EXPECT_EQ(strncmp((reinterpret_cast<char *>(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<void *>(&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<void *>(&data), nullptr), false);
EXPECT_EQ(CParcelReadInterfaceToken(parcel, reinterpret_cast<void *>(&data), CParcelBytesAllocatorOk), true);
EXPECT_EQ(strncmp((reinterpret_cast<char *>(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<void *>(&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
/*
* 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 <gtest/gtest.h>
#include <nativetoken_kit.h>
#include <token_setproc.h>
#include <unistd.h>
#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<uint64_t>(getpid()));
EXPECT_EQ(GetCallingUid(), static_cast<uint64_t>(getuid()));
}
\ No newline at end of file
/*
* 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 <gtest/gtest.h>
#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<RefBase *>(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<CRemoteObjectHolder *>(samgr1);
CRemoteObjectHolder *holder = static_cast<CRemoteObjectHolder *>(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<RefBase *>(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
# 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",
]
}
###############################################################################
......@@ -11,17 +11,22 @@
# See the License for the specific language governing permissions and
# 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"
}
......@@ -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<dyn ITest>
{
......@@ -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");
<dyn IFoo as FromRemoteObj>::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<u8> = 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
......@@ -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"
......
......@@ -13,38 +13,76 @@
* 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, init_access_token, get_calling_token_id, get_first_token_id,
get_calling_pid, get_calling_uid,
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};
use std::io::{Read, Seek, SeekFrom};
use std::fs::File;
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 echo_str(&self, value: &str) -> String {
println!("TestService echo_str: {}", value);
String::from(value)
fn test_sync_transaction(&self, value: i32, delay_time: i32) -> Result<i32> {
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<FileDesc> {
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 request_concurent(&self, is_async: bool) -> bool {
println!("TestService request_concurent: {}", is_async);
true
fn test_transact_string(&self, value: &str) -> Result<i32> {
Ok(value.len() as i32)
}
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 test_get_foo_service(&self) -> Result<RemoteObj> {
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<InterfaceToken> {
......@@ -68,7 +106,7 @@ fn main() {
// 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);
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
......@@ -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"
......
/*
* 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
......@@ -13,63 +13,121 @@
* limitations under the License.
*/
//! This create implement the IPC proxy and stub for "test.ipc.ITestService"
extern crate ipc_rust;
// Import types
// use std::convert::{TryFrom, TryInto};
mod access_token;
use ipc_rust::{
IRemoteBroker, IRemoteObj, RemoteStub, Result,
RemoteObj, define_remote_object, FIRST_CALL_TRANSACTION
};
use ipc_rust::{
MsgParcel, BorrowedMsgParcel, FileDesc, InterfaceToken,
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 {
CodeEchoStr = FIRST_CALL_TRANSACTION,
CodeRequestConcurrent = 2,
CodePassFd = 3,
CodeInterfaceToekn = 4,
CodeCallingInfo = 5,
/// 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 {
fn echo_str(&self, value: &str) -> String;
fn request_concurent(&self, is_async: bool) -> bool;
fn pass_file(&self, fd: FileDesc) -> String;
/// Test sync transaction
fn test_sync_transaction(&self, value: i32, delay_time: i32) -> Result<i32>;
/// 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<FileDesc>;
/// Test string transaction
fn test_transact_string(&self, value: &str) -> Result<i32>;
/// Test get foo service IPC object transaction
fn test_get_foo_service(&self) -> Result<RemoteObj>;
/// Test interface token transaction
fn echo_interface_token(&self, token: &InterfaceToken) -> Result<InterfaceToken>;
/// Test calling infomation transaction
fn echo_calling_info(&self) -> Result<(u64, u64, u64, u64)>;
}
fn on_remote_request(stub: &dyn ITest, code: u32, data: &BorrowedMsgParcel,
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: String = data.read().expect("should have a string");
let value = stub.echo_str(&value);
reply.write(&value);
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 => {
stub.request_concurent(true);
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 fd: FileDesc = data.read().expect("should have a fd");
let value = stub.pass_file(fd);
reply.write(&value);
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(())
}
5 => {
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");
......@@ -82,26 +140,36 @@ fn on_remote_request(stub: &dyn ITest, code: u32, data: &BorrowedMsgParcel,
}
define_remote_object!(
ITest["ohos.ipc.test"] {
stub: TestStub(on_remote_request),
ITest["test.ipc.ITestService"] {
stub: TestStub(on_itest_remote_request),
proxy: TestProxy,
}
);
// Make RemoteStub<TestStub> object can call ITest function directly.
impl ITest for RemoteStub<TestStub> {
fn echo_str(&self, value: &str) -> String {
// self will be convert to TestStub automatic because RemoteStub<TestStub>
// implement the Deref trait
self.0.echo_str(value)
fn test_sync_transaction(&self, value: i32, delay_time: i32) -> Result<i32> {
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<FileDesc> {
self.0.test_transact_fd()
}
fn request_concurent(&self, is_async: bool) -> bool {
self.0.request_concurent(is_async)
fn test_transact_string(&self, value: &str) -> Result<i32> {
self.0.test_transact_string(value)
}
fn pass_file(&self, fd: FileDesc) -> String {
self.0.pass_file(fd)
fn test_get_foo_service(&self) -> Result<RemoteObj> {
self.0.test_get_foo_service()
}
fn echo_interface_token(&self, token: &InterfaceToken) -> Result<InterfaceToken> {
......@@ -114,46 +182,56 @@ impl ITest for RemoteStub<TestStub> {
}
impl ITest for TestProxy {
fn echo_str(&self, value: &str) -> String {
fn test_sync_transaction(&self, value: i32, delay_time: i32) -> Result<i32> {
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")
}
}
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 request_concurent(&self, is_async: bool) -> bool {
fn test_async_transaction(&self, value: i32, delay_time: i32) -> Result<()> {
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
}
data.write(&value)?;
data.write(&delay_time)?;
let _reply = self.remote.send_request(ITestCode::CodeAsyncTransaction as u32,
&data, true)?;
Ok(())
}
fn pass_file(&self, fd: FileDesc) -> String {
fn test_ping_service(&self, service_name: &String16) -> Result<()> {
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
data.write(service_name)?;
let _reply = self.remote.send_request(ITestCode::CodePingService as u32,
&data, false)?;
Ok(())
}
Err(_) => {
String::from("Error")
fn test_transact_fd(&self) -> Result<FileDesc> {
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<i32> {
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<RemoteObj> {
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<InterfaceToken> {
......@@ -166,7 +244,7 @@ impl ITest for TestProxy {
}
fn echo_calling_info(&self) -> Result<(u64, u64, u64, u64)> {
let mut data = MsgParcel::new().expect("MsgParcel should success");
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");
......@@ -176,3 +254,25 @@ impl ITest for TestProxy {
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<FooStub> {
}
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
......@@ -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",
......
......@@ -26,11 +26,30 @@
#include "test_service_skeleton.h"
#include "if_system_ability_manager.h"
#include "log_tags.h"
#include <nativetoken_kit.h>
#include <token_setproc.h>
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<std::string> GetArgvOptions(int argc, char **argv)
{
std::vector<std::string> argvOptions;
......@@ -42,6 +61,7 @@ std::vector<std::string> 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) {
......
......@@ -17,14 +17,34 @@
#include "ipc_skeleton.h"
#include "test_service.h"
#include "log_tags.h"
#include <nativetoken_kit.h>
#include <token_setproc.h>
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();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册