mirror of
https://gitee.com/openharmony/communication_ipc
synced 2024-11-23 07:50:24 +00:00
ipc_rust 接口重构
Signed-off-by: fqwert <yanglv2@huawei.com> Change-Id: Ib233f76fcc35feb72f006bfd8b203ab3509318c0
This commit is contained in:
parent
9d0c8cea51
commit
640b345c1e
2
.gitignore
vendored
2
.gitignore
vendored
@ -13,3 +13,5 @@
|
||||
|
||||
target
|
||||
Cargo.lock
|
||||
.clang-format
|
||||
.vscode
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
89
interfaces/innerkits/rust/include/parcel_wrapper.h
Normal file
89
interfaces/innerkits/rust/include/parcel_wrapper.h
Normal file
@ -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 <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "cxx.h"
|
||||
#include "message_option.h"
|
||||
#include "message_parcel.h"
|
||||
#include "remote_object_wrapper.h"
|
||||
|
||||
namespace OHOS {
|
||||
|
||||
namespace IpcRust {
|
||||
|
||||
std::unique_ptr<MessageParcel> NewMessageParcel();
|
||||
std::unique_ptr<MessageOption> 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<const uint8_t> buffer);
|
||||
bool ReadBuffer(MessageParcel &msgParcel, size_t len, rust::Vec<uint8_t> &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<rust::String &> &v);
|
||||
rust::vec<rust::String> ReadString16Vec(Parcel &parcel);
|
||||
|
||||
bool WriteBoolVector(Parcel &parcel, rust::slice<const bool> val);
|
||||
bool WriteInt8Vector(Parcel &parcel, rust::slice<const int8_t> val);
|
||||
bool WriteInt16Vector(Parcel &parcel, rust::slice<const int16_t> val);
|
||||
bool WriteInt32Vector(Parcel &parcel, rust::slice<const int32_t> val);
|
||||
bool WriteInt64Vector(Parcel &parcel, rust::slice<const int64_t> val);
|
||||
bool WriteUInt8Vector(Parcel &parcel, rust::slice<const uint8_t> val);
|
||||
bool WriteUInt16Vector(Parcel &parcel, rust::slice<const uint16_t> val);
|
||||
bool WriteUInt32Vector(Parcel &parcel, rust::slice<const uint32_t> val);
|
||||
bool WriteUInt64Vector(Parcel &parcel, rust::slice<const uint64_t> val);
|
||||
bool WriteFloatVector(Parcel &parcel, rust::slice<const float> val);
|
||||
bool WriteDoubleVector(Parcel &parcel, rust::slice<const double> val);
|
||||
bool WriteStringVector(Parcel &parcel, rust::slice<const rust::string> val);
|
||||
bool WriteString16Vector(Parcel &parcel, rust::slice<const rust::string> val);
|
||||
|
||||
bool ReadBoolVector(Parcel &parcel, rust::vec<bool> &val);
|
||||
bool ReadInt8Vector(Parcel &parcel, rust::vec<int8_t> &val);
|
||||
bool ReadInt16Vector(Parcel &parcel, rust::vec<int16_t> &val);
|
||||
bool ReadInt32Vector(Parcel &parcel, rust::vec<int32_t> &val);
|
||||
bool ReadInt64Vector(Parcel &parcel, rust::vec<int64_t> &val);
|
||||
bool ReadUInt8Vector(Parcel &parcel, rust::vec<uint8_t> &val);
|
||||
bool ReadUInt16Vector(Parcel &parcel, rust::vec<uint16_t> &val);
|
||||
bool ReadUInt32Vector(Parcel &parcel, rust::vec<uint32_t> &val);
|
||||
bool ReadUInt64Vector(Parcel &parcel, rust::vec<uint64_t> &val);
|
||||
bool ReadFloatVector(Parcel &parcel, rust::vec<float> &val);
|
||||
bool ReadDoubleVector(Parcel &parcel, rust::vec<double> &val);
|
||||
bool ReadStringVector(Parcel &parcel, rust::vec<rust::string> &val);
|
||||
bool ReadString16Vector(Parcel &parcel, rust::vec<rust::string> &val);
|
||||
|
||||
bool WriteRemoteObject(MessageParcel &msgParcel, std::unique_ptr<IRemoteObjectWrapper> object);
|
||||
std::unique_ptr<IRemoteObjectWrapper> ReadRemoteObject(MessageParcel &msgParcel);
|
||||
|
||||
} // namespace IpcRust
|
||||
} // namespace OHOS
|
||||
|
||||
#endif
|
106
interfaces/innerkits/rust/include/remote_object_wrapper.h
Normal file
106
interfaces/innerkits/rust/include/remote_object_wrapper.h
Normal file
@ -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 <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#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<IRemoteObject> 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<const rust::String> args) const;
|
||||
|
||||
std::unique_ptr<DeathRecipientRemoveHandler> AddDeathRecipient(rust::Fn<void(rust::Box<RemoteObj>)>) const;
|
||||
|
||||
IRemoteObject *GetInner() const;
|
||||
|
||||
bool is_raw_ = false;
|
||||
sptr<IRemoteObject> sptr_;
|
||||
IRemoteObject *raw_;
|
||||
};
|
||||
|
||||
struct DeathRecipientWrapper : public virtual IRemoteObject::DeathRecipient {
|
||||
public:
|
||||
DeathRecipientWrapper(rust::Fn<void(rust::Box<RemoteObj>)> cb);
|
||||
virtual void OnRemoteDied(const OHOS::wptr<OHOS::IRemoteObject> &object) override;
|
||||
|
||||
private:
|
||||
rust::Fn<void(rust::Box<RemoteObj>)> inner_;
|
||||
};
|
||||
|
||||
struct DeathRecipientRemoveHandler {
|
||||
public:
|
||||
DeathRecipientRemoveHandler(sptr<IRemoteObject> remote, sptr<IRemoteObject::DeathRecipient> recipient);
|
||||
void remove() const;
|
||||
|
||||
private:
|
||||
sptr<IRemoteObject> remote_;
|
||||
sptr<IRemoteObject::DeathRecipient> 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<std::u16string> &args) override;
|
||||
|
||||
private:
|
||||
RemoteStubWrapper *inner_;
|
||||
};
|
||||
|
||||
std::unique_ptr<IRemoteObjectWrapper> FromSptrRemote(std::unique_ptr<sptr<IRemoteObject>> remote);
|
||||
|
||||
std::unique_ptr<IRemoteObjectWrapper> CloneRemoteObj(const IRemoteObjectWrapper &remote);
|
||||
|
||||
std::unique_ptr<IRemoteObjectWrapper> FromRemoteStub(rust::Box<RemoteStubWrapper> stub);
|
||||
|
||||
std::unique_ptr<IRemoteObjectWrapper> FromCIRemoteObject(IRemoteObject *stub);
|
||||
|
||||
} // namespace IpcRust
|
||||
} // namespace OHOS
|
||||
|
||||
#endif
|
66
interfaces/innerkits/rust/include/skeleton_wrapper.h
Normal file
66
interfaces/innerkits/rust/include/skeleton_wrapper.h
Normal file
@ -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<IRemoteObjectWrapper> GetContextObject();
|
||||
|
||||
int FlushCommands(IRemoteObjectWrapper &object);
|
||||
|
||||
rust::string ResetCallingIdentity();
|
||||
|
||||
bool SetCallingIdentity(rust::str identity);
|
||||
|
||||
bool IsHandlingTransaction();
|
||||
|
||||
} // namespace IpcRust
|
||||
} // namespace OHOS
|
||||
|
||||
#endif
|
@ -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<Self> {
|
||||
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<Self> {
|
||||
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<RawData> {
|
||||
// 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<Self> {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
298
interfaces/innerkits/rust/src/cxx/parcel_wrapper.cpp
Normal file
298
interfaces/innerkits/rust/src/cxx/parcel_wrapper.cpp
Normal file
@ -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 <securec.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <codecvt>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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<MessageParcel> NewMessageParcel()
|
||||
{
|
||||
return std::make_unique<MessageParcel>();
|
||||
}
|
||||
|
||||
std::unique_ptr<MessageOption> NewMessageOption()
|
||||
{
|
||||
return std::make_unique<MessageOption>();
|
||||
}
|
||||
|
||||
Parcel const *AsParcel(const MessageParcel &msgParcel)
|
||||
{
|
||||
auto msgParcelMut = const_cast<MessageParcel *>(&msgParcel);
|
||||
return reinterpret_cast<Parcel *>(msgParcelMut);
|
||||
}
|
||||
|
||||
Parcel *AsParcelMut(MessageParcel &msgParcel)
|
||||
{
|
||||
return reinterpret_cast<Parcel *>(&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<IRemoteObjectWrapper> object)
|
||||
{
|
||||
if (object->is_raw_) {
|
||||
return false;
|
||||
} else {
|
||||
return msgParcel.WriteRemoteObject(object->sptr_);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<IRemoteObjectWrapper> ReadRemoteObject(MessageParcel &msgParcel)
|
||||
{
|
||||
sptr<IRemoteObject> remote = msgParcel.ReadRemoteObject();
|
||||
if (remote == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
auto wrapper = std::make_unique<IRemoteObjectWrapper>();
|
||||
wrapper->is_raw_ = false;
|
||||
wrapper->sptr_ = std::move(remote);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
bool WriteBuffer(MessageParcel &msgParcel, rust::slice<const uint8_t> buffer)
|
||||
{
|
||||
return msgParcel.WriteBuffer(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
bool ReadBuffer(MessageParcel &msgParcel, size_t len, rust::Vec<uint8_t> &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<typename T> std::vector<T> RustVec2CppVec(rust::slice<const T> val)
|
||||
{
|
||||
std::vector<T> v;
|
||||
for (auto i : val) {
|
||||
v.push_back(i);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
bool WriteBoolVector(Parcel &parcel, rust::slice<const bool> val)
|
||||
{
|
||||
return parcel.WriteBoolVector(RustVec2CppVec(val));
|
||||
}
|
||||
|
||||
bool WriteInt8Vector(Parcel &parcel, rust::slice<const int8_t> val)
|
||||
{
|
||||
return parcel.WriteInt8Vector(RustVec2CppVec(val));
|
||||
}
|
||||
|
||||
bool WriteInt16Vector(Parcel &parcel, rust::slice<const int16_t> val)
|
||||
{
|
||||
return parcel.WriteInt16Vector(RustVec2CppVec(val));
|
||||
}
|
||||
bool WriteInt32Vector(Parcel &parcel, rust::slice<const int32_t> val)
|
||||
{
|
||||
return parcel.WriteInt32Vector(RustVec2CppVec(val));
|
||||
}
|
||||
bool WriteInt64Vector(Parcel &parcel, rust::slice<const int64_t> val)
|
||||
{
|
||||
return parcel.WriteInt64Vector(RustVec2CppVec(val));
|
||||
}
|
||||
bool WriteUInt8Vector(Parcel &parcel, rust::slice<const uint8_t> val)
|
||||
{
|
||||
return parcel.WriteUInt8Vector(RustVec2CppVec(val));
|
||||
}
|
||||
bool WriteUInt16Vector(Parcel &parcel, rust::slice<const uint16_t> val)
|
||||
{
|
||||
return parcel.WriteUInt16Vector(RustVec2CppVec(val));
|
||||
}
|
||||
bool WriteUInt32Vector(Parcel &parcel, rust::slice<const uint32_t> val)
|
||||
{
|
||||
return parcel.WriteUInt32Vector(RustVec2CppVec(val));
|
||||
}
|
||||
bool WriteUInt64Vector(Parcel &parcel, rust::slice<const uint64_t> val)
|
||||
{
|
||||
return parcel.WriteUInt64Vector(RustVec2CppVec(val));
|
||||
}
|
||||
bool WriteFloatVector(Parcel &parcel, rust::slice<const float> val)
|
||||
{
|
||||
return parcel.WriteFloatVector(RustVec2CppVec(val));
|
||||
}
|
||||
bool WriteDoubleVector(Parcel &parcel, rust::slice<const double> val)
|
||||
{
|
||||
return parcel.WriteDoubleVector(RustVec2CppVec(val));
|
||||
}
|
||||
|
||||
bool WriteStringVector(Parcel &parcel, rust::slice<const rust::string> val)
|
||||
{
|
||||
std::vector<std::string> 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<const rust::string> val)
|
||||
{
|
||||
std::vector<std::u16string> 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<typename T> bool ReadVector(Parcel &parcel, rust::vec<T> &val, bool (Parcel::*ReadVec)(std::vector<T> *))
|
||||
{
|
||||
std::vector<T> v;
|
||||
if (!(parcel.*ReadVec)(&v)) {
|
||||
return false;
|
||||
}
|
||||
for (auto i : v) {
|
||||
val.push_back(i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadBoolVector(Parcel &parcel, rust::vec<bool> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadBoolVector);
|
||||
}
|
||||
bool ReadInt8Vector(Parcel &parcel, rust::vec<int8_t> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadInt8Vector);
|
||||
}
|
||||
bool ReadInt16Vector(Parcel &parcel, rust::vec<int16_t> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadInt16Vector);
|
||||
}
|
||||
bool ReadInt32Vector(Parcel &parcel, rust::vec<int32_t> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadInt32Vector);
|
||||
}
|
||||
bool ReadInt64Vector(Parcel &parcel, rust::vec<int64_t> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadInt64Vector);
|
||||
}
|
||||
bool ReadUInt8Vector(Parcel &parcel, rust::vec<uint8_t> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadUInt8Vector);
|
||||
}
|
||||
bool ReadUInt16Vector(Parcel &parcel, rust::vec<uint16_t> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadUInt16Vector);
|
||||
}
|
||||
bool ReadUInt32Vector(Parcel &parcel, rust::vec<uint32_t> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadUInt32Vector);
|
||||
}
|
||||
bool ReadUInt64Vector(Parcel &parcel, rust::vec<uint64_t> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadUInt64Vector);
|
||||
}
|
||||
bool ReadFloatVector(Parcel &parcel, rust::vec<float> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadFloatVector);
|
||||
}
|
||||
bool ReadDoubleVector(Parcel &parcel, rust::vec<double> &val)
|
||||
{
|
||||
return ReadVector(parcel, val, &Parcel::ReadDoubleVector);
|
||||
}
|
||||
|
||||
bool ReadStringVector(Parcel &parcel, rust::vec<rust::string> &val)
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
if (!parcel.ReadStringVector(&v)) {
|
||||
return false;
|
||||
}
|
||||
for (auto s : v) {
|
||||
val.push_back(s.data());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadString16Vector(Parcel &parcel, rust::vec<rust::string> &val)
|
||||
{
|
||||
std::vector<std::u16string> v;
|
||||
if (!parcel.ReadString16Vector(&v)) {
|
||||
return false;
|
||||
}
|
||||
for (auto i : v) {
|
||||
val.push_back(i.data());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace IpcRust
|
||||
} // namespace OHOS
|
222
interfaces/innerkits/rust/src/cxx/remote_object_wrapper.cpp
Normal file
222
interfaces/innerkits/rust/src/cxx/remote_object_wrapper.cpp
Normal file
@ -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 <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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<DeathRecipientRemoveHandler> IRemoteObjectWrapper::AddDeathRecipient(
|
||||
rust::Fn<void(rust::Box<RemoteObj>)> callback) const
|
||||
{
|
||||
sptr<IRemoteObject::DeathRecipient> recipient(new DeathRecipientWrapper(callback));
|
||||
bool res = sptr_->AddDeathRecipient(recipient);
|
||||
if (!res) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<DeathRecipientRemoveHandler>(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<const rust::String> args) const
|
||||
{
|
||||
std::vector<std::u16string> 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<void(rust::Box<RemoteObj>)> cb)
|
||||
{
|
||||
this->inner_ = cb;
|
||||
}
|
||||
|
||||
void DeathRecipientWrapper::OnRemoteDied(const OHOS::wptr<OHOS::IRemoteObject> &object)
|
||||
{
|
||||
auto obj = object.promote();
|
||||
if (obj == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto wrapper = std::make_unique<IRemoteObjectWrapper>();
|
||||
|
||||
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<IRemoteObject> remote, sptr<IRemoteObject::DeathRecipient> 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<RemoteStubWrapper>::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<std::u16string> &args)
|
||||
{
|
||||
auto v = rust::Vec<rust::String>();
|
||||
for (auto arg : args) {
|
||||
v.push_back(rust::String(arg.data()));
|
||||
}
|
||||
return inner_->dump(fd, v);
|
||||
}
|
||||
|
||||
std::unique_ptr<IRemoteObjectWrapper> FromSptrRemote(std::unique_ptr<sptr<IRemoteObject>> remote)
|
||||
{
|
||||
if (remote == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
auto wrapper = std::make_unique<IRemoteObjectWrapper>();
|
||||
|
||||
wrapper->is_raw_ = false;
|
||||
wrapper->sptr_ = std::move(*remote.release());
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
std::unique_ptr<IRemoteObjectWrapper> 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<IRemoteObjectWrapper>();
|
||||
|
||||
wrapper->is_raw_ = false;
|
||||
wrapper->sptr_ = sptr;
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<IRemoteObjectWrapper> FromRemoteStub(rust::Box<RemoteStubWrapper> 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<RemoteServiceStub>::MakeSptr(raw, descriptor);
|
||||
|
||||
auto wrapper = std::make_unique<IRemoteObjectWrapper>();
|
||||
|
||||
wrapper->is_raw_ = false;
|
||||
wrapper->sptr_ = stub_sptr;
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
std::unique_ptr<IRemoteObjectWrapper> FromCIRemoteObject(IRemoteObject *stub)
|
||||
{
|
||||
if (stub == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
auto wrapper = std::make_unique<IRemoteObjectWrapper>();
|
||||
|
||||
wrapper->is_raw_ = true;
|
||||
wrapper->raw_ = stub;
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
} // namespace IpcRust
|
||||
} // namespace OHOS
|
130
interfaces/innerkits/rust/src/cxx/skeleton_wrapper.cpp
Normal file
130
interfaces/innerkits/rust/src/cxx/skeleton_wrapper.cpp
Normal file
@ -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<IRemoteObjectWrapper> GetContextObject()
|
||||
{
|
||||
auto wrapper = std::make_unique<IRemoteObjectWrapper>();
|
||||
|
||||
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
|
21
interfaces/innerkits/rust/src/cxx_share.rs
Normal file
21
interfaces/innerkits/rust/src/cxx_share.rs
Normal file
@ -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,
|
||||
};
|
@ -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<T> = std::result::Result<T, IpcStatusCode>;
|
||||
@ -32,7 +23,7 @@ pub type IpcResult<T> = std::result::Result<T, IpcStatusCode>;
|
||||
/// or
|
||||
/// status_result::<MsgParcel>(result, reply)
|
||||
pub fn status_result<T>(code: i32, val: T) -> IpcResult<T> {
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
50
interfaces/innerkits/rust/src/hilog.rs
Normal file
50
interfaces/innerkits/rust/src/hilog.rs
Normal file
@ -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));
|
||||
}}
|
||||
}
|
@ -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<Self> {
|
||||
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<dyn $remote_broker + Sync + Send>);
|
||||
|
||||
impl $stub {
|
||||
/// Create a new remote stub service
|
||||
#[allow(dead_code)]
|
||||
pub fn new_remote_stub<T>(obj: T) -> Option<$crate::RemoteStub<Self>>
|
||||
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<dyn ITest>", "*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<dyn ITest>
|
||||
fn try_from(object: $crate::RemoteObj)
|
||||
-> $crate::IpcResult<$crate::RemoteObjRef<dyn $remote_broker>> {
|
||||
Ok($crate::RemoteObjRef::new(Box::new($proxy::from_remote_object(&object)?)))
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
// For example, convert RemoteObj to RemoteObjRef<dyn IATest<P>>
|
||||
impl<P: $crate::IpcAsyncPool> $crate::FromRemoteObj for dyn $async_interface<P> {
|
||||
fn try_from(object: $crate::RemoteObj)
|
||||
-> $crate::IpcResult<$crate::RemoteObjRef<dyn $async_interface<P>>> {
|
||||
Ok($crate::RemoteObjRef::new(Box::new($proxy::from_remote_object(&object)?)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: $crate::IpcAsyncPool> $crate::ToAsyncIpc<P> for dyn $remote_broker {
|
||||
type Target = dyn $async_interface<P>;
|
||||
}
|
||||
|
||||
impl<P: $crate::IpcAsyncPool> $crate::ToSyncIpc for dyn $async_interface<P> {
|
||||
type Target = dyn $remote_broker;
|
||||
}
|
||||
)?
|
||||
};
|
||||
}
|
@ -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<MsgParcel>;
|
||||
|
||||
/// 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<F, R>(&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<String16>) -> i32;
|
||||
|
||||
/// Judge whether the object is dead
|
||||
fn is_dead(&self) -> bool;
|
||||
|
||||
/// get interface descriptor
|
||||
fn interface_descriptor(&self) -> IpcResult<String>;
|
||||
}
|
||||
|
||||
/// 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<String16>) -> i32;
|
||||
}
|
||||
|
||||
/// Like C++ IRemoteBroker class
|
||||
pub trait IRemoteBroker: Send + Sync {
|
||||
/// Convert self to RemoteObject
|
||||
fn as_object(&self) -> Option<RemoteObj> {
|
||||
panic!("This is not a RemoteObject.")
|
||||
}
|
||||
/// Default dump
|
||||
fn dump(&self, _file: &FileDesc, _args: &mut Vec<String16>) -> 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<RemoteObjRef<Self>>;
|
||||
}
|
||||
|
||||
/// Strong reference for "dyn IRemoteBroker" object, for example T is "dyn ITest"
|
||||
pub struct RemoteObjRef<T: FromRemoteObj + ?Sized>(Box<T>);
|
||||
|
||||
impl<T: FromRemoteObj + ?Sized> RemoteObjRef<T> {
|
||||
/// Create a RemoteObjRef object
|
||||
pub fn new(object: Box<T>) -> Self {
|
||||
Self(object)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromRemoteObj + ?Sized> Deref for RemoteObjRef<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: FromRemoteObj + ?Sized> Clone for RemoteObjRef<I> {
|
||||
fn clone(&self) -> Self {
|
||||
// Clone is a method in the RemoteObjRef structure.
|
||||
// T in RemoteObjRef<T>implements 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<I: FromRemoteObj + ?Sized> Ord for RemoteObjRef<I> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.0.as_object().cmp(&other.0.as_object())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: FromRemoteObj + ?Sized> PartialOrd for RemoteObjRef<I> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.0.as_object().partial_cmp(&other.0.as_object())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: FromRemoteObj + ?Sized> PartialEq for RemoteObjRef<I> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.as_object().eq(&other.0.as_object())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: FromRemoteObj + ?Sized> Eq for RemoteObjRef<I> {}
|
@ -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<CRemoteObject>);
|
||||
|
||||
impl RemoteObj {
|
||||
/// Create an `RemoteObj` wrapper object from a raw `CRemoteObject` pointer.
|
||||
/// # Safety
|
||||
pub unsafe fn from_raw(obj: *mut CRemoteObject) -> Option<RemoteObj> {
|
||||
if obj.is_null() {
|
||||
None
|
||||
} 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<RemoteObj> {
|
||||
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<MsgParcel> {
|
||||
// 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<F, R>(&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<String16>) -> 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::<Vec<String16>>(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<String> {
|
||||
let mut vec: Option<Vec<u16>> = 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::<u16>
|
||||
)
|
||||
};
|
||||
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<Self> {
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Ordering> {
|
||||
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 {}
|
@ -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<F>(callback: F) -> Option<DeathRecipient>
|
||||
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::<F>,
|
||||
Self::on_destroy::<F>, 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<F>(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<F>(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<CDeathRecipient> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<T: IRemoteStub> {
|
||||
native: *mut CRemoteObject,
|
||||
rust: *mut T,
|
||||
}
|
||||
|
||||
impl<T: IRemoteStub> RemoteStub<T> {
|
||||
/// Create a RemoteStub object
|
||||
pub fn new(rust: T) -> Option<Self> {
|
||||
let rust = Box::into_raw(Box::new(rust));
|
||||
let descripor = CString::new(T::get_descriptor()).expect("descripor must be valid!");
|
||||
// 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<T: IRemoteStub> IRemoteBroker for RemoteStub<T> {
|
||||
fn as_object(&self) -> Option<RemoteObj> {
|
||||
// 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<T: IRemoteStub> Send for RemoteStub<T> {}
|
||||
/// # Safety
|
||||
///
|
||||
/// RemoteSub thread safety. Multi-thread access and sharing have been considered inside the C-side code
|
||||
unsafe impl<T: IRemoteStub> Sync for RemoteStub<T> {}
|
||||
|
||||
impl<T: IRemoteStub> Deref for RemoteStub<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
// SAFETY:
|
||||
// Rust `Box::into_raw` poiter, so is valid
|
||||
unsafe {
|
||||
&*self.rust
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IRemoteStub> Drop for RemoteStub<T> {
|
||||
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<T: IRemoteStub> RemoteStub<T> {
|
||||
/// # 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::<FileDesc>() {
|
||||
Ok(file) => file,
|
||||
_ => {
|
||||
error!(LOG_LABEL, "read FileDesc failed");
|
||||
return IpcStatusCode::Failed as i32;
|
||||
}
|
||||
};
|
||||
let mut args: Vec<String16> = match data.read::<Vec<String16>>() {
|
||||
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<T> on_destroy in Rust");
|
||||
// T will be freed by Box after this function end.
|
||||
drop(Box::from_raw(user_data as *mut T));
|
||||
}
|
||||
}
|
@ -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<F: Future>(future: F) -> F::Output
|
||||
{
|
||||
fn block_on<F: Future>(future: F) -> F::Output {
|
||||
ylong_runtime::block_on(future)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<Box<dyn Future<Output = T> + 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<B>>
|
||||
fn spawn<'a, F1, F2, Fut, A, B>(
|
||||
spawn_this: F1,
|
||||
after_handle: F2,
|
||||
) -> BoxFuture<'a, IpcResult<B>>
|
||||
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<Output = R>,
|
||||
T: Send + 'static,
|
||||
R: Send + 'static,;
|
||||
R: Send + 'static;
|
||||
|
||||
/// Using the default task setting, spawns a blocking task.
|
||||
fn spawn_blocking<T, R>(task: T) -> JoinHandle<R>
|
||||
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<F: Future>(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<P>
|
||||
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<I: FromRemoteObj + ?Sized> RemoteObjRef<I> {
|
||||
/// Convert this synchronous remote object handle into an asynchronous one.
|
||||
pub fn into_async<P>(&self) -> RemoteObjRef<<I as ToAsyncIpc<P>>::Target>
|
||||
where
|
||||
I: ToAsyncIpc<P>,
|
||||
{
|
||||
// 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<<I as ToSyncIpc>::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()
|
||||
}
|
||||
}
|
@ -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<T> = 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::<u16>) -> 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::<u8>) -> 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::<u8>) -> 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::<u8>) -> 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>) -> 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::<i8>) -> 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::<i16>) -> 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::<i32>) -> 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::<i64>) -> 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::<f32>) -> 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::<f64>) -> 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::<u8>) -> bool;
|
||||
pub fn CParcelReadString16Element(index: u32, data: *const c_void, value: *mut c_void,
|
||||
allocator: OnCParcelBytesAllocator::<u16>) -> 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::<u8>) -> bool;
|
||||
pub fn GetCallingDeviceID(value: *mut c_void, allocator: OnCParcelBytesAllocator::<u8>) -> bool;
|
||||
pub fn ResetCallingIdentity(value: *mut c_void, allocator: OnCParcelBytesAllocator::<u8>) -> bool;
|
||||
|
||||
pub fn IsHandlingTransaction() -> bool;
|
||||
}
|
@ -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<T> {
|
||||
/// 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;
|
||||
}
|
||||
const LOG_LABEL: HiLogLabel = HiLogLabel {
|
||||
log_type: LogType::LogCore,
|
||||
domain: 0xD0057CA,
|
||||
tag: "IPC_RUST",
|
||||
};
|
||||
|
29
interfaces/innerkits/rust/src/parcel/error.rs
Normal file
29
interfaces/innerkits/rust/src/parcel/error.rs
Normal file
@ -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 {}
|
159
interfaces/innerkits/rust/src/parcel/exts.rs
Normal file
159
interfaces/innerkits/rust/src/parcel/exts.rs
Normal file
@ -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<i32>,
|
||||
/// 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<i32>,
|
||||
/// b: String,
|
||||
/// }
|
||||
///
|
||||
/// impl Deserialize for Foo {
|
||||
/// fn deserialize(parcel: &mut MsgParcel) -> IpcResult<Self> {
|
||||
/// 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<Self>;
|
||||
}
|
||||
|
||||
pub const NULL_FLAG: i32 = 0;
|
||||
pub const NON_NULL_FLAG: i32 = 1;
|
||||
|
||||
impl<T: Serialize> Serialize for Option<T> {
|
||||
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<T: Deserialize> Deserialize for Option<T> {
|
||||
fn deserialize(parcel: &mut MsgParcel) -> IpcResult<Self> {
|
||||
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::<bool>().unwrap());
|
||||
assert_eq!(String::from("hello"), msg.read::<String>().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<Self> {
|
||||
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());
|
||||
}
|
||||
}
|
@ -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<CParcel> {
|
||||
/// 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<Vec<u8>> {
|
||||
let mut buffer: Vec<MaybeUninit<u8>> = Vec::with_capacity(len as usize);
|
||||
// SAFETY: this is safe because the vector contains MaybeUninit elements which can be uninitialized
|
||||
unsafe{
|
||||
buffer.set_len(len as usize);
|
||||
}
|
||||
// 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<std::mem::MaybeUninit<u8>>) -> Vec<u8> {
|
||||
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<RawData> {
|
||||
// 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::<u8>() `
|
||||
// 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::<u8>()` of the slice is no larger than `isize::MAX`
|
||||
unsafe {
|
||||
Ok(slice::from_raw_parts::<u8>(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<CParcel>,
|
||||
}
|
||||
/// # 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<Self> {
|
||||
// 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<MsgParcel> {
|
||||
NonNull::new(ptr).map(|ptr| Self { ptr })
|
||||
}
|
||||
|
||||
/// Get a raw CParcel pointer and MsgParcel dropped its ownership
|
||||
pub fn into_raw(self) -> *mut CParcel {
|
||||
let ptr = self.ptr.as_ptr();
|
||||
let _ = ManuallyDrop::new(self);
|
||||
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<CParcel> 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<CParcel> 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<CParcel>,
|
||||
_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<BorrowedMsgParcel<'a>> {
|
||||
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<CParcel> 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<D: Deserialize>(&self) -> IpcResult<D> {
|
||||
self.borrowed_ref().read()
|
||||
}
|
||||
|
||||
/// Write a data object which implements the Serialize trait to MsgParcel
|
||||
pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> IpcResult<()> {
|
||||
self.borrowed().write(parcelable)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BorrowedMsgParcel<'a> {
|
||||
/// Read a data object which implements the Deserialize trait from BorrowedMsgParcel
|
||||
pub fn read<D: Deserialize>(&self) -> IpcResult<D> {
|
||||
D::deserialize(self)
|
||||
}
|
||||
|
||||
/// Write a data object which implements the Serialize trait to BorrowedMsgParcel
|
||||
pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> IpcResult<()> {
|
||||
parcelable.serialize(self)
|
||||
}
|
||||
}
|
||||
pub mod error;
|
||||
pub use exts::{Deserialize, Serialize};
|
||||
pub use msg::{MsgOption, MsgParcel};
|
||||
|
832
interfaces/innerkits/rust/src/parcel/msg.rs
Normal file
832
interfaces/innerkits/rust/src/parcel/msg.rs
Normal file
@ -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<MessageParcel>),
|
||||
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::<i32>().unwrap());
|
||||
/// ```
|
||||
pub fn write<T: Serialize + ?Sized>(&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<Self> {
|
||||
/// Ok(Foo { a: parcel.read()? })
|
||||
/// }
|
||||
/// }
|
||||
/// let mut msg = MsgParcel::new();
|
||||
/// msg.write(&Foo { a: 1 }).unwrap();
|
||||
/// let foo = msg.read::<Foo>().unwrap();
|
||||
/// assert_eq!(foo.a, 1);
|
||||
/// ```
|
||||
pub fn read<T: Deserialize>(&mut self) -> IpcResult<T> {
|
||||
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<String> {
|
||||
fn read_process(parcel: Pin<&mut MessageParcel>) -> IpcResult<String> {
|
||||
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<File> {
|
||||
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<Vec<u8>> {
|
||||
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<String> {
|
||||
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<Vec<String>> {
|
||||
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<RemoteObj> {
|
||||
fn read_remote_process(
|
||||
parcel: Pin<&mut MessageParcel>,
|
||||
) -> IpcResult<UniquePtr<IRemoteObjectWrapper>> {
|
||||
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::<i32>().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<T>(
|
||||
&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<T>(
|
||||
&mut self,
|
||||
f: fn(parcel: Pin<&mut MessageParcel>) -> IpcResult<T>,
|
||||
) -> IpcResult<T> {
|
||||
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<Pin<&mut MessageParcel>> {
|
||||
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<MessageOption>,
|
||||
}
|
||||
|
||||
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::<i32>();
|
||||
assert_eq!(size, msg.size());
|
||||
|
||||
msg.write(&1i16).unwrap();
|
||||
size += mem::size_of::<i32>();
|
||||
assert_eq!(size, msg.size());
|
||||
|
||||
msg.write(&1i32).unwrap();
|
||||
size += mem::size_of::<i32>();
|
||||
assert_eq!(size, msg.size());
|
||||
|
||||
msg.write(&1i64).unwrap();
|
||||
size += mem::size_of::<i64>();
|
||||
assert_eq!(size, msg.size());
|
||||
|
||||
msg.write(&1u8).unwrap();
|
||||
size += mem::size_of::<u32>();
|
||||
assert_eq!(size, msg.size());
|
||||
|
||||
msg.write(&1u16).unwrap();
|
||||
size += mem::size_of::<u32>();
|
||||
assert_eq!(size, msg.size());
|
||||
|
||||
msg.write(&1u32).unwrap();
|
||||
size += mem::size_of::<u32>();
|
||||
assert_eq!(size, msg.size());
|
||||
|
||||
msg.write(&1u64).unwrap();
|
||||
size += mem::size_of::<u64>();
|
||||
assert_eq!(size, msg.size());
|
||||
|
||||
msg.write(&true).unwrap();
|
||||
size += mem::size_of::<i32>();
|
||||
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::<bool>().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()
|
||||
);
|
||||
}
|
||||
}
|
@ -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<Self> {
|
||||
/// let i = parcel::read::<i64>(parcel);
|
||||
/// Ok(Year(i))
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Deserialize: Sized {
|
||||
/// Deserialize an instance from the given [`Parcel`].
|
||||
fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self>;
|
||||
}
|
||||
|
||||
pub const NULL_FLAG : i32 = 0;
|
||||
pub const NON_NULL_FLAG : i32 = 1;
|
||||
|
||||
/// Define trait function for Option<T> which T must implements the trait Serialize.
|
||||
pub trait SerOption: Serialize {
|
||||
/// Serialize the Option<T>
|
||||
fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<(), > {
|
||||
if let Some(inner) = this {
|
||||
parcel.write(&NON_NULL_FLAG)?;
|
||||
parcel.write(inner)
|
||||
} else {
|
||||
parcel.write(&NULL_FLAG)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Define trait function for Option<T> which T must implements the trait Deserialize.
|
||||
pub trait DeOption: Deserialize {
|
||||
/// Deserialize the Option<T>
|
||||
fn de_option(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Option<Self>> {
|
||||
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<Vec<MaybeUninit<T>>>`.
|
||||
pub unsafe extern "C" fn allocate_vec_with_buffer<T>(
|
||||
value: *mut c_void,
|
||||
buffer: *mut *mut T,
|
||||
len: i32
|
||||
) -> bool {
|
||||
let res = allocate_vec::<T>(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<Vec<MaybeUninit<T>>>);
|
||||
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<Vec<MaybeUninit<T>>>`.
|
||||
unsafe extern "C" fn allocate_vec<T>(
|
||||
value: *mut c_void,
|
||||
len: i32,
|
||||
) -> bool {
|
||||
if len < 0 {
|
||||
return false;
|
||||
}
|
||||
allocate_vec_maybeuninit::<T>(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::<Self>,
|
||||
)
|
||||
};
|
||||
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<T: Serialize>(
|
||||
parcel: *mut ipc_binding::CParcel,
|
||||
array: *const c_void,
|
||||
index: c_ulong,
|
||||
) -> bool {
|
||||
// c_ulong and usize are the same, but we need the explicitly sized version
|
||||
// so the function signature matches what bindgen generates.
|
||||
let index = index as usize;
|
||||
|
||||
let slice: &[T] = std::slice::from_raw_parts(array.cast(), index+1);
|
||||
|
||||
let mut parcel = match BorrowedMsgParcel::from_raw(parcel) {
|
||||
None => return false,
|
||||
Some(p) => p,
|
||||
};
|
||||
slice[index].serialize(&mut parcel).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<Option<Vec<Self>>> {
|
||||
let mut vec: Option<Vec<MaybeUninit<Self>>> = 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::<Self>,
|
||||
de_element::<Self>,
|
||||
)
|
||||
};
|
||||
|
||||
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<MaybeUninit<T>> to Vec<T> because MaybeUninit<T> has the same
|
||||
// alignment and size as T, so the pointer to the vector allocation
|
||||
// will be compatible.
|
||||
let vec: Option<Vec<Self>> = 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<Vec<MaybeUninit<T>>>` with at least enough elements for `index` to be valid
|
||||
/// (zero-based).
|
||||
#[allow(dead_code)]
|
||||
unsafe extern "C" fn de_element<T: Deserialize>(
|
||||
parcel: *const ipc_binding::CParcel,
|
||||
array: *mut c_void,
|
||||
index: c_ulong,
|
||||
) -> bool {
|
||||
// c_ulong and usize are the same, but we need the explicitly sized version
|
||||
// so the function signature matches what bindgen generates.
|
||||
let index = index as usize;
|
||||
|
||||
let vec = &mut *(array as *mut Option<Vec<MaybeUninit<T>>>);
|
||||
let vec = match vec {
|
||||
Some(v) => v,
|
||||
None => return false,
|
||||
};
|
||||
let parcel = match BorrowedMsgParcel::from_raw(parcel as *mut _) {
|
||||
None => return false,
|
||||
Some(p) => p,
|
||||
};
|
||||
let element = match parcel.read() {
|
||||
Ok(e) => e,
|
||||
Err(_) => 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<T>(vec: Vec<MaybeUninit<T>>) -> Vec<T> {
|
||||
// We can convert from Vec<MaybeUninit<T>> to Vec<T> because MaybeUninit<T>
|
||||
// has the same alignment and size as T, so the pointer to the vector
|
||||
// allocation will be compatible.
|
||||
let mut vec = std::mem::ManuallyDrop::new(vec);
|
||||
Vec::from_raw_parts(
|
||||
vec.as_mut_ptr().cast(),
|
||||
vec.len(),
|
||||
vec.capacity(),
|
||||
)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Ensure that the value pointer is not null
|
||||
pub(crate) unsafe fn allocate_vec_maybeuninit<T>(
|
||||
value: *mut c_void,
|
||||
len: u32,
|
||||
) {
|
||||
let vec = &mut *(value as *mut Option<Vec<MaybeUninit<T>>>);
|
||||
let mut new_vec: Vec<MaybeUninit<T>> = 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));
|
||||
}
|
@ -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
|
||||
};
|
@ -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<Self> {
|
||||
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::<bool>(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<Option<Vec<Self>>> {
|
||||
let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
|
||||
// SAFETY:
|
||||
// `parcel` always contains a valid pointer to a `CParcel`
|
||||
// `allocate_vec<T>` expects the opaque pointer to
|
||||
// be of type `*mut Option<Vec<MaybeUninit<T>>>`, so `&mut vec` is
|
||||
// correct for it.
|
||||
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<Vec<Self>> = unsafe {
|
||||
vec.map(|vec| vec_assume_init(vec))
|
||||
};
|
||||
Ok(vec)
|
||||
} else {
|
||||
Err(IpcStatusCode::Failed)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<T: Serialize> Serialize for Box<T> {
|
||||
fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
|
||||
Serialize::serialize(&(**self), parcel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Deserialize> Deserialize for Box<T> {
|
||||
fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self> {
|
||||
Deserialize::deserialize(parcel).map(Box::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SerOption> SerOption for Box<T> {
|
||||
fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
|
||||
SerOption::ser_option(this.map(|inner| &(**inner)), parcel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DeOption> DeOption for Box<T> {
|
||||
fn de_option(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Option<Self>> {
|
||||
DeOption::de_option(parcel).map(|t| t.map(Box::new))
|
||||
}
|
||||
}
|
@ -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<T: SerArray, const N: usize> Serialize for [T; N] {
|
||||
fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
|
||||
// forwards to T::serialize_array.
|
||||
SerArray::ser_array(self, parcel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SerArray, const N: usize> SerOption for [T; N] {
|
||||
fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
|
||||
SerOption::ser_option(this.map(|arr| &arr[..]), parcel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SerArray, const N: usize> SerArray for [T; N] {}
|
||||
|
||||
impl<T: DeArray, const N: usize> Deserialize for [T; N] {
|
||||
fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self> {
|
||||
let vec = DeArray::de_array(parcel)
|
||||
.transpose()
|
||||
.unwrap_or(Err(IpcStatusCode::Failed))?;
|
||||
vec.try_into().or(Err(IpcStatusCode::Failed))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DeArray, const N: usize> DeOption for [T; N] {
|
||||
fn de_option(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Option<Self>> {
|
||||
let vec = DeArray::de_array(parcel)?;
|
||||
vec.map(|v| v.try_into().or(Err(IpcStatusCode::Failed))).transpose()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DeArray, const N: usize> DeArray for [T; N] {}
|
@ -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<File> for FileDesc {
|
||||
fn as_ref(&self) -> &File {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FileDesc> 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<Option<Self>> {
|
||||
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<Self> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Self> {
|
||||
/// 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::<i8>(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<Self> {
|
||||
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<Self> {
|
||||
/// 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<Self> {
|
||||
<$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<Option<Vec<Self>>> {
|
||||
/// let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
|
||||
/// // SAFETY: `parcel` always contains a valid pointer to a `CParcel`
|
||||
/// // `allocate_vec<T>` expects the opaque pointer to
|
||||
/// // be of type `*mut Option<Vec<MaybeUninit<T>>>`, so `&mut vec` is
|
||||
/// // correct for it.
|
||||
/// 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<Vec<Self>> = 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<Option<Vec<Self>>> {
|
||||
let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
|
||||
// SAFETY: `parcel` always contains a valid pointer to a `CParcel`
|
||||
// `allocate_vec<T>` expects the opaque pointer to
|
||||
// be of type `*mut Option<Vec<MaybeUninit<T>>>`, so `&mut vec` is
|
||||
// correct for it.
|
||||
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<Vec<Self>> = 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<Option<Vec<Self>>> {
|
||||
// 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<Option<Vec<Self>>> {
|
||||
<$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;
|
||||
}
|
@ -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<Self> {
|
||||
let mut vec: Option<Vec<u8>> = 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::<u8>
|
||||
)
|
||||
};
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<T: SerOption> Serialize for Option<T> {
|
||||
fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
|
||||
SerOption::ser_option(self.as_ref(), parcel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DeOption> Deserialize for Option<T> {
|
||||
fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self> {
|
||||
DeOption::de_option(parcel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DeOption> DeArray for Option<T> {}
|
||||
impl<T: SerOption> SerArray for Option<T> {}
|
@ -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<T: Serialize + ?Sized> Serialize for &T {
|
||||
fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
|
||||
Serialize::serialize(*self, parcel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SerOption + ?Sized> SerOption for &T {
|
||||
fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<(), > {
|
||||
SerOption::ser_option(this.copied(), parcel)
|
||||
}
|
||||
}
|
@ -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<T: SerArray> Serialize for [T] {
|
||||
fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
|
||||
SerArray::ser_array(self, parcel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SerArray> 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Self> {
|
||||
let mut vec: Option<Vec<u8>> = 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::<u8>
|
||||
)
|
||||
};
|
||||
|
||||
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<Option<Vec<Self>>> {
|
||||
let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
|
||||
// SAFETY: `parcel` always contains a valid pointer to a `CParcel`
|
||||
// `allocate_vec<T>` expects the opaque pointer to
|
||||
// be of type `*mut Option<Vec<MaybeUninit<T>>>`, so `&mut vec` is
|
||||
// correct for it.
|
||||
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<Vec<Self>> = 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<std::u16string>.
|
||||
///
|
||||
/// # 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<String16>.
|
||||
///
|
||||
/// # Safety:
|
||||
///
|
||||
/// The opaque array data pointer must be a mutable pointer to an
|
||||
/// `Option<Vec<MaybeUninit<T>>>` with at least enough elements for `index` to be valid
|
||||
/// (zero-based).
|
||||
#[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<String16> capacity, data_len will set correctly by vec.push().
|
||||
unsafe { allocate_vec_maybeuninit::<String16>(value, 0) };
|
||||
let vec = &mut *(value as *mut Option<Vec<MaybeUninit<String16>>>);
|
||||
for index in 0..len {
|
||||
let mut vec_u16: Option<Vec<u16>> = 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::<u16>
|
||||
)
|
||||
};
|
||||
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()
|
||||
}
|
||||
}
|
@ -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<Self> {
|
||||
let mut vec: Option<Vec<u8>> = 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::<u8>
|
||||
)
|
||||
};
|
||||
|
||||
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<Option<Vec<Self>>> {
|
||||
let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
|
||||
// SAFETY: `parcel` always contains a valid pointer to a `CParcel`
|
||||
// `allocate_vec<T>` expects the opaque pointer to
|
||||
// be of type `*mut Option<Vec<MaybeUninit<T>>>`, so `&mut vec` is
|
||||
// correct for it.
|
||||
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<Vec<Self>> = 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<std::string>.
|
||||
///
|
||||
/// # 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<std::string>.
|
||||
///
|
||||
/// # 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<String>.
|
||||
///
|
||||
/// # Safety:
|
||||
///
|
||||
/// The opaque array data pointer must be a mutable pointer to an
|
||||
/// `Option<Vec<MaybeUninit<T>>>` with at least enough elements for `index` to be valid
|
||||
/// (zero-based).
|
||||
#[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<String> capacity, data_len will set correctly by vec.push().
|
||||
unsafe { allocate_vec_maybeuninit::<String>(value, 0) };
|
||||
let vec = &mut *(value as *mut Option<Vec<MaybeUninit<String>>>);
|
||||
for index in 0..len {
|
||||
let mut vec_u8: Option<Vec<u8>> = 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::<u8>
|
||||
)
|
||||
};
|
||||
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<Vec<u8>>) -> IpcResult<String> {
|
||||
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<Vec<u16>>) -> IpcResult<String> {
|
||||
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)
|
||||
}
|
||||
}
|
@ -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<T: SerArray> Serialize for Vec<T> {
|
||||
fn serialize(&self, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
|
||||
SerArray::ser_array(&self[..], parcel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SerArray> SerOption for Vec<T> {
|
||||
fn ser_option(this: Option<&Self>, parcel: &mut BorrowedMsgParcel<'_>) -> IpcResult<()> {
|
||||
SerOption::ser_option(this.map(Vec::as_slice), parcel)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DeArray> Deserialize for Vec<T> {
|
||||
fn deserialize(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Self> {
|
||||
DeArray::de_array(parcel)
|
||||
.transpose()
|
||||
.unwrap_or(Err(IpcStatusCode::Failed))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DeArray> DeOption for Vec<T> {
|
||||
fn de_option(parcel: &BorrowedMsgParcel<'_>) -> IpcResult<Option<Self>> {
|
||||
DeArray::de_array(parcel)
|
||||
}
|
||||
}
|
820
interfaces/innerkits/rust/src/parcel/wrapper.rs
Normal file
820
interfaces/innerkits/rust/src/parcel/wrapper.rs
Normal file
@ -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<MessageParcel>;
|
||||
fn NewMessageOption() -> UniquePtr<MessageOption>;
|
||||
|
||||
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<u8>)
|
||||
-> bool;
|
||||
|
||||
fn WriteRemoteObject(
|
||||
msgParcel: Pin<&mut MessageParcel>,
|
||||
value: UniquePtr<IRemoteObjectWrapper>,
|
||||
) -> bool;
|
||||
|
||||
fn ReadRemoteObject(msgParcel: Pin<&mut MessageParcel>) -> UniquePtr<IRemoteObjectWrapper>;
|
||||
|
||||
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>) -> bool;
|
||||
fn ReadInt8Vector(parcel: Pin<&mut Parcel>, v: &mut Vec<i8>) -> bool;
|
||||
fn ReadInt16Vector(parcel: Pin<&mut Parcel>, v: &mut Vec<i16>) -> bool;
|
||||
fn ReadInt32Vector(parcel: Pin<&mut Parcel>, v: &mut Vec<i32>) -> bool;
|
||||
fn ReadInt64Vector(parcel: Pin<&mut Parcel>, v: &mut Vec<i64>) -> bool;
|
||||
fn ReadUInt8Vector(parcel: Pin<&mut Parcel>, v: &mut Vec<u8>) -> bool;
|
||||
fn ReadUInt16Vector(parcel: Pin<&mut Parcel>, v: &mut Vec<u16>) -> bool;
|
||||
fn ReadUInt32Vector(parcel: Pin<&mut Parcel>, v: &mut Vec<u32>) -> bool;
|
||||
fn ReadUInt64Vector(parcel: Pin<&mut Parcel>, v: &mut Vec<u64>) -> bool;
|
||||
fn ReadFloatVector(parcel: Pin<&mut Parcel>, v: &mut Vec<f32>) -> bool;
|
||||
fn ReadDoubleVector(parcel: Pin<&mut Parcel>, v: &mut Vec<f64>) -> bool;
|
||||
fn ReadStringVector(parcel: Pin<&mut Parcel>, v: &mut Vec<String>) -> bool;
|
||||
fn ReadString16Vector(parcel: Pin<&mut Parcel>, v: &mut Vec<String>) -> 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<Self>;
|
||||
|
||||
fn write_process_vec(val: &[Self], parcel: Pin<&mut Parcel>) -> bool;
|
||||
|
||||
fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult<Vec<Self>>;
|
||||
}
|
||||
|
||||
impl Process for bool {
|
||||
fn write_process(&self, parcel: Pin<&mut Parcel>) -> bool {
|
||||
parcel.WriteBool(*self)
|
||||
}
|
||||
|
||||
fn read_process(parcel: Pin<&mut Parcel>) -> IpcResult<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<u64> = val.iter().map(|i| *i as u64).collect();
|
||||
WriteUInt64Vector(parcel, &v[..])
|
||||
}
|
||||
|
||||
fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<u32> = val.iter().map(|i| *i as u32).collect();
|
||||
WriteUInt32Vector(parcel, &v[..])
|
||||
}
|
||||
|
||||
fn read_process_vec(parcel: Pin<&mut Parcel>) -> IpcResult<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
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<Self> {
|
||||
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<Vec<Self>> {
|
||||
let mut v = vec![];
|
||||
match ReadStringVector(parcel, &mut v) {
|
||||
true => Ok(v),
|
||||
false => Err(IpcStatusCode::Failed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Process> Serialize for T {
|
||||
fn serialize(&self, parcel: &mut MsgParcel) -> IpcResult<()> {
|
||||
fn write<T: Process>(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<T: Process> Deserialize for T {
|
||||
fn deserialize(parcel: &mut MsgParcel) -> IpcResult<T> {
|
||||
fn read<T: Process>(parcel: Pin<&mut MessageParcel>) -> IpcResult<T> {
|
||||
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<T: Process> 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<T: Process> Deserialize for Vec<T> {
|
||||
fn deserialize(parcel: &mut MsgParcel) -> IpcResult<Self> {
|
||||
T::read_process_vec(parcel.as_parcel_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Process> Serialize for Vec<T> {
|
||||
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::<bool>().unwrap());
|
||||
|
||||
msg.write(&false).unwrap();
|
||||
assert!(!msg.read::<bool>().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::<String>().unwrap());
|
||||
|
||||
let s = String::from("hello ipc");
|
||||
msg.write(&s).unwrap();
|
||||
assert_eq!(String::from("hello ipc"), msg.read::<String>().unwrap());
|
||||
|
||||
let v = vec![1];
|
||||
msg.write(&v).unwrap();
|
||||
assert_eq!(vec![1], msg.read::<Vec<i32>>().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::<Vec<String>>().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::<bool>().unwrap());
|
||||
assert!(!msg.read::<bool>().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::<String>().unwrap());
|
||||
assert_eq!(String::from("hello ipc"), msg.read::<String>().unwrap());
|
||||
assert_eq!(vec![1], msg.read::<Vec<i32>>().unwrap());
|
||||
assert_eq!(v, msg.read::<Vec<String>>().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());
|
||||
}
|
||||
}
|
@ -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<RemoteObj>
|
||||
{
|
||||
// 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<RemoteObj>
|
||||
{
|
||||
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<Vec<MaybeUninit<T>>>`.
|
||||
pub unsafe extern "C" fn allocate_vec_with_buffer<T>(
|
||||
value: *mut c_void,
|
||||
buffer: *mut *mut T,
|
||||
len: i32,
|
||||
) -> bool {
|
||||
let res = allocate_vec::<T>(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<Vec<MaybeUninit<T>>>);
|
||||
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<Vec<MaybeUninit<T>>>`.
|
||||
unsafe extern "C" fn allocate_vec<T>(value: *mut c_void, len: i32) -> bool {
|
||||
if len < 0 {
|
||||
return false;
|
||||
}
|
||||
allocate_vec_maybeuninit::<T>(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()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<String>
|
||||
{
|
||||
let mut vec: Option<Vec<u8>> = 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::<u8>
|
||||
)
|
||||
};
|
||||
|
||||
if ok_status {
|
||||
vec_to_string(vec)
|
||||
} else {
|
||||
Err(IpcStatusCode::Failed)
|
||||
}
|
||||
}
|
||||
|
||||
/// get calling device id
|
||||
#[inline]
|
||||
pub fn get_calling_device_id() -> IpcResult<String>
|
||||
{
|
||||
let mut vec: Option<Vec<u8>> = 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::<u8>
|
||||
)
|
||||
};
|
||||
|
||||
if ok_status {
|
||||
vec_to_string(vec)
|
||||
} else {
|
||||
Err(IpcStatusCode::Failed)
|
||||
}
|
||||
}
|
||||
|
||||
/// reset calling identity
|
||||
#[inline]
|
||||
pub fn reset_calling_identity() -> IpcResult<String>
|
||||
{
|
||||
let mut vec: Option<Vec<u8>> = 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::<u8>
|
||||
)
|
||||
};
|
||||
|
||||
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()
|
||||
}
|
||||
/// # Safety
|
||||
///
|
||||
/// Ensure that the value pointer is not null
|
||||
pub(crate) unsafe fn allocate_vec_maybeuninit<T>(value: *mut c_void, len: u32) {
|
||||
let vec = &mut *(value as *mut Option<Vec<MaybeUninit<T>>>);
|
||||
let mut new_vec: Vec<MaybeUninit<T>> = 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));
|
||||
}
|
23
interfaces/innerkits/rust/src/remote/mod.rs
Normal file
23
interfaces/innerkits/rust/src/remote/mod.rs
Normal file
@ -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;
|
||||
|
179
interfaces/innerkits/rust/src/remote/obj.rs
Normal file
179
interfaces/innerkits/rust/src/remote/obj.rs
Normal file
@ -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<IRemoteObjectWrapper>,
|
||||
}
|
||||
|
||||
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<DeathRecipientRemoveHandler>,
|
||||
}
|
||||
|
||||
impl RemoteObj {
|
||||
/// Creates a Remote Object from C++ IRemoteObejectWrapper.
|
||||
pub fn try_new(wrap: UniquePtr<IRemoteObjectWrapper>) -> Option<Self> {
|
||||
if wrap.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(Self { inner: wrap })
|
||||
}
|
||||
|
||||
/// Creates a Remote Object from C++ IRemoteObejectWrapper.
|
||||
pub unsafe fn new_unchecked(wrap: UniquePtr<IRemoteObjectWrapper>) -> Self {
|
||||
Self { inner: wrap }
|
||||
}
|
||||
|
||||
pub unsafe fn from_ciremote(remote: *mut IRemoteObject) -> Option<Self> {
|
||||
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<T: RemoteStub + 'static>(stub: T) -> Option<Self> {
|
||||
RemoteStubWrapper::new(stub).into_remote()
|
||||
}
|
||||
|
||||
/// Creates a RemoteObj from sptr
|
||||
pub fn from_sptr(sptr: UniquePtr<SptrIRemoteObject>) -> Option<Self> {
|
||||
Self::try_new(FromSptrRemote(sptr))
|
||||
}
|
||||
|
||||
/// Sends a IPC request to remote service
|
||||
pub fn send_request(&self, code: u32, data: &mut MsgParcel) -> IpcResult<MsgParcel> {
|
||||
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<F, R>(
|
||||
self: &Arc<Self>,
|
||||
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<RemoteObj>)) -> Option<RecipientRemoveHandler> {
|
||||
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<String> {
|
||||
Ok(self.inner.GetInterfaceDescriptor())
|
||||
}
|
||||
|
||||
/// Returns Object descriptor.
|
||||
pub fn object_descriptor(&self) -> IpcResult<String> {
|
||||
Ok(self.inner.GetObjectDescriptor())
|
||||
}
|
||||
}
|
||||
|
||||
impl RecipientRemoveHandler {
|
||||
pub fn remove_recipient(self) {
|
||||
self.inner.remove();
|
||||
}
|
||||
}
|
66
interfaces/innerkits/rust/src/remote/stub.rs
Normal file
66
interfaces/innerkits/rust/src/remote/stub.rs
Normal file
@ -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<String>) -> 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<String>) -> 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();
|
||||
}
|
||||
}
|
140
interfaces/innerkits/rust/src/remote/wrapper.rs
Normal file
140
interfaces/innerkits/rust/src/remote/wrapper.rs
Normal file
@ -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<String>) -> i32;
|
||||
|
||||
fn descriptor(self: &mut RemoteStubWrapper) -> &'static str;
|
||||
|
||||
fn new_remote_obj(wrap: UniquePtr<IRemoteObjectWrapper>) -> Box<RemoteObj>;
|
||||
|
||||
}
|
||||
|
||||
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<SptrIRemoteObject>) -> UniquePtr<IRemoteObjectWrapper>;
|
||||
|
||||
fn FromRemoteStub(stub: Box<RemoteStubWrapper>) -> UniquePtr<IRemoteObjectWrapper>;
|
||||
|
||||
unsafe fn FromCIRemoteObject(remote: *mut IRemoteObject)
|
||||
-> UniquePtr<IRemoteObjectWrapper>;
|
||||
|
||||
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<RemoteObj>),
|
||||
) -> UniquePtr<DeathRecipientRemoveHandler>;
|
||||
|
||||
fn remove(self: &DeathRecipientRemoveHandler);
|
||||
|
||||
fn CloneRemoteObj(remote: &IRemoteObjectWrapper) -> UniquePtr<IRemoteObjectWrapper>;
|
||||
}
|
||||
impl UniquePtr<IRemoteObjectWrapper> {}
|
||||
}
|
||||
|
||||
fn new_remote_obj(wrap: UniquePtr<ffi::IRemoteObjectWrapper>) -> Box<RemoteObj> {
|
||||
Box::new(RemoteObj::try_new(wrap).unwrap())
|
||||
}
|
||||
|
||||
pub struct RemoteStubWrapper {
|
||||
inner: Box<dyn RemoteStub>,
|
||||
}
|
||||
|
||||
impl RemoteStubWrapper {
|
||||
pub fn new<A: RemoteStub + 'static>(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<String>) -> 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> {
|
||||
RemoteObj::try_new(FromRemoteStub(Box::new(self)))
|
||||
}
|
||||
}
|
159
interfaces/innerkits/rust/src/skeleton.rs
Normal file
159
interfaces/innerkits/rust/src/skeleton.rs
Normal file
@ -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<IRemoteObjectWrapper>;
|
||||
|
||||
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> {
|
||||
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)
|
||||
}
|
||||
}
|
62
interfaces/innerkits/rust/tests/BUILD.gn
Normal file
62
interfaces/innerkits/rust/tests/BUILD.gn
Normal file
@ -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",
|
||||
]
|
||||
}
|
34
interfaces/innerkits/rust/tests/c/BUILD.gn
Normal file
34
interfaces/innerkits/rust/tests/c/BUILD.gn
Normal file
@ -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"
|
||||
}
|
68
interfaces/innerkits/rust/tests/c/include/ipc_rust_test.h
Normal file
68
interfaces/innerkits/rust/tests/c/include/ipc_rust_test.h
Normal file
@ -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 <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#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<std::u16string> &args) override;
|
||||
};
|
||||
|
||||
} // namespace OHOS
|
||||
|
||||
#endif
|
227
interfaces/innerkits/rust/tests/c/src/ipc_rust_test.cpp
Normal file
227
interfaces/innerkits/rust/tests/c/src/ipc_rust_test.cpp
Normal file
@ -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 <climits>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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<typename T> void WriteTestVector(Parcel *parcel, T testValue, bool (Parcel::*Write)(const std::vector<T> &))
|
||||
{
|
||||
std::vector<T> 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<uint8_t>(parcel, UCHAR_MAX, &Parcel::WriteUInt8Vector);
|
||||
WriteTestVector<uint16_t>(parcel, USHRT_MAX, &Parcel::WriteUInt16Vector);
|
||||
WriteTestVector<uint32_t>(parcel, UINT_MAX, &Parcel::WriteUInt32Vector);
|
||||
WriteTestVector<uint64_t>(parcel, ULLONG_MAX, &Parcel::WriteUInt64Vector);
|
||||
|
||||
WriteTestVector<int8_t>(parcel, SCHAR_MAX, &Parcel::WriteInt8Vector);
|
||||
WriteTestVector<int16_t>(parcel, SHRT_MAX, &Parcel::WriteInt16Vector);
|
||||
WriteTestVector<int32_t>(parcel, INT_MAX, &Parcel::WriteInt32Vector);
|
||||
WriteTestVector<int64_t>(parcel, LLONG_MAX, &Parcel::WriteInt64Vector);
|
||||
|
||||
WriteTestVector<int8_t>(parcel, SCHAR_MIN, &Parcel::WriteInt8Vector);
|
||||
WriteTestVector<int16_t>(parcel, SHRT_MIN, &Parcel::WriteInt16Vector);
|
||||
WriteTestVector<int32_t>(parcel, INT_MIN, &Parcel::WriteInt32Vector);
|
||||
WriteTestVector<int64_t>(parcel, LLONG_MIN, &Parcel::WriteInt64Vector);
|
||||
|
||||
WriteTestVector<float>(parcel, TEST_FLOAT, &Parcel::WriteFloatVector);
|
||||
WriteTestVector<double>(parcel, TEST_DOUBLE, &Parcel::WriteDoubleVector);
|
||||
|
||||
WriteTestVector<std::string>(parcel, "TEST", &Parcel::WriteStringVector);
|
||||
WriteTestVector<std::u16string>(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<typename T>
|
||||
void ReadAndWriteV(MessageParcel *parcel, MessageParcel &data, bool (Parcel::*Write)(const std::vector<T> &),
|
||||
bool (Parcel::*Read)(std::vector<T> *))
|
||||
{
|
||||
std::vector<T> 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
|
12
interfaces/innerkits/rust/tests/c_mem.rs
Normal file
12
interfaces/innerkits/rust/tests/c_mem.rs
Normal file
@ -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.
|
59
interfaces/innerkits/rust/tests/entry.rs
Normal file
59
interfaces/innerkits/rust/tests/entry.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
142
interfaces/innerkits/rust/tests/interactive.rs
Normal file
142
interfaces/innerkits/rust/tests/interactive.rs
Normal file
@ -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::<bool>().unwrap());
|
||||
assert_eq!(msg.read::<u8>().unwrap(), u8::MAX);
|
||||
assert_eq!(msg.read::<u16>().unwrap(), u16::MAX);
|
||||
assert_eq!(msg.read::<u32>().unwrap(), u32::MAX);
|
||||
assert_eq!(msg.read::<u64>().unwrap(), u64::MAX);
|
||||
|
||||
assert_eq!(msg.read::<i8>().unwrap(), i8::MAX);
|
||||
assert_eq!(msg.read::<i16>().unwrap(), i16::MAX);
|
||||
assert_eq!(msg.read::<i32>().unwrap(), i32::MAX);
|
||||
assert_eq!(msg.read::<i64>().unwrap(), i64::MAX);
|
||||
|
||||
assert_eq!(msg.read::<i8>().unwrap(), i8::MIN);
|
||||
assert_eq!(msg.read::<i16>().unwrap(), i16::MIN);
|
||||
assert_eq!(msg.read::<i32>().unwrap(), i32::MIN);
|
||||
assert_eq!(msg.read::<i64>().unwrap(), i64::MIN);
|
||||
|
||||
assert_eq!(msg.read::<f32>().unwrap(), 7.02);
|
||||
assert_eq!(msg.read::<f64>().unwrap(), 7.03);
|
||||
|
||||
assert_eq!(msg.read::<Vec<bool>>().unwrap(), vec![true; 3]);
|
||||
|
||||
assert_eq!(msg.read::<Vec<u8>>().unwrap(), vec![u8::MAX; 3]);
|
||||
assert_eq!(msg.read::<Vec<u16>>().unwrap(), vec![u16::MAX; 3]);
|
||||
assert_eq!(msg.read::<Vec<u32>>().unwrap(), vec![u32::MAX; 3]);
|
||||
assert_eq!(msg.read::<Vec<u64>>().unwrap(), vec![u64::MAX; 3]);
|
||||
|
||||
assert_eq!(msg.read::<Vec<i8>>().unwrap(), vec![i8::MAX; 3]);
|
||||
assert_eq!(msg.read::<Vec<i16>>().unwrap(), vec![i16::MAX; 3]);
|
||||
assert_eq!(msg.read::<Vec<i32>>().unwrap(), vec![i32::MAX; 3]);
|
||||
assert_eq!(msg.read::<Vec<i64>>().unwrap(), vec![i64::MAX; 3]);
|
||||
|
||||
assert_eq!(msg.read::<Vec<i8>>().unwrap(), vec![i8::MIN; 3]);
|
||||
assert_eq!(msg.read::<Vec<i16>>().unwrap(), vec![i16::MIN; 3]);
|
||||
assert_eq!(msg.read::<Vec<i32>>().unwrap(), vec![i32::MIN; 3]);
|
||||
assert_eq!(msg.read::<Vec<i64>>().unwrap(), vec![i64::MIN; 3]);
|
||||
|
||||
assert_eq!(msg.read::<Vec<f32>>().unwrap(), vec![TEST_FLOAT; 3]);
|
||||
assert_eq!(msg.read::<Vec<f64>>().unwrap(), vec![TEST_DOUBLE; 3]);
|
||||
|
||||
assert_eq!(
|
||||
msg.read::<Vec<String>>().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;
|
||||
}
|
285
interfaces/innerkits/rust/tests/parcel_remote.rs
Normal file
285
interfaces/innerkits/rust/tests/parcel_remote.rs
Normal file
@ -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::<i32>().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::<bool>().unwrap());
|
||||
reply.write(&data.read::<bool>().unwrap());
|
||||
reply.write(&data.read::<i8>().unwrap());
|
||||
reply.write(&data.read::<i8>().unwrap());
|
||||
reply.write(&data.read::<i16>().unwrap());
|
||||
reply.write(&data.read::<i16>().unwrap());
|
||||
reply.write(&data.read::<i32>().unwrap());
|
||||
reply.write(&data.read::<i32>().unwrap());
|
||||
reply.write(&data.read::<i64>().unwrap());
|
||||
reply.write(&data.read::<i64>().unwrap());
|
||||
|
||||
reply.write(&data.read::<u8>().unwrap());
|
||||
reply.write(&data.read::<u8>().unwrap());
|
||||
reply.write(&data.read::<u16>().unwrap());
|
||||
reply.write(&data.read::<u16>().unwrap());
|
||||
reply.write(&data.read::<u32>().unwrap());
|
||||
reply.write(&data.read::<u32>().unwrap());
|
||||
reply.write(&data.read::<u64>().unwrap());
|
||||
reply.write(&data.read::<u64>().unwrap());
|
||||
|
||||
reply.write(&data.read::<usize>().unwrap());
|
||||
reply.write(&data.read::<usize>().unwrap());
|
||||
|
||||
reply.write(&data.read::<Vec<bool>>().unwrap());
|
||||
reply.write(&data.read::<Vec<i8>>().unwrap());
|
||||
reply.write(&data.read::<Vec<i16>>().unwrap());
|
||||
reply.write(&data.read::<Vec<i32>>().unwrap());
|
||||
reply.write(&data.read::<Vec<i64>>().unwrap());
|
||||
|
||||
reply.write(&data.read::<Vec<i8>>().unwrap());
|
||||
reply.write(&data.read::<Vec<i16>>().unwrap());
|
||||
reply.write(&data.read::<Vec<i32>>().unwrap());
|
||||
reply.write(&data.read::<Vec<i64>>().unwrap());
|
||||
|
||||
reply.write(&data.read::<Vec<u8>>().unwrap());
|
||||
reply.write(&data.read::<Vec<u16>>().unwrap());
|
||||
reply.write(&data.read::<Vec<u32>>().unwrap());
|
||||
reply.write(&data.read::<Vec<u64>>().unwrap());
|
||||
|
||||
reply.write(&data.read::<Vec<u8>>().unwrap());
|
||||
reply.write(&data.read::<Vec<u16>>().unwrap());
|
||||
reply.write(&data.read::<Vec<u32>>().unwrap());
|
||||
reply.write(&data.read::<Vec<u64>>().unwrap());
|
||||
|
||||
reply.write(&data.read::<Vec<f32>>().unwrap());
|
||||
reply.write(&data.read::<Vec<f64>>().unwrap());
|
||||
|
||||
reply.write(&data.read::<String>().unwrap());
|
||||
reply.write(&data.read::<String>().unwrap());
|
||||
reply.write(&data.read::<Vec<String>>().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::<bool>().unwrap());
|
||||
assert!(!reply.read::<bool>().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::<Vec<bool>>().unwrap(), vec![true; 3]);
|
||||
assert_eq!(reply.read::<Vec<i8>>().unwrap(), vec![i8::MIN; 3]);
|
||||
assert_eq!(reply.read::<Vec<i16>>().unwrap(), vec![i16::MIN; 3]);
|
||||
assert_eq!(reply.read::<Vec<i32>>().unwrap(), vec![i32::MIN; 3]);
|
||||
assert_eq!(reply.read::<Vec<i64>>().unwrap(), vec![i64::MIN; 3]);
|
||||
|
||||
assert_eq!(reply.read::<Vec<i8>>().unwrap(), vec![i8::MAX; 3]);
|
||||
assert_eq!(reply.read::<Vec<i16>>().unwrap(), vec![i16::MAX; 3]);
|
||||
assert_eq!(reply.read::<Vec<i32>>().unwrap(), vec![i32::MAX; 3]);
|
||||
assert_eq!(reply.read::<Vec<i64>>().unwrap(), vec![i64::MAX; 3]);
|
||||
|
||||
assert_eq!(reply.read::<Vec<u8>>().unwrap(), vec![u8::MIN; 3]);
|
||||
assert_eq!(reply.read::<Vec<u16>>().unwrap(), vec![u16::MIN; 3]);
|
||||
assert_eq!(reply.read::<Vec<u32>>().unwrap(), vec![u32::MIN; 3]);
|
||||
assert_eq!(reply.read::<Vec<u64>>().unwrap(), vec![u64::MIN; 3]);
|
||||
|
||||
assert_eq!(reply.read::<Vec<u8>>().unwrap(), vec![u8::MAX; 3]);
|
||||
assert_eq!(reply.read::<Vec<u16>>().unwrap(), vec![u16::MAX; 3]);
|
||||
assert_eq!(reply.read::<Vec<u32>>().unwrap(), vec![u32::MAX; 3]);
|
||||
assert_eq!(reply.read::<Vec<u64>>().unwrap(), vec![u64::MAX; 3]);
|
||||
|
||||
assert_eq!(reply.read::<Vec<f32>>().unwrap(), vec![TEST_FLOAT; 3]);
|
||||
assert_eq!(reply.read::<Vec<f64>>().unwrap(), vec![TEST_DOUBLE; 3]);
|
||||
|
||||
assert_eq!(String::from("hello ipc"), reply.read::<String>().unwrap());
|
||||
assert_eq!(String::from("hello ipc"), reply.read::<String>().unwrap());
|
||||
assert_eq!(v, reply.read::<Vec<String>>().unwrap());
|
||||
assert_eq!(String::from("ipc hello"), reply.read_string16().unwrap());
|
||||
assert_eq!(v, reply.read_string16_vec().unwrap());
|
||||
}
|
87
interfaces/innerkits/rust/tests/remote.rs
Normal file
87
interfaces/innerkits/rust/tests/remote.rs
Normal file
@ -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::<i32>().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() {}
|
132
interfaces/innerkits/rust/tests/skeleton.rs
Normal file
132
interfaces/innerkits/rust/tests/skeleton.rs
Normal file
@ -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::<i32>().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::<String>().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::<i32>().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;
|
||||
}
|
@ -87,7 +87,7 @@ async fn get_async_test_service<T: FromRemoteObj + ?Sized + 'static>(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),
|
||||
|
19
rustfmt.toml
Normal file
19
rustfmt.toml
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user