ipc_rust 接口重构

Signed-off-by: fqwert <yanglv2@huawei.com>
Change-Id: Ib233f76fcc35feb72f006bfd8b203ab3509318c0
This commit is contained in:
fqwert 2024-04-08 11:29:43 +08:00
parent 9d0c8cea51
commit 640b345c1e
61 changed files with 4760 additions and 4117 deletions

4
.gitignore vendored
View File

@ -12,4 +12,6 @@
# limitations under the License.
target
Cargo.lock
Cargo.lock
.clang-format
.vscode

View File

@ -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"

View File

@ -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

View File

@ -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"

View 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

View 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

View 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

View File

@ -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)
}
}
}
}
}
}

View 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

View 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

View 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

View 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,
};

View File

@ -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"),
}
}
}
}

View 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));
}}
}

View File

@ -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;
}
)?
};
}

View File

@ -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> {}

View File

@ -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());
}
}
}

View File

@ -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 {}

View File

@ -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);
}
}
}

View File

@ -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));
}
}

View File

@ -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)
}
}

View File

@ -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()
}
}

View File

@ -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;
}

View File

@ -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",
};

View 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 {}

View 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());
}
}

View File

@ -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};

View 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()
);
}
}

View File

@ -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));
}

View File

@ -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
};

View File

@ -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)
}
}
}

View File

@ -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))
}
}

View File

@ -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] {}

View File

@ -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)
}
}
}

View File

@ -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;
}

View File

@ -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)
}
}
}

View File

@ -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> {}

View File

@ -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)
}
}

View File

@ -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)
}
}
}

View File

@ -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()
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View 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());
}
}

View File

@ -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()
}
/// # 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));
}
/// 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()
}
}

View 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;

View 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();
}
}

View 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();
}
}

View 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)))
}
}

View 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)
}
}

View 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",
]
}

View 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"
}

View 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

View 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

View 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.

View 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);
}
}

View 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;
}

View 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());
}

View 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() {}

View 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;
}

View File

@ -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
View 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