From 640b345c1e4acb9768e2d7dc7045c8c840e344a9 Mon Sep 17 00:00:00 2001 From: fqwert Date: Mon, 8 Apr 2024 11:29:43 +0800 Subject: [PATCH] =?UTF-8?q?ipc=5Frust=20=E6=8E=A5=E5=8F=A3=E9=87=8D?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: fqwert Change-Id: Ib233f76fcc35feb72f006bfd8b203ab3509318c0 --- .gitignore | 4 +- bundle.json | 1 + interfaces/innerkits/rust/BUILD.gn | 59 +- interfaces/innerkits/rust/Cargo.toml | 3 +- .../innerkits/rust/include/parcel_wrapper.h | 89 ++ .../rust/include/remote_object_wrapper.h | 106 +++ .../innerkits/rust/include/skeleton_wrapper.h | 66 ++ interfaces/innerkits/rust/src/ashmem.rs | 250 ------ .../innerkits/rust/src/cxx/parcel_wrapper.cpp | 298 +++++++ .../rust/src/cxx/remote_object_wrapper.cpp | 222 +++++ .../rust/src/cxx/skeleton_wrapper.cpp | 130 +++ interfaces/innerkits/rust/src/cxx_share.rs | 21 + interfaces/innerkits/rust/src/errors.rs | 49 +- interfaces/innerkits/rust/src/hilog.rs | 50 ++ interfaces/innerkits/rust/src/ipc/macros.rs | 137 --- interfaces/innerkits/rust/src/ipc/mod.rs | 140 --- .../innerkits/rust/src/ipc/remote_obj.rs | 256 ------ .../innerkits/rust/src/ipc/remote_obj/cmp.rs | 53 -- .../src/ipc/remote_obj/death_recipient.rs | 110 --- .../innerkits/rust/src/ipc/remote_stub.rs | 178 ---- .../innerkits/rust/src/ipc_async/ipc_ylong.rs | 51 +- .../innerkits/rust/src/ipc_async/mod.rs | 107 +-- interfaces/innerkits/rust/src/ipc_binding.rs | 320 ------- interfaces/innerkits/rust/src/lib.rs | 102 +-- interfaces/innerkits/rust/src/parcel/error.rs | 29 + interfaces/innerkits/rust/src/parcel/exts.rs | 159 ++++ interfaces/innerkits/rust/src/parcel/mod.rs | 455 +--------- interfaces/innerkits/rust/src/parcel/msg.rs | 832 ++++++++++++++++++ .../innerkits/rust/src/parcel/parcelable.rs | 276 ------ interfaces/innerkits/rust/src/parcel/types.rs | 53 -- .../innerkits/rust/src/parcel/types/bool.rs | 90 -- .../innerkits/rust/src/parcel/types/boxt.rs | 40 - .../rust/src/parcel/types/const_array.rs | 49 -- .../rust/src/parcel/types/file_desc.rs | 189 ---- .../rust/src/parcel/types/integer.rs | 345 -------- .../rust/src/parcel/types/interface_token.rs | 90 -- .../innerkits/rust/src/parcel/types/option.rs | 31 - .../rust/src/parcel/types/reference.rs | 30 - .../innerkits/rust/src/parcel/types/slices.rs | 33 - .../rust/src/parcel/types/string16.rs | 223 ----- .../rust/src/parcel/types/strings.rs | 278 ------ .../innerkits/rust/src/parcel/types/vector.rs | 42 - .../innerkits/rust/src/parcel/wrapper.rs | 820 +++++++++++++++++ interfaces/innerkits/rust/src/process.rs | 315 ++----- interfaces/innerkits/rust/src/remote/mod.rs | 23 + interfaces/innerkits/rust/src/remote/obj.rs | 179 ++++ interfaces/innerkits/rust/src/remote/stub.rs | 66 ++ .../innerkits/rust/src/remote/wrapper.rs | 140 +++ interfaces/innerkits/rust/src/skeleton.rs | 159 ++++ interfaces/innerkits/rust/tests/BUILD.gn | 62 ++ interfaces/innerkits/rust/tests/c/BUILD.gn | 34 + .../rust/tests/c/include/ipc_rust_test.h | 68 ++ .../rust/tests/c/src/ipc_rust_test.cpp | 227 +++++ interfaces/innerkits/rust/tests/c_mem.rs | 12 + interfaces/innerkits/rust/tests/entry.rs | 59 ++ .../innerkits/rust/tests/interactive.rs | 142 +++ .../innerkits/rust/tests/parcel_remote.rs | 285 ++++++ interfaces/innerkits/rust/tests/remote.rs | 87 ++ interfaces/innerkits/rust/tests/skeleton.rs | 132 +++ .../test/unittest/rust/client/src/main.rs | 2 +- rustfmt.toml | 19 + 61 files changed, 4760 insertions(+), 4117 deletions(-) create mode 100644 interfaces/innerkits/rust/include/parcel_wrapper.h create mode 100644 interfaces/innerkits/rust/include/remote_object_wrapper.h create mode 100644 interfaces/innerkits/rust/include/skeleton_wrapper.h delete mode 100644 interfaces/innerkits/rust/src/ashmem.rs create mode 100644 interfaces/innerkits/rust/src/cxx/parcel_wrapper.cpp create mode 100644 interfaces/innerkits/rust/src/cxx/remote_object_wrapper.cpp create mode 100644 interfaces/innerkits/rust/src/cxx/skeleton_wrapper.cpp create mode 100644 interfaces/innerkits/rust/src/cxx_share.rs create mode 100644 interfaces/innerkits/rust/src/hilog.rs delete mode 100644 interfaces/innerkits/rust/src/ipc/macros.rs delete mode 100644 interfaces/innerkits/rust/src/ipc/mod.rs delete mode 100644 interfaces/innerkits/rust/src/ipc/remote_obj.rs delete mode 100644 interfaces/innerkits/rust/src/ipc/remote_obj/cmp.rs delete mode 100644 interfaces/innerkits/rust/src/ipc/remote_obj/death_recipient.rs delete mode 100644 interfaces/innerkits/rust/src/ipc/remote_stub.rs delete mode 100644 interfaces/innerkits/rust/src/ipc_binding.rs create mode 100644 interfaces/innerkits/rust/src/parcel/error.rs create mode 100644 interfaces/innerkits/rust/src/parcel/exts.rs create mode 100644 interfaces/innerkits/rust/src/parcel/msg.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/parcelable.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/bool.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/boxt.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/const_array.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/file_desc.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/integer.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/interface_token.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/option.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/reference.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/slices.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/string16.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/strings.rs delete mode 100644 interfaces/innerkits/rust/src/parcel/types/vector.rs create mode 100644 interfaces/innerkits/rust/src/parcel/wrapper.rs create mode 100644 interfaces/innerkits/rust/src/remote/mod.rs create mode 100644 interfaces/innerkits/rust/src/remote/obj.rs create mode 100644 interfaces/innerkits/rust/src/remote/stub.rs create mode 100644 interfaces/innerkits/rust/src/remote/wrapper.rs create mode 100644 interfaces/innerkits/rust/src/skeleton.rs create mode 100644 interfaces/innerkits/rust/tests/BUILD.gn create mode 100644 interfaces/innerkits/rust/tests/c/BUILD.gn create mode 100644 interfaces/innerkits/rust/tests/c/include/ipc_rust_test.h create mode 100644 interfaces/innerkits/rust/tests/c/src/ipc_rust_test.cpp create mode 100644 interfaces/innerkits/rust/tests/c_mem.rs create mode 100644 interfaces/innerkits/rust/tests/entry.rs create mode 100644 interfaces/innerkits/rust/tests/interactive.rs create mode 100644 interfaces/innerkits/rust/tests/parcel_remote.rs create mode 100644 interfaces/innerkits/rust/tests/remote.rs create mode 100644 interfaces/innerkits/rust/tests/skeleton.rs create mode 100644 rustfmt.toml diff --git a/.gitignore b/.gitignore index b794ab5f..fc8d1453 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,6 @@ # limitations under the License. target -Cargo.lock \ No newline at end of file +Cargo.lock +.clang-format +.vscode diff --git a/bundle.json b/bundle.json index 9ff79b5a..d43823fd 100644 --- a/bundle.json +++ b/bundle.json @@ -138,6 +138,7 @@ "test": [ "//foundation/communication/ipc/ipc/test:moduletest", "//foundation/communication/ipc/ipc/native/test:unittest", + "//foundation/communication/ipc/interfaces/innerkits/rust/tests:unittest", "//foundation/communication/ipc/ipc/native/test/fuzztest:fuzztest", "//foundation/communication/ipc/services/dbinder/test/unittest:unittest", "//foundation/communication/ipc/services/dbinder/test/fuzztest:fuzztest" diff --git a/interfaces/innerkits/rust/BUILD.gn b/interfaces/innerkits/rust/BUILD.gn index 7a0867cb..93850a0d 100644 --- a/interfaces/innerkits/rust/BUILD.gn +++ b/interfaces/innerkits/rust/BUILD.gn @@ -16,13 +16,61 @@ import("//build/ohos.gni") SUBSYSTEM_DIR = "//foundation/communication/ipc" IPC_CORE_ROOT = "$SUBSYSTEM_DIR/ipc/native" +rust_cxx("ipc_cxx_gen") { + sources = [ + "src/parcel/wrapper.rs", + "src/remote/wrapper.rs", + "src/skeleton.rs", + ] +} + +config("libipc_c_private_config") { + cflags_cc = [ + "-DCONFIG_IPC_SINGLE", + "-O2", + ] +} + +ohos_static_library("ipc_rust_cxx") { + sources = [ + "src/cxx/parcel_wrapper.cpp", + "src/cxx/remote_object_wrapper.cpp", + "src/cxx/skeleton_wrapper.cpp", + ] + sources += get_target_outputs(":ipc_cxx_gen") + + include_dirs = [ + "include", + "${target_gen_dir}/src", + ] + + configs = [ ":libipc_c_private_config" ] + + deps = [ + ":ipc_cxx_gen", + "$SUBSYSTEM_DIR/interfaces/innerkits/ipc_single:ipc_single", + "//third_party/rust/crates/cxx:cxx_cppdeps", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + ] + + subsystem_name = "communication" + part_name = "ipc" +} + ohos_rust_shared_library("ipc_rust") { - crate_name = "ipc_rust" + crate_name = "ipc" edition = "2021" sources = [ "src/lib.rs" ] - deps = [ ":ipc_c" ] + deps = [ + ":ipc_rust_cxx", + "//third_party/rust/crates/cxx:lib", + ] external_deps = [ "hilog:hilog_rust", @@ -34,13 +82,6 @@ ohos_rust_shared_library("ipc_rust") { part_name = "ipc" } -config("libipc_c_private_config") { - cflags_cc = [ - "-DCONFIG_IPC_SINGLE", - "-O2", - ] -} - ohos_shared_library("ipc_c") { sanitize = { integer_overflow = true diff --git a/interfaces/innerkits/rust/Cargo.toml b/interfaces/innerkits/rust/Cargo.toml index efbc8d0c..74520182 100644 --- a/interfaces/innerkits/rust/Cargo.toml +++ b/interfaces/innerkits/rust/Cargo.toml @@ -12,7 +12,7 @@ # limitations under the License. [package] -name = "ipc_rust" +name = "ipc" version = "1.0.0" edition = "2021" license = "Apache-2.0" @@ -22,3 +22,4 @@ repository = "https://gitee.com/openharmony/communication_ipc" [dependencies] ylong_runtime = { git = "https://gitee.com/openharmony/commonlibrary_rust_ylong_runtime", features = ["macros", "fs", "net", "sync", "time"] } hilog_rust = { git = "https://gitee.com/openharmony/hiviewdfx_hilog.git" } +cxx = "1.0.115" diff --git a/interfaces/innerkits/rust/include/parcel_wrapper.h b/interfaces/innerkits/rust/include/parcel_wrapper.h new file mode 100644 index 00000000..24a6d6a8 --- /dev/null +++ b/interfaces/innerkits/rust/include/parcel_wrapper.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2024 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. + */ + +#ifndef IPC_RUST_CXX_PARCEL_H +#define IPC_RUST_CXX_PARCEL_H + + +#include +#include +#include + +#include "cxx.h" +#include "message_option.h" +#include "message_parcel.h" +#include "remote_object_wrapper.h" + +namespace OHOS { + +namespace IpcRust { + +std::unique_ptr NewMessageParcel(); +std::unique_ptr NewMessageOption(); + +Parcel const *AsParcel(const MessageParcel &msgParcel); + +Parcel *AsParcelMut(MessageParcel &msgParcel); + +bool WriteInterfaceToken(MessageParcel &msgParcel, const rust::str name); +rust::String ReadInterfaceToken(MessageParcel &msgParcel); + +bool WriteBuffer(MessageParcel &msgParcel, rust::slice buffer); +bool ReadBuffer(MessageParcel &msgParcel, size_t len, rust::Vec &buffer); + +bool WriteString(Parcel &parcel, const rust::Str val); +bool ReadString(Parcel &parcel, rust::String &val); + +bool WriteString16(Parcel &parcel, const rust::Str val); +rust::String ReadString16(Parcel &parcel); + +bool WriteString16Vec(Parcel &parcel, const rust::vec &v); +rust::vec ReadString16Vec(Parcel &parcel); + +bool WriteBoolVector(Parcel &parcel, rust::slice val); +bool WriteInt8Vector(Parcel &parcel, rust::slice val); +bool WriteInt16Vector(Parcel &parcel, rust::slice val); +bool WriteInt32Vector(Parcel &parcel, rust::slice val); +bool WriteInt64Vector(Parcel &parcel, rust::slice val); +bool WriteUInt8Vector(Parcel &parcel, rust::slice val); +bool WriteUInt16Vector(Parcel &parcel, rust::slice val); +bool WriteUInt32Vector(Parcel &parcel, rust::slice val); +bool WriteUInt64Vector(Parcel &parcel, rust::slice val); +bool WriteFloatVector(Parcel &parcel, rust::slice val); +bool WriteDoubleVector(Parcel &parcel, rust::slice val); +bool WriteStringVector(Parcel &parcel, rust::slice val); +bool WriteString16Vector(Parcel &parcel, rust::slice val); + +bool ReadBoolVector(Parcel &parcel, rust::vec &val); +bool ReadInt8Vector(Parcel &parcel, rust::vec &val); +bool ReadInt16Vector(Parcel &parcel, rust::vec &val); +bool ReadInt32Vector(Parcel &parcel, rust::vec &val); +bool ReadInt64Vector(Parcel &parcel, rust::vec &val); +bool ReadUInt8Vector(Parcel &parcel, rust::vec &val); +bool ReadUInt16Vector(Parcel &parcel, rust::vec &val); +bool ReadUInt32Vector(Parcel &parcel, rust::vec &val); +bool ReadUInt64Vector(Parcel &parcel, rust::vec &val); +bool ReadFloatVector(Parcel &parcel, rust::vec &val); +bool ReadDoubleVector(Parcel &parcel, rust::vec &val); +bool ReadStringVector(Parcel &parcel, rust::vec &val); +bool ReadString16Vector(Parcel &parcel, rust::vec &val); + +bool WriteRemoteObject(MessageParcel &msgParcel, std::unique_ptr object); +std::unique_ptr ReadRemoteObject(MessageParcel &msgParcel); + +} // namespace IpcRust +} // namespace OHOS + +#endif diff --git a/interfaces/innerkits/rust/include/remote_object_wrapper.h b/interfaces/innerkits/rust/include/remote_object_wrapper.h new file mode 100644 index 00000000..f2cdf00d --- /dev/null +++ b/interfaces/innerkits/rust/include/remote_object_wrapper.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2024 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. + */ + +#ifndef IPC_RUST_CXX_REMOTE_OBJECT_H +#define IPC_RUST_CXX_REMOTE_OBJECT_H + +#include +#include +#include + +#include "cxx.h" +#include "ipc_object_stub.h" +#include "iremote_object.h" +#include "message_option.h" +#include "message_parcel.h" +#include "refbase.h" + +namespace OHOS { + +typedef sptr SptrIRemoteObject; + +namespace IpcRust { +struct RemoteObj; +struct RemoteStubWrapper; +struct DeathRecipientRemoveHandler; + +class IRemoteObjectWrapper { +public: + IRemoteObjectWrapper(); + + ~IRemoteObjectWrapper() = default; + + int32_t SendRequest(const uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) const; + rust::String GetInterfaceDescriptor() const; + rust::String GetObjectDescriptor() const; + int32_t GetObjectRefCount() const; + bool IsProxyObject() const; + bool IsObjectDead() const; + bool CheckObjectLegality() const; + int Dump(int fd, const rust::Slice args) const; + + std::unique_ptr AddDeathRecipient(rust::Fn)>) const; + + IRemoteObject *GetInner() const; + + bool is_raw_ = false; + sptr sptr_; + IRemoteObject *raw_; +}; + +struct DeathRecipientWrapper : public virtual IRemoteObject::DeathRecipient { +public: + DeathRecipientWrapper(rust::Fn)> cb); + virtual void OnRemoteDied(const OHOS::wptr &object) override; + +private: + rust::Fn)> inner_; +}; + +struct DeathRecipientRemoveHandler { +public: + DeathRecipientRemoveHandler(sptr remote, sptr recipient); + void remove() const; + +private: + sptr remote_; + sptr inner_; +}; + +struct RemoteServiceStub : public IPCObjectStub { +public: + explicit RemoteServiceStub(RemoteStubWrapper *stub, std::u16string); + ~RemoteServiceStub(); + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + + int Dump(int fd, const std::vector &args) override; + +private: + RemoteStubWrapper *inner_; +}; + +std::unique_ptr FromSptrRemote(std::unique_ptr> remote); + +std::unique_ptr CloneRemoteObj(const IRemoteObjectWrapper &remote); + +std::unique_ptr FromRemoteStub(rust::Box stub); + +std::unique_ptr FromCIRemoteObject(IRemoteObject *stub); + +} // namespace IpcRust +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/interfaces/innerkits/rust/include/skeleton_wrapper.h b/interfaces/innerkits/rust/include/skeleton_wrapper.h new file mode 100644 index 00000000..a77e1c56 --- /dev/null +++ b/interfaces/innerkits/rust/include/skeleton_wrapper.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 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. + */ + +#ifndef IPC_RUST_CXX_SKELETON_H +#define IPC_RUST_CXX_SKELETON_H + +#include "cxx.h" +#include "ipc_skeleton.h" +#include "remote_object_wrapper.h" + +namespace OHOS { +namespace IpcRust { +bool SetMaxWorkThreadNum(int maxThreadNum); + +void JoinWorkThread(); + +void StopWorkThread(); + +uint64_t GetCallingPid(); + +uint64_t GetCallingRealPid(); + +uint64_t GetCallingUid(); + +uint32_t GetCallingTokenID(); + +uint64_t GetCallingFullTokenID(); + +uint32_t GetFirstTokenID(); + +uint64_t GetFirstFullTokenID(); + +uint64_t GetSelfTokenID(); + +rust::string GetLocalDeviceID(); + +rust::string GetCallingDeviceID(); + +bool IsLocalCalling(); + +std::unique_ptr GetContextObject(); + +int FlushCommands(IRemoteObjectWrapper &object); + +rust::string ResetCallingIdentity(); + +bool SetCallingIdentity(rust::str identity); + +bool IsHandlingTransaction(); + +} // namespace IpcRust +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/ashmem.rs b/interfaces/innerkits/rust/src/ashmem.rs deleted file mode 100644 index 6909b626..00000000 --- a/interfaces/innerkits/rust/src/ashmem.rs +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use crate::{ - ipc_binding, RawData, IpcResult, IpcStatusCode, - BorrowedMsgParcel, status_result, AsRawPtr -}; -use crate::ipc_binding::CAshmem; -use std::ffi::{CString, c_char}; -use crate::parcel::parcelable::{Serialize, Deserialize}; -use hilog_rust::{error, hilog, HiLogLabel, LogType}; - -const LOG_LABEL: HiLogLabel = HiLogLabel { - log_type: LogType::LogCore, - domain: 0xD0057CA, - tag: "RustAshmem" -}; - -/// Ashmem packed the native CAshmem -#[repr(C)] -pub struct Ashmem(*mut CAshmem); - -impl Ashmem { - /// Create a Ashmem object - pub fn new(name: &str, size: i32) -> Option { - if size <= 0 { - return None; - } - let c_name = CString::new(name).expect("ashmem name is invalid!"); - // SAFETY: - // requires ensuring the provided name is valid and not null-terminated within the string itself - let native = unsafe { - ipc_binding::CreateCAshmem(c_name.as_ptr(), size) - }; - if native.is_null() { - None - } else { - Some(Self(native)) - } - } - - /// Extract a raw `CAshmem` pointer from this wrapper. - /// # Safety - pub unsafe fn as_inner(&self) -> *mut CAshmem { - self.0 - } - - /// Create an `Ashmem` wrapper object from a raw `CAshmem` pointer. - /// # Safety - pub unsafe fn from_raw(cashmem: *mut CAshmem) -> Option { - if cashmem.is_null() { - None - } else { - Some(Self(cashmem)) - } - } -} - -/// Memory protection for mmap() PROT_NONE -pub const PROT_NONE: i32 = 0; -/// Memory protection for mmap() PROT_READ -pub const PROT_READ: i32 = 1; -/// Memory protection for mmap() PROT_WRITE -pub const PROT_WRITE: i32 = 2; -/// Memory protection for mmap() PROT_EXEC -pub const PROT_EXEC: i32 = 4; - -impl Ashmem { - /// Close Ashmem, the ashmem becomes invalid after closing. - pub fn close(&self) { - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - unsafe { - ipc_binding::CloseCAshmem(self.as_inner()); - } - } - - /// Set ashmem map type with above PROT_XXX by mmap() - pub fn map(&self, map_type: i32) -> bool { - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - unsafe { - ipc_binding::MapCAshmem(self.as_inner(), map_type) - } - } - - /// Set ashmem map type with `PROT_READ | PROT_WRITE` by mmap() - pub fn map_read_write(&self) -> bool { - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - unsafe { - ipc_binding::MapReadAndWriteCAshmem(self.as_inner()) - } - } - - /// Set ashmem map type with `PROT_READ` by mmap() - pub fn map_readonly(&self) -> bool { - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - unsafe { - ipc_binding::MapReadOnlyCAshmem(self.as_inner()) - } - } - - /// unmap ashmem - pub fn unmap(&self) { - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - unsafe { - ipc_binding::UnmapCAshmem(self.as_inner()); - } - } - - /// Set ashmem map type with above PROT_XXX by ioctl() - pub fn set_protection(&self, protection: i32) -> bool { - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - unsafe { - ipc_binding::SetCAshmemProtection(self.as_inner(), protection) - } - } - - /// Get ashmem map type - pub fn get_protection(&self) -> i32 { - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - unsafe { - ipc_binding::GetCAshmemProtection(self.as_inner()) - } - } - - /// Get ashmem size - pub fn get_size(&self) -> i32 { - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - unsafe { - ipc_binding::GetCAshmemSize(self.as_inner()) - } - } - - /// Write data to ashmem - pub fn write(&self, data: &[u8], offset: i32) -> bool { - let len = data.len() as i32; - if (offset < 0) || (offset >= len) { - error!(LOG_LABEL, "invalid offset: {}, len: {}", offset, len); - return false; - } - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - unsafe { - ipc_binding::WriteToCAshmem(self.as_inner(), - data.as_ptr(), len, offset) - } - } - - /// Read ashmem - pub fn read(&self, size: i32, offset: i32) -> IpcResult { - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - let raw_ptr = unsafe { - ipc_binding::ReadFromCAshmem(self.as_inner(), size, offset) - }; - if raw_ptr.is_null() { - Err(IpcStatusCode::Failed) - } else { - Ok(RawData::new(raw_ptr, size as u32)) - } - } - - /// Get ashmem inner file descriptor - pub fn get_fd(&self) -> i32 { - // SAFETY: - // Rust Ashmem always hold a valid native CAshmem. - unsafe { - ipc_binding::GetCAshmemFd(self.as_inner()) - } - } -} - -impl Clone for Ashmem { - fn clone(&self) -> Self { - // SAFETY: - // Ensure `self` is a valid `Ashmem` object with a non-null internal pointer. - unsafe { - ipc_binding::CAshmemIncStrongRef(self.as_inner()); - } - // SAFETY: no `None` here, cause `self` is valid - Self(self.0) - } -} - -impl Drop for Ashmem { - fn drop(&mut self) { - // SAFETY: - // Ensure `self` is a valid `Ashmem` object with a non-null internal pointer. - unsafe { - ipc_binding::CAshmemDecStrongRef(self.as_inner()); - } - } -} - -/// Write a ashmem -impl Serialize for Ashmem { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // SAFETY: - let ret = unsafe { - ipc_binding::CParcelWriteAshmem(parcel.as_mut_raw(), self.as_inner()) - }; - status_result::<()>(ret as i32, ()) - } -} - -/// read a ashmem -impl Deserialize for Ashmem { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - // SAFETY: - // Ensure `parcel` is a valid BorrowedMsgParcel. - let ptr = unsafe { - ipc_binding::CParcelReadAshmem(parcel.as_raw()) - }; - if ptr.is_null() { - Err(IpcStatusCode::Failed) - } else { - // SAFETY: - // constructs a new Ashmem object from a raw pointer - // lead to undefined behavior if the pointer is invalid. - unsafe { - match Ashmem::from_raw(ptr) { - Some(ashmem) => Ok(ashmem), - _ => { - error!(LOG_LABEL, "Failed to create Ashmem object from raw pointer"); - Err(IpcStatusCode::Failed) - } - } - } - } - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/cxx/parcel_wrapper.cpp b/interfaces/innerkits/rust/src/cxx/parcel_wrapper.cpp new file mode 100644 index 00000000..14184135 --- /dev/null +++ b/interfaces/innerkits/rust/src/cxx/parcel_wrapper.cpp @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2024 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 "parcel_wrapper.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ashmem.h" +#include "cxx.h" +#include "message_option.h" +#include "message_parcel.h" +#include "parcel.h" +#include "remote/wrapper.rs.h" +#include "string_ex.h" + +namespace OHOS { +namespace IpcRust { +std::unique_ptr NewMessageParcel() +{ + return std::make_unique(); +} + +std::unique_ptr NewMessageOption() +{ + return std::make_unique(); +} + +Parcel const *AsParcel(const MessageParcel &msgParcel) +{ + auto msgParcelMut = const_cast(&msgParcel); + return reinterpret_cast(msgParcelMut); +} + +Parcel *AsParcelMut(MessageParcel &msgParcel) +{ + return reinterpret_cast(&msgParcel); +} + +bool WriteInterfaceToken(MessageParcel &msgParcel, rust::str name) +{ + std::string s = std::string(name.data(), name.length()); + std::u16string name_u16 = Str8ToStr16(s); + return msgParcel.WriteInterfaceToken(name_u16); +} + +rust::String ReadInterfaceToken(MessageParcel &msgParcel) +{ + return msgParcel.ReadInterfaceToken().data(); +} + +bool WriteRemoteObject(MessageParcel &msgParcel, std::unique_ptr object) +{ + if (object->is_raw_) { + return false; + } else { + return msgParcel.WriteRemoteObject(object->sptr_); + } +} + +std::unique_ptr ReadRemoteObject(MessageParcel &msgParcel) +{ + sptr remote = msgParcel.ReadRemoteObject(); + if (remote == nullptr) { + return nullptr; + } + auto wrapper = std::make_unique(); + wrapper->is_raw_ = false; + wrapper->sptr_ = std::move(remote); + return wrapper; +} + +bool WriteBuffer(MessageParcel &msgParcel, rust::slice buffer) +{ + return msgParcel.WriteBuffer(buffer.data(), buffer.size()); +} + +bool ReadBuffer(MessageParcel &msgParcel, size_t len, rust::Vec &buffer) +{ + if (len == 0) { + return true; + } + const uint8_t *data = msgParcel.ReadBuffer(len); + if (data == nullptr) { + return false; + } + if (memcpy_s(buffer.data(), len, data, len) != EOK) { + return false; + } + return true; +} + +bool ReadString(Parcel &parcel, rust::String &val) +{ + std::string v; + if (parcel.ReadString(v)) { + val = v; + return true; + } else { + return false; + } +} + +bool WriteString(Parcel &parcel, const rust::Str val) +{ + auto s = std::string(val); + return parcel.WriteString(s); +} + +bool WriteString16(Parcel &parcel, const rust::Str val) +{ + std::u16string u16string = Str8ToStr16(std::string(val)); + return parcel.WriteString16(u16string); +} +rust::String ReadString16(Parcel &parcel) +{ + std::u16string u16string; + parcel.ReadString16(u16string); + return rust::string(u16string.data()); +} + +template std::vector RustVec2CppVec(rust::slice val) +{ + std::vector v; + for (auto i : val) { + v.push_back(i); + } + return v; +} + +bool WriteBoolVector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteBoolVector(RustVec2CppVec(val)); +} + +bool WriteInt8Vector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteInt8Vector(RustVec2CppVec(val)); +} + +bool WriteInt16Vector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteInt16Vector(RustVec2CppVec(val)); +} +bool WriteInt32Vector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteInt32Vector(RustVec2CppVec(val)); +} +bool WriteInt64Vector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteInt64Vector(RustVec2CppVec(val)); +} +bool WriteUInt8Vector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteUInt8Vector(RustVec2CppVec(val)); +} +bool WriteUInt16Vector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteUInt16Vector(RustVec2CppVec(val)); +} +bool WriteUInt32Vector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteUInt32Vector(RustVec2CppVec(val)); +} +bool WriteUInt64Vector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteUInt64Vector(RustVec2CppVec(val)); +} +bool WriteFloatVector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteFloatVector(RustVec2CppVec(val)); +} +bool WriteDoubleVector(Parcel &parcel, rust::slice val) +{ + return parcel.WriteDoubleVector(RustVec2CppVec(val)); +} + +bool WriteStringVector(Parcel &parcel, rust::slice val) +{ + std::vector v; + for (auto rust_s : val) { + v.push_back(std::string(rust_s.data(), rust_s.length())); + } + return parcel.WriteStringVector(v); +} + +bool WriteString16Vector(Parcel &parcel, rust::slice val) +{ + std::vector v; + for (auto rust_s : val) { + std::u16string u16string = Str8ToStr16(std::string(rust_s.data(), rust_s.length())); + v.push_back(u16string); + } + return parcel.WriteString16Vector(v); +} + +template bool ReadVector(Parcel &parcel, rust::vec &val, bool (Parcel::*ReadVec)(std::vector *)) +{ + std::vector v; + if (!(parcel.*ReadVec)(&v)) { + return false; + } + for (auto i : v) { + val.push_back(i); + } + return true; +} + +bool ReadBoolVector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadBoolVector); +} +bool ReadInt8Vector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadInt8Vector); +} +bool ReadInt16Vector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadInt16Vector); +} +bool ReadInt32Vector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadInt32Vector); +} +bool ReadInt64Vector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadInt64Vector); +} +bool ReadUInt8Vector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadUInt8Vector); +} +bool ReadUInt16Vector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadUInt16Vector); +} +bool ReadUInt32Vector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadUInt32Vector); +} +bool ReadUInt64Vector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadUInt64Vector); +} +bool ReadFloatVector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadFloatVector); +} +bool ReadDoubleVector(Parcel &parcel, rust::vec &val) +{ + return ReadVector(parcel, val, &Parcel::ReadDoubleVector); +} + +bool ReadStringVector(Parcel &parcel, rust::vec &val) +{ + std::vector v; + if (!parcel.ReadStringVector(&v)) { + return false; + } + for (auto s : v) { + val.push_back(s.data()); + } + return true; +} + +bool ReadString16Vector(Parcel &parcel, rust::vec &val) +{ + std::vector v; + if (!parcel.ReadString16Vector(&v)) { + return false; + } + for (auto i : v) { + val.push_back(i.data()); + } + return true; +} + +} // namespace IpcRust +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/cxx/remote_object_wrapper.cpp b/interfaces/innerkits/rust/src/cxx/remote_object_wrapper.cpp new file mode 100644 index 00000000..51e7439d --- /dev/null +++ b/interfaces/innerkits/rust/src/cxx/remote_object_wrapper.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2024 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 "remote_object_wrapper.h" + +#include +#include +#include +#include + +#include "cxx.h" +#include "iremote_object.h" +#include "message_parcel.h" +#include "refbase.h" +#include "remote/wrapper.rs.h" +#include "string_ex.h" + +namespace OHOS { +namespace IpcRust { +IRemoteObjectWrapper::IRemoteObjectWrapper() +{ +} + +int32_t IRemoteObjectWrapper::SendRequest( + const uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) const +{ + return GetInner()->SendRequest(code, data, reply, option); +} + +IRemoteObject *IRemoteObjectWrapper::GetInner() const +{ + if (is_raw_) { + return raw_; + } else { + return sptr_; + } +} + +rust::String IRemoteObjectWrapper::GetInterfaceDescriptor() const +{ + return GetInner()->GetInterfaceDescriptor().data(); +} + +rust::String IRemoteObjectWrapper::GetObjectDescriptor() const +{ + return GetInner()->GetObjectDescriptor().data(); +} + +std::unique_ptr IRemoteObjectWrapper::AddDeathRecipient( + rust::Fn)> callback) const +{ + sptr recipient(new DeathRecipientWrapper(callback)); + bool res = sptr_->AddDeathRecipient(recipient); + if (!res) { + return nullptr; + } + return std::make_unique(sptr(sptr_), sptr(recipient)); +} + +int32_t IRemoteObjectWrapper::GetObjectRefCount() const +{ + return GetInner()->GetObjectRefCount(); +} + +bool IRemoteObjectWrapper::IsProxyObject() const +{ + return GetInner()->IsProxyObject(); +} +bool IRemoteObjectWrapper::IsObjectDead() const +{ + return GetInner()->IsObjectDead(); +} +bool IRemoteObjectWrapper::CheckObjectLegality() const +{ + return GetInner()->CheckObjectLegality(); +} + +int IRemoteObjectWrapper::Dump(int fd, const rust::Slice args) const +{ + std::vector res; + for (auto rust_s : args) { + std::u16string s_u16 = Str8ToStr16(std::string(rust_s.data(), rust_s.length())); + res.push_back(s_u16); + } + return GetInner()->Dump(fd, res); +} + +DeathRecipientWrapper::DeathRecipientWrapper(rust::Fn)> cb) +{ + this->inner_ = cb; +} + +void DeathRecipientWrapper::OnRemoteDied(const OHOS::wptr &object) +{ + auto obj = object.promote(); + if (obj == nullptr) { + return; + } + + auto wrapper = std::make_unique(); + + wrapper->is_raw_ = false; + wrapper->sptr_ = obj; + + auto rust_remote_obj = new_remote_obj(std::move(wrapper)); + inner_(std::move(rust_remote_obj)); +} + +DeathRecipientRemoveHandler::DeathRecipientRemoveHandler( + sptr remote, sptr recipient) +{ + this->remote_ = std::move(remote); + this->inner_ = std::move(recipient); +} + +void DeathRecipientRemoveHandler::remove() const +{ + remote_->RemoveDeathRecipient(inner_); +} + +RemoteServiceStub::RemoteServiceStub(RemoteStubWrapper *ability, std::u16string descriptor) : IPCObjectStub(descriptor) +{ + this->inner_ = ability; +} + +RemoteServiceStub::~RemoteServiceStub() +{ + auto ability = rust::Box::from_raw(this->inner_); +} + +int RemoteServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + return inner_->on_remote_request(code, data, reply); +} + +int RemoteServiceStub::Dump(int fd, const std::vector &args) +{ + auto v = rust::Vec(); + for (auto arg : args) { + v.push_back(rust::String(arg.data())); + } + return inner_->dump(fd, v); +} + +std::unique_ptr FromSptrRemote(std::unique_ptr> remote) +{ + if (remote == nullptr) { + return nullptr; + } + auto wrapper = std::make_unique(); + + wrapper->is_raw_ = false; + wrapper->sptr_ = std::move(*remote.release()); + + return wrapper; +} + +std::unique_ptr CloneRemoteObj(const IRemoteObjectWrapper &remote) +{ + if (remote.is_raw_) { + auto raw_ptr = remote.raw_; + if (raw_ptr == nullptr) { + return nullptr; + } + return FromCIRemoteObject(raw_ptr); + } else { + auto sptr = remote.sptr_; + if (sptr == nullptr) { + return nullptr; + } + auto wrapper = std::make_unique(); + + wrapper->is_raw_ = false; + wrapper->sptr_ = sptr; + return wrapper; + } +} + +std::unique_ptr FromRemoteStub(rust::Box stub) +{ + auto raw = stub.into_raw(); + auto rust_s = raw->descriptor(); + std::string s = std::string(rust_s.data(), rust_s.length()); + std::u16string descriptor = Str8ToStr16(s); + + auto stub_sptr = sptr::MakeSptr(raw, descriptor); + + auto wrapper = std::make_unique(); + + wrapper->is_raw_ = false; + wrapper->sptr_ = stub_sptr; + + return wrapper; +} + +std::unique_ptr FromCIRemoteObject(IRemoteObject *stub) +{ + if (stub == nullptr) { + return nullptr; + } + auto wrapper = std::make_unique(); + + wrapper->is_raw_ = true; + wrapper->raw_ = stub; + + return wrapper; +} + +} // namespace IpcRust +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/cxx/skeleton_wrapper.cpp b/interfaces/innerkits/rust/src/cxx/skeleton_wrapper.cpp new file mode 100644 index 00000000..0f51f25f --- /dev/null +++ b/interfaces/innerkits/rust/src/cxx/skeleton_wrapper.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2024 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 "skeleton_wrapper.h" + +#include "ipc_skeleton.h" +#include "ipc_thread_skeleton.h" +namespace OHOS { +namespace IpcRust { +using namespace IPC_SINGLE; + +bool SetMaxWorkThreadNum(int maxThreadNum) +{ + return OHOS::IPCSkeleton::SetMaxWorkThreadNum(maxThreadNum); +} + +void JoinWorkThread() +{ + return OHOS::IPCSkeleton::JoinWorkThread(); +} + +void StopWorkThread() +{ + return OHOS::IPCSkeleton::StopWorkThread(); +} + +uint64_t GetCallingPid() +{ + return OHOS::IPCSkeleton::GetCallingPid(); +} + +uint64_t GetCallingRealPid() +{ + return OHOS::IPCSkeleton::GetCallingRealPid(); +} + +uint64_t GetCallingUid() +{ + return OHOS::IPCSkeleton ::GetCallingUid(); +} + +uint32_t GetCallingTokenID() +{ + return OHOS::IPCSkeleton ::GetCallingTokenID(); +} + +uint64_t GetCallingFullTokenID() +{ + return OHOS::IPCSkeleton ::GetCallingFullTokenID(); +} + +uint32_t GetFirstTokenID() +{ + return OHOS::IPCSkeleton ::GetFirstTokenID(); +} + +uint64_t GetFirstFullTokenID() +{ + return OHOS::IPCSkeleton ::GetFirstFullTokenID(); +} + +uint64_t GetSelfTokenID() +{ + return OHOS::IPCSkeleton::GetSelfTokenID(); +} + +rust::string GetLocalDeviceID() +{ + return OHOS::IPCSkeleton::GetLocalDeviceID(); +} + +rust::string GetCallingDeviceID() +{ + return OHOS::IPCSkeleton::GetCallingDeviceID(); +} + +bool IsLocalCalling() +{ + return OHOS::IPCSkeleton::IsLocalCalling(); +} + +std::unique_ptr GetContextObject() +{ + auto wrapper = std::make_unique(); + + wrapper->is_raw_ = true; + wrapper->raw_ = OHOS::IPCSkeleton::GetContextObject(); + + return wrapper; +} + +int FlushCommands(IRemoteObjectWrapper &object) +{ + return IPCSkeleton::FlushCommands(object.GetInner()); +} + +rust::string ResetCallingIdentity() +{ + return IPCSkeleton::ResetCallingIdentity(); +} + +bool SetCallingIdentity(rust::str identity) +{ + auto s = std::string(identity); + return IPCSkeleton::SetCallingIdentity(s); +} + +bool IsHandlingTransaction() +{ + if (IPCThreadSkeleton::GetActiveInvoker() != nullptr) { + return true; + } + + return false; +} + +} // namespace IpcRust +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/cxx_share.rs b/interfaces/innerkits/rust/src/cxx_share.rs new file mode 100644 index 00000000..d5027655 --- /dev/null +++ b/interfaces/innerkits/rust/src/cxx_share.rs @@ -0,0 +1,21 @@ +// Copyright (C) 2024 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. + +//! cxx shared c++ class. + +pub use cxx::UniquePtr; + +pub use crate::parcel::wrapper::MessageParcel; +pub use crate::remote::wrapper::{ + IRemoteObject, IRemoteObjectWrapper, RemoteStubWrapper, SptrIRemoteObject, +}; diff --git a/interfaces/innerkits/rust/src/errors.rs b/interfaces/innerkits/rust/src/errors.rs index 712647c2..5445dab3 100644 --- a/interfaces/innerkits/rust/src/errors.rs +++ b/interfaces/innerkits/rust/src/errors.rs @@ -1,28 +1,19 @@ -/* - * 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. - */ +// Copyright (C) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use std::error::Error; +use std::ffi::{c_char, CString}; use std::fmt; -use std::ffi::{CString, c_char}; -use hilog_rust::{debug, hilog, HiLogLabel, LogType}; - -const LOG_LABEL: HiLogLabel = HiLogLabel { - log_type: LogType::LogCore, - domain: 0xD0057CA, - tag: "RustStatus" -}; /// IPC specific Result, error is i32 type pub type IpcResult = std::result::Result; @@ -32,7 +23,7 @@ pub type IpcResult = std::result::Result; /// or /// status_result::(result, reply) pub fn status_result(code: i32, val: T) -> IpcResult { - debug!(LOG_LABEL, "rust status code: {}", code); + debug!("rust status code: {}", code); match parse_status_code(code) { IpcStatusCode::Ok => Ok(val), e => Err(e), @@ -53,11 +44,7 @@ pub fn parse_status_code(code: i32) -> IpcStatusCode { } /// IPC unified status code -#[derive(Hash)] -#[derive(Eq, PartialEq)] -#[derive(Ord, PartialOrd)] -#[derive(Clone, Copy)] -#[derive(Debug)] +#[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] #[non_exhaustive] pub enum IpcStatusCode { /// success @@ -91,9 +78,9 @@ impl fmt::Display for IpcStatusCode { IpcStatusCode::Failed => write!(f, "Call Failed"), IpcStatusCode::Einval => write!(f, "Invalid Params"), IpcStatusCode::ErrNullObject => write!(f, "Null Obj"), - IpcStatusCode::ErrDeadObject => write!(f, "Dead Obj"), + IpcStatusCode::ErrDeadObject => write!(f, "Dead Obj"), IpcStatusCode::InvalidValue => write!(f, "Invalid Value"), - _ => write!(f, "Unknow Error"), + _ => write!(f, "Unknow Error"), } } -} \ No newline at end of file +} diff --git a/interfaces/innerkits/rust/src/hilog.rs b/interfaces/innerkits/rust/src/hilog.rs new file mode 100644 index 00000000..4395c5c1 --- /dev/null +++ b/interfaces/innerkits/rust/src/hilog.rs @@ -0,0 +1,50 @@ +// Copyright (C) 2024 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. + +/// hilog label. + +macro_rules! debug { + ($($args:tt)*) => {{ + use hilog_rust::hilog; + use std::ffi::{c_char, CString}; + use $crate::LOG_LABEL; + + let log = format!($($args)*); + + hilog_rust::debug!(LOG_LABEL,"{}",@public(log)); + }} +} + +macro_rules! info { + ($($args:tt)*) => {{ + use hilog_rust::hilog; + use std::ffi::{c_char, CString}; + use $crate::LOG_LABEL; + + let log = format!($($args)*); + + hilog_rust::info!(LOG_LABEL,"{}",@public(log)); + }} +} +#[allow(unused)] +macro_rules! error { + ($($args:tt)*) => {{ + use hilog_rust::hilog; + use std::ffi::{c_char, CString}; + use $crate::LOG_LABEL; + + let log = format!($($args)*); + + hilog_rust::error!(LOG_LABEL,"{}",@public(log)); + }} +} diff --git a/interfaces/innerkits/rust/src/ipc/macros.rs b/interfaces/innerkits/rust/src/ipc/macros.rs deleted file mode 100644 index efba2c21..00000000 --- a/interfaces/innerkits/rust/src/ipc/macros.rs +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/// This macro can define a rust IPC proxy and stub releations. -#[macro_export] -macro_rules! define_remote_object { - { - $remote_broker:path[$descriptor:expr] { - stub: $stub:ident($on_remote_request:path), - proxy: $proxy:ident, - $(async: $async_interface:ident,)? - } - } => { - $crate::define_remote_object! { - $remote_broker[$descriptor] { - stub: $stub($on_remote_request), - proxy: $proxy {}, - $(async: $async_interface,)? - } - } - }; - - { - $remote_broker:path[$descriptor:expr] { - stub: $stub:ident($on_remote_request:path), - proxy: $proxy:ident { - $($item_name:ident: $item_type:ty = $item_init:expr),* - }, - $(async: $async_interface:ident,)? - } - } => { - /// 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::IpcResult { - Ok(Self { - remote: remote.clone(), - $($item_name: $item_init),* - }) - } - - /// Get proxy object descriptor - #[allow(dead_code)] - pub fn get_descriptor() -> &'static str { - $descriptor - } - } - - impl $crate::IRemoteBroker for $proxy { - /// Get RemoteObject object from proxy - fn as_object(&self) -> Option<$crate::RemoteObj> { - Some(self.remote.clone()) - } - } - - /// IPC stub type - pub struct $stub(Box); - - impl $stub { - /// Create a new remote stub service - #[allow(dead_code)] - pub fn new_remote_stub(obj: T) -> Option<$crate::RemoteStub> - where - T: $remote_broker + Send + Sync + 'static, - { - RemoteStub::new($stub(Box::new(obj))) - } - } - - impl $crate::IRemoteStub for $stub { - /// Get stub object descriptor - fn get_descriptor() -> &'static str { - $descriptor - } - - /// Callback to deal IPC request for this stub - fn on_remote_request(&self, code: u32, data: &$crate::BorrowedMsgParcel, - reply: &mut $crate::BorrowedMsgParcel) -> i32 { - // For example, "self.0" is "Box", "*self.0" is "dyn ITest" - let result = $on_remote_request(&*self.0, code, data, reply); - - match result { - Ok(_) => 0, - Err(error) => { - error as i32 - } - } - } - fn on_dump(&self, file: &$crate::FileDesc, args: &mut Vec<$crate::String16>) -> i32 { - self.0.dump(file, args) - } - } - - impl $crate::FromRemoteObj for dyn $remote_broker { - // For example, convert RemoteObj to RemoteObjRef - fn try_from(object: $crate::RemoteObj) - -> $crate::IpcResult<$crate::RemoteObjRef> { - Ok($crate::RemoteObjRef::new(Box::new($proxy::from_remote_object(&object)?))) - } - } - - $( - // For example, convert RemoteObj to RemoteObjRef> - impl $crate::FromRemoteObj for dyn $async_interface

{ - fn try_from(object: $crate::RemoteObj) - -> $crate::IpcResult<$crate::RemoteObjRef>> { - Ok($crate::RemoteObjRef::new(Box::new($proxy::from_remote_object(&object)?))) - } - } - - impl $crate::ToAsyncIpc

for dyn $remote_broker { - type Target = dyn $async_interface

; - } - - impl $crate::ToSyncIpc for dyn $async_interface

{ - type Target = dyn $remote_broker; - } - )? - }; -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/ipc/mod.rs b/interfaces/innerkits/rust/src/ipc/mod.rs deleted file mode 100644 index e2e6d4e8..00000000 --- a/interfaces/innerkits/rust/src/ipc/mod.rs +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -pub mod remote_obj; -pub mod remote_stub; -pub mod macros; - -use crate::{ - BorrowedMsgParcel, MsgParcel, IpcResult, DeathRecipient, - FileDesc, IpcStatusCode, -}; -use std::ops::Deref; -use std::cmp::Ordering; -use crate::String16; - -// Export types of this module -pub use crate::RemoteObj; - -/// Like C++ IRemoteObject class, define function for both proxy and stub object -pub trait IRemoteObj { - /// Send a IPC request to remote service - fn send_request(&self, code: u32, data: &MsgParcel, is_async: bool) -> IpcResult; - - /// Send asynchronous IPC requests to remote services, - /// The current interface will use ylong runtime to start a separate thread to execute requests - fn async_send_request(&self, code: u32, data: MsgParcel, call_back: F) - where - F: FnOnce(MsgParcel) -> R, - F: Send + 'static, - R: Send + 'static,; - - /// 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; - - /// Determine whether it is a proxy object - fn is_proxy(&self) -> bool; - - /// Dump a service through a String16 - fn dump(&self, fd: i32, args: &mut Vec) -> i32; - - /// Judge whether the object is dead - fn is_dead(&self) -> bool; - - /// get interface descriptor - fn interface_descriptor(&self) -> IpcResult; -} - -/// 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; - - /// Callback for IPC dump - fn on_dump(&self, file: &FileDesc, args: &mut Vec) -> i32; -} - -/// Like C++ IRemoteBroker class -pub trait IRemoteBroker: Send + Sync { - /// Convert self to RemoteObject - fn as_object(&self) -> Option { - panic!("This is not a RemoteObject.") - } - /// Default dump - fn dump(&self, _file: &FileDesc, _args: &mut Vec) -> i32 { - println!("This is the default dump function, and you can override it to implement your own dump function"); - IpcStatusCode::Ok as i32 - } -} - -/// 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 try_from(object: RemoteObj) -> IpcResult>; -} - -/// Strong reference for "dyn IRemoteBroker" object, for example T is "dyn ITest" -pub struct RemoteObjRef(Box); - -impl RemoteObjRef { - /// Create a RemoteObjRef object - pub fn new(object: Box) -> Self { - Self(object) - } -} - -impl Deref for RemoteObjRef { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Clone for RemoteObjRef { - fn clone(&self) -> Self { - // Clone is a method in the RemoteObjRef structure. - // T in RemoteObjRefimplements the trait FromRemoteObj, - // so self.0.as_ Object(). unwrap() must be a RemoteObj object that exists - FromRemoteObj::try_from(self.0.as_object().unwrap()).unwrap() - } -} - -impl Ord for RemoteObjRef { - fn cmp(&self, other: &Self) -> Ordering { - self.0.as_object().cmp(&other.0.as_object()) - } -} - -impl PartialOrd for RemoteObjRef { - fn partial_cmp(&self, other: &Self) -> Option { - self.0.as_object().partial_cmp(&other.0.as_object()) - } -} - -impl PartialEq for RemoteObjRef { - fn eq(&self, other: &Self) -> bool { - self.0.as_object().eq(&other.0.as_object()) - } -} - -impl Eq for RemoteObjRef {} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/ipc/remote_obj.rs b/interfaces/innerkits/rust/src/ipc/remote_obj.rs deleted file mode 100644 index 998026b7..00000000 --- a/interfaces/innerkits/rust/src/ipc/remote_obj.rs +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//! Implement of RemoteObj type, which represent a C++ IRemoteObject. - -use std::ptr; -use crate::{ - ipc_binding, IRemoteObj, DeathRecipient, IpcResult, - MsgParcel, BorrowedMsgParcel, AsRawPtr, IpcStatusCode, - parcel::vec_u16_to_string, parse_status_code, Runtime, - IpcAsyncRuntime, -}; -use crate::ipc_binding::{CRemoteObject, CDeathRecipient, CIRemoteObject}; -use crate::parcel::parcelable::{Serialize, Deserialize, allocate_vec_with_buffer}; -use std::ffi::{c_void, CString, c_char}; -use crate::String16; -use hilog_rust::{error, hilog, HiLogLabel, LogType}; - -const LOG_LABEL: HiLogLabel = HiLogLabel { - log_type: LogType::LogCore, - domain: 0xD0057CA, - tag: "RustRemoteObj" -}; - -pub mod death_recipient; -pub mod cmp; - -/// RemoteObject can be used as proxy or stub object. -/// It always contained a native CRemoteObject pointer. -/// # Invariant -/// -/// `*mut CRemoteObject` must be valid -pub struct RemoteObj(ptr::NonNull); - -impl RemoteObj { - /// Create an `RemoteObj` wrapper object from a raw `CRemoteObject` pointer. - /// # Safety - pub unsafe fn from_raw(obj: *mut CRemoteObject) -> Option { - if obj.is_null() { - None - } else { - Some(RemoteObj(unsafe{ptr::NonNull::new_unchecked(obj)})) - } - } - - /// Extract a raw `CRemoteObject` pointer from this wrapper. - /// # Safety - pub unsafe fn as_inner(&self) -> *mut CRemoteObject { - self.0.as_ptr() - } - - /// Convert an `RemoteObj` by `CIRemoteObject` pointer. - pub fn from_raw_ciremoteobj(obj: *mut CIRemoteObject) -> Option { - if obj.is_null() { - None - } else { - // SAFETY: he returned CIRemoteObject may be a null pointer - unsafe { - let sa = ipc_binding::CreateCRemoteObject(obj as *mut _ as *mut c_void); - RemoteObj::from_raw(sa) - } - } - } - - /// Extract a raw `CIRemoteObject` pointer from this wrapper. - /// # Safety - /// The returned CIRemoteObject may be a null pointer - pub unsafe fn as_raw_ciremoteobj(&self) -> *mut CIRemoteObject { - ipc_binding::GetCIRemoteObject(self.0.as_ptr()) as *mut CIRemoteObject - } -} - -impl IRemoteObj for RemoteObj { - fn send_request(&self, code: u32, data: &MsgParcel, is_async: bool) -> IpcResult { - // SAFETY: - // Validate and ensure the validity of all pointers before using them. - unsafe { - let mut reply = MsgParcel::new().expect("create reply MsgParcel not success"); - let result = ipc_binding::RemoteObjectSendRequest(self.as_inner(), code, data.as_raw(), - reply.as_mut_raw(), is_async); - if result == 0 { - Ok(reply) - } else { - Err(parse_status_code(result)) - } - } - } - - fn async_send_request(&self, code: u32, data: MsgParcel, call_back: F) - where - F: FnOnce(MsgParcel) -> R, - F: Send + 'static, - R: Send + 'static, - { - let remote = self.clone(); - Runtime::spawn_blocking(move || { - let reply = remote.send_request(code, &data, false); - match reply { - Ok(reply) => { - call_back(reply); - IpcStatusCode::Ok - }, - _ => { - error!(LOG_LABEL, "send_request failed"); - IpcStatusCode::Failed - } - } - }); - } - - fn add_death_recipient(&self, recipient: &mut DeathRecipient) -> bool { - // SAFETY: - // Validate and ensure the validity of all pointers before using them. - unsafe { - ipc_binding::AddDeathRecipient(self.as_inner(), recipient.as_mut_raw()) - } - } - - // remove death Recipients - fn remove_death_recipient(&self, recipient: &mut DeathRecipient) -> bool { - // SAFETY: - // The death recipient will no longer be notified when the remote object is destroyed. - unsafe { - ipc_binding::RemoveDeathRecipient(self.as_inner(), recipient.as_mut_raw()) - } - } - - fn is_proxy(&self) -> bool { - // SAFETY: - // Validate and ensure the validity of all pointers before using them. - unsafe { - ipc_binding::IsProxyObject(self.as_inner()) - } - } - - fn dump(&self, fd: i32, args: &mut Vec) -> i32 { - let mut parcel = match MsgParcel::new() { - Some(parcel) => parcel, - None => { - error!(LOG_LABEL, "create MsgParcel failed"); - return IpcStatusCode::Failed as i32; - } - }; - match parcel.write::>(args) { - Ok(_) => { - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - unsafe { - ipc_binding::Dump(self.as_inner(), fd, parcel.into_raw()) - } - } - _ => { - error!(LOG_LABEL, "create MsgParcel failed"); - IpcStatusCode::Failed as i32 - } - } - } - - fn is_dead(&self) -> bool { - // SAFETY: - //`object` always contains a valid pointer - unsafe { - ipc_binding::IsObjectDead(self.as_inner()) - } - } - - fn interface_descriptor(&self) -> IpcResult { - let mut vec: Option> = None; - // SAFETY: get the interface descriptor for a remote object. - // It's crucial here to ensure vec is valid and non-null before casting. - // Ensure the provided buffer size is sufficient to hold the returned data. - let ok_status = unsafe { - ipc_binding::GetInterfaceDescriptor( - self.as_inner(), - &mut vec as *mut _ as *mut c_void, - allocate_vec_with_buffer:: - ) - }; - if ok_status { - vec_u16_to_string(vec) - } else { - Err(IpcStatusCode::Failed) - } - } -} - -impl Serialize for RemoteObj { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - let ret = unsafe { - ipc_binding::CParcelWriteRemoteObject(parcel.as_mut_raw(), self.as_inner()) - }; - if ret { - Ok(()) - } else { - Err(IpcStatusCode::Failed) - } - } -} - -impl Deserialize for RemoteObj { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - // Safety: - // `Parcel` always contains a valid pointer to an `AParcel`. - // We pass a valid, mutable pointer to `val`, a literal of type `$ty`, - // and `$read_fn` will write the data into the memory pointed to by `val`. - let object = unsafe { - let remote = ipc_binding::CParcelReadRemoteObject(parcel.as_raw()); - Self::from_raw(remote) - }; - if let Some(x) = object { - Ok(x) - } else { - Err(IpcStatusCode::Failed) - } - } -} - -/// # Safety -/// -/// An `RemoteObj` is an immutable handle to CRemoteObject, which is thread-safe -unsafe impl Send for RemoteObj {} -/// # Safety -/// -/// An `RemoteObj` is an immutable handle to CRemoteObject, which is thread-safe -unsafe impl Sync for RemoteObj {} - -impl Clone for RemoteObj { - fn clone(&self) -> Self { - // SAFETY: - unsafe { - ipc_binding::RemoteObjectIncStrongRef(self.as_inner()); - } - // SAFETY: no `None` here, cause `self` is valid - Self(self.0) - } -} - -impl Drop for RemoteObj { - fn drop(&mut self) { - // SAFETY: - unsafe { - ipc_binding::RemoteObjectDecStrongRef(self.as_inner()); - } - } -} diff --git a/interfaces/innerkits/rust/src/ipc/remote_obj/cmp.rs b/interfaces/innerkits/rust/src/ipc/remote_obj/cmp.rs deleted file mode 100644 index 125533fb..00000000 --- a/interfaces/innerkits/rust/src/ipc/remote_obj/cmp.rs +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; -use std::cmp::Ordering; - -impl Ord for RemoteObj { - fn cmp(&self, other: &Self) -> Ordering { - // SAFETY: RemoteObj always holds a valid `CRemoteObject` pointer - // (null is also safe to pass to this function, but we should never do that). - let less_than = unsafe { - ipc_binding::RemoteObjectLessThan(self.0.as_ptr(), other.0.as_ptr()) - }; - // SAFETY: RemoteObj always holds a valid `CRemoteObject` pointer - // (null is also safe to pass to this function, but we should never do that). - let greater_than = unsafe { - ipc_binding::RemoteObjectLessThan(other.0.as_ptr(), self.0.as_ptr()) - }; - if (!less_than) && (!greater_than) { - Ordering::Equal - } else if less_than { - Ordering::Less - } else { - Ordering::Greater - } - } -} - -impl PartialOrd for RemoteObj { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for RemoteObj { - fn eq(&self, other: &Self) -> bool { - ptr::eq(self.0.as_ptr(), other.0.as_ptr()) - } -} - -impl Eq for RemoteObj {} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/ipc/remote_obj/death_recipient.rs b/interfaces/innerkits/rust/src/ipc/remote_obj/death_recipient.rs deleted file mode 100644 index 84763fb3..00000000 --- a/interfaces/innerkits/rust/src/ipc/remote_obj/death_recipient.rs +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; -use std::ffi::{CString, c_char}; -use hilog_rust::{info, hilog, HiLogLabel, LogType}; - -const LOG_LABEL: HiLogLabel = HiLogLabel { - log_type: LogType::LogCore, - domain: 0xD0057CA, - tag: "RustDeathRecipient" -}; - -/// This type represent a rust DeathRecipient which like C++ DethRecipient. -#[repr(C)] -pub struct DeathRecipient { - native: *mut CDeathRecipient, - callback: *mut c_void, -} - -impl DeathRecipient { - /// Create a rust DeathRecipient object with a death recipient callback. - pub fn new(callback: F) -> Option - where - F: Fn() + Send + Sync + 'static, - { - let callback = Box::into_raw(Box::new(callback)); - // SAFETY: set callback pointer to native, so we can find call which fuction - // when remote service died. - let native = unsafe { - ipc_binding::CreateDeathRecipient(Self::on_remote_died::, - Self::on_destroy::, callback as *mut c_void) - }; - if native.is_null() { - None - } else { - Some(DeathRecipient { - native, - callback: callback as *mut c_void, - }) - } - } - - /// Callback when remote service died by native. - /// - /// # Safety - /// - /// The callback parameter will be kept valid during native - /// CDeathRecipient object lifetime. - unsafe extern "C" fn on_remote_died(callback: *mut c_void) - where - F: Fn() + Send + Sync + 'static, - { - let callback = (callback as *const F).as_ref().expect("Failed to convert callback to reference"); - callback(); - } - - /// Callback when native CDeathRecipient destroyed - /// - /// # Safety - /// - /// The callback parameter will be kept valid during native - /// CDeathRecipient object lifetime. - unsafe extern "C" fn on_destroy(callback: *mut c_void) - where - F: Fn() + Send + Sync + 'static, - { - if callback.is_null() { - return; - } - info!(LOG_LABEL, "death recipient on destroy"); - drop(Box::from_raw(callback as *mut F)); - } -} - -/// # Safety -/// -/// A `DeathRecipient` is always constructed with a valid raw pointer -/// to a `CDeathRecipient`. -unsafe impl AsRawPtr for DeathRecipient { - fn as_raw(&self) -> *const CDeathRecipient { - self.native - } - - fn as_mut_raw(&mut self) -> *mut CDeathRecipient { - self.native - } -} - -impl Drop for DeathRecipient { - fn drop(&mut self) { - // Safety: DeathRecipient will always hold a reference for - // native CDeathRecipient. - unsafe { - ipc_binding::DeathRecipientDecStrongRef(self.native); - } - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/ipc/remote_stub.rs b/interfaces/innerkits/rust/src/ipc/remote_stub.rs deleted file mode 100644 index 53684ffd..00000000 --- a/interfaces/innerkits/rust/src/ipc/remote_stub.rs +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use crate::{ - ipc_binding, IRemoteStub, IRemoteBroker, IpcStatusCode, - RemoteObj, BorrowedMsgParcel, FileDesc, String16, -}; -use crate::ipc_binding::{CRemoteObject, CParcel}; -use std::ffi::{c_void, CString, c_char}; -use std::ops::Deref; -use hilog_rust::{ - info, error, hilog, HiLogLabel, - LogType -}; - -const LOG_LABEL: HiLogLabel = HiLogLabel { - log_type: LogType::LogCore, - domain: 0xD0057CA, - tag: "RustRemoteStub" -}; - -/// RemoteStub packed the native CRemoteObject and the rust stub object T -/// which must implement IRemoteStub trait. -/// Safety Invariant: The native pointer must be a valid pointer and cannot be null. -/// The native is guaranteed by the c interface -/// FFI Safety : Ensure stable memory layout C-ABI compatibility -#[repr(C)] -pub struct RemoteStub { - native: *mut CRemoteObject, - rust: *mut T, -} - -impl RemoteStub { - /// Create a RemoteStub object - pub fn new(rust: T) -> Option { - let rust = Box::into_raw(Box::new(rust)); - let descripor = CString::new(T::get_descriptor()).expect("descripor must be valid!"); - // SAFETY: The incoming parameters are FFI safety - // Descripor is converted to a string type compatible with the c interface through CString. - // on_remote_request and on_destroy callback function has been checked for security, - // and the parameter type is FFI safety - let native = unsafe { - // set rust object pointer to native, so we can figure out who deal - // the request during on_remote_request(). - ipc_binding::CreateRemoteStub(descripor.as_ptr(), Self::on_remote_request, - Self::on_destroy, rust as *mut c_void, Self::on_dump) - }; - - if native.is_null() { - None - } else { - Some( RemoteStub { native, rust } ) - } - } -} - -impl IRemoteBroker for RemoteStub { - fn as_object(&self) -> Option { - // SAFETY: - // Validate and ensure the validity of all pointers before using them. - // Be mindful of potential memory leaks and manage reference counts carefully. - unsafe { - // add remote object reference count - ipc_binding::RemoteObjectIncStrongRef(self.native); - // construct a new RemoteObject from a native pointer - RemoteObj::from_raw(self.native) - } - } -} - -unsafe impl Send for RemoteStub {} -/// # Safety -/// -/// RemoteSub thread safety. Multi-thread access and sharing have been considered inside the C-side code -unsafe impl Sync for RemoteStub {} - -impl Deref for RemoteStub { - type Target = T; - - fn deref(&self) -> &Self::Target { - // SAFETY: - // Rust `Box::into_raw` poiter, so is valid - unsafe { - &*self.rust - } - } -} - -impl Drop for RemoteStub { - fn drop(&mut self) { - // SAFETY: - // Because self is valid, its internal native pointer is valid. - unsafe { - ipc_binding::RemoteObjectDecStrongRef(self.native); - } - } -} - -/// C call Rust -impl RemoteStub { - /// # Safety - /// - /// The parameters passed in should ensure FFI safety - /// user_data pointer, data pointer and reply pointer on the c side must be guaranteed not to be null - unsafe extern "C" fn on_remote_request(user_data: *mut c_void, code: u32, - data: *const CParcel, reply: *mut CParcel) -> i32 { - let res = { - // BorrowedMsgParcel calls the correlation function from_raw must return as Some, - // direct deconstruction will not crash. - let mut reply = BorrowedMsgParcel::from_raw(reply).expect("MsgParcel should success"); - let data = match BorrowedMsgParcel::from_raw(data as *mut CParcel) { - Some(data) => data, - _ => { - error!(LOG_LABEL, "Failed to create BorrowedMsgParcel from raw pointer"); - return IpcStatusCode::Failed as i32; - } - }; - let rust_object: &T = &*(user_data as *mut T); - rust_object.on_remote_request(code, &data, &mut reply) - }; - res - } - /// # Safety - /// - /// The parameters passed in should ensure FFI safety - /// user_data pointer, data pointer and reply pointer on the c side must be guaranteed not to be null - unsafe extern "C" fn on_dump(user_data: *mut c_void, data: *const CParcel) -> i32 { - let res = { - let rust_object: &T = &*(user_data as *mut T); - // BorrowedMsgParcel calls the correlation functio from_raw must return as Some, - // direct deconstruction will not crash. - let data = match BorrowedMsgParcel::from_raw(data as *mut CParcel) { - Some(data) => data, - _ => { - error!(LOG_LABEL, "Failed to create BorrowedMsgParcel from raw pointer"); - return IpcStatusCode::Failed as i32; - } - }; - let file: FileDesc = match data.read::() { - Ok(file) => file, - _ => { - error!(LOG_LABEL, "read FileDesc failed"); - return IpcStatusCode::Failed as i32; - } - }; - let mut args: Vec = match data.read::>() { - Ok(args) => args, - _ => { - error!(LOG_LABEL, "read String16 array failed"); - return IpcStatusCode::Failed as i32; - } - }; - rust_object.on_dump(&file, &mut args) - }; - res - } - /// # Safety - /// - /// The parameters passed in should ensure FFI safety - /// user_data pointer, data pointer and reply pointer on the c side must be guaranteed not to be null - unsafe extern "C" fn on_destroy(user_data: *mut c_void) { - info!(LOG_LABEL, "RemoteStub on_destroy in Rust"); - // T will be freed by Box after this function end. - drop(Box::from_raw(user_data as *mut T)); - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/ipc_async/ipc_ylong.rs b/interfaces/innerkits/rust/src/ipc_async/ipc_ylong.rs index ec706db4..7bd45b0f 100644 --- a/interfaces/innerkits/rust/src/ipc_async/ipc_ylong.rs +++ b/interfaces/innerkits/rust/src/ipc_async/ipc_ylong.rs @@ -1,25 +1,23 @@ -/* - * Copyright (C) 2023 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. - */ +// Copyright (C) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use super::*; extern crate ylong_runtime; use std::future::Future; -use crate::is_handling_transaction; -use crate::errors::{IpcStatusCode}; + +use crate::errors::IpcStatusCode; /// Use the Ylong `spawn_blocking` pool pub enum Ylong {} @@ -36,13 +34,15 @@ impl IpcAsyncPool for Ylong { A: Send + 'static, B: Send + 'a, { - if is_handling_transaction() { - // We are currently on the thread pool for a binder server, so we should execute the - // transaction on the current thread so that the binder kernel driver is able to apply - // its deadlock prevention strategy to the sub-call. + if crate::process::is_handling_transaction() { + // We are currently on the thread pool for a binder server, so we should execute + // the transaction on the current thread so that the binder kernel + // driver is able to apply its deadlock prevention strategy to the + // sub-call. // - // This shouldn't cause issues with blocking the thread as only one task will run in a - // call to `block_on`, so there aren't other tasks to block. + // This shouldn't cause issues with blocking the thread as only one task will + // run in a call to `block_on`, so there aren't other tasks to + // block. let result = spawn_this(); Box::pin(after_handle(result)) } else { @@ -59,7 +59,8 @@ impl IpcAsyncPool for Ylong { } } -/// Wrapper around Ylong runtime types for providing a runtime to a binder server. +/// Wrapper around Ylong runtime types for providing a runtime to a binder +/// server. pub struct Runtime; impl IpcAsyncRuntime for Runtime { @@ -81,9 +82,7 @@ impl IpcAsyncRuntime for Runtime { ylong_runtime::spawn_blocking(task) } - fn block_on(future: F) -> F::Output - { + fn block_on(future: F) -> F::Output { ylong_runtime::block_on(future) } } - diff --git a/interfaces/innerkits/rust/src/ipc_async/mod.rs b/interfaces/innerkits/rust/src/ipc_async/mod.rs index 4519e5f7..78b8cd01 100644 --- a/interfaces/innerkits/rust/src/ipc_async/mod.rs +++ b/interfaces/innerkits/rust/src/ipc_async/mod.rs @@ -1,30 +1,30 @@ -/* - * Copyright (C) 2023 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. - */ +// Copyright (C) 2024 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. -pub mod ipc_ylong; -pub use ipc_ylong::{Runtime, Ylong}; +//! ipc async impl + +mod ipc_ylong; -use crate::errors::{IpcResult}; -use crate::ipc::{RemoteObjRef, FromRemoteObj}; -use crate::IRemoteBroker; use std::future::Future; use std::pin::Pin; + +pub use ipc_ylong::{Runtime, Ylong}; use ylong_runtime::task::JoinHandle; -/// A type alias for a pinned, boxed future that lets you write shorter code without littering it -/// with Pin and Send bounds. +use crate::errors::IpcResult; + +/// A type alias for a pinned, boxed future that lets you write shorter code +/// without littering it with Pin and Send bounds. pub type BoxFuture<'a, T> = Pin + Send + 'a>>; /// A thread pool for running ipc transactions. @@ -34,7 +34,10 @@ pub trait IpcAsyncPool { /// ```text /// let result = spawn(spawn, after_handle).await; /// ``` - fn spawn<'a, F1, F2, Fut, A, B>(spawn_this: F1, after_handle: F2) -> BoxFuture<'a, IpcResult> + fn spawn<'a, F1, F2, Fut, A, B>( + spawn_this: F1, + after_handle: F2, + ) -> BoxFuture<'a, IpcResult> where F1: FnOnce() -> A, F2: FnOnce(A) -> Fut, @@ -43,7 +46,7 @@ pub trait IpcAsyncPool { F2: Send + 'a, Fut: Send + 'a, A: Send + 'static, - B: Send + 'a,; + B: Send + 'a; } /// A runtime for executing an async ipc server. @@ -53,66 +56,16 @@ pub trait IpcAsyncRuntime { where T: Future, T: Send + 'static, - R: Send + 'static,; + R: Send + 'static; /// Using the default task setting, spawns a blocking task. fn spawn_blocking(task: T) -> JoinHandle where T: FnOnce() -> R, T: Send + 'static, - R: Send + 'static,; + R: Send + 'static; - /// Block on the provided future, running it to completion and returning its output. + /// Block on the provided future, running it to completion and returning its + /// output. fn block_on(future: F) -> F::Output; } - -/// Implemented by sync interfaces to specify what the associated async interface is. -/// Generic to handle the fact that async interfaces are generic over a thread pool. -/// -/// The binder in any object implementing this trait should be compatible with the -/// `Target` associated type, and using `FromIBinder` to convert it to the target -/// should not fail. -pub trait ToAsyncIpc

-where - Self: IRemoteBroker, - Self::Target: FromRemoteObj, -{ - /// The async interface associated with this sync interface. - type Target: ?Sized; -} - -/// Implemented by async interfaces to specify what the associated sync interface is. -/// -/// The binder in any object implementing this trait should be compatible with the -/// `Target` associated type, and using `FromRemoteObj` to convert it to the target -/// should not fail. -pub trait ToSyncIpc -where - Self: IRemoteBroker, - Self::Target: FromRemoteObj, -{ - /// The sync interface associated with this async interface. - type Target: ?Sized; -} - -impl RemoteObjRef { - /// Convert this synchronous remote object handle into an asynchronous one. - pub fn into_async

(&self) -> RemoteObjRef<>::Target> - where - I: ToAsyncIpc

, - { - // By implementing the ToAsyncIpc trait, it is guaranteed that the remote - // object is also valid for the target type. - FromRemoteObj::try_from(self.as_object().unwrap()).unwrap() - } - - /// Convert this asynchronous remote object handle into a synchronous one. - pub fn into_sync(&self) -> RemoteObjRef<::Target> - where - I: ToSyncIpc, - { - // By implementing the ToSyncIpc trait, it is guaranteed that the binder - // object is also valid for the target type. - FromRemoteObj::try_from(self.as_object().unwrap()).unwrap() - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/ipc_binding.rs b/interfaces/innerkits/rust/src/ipc_binding.rs deleted file mode 100644 index 770766c1..00000000 --- a/interfaces/innerkits/rust/src/ipc_binding.rs +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#![allow(dead_code)] - -use std::ffi::{c_char, c_void, c_ulong}; - -/// CRemoteObject is a member of RemoteObject, -/// RemoteObject always contained a native CRemoteObject pointer. -#[repr(C)] -pub struct CRemoteObject { - _private: [u8; 0], -} - -/// CIRemoteObject is a member of CRemoteObject, -/// CRemoteObject always contained a native CIRemoteObject pointer. -/// Please refer to the CRemoteObject object on side c -#[repr(C)] -pub struct CIRemoteObject { - _private: [u8; 0], -} - -#[repr(C)] -pub struct CDeathRecipient { - _private: [u8; 0], -} - -#[repr(C)] -pub struct CParcel { - _private: [u8; 0], -} - -#[repr(C)] -pub struct CAshmem { - _private: [u8; 0], -} - -// Callback function type for OnRemoteRequest() from native, this -// callback will be called when native recive client IPC request. -pub type OnRemoteRequest = unsafe extern "C" fn ( - user_data: *mut c_void, - code: u32, - data: *const CParcel, - reply: *mut CParcel -) -> i32; - -// Callback function type for OnRemoteDump() from native, this -// callback will be called when native recive client IPC dump. -pub type OnRemoteDump = unsafe extern "C" fn ( - user_data: *mut c_void, - data: *const CParcel, -) -> i32; - -// Callback function type for OnRemoteObjectDestroy() from native, -// this callback will be called when native remote object destroyed. -pub type OnRemoteObjectDestroy = unsafe extern "C" fn ( - user_data: *mut c_void -); - -// Callback function type for OnDeathRecipientCb() from native, -// this callback will be called when remote stub is destroyed. -pub type OnDeathRecipientCb = unsafe extern "C" fn ( - callback: *mut c_void -); - -// Callback function type for OnDeathRecipientDestroyCb() from native, -// this callback will be called when native CDeathRecipient destroyed. -pub type OnDeathRecipientDestroyCb = unsafe extern "C" fn ( - callback: *mut c_void -); - -// Callback function type for OnCParcelBytesAllocator() from native, -// this callback will be called when native parcel need allocate buffer -// for string or bytes buffer by rust. -pub type OnCParcelBytesAllocator = unsafe extern "C" fn ( - value: *mut c_void, - buffer: *mut *mut T, - len: i32 -) -> bool; - -pub type OnCParcelAllocator = unsafe extern "C" fn ( - value: *mut c_void, - len: i32 -) -> bool; - -// Callback function type for CParcelReadStringArray() from native. -// Rust side need read string one by one from native according calling -// CParcelReadStringElement(). -pub type OnStringArrayRead = unsafe extern "C" fn( - data: *const c_void, // C++ vector pointer - value: *mut c_void, // Rust vector pointer - len: u32 // C++ vector length -) -> bool; - -// Callback function type for CParcelReadString16Array() from native. -// Rust side need read string one by one from native according calling -// CParcelReadString16Element(). -pub type OnString16ArrayRead = unsafe extern "C" fn( - data: *const c_void, // C++ vector pointer - value: *mut c_void, // Rust vector pointer - len: u32 // C++ vector length -) -> bool; - -// Callback function type for CParcelWriteStringArray() from native. -// Rust side need write string one by one to native according calling -// CParcelWriteStringElement(). -pub type OnStringArrayWrite = unsafe extern "C" fn( - array: *const c_void, // C++ vector pointer - value: *mut c_void, // Rust vector pointer - len: u32, // Rust vector length -) -> bool; - -// Callback function type for CParcelWriteString16Array() from native. -// Rust side need write string one by one to native according calling -// CParcelWriteString16Element(). -pub type OnString16ArrayWrite = unsafe extern "C" fn( - array: *const c_void, // C++ vector pointer - value: *mut c_void, // Rust vector pointer - len: u32, // Rust vector length -) -> bool; - -pub type OnCParcelWriteElement = unsafe extern "C" fn ( - value: *mut CParcel, - arr: *const c_void, - index: c_ulong, -) -> bool; - -pub type OnCParcelReadElement = unsafe extern "C" fn ( - value: *const CParcel, - arr: *mut c_void, - index: c_ulong, -) -> bool; - -// C interface for IPC core object -extern "C" { - pub fn CreateCRemoteObject(object: *mut c_void) -> *mut CRemoteObject; - pub fn GetCIRemoteObject(object: *mut CRemoteObject) -> *mut c_void; - pub fn CreateRemoteStub(descripor: *const c_char, on_remote_request: OnRemoteRequest, - on_remote_object_destroy: OnRemoteObjectDestroy, - user_data: *const c_void, on_remote_dump: OnRemoteDump) -> *mut CRemoteObject; - pub fn RemoteObjectIncStrongRef(object: *mut CRemoteObject); - pub fn RemoteObjectDecStrongRef(object: *mut CRemoteObject); - - pub fn RemoteObjectSendRequest(object: *mut CRemoteObject, code: u32, - data: *const CParcel, reply: *mut CParcel, is_async: bool) -> i32; - pub fn RemoteObjectLessThan(object: *const CRemoteObject, - other: *const CRemoteObject) -> bool; - - pub fn CreateDeathRecipient(onDeathRecipient: OnDeathRecipientCb, - onDestroy: OnDeathRecipientDestroyCb, - userData: *const c_void) -> *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; - - pub fn IsProxyObject(object: *mut CRemoteObject) -> bool; - pub fn Dump(object: *mut CRemoteObject, fd: i32, parcel: *mut CParcel) -> i32; - - pub fn IsObjectDead(object: *mut CRemoteObject) -> bool; - pub fn GetInterfaceDescriptor(object: *mut CRemoteObject, - value: *mut c_void, allocator: OnCParcelBytesAllocator::) -> bool; -} - -// C interface for Parcel -extern "C" { - pub fn CParcelObtain() -> *mut CParcel; - pub fn CParcelDecStrongRef(parcel: *mut CParcel); - - pub fn CParcelWriteBool(parcel: *mut CParcel, value: bool) -> bool; - pub fn CParcelReadBool(parcel: *const CParcel, value: *mut bool) -> bool; - pub fn CParcelWriteInt8(parcel: *mut CParcel, value: i8) -> bool; - pub fn CParcelReadInt8(parcel: *const CParcel, value: *mut i8) -> bool; - pub fn CParcelWriteInt16(parcel: *mut CParcel, value: i16) -> bool; - pub fn CParcelReadInt16(parcel: *const CParcel, value: *mut i16) -> bool; - pub fn CParcelWriteInt32(parcel: *mut CParcel, value: i32) -> bool; - pub fn CParcelReadInt32(parcel: *const CParcel, value: *mut i32) -> bool; - pub fn CParcelWriteInt64(parcel: *mut CParcel, value: i64) -> bool; - pub fn CParcelReadInt64(parcel: *const CParcel, value: *mut i64) -> bool; - pub fn CParcelWriteFloat(parcel: *mut CParcel, value: f32) -> bool; - pub fn CParcelReadFloat(parcel: *const CParcel, value: *mut f32) -> bool; - pub fn CParcelWriteDouble(parcel: *mut CParcel, value: f64) -> bool; - pub fn CParcelReadDouble(parcel: *const CParcel, value: *mut f64) -> bool; - pub fn CParcelWriteString(parcel: *mut CParcel, value: *const c_char, len: i32) -> bool; - pub fn CParcelReadString(parcel: *const CParcel, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelWriteString16(parcel: *mut CParcel, value: *const c_char, len: i32) -> bool; - pub fn CParcelReadString16(parcel: *const CParcel, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelWriteInterfaceToken(parcel: *mut CParcel, - token: *const c_char, len: i32) -> bool; - pub fn CParcelReadInterfaceToken(parcel: *const CParcel, token: *mut c_void, - 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 u8, len: u32) -> bool; - pub fn CParcelReadBuffer(parcel: *const CParcel, value: *mut u8, len: u32) -> bool; - pub fn CParcelWriteRawData(parcel: *mut CParcel, value: *const u8, len: u32) -> bool; - pub fn CParcelReadRawData(parcel: *const CParcel, len: u32) -> *mut u8; - pub fn CParcelWriteFileDescriptor(parcel: *mut CParcel, fd: i32) -> bool; - pub fn CParcelReadFileDescriptor(parcel: *const CParcel, fd: *mut i32) -> bool; - - pub fn CParcelWriteBoolArray(parcel: *mut CParcel, value: *const bool, len: i32) -> bool; - pub fn CParcelReadBoolArray(parcel: *const CParcel, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelWriteInt8Array(parcel: *mut CParcel, value: *const i8, len: i32) -> bool; - pub fn CParcelReadInt8Array(parcel: *const CParcel, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelWriteInt16Array(parcel: *mut CParcel, value: *const i16, len: i32) -> bool; - pub fn CParcelReadInt16Array(parcel: *const CParcel, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelWriteInt32Array(parcel: *mut CParcel, value: *const i32, len: i32) -> bool; - pub fn CParcelReadInt32Array(parcel: *const CParcel, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelWriteInt64Array(parcel: *mut CParcel, value: *const i64, len: i32) -> bool; - pub fn CParcelReadInt64Array(parcel: *const CParcel, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelWriteFloatArray(parcel: *mut CParcel, value: *const f32, len: i32) -> bool; - pub fn CParcelReadFloatArray(parcel: *const CParcel, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelWriteDoubleArray(parcel: *mut CParcel, value: *const f64, len: i32) -> bool; - pub fn CParcelReadDoubleArray(parcel: *const CParcel, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelWriteStringArray(parcel: *mut CParcel, value: *const c_void, len: i32, - writer: OnStringArrayWrite) -> bool; - pub fn CParcelWriteString16Array(parcel: *mut CParcel, value: *const c_void, len: i32, - writer: OnString16ArrayWrite) -> bool; - pub fn CParcelWriteStringElement(data: *const c_void, value: *const c_char, - len: i32) -> bool; - pub fn CParcelWritU16stringElement(data: *const c_void, value: *const c_char, - len: i32) -> bool; - pub fn CParcelReadStringArray(parcel: *const CParcel, value: *mut c_void, - reader: OnStringArrayRead) -> bool; - pub fn CParcelReadString16Array(parcel: *const CParcel, value: *mut c_void, - reader: OnString16ArrayRead) -> bool; - pub fn CParcelReadStringElement(index: u32, data: *const c_void, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelReadString16Element(index: u32, data: *const c_void, value: *mut c_void, - allocator: OnCParcelBytesAllocator::) -> bool; - pub fn CParcelWriteParcelableArray(parcel: *mut CParcel, value: *const c_void, len: i32, - element_writer: OnCParcelWriteElement) -> bool; - pub fn CParcelReadParcelableArray(parcel: *const CParcel, value: *mut c_void, - allocator: OnCParcelAllocator, element_reader: OnCParcelReadElement ) -> bool; - - pub fn CParcelGetDataSize(parcel: *const CParcel) -> u32; - pub fn CParcelSetDataSize(parcel: *mut CParcel, new_size: u32) -> bool; - pub fn CParcelGetDataCapacity(parcel: *const CParcel) -> u32; - pub fn CParcelSetDataCapacity(parcel: *mut CParcel, new_size: u32) -> bool; - pub fn CParcelGetMaxCapacity(parcel: *const CParcel) -> u32; - pub fn CParcelSetMaxCapacity(parcel: *mut CParcel, new_size: u32) -> bool; - pub fn CParcelGetWritableBytes(parcel: *const CParcel) -> u32; - pub fn CParcelGetReadableBytes(parcel: *const CParcel) -> u32; - pub fn CParcelGetReadPosition(parcel: *const CParcel) -> u32; - pub fn CParcelGetWritePosition(parcel: *const CParcel) -> u32; - pub fn CParcelRewindRead(parcel: *mut CParcel, new_pos: u32) -> bool; - pub fn CParcelRewindWrite(parcel: *mut CParcel, new_pos: u32) -> bool; - pub fn CParcelWriteAshmem(parcel: *mut CParcel, ashmem: *mut CAshmem) -> bool; - pub fn CParcelReadAshmem(parcel: *const CParcel) -> *mut CAshmem; - - pub fn CParcelContainFileDescriptors(parcel: *const CParcel) -> bool; - pub fn CParcelGetRawDataSize(parcel: *const CParcel) -> usize; - pub fn CParcelGetRawDataCapacity(parcel: *const CParcel) -> usize; - pub fn CParcelClearFileDescriptor(parcel: *mut CParcel); - pub fn CParcelSetClearFdFlag(parcel: *mut CParcel); - pub fn CParcelAppend(parcel: *mut CParcel, data: *mut CParcel) -> bool; -} - -// C interface for Ashmem -extern "C" { - pub fn CreateCAshmem(name: *const c_char, size: i32) -> *mut CAshmem; - pub fn CAshmemIncStrongRef(ashmem: *mut CAshmem); - pub fn CAshmemDecStrongRef(ashmem: *mut CAshmem); - - pub fn CloseCAshmem(ashmem: *mut CAshmem); - pub fn MapCAshmem(ashmem: *mut CAshmem, mapType: i32) -> bool; - pub fn MapReadAndWriteCAshmem(ashmem: *mut CAshmem) -> bool; - pub fn MapReadOnlyCAshmem(ashmem: *mut CAshmem) -> bool; - pub fn UnmapCAshmem(ashmem: *mut CAshmem); - pub fn SetCAshmemProtection(ashmem: *mut CAshmem, protectionType: i32) -> bool; - pub fn GetCAshmemProtection(ashmem: *const CAshmem) -> i32; - pub fn GetCAshmemSize(ashmem: *const CAshmem) -> i32; - pub fn WriteToCAshmem(ashmem: *mut CAshmem, data: *const u8, - size: i32, offset: i32) -> bool; - pub fn ReadFromCAshmem(ashmem: *const CAshmem, size: i32, offset: i32) -> *const u8; - pub fn GetCAshmemFd(ashmem: *const CAshmem) -> i32; -} - -// C interface for IPC miscellaneous -extern "C" { - pub fn GetContextManager() -> *mut CRemoteObject; - pub fn JoinWorkThread(); - pub fn StopWorkThread(); - pub fn GetCallingTokenId() -> u64; - pub fn GetFirstToekenId() -> u64; - pub fn GetSelfToekenId() -> u64; - pub fn GetCallingPid() -> u64; - pub fn GetCallingUid() -> u64; - - pub fn SetMaxWorkThreadNum(maxThreadNum: i32) -> bool; - pub fn IsLocalCalling() -> bool; - pub fn SetCallingIdentity(identity: *const c_char) -> bool; - pub fn GetLocalDeviceID(value: *mut c_void, allocator: OnCParcelBytesAllocator::) -> bool; - pub fn GetCallingDeviceID(value: *mut c_void, allocator: OnCParcelBytesAllocator::) -> bool; - pub fn ResetCallingIdentity(value: *mut c_void, allocator: OnCParcelBytesAllocator::) -> bool; - - pub fn IsHandlingTransaction() -> bool; -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/lib.rs b/interfaces/innerkits/rust/src/lib.rs index bbd6eba7..c8b4a220 100644 --- a/interfaces/innerkits/rust/src/lib.rs +++ b/interfaces/innerkits/rust/src/lib.rs @@ -1,82 +1,44 @@ -/* - * 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. - */ +// Copyright (C) 2024 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. //! Safe Rust interface to OHOS IPC/RPC +#![allow(clippy::missing_safety_doc)] +#![allow(missing_docs, unused)] + +#[macro_use] +mod hilog; -mod ipc_binding; mod errors; -mod ipc; -mod ipc_async; -mod parcel; -mod process; -mod ashmem; +pub mod ipc_async; +pub mod parcel; +pub mod process; +pub mod remote; + +pub mod cxx_share; +mod skeleton; // Export types of this crate -pub use crate::errors::{IpcResult, status_result, IpcStatusCode, parse_status_code}; -pub use crate::ipc::{ - IRemoteBroker, IRemoteObj, IRemoteStub, FromRemoteObj, - RemoteObjRef, remote_obj::RemoteObj, remote_obj::death_recipient::DeathRecipient, remote_stub::RemoteStub, -}; -pub use crate::ipc_async::{ - IpcAsyncPool, IpcAsyncRuntime, ToAsyncIpc, ToSyncIpc, - BoxFuture, Ylong, Runtime, -}; - -pub use crate::parcel::{ - MsgParcel, BorrowedMsgParcel, IMsgParcel, RawData, - parcelable::{Serialize, Deserialize, SerOption, DeOption}, -}; -pub use crate::parcel::parcelable::{SerArray, DeArray}; -pub use crate::parcel::types::{ - interface_token::InterfaceToken, file_desc::FileDesc, string16::String16 -}; -pub use crate::ashmem::{ - Ashmem, PROT_NONE, PROT_READ, PROT_WRITE, - PROT_EXEC, -}; -pub use crate::process::{ - get_context_object, 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, set_max_work_thread, is_local_calling, - set_calling_identity, get_local_device_id, get_calling_device_id, reset_calling_identity, - is_handling_transaction, -}; - -pub use crate::ipc_binding::{CRemoteObject, CIRemoteObject}; +pub use crate::errors::{parse_status_code, status_result, IpcResult, IpcStatusCode}; /// First request code available for user IPC request(inclusive) pub const FIRST_CALL_TRANSACTION: isize = 0x00000001; /// Last request code available for user IPC request(inclusive) pub const LAST_CALL_TRANSACTION: isize = 0x00ffffff; +use hilog_rust::{HiLogLabel, LogType}; +pub use skeleton::Skeleton; -/// Trait for transparent Rust wrappers around native raw pointer types. -/// -/// # Safety -/// -/// The pointer return by this trait's methods should be immediately passed to -/// native and not stored by Rust. The pointer is valid only as long as the -/// underlying native object is alive, so users must be careful to take this into -/// account, as Rust cannot enforce this. -/// -/// For this trait to be a correct implementation, `T` must be a valid native -/// type. Since we cannot constrain this via the type system, this trait is -/// marked as unsafe. -pub unsafe trait AsRawPtr { - /// Return a pointer to the native version of `self` - fn as_raw(&self) -> *const T; - - /// Return a mutable pointer to the native version of `self` - fn as_mut_raw(&mut self) -> *mut T; -} \ No newline at end of file +const LOG_LABEL: HiLogLabel = HiLogLabel { + log_type: LogType::LogCore, + domain: 0xD0057CA, + tag: "IPC_RUST", +}; diff --git a/interfaces/innerkits/rust/src/parcel/error.rs b/interfaces/innerkits/rust/src/parcel/error.rs new file mode 100644 index 00000000..4bccaac9 --- /dev/null +++ b/interfaces/innerkits/rust/src/parcel/error.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2024 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. + +//! Parcel Errors + +use std::error::Error; +use std::fmt; + +/// An error indicating that Parcel set size failed. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ParcelSetError; + +impl fmt::Display for ParcelSetError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "parcel set size failed") + } +} + +impl Error for ParcelSetError {} diff --git a/interfaces/innerkits/rust/src/parcel/exts.rs b/interfaces/innerkits/rust/src/parcel/exts.rs new file mode 100644 index 00000000..6bbe7b97 --- /dev/null +++ b/interfaces/innerkits/rust/src/parcel/exts.rs @@ -0,0 +1,159 @@ +// Copyright (C) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +use super::msg::MsgParcel; +use crate::errors::IpcResult; +/// Data structures that can be serialized and written by MsgPracel +/// +/// # Example: +/// +/// ```rust +/// use ipc::parcel::{MsgParcel, Serialize}; +/// use ipc::IpcResult; +/// +/// struct Foo { +/// a: Vec, +/// b: String, +/// } +/// +/// impl Serialize for Foo { +/// fn serialize(&self, parcel: &mut MsgParcel) -> IpcResult<()> { +/// parcel.write(&self.a)?; +/// parcel.write(&self.b)?; +/// Ok(()) +/// } +/// } +/// ``` +pub trait Serialize { + /// serialize and write into MsgParcel + fn serialize(&self, parcel: &mut MsgParcel) -> IpcResult<()>; +} + +/// Data structures that can be deserialized and read out by MsgPracel,typically +/// used in conjunction with [`Serialize`]. +/// +/// # Example: +/// +/// ```rust +/// use ipc::parcel::{Deserialize, MsgParcel}; +/// use ipc::IpcResult; +/// +/// struct Foo { +/// a: Vec, +/// b: String, +/// } +/// +/// impl Deserialize for Foo { +/// fn deserialize(parcel: &mut MsgParcel) -> IpcResult { +/// let a = parcel.read()?; +/// let b = parcel.read()?; +/// Ok(Self { a, b }) +/// } +/// } +/// ``` +pub trait Deserialize: Sized { + /// Deserialize and read out from MsgParcel. + fn deserialize(parcel: &mut MsgParcel) -> IpcResult; +} + +pub const NULL_FLAG: i32 = 0; +pub const NON_NULL_FLAG: i32 = 1; + +impl Serialize for Option { + fn serialize(&self, parcel: &mut MsgParcel) -> IpcResult<()> { + if let Some(inner) = self { + parcel.write(&NON_NULL_FLAG)?; + parcel.write(inner) + } else { + parcel.write(&NULL_FLAG) + } + } +} + +impl Deserialize for Option { + fn deserialize(parcel: &mut MsgParcel) -> IpcResult { + let null: i32 = parcel.read()?; + if null == NULL_FLAG { + Ok(None) + } else { + parcel.read().map(Some) + } + } +} + +#[cfg(test)] +mod test { + use super::{Deserialize, Serialize}; + use crate::parcel::MsgParcel; + #[derive(PartialEq, Eq, Debug)] + struct TestStruct { + a: bool, + b: i8, + c: String, + } + + /// UT test cases for `Serialize` + /// + /// # Brief + /// 1. Impl Serialize for a type. + /// 2. Write this type to the MsgParcel and then read it out, check the + /// correctness. + #[test] + fn serialize_test() { + impl Serialize for TestStruct { + fn serialize(&self, parcel: &mut crate::parcel::MsgParcel) -> crate::IpcResult<()> { + parcel.write(&self.a).unwrap(); + parcel.write(&self.c).unwrap(); + Ok(()) + } + } + let mut msg = MsgParcel::new(); + let test = TestStruct { + a: true, + b: 0, + c: String::from("hello"), + }; + msg.write(&test).unwrap(); + assert!(msg.read::().unwrap()); + assert_eq!(String::from("hello"), msg.read::().unwrap()); + } + + /// UT test cases for `Deserialize` + /// + /// # Brief + /// 1. Impl Deserialize for a type. + /// 2. Write this type to the MsgParcel and then read it out, check the + /// correctness. + #[test] + fn deserialize_test() { + impl Deserialize for TestStruct { + fn deserialize(parcel: &mut MsgParcel) -> crate::IpcResult { + let a = parcel.read().unwrap(); + let b = parcel.read().unwrap(); + let c = parcel.read().unwrap(); + Ok(Self { a, b, c }) + } + } + let mut msg = MsgParcel::new(); + let test = TestStruct { + a: true, + b: 0, + c: String::from("hello"), + }; + msg.write(&test.a).unwrap(); + msg.write(&test.b).unwrap(); + msg.write(&test.c).unwrap(); + assert_eq!(test, msg.read().unwrap()); + } +} diff --git a/interfaces/innerkits/rust/src/parcel/mod.rs b/interfaces/innerkits/rust/src/parcel/mod.rs index ab9fc5bb..c784be8a 100644 --- a/interfaces/innerkits/rust/src/parcel/mod.rs +++ b/interfaces/innerkits/rust/src/parcel/mod.rs @@ -1,440 +1,23 @@ -/* - * 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. - */ +// Copyright (C) 2024 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. -pub mod parcelable; -pub mod types; +//! IPC MsgParcel -pub use types::on_string16_writer; -pub use types::vec_u16_to_string; -pub use types::vec_to_string; -pub use parcelable::allocate_vec_with_buffer; +mod exts; +pub(crate) mod msg; -use crate::{ipc_binding, IpcResult, IpcStatusCode}; -use crate::ipc_binding::CParcel; -use std::marker::PhantomData; -use std::mem::{ManuallyDrop, MaybeUninit}; -use std::ops::Drop; -use std::ptr::NonNull; -use std::slice; -use crate::AsRawPtr; -use crate::parcel::parcelable::{Serialize, Deserialize}; +pub(crate) mod wrapper; -/// This trait implements the common function for MsgParcel -/// and BorrowedMsgParcel -pub trait IMsgParcel: AsRawPtr { - /// Get current data size in parcel - fn get_data_size(&self) -> u32 { - // SAFETY: - // The self reference must be valid and point to a properly allocated CParcel object - unsafe { - ipc_binding::CParcelGetDataSize(self.as_raw()) - } - } - - /// Set current data size in parcel - fn set_data_size(&mut self, new_size: u32) -> bool { - // SAFETY: - // The self reference must be valid and point to a properly allocated CParcel object. - // Calling this function with an invalid self reference can lead to undefined behavior, - // including memory access violations and data corruption. - unsafe { - ipc_binding::CParcelSetDataSize(self.as_mut_raw(), new_size) - } - } - - /// Get current data capacity in parcel - fn get_data_capacity(&self) -> u32 { - // SAFETY: - unsafe { - ipc_binding::CParcelGetDataCapacity(self.as_raw()) - } - } - - /// Set current data capacity in parcel - fn set_data_capacity(&mut self, new_size: u32) -> bool { - // SAFETY: - unsafe { - ipc_binding::CParcelSetDataCapacity(self.as_mut_raw(), new_size) - } - } - - /// Get maximum capacity in parcel - fn get_max_capacity(&self) -> u32 { - // SAFETY: - unsafe { - ipc_binding::CParcelGetMaxCapacity(self.as_raw()) - } - } - - /// Set maximum capacity in parcel - fn set_max_capacity(&mut self, new_size: u32) -> bool { - // SAFETY: - unsafe { - ipc_binding::CParcelSetMaxCapacity(self.as_mut_raw(), new_size) - } - } - - /// Get current writalbe bytes in parcel - fn get_writable_bytes(&self) -> u32 { - // SAFETY: - unsafe { - ipc_binding::CParcelGetWritableBytes(self.as_raw()) - } - } - - /// Get current readable bytes in parcel - fn get_readable_bytes(&self) -> u32 { - // SAFETY: - unsafe { - ipc_binding::CParcelGetReadableBytes(self.as_raw()) - } - } - - /// Get current read position of parcel - fn get_read_position(&self) -> u32 { - // SAFETY: - unsafe { - ipc_binding::CParcelGetReadPosition(self.as_raw()) - } - } - - /// Get current write position of parcel - fn get_write_position(&self) -> u32 { - // SAFETY: - 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 { - // SAFETY: - 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 { - // SAFETY: - 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) -> IpcResult> { - let mut buffer: Vec> = Vec::with_capacity(len as usize); - // SAFETY: this is safe because the vector contains MaybeUninit elements which can be uninitialized - unsafe{ - buffer.set_len(len as usize); - } - // SAFETY: - let ok_status = unsafe { - ipc_binding::CParcelReadBuffer( - self.as_raw(), - buffer.as_mut_ptr() as *mut u8, - len - ) - }; - // SAFETY: MaybeUninit has been initialized, this should be safe - // since MaybeUninit should have same layout as inner type - unsafe fn transmute_vec(v: Vec>) -> Vec { - std::mem::transmute(v) - } - // SAFETY: - let buffer = unsafe { transmute_vec(buffer) }; - if ok_status { Ok(buffer) } else { Err(IpcStatusCode::Failed) } - } - - /// Write a large bytes stream into parcel - fn write_raw_data(&mut self, data: &[u8]) -> bool { - // SAFETY: - unsafe { - ipc_binding::CParcelWriteRawData(self.as_mut_raw(), - data.as_ptr(), data.len() as u32) - } - } - - /// Read a big bytes stream from parcel - fn read_raw_data(&self, len: u32) -> IpcResult { - // SAFETY: - let raw_data_ptr = unsafe { - ipc_binding::CParcelReadRawData(self.as_raw(), len) - }; - if raw_data_ptr.is_null() { - Err(IpcStatusCode::Failed) - } else { - Ok(RawData::new(raw_data_ptr, len)) - } - } - - /// contain file descriptors - fn has_fd(&self) -> bool { - // SAFETY: - unsafe { - ipc_binding::CParcelContainFileDescriptors(self.as_raw()) - } - } - - /// clear file descriptor - fn clear_fd(&mut self) { - // SAFETY: - unsafe { - ipc_binding::CParcelClearFileDescriptor(self.as_mut_raw()); - } - } - - /// get raw data size - fn get_raw_data_size(&self) -> usize { - // SAFETY: - unsafe { - ipc_binding::CParcelGetRawDataSize(self.as_raw()) - } - } - - /// get raw data capacity - fn get_raw_data_capacity(&self) -> usize { - // SAFETY: - unsafe { - ipc_binding::CParcelGetRawDataCapacity(self.as_raw()) - } - } - - /// set clear fd flag - fn set_clear_fd_flag(&mut self) { - // SAFETY: - unsafe { - ipc_binding::CParcelSetClearFdFlag(self.as_mut_raw()); - } - } - - /// append a MsgParcel - fn append(&mut self, data: &mut MsgParcel) -> bool { - let data_parcel = data.as_mut_raw(); - // SAFETY: - unsafe { - ipc_binding::CParcelAppend(self.as_mut_raw(), data_parcel) - } - } -} - -/// Rust RawData type which just for fetch data from C++ MssageParcel::ReadRawData() -#[repr(C)] -pub struct RawData{ - raw_ptr: *const u8, - len: u32, -} - -impl RawData{ - /// Create RawData object - pub fn new(raw_ptr: *const u8, len: u32) -> Self { - RawData { - raw_ptr, - len, - } - } - - /// The caller should ensure that the u8 slice can be - /// correctly converted to other rust types - pub fn read(&self, start: u32, len: u32) -> IpcResult<&[u8]> { - if (len == 0) || (len > self.len) || (start >= self.len) || ((start + len) > self.len) { - return Err(IpcStatusCode::Failed); - } - // SAFETY: - // raw_ptr is valid in [0..len], the memory is matained by C++ Parcel. - let data_ptr = unsafe { - self.raw_ptr.add(start as usize) - }; - if data_ptr.is_null() { - Err(IpcStatusCode::Failed) - } else { - // SAFETY: - // 1. data is valid for reads for `len * mem::size_of::() ` - // 2. The entire memory range of this slice be contained within a single allocated object (From Cpp) - // 3. data_ptr point to len consecutive properly initialized values of `u8` - // 4. The total size `len * mem::size_of::()` of the slice is no larger than `isize::MAX` - unsafe { - Ok(slice::from_raw_parts::(data_ptr, len as usize)) - } - } - } -} - - -/// Container for a message (data and object references) that can be sent -/// through Binder. -/// -/// This type represents a parcel that is owned by Rust code. -#[repr(transparent)] -pub struct MsgParcel { - ptr: NonNull, -} -/// # Safety -/// -/// An `MsgParcel` is an immutable handle to CParcel, which is thread-safe -unsafe impl Send for MsgParcel {} - -/// # Safety -/// -/// An `MsgParcel` is an immutable handle to CParcel, which is thread-safe -unsafe impl Sync for MsgParcel {} - -impl IMsgParcel for MsgParcel {} - -impl MsgParcel { - /// Create a MsgParcel object - pub fn new() -> Option { - // SAFETY: - let cparcel: *mut CParcel = unsafe { - ipc_binding::CParcelObtain() - }; - - NonNull::new(cparcel).map(|x| MsgParcel{ptr: x}) - } - - /// # Safety - pub unsafe fn from_raw(ptr: *mut CParcel) -> Option { - NonNull::new(ptr).map(|ptr| Self { ptr }) - } - - /// Get a raw CParcel pointer and MsgParcel dropped its ownership - pub fn into_raw(self) -> *mut CParcel { - let ptr = self.ptr.as_ptr(); - let _ = ManuallyDrop::new(self); - ptr - } - - /// Get a borrowed view into the contents of this `MsgParcel`. - pub fn borrowed(&mut self) -> BorrowedMsgParcel<'_> { - // SAFETY: The raw pointer is a valid pointer - BorrowedMsgParcel { - ptr: self.ptr, - _mark: PhantomData, - } - } - - /// Get an immutable borrowed view into the contents of this `MsgParcel`. - pub fn borrowed_ref(&self) -> &BorrowedMsgParcel<'_> { - // Safety: MsgParcel and BorrowedParcel are both represented in the same - // way as a NonNull due to their use of repr(transparent), - // so casting references as done here is valid. - unsafe { - &*(self as *const MsgParcel as *const BorrowedMsgParcel<'_>) - } - } -} - -/// # Safety -/// -/// The `MsgParcel` constructors guarantee that a `MsgParcel` object will always -/// contain a valid pointer to an `CParcel`. -unsafe impl AsRawPtr for MsgParcel { - fn as_raw(&self) -> *const CParcel { - self.ptr.as_ptr() - } - - fn as_mut_raw(&mut self) -> *mut CParcel { - self.ptr.as_ptr() - } -} - -impl Drop for MsgParcel { - fn drop(&mut self) { - // Safety: - unsafe { - ipc_binding::CParcelDecStrongRef(self.as_mut_raw()) - } - } -} - -/// Container for a message (data and object references) that can be sent -/// through Binder. -/// -/// This object is a borrowed variant of [`MsgParcel`] -#[repr(transparent)] -pub struct BorrowedMsgParcel<'a> { - ptr: NonNull, - _mark: PhantomData<&'a mut MsgParcel>, -} - -impl<'a> IMsgParcel for BorrowedMsgParcel<'a> {} - -impl<'a> BorrowedMsgParcel<'a> { - /// # Safety - /// - /// `*mut CParcel` must be a valid pointer - pub unsafe fn from_raw(ptr: *mut CParcel) -> Option> { - Some(Self { - ptr: NonNull::new(ptr)?, - _mark: PhantomData, - }) - } - - /// Get a sub-reference to this reference to the parcel. - pub fn reborrow(&mut self) -> BorrowedMsgParcel<'_> { - BorrowedMsgParcel { - ptr: self.ptr, - _mark: PhantomData, - } - } -} - -/// # Safety -/// -/// The `BorrowedMsgParcel` constructors guarantee that a `BorrowedMsgParcel` object -/// will always contain a valid pointer to an `CParcel`. -unsafe impl<'a> AsRawPtr for BorrowedMsgParcel<'a> { - fn as_raw(&self) -> *const CParcel { - self.ptr.as_ptr() - } - - fn as_mut_raw(&mut self) -> *mut CParcel { - self.ptr.as_ptr() - } -} - -impl MsgParcel { - /// Read a data object which implements the Deserialize trait from MsgParcel - pub fn read(&self) -> IpcResult { - self.borrowed_ref().read() - } - - /// Write a data object which implements the Serialize trait to MsgParcel - pub fn write(&mut self, parcelable: &S) -> IpcResult<()> { - self.borrowed().write(parcelable) - } -} - -impl<'a> BorrowedMsgParcel<'a> { - /// Read a data object which implements the Deserialize trait from BorrowedMsgParcel - pub fn read(&self) -> IpcResult { - D::deserialize(self) - } - - /// Write a data object which implements the Serialize trait to BorrowedMsgParcel - pub fn write(&mut self, parcelable: &S) -> IpcResult<()> { - parcelable.serialize(self) - } -} \ No newline at end of file +pub mod error; +pub use exts::{Deserialize, Serialize}; +pub use msg::{MsgOption, MsgParcel}; diff --git a/interfaces/innerkits/rust/src/parcel/msg.rs b/interfaces/innerkits/rust/src/parcel/msg.rs new file mode 100644 index 00000000..da6211c2 --- /dev/null +++ b/interfaces/innerkits/rust/src/parcel/msg.rs @@ -0,0 +1,832 @@ +// Copyright (C) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::borrow::Borrow; +use std::fs::File; +use std::mem; +use std::ops::Deref; +use std::os::fd::{FromRawFd, IntoRawFd}; +use std::pin::Pin; + +use cxx::UniquePtr; + +use super::error::ParcelSetError; +use super::wrapper::{ + AsParcel, AsParcelMut, MessageOption, MessageParcel, NewMessageOption, NewMessageParcel, + Parcel, ReadBuffer, ReadInterfaceToken, ReadRemoteObject, ReadString16, ReadString16Vector, + WriteBuffer, WriteInterfaceToken, WriteRemoteObject, WriteString16, WriteString16Vector, +}; +use super::{Deserialize, Serialize}; +use crate::parcel::wrapper::IRemoteObjectWrapper; +use crate::remote::RemoteObj; +use crate::{IpcResult, IpcStatusCode}; +const STRING_16_SIZE: usize = 12; + +pub(crate) enum ParcelMem { + Unique(UniquePtr), + Borrow(*mut MessageParcel), + Null, +} + +/// Ipc MsgParcel +pub struct MsgParcel { + pub(crate) inner: ParcelMem, +} + +unsafe impl Send for MsgParcel {} +unsafe impl Send for MsgOption {} + +impl MsgParcel { + /// Creates a new, empty MsgParcel. + /// + /// # Panics + /// Panics if allocate failed. + /// + /// # Examples + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let msg = MsgParcel::new(); + /// ``` + pub fn new() -> Self { + let ptr = NewMessageParcel(); + assert!(!ptr.is_null(), "memory allocation of MessageParcel failed"); + Self { + inner: ParcelMem::Unique(ptr), + } + } + + /// create MsgParcel from raw ptr + pub fn from_ptr(ptr: *mut MessageParcel) -> Self { + Self { + inner: ParcelMem::Borrow(ptr), + } + } + + /// into raw ptr + pub fn into_raw(self) -> *mut MessageParcel { + match self.inner { + ParcelMem::Unique(p) => p.into_raw(), + ParcelMem::Borrow(p) => p, + ParcelMem::Null => unreachable!(), + } + } + + /// Writes a [`Serialize`] value into this MsgParcel. + /// + /// [Serialize]: crate::parcel::Serialize + /// + /// # Example + /// ``` rust + /// use ipc::parcel::{MsgParcel, Serialize}; + /// use ipc::IpcResult; + /// struct Foo { + /// a: i32, + /// } + /// + /// impl Serialize for Foo { + /// fn serialize(&self, parcel: &mut MsgParcel) -> IpcResult<()> { + /// parcel.write(&self.a) + /// } + /// } + /// + /// let mut msg = MsgParcel::new(); + /// msg.write(&Foo { a: 1 }).unwrap(); + /// assert_eq!(1, msg.read::().unwrap()); + /// ``` + pub fn write(&mut self, value: &T) -> IpcResult<()> { + value.serialize(self) + } + + /// Reads a [`Deserialize`] value out of this MsgParcel. + /// + /// [Deserialize]: crate::parcel::Deserialize + /// + /// # Example + /// ```rust + /// use ipc::parcel::{Deserialize, MsgParcel, Serialize}; + /// use ipc::IpcResult; + /// + /// struct Foo { + /// a: i32, + /// } + /// impl Serialize for Foo { + /// fn serialize(&self, parcel: &mut MsgParcel) -> IpcResult<()> { + /// parcel.write(&self.a) + /// } + /// } + /// impl Deserialize for Foo { + /// fn deserialize(parcel: &mut MsgParcel) -> IpcResult { + /// Ok(Foo { a: parcel.read()? }) + /// } + /// } + /// let mut msg = MsgParcel::new(); + /// msg.write(&Foo { a: 1 }).unwrap(); + /// let foo = msg.read::().unwrap(); + /// assert_eq!(foo.a, 1); + /// ``` + pub fn read(&mut self) -> IpcResult { + T::deserialize(self) + } + + /// Writes a interface token into this MsgParcel. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// msg.write_interface_token("OHOS.Download.RequestServiceInterface"); + /// ``` + pub fn write_interface_token(&mut self, name: &str) -> IpcResult<()> { + self.write_process(name, WriteInterfaceToken) + } + + /// Reads a interface token from this MsgParcel. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// msg.write_interface_token("OHOS.Download.RequestServiceInterface"); + /// assert_eq!( + /// "OHOS.Download.RequestServiceInterface", + /// msg.read_interface_token().unwrap().as_str(), + /// ); + /// ``` + pub fn read_interface_token(&mut self) -> IpcResult { + fn read_process(parcel: Pin<&mut MessageParcel>) -> IpcResult { + Ok(ReadInterfaceToken(parcel)) + } + + self.read_process(read_process) + } + + /// Writes a raw fd from a given file into this MsgParcel. + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::{Read, Seek, Write}; + /// + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// let mut file = std::fs::OpenOptions::new() + /// .read(true) + /// .write(true) + /// .truncate(true) + /// .open("foo") + /// .unwrap(); + /// file.write_all(b"hello world").unwrap(); + /// msg.write_file(file).unwrap(); + /// + /// let mut f = msg.read_file().unwrap(); + /// let mut buf = String::new(); + /// f.rewind().unwrap(); + /// f.read_to_string(&mut buf).unwrap(); + /// assert_eq!("hello world", buf); + /// ``` + pub fn write_file(&mut self, file: File) -> IpcResult<()> { + let fd = file.into_raw_fd(); + match self.as_msg_parcel_mut().WriteFileDescriptor(fd) { + true => Ok(()), + false => Err(IpcStatusCode::Failed), + } + } + + /// Reads a file out of this MsgParcel, that created from the fd written + /// before. + /// + /// # Examples + /// ```no_run + /// use std::fs::File; + /// use std::io::{Read, Seek, Write}; + /// + /// use ipc::parcel::MsgParcel; + /// let mut msg = MsgParcel::new(); + /// let mut file = std::fs::OpenOptions::new() + /// .read(true) + /// .write(true) + /// .truncate(true) + /// .open("foo") + /// .unwrap(); + /// file.write_all(b"hello world").unwrap(); + /// msg.write_file(file).unwrap(); + /// + /// let mut f = msg.read_file().unwrap(); + /// let mut buf = String::new(); + /// f.rewind().unwrap(); + /// f.read_to_string(&mut buf).unwrap(); + /// assert_eq!("hello world", buf); + /// ``` + pub fn read_file(&mut self) -> IpcResult { + let fd = self.as_msg_parcel_mut().ReadFileDescriptor(); + unsafe { Ok(File::from_raw_fd(fd)) } + } + + /// Writes a data region (buffer) to this parcel + /// + /// # Example + /// ```rust + /// use crate::parcel::MsgParcel; + /// + /// let msg = MsgParcel::new(); + /// let data = vec![]; + /// msg.write_buffer(data.as_bytes); + /// ``` + pub fn write_buffer(&mut self, buffer: &[u8]) -> IpcResult<()> { + match WriteBuffer(self.as_msg_parcel_mut(), buffer) { + true => Ok(()), + false => Err(IpcStatusCode::Failed), + } + } + + /// Reads a block of data (buffer data) from this parcel + /// + /// # Example + /// ```rust + /// use crate::parcel::MsgParcel; + /// + /// let msg = MsgParcel::new(); + /// let data = msg.read_buffer().unwrap(); + /// ``` + pub fn read_buffer(&mut self, len: usize) -> IpcResult> { + let pad_size = Self::get_pad_size(len); + let mut vec = Vec::with_capacity(len + pad_size); + match ReadBuffer(self.as_msg_parcel_mut(), len + pad_size, &mut vec) { + true => Ok({ + unsafe { vec.set_len(len) }; + vec + }), + false => Err(IpcStatusCode::Failed), + } + } + + pub fn write_string16(&mut self, s: &str) -> IpcResult<()> { + match WriteString16(self.as_parcel_mut(), s) { + true => Ok(()), + false => Err(IpcStatusCode::Failed), + } + } + + pub fn read_string16(&mut self) -> IpcResult { + Ok(ReadString16(self.as_parcel_mut())) + } + + pub fn write_string16_vec(&mut self, s: &[String]) -> IpcResult<()> { + match WriteString16Vector(self.as_parcel_mut(), s) { + true => Ok(()), + false => Err(IpcStatusCode::Failed), + } + } + + pub fn read_string16_vec(&mut self) -> IpcResult> { + let mut v = vec![]; + match ReadString16Vector(self.as_parcel_mut(), &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + + /// Writes a RemoteObj into this MsgParcel. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// use ipc::remote::{RemoteObj, RemoteStub}; + /// + /// struct TestRemoteStub; + /// impl RemoteStub for TestRemoteStub { + /// fn on_remote_request(&self, code: u32, data: &mut MsgParcel, reply: &mut MsgParcel) -> i32 { + /// reply.write("nihao"); + /// println!("hello"); + /// 0 + /// } + /// } + /// + /// let mut msg = MsgParcel::new(); + /// msg.write_remote(RemoteObj::from_stub(TestRemoteStub).unwrap()) + /// .unwrap(); + /// ``` + pub fn write_remote(&mut self, remote: RemoteObj) -> IpcResult<()> { + self.write_process(remote.inner, WriteRemoteObject) + } + + /// Reads a RemoteObj from this MsgParcel. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// use ipc::remote::{RemoteObj, RemoteStub}; + /// + /// struct TestRemoteStub; + /// impl RemoteStub for TestRemoteStub { + /// fn on_remote_request(&self, code: u32, data: &mut MsgParcel, reply: &mut MsgParcel) -> i32 { + /// reply.write("nihao"); + /// println!("hello"); + /// 0 + /// } + /// } + /// + /// let mut msg = MsgParcel::new(); + /// msg.write_remote(RemoteObj::from_stub(TestRemoteStub).unwrap()) + /// .unwrap(); + /// let remote = msg.read_remote().unwrap(); + /// ``` + pub fn read_remote(&mut self) -> IpcResult { + fn read_remote_process( + parcel: Pin<&mut MessageParcel>, + ) -> IpcResult> { + let remote = ReadRemoteObject(parcel); + if remote.is_null() { + Err(IpcStatusCode::Failed) + } else { + Ok(remote) + } + } + + self.read_process(read_remote_process) + .map(|remote| unsafe { RemoteObj::new_unchecked(remote) }) + } + + /// Returns the size that this MsgParcel has written in bytes. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// msg.write(&1i32); + /// assert_eq!(msg.size(), 4); + /// ``` + pub fn size(&self) -> usize { + self.as_parcel().GetDataSize() + } + + /// Returns the remaining writable size in bytes before reallocating. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// assert_eq!(0, msg.writable()); + /// msg.write(&1i32); + /// assert_eq!(60, msg.writable()); + /// ``` + pub fn writable(&self) -> usize { + self.as_parcel().GetWritableBytes() + } + + /// Returns the remaining readable size in bytes. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// msg.write(&1i32); + /// assert_eq!(4, msg.readable() as u32); + /// ``` + pub fn readable(&self) -> usize { + self.as_parcel().GetReadableBytes() + } + + /// Returns the offset size in bytes. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// let msg = MsgParcel::new(); + /// ``` + pub fn offset(&self) -> usize { + self.as_parcel().GetOffsetsSize() + } + + /// Returns the total bytes the MsgParcel can hold without reallocating. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// assert_eq!(0, msg.capacity()); + /// msg.write(&1i32); + /// assert_eq!(64, msg.capacity()); + /// ``` + pub fn capacity(&self) -> usize { + self.as_parcel().GetDataCapacity() + } + + /// Returns the maximum capacity MsgParcel can allocate. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let msg = MsgParcel::new(); + /// assert_eq!(204800, msg.max_capacity()); + /// ``` + pub fn max_capacity(&self) -> usize { + self.as_parcel().GetMaxCapacity() + } + + /// Returns the write_position of the MsgPacel in bytes. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// assert_eq!(0, msg.write_position()); + /// msg.write(&1i32).unwrap(); + /// assert_eq!(4, msg.write_position()); + /// ``` + pub fn write_position(&mut self) -> usize { + self.as_parcel_mut().GetWritePosition() + } + + /// Returns the read_position of the MsgParcel in bytes. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// assert_eq!(0, msg.read_position()); + /// msg.write(&1i32).unwrap(); + /// assert_eq!(0, msg.read_position()); + /// msg.read::().unwrap(); + /// assert_eq!(4, msg.read_position()); + /// ``` + pub fn read_position(&mut self) -> usize { + self.as_parcel_mut().GetReadPosition() + } + + /// Changes the size of the MsgParcel. + /// + /// # Errors + /// If new data size > capacity, set will fail. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// msg.write(&1i32); + /// assert_eq!(4, msg.size()); + /// msg.set_size(0); + /// assert_eq!(0, msg.size()); + /// ``` + pub fn set_size(&mut self, size: usize) -> Result<(), ParcelSetError> { + if self.as_parcel_mut().SetDataSize(size) { + Ok(()) + } else { + Err(ParcelSetError) + } + } + + /// Changes the capacity of the MsgParcel. + /// + /// # Errors + /// If data size > new capacity bytes, set will fail. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let msg = MsgParcel::new(); + /// msg.set_capacity(64).unwrap(); + /// assert_eq!(64, msg.capacity()); + /// ``` + pub fn set_capacity(&mut self, size: usize) -> Result<(), ParcelSetError> { + if self.as_parcel_mut().SetDataCapacity(size) { + Ok(()) + } else { + Err(ParcelSetError) + } + } + + /// Changes the capacity of the MsgParcel. + /// + /// # Errors + /// If new max capacity reach the limit, set will fail. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// msg.set_max_capacity(64).unwrap(); + /// ``` + pub fn set_max_capacity(&mut self, size: usize) -> Result<(), ParcelSetError> { + if self.as_parcel_mut().SetMaxCapacity(size) { + Ok(()) + } else { + Err(ParcelSetError) + } + } + + /// Changes the read position of the MsgParcel. + /// + /// # Errors + /// If new position > data size, set will fail. + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// msg.write(&1i32).unwrap(); + /// msg.write(&2i32).unwrap(); + /// msg.set_read_position(4).unwrap(); + /// assert_eq!(2, msg.read().unwrap()); + /// ``` + pub fn set_read_position(&mut self, size: usize) -> Result<(), ParcelSetError> { + if self.as_parcel_mut().RewindRead(size) { + Ok(()) + } else { + Err(ParcelSetError) + } + } + + /// Changes the write position of the MsgParcel. + /// + /// # Errors + /// if new position > data size, set will fail + /// + /// # Example + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// msg.write(&1i32).unwrap(); + /// msg.write(&2i32).unwrap(); + /// msg.set_write_position(0); + /// msg.write(&2i32).unwrap(); + /// assert_eq(2, msg.read().unwrap()); + /// ``` + pub fn set_write_position(&mut self, size: usize) -> Result<(), ParcelSetError> { + if self.as_parcel_mut().RewindWrite(size) { + Ok(()) + } else { + Err(ParcelSetError) + } + } + + /// Skip read data in bytes of the MsgParcel + /// + /// # Errors + /// if skip size > readable data the the read position will be the capacity. + /// + /// # Examples + /// ```rust + /// use ipc::parcel::MsgParcel; + /// + /// let mut msg = MsgParcel::new(); + /// msg.write(&1i32).unwrap(); + /// msg.write(&2i32).unwrap(); + /// msg.skip_read(4); + /// assert_eq!(2, msg.read().unwrap()); + /// ``` + pub fn skip_read(&mut self, size: usize) { + self.as_parcel_mut().SkipBytes(size) + } + + fn as_msg_parcel_mut(&mut self) -> Pin<&mut MessageParcel> { + match &mut self.inner { + ParcelMem::Unique(p) => p.pin_mut(), + ParcelMem::Borrow(p) => unsafe { Pin::new_unchecked(&mut **p) }, + _ => unreachable!(), + } + } + + fn as_parcel(&self) -> &Parcel { + match &self.inner { + ParcelMem::Unique(p) => unsafe { + let parcel = AsParcel(p.as_ref().unwrap()); + &*parcel + }, + ParcelMem::Borrow(p) => unsafe { + let parcel = AsParcel(&**p); + &*parcel + }, + _ => unreachable!(), + } + } + + pub(crate) fn as_parcel_mut(&mut self) -> Pin<&mut Parcel> { + match &mut self.inner { + ParcelMem::Unique(p) => unsafe { + let parcel = AsParcelMut(p.pin_mut()); + Pin::new_unchecked(&mut *parcel) + }, + ParcelMem::Borrow(p) => unsafe { + let parcel = AsParcelMut(Pin::new_unchecked(&mut **p)); + Pin::new_unchecked(&mut *parcel) + }, + _ => unreachable!(), + } + } + + pub(crate) fn write_process( + &mut self, + value: T, + f: fn(parcel: Pin<&mut MessageParcel>, value: T) -> bool, + ) -> IpcResult<()> { + match mem::replace(&mut self.inner, ParcelMem::Null) { + ParcelMem::Unique(mut p) => { + let res = f(p.pin_mut(), value); + self.inner = ParcelMem::Unique(p); + match res { + true => Ok(()), + false => Err(IpcStatusCode::Failed), + } + } + ParcelMem::Borrow(p) => { + let w = unsafe { Pin::new_unchecked(&mut *p) }; + let res = f(w, value); + self.inner = ParcelMem::Borrow(p); + match res { + true => Ok(()), + false => Err(IpcStatusCode::Failed), + } + } + ParcelMem::Null => IpcResult::Err(IpcStatusCode::Failed), + } + } + + pub(crate) fn read_process( + &mut self, + f: fn(parcel: Pin<&mut MessageParcel>) -> IpcResult, + ) -> IpcResult { + match mem::replace(&mut self.inner, ParcelMem::Null) { + ParcelMem::Unique(mut p) => { + let res = f(p.pin_mut()); + self.inner = ParcelMem::Unique(p); + res + } + ParcelMem::Borrow(p) => { + let w = unsafe { Pin::new_unchecked(&mut *p) }; + let res = f(w); + self.inner = ParcelMem::Borrow(p); + res + } + ParcelMem::Null => IpcResult::Err(IpcStatusCode::Failed), + } + } + + pub(crate) fn pin_mut(&mut self) -> Option> { + match &mut self.inner { + ParcelMem::Unique(p) => Some(p.pin_mut()), + _ => None, + } + } + + fn get_pad_size(size: usize) -> usize { + const SIZE_OFFSET: usize = 3; + ((size + SIZE_OFFSET) & (!SIZE_OFFSET)) - size + } +} + +/// Ipc MsgOption used when send request, including some settings. +pub struct MsgOption { + pub(crate) inner: UniquePtr, +} + +impl MsgOption { + const TF_SYNC: i32 = 0x00; + const TF_ASYNC: i32 = 0x01; + + /// Creates a new, empty MsgOption. + + /// # Panics + /// Panics if allocate failed. + /// + /// # Examples + /// ```rust + /// use ipc::parcel::MsgOption; + /// + /// let msg = MsgOption::new(); + /// ``` + pub fn new() -> Self { + let ptr = NewMessageOption(); + assert!(!ptr.is_null(), "memory allocation of MessageOption failed"); + + Self { + inner: NewMessageOption(), + } + } + + /// Set send to be async. + pub fn set_async(&mut self) { + self.inner.pin_mut().SetFlags(Self::TF_ASYNC); + } + + /// Sets send to be sync. + pub fn set_sync(&mut self) { + self.inner.pin_mut().SetFlags(Self::TF_SYNC); + } + + /// Return true if has set to async. + pub fn is_async(&self) -> bool { + self.inner.GetFlags() == Self::TF_ASYNC + } +} + +impl Default for MsgParcel { + fn default() -> Self { + Self::new() + } +} + +impl Default for MsgOption { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod test { + use std::mem; + + use super::MsgParcel; + + /// UT test cases for `GetDataSize` + /// + /// # Brief + /// 1. Creates a MsgParcel + /// 2. Writes a value to the MsgParcel and then check its data size. + #[test] + fn parcel_size() { + let mut msg = MsgParcel::new(); + let mut size = 0; + + msg.write(&1i8).unwrap(); + size += mem::size_of::(); + assert_eq!(size, msg.size()); + + msg.write(&1i16).unwrap(); + size += mem::size_of::(); + assert_eq!(size, msg.size()); + + msg.write(&1i32).unwrap(); + size += mem::size_of::(); + assert_eq!(size, msg.size()); + + msg.write(&1i64).unwrap(); + size += mem::size_of::(); + assert_eq!(size, msg.size()); + + msg.write(&1u8).unwrap(); + size += mem::size_of::(); + assert_eq!(size, msg.size()); + + msg.write(&1u16).unwrap(); + size += mem::size_of::(); + assert_eq!(size, msg.size()); + + msg.write(&1u32).unwrap(); + size += mem::size_of::(); + assert_eq!(size, msg.size()); + + msg.write(&1u64).unwrap(); + size += mem::size_of::(); + assert_eq!(size, msg.size()); + + msg.write(&true).unwrap(); + size += mem::size_of::(); + assert_eq!(size, msg.size()); + } + + /// UT test cases for read_to_end + /// + /// # Brief + /// 1. Creates a new MsgParcel. + /// 3. Write a bool and read it out. + /// 2. write a vector into this MsgParcel, and read_to_end check the + /// correctness. + #[test] + fn read_to_end() { + let mut msg = MsgParcel::new(); + msg.write(&true).unwrap(); + msg.read::().unwrap(); + + msg.write(&vec![1, 2, 3]).unwrap(); + assert_eq!( + vec![3, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0], + msg.read_buffer(msg.readable()).unwrap() + ); + } +} diff --git a/interfaces/innerkits/rust/src/parcel/parcelable.rs b/interfaces/innerkits/rust/src/parcel/parcelable.rs deleted file mode 100644 index 013f3ed4..00000000 --- a/interfaces/innerkits/rust/src/parcel/parcelable.rs +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use crate::{ - IpcResult, IpcStatusCode, status_result, BorrowedMsgParcel, - ipc_binding, AsRawPtr -}; -use std::mem::MaybeUninit; -use std::ffi::{c_void, c_ulong}; -use std::ptr; - -/// Implement `Serialize` trait to serialize a custom MsgParcel. -/// -/// # Example: -/// -/// ```ignore -/// struct Year(i64); -/// -/// impl Serialize for Year { -/// fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { -/// parcel::write(self.0); -/// } -/// } -/// ``` -pub trait Serialize { - /// Serialize Self to BorrowedMsgParcel - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()>; -} - -/// Implement `Deserialize` trait to deserialize a custom MsgParcel. -/// -/// # Example: -/// -/// ```ignore -/// struct Year(i64); -/// -/// impl Deserialize for Year { -/// fn deserialize(parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult { -/// let i = parcel::read::(parcel); -/// Ok(Year(i)) -/// } -/// } -/// ``` -pub trait Deserialize: Sized { - /// Deserialize an instance from the given [`Parcel`]. - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult; -} - -pub const NULL_FLAG : i32 = 0; -pub const NON_NULL_FLAG : i32 = 1; - -/// Define trait function for Option which T must implements the trait Serialize. -pub trait SerOption: Serialize { - /// Serialize the Option - fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<(), > { - if let Some(inner) = this { - parcel.write(&NON_NULL_FLAG)?; - parcel.write(inner) - } else { - parcel.write(&NULL_FLAG) - } - } -} - -/// Define trait function for Option which T must implements the trait Deserialize. -pub trait DeOption: Deserialize { - /// Deserialize the Option - fn de_option(parcel: &BorrowedMsgParcel<'_>) -> IpcResult> { - let null: i32 = parcel.read()?; - if null == NULL_FLAG { - Ok(None) - } else { - parcel.read().map(Some) - } - } -} - -/// Callback to allocate a vector for parcel array read functions. -/// -/// # Safety -/// -/// The opaque data pointer passed to the array read function must be a mutable -/// pointer to an `Option>>`. -pub unsafe extern "C" fn allocate_vec_with_buffer( - value: *mut c_void, - buffer: *mut *mut T, - len: i32 -) -> bool { - let res = allocate_vec::(value, len); - // `buffer` will be assigned a mutable pointer to the allocated vector data - // if this function returns true. - let vec = &mut *(value as *mut Option>>); - if let Some(new_vec) = vec { - *buffer = new_vec.as_mut_ptr() as *mut T; - } - res -} - -/// Callback to allocate a vector for parcel array read functions. -/// -/// # Safety -/// -/// The opaque data pointer passed to the array read function must be a mutable -/// pointer to an `Option>>`. -unsafe extern "C" fn allocate_vec( - value: *mut c_void, - len: i32, -) -> bool { - if len < 0 { - return false; - } - allocate_vec_maybeuninit::(value, len as u32); - true -} - -/// 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 { - /// Default array serialize implement. - fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // SAFETY: Safe FFI, slice will always be a safe pointer to pass. - let ret = unsafe { - ipc_binding::CParcelWriteParcelableArray( - parcel.as_mut_raw(), - slice.as_ptr() as *const c_void, - slice.len().try_into().unwrap(), - ser_element::, - ) - }; - status_result::<()>(ret as i32, ()) - } -} - -/// Callback to serialize an element of a generic parcelable array. -/// -/// # Safety -/// -/// We are relying on c interface 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. -#[allow(dead_code)] -pub(crate) unsafe extern "C" fn ser_element( - parcel: *mut ipc_binding::CParcel, - array: *const c_void, - index: c_ulong, -) -> bool { - // c_ulong and usize are the same, but we need the explicitly sized version - // so the function signature matches what bindgen generates. - let index = index as usize; - - let slice: &[T] = std::slice::from_raw_parts(array.cast(), index+1); - - let mut parcel = match BorrowedMsgParcel::from_raw(parcel) { - None => return false, - Some(p) => p, - }; - slice[index].serialize(&mut parcel).is_ok() -} - -/// 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<'_>) -> IpcResult>> { - let mut vec: Option>> = None; - // SAFETY: - // Safe FFI, vec is the correct opaque type expected by - // allocate_vec and de_element. - let ok_status = unsafe { - ipc_binding::CParcelReadParcelableArray( - parcel.as_raw(), - &mut vec as *mut _ as *mut c_void, - allocate_vec::, - de_element::, - ) - }; - - if ok_status{ - // SAFETY: - // We are assuming that the C-API correctly initialized every - // element of the vector by now, so we know that all the - // MaybeUninits are now properly initialized. We can transmute from - // Vec> to Vec because MaybeUninit has the same - // alignment and size as T, so the pointer to the vector allocation - // will be compatible. - let vec: Option> = unsafe { - std::mem::transmute(vec) - }; - Ok(vec) - } else { - Err(IpcStatusCode::Failed) - } - } -} - -/// Callback to deserialize a parcelable element. -/// -/// # Safety -/// -/// The opaque array data pointer must be a mutable pointer to an -/// `Option>>` with at least enough elements for `index` to be valid -/// (zero-based). -#[allow(dead_code)] -unsafe extern "C" fn de_element( - parcel: *const ipc_binding::CParcel, - array: *mut c_void, - index: c_ulong, -) -> bool { - // c_ulong and usize are the same, but we need the explicitly sized version - // so the function signature matches what bindgen generates. - let index = index as usize; - - let vec = &mut *(array as *mut Option>>); - let vec = match vec { - Some(v) => v, - None => return false, - }; - let parcel = match BorrowedMsgParcel::from_raw(parcel as *mut _) { - None => return false, - Some(p) => p, - }; - let element = match parcel.read() { - Ok(e) => e, - Err(_) => return false, - }; - ptr::write(vec[index].as_mut_ptr(), element); - true -} -/// # Safety -/// -/// All elements in the vector must be properly initialized. -pub unsafe fn vec_assume_init(vec: Vec>) -> Vec { - // We can convert from Vec> to Vec because MaybeUninit - // has the same alignment and size as T, so the pointer to the vector - // allocation will be compatible. - let mut vec = std::mem::ManuallyDrop::new(vec); - Vec::from_raw_parts( - vec.as_mut_ptr().cast(), - vec.len(), - vec.capacity(), - ) -} - -/// # Safety -/// -/// Ensure that the value pointer is not null -pub(crate) unsafe fn allocate_vec_maybeuninit( - value: *mut c_void, - len: u32, -) { - let vec = &mut *(value as *mut Option>>); - let mut new_vec: Vec> = Vec::with_capacity(len as usize); - - // SAFETY: this is safe because the vector contains MaybeUninit elements which can be uninitialized - new_vec.set_len(len as usize); - ptr::write(vec, Some(new_vec)); -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types.rs b/interfaces/innerkits/rust/src/parcel/types.rs deleted file mode 100644 index 1e4ebfc3..00000000 --- a/interfaces/innerkits/rust/src/parcel/types.rs +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/// # Example -/// -/// ```ignore -/// impl_serde_option_for_parcelable!(i32, bool); -/// ``` -#[macro_export] -macro_rules! impl_serde_option_for_parcelable { - ($($ty:ty),*) => { - $( - impl SerOption for $ty {} - impl DeOption for $ty {} - )* - }; -} - -pub mod bool; -pub mod integer; -pub mod option; -pub mod reference; -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; - -pub use self::string16::on_string16_writer; -pub use self::strings::vec_u16_to_string; -pub use self::strings::vec_to_string; - -use crate::parcel::parcelable::*; -use std::ffi::{c_char, c_void}; -use crate::{ - ipc_binding, BorrowedMsgParcel, AsRawPtr, status_result, - IpcResult, IpcStatusCode, SerOption, DeOption -}; \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/bool.rs b/interfaces/innerkits/rust/src/parcel/types/bool.rs deleted file mode 100644 index e4b99678..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/bool.rs +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; -use std::mem::MaybeUninit; - -impl_serde_option_for_parcelable!(bool); - -impl Serialize for bool { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ret = unsafe { - ipc_binding::CParcelWriteBool(parcel.as_mut_raw(), *self) - }; - status_result::<()>(ret as i32, ()) - } -} - -impl Deserialize for bool { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - let mut val = Self::default(); - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ret = unsafe { - ipc_binding::CParcelReadBool(parcel.as_raw(), &mut val) - }; - status_result::(ret as i32, val) - } -} - -impl SerArray for bool { - fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // 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. - let ret = unsafe { - ipc_binding::CParcelWriteBoolArray( - parcel.as_mut_raw(), - slice.as_ptr(), - slice.len().try_into().unwrap(), - ) - }; - status_result::<()>(ret as i32, ()) - } -} - -impl DeArray for bool { - fn de_array(parcel: &BorrowedMsgParcel<'_>) -> IpcResult>> { - let mut vec: Option>> = None; - // SAFETY: - // `parcel` always contains a valid pointer to a `CParcel` - // `allocate_vec` expects the opaque pointer to - // be of type `*mut Option>>`, so `&mut vec` is - // correct for it. - let ok_status = unsafe { - ipc_binding::CParcelReadBoolArray( - parcel.as_raw(), - &mut vec as *mut _ as *mut c_void, - allocate_vec_with_buffer, - ) - }; - if ok_status{ - // 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. - let vec: Option> = unsafe { - vec.map(|vec| vec_assume_init(vec)) - }; - Ok(vec) - } else { - Err(IpcStatusCode::Failed) - } - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/boxt.rs b/interfaces/innerkits/rust/src/parcel/types/boxt.rs deleted file mode 100644 index 7a538fe3..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/boxt.rs +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; - -impl Serialize for Box { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - Serialize::serialize(&(**self), parcel) - } -} - -impl Deserialize for Box { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - Deserialize::deserialize(parcel).map(Box::new) - } -} - -impl SerOption for Box { - fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - SerOption::ser_option(this.map(|inner| &(**inner)), parcel) - } -} - -impl DeOption for Box { - fn de_option(parcel: &BorrowedMsgParcel<'_>) -> IpcResult> { - DeOption::de_option(parcel).map(|t| t.map(Box::new)) - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/const_array.rs b/interfaces/innerkits/rust/src/parcel/types/const_array.rs deleted file mode 100644 index 24115727..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/const_array.rs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; - -impl Serialize for [T; N] { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // forwards to T::serialize_array. - SerArray::ser_array(self, parcel) - } -} - -impl SerOption for [T; N] { - fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - SerOption::ser_option(this.map(|arr| &arr[..]), parcel) - } -} - -impl SerArray for [T; N] {} - -impl Deserialize for [T; N] { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - let vec = DeArray::de_array(parcel) - .transpose() - .unwrap_or(Err(IpcStatusCode::Failed))?; - vec.try_into().or(Err(IpcStatusCode::Failed)) - } -} - -impl DeOption for [T; N] { - fn de_option(parcel: &BorrowedMsgParcel<'_>) -> IpcResult> { - let vec = DeArray::de_array(parcel)?; - vec.map(|v| v.try_into().or(Err(IpcStatusCode::Failed))).transpose() - } -} - -impl DeArray for [T; N] {} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/file_desc.rs b/interfaces/innerkits/rust/src/parcel/types/file_desc.rs deleted file mode 100644 index 0909b9c3..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/file_desc.rs +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; -use crate::{ - ipc_binding, BorrowedMsgParcel, AsRawPtr, status_result, - IpcResult, IpcStatusCode -}; - -use std::fs::File; -use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use std::ffi::CString; -use hilog_rust::{error, hilog, HiLogLabel, LogType}; - -const LOG_LABEL: HiLogLabel = HiLogLabel { - log_type: LogType::LogCore, - domain: 0xD0057CA, - tag: "RustFileDesc" -}; - -/// Rust version of the C++ class IPCFileDescriptor -#[derive(Debug)] -pub struct FileDesc(File); - -impl FileDesc { - /// Create a FileDesc object with rust File object. - pub fn new(file: File) -> Self { - Self(file) - } -} - -impl AsRef for FileDesc { - fn as_ref(&self) -> &File { - &self.0 - } -} - -impl From for File { - fn from(file: FileDesc) -> File { - file.0 - } -} - -impl AsRawFd for FileDesc { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} - -impl IntoRawFd for FileDesc { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} - -/// # Safety -/// -/// An `FileDesc` is an immutable handle to File, which is thread-safe -unsafe impl Send for FileDesc {} - -/// # Safety -/// -/// An `FileDesc` is an immutable handle to File, which is thread-safe -unsafe impl Sync for FileDesc {} - -impl PartialEq for FileDesc { - // Since ParcelFileDescriptors own the FD, if this function ever returns true (and it is used to - // compare two different objects), then it would imply that an FD is double-owned. - fn eq(&self, other: &Self) -> bool { - self.as_raw_fd() == other.as_raw_fd() - } -} - -impl Eq for FileDesc {} - -impl Serialize for FileDesc { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - let fd = self.0.as_raw_fd(); - // SAFETY: - // `parcel` always contains a valid pointer to an `CParcel`. - let ret = unsafe { - ipc_binding::CParcelWriteFileDescriptor(parcel.as_mut_raw(), fd) - }; - status_result::<()>(ret as i32, ()) - } -} - -impl SerOption for FileDesc { - fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - if let Some(f) = this { - f.serialize(parcel) - } else { - // SAFETY: - // `parcel` always contains a valid pointer to an `CParcel`. - // `CParcelWriteFileDescriptor` accepts the value `-1` as the file - // descriptor to signify serializing a null file descriptor. - let ret = unsafe { - ipc_binding::CParcelWriteFileDescriptor(parcel.as_mut_raw(), -1i32) - }; - status_result::<()>(ret as i32, ()) - } - } -} - -impl DeOption for FileDesc { - fn de_option(parcel: &BorrowedMsgParcel<'_>) -> IpcResult> { - let mut fd = -1i32; - // SAFETY: - // `parcel` always contains a valid pointer to an `CParcel`. - // `CParcelWriteFileDescriptor` accepts the value `-1` as the file - // descriptor to signify serializing a null file descriptor. - // The read function passes ownership of the file - // descriptor to its caller if it was non-null, so we must take - // ownership of the file and ensure that it is eventually closed. - let ok_status = unsafe { - ipc_binding::CParcelReadFileDescriptor( - parcel.as_raw(), - &mut fd, - ) - }; - if ok_status { - if fd < 0 { - error!(LOG_LABEL, "file descriptor is invalid from native"); - Err(IpcStatusCode::Failed) - } else { - // SAFETY: - // At this point, we know that the file descriptor was - // not -1, so must be a valid, owned file descriptor which we - // can safely turn into a `File`. - let file = unsafe { - File::from_raw_fd(fd) - }; - Ok(Some(FileDesc::new(file))) - } - } else { - error!(LOG_LABEL, "read file descriptor failed from native"); - Err(IpcStatusCode::Failed) - } - } -} - -impl Deserialize for FileDesc { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - let mut fd = -1i32; - // SAFETY: - // `parcel` always contains a valid pointer to an `CParcel`. - // `CParcelWriteFileDescriptor` accepts the value `-1` as the file - // descriptor to signify serializing a null file descriptor. - // The read function passes ownership of the file - // descriptor to its caller if it was non-null, so we must take - // ownership of the file and ensure that it is eventually closed. - let ok_status = unsafe { - ipc_binding::CParcelReadFileDescriptor( - parcel.as_raw(), - &mut fd, - ) - }; - if ok_status { - if fd < 0 { - error!(LOG_LABEL, "file descriptor is invalid from native"); - Err(IpcStatusCode::Failed) - } else { - // SAFETY: - // At this point, we know that the file descriptor was - // not -1, so must be a valid, owned file descriptor which we - // can safely turn into a `File`. - let file = unsafe { - File::from_raw_fd(fd) - }; - Ok(FileDesc::new(file)) - } - } else { - error!(LOG_LABEL, "read file descriptor failed from native"); - Err(IpcStatusCode::Failed) - } - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/integer.rs b/interfaces/innerkits/rust/src/parcel/types/integer.rs deleted file mode 100644 index e7840273..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/integer.rs +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; -use crate::{ - ipc_binding, BorrowedMsgParcel, IpcResult, status_result, - AsRawPtr -}; -use std::mem::MaybeUninit; - -impl_serde_option_for_parcelable!(i8, u8, i16, u16, i32, u32, i64, u64, f32,f64); - -/// Macros expand signed numbers and floating point numbers -#[macro_export] -macro_rules! parcelable_number { - { - $( - impl $trait:ident for $num_ty:ty = $fn:path; - )* - } => { - $(define_impl_serde!{$trait, $num_ty, $fn})* - }; -} - -/// # Macro expand example: -/// -/// ```ignore -/// impl Serialize for i8 { -/// fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { -/// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` -/// let ret = unsafe { -/// ipc_binding::CParcelWriteInt8(parcel.as_mut_raw(), *self) -/// }; -/// status_result::<()>(i32::from(ret), ()) -/// } -/// } -/// -/// impl Deserialize for i8 { -/// fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { -/// let mut val = Self::default(); -/// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` -/// let ret = unsafe { -/// ipc_binding::CParcelReadInt8(parcel.as_raw(), &mut val) -/// }; -/// status_result::(ret, val) -/// } -/// } -/// ``` -#[macro_export] -macro_rules! define_impl_serde { - {Serialize, $num_ty:ty, $cparcel_write_fn:path} => { - impl Serialize for $num_ty { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // SAFETY: `parcel` always contains a valid pointer to a `CParcel`, - // and any `$num_ty` literal value is safe to pass to `$cparcel_write_fn`. - let ret = unsafe { - $cparcel_write_fn(parcel.as_mut_raw(), *self) - }; - status_result::<()>(i32::from(ret), ()) - } - } - }; - - {Deserialize, $num_ty:ty, $cparcel_read_fn:path} => { - impl Deserialize for $num_ty { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - let mut val = Self::default(); - // SAFETY: `parcel` always contains a valid pointer to a `CParcel`. - // We pass a valid, mutable pointer to `val`, a literal of type `$num_ty`, - // and `$cparcel_read_fn` will write the value read into `val` if successful - let ret = unsafe { - $cparcel_read_fn(parcel.as_raw(), &mut val) - }; - status_result::<$num_ty>(ret as i32, val) - } - } - } -} - -parcelable_number! { - impl Serialize for i8 = ipc_binding::CParcelWriteInt8; - impl Deserialize for i8 = ipc_binding::CParcelReadInt8; - impl Serialize for i16 = ipc_binding::CParcelWriteInt16; - impl Deserialize for i16 = ipc_binding::CParcelReadInt16; - impl Serialize for i32 = ipc_binding::CParcelWriteInt32; - impl Deserialize for i32 = ipc_binding::CParcelReadInt32; - impl Serialize for i64 = ipc_binding::CParcelWriteInt64; - impl Deserialize for i64 = ipc_binding::CParcelReadInt64; - impl Serialize for f32 = ipc_binding::CParcelWriteFloat; - impl Deserialize for f32 = ipc_binding::CParcelReadFloat; - impl Serialize for f64 = ipc_binding::CParcelWriteDouble; - impl Deserialize for f64 = ipc_binding::CParcelReadDouble; -} - -/// Unsigned number of macro expansion -#[macro_export] -macro_rules! parcelable_for_unsign_number { - { - $( - impl $trait:ident for $unum_ty:ty as $inum_ty:ty; - )* - } => { - $( - define_impl_serde_for_unsign!{ $trait, $unum_ty, $inum_ty} - )* - }; -} - -/// # Example: -/// -/// ```ignore -/// // u8 -> i8 -/// impl Serialize for u8 { -/// fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { -/// (*self as i8).serialize(parcel) -/// } -/// } -/// // i8 -> u8 -/// impl Deserialize for u8 { -/// fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { -/// i8::deserialize(parcel).map(|v| v as u8) -/// } -/// } -/// ``` -#[macro_export] -macro_rules! define_impl_serde_for_unsign { - {Serialize, $unum_ty:ty, $inum_ty:ty} => { - impl Serialize for $unum_ty { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - (*self as $inum_ty).serialize(parcel) - } - } - }; - - {Deserialize, $unum_ty:ty, $inum_ty:ty} => { - impl Deserialize for $unum_ty { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - <$inum_ty>::deserialize(parcel).map(|v| v as $unum_ty) - } - } - } -} - -parcelable_for_unsign_number! { - impl Serialize for u8 as i8; - impl Deserialize for u8 as i8; - impl Serialize for u16 as i16; - impl Deserialize for u16 as i16; - impl Serialize for u32 as i32; - impl Deserialize for u32 as i32; - impl Serialize for u64 as i64; - impl Deserialize for u64 as i64; -} - -/// Macros expand signed numbers and floating point arrays -#[macro_export] -macro_rules! parcelable_array { - { - $( - impl $trait:ident for $num_ty:ty = $fn:path; - )* - } => { - $(define_impl_array!{$trait, $num_ty, $fn})* - }; -} - -/// # Example: -/// -/// ```ignore -/// impl DeArray for i8 { -/// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> IpcResult>> { -/// let mut vec: Option>> = None; -/// // SAFETY: `parcel` always contains a valid pointer to a `CParcel` -/// // `allocate_vec` expects the opaque pointer to -/// // be of type `*mut Option>>`, so `&mut vec` is -/// // correct for it. -/// let ok_status = unsafe { -/// ipc_binding::CParcelReadInt8Array( -/// parcel.as_raw(), -/// &mut vec as *mut _ as *mut c_void, -/// allocate_vec_with_buffer, -/// ) -/// }; -/// if ok_status { -/// // 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. -/// let vec: Option> = unsafe { -/// vec.map(|vec| vec_assume_init(vec)) -/// }; -/// Ok(vec) -/// } else { -/// Err(IpcStatusCode::Failed) -/// } -/// } -// } -/// ``` -#[macro_export] -macro_rules! define_impl_array { - {SerArray, $num_ty:ty, $cparcel_write_fn:path} => { - impl SerArray for $num_ty { - fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // 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. - let ret = unsafe { - $cparcel_write_fn( - parcel.as_mut_raw(), - slice.as_ptr(), - slice.len().try_into().unwrap(), - ) - }; - status_result::<()>(ret as i32, ()) - } - } - }; - - {DeArray, $num_ty:ty, $cparcel_read_fn:path} => { - impl DeArray for $num_ty { - fn de_array(parcel: &BorrowedMsgParcel<'_>) -> IpcResult>> { - let mut vec: Option>> = None; - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - // `allocate_vec` expects the opaque pointer to - // be of type `*mut Option>>`, so `&mut vec` is - // correct for it. - let ok_status = unsafe { - $cparcel_read_fn( - parcel.as_raw(), - &mut vec as *mut _ as *mut c_void, - allocate_vec_with_buffer, - ) - }; - if ok_status { - // 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. - let vec: Option> = unsafe { - vec.map(|vec| vec_assume_init(vec)) - }; - Ok(vec) - } else { - Err(IpcStatusCode::Failed) - } - } - } - } -} - -parcelable_array! { - impl SerArray for i8 = ipc_binding::CParcelWriteInt8Array; - impl DeArray for i8 = ipc_binding::CParcelReadInt8Array; - impl SerArray for i16 = ipc_binding::CParcelWriteInt16Array; - impl DeArray for i16 = ipc_binding::CParcelReadInt16Array; - impl SerArray for i32 = ipc_binding::CParcelWriteInt32Array; - impl DeArray for i32 = ipc_binding::CParcelReadInt32Array; - impl SerArray for i64 = ipc_binding::CParcelWriteInt64Array; - impl DeArray for i64 = ipc_binding::CParcelReadInt64Array; - impl SerArray for f32 = ipc_binding::CParcelWriteFloatArray; - impl DeArray for f32 = ipc_binding::CParcelReadFloatArray; - impl SerArray for f64 = ipc_binding::CParcelWriteDoubleArray; - impl DeArray for f64 = ipc_binding::CParcelReadDoubleArray; -} - -/// Macro Expand Unsigned Count Group -#[macro_export] -macro_rules! parcelable_for_array_unsign_number { - { - $( - impl $trait:ident for $unum_ty:ty as $inum_ty:ty; - )* - } => { - $( - define_impl_array_for_unsign!{ $trait, $unum_ty, $inum_ty} - )* - }; -} - -/// # Example: -/// -/// ```ignore -/// impl SerArray for u8 { -/// fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { -/// // SAFETY: -/// let slice = unsafe {std::slice::from_raw_parts(slice.as_ptr() as *const i8, slice.len()) }; -/// i8::ser_array(slice, parcel) -/// } -/// } -/// -/// impl DeArray for u8 { -/// fn de_array(parcel: &BorrowedMsgParcel<'_>) -> IpcResult>> { -// i8::de_array(parcel).map(|v| -/// v.map(|mut v| v.iter_mut().map(|i| *i as u8).collect()) -/// ) -/// } -/// } -/// ``` -#[macro_export] -macro_rules! define_impl_array_for_unsign { - {SerArray, $unum_ty:ty, $inum_ty:ty} => { - impl SerArray for $unum_ty { - fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // SAFETY: - let slice = unsafe {std::slice::from_raw_parts(slice.as_ptr() as *const $inum_ty, slice.len()) }; - <$inum_ty>::ser_array(slice, parcel) - } - } - }; - - {DeArray, $unum_ty:ty, $inum_ty:ty} => { - impl DeArray for $unum_ty { - fn de_array(parcel: &BorrowedMsgParcel<'_>) -> IpcResult>> { - <$inum_ty>::de_array(parcel).map(|v| - v.map(|mut v| v.iter_mut().map(|i| *i as $unum_ty).collect()) - ) - } - } - } -} - -parcelable_for_array_unsign_number! { - impl SerArray for u8 as i8; - impl DeArray for u8 as i8; - impl SerArray for u16 as i16; - impl DeArray for u16 as i16; - impl SerArray for u32 as i32; - impl DeArray for u32 as i32; - impl SerArray for u64 as i64; - impl DeArray for u64 as i64; -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/interface_token.rs b/interfaces/innerkits/rust/src/parcel/types/interface_token.rs deleted file mode 100644 index b663e698..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/interface_token.rs +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; -use crate::{ - ipc_binding, BorrowedMsgParcel, IpcResult, IpcStatusCode, - AsRawPtr, status_result -}; -use std::convert::TryInto; -use std::ffi::{CString, c_char}; -use hilog_rust::{error, hilog, HiLogLabel, LogType}; - -const LOG_LABEL: HiLogLabel = HiLogLabel { - log_type: LogType::LogCore, - domain: 0xD0057CA, - tag: "RustInterfaceToken" -}; - -/// 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) - } -} - -impl Serialize for InterfaceToken { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - let token = &self.0; - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ret = unsafe { - ipc_binding::CParcelWriteInterfaceToken( - parcel.as_mut_raw(), - token.as_ptr() as *const c_char, - token.as_bytes().len().try_into().unwrap() - )}; - status_result::<()>(ret as i32, ()) - } -} - -impl Deserialize for InterfaceToken { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - let mut vec: Option> = None; - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ok_status = unsafe { - ipc_binding::CParcelReadInterfaceToken( - parcel.as_raw(), - &mut vec as *mut _ as *mut c_void, - allocate_vec_with_buffer:: - ) - }; - - if ok_status { - let result = vec.map(|s| { - match String::from_utf8(s) { - Ok(val) => val, - Err(_) => String::from("") - } - }); - if let Some(val) = result { - Ok(Self(val)) - } else { - error!(LOG_LABEL, "convert interface token to String fail"); - Err(IpcStatusCode::Failed) - } - }else{ - error!(LOG_LABEL, "read interface token from native fail"); - Err(IpcStatusCode::Failed) - } - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/option.rs b/interfaces/innerkits/rust/src/parcel/types/option.rs deleted file mode 100644 index 2cdd7944..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/option.rs +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; - -impl Serialize for Option { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - SerOption::ser_option(self.as_ref(), parcel) - } -} - -impl Deserialize for Option { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - DeOption::de_option(parcel) - } -} - -impl DeArray for Option {} -impl SerArray for Option {} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/reference.rs b/interfaces/innerkits/rust/src/parcel/types/reference.rs deleted file mode 100644 index 60a6c88b..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/reference.rs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; -use crate::{BorrowedMsgParcel, IpcResult}; - -// We need these to support Option<&T> for all T -impl Serialize for &T { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - Serialize::serialize(*self, parcel) - } -} - -impl SerOption for &T { - fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<(), > { - SerOption::ser_option(this.copied(), parcel) - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/slices.rs b/interfaces/innerkits/rust/src/parcel/types/slices.rs deleted file mode 100644 index 37bfcf30..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/slices.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; -use crate::{BorrowedMsgParcel, IpcResult}; - -impl Serialize for [T] { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - SerArray::ser_array(self, parcel) - } -} - -impl SerOption for [T] { - fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - if let Some(v) = this { - SerArray::ser_array(v, parcel) - } else { - parcel.write(&-1i32) - } - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/string16.rs b/interfaces/innerkits/rust/src/parcel/types/string16.rs deleted file mode 100644 index 03fcd377..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/string16.rs +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; -use crate::{ - ipc_binding, BorrowedMsgParcel, IpcResult, IpcStatusCode, - status_result, AsRawPtr -}; -use std::convert::TryInto; -use std::mem::MaybeUninit; -use std::ffi::CString; -use hilog_rust::{error, hilog, HiLogLabel, LogType}; - -const LOG_LABEL: HiLogLabel = HiLogLabel { - log_type: LogType::LogCore, - domain: 0xD0057CA, - tag: "RustString16" -}; - -/// 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) - } -} - -impl Serialize for String16 { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - let string = &self.0; - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ret = unsafe { - ipc_binding::CParcelWriteString16( - parcel.as_mut_raw(), - string.as_ptr() as *const c_char, - string.as_bytes().len().try_into().unwrap() - )}; - status_result::<()>(ret as i32, ()) - } -} - -impl Deserialize for String16 { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - let mut vec: Option> = None; - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ok_status = unsafe { - ipc_binding::CParcelReadString16( - parcel.as_raw(), - &mut vec as *mut _ as *mut c_void, - allocate_vec_with_buffer:: - ) - }; - - if ok_status { - let result = vec.map(|s| { - match String::from_utf8(s) { - Ok(val) => val, - Err(_) => String::from("") - } - }); - if let Some(val) = result { - Ok(Self(val)) - } else { - error!(LOG_LABEL, "convert native string16 to String fail"); - Err(IpcStatusCode::Failed) - } - } else { - error!(LOG_LABEL, "read string16 from native fail"); - Err(IpcStatusCode::Failed) - } - } -} - -impl SerArray for String16 { - fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ret = unsafe { - ipc_binding::CParcelWriteString16Array( - parcel.as_mut_raw(), - slice.as_ptr() as *const c_void, - slice.len().try_into().unwrap(), - on_string16_writer, - ) - }; - status_result::<()>(ret as i32, ()) - } -} - -impl DeArray for String16 { - fn de_array(parcel: &BorrowedMsgParcel<'_>) -> IpcResult>> { - let mut vec: Option>> = None; - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - // `allocate_vec` expects the opaque pointer to - // be of type `*mut Option>>`, so `&mut vec` is - // correct for it. - let ok_status = unsafe { - ipc_binding::CParcelReadString16Array( - parcel.as_raw(), - &mut vec as *mut _ as *mut c_void, - on_string16_reader, - ) - }; - if ok_status { - // SAFETY: all the MaybeUninits are now properly initialized. - let vec: Option> = unsafe { - vec.map(|vec| vec_assume_init(vec)) - }; - Ok(vec) - } else { - error!(LOG_LABEL, "read string16 from native fail"); - Err(IpcStatusCode::Failed) - } - } -} -/// Callback to serialize a String16 array to c++ std::vector. -/// -/// # Safety: -/// -/// We are relying on c interface to not overrun our slice. As long -/// as it doesn't provide an index larger than the length of the original -/// slice in ser_array, this operation is safe. The index provided -/// is zero-based. -#[allow(dead_code)] -pub unsafe extern "C" fn on_string16_writer( - array: *const c_void, // C++ vector pointer - value: *mut c_void, // Rust slice pointer - len: u32, -) -> bool { - if len == 0 { - return false; - } - let len = len as usize; - let slice: &[String16] = std::slice::from_raw_parts(value.cast(), len); - - for item in slice.iter().take(len) { - // SAFETY: This function writes a String16 element to a parcel. - // 1. Ensure the `item` is valid within the slice bounds. - // 2. Ensure the `item.0` pointer is valid and non-null. - let ret = unsafe { - ipc_binding::CParcelWritU16stringElement( - array, - item.0.as_ptr() as *const c_char, - item.0.as_bytes().len().try_into().unwrap()) - }; - if !ret { - return false; - } - } - true -} - -/// Callback to deserialize a String element in Vector. -/// -/// # Safety: -/// -/// The opaque array data pointer must be a mutable pointer to an -/// `Option>>` with at least enough elements for `index` to be valid -/// (zero-based). -#[allow(dead_code)] -unsafe extern "C" fn on_string16_reader( - data: *const c_void, // C++ vector pointer - value: *mut c_void, // Rust vector pointer - len: u32, // C++ vector length -) -> bool { - // SAFETY: - // Allocate Vec capacity, data_len will set correctly by vec.push(). - unsafe { allocate_vec_maybeuninit::(value, 0) }; - let vec = &mut *(value as *mut Option>>); - for index in 0..len { - let mut vec_u16: Option> = None; - // SAFETY: The length of the index will not exceed the range, - // as the traversal range is the pointer length of the data passed from the C++side - let ok_status = unsafe { - ipc_binding::CParcelReadString16Element( - index, - data, - &mut vec_u16 as *mut _ as *mut c_void, - allocate_vec_with_buffer:: - ) - }; - if ok_status { - if let Ok(string) = vec_u16_to_string(vec_u16) { - if let Some(new_vec) = vec { - new_vec.push(MaybeUninit::new(String16::new(string.as_str()))); - } else { - error!(LOG_LABEL, "on_string_reader allocate vec failed"); - return false; - } - } else { - error!(LOG_LABEL, "on_string_reader vec_to_string failed"); - return false; - } - } else { - return false; - } - } - true -} - -impl PartialEq for String16 { - fn eq(&self, other: &Self) -> bool { - self.get_string() == other.get_string() - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/strings.rs b/interfaces/innerkits/rust/src/parcel/types/strings.rs deleted file mode 100644 index 1eba5d44..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/strings.rs +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; -use crate::{ - ipc_binding, BorrowedMsgParcel, IpcResult, IpcStatusCode, - status_result, AsRawPtr -}; -use std::convert::TryInto; -use std::mem::MaybeUninit; -use std::ffi::CString; -use hilog_rust::{error, hilog, HiLogLabel, LogType}; - -const LOG_LABEL: HiLogLabel = HiLogLabel { - log_type: LogType::LogCore, - domain: 0xD0057CA, - tag: "RustString" -}; - -impl SerOption for str {} -impl SerOption for String {} -impl DeOption for String {} - -impl Serialize for str { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ret = unsafe { - ipc_binding::CParcelWriteString( - parcel.as_mut_raw(), - self.as_ptr() as *const c_char, - self.as_bytes().len().try_into().unwrap() - )}; - status_result::<()>(ret as i32, ()) - } -} - -impl Serialize for String { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - self.as_str().serialize(parcel) - } -} - -impl Deserialize for String { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - let mut vec: Option> = None; - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ok_status = unsafe { - ipc_binding::CParcelReadString( - parcel.as_raw(), - &mut vec as *mut _ as *mut c_void, - allocate_vec_with_buffer:: - ) - }; - - if ok_status { - vec_to_string(vec) - } else { - Err(IpcStatusCode::Failed) - } - } -} - -impl SerArray for &str { - fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ret = unsafe { - ipc_binding::CParcelWriteStringArray( - parcel.as_mut_raw(), - slice.as_ptr() as *const c_void, - slice.len().try_into().unwrap(), - on_str_writer, - ) - }; - status_result::<()>(ret as i32, ()) - } -} - -impl SerArray for String { - fn ser_array(slice: &[Self], parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - let ret = unsafe { - ipc_binding::CParcelWriteStringArray( - parcel.as_mut_raw(), - slice.as_ptr() as *const c_void, - slice.len().try_into().unwrap(), - on_string_writer, - ) - }; - status_result::<()>(ret as i32, ()) - } -} - -impl DeArray for String { - fn de_array(parcel: &BorrowedMsgParcel<'_>) -> IpcResult>> { - let mut vec: Option>> = None; - // SAFETY: `parcel` always contains a valid pointer to a `CParcel` - // `allocate_vec` expects the opaque pointer to - // be of type `*mut Option>>`, so `&mut vec` is - // correct for it. - let ok_status = unsafe { - ipc_binding::CParcelReadStringArray( - parcel.as_raw(), - &mut vec as *mut _ as *mut c_void, - on_string_reader, - ) - }; - if ok_status { - // SAFETY: all the MaybeUninits are now properly initialized. - let vec: Option> = unsafe { - vec.map(|vec| vec_assume_init(vec)) - }; - Ok(vec) - } else { - error!(LOG_LABEL, "read string from native fail"); - Err(IpcStatusCode::Failed) - } - } -} - -/// Callback to serialize a String array to c++ std::vector. -/// -/// # Safety: -/// -/// We are relying on c interface to not overrun our slice. As long -/// as it doesn't provide an index larger than the length of the original -/// slice in ser_array, this operation is safe. The index provided -/// is zero-based. -#[allow(dead_code)] -unsafe extern "C" fn on_str_writer( - array: *const c_void, // C++ vector pointer - value: *mut c_void, // Rust slice pointer - len: u32, -) -> bool { - if len == 0 { - return false; - } - let len = len as usize; - let slice: &[&str] = std::slice::from_raw_parts(value.cast(), len); - - for item in slice.iter().take(len) { - // SAFETY: The C interface is assumed to handle the provided index correctly - // and not overrun the original slice. - let ret = unsafe { - ipc_binding::CParcelWriteStringElement( - array, - item.as_ptr() as *const c_char, - item.as_bytes().len().try_into().unwrap()) - }; - if !ret { - return false; - } - } - true -} - -/// Callback to serialize a String array to c++ std::vector. -/// -/// # Safety: -/// -/// We are relying on c interface to not overrun our slice. As long -/// as it doesn't provide an index larger than the length of the original -/// slice in ser_array, this operation is safe. The index provided -/// is zero-based. -#[allow(dead_code)] -unsafe extern "C" fn on_string_writer( - array: *const c_void, // C++ vector pointer - value: *mut c_void, // Rust slice pointer - len: u32, -) -> bool { - if len == 0 { - return false; - } - let len = len as usize; - let slice: &[String] = std::slice::from_raw_parts(value.cast(), len); - - for item in slice.iter().take(len) { - // SAFETY: writes a String element to a parcel. - let ret = unsafe { - ipc_binding::CParcelWriteStringElement( - array, - item.as_ptr() as *const c_char, - item.as_bytes().len().try_into().unwrap()) - }; - if !ret { - return false; - } - } - true -} - -/// Callback to deserialize a String element in Vector. -/// -/// # Safety: -/// -/// The opaque array data pointer must be a mutable pointer to an -/// `Option>>` with at least enough elements for `index` to be valid -/// (zero-based). -#[allow(dead_code)] -unsafe extern "C" fn on_string_reader( - data: *const c_void, // C++ vector pointer - value: *mut c_void, // Rust vector pointer - len: u32, // C++ vector length -) -> bool { - // SAFETY: - // Allocate Vec capacity, data_len will set correctly by vec.push(). - unsafe { allocate_vec_maybeuninit::(value, 0) }; - let vec = &mut *(value as *mut Option>>); - for index in 0..len { - let mut vec_u8: Option> = None; - // SAFETY: - // This function reads a string element from a parcel and stores it in the provided vec_u8 pointer. - let ok_status = unsafe { - ipc_binding::CParcelReadStringElement( - index, - data, - &mut vec_u8 as *mut _ as *mut c_void, - allocate_vec_with_buffer:: - ) - }; - if ok_status { - if let Ok(string) = vec_to_string(vec_u8) { - if let Some(new_vec) = vec { - new_vec.push(MaybeUninit::new(string)); - } else { - error!(LOG_LABEL, "on_string_reader allocate vec failed"); - return false; - } - } else { - error!(LOG_LABEL, "on_string_reader vec_to_string failed"); - return false; - } - } else { - return false; - } - } - true -} - -pub fn vec_to_string(vec: Option>) -> IpcResult { - let value = vec.map(|s| { - // The vector includes a null-terminator and - // we don't want the string to be null-terminated for Rust. - String::from_utf8(s).or(Err(IpcStatusCode::Failed)) - }); - if let Some(ret) = value { - ret - } else { - error!(LOG_LABEL, "convert vector u8 to String fail"); - Err(IpcStatusCode::Failed) - } -} - -pub fn vec_u16_to_string(vec: Option>) -> IpcResult { - let value = vec.map(|s| { - // The vector includes a null-terminator and - // we don't want the string to be null-terminated for Rust. - let slice = &s[..]; - String::from_utf16(slice).or(Err(IpcStatusCode::Failed)) - }); - if let Some(ret) = value { - ret - } else { - error!(LOG_LABEL, "convert vector u16 to String fail"); - Err(IpcStatusCode::Failed) - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/types/vector.rs b/interfaces/innerkits/rust/src/parcel/types/vector.rs deleted file mode 100644 index 749481b3..00000000 --- a/interfaces/innerkits/rust/src/parcel/types/vector.rs +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use super::*; - -impl Serialize for Vec { - fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - SerArray::ser_array(&self[..], parcel) - } -} - -impl SerOption for Vec { - fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> { - SerOption::ser_option(this.map(Vec::as_slice), parcel) - } -} - -impl Deserialize for Vec { - fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult { - DeArray::de_array(parcel) - .transpose() - .unwrap_or(Err(IpcStatusCode::Failed)) - } -} - -impl DeOption for Vec { - fn de_option(parcel: &BorrowedMsgParcel<'_>) -> IpcResult> { - DeArray::de_array(parcel) - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/parcel/wrapper.rs b/interfaces/innerkits/rust/src/parcel/wrapper.rs new file mode 100644 index 00000000..f6953d31 --- /dev/null +++ b/interfaces/innerkits/rust/src/parcel/wrapper.rs @@ -0,0 +1,820 @@ +// Copyright (C) 2024 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. + +#![allow(unused)] + +use std::mem::size_of; +use std::pin::Pin; + +use cxx::CxxVector; +pub use ffi::*; + +use super::msg::MsgParcel; +use super::{Deserialize, Serialize}; +use crate::{IpcResult, IpcStatusCode}; + +#[cxx::bridge(namespace = "OHOS::IpcRust")] +mod ffi { + + unsafe extern "C++" { + include!("parcel_wrapper.h"); + include!("message_option.h"); + type IRemoteObjectWrapper = crate::remote::wrapper::IRemoteObjectWrapper; + + #[namespace = "OHOS"] + type MessageParcel; + #[namespace = "OHOS"] + type MessageOption; + #[namespace = "OHOS"] + type Parcel; + + fn NewMessageParcel() -> UniquePtr; + fn NewMessageOption() -> UniquePtr; + + fn ReadFileDescriptor(self: Pin<&mut MessageParcel>) -> i32; + fn WriteFileDescriptor(self: Pin<&mut MessageParcel>, fd: i32) -> bool; + + unsafe fn AsParcel(MsgParcel: &MessageParcel) -> *const Parcel; + unsafe fn AsParcelMut(msgParcel: Pin<&mut MessageParcel>) -> *mut Parcel; + + fn WriteInterfaceToken(msgParcel: Pin<&mut MessageParcel>, name: &str) -> bool; + fn ReadInterfaceToken(msgParcel: Pin<&mut MessageParcel>) -> String; + + fn WriteBuffer(msgParcel: Pin<&mut MessageParcel>, buffer: &[u8]) -> bool; + + fn ReadBuffer(msgParcel: Pin<&mut MessageParcel>, len: usize, buffer: &mut Vec) + -> bool; + + fn WriteRemoteObject( + msgParcel: Pin<&mut MessageParcel>, + value: UniquePtr, + ) -> bool; + + fn ReadRemoteObject(msgParcel: Pin<&mut MessageParcel>) -> UniquePtr; + + fn ReadString(parcel: Pin<&mut Parcel>, val: &mut String) -> bool; + fn WriteString(parcel: Pin<&mut Parcel>, val: &str) -> bool; + + fn ReadString16(parcel: Pin<&mut Parcel>) -> String; + fn WriteString16(parcel: Pin<&mut Parcel>, val: &str) -> bool; + + fn WriteBool(self: Pin<&mut Parcel>, mut value: bool) -> bool; + fn WriteInt8(self: Pin<&mut Parcel>, mut value: i8) -> bool; + fn WriteInt16(self: Pin<&mut Parcel>, mut value: i16) -> bool; + fn WriteInt32(self: Pin<&mut Parcel>, mut value: i32) -> bool; + fn WriteInt64(self: Pin<&mut Parcel>, mut value: i64) -> bool; + + fn WriteUint8(self: Pin<&mut Parcel>, mut value: u8) -> bool; + fn WriteUint16(self: Pin<&mut Parcel>, mut value: u16) -> bool; + fn WriteUint32(self: Pin<&mut Parcel>, mut value: u32) -> bool; + fn WriteUint64(self: Pin<&mut Parcel>, mut value: u64) -> bool; + + fn WriteFloat(self: Pin<&mut Parcel>, mut value: f32) -> bool; + fn WriteDouble(self: Pin<&mut Parcel>, mut value: f64) -> bool; + fn WritePointer(self: Pin<&mut Parcel>, mut value: usize) -> bool; + + fn ReadBool(self: Pin<&mut Parcel>, v: &mut bool) -> bool; + fn ReadInt8(self: Pin<&mut Parcel>, v: &mut i8) -> bool; + fn ReadInt16(self: Pin<&mut Parcel>, v: &mut i16) -> bool; + fn ReadInt32(self: Pin<&mut Parcel>, v: &mut i32) -> bool; + fn ReadInt64(self: Pin<&mut Parcel>, v: &mut i64) -> bool; + fn ReadUint8(self: Pin<&mut Parcel>, v: &mut u8) -> bool; + fn ReadUint16(self: Pin<&mut Parcel>, v: &mut u16) -> bool; + fn ReadUint32(self: Pin<&mut Parcel>, v: &mut u32) -> bool; + fn ReadUint64(self: Pin<&mut Parcel>, v: &mut u64) -> bool; + fn ReadFloat(self: Pin<&mut Parcel>, v: &mut f32) -> bool; + fn ReadDouble(self: Pin<&mut Parcel>, v: &mut f64) -> bool; + fn ReadPointer(self: Pin<&mut Parcel>) -> usize; + + fn GetDataSize(self: &Parcel) -> usize; + fn GetWritableBytes(self: &Parcel) -> usize; + fn GetReadableBytes(self: &Parcel) -> usize; + fn GetOffsetsSize(self: &Parcel) -> usize; + fn GetDataCapacity(self: &Parcel) -> usize; + fn GetMaxCapacity(self: &Parcel) -> usize; + + fn SetDataCapacity(self: Pin<&mut Parcel>, size: usize) -> bool; + fn SetDataSize(self: Pin<&mut Parcel>, size: usize) -> bool; + fn SetMaxCapacity(self: Pin<&mut Parcel>, size: usize) -> bool; + + fn GetReadPosition(self: Pin<&mut Parcel>) -> usize; + fn GetWritePosition(self: Pin<&mut Parcel>) -> usize; + + fn SkipBytes(self: Pin<&mut Parcel>, size: usize); + fn RewindRead(self: Pin<&mut Parcel>, size: usize) -> bool; + fn RewindWrite(self: Pin<&mut Parcel>, size: usize) -> bool; + + fn ReadUint8Unaligned(self: Pin<&mut Parcel>, val: &mut u8) -> bool; + + fn SetFlags(self: Pin<&mut MessageOption>, flag: i32); + fn GetFlags(self: &MessageOption) -> i32; + + fn WriteBoolVector(parcel: Pin<&mut Parcel>, val: &[bool]) -> bool; + fn WriteInt8Vector(parcel: Pin<&mut Parcel>, val: &[i8]) -> bool; + fn WriteInt16Vector(parcel: Pin<&mut Parcel>, val: &[i16]) -> bool; + fn WriteInt32Vector(parcel: Pin<&mut Parcel>, val: &[i32]) -> bool; + fn WriteInt64Vector(parcel: Pin<&mut Parcel>, val: &[i64]) -> bool; + fn WriteUInt8Vector(parcel: Pin<&mut Parcel>, val: &[u8]) -> bool; + fn WriteUInt16Vector(parcel: Pin<&mut Parcel>, val: &[u16]) -> bool; + fn WriteUInt32Vector(parcel: Pin<&mut Parcel>, val: &[u32]) -> bool; + fn WriteUInt64Vector(parcel: Pin<&mut Parcel>, val: &[u64]) -> bool; + fn WriteFloatVector(parcel: Pin<&mut Parcel>, val: &[f32]) -> bool; + fn WriteDoubleVector(parcel: Pin<&mut Parcel>, val: &[f64]) -> bool; + fn WriteStringVector(parcel: Pin<&mut Parcel>, val: &[String]) -> bool; + fn WriteString16Vector(parcel: Pin<&mut Parcel>, val: &[String]) -> bool; + + fn ReadBoolVector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadInt8Vector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadInt16Vector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadInt32Vector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadInt64Vector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadUInt8Vector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadUInt16Vector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadUInt32Vector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadUInt64Vector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadFloatVector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadDoubleVector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadStringVector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + fn ReadString16Vector(parcel: Pin<&mut Parcel>, v: &mut Vec) -> bool; + } +} + +pub(crate) fn get_pad_size(size: usize) -> usize { + const SIZE_OFFSET: usize = 3; + (((size + SIZE_OFFSET) & (!SIZE_OFFSET)) - size) +} + +trait Process: Sized { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool; + + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult; + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool; + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult>; +} + +impl Process for bool { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteBool(*self) + } + + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadBool(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteBoolVector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadBoolVector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for i8 { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteInt8(*self) + } + + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadInt8(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteInt8Vector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadInt8Vector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for i16 { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteInt16(*self) + } + + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadInt16(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteInt16Vector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadInt16Vector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for i32 { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteInt32(*self) + } + + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadInt32(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteInt32Vector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadInt32Vector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for i64 { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteInt64(*self) + } + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadInt64(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteInt64Vector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadInt64Vector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for u8 { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteUint8(*self) + } + + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadUint8(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteUInt8Vector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadUInt8Vector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for u16 { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteUint16(*self) + } + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadUint16(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteUInt16Vector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadUInt16Vector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for u32 { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteUint32(*self) + } + + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadUint32(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteUInt32Vector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadUInt32Vector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for u64 { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteUint64(*self) + } + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadUint64(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteUInt64Vector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadUInt64Vector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} +#[cfg(target_pointer_width = "64")] +impl Process for usize { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteUint64(*self as u64) + } + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v: u64 = u64::default(); + match parcel.ReadUint64(&mut v) { + true => Ok(v as usize), + false => Err(IpcStatusCode::Failed), + } + } + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + let v: Vec = val.iter().map(|i| *i as u64).collect(); + WriteUInt64Vector(parcel, &v[..]) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadUInt64Vector(parcel, &mut v) { + true => Ok(v.into_iter().map(|i| i as usize).collect()), + false => Err(IpcStatusCode::Failed), + } + } +} + +#[cfg(target_pointer_width = "32")] +impl Process for usize { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteUint32(*self as u32) + } + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v: u32 = u32::default(); + match parcel.ReadUint32(&mut v) { + true => Ok(v as usize), + false => Err(IpcStatusCode::Failed), + } + } + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + let v: Vec = val.iter().map(|i| *i as u32).collect(); + WriteUInt32Vector(parcel, &v[..]) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadUInt32Vector(parcel, &mut v) { + true => Ok(v.into_iter().map(|i| i as usize).collect()), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for f32 { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteFloat(*self) + } + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadFloat(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteFloatVector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadFloatVector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for f64 { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + parcel.WriteDouble(*self) + } + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut v = Self::default(); + match parcel.ReadDouble(&mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteDoubleVector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadDoubleVector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Process for String { + fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool { + WriteString(parcel, self.as_str()) + } + fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult { + let mut s = String::new(); + match ReadString(parcel, &mut s) { + true => Ok(s), + false => Err(IpcStatusCode::Failed), + } + } + + fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool { + WriteStringVector(parcel, val) + } + + fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult> { + let mut v = vec![]; + match ReadStringVector(parcel, &mut v) { + true => Ok(v), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Serialize for T { + fn serialize(&self, parcel: &mut MsgParcel) -> IpcResult<()> { + fn write(parcel: Pin<&mut MessageParcel>, value: &T) -> bool { + unsafe { + let parcel = AsParcelMut(parcel); + value.write_process(Pin::new_unchecked(&mut *parcel)) + } + } + parcel.write_process(self, write) + } +} + +impl Deserialize for T { + fn deserialize(parcel: &mut MsgParcel) -> IpcResult { + fn read(parcel: Pin<&mut MessageParcel>) -> IpcResult { + unsafe { + let parcel = AsParcelMut(parcel); + Process::read_process(Pin::new_unchecked(&mut *parcel)) + } + } + parcel.read_process(read) + } +} + +impl Serialize for str { + fn serialize(&self, parcel: &mut MsgParcel) -> crate::IpcResult<()> { + fn write(parcel: Pin<&mut MessageParcel>, value: &str) -> bool { + unsafe { + let parcel = AsParcelMut(parcel); + WriteString(Pin::new_unchecked(&mut *parcel), value) + } + } + parcel.write_process(self, write) + } +} + +impl Serialize for [T] { + fn serialize(&self, parcel: &mut MsgParcel) -> IpcResult<()> { + match T::write_process_vec(self, parcel.as_parcel_mut()) { + true => Ok(()), + false => Err(IpcStatusCode::Failed), + } + } +} + +impl Deserialize for Vec { + fn deserialize(parcel: &mut MsgParcel) -> IpcResult { + T::read_process_vec(parcel.as_parcel_mut()) + } +} + +impl Serialize for Vec { + fn serialize(&self, parcel: &mut MsgParcel) -> crate::IpcResult<()> { + <[T]>::serialize(self, parcel) + } +} + +#[cfg(test)] +mod test { + use std::fs; + use std::io::{Read, Seek, Write}; + + use crate::parcel::MsgParcel; + + /// UT test cases for `MsgParcel` + /// + /// # Brief + /// 1. Create a MsgParcel + /// 2. Write a value to the MsgParcel and then read it out, check the + /// correctness. + /// 3. Check other types. + #[test] + fn primitive() { + let mut msg = MsgParcel::new(); + + msg.write_interface_token("test"); + assert_eq!(msg.read_interface_token().unwrap(), "test"); + + msg.write_buffer("test".as_bytes()); + assert_eq!(msg.read_buffer(msg.readable()).unwrap(), "test".as_bytes()); + + msg.write(&true).unwrap(); + assert!(msg.read::().unwrap()); + + msg.write(&false).unwrap(); + assert!(!msg.read::().unwrap()); + + msg.write(&i8::MAX).unwrap(); + assert_eq!(i8::MAX, msg.read().unwrap()); + msg.write(&i8::MIN).unwrap(); + assert_eq!(i8::MIN, msg.read().unwrap()); + + msg.write(&i16::MAX).unwrap(); + assert_eq!(i16::MAX, msg.read().unwrap()); + msg.write(&i16::MIN).unwrap(); + assert_eq!(i16::MIN, msg.read().unwrap()); + + msg.write(&i32::MAX).unwrap(); + assert_eq!(i32::MAX, msg.read().unwrap()); + msg.write(&i32::MIN).unwrap(); + assert_eq!(i32::MIN, msg.read().unwrap()); + + msg.write(&i64::MAX).unwrap(); + assert_eq!(i64::MAX, msg.read().unwrap()); + msg.write(&i64::MIN).unwrap(); + assert_eq!(i64::MIN, msg.read().unwrap()); + + msg.write(&u8::MAX).unwrap(); + assert_eq!(u8::MAX, msg.read().unwrap()); + msg.write(&u8::MIN).unwrap(); + assert_eq!(u8::MIN, msg.read().unwrap()); + + msg.write(&u16::MAX).unwrap(); + assert_eq!(u16::MAX, msg.read().unwrap()); + msg.write(&u16::MIN).unwrap(); + assert_eq!(u16::MIN, msg.read().unwrap()); + + msg.write(&u32::MAX).unwrap(); + assert_eq!(u32::MAX, msg.read().unwrap()); + msg.write(&u32::MIN).unwrap(); + assert_eq!(u32::MIN, msg.read().unwrap()); + + msg.write(&u64::MAX).unwrap(); + assert_eq!(u64::MAX, msg.read().unwrap()); + msg.write(&u64::MIN).unwrap(); + assert_eq!(u64::MIN, msg.read().unwrap()); + + msg.write(&usize::MAX).unwrap(); + assert_eq!(usize::MAX, msg.read().unwrap()); + msg.write(&usize::MIN).unwrap(); + assert_eq!(usize::MIN, msg.read().unwrap()); + + msg.write("hello ipc").unwrap(); + assert_eq!(String::from("hello ipc"), msg.read::().unwrap()); + + let s = String::from("hello ipc"); + msg.write(&s).unwrap(); + assert_eq!(String::from("hello ipc"), msg.read::().unwrap()); + + let v = vec![1]; + msg.write(&v).unwrap(); + assert_eq!(vec![1], msg.read::>().unwrap()); + + let s = String::from("ipc hello"); + let v = vec![s.clone(), s.clone(), s.clone(), s]; + msg.write(&v).unwrap(); + assert_eq!(v, msg.read::>().unwrap()); + } + + /// UT test cases for `MsgParcel` + /// + /// # Brief + /// 1. Create a MsgParcel + /// 2. Write a bunch of value to the MsgParcel and then read them out, check + /// the correctness. + #[test] + fn primitive_bunch() { + let mut msg = MsgParcel::new(); + msg.write(&true).unwrap(); + msg.write(&false).unwrap(); + msg.write(&i8::MAX).unwrap(); + msg.write(&i8::MIN).unwrap(); + msg.write(&i16::MAX).unwrap(); + msg.write(&i16::MIN).unwrap(); + msg.write(&i32::MAX).unwrap(); + msg.write(&i32::MIN).unwrap(); + msg.write(&i64::MAX).unwrap(); + msg.write(&i64::MIN).unwrap(); + msg.write(&u8::MAX).unwrap(); + msg.write(&u8::MIN).unwrap(); + + msg.write(&u16::MAX).unwrap(); + msg.write(&u16::MIN).unwrap(); + msg.write(&u32::MAX).unwrap(); + msg.write(&u32::MIN).unwrap(); + msg.write(&u64::MAX).unwrap(); + msg.write(&u64::MIN).unwrap(); + msg.write(&usize::MAX).unwrap(); + msg.write(&usize::MIN).unwrap(); + msg.write("hello ipc").unwrap(); + let s = String::from("hello ipc"); + msg.write(&s).unwrap(); + let v = vec![1]; + msg.write(&v).unwrap(); + let s = String::from("ipc hello"); + let v = vec![s.clone(), s.clone(), s.clone(), s]; + msg.write(&v).unwrap(); + + assert!(msg.read::().unwrap()); + assert!(!msg.read::().unwrap()); + assert_eq!(i8::MAX, msg.read().unwrap()); + assert_eq!(i8::MIN, msg.read().unwrap()); + + assert_eq!(i16::MAX, msg.read().unwrap()); + assert_eq!(i16::MIN, msg.read().unwrap()); + assert_eq!(i32::MAX, msg.read().unwrap()); + assert_eq!(i32::MIN, msg.read().unwrap()); + assert_eq!(i64::MAX, msg.read().unwrap()); + assert_eq!(i64::MIN, msg.read().unwrap()); + assert_eq!(u8::MAX, msg.read().unwrap()); + assert_eq!(u8::MIN, msg.read().unwrap()); + + assert_eq!(u16::MAX, msg.read().unwrap()); + assert_eq!(u16::MIN, msg.read().unwrap()); + assert_eq!(u32::MAX, msg.read().unwrap()); + assert_eq!(u32::MIN, msg.read().unwrap()); + assert_eq!(u64::MAX, msg.read().unwrap()); + assert_eq!(u64::MIN, msg.read().unwrap()); + assert_eq!(usize::MAX, msg.read().unwrap()); + assert_eq!(usize::MIN, msg.read().unwrap()); + assert_eq!(String::from("hello ipc"), msg.read::().unwrap()); + assert_eq!(String::from("hello ipc"), msg.read::().unwrap()); + assert_eq!(vec![1], msg.read::>().unwrap()); + assert_eq!(v, msg.read::>().unwrap()); + } + + /// UT test cases for `MsgParcel` + /// + /// # Brief + /// 1. Create a MsgParcel + /// 2. Write interface to the MsgParcel and then read them out, check the + /// correctness. + #[test] + fn interface() { + let mut msg = MsgParcel::new(); + msg.write_interface_token("test token").unwrap(); + assert_eq!("test token", msg.read_interface_token().unwrap()); + } + + /// UT test cases for `MsgParcel` + /// + /// # Brief + /// 1. Create a MsgParcel + /// 2. Write a file descriptor to the MsgParcel and then read them out, + /// check the correctness. + #[test] + fn file_descriptor() { + let mut msg = MsgParcel::new(); + + let mut file = std::fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open("ipc_rust_test_temp0") + .unwrap(); + file.write_all(b"hello world").unwrap(); + file.sync_all().unwrap(); + + msg.write_file(file).unwrap(); + let mut f = msg.read_file().unwrap(); + let mut buf = String::new(); + f.rewind().unwrap(); + f.read_to_string(&mut buf).unwrap(); + fs::remove_file("ipc_rust_test_temp0").unwrap(); + assert_eq!("hello world", buf); + } + + /// UT test cases for `MsgParcel` + /// + /// # Brief + /// 1. Create a MsgParcel + /// 2. Write a i32 value to the MsgParcel in different position and then + /// read them out, check the correctness. + #[test] + fn position() { + let mut msg = MsgParcel::new(); + assert_eq!(0, msg.write_position()); + assert_eq!(0, msg.read_position()); + + msg.set_write_position(4).unwrap_err(); + msg.set_read_position(4).unwrap_err(); + + msg.write(&1).unwrap(); + msg.write(&2).unwrap(); + assert_eq!(msg.size(), 8); + + msg.set_capacity(4).unwrap_err(); + msg.set_size(msg.capacity() + 1).unwrap_err(); + + msg.set_read_position(4).unwrap(); + assert_eq!(2, msg.read().unwrap()); + + msg.set_write_position(0).unwrap(); + msg.write(&2).unwrap(); + + assert_eq!(4, msg.size()); + + msg.set_read_position(0).unwrap(); + assert_eq!(2, msg.read().unwrap()); + msg.write(&1).unwrap(); + msg.write(&2).unwrap(); + + assert_eq!(8, msg.readable() as u32); + + msg.skip_read(4); + assert_eq!(2, msg.read().unwrap()); + } +} diff --git a/interfaces/innerkits/rust/src/process.rs b/interfaces/innerkits/rust/src/process.rs index 3fea259c..50f7c416 100644 --- a/interfaces/innerkits/rust/src/process.rs +++ b/interfaces/innerkits/rust/src/process.rs @@ -1,267 +1,78 @@ -/* - * 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. - */ +// Copyright (C) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -use crate::{ - ipc_binding, MsgParcel, RemoteObj, IRemoteObj, - InterfaceToken, String16, IpcResult, IpcStatusCode, - parse_status_code -}; -use crate::parcel::{vec_to_string, allocate_vec_with_buffer}; -use std::ffi::{CString, c_char, c_void}; -use hilog_rust::{info, hilog, HiLogLabel, LogType}; +//! IPC process -const LOG_LABEL: HiLogLabel = HiLogLabel { - log_type: LogType::LogCore, - domain: 0xD0057CA, - tag: "RustProcess" -}; +use std::ffi::c_void; +use std::mem::MaybeUninit; +use std::ptr; -/// Get proxy object of samgr -pub fn get_context_object() -> Option -{ - // SAFETY: If no SamgrContextManager object is available, the function might return nullptr, - // causing the subsequent RemoteObj::from_raw call to fail. - unsafe { - let samgr = ipc_binding::GetContextManager(); - RemoteObj::from_raw(samgr) - } -} +use crate::skeleton::ffi::IsHandlingTransaction; -/// Add a service to samgr -pub fn add_service(service: &RemoteObj, said: i32) -> IpcResult<()> -{ - let samgr = get_context_object().expect("samgr is not null"); - let mut data = MsgParcel::new().expect("MsgParcel is not null"); - 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 reply_value: i32 = reply.read()?; - info!(LOG_LABEL, "register service result: {}", reply_value); - if reply_value == 0 { Ok(())} else { Err(parse_status_code(reply_value)) } -} - -/// Get a service proxy from samgr -pub fn get_service(said: i32) -> IpcResult -{ - let samgr = get_context_object().expect("samgr is not null"); - let mut data = MsgParcel::new().expect("MsgParcel is not null"); - data.write(&InterfaceToken::new("ohos.samgr.accessToken"))?; - data.write(&said)?; - let reply = samgr.send_request(2, &data, false)?; - let remote: RemoteObj = reply.read()?; - info!(LOG_LABEL, "get service success"); - Ok(remote) -} - -/// Make current thread join to the IPC/RPC work thread pool +/// Determine whether the current thread is currently executing an incoming +/// transaction. #[inline] -pub fn join_work_thread() -{ +pub fn is_handling_transaction() -> bool { // SAFETY: - // It should only be called from a thread not already part of the pool. - // The potential blocking nature of the function and its impact on other threads. - unsafe { - ipc_binding::JoinWorkThread(); - } + // Ensure proper usage within the context of the IPC binding system and its + // intended behavior. + IsHandlingTransaction() } -/// Exit current thread from IPC/RPC work thread pool -#[inline] -pub fn stop_work_thread() -{ - // SAFETY: - // It should only be called from a thread belonging to the pool. - // Prematurely exiting might leave pending requests unprocessed and cause unexpected behavior. - unsafe { - ipc_binding::StopWorkThread() +/// Callback to allocate a vector for parcel array read functions. +/// +/// # Safety +/// +/// The opaque data pointer passed to the array read function must be a mutable +/// pointer to an `Option>>`. +pub unsafe extern "C" fn allocate_vec_with_buffer( + value: *mut c_void, + buffer: *mut *mut T, + len: i32, +) -> bool { + let res = allocate_vec::(value, len); + // `buffer` will be assigned a mutable pointer to the allocated vector data + // if this function returns true. + let vec = &mut *(value as *mut Option>>); + if let Some(new_vec) = vec { + *buffer = new_vec.as_mut_ptr() as *mut T; } + res } -/// Get calling token ID of caller -#[inline] -pub fn get_calling_token_id() -> u64 -{ - // SAFETY: - // Consider verifying it with additional security measures and context-based information when necessary. - unsafe { - ipc_binding::GetCallingTokenId() +/// Callback to allocate a vector for parcel array read functions. +/// +/// # Safety +/// +/// The opaque data pointer passed to the array read function must be a mutable +/// pointer to an `Option>>`. +unsafe extern "C" fn allocate_vec(value: *mut c_void, len: i32) -> bool { + if len < 0 { + return false; } + allocate_vec_maybeuninit::(value, len as u32); + true } -/// Get first calling token ID of caller -#[inline] -pub fn get_first_token_id() -> u64 -{ - // SAFETY: - // Consider verifying it with additional security measures and context-based information when necessary. - unsafe { - ipc_binding::GetFirstToekenId() - } +/// # Safety +/// +/// Ensure that the value pointer is not null +pub(crate) unsafe fn allocate_vec_maybeuninit(value: *mut c_void, len: u32) { + let vec = &mut *(value as *mut Option>>); + let mut new_vec: Vec> = Vec::with_capacity(len as usize); + + // SAFETY: this is safe because the vector contains MaybeUninit elements which + // can be uninitialized + new_vec.set_len(len as usize); + ptr::write(vec, Some(new_vec)); } - -/// Get self token id of current process -#[inline] -pub fn get_self_token_id() -> u64 -{ - // SAFETY: - // Minimize its exposure, restrict access to authorized parties within your application. - unsafe { - ipc_binding::GetSelfToekenId() - } -} - -/// Get calling process id of caller -#[inline] -pub fn get_calling_pid() -> u64 -{ - // SAFETY: - // The returned PID might be incorrect or invalid due to potential issues - // with the IPC mechanism or malicious attempts to manipulate it. - unsafe { - ipc_binding::GetCallingPid() - } -} - -/// Get calling user id of caller -#[inline] -pub fn get_calling_uid() -> u64 -{ - // SAFETY: - // Minimize its exposure, restrict access to authorized parties, - // and implement robust security measures to prevent unauthorized leaks or manipulation. - unsafe { - ipc_binding::GetCallingUid() - } -} - -/// Set the maximum number of threads -#[inline] -pub fn set_max_work_thread(max_thread_num: i32) -> bool -{ - // SAFETY: - // Ensuring the provided value is valid and appropriate for the system resources and workload. - unsafe { - ipc_binding::SetMaxWorkThreadNum(max_thread_num) - } -} - -/// Determine whether it is a local call -#[inline] -pub fn is_local_calling() -> bool -{ - // SAFETY: - // Ensure proper usage within the context of the IPC binding system and its intended behavior. - unsafe { - ipc_binding::IsLocalCalling() - } -} - -/// Set calling identity -#[inline] -pub fn set_calling_identity(identity: String) -> bool -{ - match CString::new(identity.as_str()) { - Ok(name) => { - // SAFETY: - // Name is valid - unsafe { - ipc_binding::SetCallingIdentity(name.as_ptr()) - } - }, - Err(_) => false, - } -} - -/// get local device id -#[inline] -pub fn get_local_device_id() -> IpcResult -{ - let mut vec: Option> = None; - // SAFETY: - // it's important to ensure that the vec contains valid data and is not null. - // The provided buffer size is sufficient to hold the returned data. - let ok_status = unsafe { - ipc_binding::GetLocalDeviceID( - &mut vec as *mut _ as *mut c_void, - allocate_vec_with_buffer:: - ) - }; - - if ok_status { - vec_to_string(vec) - } else { - Err(IpcStatusCode::Failed) - } -} - -/// get calling device id -#[inline] -pub fn get_calling_device_id() -> IpcResult -{ - let mut vec: Option> = None; - // SAFETY: - // it's important to ensure that the vec contains valid data and is not null. - // The provided buffer size is sufficient to hold the returned data. - let ok_status = unsafe { - ipc_binding::GetCallingDeviceID( - &mut vec as *mut _ as *mut c_void, - allocate_vec_with_buffer:: - ) - }; - - if ok_status { - vec_to_string(vec) - } else { - Err(IpcStatusCode::Failed) - } -} - -/// reset calling identity -#[inline] -pub fn reset_calling_identity() -> IpcResult -{ - let mut vec: Option> = None; - // SAFETY: - // The provided buffer size is sufficient to hold the returned data. - // The returned `String` is validated before using it. - let ok_status = unsafe { - ipc_binding::ResetCallingIdentity( - &mut vec as *mut _ as *mut c_void, - allocate_vec_with_buffer:: - ) - }; - - if ok_status { - vec_to_string(vec) - } else { - Err(IpcStatusCode::Failed) - } -} - -/// Determine whether the current thread is currently executing an incoming transaction. -#[inline] -pub fn is_handling_transaction() -> bool -{ - // SAFETY: - // Ensure proper usage within the context of the IPC binding system and its intended behavior. - unsafe { - ipc_binding::IsHandlingTransaction() - } -} \ No newline at end of file diff --git a/interfaces/innerkits/rust/src/remote/mod.rs b/interfaces/innerkits/rust/src/remote/mod.rs new file mode 100644 index 00000000..6f942881 --- /dev/null +++ b/interfaces/innerkits/rust/src/remote/mod.rs @@ -0,0 +1,23 @@ +// Copyright (C) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +//! IPC RemoteObj + +mod obj; +mod stub; +pub(crate) mod wrapper; + +pub use obj::RemoteObj; +pub use stub::RemoteStub; + diff --git a/interfaces/innerkits/rust/src/remote/obj.rs b/interfaces/innerkits/rust/src/remote/obj.rs new file mode 100644 index 00000000..2bf0502f --- /dev/null +++ b/interfaces/innerkits/rust/src/remote/obj.rs @@ -0,0 +1,179 @@ +// Copyright (C) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::mem; +use std::sync::Arc; + +use cxx::UniquePtr; + +use super::wrapper::{ + CloneRemoteObj, DeathRecipientRemoveHandler, FromCIRemoteObject, FromSptrRemote, IRemoteObject, + IRemoteObjectWrapper, RemoteStubWrapper, SptrIRemoteObject, +}; +use super::RemoteStub; +use crate::errors::{IpcResult, IpcStatusCode}; +use crate::ipc_async::{IpcAsyncRuntime, Runtime}; +use crate::parcel::msg::ParcelMem; +use crate::parcel::{MsgOption, MsgParcel}; + +/// Remote Object +pub struct RemoteObj { + pub(crate) inner: UniquePtr, +} + +impl Clone for RemoteObj { + fn clone(&self) -> Self { + Self { + inner: CloneRemoteObj(self.inner.as_ref().unwrap()), + } + } +} + +unsafe impl Send for RemoteObj {} +unsafe impl Sync for RemoteObj {} + +pub struct RecipientRemoveHandler { + inner: UniquePtr, +} + +impl RemoteObj { + /// Creates a Remote Object from C++ IRemoteObejectWrapper. + pub fn try_new(wrap: UniquePtr) -> Option { + if wrap.is_null() { + return None; + } + Some(Self { inner: wrap }) + } + + /// Creates a Remote Object from C++ IRemoteObejectWrapper. + pub unsafe fn new_unchecked(wrap: UniquePtr) -> Self { + Self { inner: wrap } + } + + pub unsafe fn from_ciremote(remote: *mut IRemoteObject) -> Option { + if remote.is_null() { + return None; + } + + let inner = FromCIRemoteObject(remote); + + if inner.is_null() { + return None; + } + + Some(Self { inner }) + } + + /// Creates a RemoteObj from RemoteStub. + pub fn from_stub(stub: T) -> Option { + RemoteStubWrapper::new(stub).into_remote() + } + + /// Creates a RemoteObj from sptr + pub fn from_sptr(sptr: UniquePtr) -> Option { + Self::try_new(FromSptrRemote(sptr)) + } + + /// Sends a IPC request to remote service + pub fn send_request(&self, code: u32, data: &mut MsgParcel) -> IpcResult { + let mut reply = MsgParcel::new(); + let mut option = MsgOption::new(); + match mem::replace(&mut data.inner, ParcelMem::Null) { + ParcelMem::Unique(mut p) => { + let res = self.inner.SendRequest( + code, + p.pin_mut(), + reply.pin_mut().unwrap(), + option.inner.pin_mut(), + ); + data.inner = ParcelMem::Unique(p); + if res != 0 { + error!("Send Request failed {}", res); + return Err(IpcStatusCode::Failed); + } + Ok(reply) + } + _ => Err(IpcStatusCode::Failed), + } + } + + /// Sends asynchronous IPC requests to remote services, The current + /// interface will use ylong runtime to start a separate thread to execute + /// requests + pub fn async_send_request( + self: &Arc, + code: u32, + mut data: MsgParcel, + mut option: MsgOption, + call_back: F, + ) where + F: FnOnce(MsgParcel) -> R, + F: Send + 'static, + R: Send + 'static, + { + let remote = self.clone(); + Runtime::spawn_blocking(move || { + let reply = remote.send_request(code, &mut data); + match reply { + Ok(reply) => { + call_back(reply); + IpcStatusCode::Ok + } + _ => IpcStatusCode::Failed, + } + }); + } + + /// Registries a death recipient, and returns a RecipientRemoveHandler, if + /// the registration is successful. + pub fn add_death_recipient(&self, f: fn(Box)) -> Option { + let inner = self.inner.AddDeathRecipient(f); + inner.is_null().then_some(RecipientRemoveHandler { inner }) + } + + /// Returns true if it is a proxy object. + pub fn is_proxy(&self) -> bool { + self.inner.IsProxyObject() + } + + /// Dumps a service through a String + pub fn dump(&self, fd: i32, args: &[String]) -> i32 { + self.inner.Dump(fd, args) + } + + /// + pub fn check_legalit(&self) -> bool { + self.inner.CheckObjectLegality() + } + + /// Returns true if the object is dead. + pub fn is_dead(&self) -> bool { + self.inner.IsObjectDead() + } + + /// Returns interface descriptor. + pub fn interface_descriptor(&self) -> IpcResult { + Ok(self.inner.GetInterfaceDescriptor()) + } + + /// Returns Object descriptor. + pub fn object_descriptor(&self) -> IpcResult { + Ok(self.inner.GetObjectDescriptor()) + } +} + +impl RecipientRemoveHandler { + pub fn remove_recipient(self) { + self.inner.remove(); + } +} diff --git a/interfaces/innerkits/rust/src/remote/stub.rs b/interfaces/innerkits/rust/src/remote/stub.rs new file mode 100644 index 00000000..16d17f44 --- /dev/null +++ b/interfaces/innerkits/rust/src/remote/stub.rs @@ -0,0 +1,66 @@ +// Copyright (C) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::fs::File; + +use crate::parcel::MsgParcel; +use crate::IpcResult; + +/// Impl this trait to build a remote stub, that can be published to +/// SystemAbilityManager and handle remote requests. +pub trait RemoteStub { + /// core method for RemoteStub, that handle remote request. + fn on_remote_request(&self, code: u32, data: &mut MsgParcel, reply: &mut MsgParcel) -> i32; + + /// Dump the contents. + fn dump(&self, _file: File, _args: Vec) -> i32 { + 0 + } + + // RemoteStub Descriptor + fn descriptor(&self) -> &'static str { + "" + } +} + +#[cfg(test)] +mod test { + use std::fs::{self, OpenOptions}; + use std::os::fd::AsRawFd; + + use super::*; + use crate::remote::RemoteObj; + + const TEST_NUM: i32 = 2024; + struct TestStub; + impl RemoteStub for TestStub { + fn on_remote_request(&self, code: u32, data: &mut MsgParcel, reply: &mut MsgParcel) -> i32 { + 0 + } + fn dump(&self, _file: File, _args: Vec) -> i32 { + TEST_NUM + } + fn descriptor(&self) -> &'static str { + "TEST STUB" + } + } + + #[test] + fn remote_stub() { + let remote = RemoteObj::from_stub(TestStub).unwrap(); + assert_eq!("TEST STUB", remote.interface_descriptor().unwrap()); + let file = File::create("ipc_rust_test_temp").unwrap(); + assert_eq!(TEST_NUM, remote.dump(file.as_raw_fd(), &[])); + fs::remove_file("ipc_rust_test_temp").unwrap(); + } +} diff --git a/interfaces/innerkits/rust/src/remote/wrapper.rs b/interfaces/innerkits/rust/src/remote/wrapper.rs new file mode 100644 index 00000000..d9c1c928 --- /dev/null +++ b/interfaces/innerkits/rust/src/remote/wrapper.rs @@ -0,0 +1,140 @@ +// Copyright (C) 2024 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. + +//! cxx wrapper +#![allow(missing_docs)] + +use std::fs::File; +use std::os::fd::FromRawFd; +use std::pin::Pin; + +use cxx::UniquePtr; +pub use ffi::*; + +pub use super::obj::RemoteObj; +use super::stub::RemoteStub; +use crate::parcel::MsgParcel; + +#[cxx::bridge(namespace = "OHOS::IpcRust")] +pub mod ffi { + + extern "Rust" { + type RemoteObj; + pub type RemoteStubWrapper; + + fn on_remote_request( + self: &mut RemoteStubWrapper, + code: u32, + data: Pin<&mut MessageParcel>, + reply: Pin<&mut MessageParcel>, + ) -> i32; + + fn dump(self: &mut RemoteStubWrapper, fd: i32, args: Vec) -> i32; + + fn descriptor(self: &mut RemoteStubWrapper) -> &'static str; + + fn new_remote_obj(wrap: UniquePtr) -> Box; + + } + + unsafe extern "C++" { + include!("remote_object_wrapper.h"); + type IRemoteObjectWrapper; + + #[namespace = "OHOS"] + type IRemoteObject; + #[namespace = "OHOS"] + type MessageParcel = crate::parcel::wrapper::MessageParcel; + #[namespace = "OHOS"] + type MessageOption = crate::parcel::wrapper::MessageOption; + type DeathRecipientRemoveHandler; + + #[namespace = "OHOS"] + type SptrIRemoteObject; + + fn FromSptrRemote(sptr: UniquePtr) -> UniquePtr; + + fn FromRemoteStub(stub: Box) -> UniquePtr; + + unsafe fn FromCIRemoteObject(remote: *mut IRemoteObject) + -> UniquePtr; + + fn SendRequest( + self: &IRemoteObjectWrapper, + code: u32, + data: Pin<&mut MessageParcel>, + reply: Pin<&mut MessageParcel>, + option: Pin<&mut MessageOption>, + ) -> i32; + + fn GetInterfaceDescriptor(self: &IRemoteObjectWrapper) -> String; + fn GetObjectDescriptor(self: &IRemoteObjectWrapper) -> String; + + fn IsProxyObject(self: &IRemoteObjectWrapper) -> bool; + fn IsObjectDead(self: &IRemoteObjectWrapper) -> bool; + fn CheckObjectLegality(self: &IRemoteObjectWrapper) -> bool; + + fn Dump(self: &IRemoteObjectWrapper, fd: i32, args: &[String]) -> i32; + fn AddDeathRecipient( + self: &IRemoteObjectWrapper, + cb: fn(Box), + ) -> UniquePtr; + + fn remove(self: &DeathRecipientRemoveHandler); + + fn CloneRemoteObj(remote: &IRemoteObjectWrapper) -> UniquePtr; + } + impl UniquePtr {} +} + +fn new_remote_obj(wrap: UniquePtr) -> Box { + Box::new(RemoteObj::try_new(wrap).unwrap()) +} + +pub struct RemoteStubWrapper { + inner: Box, +} + +impl RemoteStubWrapper { + pub fn new(remote: A) -> Self { + Self { + inner: Box::new(remote), + } + } + + pub fn on_remote_request( + &mut self, + code: u32, + data: Pin<&mut MessageParcel>, + reply: Pin<&mut MessageParcel>, + ) -> i32 { + unsafe { + let mut data = MsgParcel::from_ptr(data.get_unchecked_mut() as *mut MessageParcel); + let mut reply = MsgParcel::from_ptr(reply.get_unchecked_mut() as *mut MessageParcel); + self.inner.on_remote_request(code, &mut data, &mut reply) + } + } + + pub fn dump(&mut self, fd: i32, args: Vec) -> i32 { + let file = unsafe { File::from_raw_fd(fd) }; + self.inner.dump(file, args) + } + + pub fn descriptor(&self) -> &'static str { + self.inner.descriptor() + } + + pub fn into_remote(self) -> Option { + RemoteObj::try_new(FromRemoteStub(Box::new(self))) + } +} diff --git a/interfaces/innerkits/rust/src/skeleton.rs b/interfaces/innerkits/rust/src/skeleton.rs new file mode 100644 index 00000000..8721adb7 --- /dev/null +++ b/interfaces/innerkits/rust/src/skeleton.rs @@ -0,0 +1,159 @@ +// Copyright (C) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +use ffi::*; + +use crate::remote::RemoteObj; + +#[cxx::bridge(namespace = "OHOS::IpcRust")] +pub mod ffi { + + unsafe extern "C++" { + include!("skeleton_wrapper.h"); + type IRemoteObjectWrapper = crate::remote::wrapper::IRemoteObjectWrapper; + + fn SetMaxWorkThreadNum(maxThreadNum: i32) -> bool; + + fn JoinWorkThread(); + + fn StopWorkThread(); + + fn GetCallingPid() -> u64; + + fn GetCallingRealPid() -> u64; + + fn GetCallingUid() -> u64; + + fn GetCallingTokenID() -> u32; + + fn GetCallingFullTokenID() -> u64; + + fn GetFirstTokenID() -> u32; + + fn GetFirstFullTokenID() -> u64; + + fn GetSelfTokenID() -> u64; + + fn GetLocalDeviceID() -> String; + + fn GetCallingDeviceID() -> String; + + fn IsLocalCalling() -> bool; + + fn GetContextObject() -> UniquePtr; + + fn FlushCommands(object: Pin<&mut IRemoteObjectWrapper>) -> i32; + + fn ResetCallingIdentity() -> String; + + fn SetCallingIdentity(identity: &str) -> bool; + + fn IsHandlingTransaction() -> bool; + } +} + +/// Ipc Skeleton +pub struct Skeleton; + +impl Skeleton { + /// Sets the maximum number of threads. + pub fn set_max_work_thread_num(max_thread_num: i32) -> bool { + SetMaxWorkThreadNum(max_thread_num) + } + + /// Makes current thread join to the IPC/RPC work thread pool. + pub fn join_work_thread() { + JoinWorkThread(); + } + + /// Exits current thread from IPC/RPC work thread pool. + pub fn stop_work_thread() { + StopWorkThread(); + } + + /// Returns the calling process id of caller. + pub fn calling_pid() -> u64 { + GetCallingPid() + } + + /// Returns the calling process id of caller. + pub fn calling_real_pid() -> u64 { + GetCallingRealPid() + } + + /// Returns the calling user id of caller. + pub fn calling_uid() -> u64 { + GetCallingUid() + } + + /// Returns the calling token ID of caller. + pub fn calling_token_id() -> u32 { + GetCallingTokenID() + } + + /// Returns the calling token ID of caller. + pub fn calling_full_token_id() -> u64 { + GetCallingFullTokenID() + } + + /// Returns the the first token ID. + pub fn first_token_id() -> u32 { + GetFirstTokenID() + } + + /// Returns the the first full token ID. + pub fn first_full_token_id() -> u64 { + GetFirstFullTokenID() + } + + /// Returns the the token ID of the self. + pub fn self_token_id() -> u64 { + GetSelfTokenID() + } + + /// Returns the local device ID. + pub fn local_device_id() -> String { + GetLocalDeviceID() + } + + /// Returns the calling device id. + pub fn calling_device_id() -> String { + GetCallingDeviceID() + } + + /// Returns true if it is a local call. + pub fn is_local_calling() -> bool { + IsLocalCalling() + } + + /// Returns the context object. + pub fn get_context_object() -> Option { + RemoteObj::try_new(GetContextObject()) + } + + /// Flushes all pending commands. + pub fn flush_commands(remote: &mut RemoteObj) -> i32 { + FlushCommands(remote.inner.pin_mut()) + } + + /// Resets calling identity. + pub fn reset_calling_identity() -> String { + ResetCallingIdentity() + } + + /// Sets calling identity. + pub fn set_calling_identity(identity: &str) -> bool { + SetCallingIdentity(identity) + } +} diff --git a/interfaces/innerkits/rust/tests/BUILD.gn b/interfaces/innerkits/rust/tests/BUILD.gn new file mode 100644 index 00000000..511cfb40 --- /dev/null +++ b/interfaces/innerkits/rust/tests/BUILD.gn @@ -0,0 +1,62 @@ +# Copyright (c) 2024 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") + +ohos_rust_unittest("rust_ipc_ut_test") { + module_out_path = "ipc/ipc_rust" + + sources = [ "../src/lib.rs" ] + deps = [ + "../../rust:ipc_rust_cxx", + "//third_party/rust/crates/cxx:lib", + ] + + external_deps = [ + "hilog:hilog_rust", + "ylong_runtime:ylong_runtime", + ] + + subsystem_name = "communication" + part_name = "ipc" +} + +ohos_rust_systemtest("rust_ipc_sdv_test") { + module_out_path = "ipc/ipc_rust" + + rustflags = [ "--cfg=gn_test" ] + + sources = [ "entry.rs" ] + + deps = [ + "../../rust:ipc_rust", + "c:ipc_rust_test_c", + ] + + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "hilog:hilog_rust", + ] + + subsystem_name = "communication" + part_name = "ipc" +} + +group("unittest") { + testonly = true + deps = [ + ":rust_ipc_sdv_test", + ":rust_ipc_ut_test", + ] +} diff --git a/interfaces/innerkits/rust/tests/c/BUILD.gn b/interfaces/innerkits/rust/tests/c/BUILD.gn new file mode 100644 index 00000000..84776c3e --- /dev/null +++ b/interfaces/innerkits/rust/tests/c/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright (c) 2024 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/ohos.gni") + +config("libipc_c_private_config") { + cflags_cc = [ + "-DCONFIG_IPC_SINGLE", + "-O2", + ] +} + +ohos_static_library("ipc_rust_test_c") { + include_dirs = [ "include" ] + + sources = [ "src/ipc_rust_test.cpp" ] + configs = [ ":libipc_c_private_config" ] + deps = [ "../../../ipc_single:ipc_single" ] + + external_deps = [ "c_utils:utils" ] + + subsystem_name = "communication" + part_name = "ipc" +} diff --git a/interfaces/innerkits/rust/tests/c/include/ipc_rust_test.h b/interfaces/innerkits/rust/tests/c/include/ipc_rust_test.h new file mode 100644 index 00000000..97fa8231 --- /dev/null +++ b/interfaces/innerkits/rust/tests/c/include/ipc_rust_test.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024 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. + */ + +#ifndef IPC_RUST_TEST_H +#define IPC_RUST_TEST_H + +#include +#include +#include +#include + +#include "ipc_types.h" +#include "iremote_object.h" +#include "iremote_stub.h" +#include "message_parcel.h" +#include "refbase.h" + +namespace OHOS { + +struct CStringWrapper { +public: + CStringWrapper(std::string *); + char *raw; + size_t len; +}; + +extern "C" { +MessageParcel *GetTestMessageParcel(); +MessageParcel *ReadAndWrite(MessageParcel &data); +CStringWrapper *GetCallingDeviceID(); +uint64_t GetCallingFullTokenID(); +uint64_t GetCallingPid(); +uint64_t GetCallingRealPid(); +uint32_t GetCallingTokenID(); +uint64_t GetCallingUid(); +uint64_t GetFirstFullTokenID(); +uint32_t GetFirstTokenID(); +uint64_t SelfTokenID(); +bool IsLocalCalling(); +CStringWrapper *LocalDeviceID(); +CStringWrapper *ResetCallingIdentity(); +}; + +struct RemoteServiceStub : public IPCObjectStub { +public: + RemoteServiceStub(); + ~RemoteServiceStub(); + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + + int Dump(int fd, const std::vector &args) override; +}; + +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/interfaces/innerkits/rust/tests/c/src/ipc_rust_test.cpp b/interfaces/innerkits/rust/tests/c/src/ipc_rust_test.cpp new file mode 100644 index 00000000..350e3ed9 --- /dev/null +++ b/interfaces/innerkits/rust/tests/c/src/ipc_rust_test.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2024 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 "ipc_rust_test.h" + +#include +#include +#include +#include +#include +#include + +#include "ipc_skeleton.h" +#include "message_parcel.h" +#include "refbase.h" + +namespace OHOS { +const int VEC_NUM = 3; + +const int TEST_BUFFER_LENGTH = 4; +const float TEST_FLOAT = 7.02; +const double TEST_DOUBLE = 7.03; + +template void WriteTestVector(Parcel *parcel, T testValue, bool (Parcel::*Write)(const std::vector &)) +{ + std::vector v; + for (int i = 0; i < VEC_NUM; i++) { + v.push_back(testValue); + } + (parcel->*Write)(v); +} + +void WriteTestVec(MessageParcel *parcel) +{ + WriteTestVector(parcel, true, &Parcel::WriteBoolVector); + WriteTestVector(parcel, UCHAR_MAX, &Parcel::WriteUInt8Vector); + WriteTestVector(parcel, USHRT_MAX, &Parcel::WriteUInt16Vector); + WriteTestVector(parcel, UINT_MAX, &Parcel::WriteUInt32Vector); + WriteTestVector(parcel, ULLONG_MAX, &Parcel::WriteUInt64Vector); + + WriteTestVector(parcel, SCHAR_MAX, &Parcel::WriteInt8Vector); + WriteTestVector(parcel, SHRT_MAX, &Parcel::WriteInt16Vector); + WriteTestVector(parcel, INT_MAX, &Parcel::WriteInt32Vector); + WriteTestVector(parcel, LLONG_MAX, &Parcel::WriteInt64Vector); + + WriteTestVector(parcel, SCHAR_MIN, &Parcel::WriteInt8Vector); + WriteTestVector(parcel, SHRT_MIN, &Parcel::WriteInt16Vector); + WriteTestVector(parcel, INT_MIN, &Parcel::WriteInt32Vector); + WriteTestVector(parcel, LLONG_MIN, &Parcel::WriteInt64Vector); + + WriteTestVector(parcel, TEST_FLOAT, &Parcel::WriteFloatVector); + WriteTestVector(parcel, TEST_DOUBLE, &Parcel::WriteDoubleVector); + + WriteTestVector(parcel, "TEST", &Parcel::WriteStringVector); + WriteTestVector(parcel, u"TEST", &Parcel::WriteString16Vector); +} + +MessageParcel *GetTestMessageParcel() +{ + MessageParcel *parcel = new MessageParcel(); + std::u16string interface = std::u16string(u"TEST"); + parcel->WriteInterfaceToken(interface); + + auto data = std::string("TEST"); + + parcel->WriteBuffer(data.data(), data.size()); + + parcel->WriteBool(true); + + parcel->WriteUint8(UCHAR_MAX); + parcel->WriteUint16(USHRT_MAX); + parcel->WriteUint32(UINT_MAX); + parcel->WriteUint64(ULLONG_MAX); + + parcel->WriteInt8(SCHAR_MAX); + parcel->WriteInt16(SHRT_MAX); + parcel->WriteInt32(INT_MAX); + parcel->WriteInt64(LLONG_MAX); + + parcel->WriteInt8(SCHAR_MIN); + parcel->WriteInt16(SHRT_MIN); + parcel->WriteInt32(INT_MIN); + parcel->WriteInt64(LLONG_MIN); + + parcel->WriteFloat(TEST_FLOAT); + parcel->WriteDouble(TEST_DOUBLE); + + WriteTestVec(parcel); + return parcel; +} + +template +void ReadAndWriteV(MessageParcel *parcel, MessageParcel &data, bool (Parcel::*Write)(const std::vector &), + bool (Parcel::*Read)(std::vector *)) +{ + std::vector v; + (data.*Read)(&v); + (parcel->*Write)(v); +} + +MessageParcel *ReadAndWrite(MessageParcel &data) +{ + MessageParcel *parcel = new MessageParcel(); + + parcel->WriteInterfaceToken(data.ReadInterfaceToken()); + parcel->WriteBuffer(data.ReadBuffer(TEST_BUFFER_LENGTH), TEST_BUFFER_LENGTH); + + parcel->WriteBool(data.ReadBool()); + parcel->WriteUint8(data.ReadUint8()); + parcel->WriteUint16(data.ReadUint16()); + parcel->WriteUint32(data.ReadUint32()); + parcel->WriteUint64(data.ReadUint64()); + + parcel->WriteInt8(data.ReadInt8()); + parcel->WriteInt16(data.ReadInt16()); + parcel->WriteInt32(data.ReadInt32()); + parcel->WriteInt64(data.ReadInt64()); + + parcel->WriteInt8(data.ReadInt8()); + parcel->WriteInt16(data.ReadInt16()); + parcel->WriteInt32(data.ReadInt32()); + parcel->WriteInt64(data.ReadInt64()); + + parcel->WriteFloat(data.ReadFloat()); + parcel->WriteDouble(data.ReadDouble()); + + ReadAndWriteV(parcel, data, &Parcel::WriteBoolVector, &Parcel::ReadBoolVector); + ReadAndWriteV(parcel, data, &Parcel::WriteUInt8Vector, &Parcel::ReadUInt8Vector); + ReadAndWriteV(parcel, data, &Parcel::WriteUInt16Vector, &Parcel::ReadUInt16Vector); + ReadAndWriteV(parcel, data, &Parcel::WriteUInt32Vector, &Parcel::ReadUInt32Vector); + ReadAndWriteV(parcel, data, &Parcel::WriteUInt64Vector, &Parcel::ReadUInt64Vector); + + ReadAndWriteV(parcel, data, &Parcel::WriteInt8Vector, &Parcel::ReadInt8Vector); + ReadAndWriteV(parcel, data, &Parcel::WriteInt16Vector, &Parcel::ReadInt16Vector); + ReadAndWriteV(parcel, data, &Parcel::WriteInt32Vector, &Parcel::ReadInt32Vector); + ReadAndWriteV(parcel, data, &Parcel::WriteInt64Vector, &Parcel::ReadInt64Vector); + + ReadAndWriteV(parcel, data, &Parcel::WriteInt8Vector, &Parcel::ReadInt8Vector); + ReadAndWriteV(parcel, data, &Parcel::WriteInt16Vector, &Parcel::ReadInt16Vector); + ReadAndWriteV(parcel, data, &Parcel::WriteInt32Vector, &Parcel::ReadInt32Vector); + ReadAndWriteV(parcel, data, &Parcel::WriteInt64Vector, &Parcel::ReadInt64Vector); + + ReadAndWriteV(parcel, data, &Parcel::WriteFloatVector, &Parcel::ReadFloatVector); + ReadAndWriteV(parcel, data, &Parcel::WriteDoubleVector, &Parcel::ReadDoubleVector); + + ReadAndWriteV(parcel, data, &Parcel::WriteStringVector, &Parcel::ReadStringVector); + ReadAndWriteV(parcel, data, &Parcel::WriteString16Vector, &Parcel::ReadString16Vector); + + return parcel; +} + +CStringWrapper::CStringWrapper(std::string *s) : raw(s->data()), len(s->length()) +{ +} + +CStringWrapper *GetCallingDeviceID() +{ + auto s = new std::string; + *s = IPCSkeleton::GetCallingDeviceID(); + return new CStringWrapper(s); +} + +uint64_t GetCallingFullTokenID() +{ + return IPCSkeleton::GetCallingFullTokenID(); +} +uint64_t GetCallingPid() +{ + return IPCSkeleton::GetCallingPid(); +} +uint64_t GetCallingRealPid() +{ + return IPCSkeleton::GetCallingRealPid(); +} +uint32_t GetCallingTokenID() +{ + return IPCSkeleton::GetCallingTokenID(); +} +uint64_t GetCallingUid() +{ + return IPCSkeleton::GetCallingUid(); +} +uint64_t GetFirstFullTokenID() +{ + return IPCSkeleton::GetFirstFullTokenID(); +} + +uint32_t GetFirstTokenID() +{ + return IPCSkeleton::GetFirstTokenID(); +} + +uint64_t SelfTokenID() +{ + return IPCSkeleton::GetSelfTokenID(); +} + +bool IsLocalCalling() +{ + return IPCSkeleton::IsLocalCalling(); +} +CStringWrapper *LocalDeviceID() +{ + auto s = new std::string; + *s = IPCSkeleton::GetLocalDeviceID(); + return new CStringWrapper(s); +} +CStringWrapper *ResetCallingIdentity() +{ + auto s = new std::string; + *s = IPCSkeleton::ResetCallingIdentity(); + return new CStringWrapper(s); +} + +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/rust/tests/c_mem.rs b/interfaces/innerkits/rust/tests/c_mem.rs new file mode 100644 index 00000000..b5d7097f --- /dev/null +++ b/interfaces/innerkits/rust/tests/c_mem.rs @@ -0,0 +1,12 @@ +// Copyright (C) 2024 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. diff --git a/interfaces/innerkits/rust/tests/entry.rs b/interfaces/innerkits/rust/tests/entry.rs new file mode 100644 index 00000000..d25b7dba --- /dev/null +++ b/interfaces/innerkits/rust/tests/entry.rs @@ -0,0 +1,59 @@ +// Copyright (C) 2024 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. + +#![cfg(gn_test)] +mod c_mem; +mod interactive; +mod parcel_remote; +mod remote; +mod skeleton; +use std::ffi::{c_char, CString}; +use std::ptr; + +#[repr(C)] +struct TokenInfoParams { + dcaps_num: i32, + perms_num: i32, + acls_num: i32, + dcaps: *const *const c_char, + perms: *const c_char, + acls: *const *const c_char, + process_name: *const c_char, + apl_str: *const c_char, +} + +extern "C" { + fn GetAccessTokenId(token_info: *mut TokenInfoParams) -> u64; + fn SetSelfTokenID(token_id: u64) -> i32; +} + +pub fn init_access_token() { + let perms_str = CString::new("ohos.permission.DISTRIBUTED_DATASYNC").unwrap(); + let name = CString::new("listen_test").unwrap(); + let apl = CString::new("system_core").unwrap(); + let mut param = TokenInfoParams { + dcaps_num: 0, + perms_num: 0, + acls_num: 0, + dcaps: ptr::null(), + perms: perms_str.as_ptr(), + acls: ptr::null(), + process_name: name.as_ptr(), + apl_str: apl.as_ptr(), + }; + + unsafe { + let token_id = GetAccessTokenId(&mut param as *mut TokenInfoParams); + SetSelfTokenID(token_id); + } +} diff --git a/interfaces/innerkits/rust/tests/interactive.rs b/interfaces/innerkits/rust/tests/interactive.rs new file mode 100644 index 00000000..90096729 --- /dev/null +++ b/interfaces/innerkits/rust/tests/interactive.rs @@ -0,0 +1,142 @@ +// Copyright (C) 2024 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use ipc::cxx_share::MessageParcel; +use ipc::parcel::MsgParcel; + +const TEST_FLOAT: f32 = 7.02; +const TEST_DOUBLE: f64 = 7.03; + +fn check_parcel(msg: &mut MsgParcel) { + assert_eq!(msg.read_interface_token().unwrap(), "TEST"); + assert_eq!(msg.read_buffer("TEST".len()).unwrap(), "TEST".as_bytes()); + assert!(msg.read::().unwrap()); + assert_eq!(msg.read::().unwrap(), u8::MAX); + assert_eq!(msg.read::().unwrap(), u16::MAX); + assert_eq!(msg.read::().unwrap(), u32::MAX); + assert_eq!(msg.read::().unwrap(), u64::MAX); + + assert_eq!(msg.read::().unwrap(), i8::MAX); + assert_eq!(msg.read::().unwrap(), i16::MAX); + assert_eq!(msg.read::().unwrap(), i32::MAX); + assert_eq!(msg.read::().unwrap(), i64::MAX); + + assert_eq!(msg.read::().unwrap(), i8::MIN); + assert_eq!(msg.read::().unwrap(), i16::MIN); + assert_eq!(msg.read::().unwrap(), i32::MIN); + assert_eq!(msg.read::().unwrap(), i64::MIN); + + assert_eq!(msg.read::().unwrap(), 7.02); + assert_eq!(msg.read::().unwrap(), 7.03); + + assert_eq!(msg.read::>().unwrap(), vec![true; 3]); + + assert_eq!(msg.read::>().unwrap(), vec![u8::MAX; 3]); + assert_eq!(msg.read::>().unwrap(), vec![u16::MAX; 3]); + assert_eq!(msg.read::>().unwrap(), vec![u32::MAX; 3]); + assert_eq!(msg.read::>().unwrap(), vec![u64::MAX; 3]); + + assert_eq!(msg.read::>().unwrap(), vec![i8::MAX; 3]); + assert_eq!(msg.read::>().unwrap(), vec![i16::MAX; 3]); + assert_eq!(msg.read::>().unwrap(), vec![i32::MAX; 3]); + assert_eq!(msg.read::>().unwrap(), vec![i64::MAX; 3]); + + assert_eq!(msg.read::>().unwrap(), vec![i8::MIN; 3]); + assert_eq!(msg.read::>().unwrap(), vec![i16::MIN; 3]); + assert_eq!(msg.read::>().unwrap(), vec![i32::MIN; 3]); + assert_eq!(msg.read::>().unwrap(), vec![i64::MIN; 3]); + + assert_eq!(msg.read::>().unwrap(), vec![TEST_FLOAT; 3]); + assert_eq!(msg.read::>().unwrap(), vec![TEST_DOUBLE; 3]); + + assert_eq!( + msg.read::>().unwrap(), + vec![String::from("TEST"); 3] + ); + + assert_eq!( + msg.read_string16_vec().unwrap(), + vec![String::from("TEST"); 3] + ); +} + +#[test] +fn interactive_msg_parcel_read() { + let mut msg = unsafe { MsgParcel::from_ptr(GetTestMessageParcel()) }; + check_parcel(&mut msg); +} + +#[test] +fn interactive_msg_parcel_write() { + let mut msg = MsgParcel::new(); + msg.write_interface_token("TEST").unwrap(); + + let data = String::from("TEST"); + msg.write_buffer(data.as_bytes()).unwrap(); + + msg.write(&true).unwrap(); + msg.write(&u8::MAX).unwrap(); + msg.write(&u16::MAX).unwrap(); + msg.write(&u32::MAX).unwrap(); + msg.write(&u64::MAX).unwrap(); + + msg.write(&i8::MAX).unwrap(); + msg.write(&i16::MAX).unwrap(); + msg.write(&i32::MAX).unwrap(); + msg.write(&i64::MAX).unwrap(); + + msg.write(&i8::MIN).unwrap(); + msg.write(&i16::MIN).unwrap(); + msg.write(&i32::MIN).unwrap(); + msg.write(&i64::MIN).unwrap(); + + msg.write(&7.02f32).unwrap(); + msg.write(&7.03f64).unwrap(); + + msg.write(&vec![true; 3]).unwrap(); + msg.write(&vec![u8::MAX; 3]).unwrap(); + msg.write(&vec![u16::MAX; 3]).unwrap(); + msg.write(&vec![u32::MAX; 3]).unwrap(); + msg.write(&vec![u64::MAX; 3]).unwrap(); + + msg.write(&vec![i8::MAX; 3]).unwrap(); + msg.write(&vec![i16::MAX; 3]).unwrap(); + msg.write(&vec![i32::MAX; 3]).unwrap(); + msg.write(&vec![i64::MAX; 3]).unwrap(); + + msg.write(&vec![i8::MIN; 3]).unwrap(); + msg.write(&vec![i16::MIN; 3]).unwrap(); + msg.write(&vec![i32::MIN; 3]).unwrap(); + msg.write(&vec![i64::MIN; 3]).unwrap(); + + msg.write(&vec![TEST_FLOAT; 3]).unwrap(); + msg.write(&vec![TEST_DOUBLE; 3]).unwrap(); + + msg.write(&vec![String::from("TEST"); 3]).unwrap(); + + msg.write_string16_vec(&[ + String::from("TEST"), + String::from("TEST"), + String::from("TEST"), + ]) + .unwrap(); + + let mut reply = unsafe { MsgParcel::from_ptr(ReadAndWrite(msg.into_raw())) }; + check_parcel(&mut reply); +} + +#[link(name = "ipc_rust_test_c")] +extern "C" { + fn GetTestMessageParcel() -> *mut MessageParcel; + fn ReadAndWrite(parcel: *mut MessageParcel) -> *mut MessageParcel; +} diff --git a/interfaces/innerkits/rust/tests/parcel_remote.rs b/interfaces/innerkits/rust/tests/parcel_remote.rs new file mode 100644 index 00000000..75a4dea2 --- /dev/null +++ b/interfaces/innerkits/rust/tests/parcel_remote.rs @@ -0,0 +1,285 @@ +// Copyright (C) 2024 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. + +#![allow(missing_docs, unused)] +use std::fs::OpenOptions; +use std::io::{Read, Seek, SeekFrom, Write}; +use std::sync::Once; + +use ipc::parcel::{Deserialize, MsgOption, MsgParcel, Serialize}; +use ipc::remote::{RemoteObj, RemoteStub}; +use ipc::{IpcResult, Skeleton}; + +const TEST_SYSTEM_ABILITY_ID: i32 = 1012; +const TEST_FLOAT: f32 = 7.02; +const TEST_DOUBLE: f64 = 7.03; + +const TEST_LEN: usize = 10; + +fn init() { + #[cfg(gn_test)] + super::init_access_token(); + + static ONCE: Once = Once::new(); + + ONCE.call_once(|| { + let context = Skeleton::get_context_object().unwrap(); + let mut data = MsgParcel::new(); + let mut option = MsgOption::new(); + data.write_interface_token("ohos.samgr.accessToken"); + data.write(&TEST_SYSTEM_ABILITY_ID); + data.write_remote(RemoteObj::from_stub(TestRemoteStub).unwrap()) + .unwrap(); + data.write(&false); + data.write(&0); + data.write(""); + data.write(""); + + let mut reply = context.send_request(3, &mut data).unwrap(); + let value = reply.read::().unwrap(); + + assert_eq!(value, 0); + }); +} + +fn test_service() -> RemoteObj { + let context = Skeleton::get_context_object().unwrap(); + let mut data = MsgParcel::new(); + let mut option = MsgOption::new(); + data.write_interface_token("ohos.samgr.accessToken"); + data.write(&TEST_SYSTEM_ABILITY_ID); + let mut reply = context.send_request(2, &mut data).unwrap(); + reply.read_remote().unwrap() +} + +struct TestRemoteStub; + +impl RemoteStub for TestRemoteStub { + fn on_remote_request(&self, code: u32, data: &mut MsgParcel, reply: &mut MsgParcel) -> i32 { + match code { + 0 => parcel_remote(data, reply), + _ => unreachable!(), + } + 0 + } +} + +fn parcel_remote(data: &mut MsgParcel, reply: &mut MsgParcel) { + reply + .write_interface_token(data.read_interface_token().unwrap().as_str()) + .unwrap(); + let w = data.read_buffer(TEST_LEN).unwrap(); + reply.write_buffer(&w); + + reply.write_file(data.read_file().unwrap()); + + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + + reply.write(&data.read::>().unwrap()); + reply.write(&data.read::>().unwrap()); + + reply.write(&data.read::().unwrap()); + reply.write(&data.read::().unwrap()); + reply.write(&data.read::>().unwrap()); + reply.write_string16(&data.read_string16().unwrap()); + reply.write_string16_vec(&data.read_string16_vec().unwrap()); +} + +#[test] +fn parcel() { + init(); + let test_service = test_service(); + + let mut msg = MsgParcel::new(); + + msg.write_interface_token("hello ipc").unwrap(); + msg.write_buffer(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + + let mut file = std::fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open("ipc_rust_test_temp1") + .unwrap(); + file.write_all("hello ipc".as_bytes()); + msg.write_file(file); + + msg.write(&true).unwrap(); + msg.write(&false).unwrap(); + msg.write(&i8::MAX).unwrap(); + msg.write(&i8::MIN).unwrap(); + msg.write(&i16::MAX).unwrap(); + msg.write(&i16::MIN).unwrap(); + msg.write(&i32::MAX).unwrap(); + msg.write(&i32::MIN).unwrap(); + msg.write(&i64::MAX).unwrap(); + msg.write(&i64::MIN).unwrap(); + msg.write(&u8::MAX).unwrap(); + msg.write(&u8::MIN).unwrap(); + + msg.write(&u16::MAX).unwrap(); + msg.write(&u16::MIN).unwrap(); + msg.write(&u32::MAX).unwrap(); + msg.write(&u32::MIN).unwrap(); + msg.write(&u64::MAX).unwrap(); + msg.write(&u64::MIN).unwrap(); + msg.write(&usize::MAX).unwrap(); + msg.write(&usize::MIN).unwrap(); + + msg.write(&vec![true; 3]).unwrap(); + msg.write(&vec![i8::MIN; 3]).unwrap(); + msg.write(&vec![i16::MIN; 3]).unwrap(); + msg.write(&vec![i32::MIN; 3]).unwrap(); + msg.write(&vec![i64::MIN; 3]).unwrap(); + + msg.write(&vec![i8::MAX; 3]).unwrap(); + msg.write(&vec![i16::MAX; 3]).unwrap(); + msg.write(&vec![i32::MAX; 3]).unwrap(); + msg.write(&vec![i64::MAX; 3]).unwrap(); + + msg.write(&vec![u8::MIN; 3]).unwrap(); + msg.write(&vec![u16::MIN; 3]).unwrap(); + msg.write(&vec![u32::MIN; 3]).unwrap(); + msg.write(&vec![u64::MIN; 3]).unwrap(); + + msg.write(&vec![u8::MAX; 3]).unwrap(); + msg.write(&vec![u16::MAX; 3]).unwrap(); + msg.write(&vec![u32::MAX; 3]).unwrap(); + msg.write(&vec![u64::MAX; 3]).unwrap(); + + msg.write(&vec![TEST_FLOAT; 3]).unwrap(); + msg.write(&vec![TEST_DOUBLE; 3]).unwrap(); + + msg.write("hello ipc").unwrap(); + let s = String::from("hello ipc"); + msg.write(&s).unwrap(); + + let s = String::from("ipc hello"); + let v = vec![s.clone(), s.clone(), s.clone()]; + msg.write(&v).unwrap(); + + msg.write_string16(&s); + msg.write_string16_vec(&v); + + let mut reply = test_service.send_request(0, &mut msg).unwrap(); + + assert_eq!(reply.read_interface_token().unwrap(), "hello ipc"); + + assert_eq!( + reply.read_buffer(TEST_LEN).unwrap(), + vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ); + + let mut file = reply.read_file().unwrap(); + file.rewind(); + let mut res = vec![]; + file.read_to_end(&mut res); + let s = String::from_utf8(res).unwrap(); + assert_eq!(s, "hello ipc"); + + assert!(reply.read::().unwrap()); + assert!(!reply.read::().unwrap()); + assert_eq!(i8::MAX, reply.read().unwrap()); + assert_eq!(i8::MIN, reply.read().unwrap()); + + assert_eq!(i16::MAX, reply.read().unwrap()); + assert_eq!(i16::MIN, reply.read().unwrap()); + assert_eq!(i32::MAX, reply.read().unwrap()); + assert_eq!(i32::MIN, reply.read().unwrap()); + assert_eq!(i64::MAX, reply.read().unwrap()); + assert_eq!(i64::MIN, reply.read().unwrap()); + assert_eq!(u8::MAX, reply.read().unwrap()); + assert_eq!(u8::MIN, reply.read().unwrap()); + + assert_eq!(u16::MAX, reply.read().unwrap()); + assert_eq!(u16::MIN, reply.read().unwrap()); + assert_eq!(u32::MAX, reply.read().unwrap()); + assert_eq!(u32::MIN, reply.read().unwrap()); + assert_eq!(u64::MAX, reply.read().unwrap()); + assert_eq!(u64::MIN, reply.read().unwrap()); + assert_eq!(usize::MAX, reply.read().unwrap()); + assert_eq!(usize::MIN, reply.read().unwrap()); + + assert_eq!(reply.read::>().unwrap(), vec![true; 3]); + assert_eq!(reply.read::>().unwrap(), vec![i8::MIN; 3]); + assert_eq!(reply.read::>().unwrap(), vec![i16::MIN; 3]); + assert_eq!(reply.read::>().unwrap(), vec![i32::MIN; 3]); + assert_eq!(reply.read::>().unwrap(), vec![i64::MIN; 3]); + + assert_eq!(reply.read::>().unwrap(), vec![i8::MAX; 3]); + assert_eq!(reply.read::>().unwrap(), vec![i16::MAX; 3]); + assert_eq!(reply.read::>().unwrap(), vec![i32::MAX; 3]); + assert_eq!(reply.read::>().unwrap(), vec![i64::MAX; 3]); + + assert_eq!(reply.read::>().unwrap(), vec![u8::MIN; 3]); + assert_eq!(reply.read::>().unwrap(), vec![u16::MIN; 3]); + assert_eq!(reply.read::>().unwrap(), vec![u32::MIN; 3]); + assert_eq!(reply.read::>().unwrap(), vec![u64::MIN; 3]); + + assert_eq!(reply.read::>().unwrap(), vec![u8::MAX; 3]); + assert_eq!(reply.read::>().unwrap(), vec![u16::MAX; 3]); + assert_eq!(reply.read::>().unwrap(), vec![u32::MAX; 3]); + assert_eq!(reply.read::>().unwrap(), vec![u64::MAX; 3]); + + assert_eq!(reply.read::>().unwrap(), vec![TEST_FLOAT; 3]); + assert_eq!(reply.read::>().unwrap(), vec![TEST_DOUBLE; 3]); + + assert_eq!(String::from("hello ipc"), reply.read::().unwrap()); + assert_eq!(String::from("hello ipc"), reply.read::().unwrap()); + assert_eq!(v, reply.read::>().unwrap()); + assert_eq!(String::from("ipc hello"), reply.read_string16().unwrap()); + assert_eq!(v, reply.read_string16_vec().unwrap()); +} diff --git a/interfaces/innerkits/rust/tests/remote.rs b/interfaces/innerkits/rust/tests/remote.rs new file mode 100644 index 00000000..75d49078 --- /dev/null +++ b/interfaces/innerkits/rust/tests/remote.rs @@ -0,0 +1,87 @@ +// Copyright (C) 2024 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. + +#![allow(missing_docs, unused)] +use std::ffi::{c_char, CString}; +use std::io::{Read, Seek, SeekFrom, Write}; +use std::sync::Once; + +use hilog_rust::{hilog, info}; +use ipc::parcel::{Deserialize, MsgOption, MsgParcel, Serialize}; +use ipc::remote::{RemoteObj, RemoteStub}; +use ipc::{IpcResult, Skeleton}; + +const TEST_SYSTEM_ABILITY_ID: i32 = 1191; + +const LOG_LABEL: hilog_rust::HiLogLabel = hilog_rust::HiLogLabel { + log_type: hilog_rust::LogType::LogCore, + domain: 0xD001C50, + tag: "RequestService", +}; + +fn init() { + #[cfg(gn_test)] + super::init_access_token(); + + static ONCE: Once = Once::new(); + + ONCE.call_once(|| { + let context = Skeleton::get_context_object().unwrap(); + let mut data = MsgParcel::new(); + let mut option = MsgOption::new(); + data.write_interface_token("ohos.samgr.accessToken"); + data.write(&TEST_SYSTEM_ABILITY_ID); + data.write_remote(RemoteObj::from_stub(TestRemoteStub).unwrap()) + .unwrap(); + data.write(&false); + data.write(&0); + data.write(""); + data.write(""); + + let mut reply = context.send_request(3, &mut data).unwrap(); + let value = reply.read::().unwrap(); + + assert_eq!(value, 0); + }); +} + +fn test_service() -> RemoteObj { + let context = Skeleton::get_context_object().unwrap(); + let mut data = MsgParcel::new(); + let mut option = MsgOption::new(); + data.write_interface_token("ohos.samgr.accessToken"); + data.write(&TEST_SYSTEM_ABILITY_ID); + let mut reply = context.send_request(2, &mut data).unwrap(); + reply.read_remote().unwrap() +} + +fn unload_service() { + let context = Skeleton::get_context_object().unwrap(); + let mut data = MsgParcel::new(); + let mut option = MsgOption::new(); + data.write_interface_token("ohos.samgr.accessToken"); + data.write(&TEST_SYSTEM_ABILITY_ID); + let mut reply = context.send_request(21, &mut data).unwrap(); +} + +struct TestRemoteStub; + +impl RemoteStub for TestRemoteStub { + fn on_remote_request(&self, code: u32, data: &mut MsgParcel, reply: &mut MsgParcel) -> i32 { + reply.write("TestRemoteStub"); + 0 + } +} + +#[test] +fn death_recipient() {} diff --git a/interfaces/innerkits/rust/tests/skeleton.rs b/interfaces/innerkits/rust/tests/skeleton.rs new file mode 100644 index 00000000..4c9ea6c7 --- /dev/null +++ b/interfaces/innerkits/rust/tests/skeleton.rs @@ -0,0 +1,132 @@ +// Copyright (C) 2024 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. + +#![allow(missing_docs, unused)] +use std::ffi::{c_char, c_uchar}; +use std::io::{Read, Seek, SeekFrom, Write}; + +use ipc::parcel::{Deserialize, MsgOption, MsgParcel, Serialize}; +use ipc::remote::{RemoteObj, RemoteStub}; +use ipc::{IpcResult, Skeleton}; + +const TEST_SYSTEM_ABILITY_ID: i32 = 1011; + +fn init() { + #[cfg(gn_test)] + super::init_access_token(); +} + +struct TestRemoteStub; + +impl RemoteStub for TestRemoteStub { + fn on_remote_request(&self, code: u32, data: &mut MsgParcel, reply: &mut MsgParcel) -> i32 { + reply.write("TestRemoteStub"); + 0 + } +} + +/// UT test case for "contest object" +/// +/// # brief +/// 1. Get SAMGR context object +/// 2. Add a system ability by send request +/// 3. Check this system ability by send request +/// 4. Remove this system ability by send request +#[test] +fn context() { + init(); + let context = Skeleton::get_context_object().unwrap(); + let mut data = MsgParcel::new(); + let mut option = MsgOption::new(); + data.write_interface_token("ohos.samgr.accessToken"); + data.write(&TEST_SYSTEM_ABILITY_ID); + data.write_remote(RemoteObj::from_stub(TestRemoteStub).unwrap()) + .unwrap(); + data.write(&false); + data.write(&0); + data.write(""); + data.write(""); + + let mut reply = context.send_request(3, &mut data).unwrap(); + let value = reply.read::().unwrap(); + + assert_eq!(value, 0); + + data.write_interface_token("ohos.samgr.accessToken"); + data.write(&TEST_SYSTEM_ABILITY_ID); + let mut reply = context.send_request(2, &mut data).unwrap(); + let remote = reply.read_remote().unwrap(); + let mut reply = remote.send_request(0, &mut data).unwrap(); + let s = reply.read::().unwrap(); + assert_eq!("TestRemoteStub", s); + + data.write_interface_token("ohos.samgr.accessToken"); + data.write(&TEST_SYSTEM_ABILITY_ID); + let mut reply = context.send_request(4, &mut data).unwrap(); + let value = reply.read::().unwrap(); + assert_eq!(value, 0); +} + +#[test] +fn skeleton() { + unsafe { + assert_eq!( + Skeleton::calling_device_id(), + (*GetCallingDeviceID()).to_string() + ); + assert_eq!(Skeleton::calling_full_token_id(), GetCallingFullTokenID()); + assert_eq!(Skeleton::calling_pid(), GetCallingPid()); + assert_eq!(Skeleton::calling_real_pid(), GetCallingRealPid()); + assert_eq!(Skeleton::calling_token_id(), GetCallingTokenID()); + assert_eq!(Skeleton::calling_uid(), GetCallingUid()); + assert_eq!(Skeleton::first_full_token_id(), GetFirstFullTokenID()); + assert_eq!(Skeleton::first_token_id(), GetFirstTokenID()); + assert_eq!(Skeleton::self_token_id(), SelfTokenID()); + assert_eq!(Skeleton::is_local_calling(), IsLocalCalling()); + assert_eq!(Skeleton::local_device_id(), (*LocalDeviceID()).to_string()); + assert_eq!( + Skeleton::reset_calling_identity(), + (*ResetCallingIdentity()).to_string() + ); + } +} + +#[repr(C)] +struct CStringWrapper { + c_str: *mut c_uchar, + len: usize, +} + +#[allow(clippy::inherent_to_string)] +impl CStringWrapper { + fn to_string(&self) -> String { + let bytes = unsafe { std::slice::from_raw_parts(self.c_str, self.len) }; + unsafe { String::from_utf8_unchecked(bytes.to_vec()) } + } +} + +#[link(name = "ipc_rust_test_c")] +extern "C" { + fn GetCallingDeviceID() -> *mut CStringWrapper; + fn GetCallingFullTokenID() -> u64; + fn GetCallingPid() -> u64; + fn GetCallingRealPid() -> u64; + fn GetCallingTokenID() -> u32; + fn GetCallingUid() -> u64; + fn GetFirstFullTokenID() -> u64; + fn GetFirstTokenID() -> u32; + fn SelfTokenID() -> u64; + fn IsLocalCalling() -> bool; + fn LocalDeviceID() -> *mut CStringWrapper; + fn ResetCallingIdentity() -> *mut CStringWrapper; +} diff --git a/ipc/native/test/unittest/rust/client/src/main.rs b/ipc/native/test/unittest/rust/client/src/main.rs index 530f9d33..d21edd5e 100644 --- a/ipc/native/test/unittest/rust/client/src/main.rs +++ b/ipc/native/test/unittest/rust/client/src/main.rs @@ -87,7 +87,7 @@ async fn get_async_test_service(name: i32) get_service(name) }).await; - // The `is_panic` branch is not actually reachable as we compile + // The `is_panic` branch is not actually reachable in Android as we compile // with `panic = abort`. match res { Ok(Ok(obj)) => T::try_from(obj), diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..28707675 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,19 @@ +# Copyright (C) 2023 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. + +edition = "2021" +wrap_comments = true +imports_granularity = "Module" +group_imports = "StdExternalCrate" +format_code_in_doc_comments = true +normalize_comments = true