Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
communication_ipc
提交
a92c8c65
C
communication_ipc
项目概览
OpenHarmony
/
communication_ipc
大约 1 年 前同步成功
通知
20
Star
3
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
communication_ipc
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
a92c8c65
编写于
12月 30, 2021
作者:
O
openharmony_ci
提交者:
Gitee
12月 30, 2021
浏览文件
操作
浏览文件
下载
差异文件
!62 RPC支持本设备收发及死亡通知
Merge pull request !62 from liubb_0516/ipc_dev
上级
dfb2308b
6266c469
变更
24
显示空白变更内容
内联
并排
Showing
24 changed file
with
2823 addition
and
0 deletion
+2823
-0
interfaces/innerkits/c/ipc/BUILD.gn
interfaces/innerkits/c/ipc/BUILD.gn
+119
-0
interfaces/innerkits/c/ipc/include/ipc_skeleton.h
interfaces/innerkits/c/ipc/include/ipc_skeleton.h
+74
-0
interfaces/innerkits/c/ipc/include/serializer.h
interfaces/innerkits/c/ipc/include/serializer.h
+63
-0
ipc/native/c/adapter/BUILD.gn
ipc/native/c/adapter/BUILD.gn
+32
-0
ipc/native/c/adapter/Linux/rpc_os_adapter.c
ipc/native/c/adapter/Linux/rpc_os_adapter.c
+27
-0
ipc/native/c/adapter/Liteos_m/rpc_os_adapter.c
ipc/native/c/adapter/Liteos_m/rpc_os_adapter.c
+26
-0
ipc/native/c/adapter/include/rpc_os_adapter.h
ipc/native/c/adapter/include/rpc_os_adapter.h
+35
-0
ipc/native/c/ipc/include/binder_invoker.h
ipc/native/c/ipc/include/binder_invoker.h
+45
-0
ipc/native/c/ipc/include/binder_types.h
ipc/native/c/ipc/include/binder_types.h
+24
-0
ipc/native/c/ipc/include/sys_binder.h
ipc/native/c/ipc/include/sys_binder.h
+237
-0
ipc/native/c/ipc/src/binder_invoker.c
ipc/native/c/ipc/src/binder_invoker.c
+555
-0
ipc/native/c/ipc/src/binder_invoker_virtual.c
ipc/native/c/ipc/src/binder_invoker_virtual.c
+21
-0
ipc/native/c/manager/include/ipc_process_skeleton.h
ipc/native/c/manager/include/ipc_process_skeleton.h
+81
-0
ipc/native/c/manager/include/ipc_thread_pool.h
ipc/native/c/manager/include/ipc_thread_pool.h
+76
-0
ipc/native/c/manager/include/iremote_invoker.h
ipc/native/c/manager/include/iremote_invoker.h
+51
-0
ipc/native/c/manager/include/rpc_errno.h
ipc/native/c/manager/include/rpc_errno.h
+34
-0
ipc/native/c/manager/include/rpc_log.h
ipc/native/c/manager/include/rpc_log.h
+117
-0
ipc/native/c/manager/include/rpc_types.h
ipc/native/c/manager/include/rpc_types.h
+58
-0
ipc/native/c/manager/src/ipc_process_skeleton.c
ipc/native/c/manager/src/ipc_process_skeleton.c
+420
-0
ipc/native/c/manager/src/ipc_skeleton.c
ipc/native/c/manager/src/ipc_skeleton.c
+135
-0
ipc/native/c/manager/src/ipc_thread_pool.c
ipc/native/c/manager/src/ipc_thread_pool.c
+203
-0
ipc/native/c/manager/src/iremote_invoker.c
ipc/native/c/manager/src/iremote_invoker.c
+28
-0
ipc/native/c/manager/src/rpc_log.c
ipc/native/c/manager/src/rpc_log.c
+88
-0
ipc/native/c/manager/src/serializer.c
ipc/native/c/manager/src/serializer.c
+274
-0
未找到文件。
interfaces/innerkits/c/ipc/BUILD.gn
0 → 100644
浏览文件 @
a92c8c65
# Copyright (c) 2021 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/lite/config/component/lite_component.gni")
SUBSYSTEM_DIR = "//foundation/communication/ipc"
IPC_CORE_ROOT = "$SUBSYSTEM_DIR/ipc/native/c"
config("ipc_rpc_interface") {
include_dirs = [ "$SUBSYSTEM_DIR/interfaces/innerkits/c/ipc/include" ]
}
if (ohos_kernel_type == "liteos_m") {
hilog_lite_include_path =
"//base/hiviewdfx/hilog_lite/interfaces/native/kits/hilog_lite"
} else {
hilog_lite_include_path =
"//base/hiviewdfx/hilog_lite/interfaces/native/innerkits"
}
ipc_common_include = [
"$IPC_CORE_ROOT/ipc/include",
"$IPC_CORE_ROOT/manager/include",
"//third_party/bounds_checking_function/include",
"//utils/native/lite/include",
"$hilog_lite_include_path",
]
ipc_common_src = [
"$IPC_CORE_ROOT/manager/src/ipc_process_skeleton.c",
"$IPC_CORE_ROOT/manager/src/ipc_skeleton.c",
"$IPC_CORE_ROOT/manager/src/ipc_thread_pool.c",
"$IPC_CORE_ROOT/manager/src/iremote_invoker.c",
"$IPC_CORE_ROOT/manager/src/serializer.c",
]
if (ohos_kernel_type == "liteos_m") {
static_library("ipc_single") {
sources = ipc_common_src
sources += [
"$IPC_CORE_ROOT/ipc/src/binder_invoker_virtual.c",
"$IPC_CORE_ROOT/manager/src/rpc_log.c",
]
include_dirs = ipc_common_include
public_configs = [ ":ipc_rpc_interface" ]
deps = [ "//foundation/communication/ipc/ipc/native/c/adapter:rpc_adapter" ]
}
} else if (ohos_kernel_type == "liteos_a") {
shared_library("rpc_log") {
sources = [ "$IPC_CORE_ROOT/manager/src/rpc_log.c" ]
include_dirs = [
"$IPC_CORE_ROOT/manager/include",
"$hilog_lite_include_path",
]
public_deps = [
"//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
"//third_party/bounds_checking_function/:libsec_shared",
]
}
shared_library("ipc_single") {
sources = ipc_common_src
sources += [ "$IPC_CORE_ROOT/ipc/src/binder_invoker_virtual.c" ]
public_configs = [ ":ipc_rpc_interface" ]
include_dirs = ipc_common_include
ldflags = [
"-lstdc++",
"-lpthread",
]
cflags = [ "-fPIC" ]
cflags_cc = cflags
public_deps = [
":rpc_log",
"//foundation/communication/ipc/ipc/native/c/adapter:rpc_adapter",
"//third_party/bounds_checking_function/:libsec_shared",
]
}
} else {
shared_library("rpc_log") {
sources = [ "$IPC_CORE_ROOT/manager/src/rpc_log.c" ]
include_dirs = [
"$IPC_CORE_ROOT/manager/include",
"$hilog_lite_include_path",
]
public_deps = [
"//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
"//third_party/bounds_checking_function/:libsec_shared",
]
}
shared_library("ipc_single") {
sources = ipc_common_src
sources += [ "$IPC_CORE_ROOT/ipc/src/binder_invoker.c" ]
public_configs = [ ":ipc_rpc_interface" ]
include_dirs = ipc_common_include
ldflags = [
"-lstdc++",
"-lpthread",
]
cflags = [ "-fPIC" ]
cflags_cc = cflags
public_deps = [
":rpc_log",
"//foundation/communication/ipc/ipc/native/c/adapter:rpc_adapter",
"//third_party/bounds_checking_function/:libsec_shared",
]
configs -= [ "//build/lite/config:clang_opt" ]
}
}
interfaces/innerkits/c/ipc/include/ipc_skeleton.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 OHOS_IPC_RPC_SKELETON_H
#define OHOS_IPC_RPC_SKELETON_H
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
#include "serializer.h"
#ifdef __cplusplus
#if __cplusplus
extern
"C"
{
#endif
#endif
/* __cplusplus */
typedef
enum
{
TF_OP_SYNC
=
0x00
,
TF_OP_ASYNC
=
0x01
,
TF_OP_STATUS_CODE
=
0x08
,
TF_OP_ACCEPT_FDS
=
0x10
,
}
MessageOption
;
typedef
int32_t
(
*
OnRemoteRequest
)(
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
);
typedef
void
(
*
OnRemoteDead
)(
void
*
args
);
typedef
struct
{
OnRemoteRequest
func
;
bool
isRemote
;
}
IpcObjectStub
;
// default is 4
int32_t
SetMaxWorkThreadNum
(
int32_t
maxThreadNum
);
// join current thread into work loop.
void
JoinWorkThread
(
void
);
pid_t
GetCallingPid
(
void
);
pid_t
GetCallingUid
(
void
);
const
SvcIdentity
*
GetContextObject
(
void
);
int32_t
SetContextObject
(
SvcIdentity
target
);
int32_t
SendRequest
(
SvcIdentity
target
,
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
,
uintptr_t
*
buffer
);
int32_t
FreeBuffer
(
void
*
ptr
);
int32_t
AddDeathRecipient
(
SvcIdentity
target
,
OnRemoteDead
deathFunc
,
void
*
args
,
uint32_t
*
cbId
);
int32_t
RemoveDeathRecipient
(
SvcIdentity
target
,
uint32_t
cbId
);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/* __cplusplus */
#endif
/* OHOS_IPC_RPC_SKELETON_H */
interfaces/innerkits/c/ipc/include/serializer.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (c) 2021 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 OHOS_IPC_RPC_SERIALIZER_H
#define OHOS_IPC_RPC_SERIALIZER_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
#if __cplusplus
extern
"C"
{
#endif
/* __cplusplus */
#endif
/* __cplusplus */
typedef
struct
{
char
*
bufferBase
;
size_t
*
offsetsBase
;
char
*
bufferCur
;
size_t
*
offsetsCur
;
size_t
bufferLeft
;
size_t
offsetsLeft
;
uint32_t
flag
;
}
IpcIo
;
typedef
struct
{
int32_t
handle
;
uintptr_t
token
;
uintptr_t
cookie
;
}
SvcIdentity
;
#define MIN_BINDER_HANDLE (-1)
#define IPC_IO_INITIALIZED 0x01
/* ipc flag indicates whether io is initialized */
#define IPC_IO_OVERFLOW 0x02
/* ipc flag indicates whether io is running out of space */
void
IpcIoInit
(
IpcIo
*
io
,
void
*
buffer
,
size_t
bufferSize
,
size_t
maxobjects
);
bool
WriteRemoteObject
(
IpcIo
*
io
,
const
SvcIdentity
*
svc
);
bool
WriteFileDescriptor
(
IpcIo
*
io
,
uint32_t
fd
);
bool
ReadRemoteObject
(
IpcIo
*
io
,
SvcIdentity
*
svc
);
int32_t
ReadFileDescriptor
(
IpcIo
*
io
);
#ifdef __cplusplus
#if __cplusplus
}
#endif
/* __cplusplus */
#endif
/* __cplusplus */
#endif
/* OHOS_IPC_RPC_SERIALIZER_H */
ipc/native/c/adapter/BUILD.gn
0 → 100644
浏览文件 @
a92c8c65
# Copyright (c) 2021 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.
config("rpc_adapter_interface") {
include_dirs = [ "include" ]
}
if (ohos_kernel_type == "liteos_m") {
static_library("rpc_adapter") {
sources = [ "Liteos_m/rpc_os_adapter.c" ]
public_configs = [ ":rpc_adapter_interface" ]
}
} else {
shared_library("rpc_adapter") {
sources = [ "Linux/rpc_os_adapter.c" ]
public_configs = [ ":rpc_adapter_interface" ]
ldflags = [
"-lstdc++",
"-fPIC",
]
}
}
ipc/native/c/adapter/Linux/rpc_os_adapter.c
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 <unistd.h>
#include "rpc_os_adapter.h"
int32_t
RpcGetPid
(
void
)
{
return
(
int32_t
)
getpid
();
}
int32_t
RpcGetUid
()
{
return
(
int32_t
)
getuid
();
}
\ No newline at end of file
ipc/native/c/adapter/Liteos_m/rpc_os_adapter.c
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 "rpc_os_adapter.h"
int32_t
RpcGetPid
(
void
)
{
return
0
;
}
int32_t
RpcGetUid
(
void
)
{
return
0
;
}
\ No newline at end of file
ipc/native/c/adapter/include/rpc_os_adapter.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 OHOS_IPC_RPC_OS_ADAPTER_H
#define OHOS_IPC_RPC_OS_ADAPTER_H
#include <stdint.h>
#ifdef __cplusplus
#if __cplusplus
extern
"C"
{
#endif
#endif
/* __cplusplus */
int32_t
RpcGetPid
(
void
);
int32_t
RpcGetUid
(
void
);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/* __cplusplus */
#endif
/* OHOS_IPC_RPC_OS_ADAPTER_H */
ipc/native/c/ipc/include/binder_invoker.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (c) 2021 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 OHOS_IPC_INVOKER_H
#define OHOS_IPC_INVOKER_H
#include "iremote_invoker.h"
#ifdef __cplusplus
#if __cplusplus
extern
"C"
{
#endif
#endif
/* __cplusplus */
RemoteInvoker
*
GetIpcInvoker
(
void
);
int32_t
AcquireHandle
(
int32_t
handle
);
int32_t
ReleaseHandle
(
int32_t
handle
);
int32_t
IpcSendRequest
(
SvcIdentity
target
,
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
,
uintptr_t
*
buffer
);
int32_t
IpcFreeBuffer
(
void
*
ptr
);
int32_t
IpcSetMaxWorkThread
(
int32_t
maxThreadNum
);
void
IpcJoinThread
(
bool
initiative
);
int32_t
IpcSetRegistryObject
(
void
);
int32_t
IpcAddDeathRecipient
(
int32_t
handle
,
void
*
cookie
);
int32_t
IpcRemoveDeathRecipient
(
int32_t
handle
,
void
*
cookie
);
void
IpcExitCurrentThread
(
void
);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/* __cplusplus */
#endif
/* OHOS_IPC_INVOKER_H */
\ No newline at end of file
ipc/native/c/ipc/include/binder_types.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (c) 2021 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 OHOS_BINDER_TYPES_H
#define OHOS_BINDER_TYPES_H
#define BINDER_DRIVER "/dev/binder"
#define MMAP_MAX_SIZE 262144UL
/* 256KB */
#define IPC_IO_DATA_MAX 8192UL
#define MAX_OBJECT_NUM 4
#endif
/* OHOS_BINDER_TYPES_H */
\ No newline at end of file
ipc/native/c/ipc/include/sys_binder.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (c) 2021 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 _UAPI_LINUX_BINDER_H
#define _UAPI_LINUX_BINDER_H
#include <stdint.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#define B_PACK_CHARS(c1, c2, c3, c4) ((((c1) << 24)) | (((c2) << 16)) | (((c3) << 8)) | (c4))
#define B_TYPE_LARGE 0x85
#define BINDER_IPC_32BIT
enum
{
BINDER_TYPE_BINDER
=
B_PACK_CHARS
(
's'
,
'b'
,
'*'
,
B_TYPE_LARGE
),
BINDER_TYPE_REMOTE_BINDER
=
B_PACK_CHARS
(
'r'
,
'b'
,
'*'
,
B_TYPE_LARGE
),
BINDER_TYPE_WEAK_BINDER
=
B_PACK_CHARS
(
'w'
,
'b'
,
'*'
,
B_TYPE_LARGE
),
BINDER_TYPE_HANDLE
=
B_PACK_CHARS
(
's'
,
'h'
,
'*'
,
B_TYPE_LARGE
),
BINDER_TYPE_REMOTE_HANDLE
=
B_PACK_CHARS
(
'r'
,
'h'
,
'*'
,
B_TYPE_LARGE
),
BINDER_TYPE_WEAK_HANDLE
=
B_PACK_CHARS
(
'w'
,
'h'
,
'*'
,
B_TYPE_LARGE
),
BINDER_TYPE_FD
=
B_PACK_CHARS
(
'f'
,
'd'
,
'*'
,
B_TYPE_LARGE
),
BINDER_TYPE_FDA
=
B_PACK_CHARS
(
'f'
,
'd'
,
'a'
,
B_TYPE_LARGE
),
BINDER_TYPE_PTR
=
B_PACK_CHARS
(
'p'
,
't'
,
'*'
,
B_TYPE_LARGE
),
};
enum
{
FLAT_BINDER_FLAG_PRIORITY_MASK
=
0xff
,
FLAT_BINDER_FLAG_ACCEPTS_FDS
=
0x100
,
};
#ifdef BINDER_IPC_32BIT
typedef
__u32
binder_size_t
;
typedef
__u32
binder_uintptr_t
;
#else
typedef
__u64
binder_size_t
;
typedef
__u64
binder_uintptr_t
;
#endif
struct
binder_object_header
{
__u32
type
;
};
struct
flat_binder_object
{
__u32
type
;
__u32
flags
;
union
{
binder_uintptr_t
binder
;
__u32
handle
;
};
binder_uintptr_t
cookie
;
};
struct
binder_fd_object
{
struct
binder_object_header
hdr
;
__u32
pad_flags
;
union
{
binder_uintptr_t
pad_binder
;
__u32
fd
;
};
binder_uintptr_t
cookie
;
};
struct
binder_buffer_object
{
struct
binder_object_header
hdr
;
__u32
flags
;
binder_uintptr_t
buffer
;
binder_size_t
length
;
binder_size_t
parent
;
binder_size_t
parent_offset
;
};
enum
{
BINDER_BUFFER_FLAG_HAS_PARENT
=
0x01
,
};
struct
binder_fd_array_object
{
struct
binder_object_header
hdr
;
__u32
pad
;
binder_size_t
num_fds
;
binder_size_t
parent
;
binder_size_t
parent_offset
;
};
struct
binder_write_read
{
binder_size_t
write_size
;
binder_size_t
write_consumed
;
binder_uintptr_t
write_buffer
;
binder_size_t
read_size
;
binder_size_t
read_consumed
;
binder_uintptr_t
read_buffer
;
};
struct
binder_version
{
__s32
protocol_version
;
};
#ifdef BINDER_IPC_32BIT
#define BINDER_CURRENT_PROTOCOL_VERSION 7
#else
#define BINDER_CURRENT_PROTOCOL_VERSION 8
#endif
struct
binder_node_debug_info
{
binder_uintptr_t
ptr
;
binder_uintptr_t
cookie
;
__u32
has_strong_ref
;
__u32
has_weak_ref
;
};
struct
binder_ptr_count
{
binder_uintptr_t
ptr
;
uint32_t
count
;
};
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info)
#define BINDER_GET_NODE_REFCOUNT _IOWR('b', 17, struct binder_ptr_count)
enum
transaction_flags
{
TF_ONE_WAY
=
0x01
,
TF_ROOT_OBJECT
=
0x04
,
TF_STATUS_CODE
=
0x08
,
TF_ACCEPT_FDS
=
0x10
,
};
struct
binder_transaction_data
{
union
{
__u32
handle
;
binder_uintptr_t
ptr
;
}
target
;
binder_uintptr_t
cookie
;
__u32
code
;
__u32
flags
;
pid_t
sender_pid
;
uid_t
sender_euid
;
binder_size_t
data_size
;
binder_size_t
offsets_size
;
union
{
struct
{
binder_uintptr_t
buffer
;
binder_uintptr_t
offsets
;
}
ptr
;
__u8
buf
[
8
];
}
data
;
};
struct
binder_transaction_data_sg
{
struct
binder_transaction_data
transaction_data
;
binder_size_t
buffers_size
;
};
struct
binder_ptr_cookie
{
binder_uintptr_t
ptr
;
binder_uintptr_t
cookie
;
};
struct
binder_handle_cookie
{
__u32
handle
;
binder_uintptr_t
cookie
;
}
__attribute__
((
__packed__
));
struct
binder_pri_desc
{
__s32
priority
;
__u32
desc
;
};
struct
binder_pri_ptr_cookie
{
__s32
priority
;
binder_uintptr_t
ptr
;
binder_uintptr_t
cookie
;
};
enum
binder_driver_return_protocol
{
BR_ERROR
=
_IOR
(
'r'
,
0
,
__s32
),
BR_OK
=
_IO
(
'r'
,
1
),
BR_TRANSACTION
=
_IOR
(
'r'
,
2
,
struct
binder_transaction_data
),
BR_REPLY
=
_IOR
(
'r'
,
3
,
struct
binder_transaction_data
),
BR_ACQUIRE_RESULT
=
_IOR
(
'r'
,
4
,
__s32
),
BR_DEAD_REPLY
=
_IO
(
'r'
,
5
),
BR_TRANSACTION_COMPLETE
=
_IO
(
'r'
,
6
),
BR_INCREFS
=
_IOR
(
'r'
,
7
,
struct
binder_ptr_cookie
),
BR_ACQUIRE
=
_IOR
(
'r'
,
8
,
struct
binder_ptr_cookie
),
BR_RELEASE
=
_IOR
(
'r'
,
9
,
struct
binder_ptr_cookie
),
BR_DECREFS
=
_IOR
(
'r'
,
10
,
struct
binder_ptr_cookie
),
BR_ATTEMPT_ACQUIRE
=
_IOR
(
'r'
,
11
,
struct
binder_pri_ptr_cookie
),
BR_NOOP
=
_IO
(
'r'
,
12
),
BR_SPAWN_LOOPER
=
_IO
(
'r'
,
13
),
BR_FINISHED
=
_IO
(
'r'
,
14
),
BR_DEAD_BINDER
=
_IOR
(
'r'
,
15
,
binder_uintptr_t
),
BR_CLEAR_DEATH_NOTIFICATION_DONE
=
_IOR
(
'r'
,
16
,
binder_uintptr_t
),
BR_FAILED_REPLY
=
_IO
(
'r'
,
17
),
BR_RELEASE_NODE
=
_IO
(
'r'
,
18
),
};
enum
binder_driver_command_protocol
{
BC_TRANSACTION
=
_IOW
(
'c'
,
0
,
struct
binder_transaction_data
),
BC_REPLY
=
_IOW
(
'c'
,
1
,
struct
binder_transaction_data
),
BC_ACQUIRE_RESULT
=
_IOW
(
'c'
,
2
,
__s32
),
BC_FREE_BUFFER
=
_IOW
(
'c'
,
3
,
binder_uintptr_t
),
BC_INCREFS
=
_IOW
(
'c'
,
4
,
__u32
),
BC_ACQUIRE
=
_IOW
(
'c'
,
5
,
__u32
),
BC_RELEASE
=
_IOW
(
'c'
,
6
,
__u32
),
BC_DECREFS
=
_IOW
(
'c'
,
7
,
__u32
),
BC_INCREFS_DONE
=
_IOW
(
'c'
,
8
,
struct
binder_ptr_cookie
),
BC_ACQUIRE_DONE
=
_IOW
(
'c'
,
9
,
struct
binder_ptr_cookie
),
BC_ATTEMPT_ACQUIRE
=
_IOW
(
'c'
,
10
,
struct
binder_pri_desc
),
BC_REGISTER_LOOPER
=
_IO
(
'c'
,
11
),
BC_ENTER_LOOPER
=
_IO
(
'c'
,
12
),
BC_EXIT_LOOPER
=
_IO
(
'c'
,
13
),
BC_REQUEST_DEATH_NOTIFICATION
=
_IOW
(
'c'
,
14
,
struct
binder_handle_cookie
),
BC_CLEAR_DEATH_NOTIFICATION
=
_IOW
(
'c'
,
15
,
struct
binder_handle_cookie
),
BC_DEAD_BINDER_DONE
=
_IOW
(
'c'
,
16
,
binder_uintptr_t
),
BC_TRANSACTION_SG
=
_IOW
(
'c'
,
17
,
struct
binder_transaction_data_sg
),
BC_REPLY_SG
=
_IOW
(
'c'
,
18
,
struct
binder_transaction_data_sg
),
BC_RELEASE_NODE
=
_IOW
(
'c'
,
19
,
binder_uintptr_t
),
};
#endif
ipc/native/c/ipc/src/binder_invoker.c
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 "binder_invoker.h"
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include "binder_types.h"
#include "ipc_process_skeleton.h"
#include "ipc_thread_pool.h"
#include "rpc_errno.h"
#include "rpc_log.h"
#include "rpc_os_adapter.h"
#include "rpc_types.h"
#include "securec.h"
#include "sys_binder.h"
#define READ_BUFFER_SIZE 32
#define ALIGN_SZ 4
#define IPC_IO_ALIGN(sz) (((sz) + ALIGN_SZ - 1) & (~(ALIGN_SZ - 1)))
typedef
struct
{
int32_t
fd
;
size_t
mmapSize
;
void
*
mmapAddr
;
}
BinderConnector
;
struct
FreeData
{
uint32_t
cmd
;
binder_uintptr_t
buffer
;
}
__attribute__
((
packed
));
struct
TransactData
{
uint32_t
cmd
;
struct
binder_transaction_data
btd
;
}
__attribute__
((
packed
));
static
RemoteInvoker
g_ipcInvoker
;
static
BinderConnector
*
g_connector
=
NULL
;
static
pthread_mutex_t
g_connectorMutex
=
PTHREAD_MUTEX_INITIALIZER
;
static
BinderConnector
*
OpenDriver
(
void
)
{
BinderConnector
*
connector
=
(
BinderConnector
*
)
malloc
(
sizeof
(
BinderConnector
));
if
(
connector
==
NULL
)
{
RPC_LOG_ERROR
(
"ipc open driver malloc failed."
);
return
NULL
;
}
connector
->
fd
=
open
(
BINDER_DRIVER
,
O_RDWR
);
if
(
connector
->
fd
<
0
)
{
RPC_LOG_ERROR
(
"Open liteipc driver failed error %d."
,
errno
);
goto
OPEN_ERR
;
}
connector
->
mmapAddr
=
mmap
(
NULL
,
MMAP_MAX_SIZE
,
PROT_READ
,
MAP_PRIVATE
,
connector
->
fd
,
0
);
if
(
connector
->
mmapAddr
==
MAP_FAILED
)
{
RPC_LOG_ERROR
(
"Mmap failed."
);
goto
MMAP_ERR
;
}
connector
->
mmapSize
=
MMAP_MAX_SIZE
;
return
connector
;
MMAP_ERR:
close
(
connector
->
fd
);
OPEN_ERR:
free
(
connector
);
return
NULL
;
}
static
void
DeleteBinderConnector
(
void
)
{
if
(
g_connector
==
NULL
)
{
return
;
}
munmap
(
g_connector
->
mmapAddr
,
g_connector
->
mmapSize
);
close
(
g_connector
->
fd
);
free
(
g_connector
);
g_connector
=
NULL
;
}
static
int32_t
BinderWrite
(
void
*
data
,
size_t
len
)
{
struct
binder_write_read
bwr
;
int32_t
res
;
bwr
.
write_size
=
len
;
bwr
.
write_consumed
=
0
;
bwr
.
write_buffer
=
(
uintptr_t
)
data
;
bwr
.
read_size
=
0
;
bwr
.
read_consumed
=
0
;
bwr
.
read_buffer
=
0
;
res
=
ioctl
(
g_connector
->
fd
,
BINDER_WRITE_READ
,
&
bwr
);
if
(
res
<
0
)
{
RPC_LOG_ERROR
(
"binder write ioctl failed errno = %d."
,
errno
);
return
IPC_INVOKER_IOCTL_FAILED
;
}
return
ERR_NONE
;
}
int32_t
AcquireHandle
(
int32_t
handle
)
{
uint32_t
cmd
[
2
];
cmd
[
0
]
=
BC_ACQUIRE
;
cmd
[
1
]
=
handle
;
int32_t
ret
=
BinderWrite
(
&
cmd
,
sizeof
(
cmd
));
return
ret
;
}
int32_t
ReleaseHandle
(
int32_t
handle
)
{
RPC_LOG_ERROR
(
"SA dead delete it, handle = %d."
,
handle
);
uint32_t
cmd
[
2
];
cmd
[
0
]
=
BC_RELEASE
;
cmd
[
1
]
=
handle
;
int32_t
ret
=
BinderWrite
(
&
cmd
,
sizeof
(
cmd
));
return
ret
;
}
static
void
ToTransData
(
uint32_t
handle
,
uint32_t
code
,
MessageOption
option
,
const
IpcIo
*
data
,
struct
TransactData
*
buf
)
{
buf
->
btd
.
target
.
handle
=
handle
;
buf
->
btd
.
code
=
code
;
buf
->
btd
.
flags
=
option
;
buf
->
btd
.
cookie
=
0
;
buf
->
btd
.
sender_pid
=
RpcGetPid
();
buf
->
btd
.
sender_euid
=
RpcGetUid
();
buf
->
btd
.
data_size
=
(
data
==
NULL
)
?
0
:
(
data
->
bufferCur
-
data
->
bufferBase
);
buf
->
btd
.
data
.
ptr
.
buffer
=
(
data
==
NULL
)
?
0
:
(
binder_uintptr_t
)
data
->
bufferBase
;
buf
->
btd
.
offsets_size
=
(
data
==
NULL
)
?
0
:
((
char
*
)
data
->
offsetsCur
-
(
char
*
)
data
->
offsetsBase
);
buf
->
btd
.
offsets_size
=
IPC_IO_ALIGN
(
buf
->
btd
.
offsets_size
);
buf
->
btd
.
data
.
ptr
.
offsets
=
(
data
==
NULL
)
?
0
:
(
binder_uintptr_t
)
data
->
offsetsBase
;
}
static
void
ToIpcData
(
const
struct
binder_transaction_data
*
tr
,
IpcIo
*
data
)
{
data
->
bufferBase
=
data
->
bufferCur
=
(
char
*
)
tr
->
data
.
ptr
.
buffer
;
data
->
bufferLeft
=
(
size_t
)
tr
->
data_size
;
data
->
offsetsBase
=
data
->
offsetsCur
=
(
size_t
*
)
tr
->
data
.
ptr
.
offsets
;
data
->
offsetsLeft
=
(
tr
->
offsets_size
)
/
sizeof
(
binder_size_t
);
data
->
flag
=
IPC_IO_INITIALIZED
;
}
static
void
BinderRefDone
(
const
struct
binder_ptr_cookie
*
ptrCookie
,
uint32_t
cmd
)
{
struct
{
uint32_t
cmd
;
struct
binder_ptr_cookie
payload
;
}
__attribute__
((
packed
))
data
;
if
(
cmd
==
BR_ACQUIRE
)
{
data
.
cmd
=
BC_ACQUIRE_DONE
;
}
else
{
data
.
cmd
=
BC_INCREFS_DONE
;
}
data
.
payload
.
ptr
=
ptrCookie
->
ptr
;
data
.
payload
.
cookie
=
ptrCookie
->
cookie
;
BinderWrite
(
&
data
,
sizeof
(
data
));
}
int32_t
IpcFreeBuffer
(
void
*
ptr
)
{
if
(
ptr
==
NULL
)
{
return
ERR_NONE
;
}
struct
FreeData
data
=
{
0
};
data
.
cmd
=
BC_FREE_BUFFER
;
data
.
buffer
=
(
binder_uintptr_t
)
ptr
;
int32_t
ret
=
BinderWrite
(
&
data
,
sizeof
(
data
));
return
ret
;
}
static
int32_t
SendReply
(
IpcIo
*
reply
,
const
int32_t
*
status
)
{
struct
TransactData
buf
;
buf
.
cmd
=
BC_REPLY
;
int32_t
ret
;
if
(
reply
->
bufferCur
>
reply
->
bufferBase
)
{
ToTransData
(
0
,
0
,
0
,
reply
,
&
buf
);
}
else
if
(
status
!=
NULL
)
{
buf
.
btd
.
flags
=
TF_OP_STATUS_CODE
;
buf
.
btd
.
data_size
=
sizeof
(
int32_t
);
buf
.
btd
.
offsets_size
=
0
;
buf
.
btd
.
data
.
ptr
.
buffer
=
(
uintptr_t
)
status
;
buf
.
btd
.
data
.
ptr
.
offsets
=
0
;
}
ret
=
BinderWrite
(
&
buf
,
sizeof
(
buf
));
return
ret
;
}
static
void
HandleTransaction
(
const
struct
binder_transaction_data
*
tr
)
{
ThreadContext
*
threadContext
=
GetCurrentThreadContext
();
const
pid_t
oldPid
=
threadContext
->
callerPid
;
const
pid_t
oldUid
=
threadContext
->
callerUid
;
threadContext
->
callerPid
=
tr
->
sender_pid
;
threadContext
->
callerUid
=
(
pid_t
)
tr
->
sender_euid
;
IpcObjectStub
*
objectStub
;
if
(
tr
->
target
.
ptr
!=
0
)
{
objectStub
=
(
IpcObjectStub
*
)
tr
->
cookie
;
}
else
{
objectStub
=
(
IpcObjectStub
*
)(
GetRegistryObject
()
->
cookie
);
}
threadContext
->
objectStub
=
objectStub
;
IpcIo
data
;
ToIpcData
(
tr
,
&
data
);
MessageOption
option
=
tr
->
flags
;
IpcIo
reply
;
uint8
tempData
[
IPC_IO_DATA_MAX
];
IpcIoInit
(
&
reply
,
tempData
,
IPC_IO_DATA_MAX
,
MAX_OBJECT_NUM
);
int32_t
error
=
OnRemoteRequestInner
(
tr
->
code
,
&
data
,
&
reply
,
option
,
objectStub
);
if
(
tr
->
flags
&
TF_ONE_WAY
)
{
IpcFreeBuffer
((
void
*
)(
tr
->
data
.
ptr
.
buffer
));
}
else
{
IpcFreeBuffer
((
void
*
)(
tr
->
data
.
ptr
.
buffer
));
SendReply
(
&
reply
,
&
error
);
}
threadContext
->
callerPid
=
oldPid
;
threadContext
->
callerUid
=
oldUid
;
}
static
void
HandleReply
(
IpcIo
*
reply
,
const
struct
binder_transaction_data
*
tr
,
uintptr_t
*
buffer
)
{
if
(
reply
==
NULL
||
buffer
==
NULL
)
{
RPC_LOG_ERROR
(
"no need reply, free the buffer."
);
IpcFreeBuffer
((
void
*
)(
tr
->
data
.
ptr
.
buffer
));
return
;
}
ToIpcData
(
tr
,
reply
);
*
buffer
=
(
uintptr_t
)
tr
->
data
.
ptr
.
buffer
;
}
static
void
HandleDeadBinderDone
(
void
*
cookie
)
{
struct
{
uint32_t
cmd
;
binder_uintptr_t
cookie
;
}
__attribute__
((
packed
))
data
;
data
.
cmd
=
BC_DEAD_BINDER_DONE
;
data
.
cookie
=
(
binder_uintptr_t
)
cookie
;
BinderWrite
(
&
data
,
sizeof
(
data
));
}
static
void
HandleDeadBinder
(
uintptr_t
ptr
)
{
DeathCallback
*
death
=
(
DeathCallback
*
)(
uintptr_t
)
*
(
binder_uintptr_t
*
)
ptr
;
if
(
death
!=
NULL
)
{
RPC_LOG_INFO
(
"dead binder now call SendObituary."
);
SendObituary
(
death
);
HandleDeadBinderDone
(
death
);
}
}
static
void
OnRemoveRecipientDone
(
uintptr_t
ptr
)
{
DeathCallback
*
death
=
(
DeathCallback
*
)(
uintptr_t
)
*
(
binder_uintptr_t
*
)
ptr
;
if
(
death
!=
NULL
)
{
DeleteDeathCallback
(
death
);
}
}
static
int32_t
BinderParse
(
IpcIo
*
reply
,
uintptr_t
ptr
,
size_t
size
,
uintptr_t
*
buffer
)
{
int32_t
ret
=
1
;
uintptr_t
end
=
ptr
+
(
uintptr_t
)
size
;
while
(
ptr
<
end
)
{
uint32_t
cmd
=
*
(
uint32_t
*
)
ptr
;
ptr
+=
sizeof
(
uint32_t
);
switch
(
cmd
)
{
case
BR_NOOP
:
case
BR_TRANSACTION_COMPLETE
:
break
;
case
BR_INCREFS
:
case
BR_ACQUIRE
:
{
struct
binder_ptr_cookie
*
ptrCookie
=
(
struct
binder_ptr_cookie
*
)
ptr
;
if
((
end
-
ptr
)
<
sizeof
(
*
ptrCookie
))
{
return
IPC_INVOKER_INVALID_DATA
;
}
BinderRefDone
(
ptrCookie
,
cmd
);
ptr
+=
sizeof
(
*
ptrCookie
);
break
;
}
case
BR_RELEASE
:
case
BR_DECREFS
:
ptr
+=
sizeof
(
struct
binder_ptr_cookie
);
break
;
case
BR_SPAWN_LOOPER
:
{
SpawnThread
(
SPAWN_PASSIVE
,
IF_PROT_DEFAULT
);
break
;
}
case
BR_TRANSACTION
:
{
struct
binder_transaction_data
*
tr
=
(
struct
binder_transaction_data
*
)
ptr
;
if
((
end
-
ptr
)
<
sizeof
(
*
tr
))
{
return
IPC_INVOKER_INVALID_DATA
;
}
HandleTransaction
(
tr
);
ptr
+=
sizeof
(
*
tr
);
break
;
}
case
BR_REPLY
:
{
struct
binder_transaction_data
*
tr
=
(
struct
binder_transaction_data
*
)
ptr
;
if
((
end
-
ptr
)
<
sizeof
(
*
tr
))
{
return
IPC_INVOKER_INVALID_DATA
;
}
HandleReply
(
reply
,
tr
,
buffer
);
ptr
+=
sizeof
(
*
tr
);
ret
=
0
;
break
;
}
case
BR_DEAD_BINDER
:
{
HandleDeadBinder
(
ptr
);
ptr
+=
sizeof
(
binder_uintptr_t
);
break
;
}
case
BR_CLEAR_DEATH_NOTIFICATION_DONE
:
{
OnRemoveRecipientDone
(
ptr
);
ptr
+=
sizeof
(
binder_uintptr_t
);
break
;
}
case
BR_FAILED_REPLY
:
ret
=
IPC_INVOKER_FAILED_REPLY
;
break
;
case
BR_DEAD_REPLY
:
ret
=
ERR_DEAD_OBJECT
;
break
;
default:
ret
=
IPC_INVOKER_UNKNOWN_CODE
;
}
}
return
ret
;
}
void
IpcJoinThread
(
bool
initiative
)
{
struct
binder_write_read
bwr
;
uint32_t
readbuf
[
READ_BUFFER_SIZE
];
int32_t
ret
;
bwr
.
write_size
=
0
;
bwr
.
write_consumed
=
0
;
bwr
.
write_buffer
=
0
;
if
(
initiative
)
{
readbuf
[
0
]
=
BC_ENTER_LOOPER
;
}
else
{
readbuf
[
0
]
=
BC_REGISTER_LOOPER
;
}
BinderWrite
(
readbuf
,
sizeof
(
uint32_t
));
for
(;;)
{
bwr
.
read_size
=
sizeof
(
readbuf
);
bwr
.
read_consumed
=
0
;
bwr
.
read_buffer
=
(
uintptr_t
)
readbuf
;
ret
=
ioctl
(
g_connector
->
fd
,
BINDER_WRITE_READ
,
&
bwr
);
if
(
ret
<
0
)
{
RPC_LOG_ERROR
(
"ioctl failed errno = %d."
,
errno
);
break
;
}
ret
=
BinderParse
(
0
,
(
uintptr_t
)
readbuf
,
bwr
.
read_consumed
,
NULL
);
if
(
ret
==
0
)
{
RPC_LOG_ERROR
(
"unexpected reply"
);
break
;
}
if
(
ret
<
0
)
{
RPC_LOG_ERROR
(
"io error ret = %d errno = %d."
,
ret
,
errno
);
break
;
}
}
}
int32_t
IpcSetMaxWorkThread
(
int32_t
maxThreadNum
)
{
if
(
g_connector
==
NULL
)
{
RPC_LOG_ERROR
(
"ipc driver not init"
);
return
ERR_FAILED
;
}
int32_t
ret
=
ioctl
(
g_connector
->
fd
,
BINDER_SET_MAX_THREADS
,
&
maxThreadNum
);
return
ret
;
}
int32_t
IpcSetRegistryObject
(
void
)
{
if
(
g_connector
==
NULL
)
{
RPC_LOG_ERROR
(
"ipc driver not init"
);
return
ERR_FAILED
;
}
int32_t
ret
=
ioctl
(
g_connector
->
fd
,
BINDER_SET_CONTEXT_MGR
,
0
);
if
(
ret
==
ERR_NONE
)
{
RPC_LOG_INFO
(
"set samgr success!!"
);
return
ERR_NONE
;
}
RPC_LOG_ERROR
(
"set samgr failed"
);
return
ERR_FAILED
;
}
static
int32_t
InternalRequest
(
SvcIdentity
sid
,
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
)
{
RPC_LOG_INFO
(
"Internal ipc request called"
);
int32_t
error
=
ERR_FAILED
;
IpcObjectStub
*
objectStub
=
(
IpcObjectStub
*
)(
sid
.
cookie
);
data
->
bufferCur
=
data
->
bufferBase
;
data
->
offsetsCur
=
data
->
offsetsBase
;
if
(
objectStub
->
func
!=
NULL
)
{
uint8
tempData
[
IPC_IO_DATA_MAX
];
IpcIoInit
(
reply
,
tempData
,
IPC_IO_DATA_MAX
,
MAX_OBJECT_NUM
);
error
=
OnRemoteRequestInner
(
code
,
data
,
reply
,
option
,
objectStub
);
}
reply
->
bufferCur
=
reply
->
bufferBase
;
reply
->
offsetsCur
=
reply
->
offsetsBase
;
return
error
;
}
int32_t
IpcSendRequest
(
SvcIdentity
target
,
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
,
uintptr_t
*
buffer
)
{
if
(
g_connector
==
NULL
)
{
return
ERR_FAILED
;
}
if
(
target
.
handle
<
0
)
{
*
buffer
=
0
;
return
InternalRequest
(
target
,
code
,
data
,
reply
,
option
);
}
int32_t
ret
;
struct
TransactData
buf
;
struct
binder_write_read
bwr
;
buf
.
cmd
=
BC_TRANSACTION
;
ToTransData
(
target
.
handle
,
code
,
option
,
data
,
&
buf
);
bwr
.
write_size
=
sizeof
(
buf
);
bwr
.
write_consumed
=
0
;
bwr
.
write_buffer
=
(
uintptr_t
)
&
buf
;
uint32_t
readbuf
[
READ_BUFFER_SIZE
]
=
{
0
};
if
(
option
!=
TF_OP_ASYNC
)
{
while
(
1
)
{
bwr
.
read_size
=
sizeof
(
readbuf
);
bwr
.
read_consumed
=
0
;
bwr
.
read_buffer
=
(
uintptr_t
)
readbuf
;
if
(
ioctl
(
g_connector
->
fd
,
BINDER_WRITE_READ
,
&
bwr
)
<
ERR_NONE
)
{
RPC_LOG_ERROR
(
"ipc send request ioctl failed."
);
return
IPC_INVOKER_IOCTL_FAILED
;
}
ret
=
BinderParse
(
reply
,
(
uintptr_t
)
readbuf
,
bwr
.
read_consumed
,
buffer
);
if
(
ret
==
0
)
{
break
;
}
if
(
ret
<
0
)
{
RPC_LOG_ERROR
(
"ipc send request failed res = %d."
,
ret
);
break
;
}
}
}
else
{
bwr
.
read_size
=
sizeof
(
readbuf
);
bwr
.
read_consumed
=
0
;
bwr
.
read_buffer
=
(
uintptr_t
)
readbuf
;
if
(
ioctl
(
g_connector
->
fd
,
BINDER_WRITE_READ
,
&
bwr
)
<
ERR_NONE
)
{
RPC_LOG_ERROR
(
"ipc send request ioctl failed."
);
return
IPC_INVOKER_IOCTL_FAILED
;
}
ret
=
BinderParse
(
reply
,
(
uintptr_t
)
readbuf
,
bwr
.
read_consumed
,
NULL
);
if
(
ret
==
1
)
{
ret
=
0
;
}
}
return
ret
;
}
int32_t
IpcAddDeathRecipient
(
int32_t
handle
,
void
*
cookie
)
{
struct
{
uint32_t
cmd
;
struct
binder_handle_cookie
payload
;
}
__attribute__
((
packed
))
data
;
data
.
cmd
=
BC_REQUEST_DEATH_NOTIFICATION
;
data
.
payload
.
handle
=
handle
;
data
.
payload
.
cookie
=
(
binder_uintptr_t
)
cookie
;
return
BinderWrite
(
&
data
,
sizeof
(
data
));
}
int32_t
IpcRemoveDeathRecipient
(
int32_t
handle
,
void
*
cookie
)
{
struct
{
uint32_t
cmd
;
struct
binder_handle_cookie
payload
;
}
__attribute__
((
packed
))
data
;
data
.
cmd
=
BC_CLEAR_DEATH_NOTIFICATION
;
data
.
payload
.
handle
=
handle
;
data
.
payload
.
cookie
=
(
binder_uintptr_t
)
cookie
;
return
BinderWrite
(
&
data
,
sizeof
(
data
));
}
void
IpcExitCurrentThread
(
void
)
{
ioctl
(
g_connector
->
fd
,
BINDER_THREAD_EXIT
,
0
);
}
static
BinderConnector
*
InitBinderConnector
(
void
)
{
if
(
g_connector
==
NULL
)
{
if
(
pthread_mutex_lock
(
&
g_connectorMutex
)
!=
0
)
{
RPC_LOG_ERROR
(
"init binder connector lock failed."
);
return
NULL
;
}
if
(
g_connector
==
NULL
)
{
BinderConnector
*
temp
=
OpenDriver
();
if
(
temp
==
NULL
)
{
pthread_mutex_unlock
(
&
g_connectorMutex
);
RPC_LOG_ERROR
(
"create binder connector failed."
);
return
NULL
;
}
g_connector
=
temp
;
g_ipcInvoker
.
connector
=
g_connector
;
g_ipcInvoker
.
AcquireHandle
=
AcquireHandle
;
g_ipcInvoker
.
ReleaseHandle
=
ReleaseHandle
;
g_ipcInvoker
.
SendRequest
=
IpcSendRequest
;
g_ipcInvoker
.
FreeBuffer
=
IpcFreeBuffer
;
g_ipcInvoker
.
SetMaxWorkThread
=
IpcSetMaxWorkThread
;
g_ipcInvoker
.
JoinThread
=
IpcJoinThread
;
g_ipcInvoker
.
SetRegistryObject
=
IpcSetRegistryObject
;
g_ipcInvoker
.
AddDeathRecipient
=
IpcAddDeathRecipient
;
g_ipcInvoker
.
RemoveDeathRecipient
=
IpcRemoveDeathRecipient
;
g_ipcInvoker
.
ExitCurrentThread
=
IpcExitCurrentThread
;
}
pthread_mutex_unlock
(
&
g_connectorMutex
);
}
return
g_connector
;
}
RemoteInvoker
*
GetIpcInvoker
(
void
)
{
if
(
InitBinderConnector
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init binder invoker failed."
);
return
NULL
;
}
return
&
g_ipcInvoker
;
}
\ No newline at end of file
ipc/native/c/ipc/src/binder_invoker_virtual.c
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 "binder_invoker.h"
RemoteInvoker
*
GetIpcInvoker
(
void
)
{
return
NULL
;
}
\ No newline at end of file
ipc/native/c/manager/include/ipc_process_skeleton.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 OHOS_IPC_RPC_PROCESS_SKELETON_H
#define OHOS_IPC_RPC_PROCESS_SKELETON_H
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include "ipc_skeleton.h"
#include "ipc_thread_pool.h"
#include "rpc_types.h"
#include "utils_list.h"
#ifdef __cplusplus
#if __cplusplus
extern
"C"
{
#endif
#endif
/* __cplusplus */
typedef
struct
{
bool
usedFlag
;
OnRemoteDead
func
;
void
*
args
;
}
DeathHandler
;
typedef
struct
{
UTILS_DL_LIST
list
;
pthread_mutex_t
lock
;
DeathHandler
handler
[
MAX_DEATH_CALLBACK_NUM
];
int32_t
handle
;
int32_t
deathNum
;
bool
isRemoteDead
;
bool
isNewHandler
;
}
DeathCallback
;
typedef
struct
{
UTILS_DL_LIST
objects
;
pthread_mutex_t
lock
;
ThreadPool
*
threadPool
;
}
IpcSkeleton
;
IpcSkeleton
*
GetCurrentSkeleton
(
void
);
int32_t
SetMaxWorkThread
(
int32_t
maxThreadNum
);
void
JoinMainWorkThread
(
void
);
pid_t
ProcessGetCallingPid
(
void
);
pid_t
ProcessGetCallingUid
(
void
);
int32_t
SpawnThread
(
int32_t
policy
,
int32_t
proto
);
int32_t
SetRegistryObject
(
SvcIdentity
target
);
const
SvcIdentity
*
GetRegistryObject
(
void
);
int32_t
ProcessSendRequest
(
SvcIdentity
target
,
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
,
uintptr_t
*
buffer
);
int32_t
ProcessFreeBuffer
(
void
*
ptr
);
void
OnLastStrongRef
(
int32_t
handle
);
int32_t
ProcessAddDeathRecipient
(
int32_t
handle
,
OnRemoteDead
deathFunc
,
void
*
args
,
uint32_t
*
cbId
);
int32_t
ProcessRemoveDeathRecipient
(
int32_t
handle
,
uint32_t
cbId
);
int32_t
OnRemoteRequestInner
(
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
,
IpcObjectStub
*
objectStub
);
bool
OnThreadTerminated
(
pthread_t
threadId
);
void
SendObituary
(
DeathCallback
*
deathCallback
);
void
DeleteDeathCallback
(
DeathCallback
*
deathCallback
);
void
WaitForProxyInit
(
int32_t
handle
);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/* __cplusplus */
#endif
/* OHOS_IPC_RPC_PROCESS_SKELETON_H */
\ No newline at end of file
ipc/native/c/manager/include/ipc_thread_pool.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 OHOS_IPC_RPC_THRREAD_H
#define OHOS_IPC_RPC_THRREAD_H
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include "ipc_skeleton.h"
#include "iremote_invoker.h"
#ifdef __cplusplus
#if __cplusplus
extern
"C"
{
#endif
#endif
/* __cplusplus */
enum
{
SPAWN_PASSIVE
,
SPAWN_ACTIVE
,
PROCESS_PASSIVE
,
PROCESS_ACTIVE
,
};
typedef
struct
{
pthread_t
threadId
;
int32_t
proto
;
int32_t
policy
;
IpcObjectStub
*
objectStub
;
pid_t
callerPid
;
pid_t
callerUid
;
char
callerDeviceID
[
64
];
bool
stopWorkThread
;
uint64_t
seqNumber
;
uint32_t
clientFd
;
}
ThreadContext
;
typedef
struct
{
int32_t
maxThreadNum
;
int32_t
idleThreadNum
;
int32_t
idleSocketThreadNum
;
pthread_mutex_t
lock
;
}
ThreadPool
;
ThreadPool
*
InitThreadPool
(
int32_t
maxThreadNum
);
void
DeinitThreadPool
(
ThreadPool
*
threadPool
);
int32_t
SpawnNewThread
(
ThreadPool
*
threadPool
,
int32_t
policy
,
int32_t
proto
);
ThreadContext
*
GetCurrentThreadContext
(
void
);
RemoteInvoker
*
GetRemoteInvoker
(
void
);
void
UpdateMaxThreadNum
(
ThreadPool
*
threadPool
,
int32_t
maxThreadNum
);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/* __cplusplus */
#endif
/* OHOS_IPC_RPC_THRREAD_H */
\ No newline at end of file
ipc/native/c/manager/include/iremote_invoker.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 OHOS_IPC_RPC_IREMOTTE_INVOKER_H
#define OHOS_IPC_RPC_IREMOTTE_INVOKER_H
#include "ipc_skeleton.h"
#include "rpc_types.h"
#include "serializer.h"
#ifdef __cplusplus
#if __cplusplus
extern
"C"
{
#endif
#endif
/* __cplusplus */
typedef
struct
{
void
*
connector
;
int32_t
(
*
AcquireHandle
)(
int32_t
handle
);
int32_t
(
*
ReleaseHandle
)(
int32_t
handle
);
int32_t
(
*
SendRequest
)(
SvcIdentity
target
,
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
,
uintptr_t
*
buffer
);
int32_t
(
*
FreeBuffer
)(
void
*
ptr
);
int32_t
(
*
SetMaxWorkThread
)(
int32_t
maxThreadNum
);
void
(
*
JoinThread
)(
bool
initiative
);
void
(
*
ExitCurrentThread
)(
void
);
void
(
*
JoinProcessThread
)(
bool
initiative
);
int32_t
(
*
SetRegistryObject
)(
void
);
int32_t
(
*
AddDeathRecipient
)(
int32_t
handle
,
void
*
cookie
);
int32_t
(
*
RemoveDeathRecipient
)(
int32_t
handle
,
void
*
cookie
);
}
RemoteInvoker
;
RemoteInvoker
*
InitRemoteInvoker
(
int32_t
proto
);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/* __cplusplus */
#endif
/* OHOS_IPC_RPC_IREMOTTE_INVOKER_H */
\ No newline at end of file
ipc/native/c/manager/include/rpc_errno.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 OHOS_IPC_RPC_ERRNO_H
#define OHOS_IPC_RPC_ERRNO_H
enum
IpcRpcErrNo
{
ERR_NONE
=
0
,
ERR_FAILED
=
-
1
,
ERR_INVALID_PARAM
=
-
2
,
ERR_IPC_SKELETON_NOT_INIT
=
-
3
,
ERR_THREAD_INVOKER_NOT_INIT
=
-
4
,
ERR_NOT_RPC
=
-
16
,
ERR_DEAD_OBJECT
=
-
32
,
IPC_INVOKER_INVALID_DATA
=
-
33
,
IPC_INVOKER_FAILED_REPLY
=
-
34
,
IPC_INVOKER_UNKNOWN_CODE
=
-
35
,
IPC_INVOKER_IOCTL_FAILED
=
-
36
,
};
#endif
/* OHOS_IPC_RPC_ERRNO_H */
ipc/native/c/manager/include/rpc_log.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 OHOS_IPC_RPC_LOG_H
#define OHOS_IPC_RPC_LOG_H
#include <stdio.h>
#include <stdbool.h>
#ifndef IPCRPC_DEBUG
#if defined(__LITEOS_M__)
#define IPCRPC_PRINTF
#include "log.h"
#else
#include "hilog/log.h"
#endif
#endif
#ifdef __cplusplus
#if __cplusplus
extern
"C"
{
#endif
#endif
#ifndef IPCRPC_DEBUG
#if defined(__LITEOS_M__)
#define RPC_LOG_DEBUG(fmt, ...) HILOG_DEBUG(HILOG_MODULE_SOFTBUS, fmt, ##__VA_ARGS__)
#define RPC_LOG_INFO(fmt, ...) HILOG_INFO(HILOG_MODULE_SOFTBUS, fmt, ##__VA_ARGS__)
#define RPC_LOG_WARN(fmt, ...) HILOG_WARN(HILOG_MODULE_SOFTBUS, fmt, ##__VA_ARGS__)
#define RPC_LOG_ERROR(fmt, ...) HILOG_ERROR(HILOG_MODULE_SOFTBUS, fmt, ##__VA_ARGS__)
#else
#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN 0xD001518
#define LOG_TAG "IPCRPC"
#define RPC_LOG_DEBUG(fmt, ...) HILOG_DEBUG(LOG_CORE, fmt, ##__VA_ARGS__)
#define RPC_LOG_INFO(fmt, ...) HILOG_INFO(LOG_CORE, fmt, ##__VA_ARGS__)
#define RPC_LOG_WARN(fmt, ...) HILOG_WARN(LOG_CORE, fmt, ##__VA_ARGS__)
#define RPC_LOG_ERROR(fmt, ...) HILOG_ERROR(LOG_CORE, fmt, ##__VA_ARGS__)
#endif
#else
enum
{
RPC_LOG_LEVEL_DEBUG
=
0
,
RPC_LOG_LEVEL_INFO
,
RPC_LOG_LEVEL_WARNING
,
RPC_LOG_LEVEL_ERROR
};
#define RPC_LOG_LEVEL RPC_LOG_LEVEL_INFO
#define LOG_DBG(fmt, ...) do { \
if
(
RPC_LOG_LEVEL_DEBUG
>=
RPC_LOG_LEVEL
)
{
\
printf
(
"DEBUG: "
fmt
"
\n
"
,
##
__VA_ARGS__
);
\
}
\
}
while
(
0
)
#define LOG_INFO(fmt, ...) do { \
if
(
RPC_LOG_LEVEL_INFO
>=
RPC_LOG_LEVEL
)
{
\
printf
(
"INFO: "
fmt
"
\n
"
,
##
__VA_ARGS__
);
\
}
\
}
while
(
0
)
#define LOG_WARN(fmt, ...) do { \
if
(
RPC_LOG_LEVEL_WARNING
>=
RPC_LOG_LEVEL
)
{
\
printf
(
"WARN: "
fmt
"
\n
"
,
##
__VA_ARGS__
);
\
}
\
}
while
(
0
)
#define LOG_ERR(fmt, ...) do { \
if
(
RPC_LOG_LEVEL_ERROR
>=
RPC_LOG_LEVEL
)
{
\
printf
(
"ERROR: "
fmt
"
\n
"
,
##
__VA_ARGS__
);
\
}
\
}
while
(
0
)
#endif
#if defined(__LITEOS_M__)
#define RPC_HILOG_ID HILOG_MODULE_SOFTBUS
#else
#define RPC_HILOG_ID LOG_CORE
#endif
typedef
enum
{
RPC_LOG_DBG
,
RPC_LOG_INFO
,
RPC_LOG_WARN
,
RPC_LOG_ERROR
,
RPC_LOG_LEVEL_MAX
,
}
RpcLogLevel
;
typedef
enum
{
RPC_LOG_IPC
,
RPC_LOG_RPC
,
RPC_LOG_SER
,
RPC_LOG_MODULE_MAX
,
}
RpcLogModule
;
void
RpcLog
(
RpcLogModule
module
,
RpcLogLevel
level
,
const
char
*
fmt
,
...);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
/* __cplusplus */
#endif
/* OHOS_IPC_RPC_LOG_H */
\ No newline at end of file
ipc/native/c/manager/include/rpc_types.h
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 OHOS_IPC_RPC_TYPES_H
#define OHOS_IPC_RPC_TYPES_H
#define ZIPC_PACK_CHARS(c1, c2, c3, c4) ((((c1) << 24)) | (((c2) << 16)) | (((c3) << 8)) | (c4))
#define GET_IDLE_THREAD_WAIT_TIME 1000
enum
{
FIRST_CALL_TRANSACTION
=
0x00000001
,
LAST_CALL_TRANSACTION
=
0x00ffffff
,
PING_TRANSACTION
=
ZIPC_PACK_CHARS
(
'_'
,
'P'
,
'N'
,
'G'
),
DUMP_TRANSACTION
=
ZIPC_PACK_CHARS
(
'_'
,
'D'
,
'M'
,
'P'
),
SHELL_COMMAND_TRANSACTION
=
ZIPC_PACK_CHARS
(
'_'
,
'C'
,
'M'
,
'D'
),
INTERFACE_TRANSACTION
=
ZIPC_PACK_CHARS
(
'_'
,
'N'
,
'T'
,
'F'
),
SYSPROPS_TRANSACTION
=
ZIPC_PACK_CHARS
(
'_'
,
'S'
,
'P'
,
'R'
),
SYNCHRONIZE_REFERENCE
=
ZIPC_PACK_CHARS
(
'_'
,
'S'
,
'Y'
,
'C'
),
INVOKE_LISTEN_THREAD
=
ZIPC_PACK_CHARS
(
'_'
,
'I'
,
'L'
,
'T'
),
GET_PROTO_INFO
=
ZIPC_PACK_CHARS
(
'_'
,
'G'
,
'R'
,
'I'
),
GET_UIDPID_INFO
=
ZIPC_PACK_CHARS
(
'_'
,
'G'
,
'U'
,
'I'
),
GRANT_DATABUS_NAME
=
ZIPC_PACK_CHARS
(
'_'
,
'G'
,
'D'
,
'N'
),
DBINDER_OBITUARY_TRANSACTION
=
ZIPC_PACK_CHARS
(
'_'
,
'D'
,
'O'
,
'T'
),
DBINDER_INCREFS_TRANSACTION
=
ZIPC_PACK_CHARS
(
'_'
,
'D'
,
'I'
,
'T'
),
DBINDER_DECREFS_TRANSACTION
=
ZIPC_PACK_CHARS
(
'_'
,
'D'
,
'D'
,
'T'
),
DBINDER_ADD_COMMAUTH
=
ZIPC_PACK_CHARS
(
'_'
,
'D'
,
'A'
,
'C'
),
TRANS_SYNC
=
0
,
TRANS_ASYNC
=
1
,
};
enum
{
IF_PROT_BINDER
=
0
,
IF_PROT_DATABUS
=
1
,
};
#define SET_MAX_THREADS_DEFAULT 4
#define SET_MAX_THREADS_MAX 16
#define MAX_DEATH_CALLBACK_NUM 4
#if defined(__LITEOS_M__)
#define IF_PROT_DEFAULT IF_PROT_DATABUS
#else
#define IF_PROT_DEFAULT IF_PROT_BINDER
#endif
#endif
/* OHOS_IPC_RPC_TYPES_H */
\ No newline at end of file
ipc/native/c/manager/src/ipc_process_skeleton.c
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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_process_skeleton.h"
#include "ipc_skeleton.h"
#include "ipc_thread_pool.h"
#include "iremote_invoker.h"
#include "rpc_errno.h"
#include "rpc_log.h"
#include "rpc_os_adapter.h"
#include "rpc_types.h"
#include "securec.h"
#include "utils_list.h"
static
IpcSkeleton
*
g_ipcSkeleton
=
NULL
;
static
pthread_mutex_t
g_ipcSkeletonMutex
=
PTHREAD_MUTEX_INITIALIZER
;
static
SvcIdentity
g_samgrSvc
=
{.
handle
=
0
,
.
token
=
0
,
.
cookie
=
0
};
static
void
DeleteIpcSkeleton
(
IpcSkeleton
*
temp
)
{
if
(
temp
==
NULL
)
{
return
;
}
DeinitThreadPool
(
temp
->
threadPool
);
free
(
temp
);
}
static
IpcSkeleton
*
IpcProcessSkeleton
()
{
IpcSkeleton
*
temp
=
(
IpcSkeleton
*
)
calloc
(
1
,
sizeof
(
IpcSkeleton
));
if
(
temp
==
NULL
)
{
RPC_LOG_ERROR
(
"create ipc skeleton failed."
);
return
NULL
;
}
temp
->
threadPool
=
InitThreadPool
(
SET_MAX_THREADS_DEFAULT
);
if
(
temp
->
threadPool
==
NULL
)
{
free
(
temp
);
RPC_LOG_ERROR
(
"init thread pool failed."
);
return
NULL
;
}
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
==
NULL
)
{
DeleteIpcSkeleton
(
temp
);
RPC_LOG_ERROR
(
"get remote invoker failed."
);
return
NULL
;
}
if
((
invoker
->
SetMaxWorkThread
)(
SET_MAX_THREADS_DEFAULT
)
!=
ERR_NONE
)
{
DeleteIpcSkeleton
(
temp
);
RPC_LOG_ERROR
(
"init thread context failed."
);
return
NULL
;
}
UtilsListInit
(
&
temp
->
objects
);
pthread_mutex_init
(
&
temp
->
lock
,
NULL
);
return
temp
;
}
IpcSkeleton
*
GetCurrentSkeleton
(
void
)
{
if
(
g_ipcSkeleton
==
NULL
)
{
if
(
pthread_mutex_lock
(
&
g_ipcSkeletonMutex
)
!=
0
)
{
RPC_LOG_ERROR
(
"init ipc skeleton lock failed."
);
return
NULL
;
}
if
(
g_ipcSkeleton
==
NULL
)
{
IpcSkeleton
*
temp
=
IpcProcessSkeleton
();
if
(
temp
==
NULL
)
{
pthread_mutex_unlock
(
&
g_ipcSkeletonMutex
);
RPC_LOG_ERROR
(
"create binder connector failed."
);
return
NULL
;
}
g_ipcSkeleton
=
temp
;
}
pthread_mutex_unlock
(
&
g_ipcSkeletonMutex
);
}
return
g_ipcSkeleton
;
}
int32_t
SpawnThread
(
int32_t
policy
,
int32_t
proto
)
{
if
(
g_ipcSkeleton
==
NULL
||
g_ipcSkeleton
->
threadPool
==
NULL
)
{
RPC_LOG_ERROR
(
"ipc skeleton not init"
);
return
ERR_IPC_SKELETON_NOT_INIT
;
}
return
SpawnNewThread
(
g_ipcSkeleton
->
threadPool
,
policy
,
proto
);
}
int32_t
SetMaxWorkThread
(
int32_t
maxThreadNum
)
{
if
(
g_ipcSkeleton
==
NULL
||
g_ipcSkeleton
->
threadPool
==
NULL
)
{
RPC_LOG_ERROR
(
"ipc skeleton not init"
);
return
ERR_IPC_SKELETON_NOT_INIT
;
}
UpdateMaxThreadNum
(
g_ipcSkeleton
->
threadPool
,
maxThreadNum
);
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
!=
NULL
)
{
return
(
invoker
->
SetMaxWorkThread
)(
maxThreadNum
);
}
RPC_LOG_ERROR
(
"current thread context not init"
);
return
ERR_THREAD_INVOKER_NOT_INIT
;
}
void
JoinMainWorkThread
(
void
)
{
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
!=
NULL
)
{
(
invoker
->
JoinThread
)(
true
);
}
}
pid_t
ProcessGetCallingPid
(
void
)
{
ThreadContext
*
currentContext
=
GetCurrentThreadContext
();
if
(
currentContext
!=
NULL
)
{
return
currentContext
->
callerPid
;
}
return
RpcGetPid
();
}
pid_t
ProcessGetCallingUid
(
void
)
{
ThreadContext
*
currentContext
=
GetCurrentThreadContext
();
if
(
currentContext
!=
NULL
)
{
return
currentContext
->
callerUid
;
}
return
RpcGetUid
();
}
const
SvcIdentity
*
GetRegistryObject
(
void
)
{
return
&
g_samgrSvc
;
}
int32_t
SetRegistryObject
(
SvcIdentity
target
)
{
int32_t
ret
=
ERR_THREAD_INVOKER_NOT_INIT
;
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
!=
NULL
)
{
ret
=
(
invoker
->
SetRegistryObject
)();
}
if
(
ret
==
ERR_NONE
)
{
g_samgrSvc
.
handle
=
-
1
;
g_samgrSvc
.
cookie
=
target
.
cookie
;
}
return
ret
;
}
static
void
DeleteDeadHandle
(
int32_t
handle
)
{
if
(
pthread_mutex_lock
(
&
g_ipcSkeleton
->
lock
)
!=
0
)
{
RPC_LOG_ERROR
(
"Get ipc skeleton mutex failed."
);
return
;
}
DeathCallback
*
node
=
NULL
;
DeathCallback
*
next
=
NULL
;
bool
isValidHandle
=
false
;
UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE
(
node
,
next
,
&
g_ipcSkeleton
->
objects
,
DeathCallback
,
list
)
{
if
(
node
->
handle
==
handle
)
{
isValidHandle
=
true
;
UtilsListDelete
(
&
node
->
list
);
free
(
node
);
break
;
}
}
pthread_mutex_unlock
(
&
g_ipcSkeleton
->
lock
);
if
(
isValidHandle
)
{
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
!=
NULL
)
{
(
invoker
->
ReleaseHandle
)(
handle
);
}
}
}
int32_t
ProcessSendRequest
(
SvcIdentity
target
,
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
,
uintptr_t
*
buffer
)
{
int32_t
ret
=
ERR_THREAD_INVOKER_NOT_INIT
;
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
!=
NULL
)
{
ret
=
(
invoker
->
SendRequest
)(
target
,
code
,
data
,
reply
,
option
,
buffer
);
}
if
(
ret
==
ERR_DEAD_OBJECT
)
{
RPC_LOG_ERROR
(
"dead binder = %d now delete it"
,
target
.
handle
);
DeleteDeadHandle
(
target
.
handle
);
}
return
ret
;
}
int32_t
ProcessFreeBuffer
(
void
*
ptr
)
{
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
!=
NULL
)
{
return
(
invoker
->
FreeBuffer
)(
ptr
);
}
return
ERR_THREAD_INVOKER_NOT_INIT
;
}
static
bool
FirstAddObject
(
int32_t
handle
)
{
if
(
pthread_mutex_lock
(
&
g_ipcSkeleton
->
lock
)
!=
0
)
{
RPC_LOG_ERROR
(
"Get ipc skeleton mutex failed."
);
return
false
;
}
DeathCallback
*
node
=
NULL
;
DeathCallback
*
next
=
NULL
;
UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE
(
node
,
next
,
&
g_ipcSkeleton
->
objects
,
DeathCallback
,
list
)
{
if
(
node
->
handle
==
handle
)
{
RPC_LOG_INFO
(
"current handle already exist"
);
pthread_mutex_unlock
(
&
g_ipcSkeleton
->
lock
);
return
false
;
}
}
node
=
(
DeathCallback
*
)
calloc
(
1
,
sizeof
(
DeathCallback
));
if
(
node
==
NULL
)
{
pthread_mutex_unlock
(
&
g_ipcSkeleton
->
lock
);
return
false
;
}
node
->
handle
=
handle
;
node
->
deathNum
=
0
;
node
->
isRemoteDead
=
false
;
node
->
isNewHandler
=
true
;
pthread_mutex_init
(
&
node
->
lock
,
NULL
);
UtilsListAdd
(
&
g_ipcSkeleton
->
objects
,
&
node
->
list
);
pthread_mutex_unlock
(
&
g_ipcSkeleton
->
lock
);
return
true
;
}
static
void
OnFirstStrongRef
(
int32_t
handle
)
{
if
(
handle
<=
0
)
{
RPC_LOG_ERROR
(
"invalid handle."
);
return
;
}
if
(
FirstAddObject
(
handle
))
{
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
!=
NULL
)
{
(
invoker
->
AcquireHandle
)(
handle
);
}
}
}
static
uint32_t
SetDeathHandlerPair
(
DeathCallback
*
node
,
uint32_t
index
,
OnRemoteDead
func
,
void
*
args
)
{
node
->
handler
[
index
].
usedFlag
=
true
;
node
->
handler
[
index
].
func
=
func
;
node
->
handler
[
index
].
args
=
args
;
node
->
deathNum
++
;
return
index
;
}
int32_t
ProcessAddDeathRecipient
(
int32_t
handle
,
OnRemoteDead
deathFunc
,
void
*
args
,
uint32_t
*
cbId
)
{
int32_t
ret
=
ERR_INVALID_PARAM
;
if
(
g_ipcSkeleton
==
NULL
)
{
return
ERR_IPC_SKELETON_NOT_INIT
;
}
if
(
deathFunc
==
NULL
||
cbId
==
NULL
)
{
return
ERR_INVALID_PARAM
;
}
if
(
pthread_mutex_lock
(
&
g_ipcSkeleton
->
lock
)
!=
0
)
{
return
ERR_FAILED
;
}
DeathCallback
*
node
=
NULL
;
DeathCallback
*
next
=
NULL
;
bool
firstDeathNode
=
false
;
UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE
(
node
,
next
,
&
g_ipcSkeleton
->
objects
,
DeathCallback
,
list
)
{
if
(
node
->
handle
!=
handle
)
{
continue
;
}
if
(
node
->
isRemoteDead
)
{
pthread_mutex_unlock
(
&
g_ipcSkeleton
->
lock
);
return
ERR_DEAD_OBJECT
;
}
if
(
node
->
deathNum
==
MAX_DEATH_CALLBACK_NUM
)
{
pthread_mutex_unlock
(
&
g_ipcSkeleton
->
lock
);
return
ERR_INVALID_PARAM
;
}
(
void
)
pthread_mutex_lock
(
&
node
->
lock
);
for
(
int
i
=
0
;
i
<
MAX_DEATH_CALLBACK_NUM
;
i
++
)
{
if
(
!
node
->
handler
[
i
].
usedFlag
)
{
*
cbId
=
SetDeathHandlerPair
(
node
,
i
,
deathFunc
,
args
);
ret
=
ERR_NONE
;
break
;
}
}
pthread_mutex_unlock
(
&
node
->
lock
);
if
(
node
->
deathNum
==
1
&&
node
->
isNewHandler
)
{
firstDeathNode
=
true
;
node
->
isNewHandler
=
false
;
}
break
;
}
pthread_mutex_unlock
(
&
g_ipcSkeleton
->
lock
);
if
(
firstDeathNode
)
{
RPC_LOG_ERROR
(
"first add death callback for handle = %d."
,
handle
);
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
!=
NULL
)
{
ret
=
(
invoker
->
AddDeathRecipient
)(
handle
,
node
);
}
}
return
ret
;
}
int32_t
ProcessRemoveDeathRecipient
(
int32_t
handle
,
uint32_t
cbId
)
{
int32_t
ret
=
ERR_INVALID_PARAM
;
if
(
g_ipcSkeleton
==
NULL
)
{
return
ERR_IPC_SKELETON_NOT_INIT
;
}
if
(
cbId
>=
MAX_DEATH_CALLBACK_NUM
)
{
RPC_LOG_ERROR
(
"invalid callback id."
);
return
ERR_INVALID_PARAM
;
}
if
(
pthread_mutex_lock
(
&
g_ipcSkeleton
->
lock
)
!=
0
)
{
return
ERR_FAILED
;
}
DeathCallback
*
node
=
NULL
;
DeathCallback
*
next
=
NULL
;
UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE
(
node
,
next
,
&
g_ipcSkeleton
->
objects
,
DeathCallback
,
list
)
{
if
(
node
->
handle
!=
handle
)
{
continue
;
}
if
(
node
->
isRemoteDead
)
{
RPC_LOG_ERROR
(
"service is dead, delete it later."
);
pthread_mutex_unlock
(
&
g_ipcSkeleton
->
lock
);
return
ERR_DEAD_OBJECT
;
}
(
void
)
pthread_mutex_lock
(
&
node
->
lock
);
if
(
node
->
handler
[
cbId
].
usedFlag
)
{
node
->
handler
[
cbId
].
usedFlag
=
false
;
node
->
handler
[
cbId
].
func
=
NULL
;
node
->
deathNum
--
;
ret
=
ERR_NONE
;
}
(
void
)
pthread_mutex_unlock
(
&
node
->
lock
);
break
;
}
pthread_mutex_unlock
(
&
g_ipcSkeleton
->
lock
);
return
ret
;
}
int32_t
OnRemoteRequestInner
(
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
,
IpcObjectStub
*
objectStub
)
{
int32_t
result
=
ERR_NOT_RPC
;
if
(
result
==
ERR_NOT_RPC
)
{
if
(
objectStub
!=
NULL
&&
objectStub
->
func
!=
NULL
)
{
result
=
(
OnRemoteRequest
)(
objectStub
->
func
)(
code
,
data
,
reply
,
option
);
}
}
return
result
;
}
void
SendObituary
(
DeathCallback
*
deathCallback
)
{
int32_t
deathNum
=
deathCallback
->
deathNum
;
deathCallback
->
isRemoteDead
=
true
;
(
void
)
pthread_mutex_lock
(
&
deathCallback
->
lock
);
for
(
int
i
=
0
;
i
<
MAX_DEATH_CALLBACK_NUM
;
i
++
)
{
if
(
deathCallback
->
handler
[
i
].
usedFlag
&&
deathCallback
->
handler
[
i
].
func
!=
NULL
)
{
(
deathCallback
->
handler
[
i
].
func
)(
deathCallback
->
handler
[
i
].
args
);
}
}
pthread_mutex_unlock
(
&
deathCallback
->
lock
);
if
(
deathNum
>
0
)
{
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
!=
NULL
)
{
(
invoker
->
RemoveDeathRecipient
)(
deathCallback
->
handle
,
deathCallback
);
}
}
}
void
DeleteDeathCallback
(
DeathCallback
*
deathCallback
)
{
(
void
)
pthread_mutex_lock
(
&
g_ipcSkeleton
->
lock
);
DeathCallback
*
node
=
NULL
;
DeathCallback
*
next
=
NULL
;
bool
isValidDead
=
false
;
UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE
(
node
,
next
,
&
g_ipcSkeleton
->
objects
,
DeathCallback
,
list
)
{
if
(
node
==
deathCallback
)
{
isValidDead
=
true
;
break
;
}
}
pthread_mutex_unlock
(
&
g_ipcSkeleton
->
lock
);
if
(
!
isValidDead
)
{
RPC_LOG_ERROR
(
"invalid death node"
);
return
;
}
RemoteInvoker
*
invoker
=
GetRemoteInvoker
();
if
(
invoker
!=
NULL
)
{
(
invoker
->
ReleaseHandle
)(
deathCallback
->
handle
);
}
UtilsListDelete
(
&
deathCallback
->
list
);
pthread_mutex_destroy
(
&
deathCallback
->
lock
);
free
(
deathCallback
);
}
void
WaitForProxyInit
(
int32_t
handle
)
{
RPC_LOG_INFO
(
"ipc skeleton wait for proxy init"
);
OnFirstStrongRef
(
handle
);
}
\ No newline at end of file
ipc/native/c/manager/src/ipc_skeleton.c
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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_skeleton.h"
#include "ipc_process_skeleton.h"
#include "rpc_errno.h"
#include "rpc_log.h"
#include "rpc_types.h"
#include "securec.h"
#include "utils_list.h"
// default is 4 max is 16
int32_t
SetMaxWorkThreadNum
(
int32_t
maxThreadNum
)
{
if
(
GetCurrentSkeleton
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init ipc process skeleton failed."
);
return
ERR_IPC_SKELETON_NOT_INIT
;
}
if
((
maxThreadNum
<
SET_MAX_THREADS_DEFAULT
)
||
(
maxThreadNum
>
SET_MAX_THREADS_MAX
))
{
RPC_LOG_ERROR
(
"max thread num is invalid."
);
return
ERR_INVALID_PARAM
;
}
return
SetMaxWorkThread
(
maxThreadNum
);
}
// join current thread into work loop.
void
JoinWorkThread
(
void
)
{
if
(
GetCurrentSkeleton
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init ipc process skeleton failed."
);
return
;
}
return
JoinMainWorkThread
();
}
pid_t
GetCallingPid
(
void
)
{
if
(
GetCurrentSkeleton
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init ipc process skeleton failed."
);
return
ERR_IPC_SKELETON_NOT_INIT
;
}
return
ProcessGetCallingPid
();
}
pid_t
GetCallingUid
(
void
)
{
if
(
GetCurrentSkeleton
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init ipc process skeleton failed."
);
return
ERR_IPC_SKELETON_NOT_INIT
;
}
return
ProcessGetCallingUid
();
}
const
SvcIdentity
*
GetContextObject
(
void
)
{
if
(
GetCurrentSkeleton
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init ipc process skeleton failed."
);
return
NULL
;
}
return
GetRegistryObject
();
}
int32_t
SetContextObject
(
SvcIdentity
target
)
{
if
(
GetCurrentSkeleton
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init ipc process skeleton failed."
);
return
ERR_IPC_SKELETON_NOT_INIT
;
}
if
(
target
.
cookie
==
0
)
{
RPC_LOG_ERROR
(
"samgr stub func is NULL."
);
return
ERR_INVALID_PARAM
;
}
return
SetRegistryObject
(
target
);
}
int32_t
SendRequest
(
SvcIdentity
target
,
uint32_t
code
,
IpcIo
*
data
,
IpcIo
*
reply
,
MessageOption
option
,
uintptr_t
*
buffer
)
{
if
(
GetCurrentSkeleton
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init ipc process skeleton failed."
);
return
ERR_IPC_SKELETON_NOT_INIT
;
}
return
ProcessSendRequest
(
target
,
code
,
data
,
reply
,
option
,
buffer
);
}
int32_t
AddDeathRecipient
(
SvcIdentity
target
,
OnRemoteDead
deathFunc
,
void
*
args
,
uint32_t
*
cbId
)
{
if
(
GetCurrentSkeleton
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init ipc process skeleton failed."
);
return
ERR_IPC_SKELETON_NOT_INIT
;
}
if
(
target
.
handle
<
0
)
{
RPC_LOG_ERROR
(
"add death recipient is invalid handle."
);
return
ERR_INVALID_PARAM
;
}
return
ProcessAddDeathRecipient
(
target
.
handle
,
deathFunc
,
args
,
cbId
);
}
int32_t
RemoveDeathRecipient
(
SvcIdentity
target
,
uint32_t
cbId
)
{
if
(
GetCurrentSkeleton
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init ipc process skeleton failed."
);
return
ERR_IPC_SKELETON_NOT_INIT
;
}
if
(
target
.
handle
<
0
)
{
RPC_LOG_ERROR
(
"add death recipient is invalid handle."
);
return
ERR_INVALID_PARAM
;
}
return
ProcessRemoveDeathRecipient
(
target
.
handle
,
cbId
);
}
int32_t
FreeBuffer
(
void
*
ptr
)
{
if
(
ptr
==
NULL
)
{
RPC_LOG_ERROR
(
"ptr is null, no data to free"
);
return
ERR_INVALID_PARAM
;
}
if
(
GetCurrentSkeleton
()
==
NULL
)
{
RPC_LOG_ERROR
(
"init ipc process skeleton failed."
);
return
ERR_IPC_SKELETON_NOT_INIT
;
}
return
ProcessFreeBuffer
(
ptr
);
}
\ No newline at end of file
ipc/native/c/manager/src/ipc_thread_pool.c
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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_thread_pool.h"
#include <unistd.h>
#include "ipc_process_skeleton.h"
#include "iremote_invoker.h"
#include "rpc_errno.h"
#include "rpc_log.h"
#include "rpc_os_adapter.h"
#include "rpc_types.h"
#include "securec.h"
#define PROTO_NUM 2
static
pthread_key_t
g_localKey
=
-
1
;
static
RemoteInvoker
*
g_invoker
[
PROTO_NUM
];
ThreadContext
*
GetCurrentThreadContext
(
void
)
{
ThreadContext
*
current
=
NULL
;
void
*
curTLS
=
pthread_getspecific
(
g_localKey
);
if
(
curTLS
!=
NULL
)
{
current
=
(
ThreadContext
*
)
curTLS
;
}
else
{
current
=
(
ThreadContext
*
)
calloc
(
1
,
sizeof
(
ThreadContext
));
if
(
current
==
NULL
)
{
return
NULL
;
}
current
->
threadId
=
pthread_self
();
current
->
proto
=
IF_PROT_DEFAULT
;
current
->
callerPid
=
RpcGetPid
();
current
->
callerUid
=
RpcGetUid
();
pthread_setspecific
(
g_localKey
,
current
);
}
return
current
;
}
static
void
TlsDestructor
(
void
*
args
)
{
RPC_LOG_INFO
(
"thread exit, call tls destructor"
);
ThreadContext
*
threadContext
=
(
ThreadContext
*
)
args
;
RemoteInvoker
*
invoker
=
g_invoker
[
threadContext
->
proto
];
free
(
threadContext
);
if
(
invoker
!=
NULL
&&
invoker
->
ExitCurrentThread
!=
NULL
)
{
(
invoker
->
ExitCurrentThread
)();
}
}
static
void
ThreadContextDestructor
(
int32_t
proto
)
{
ThreadPool
*
threadPool
=
GetCurrentSkeleton
()
->
threadPool
;
pthread_mutex_lock
(
&
threadPool
->
lock
);
if
(
proto
==
IF_PROT_BINDER
)
{
++
threadPool
->
idleThreadNum
;
}
else
if
(
proto
==
IF_PROT_DATABUS
)
{
++
threadPool
->
idleSocketThreadNum
;
}
pthread_mutex_unlock
(
&
threadPool
->
lock
);
}
static
RemoteInvoker
*
GetAndUpdateInvoker
(
int32_t
proto
)
{
ThreadContext
*
threadContext
=
GetCurrentThreadContext
();
if
(
threadContext
==
NULL
)
{
return
NULL
;
}
threadContext
->
proto
=
proto
;
return
g_invoker
[
proto
];
}
static
void
*
ThreadHandler
(
void
*
args
)
{
ThreadContext
*
threadContext
=
(
ThreadContext
*
)
args
;
int32_t
proto
=
threadContext
->
proto
;
int32_t
policy
=
threadContext
->
policy
;
free
(
threadContext
);
threadContext
=
NULL
;
RemoteInvoker
*
invoker
=
GetAndUpdateInvoker
(
proto
);
if
(
invoker
!=
NULL
)
{
switch
(
policy
)
{
case
SPAWN_PASSIVE
:
invoker
->
JoinThread
(
false
);
break
;
case
SPAWN_ACTIVE
:
invoker
->
JoinThread
(
true
);
break
;
default:
break
;
}
}
ThreadContextDestructor
(
proto
);
return
NULL
;
}
ThreadPool
*
InitThreadPool
(
int32_t
maxThreadNum
)
{
ThreadPool
*
threadPool
=
(
ThreadPool
*
)
calloc
(
1
,
sizeof
(
ThreadPool
));
if
(
threadPool
==
NULL
)
{
return
NULL
;
}
threadPool
->
maxThreadNum
=
maxThreadNum
+
maxThreadNum
;
threadPool
->
idleThreadNum
=
maxThreadNum
;
threadPool
->
idleSocketThreadNum
=
maxThreadNum
;
pthread_mutex_init
(
&
threadPool
->
lock
,
NULL
);
pthread_key_create
(
&
g_localKey
,
TlsDestructor
);
for
(
int32_t
index
=
0
;
index
<
PROTO_NUM
;
++
index
)
{
g_invoker
[
index
]
=
InitRemoteInvoker
(
index
);
}
return
threadPool
;
}
void
DeinitThreadPool
(
ThreadPool
*
threadPool
)
{
if
(
threadPool
==
NULL
)
{
return
;
}
pthread_mutex_destroy
(
&
threadPool
->
lock
);
pthread_key_delete
(
g_localKey
);
free
(
threadPool
);
for
(
int32_t
index
=
0
;
index
<
PROTO_NUM
;
++
index
)
{
g_invoker
[
index
]
=
NULL
;
}
}
int32_t
SpawnNewThread
(
ThreadPool
*
threadPool
,
int32_t
policy
,
int32_t
proto
)
{
if
(
!
(
proto
==
IF_PROT_BINDER
&&
threadPool
->
idleThreadNum
>
0
)
&&
!
(
proto
==
IF_PROT_DATABUS
&&
threadPool
->
idleSocketThreadNum
>
0
))
{
RPC_LOG_ERROR
(
"thread pool is full."
);
return
ERR_INVALID_PARAM
;
}
pthread_t
threadId
;
if
(
pthread_mutex_lock
(
&
threadPool
->
lock
)
!=
0
)
{
RPC_LOG_ERROR
(
"get thread pool lock failed."
);
return
ERR_FAILED
;
}
ThreadContext
*
threadContext
=
(
ThreadContext
*
)
calloc
(
1
,
sizeof
(
ThreadContext
));
if
(
threadContext
==
NULL
)
{
pthread_mutex_unlock
(
&
threadPool
->
lock
);
RPC_LOG_ERROR
(
"create thread context failed."
);
return
ERR_FAILED
;
}
threadContext
->
proto
=
proto
;
threadContext
->
policy
=
policy
;
int
ret
=
pthread_create
(
&
threadId
,
NULL
,
ThreadHandler
,
threadContext
);
if
(
ret
!=
0
)
{
pthread_mutex_unlock
(
&
threadPool
->
lock
);
free
(
threadContext
);
RPC_LOG_ERROR
(
"spawn new thread failed."
);
return
ERR_FAILED
;
}
pthread_detach
(
threadId
);
if
(
proto
==
IF_PROT_BINDER
)
{
--
threadPool
->
idleThreadNum
;
}
else
if
(
proto
==
IF_PROT_DATABUS
)
{
--
threadPool
->
idleSocketThreadNum
;
}
pthread_mutex_unlock
(
&
threadPool
->
lock
);
return
ERR_NONE
;
}
void
UpdateMaxThreadNum
(
ThreadPool
*
threadPool
,
int32_t
maxThreadNum
)
{
int32_t
totalNum
=
maxThreadNum
+
maxThreadNum
;
int32_t
oldThreadNum
=
threadPool
->
maxThreadNum
;
if
(
totalNum
<=
oldThreadNum
)
{
RPC_LOG_ERROR
(
"not support set lower max thread num."
);
return
;
}
if
(
pthread_mutex_lock
(
&
threadPool
->
lock
)
!=
0
)
{
RPC_LOG_ERROR
(
"get thread pool lock failed."
);
return
;
}
int32_t
diff
=
totalNum
-
oldThreadNum
;
threadPool
->
maxThreadNum
=
totalNum
;
threadPool
->
idleThreadNum
+=
diff
/
PROTO_NUM
;
threadPool
->
idleSocketThreadNum
+=
diff
/
PROTO_NUM
;
pthread_mutex_unlock
(
&
threadPool
->
lock
);
}
RemoteInvoker
*
GetRemoteInvoker
(
void
)
{
ThreadContext
*
threadContext
=
GetCurrentThreadContext
();
if
(
threadContext
==
NULL
)
{
return
NULL
;
}
return
g_invoker
[
threadContext
->
proto
];
}
\ No newline at end of file
ipc/native/c/manager/src/iremote_invoker.c
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (C) 2021 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 "iremote_invoker.h"
#include "binder_invoker.h"
#include "rpc_types.h"
RemoteInvoker
*
InitRemoteInvoker
(
int32_t
proto
)
{
RemoteInvoker
*
remoteInvoker
=
NULL
;
if
(
proto
==
IF_PROT_BINDER
)
{
remoteInvoker
=
GetIpcInvoker
();
}
return
remoteInvoker
;
}
\ No newline at end of file
ipc/native/c/manager/src/rpc_log.c
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (c) 2021 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 "rpc_log.h"
#include <stdint.h>
#include "securec.h"
#define LOG_NAME_MAX_LEN 5
#define LOG_PRINT_MAX_LEN 256
typedef
struct
{
RpcLogModule
mod
;
char
name
[
LOG_NAME_MAX_LEN
];
}
LogInfo
;
static
LogInfo
g_logInfo
[
RPC_LOG_MODULE_MAX
]
=
{
{
RPC_LOG_IPC
,
"IPC"
},
{
RPC_LOG_RPC
,
"RPC"
},
{
RPC_LOG_SER
,
"SER"
},
};
static
void
RpcOutPrint
(
const
char
*
buf
,
RpcLogLevel
level
)
{
#ifdef IPCRPC_PRINTF
printf
(
"%s
\n
"
,
buf
);
return
;
#endif
switch
(
level
)
{
case
RPC_LOG_DBG
:
HILOG_DEBUG
(
RPC_HILOG_ID
,
"%{public}s"
,
buf
);
break
;
case
RPC_LOG_INFO
:
HILOG_INFO
(
RPC_HILOG_ID
,
"%{public}s"
,
buf
);
break
;
case
RPC_LOG_WARN
:
HILOG_WARN
(
RPC_HILOG_ID
,
"%{public}s"
,
buf
);
break
;
case
RPC_LOG_ERROR
:
HILOG_ERROR
(
RPC_HILOG_ID
,
"%{public}s"
,
buf
);
break
;
default:
break
;
}
}
void
RpcLog
(
RpcLogModule
module
,
RpcLogLevel
level
,
const
char
*
fmt
,
...)
{
int32_t
ulPos
;
char
szStr
[
LOG_PRINT_MAX_LEN
]
=
{
0
};
va_list
arg
;
int32_t
ret
;
if
(
module
>=
RPC_LOG_MODULE_MAX
||
level
>=
RPC_LOG_LEVEL_MAX
)
{
HILOG_ERROR
(
RPC_HILOG_ID
,
"rpc log type or module error"
);
return
;
}
ret
=
sprintf_s
(
szStr
,
sizeof
(
szStr
),
"[%s]"
,
g_logInfo
[
module
].
name
);
if
(
ret
<
0
)
{
HILOG_ERROR
(
RPC_HILOG_ID
,
"rpc log error"
);
return
;
}
ulPos
=
strlen
(
szStr
);
(
void
)
memset_s
(
&
arg
,
sizeof
(
va_list
),
0
,
sizeof
(
va_list
));
va_start
(
arg
,
fmt
);
ret
=
vsprintf_s
(
&
szStr
[
ulPos
],
sizeof
(
szStr
)
-
ulPos
,
fmt
,
arg
);
va_end
(
arg
);
if
(
ret
<
0
)
{
HILOG_ERROR
(
RPC_HILOG_ID
,
"rpc log len error"
);
return
;
}
RpcOutPrint
(
szStr
,
level
);
return
;
}
ipc/native/c/manager/src/serializer.c
0 → 100644
浏览文件 @
a92c8c65
/*
* Copyright (c) 2021 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 "serializer.h"
#include <stdlib.h>
#include <string.h>
#ifdef __LINUX__
#include "sys_binder.h"
#endif
#include "ipc_process_skeleton.h"
#include "rpc_log.h"
#include "securec.h"
#define MAX_IO_SIZE 8192UL
#define MAX_OBJ_NUM 32UL
#define ALIGN_SZ 4
#define IPC_IO_ALIGN(sz) (((sz) + ALIGN_SZ - 1) & (~(ALIGN_SZ - 1)))
#define IPC_IO_RETURN_IF_FAIL(value) \
do
{
\
if
(
!
(
value
))
{
\
printf
(
"IPC_CHECK failed: %s:%d
\n
"
,
__FUNCTION__
,
__LINE__
);
\
if
(
io
!=
NULL
)
{
\
io
->
flag
|=
IPC_IO_OVERFLOW
;
\
}
\
return
NULL
;
\
}
\
}
while
(
0
)
void
IpcIoInit
(
IpcIo
*
io
,
void
*
buffer
,
size_t
bufferSize
,
size_t
maxobjects
)
{
if
((
io
==
NULL
)
||
(
buffer
==
NULL
)
||
(
bufferSize
==
0
)
||
(
bufferSize
>
MAX_IO_SIZE
)
||
(
maxobjects
>
MAX_OBJ_NUM
))
{
return
;
}
size_t
objectsSize
=
maxobjects
*
sizeof
(
size_t
);
if
(
objectsSize
>
bufferSize
)
{
io
->
flag
=
IPC_IO_OVERFLOW
;
io
->
bufferLeft
=
0
;
io
->
offsetsLeft
=
0
;
return
;
}
io
->
bufferCur
=
io
->
bufferBase
=
(
char
*
)
buffer
+
objectsSize
;
io
->
offsetsCur
=
io
->
offsetsBase
=
(
size_t
*
)
buffer
;
io
->
bufferLeft
=
bufferSize
-
objectsSize
;
io
->
offsetsLeft
=
maxobjects
;
io
->
flag
=
IPC_IO_INITIALIZED
;
}
static
bool
IpcIoAvailable
(
IpcIo
*
io
)
{
bool
ret
=
false
;
if
(
io
!=
NULL
)
{
ret
=
(
io
->
flag
&
IPC_IO_INITIALIZED
)
&&
!
(
io
->
flag
&
IPC_IO_OVERFLOW
);
}
return
ret
;
}
static
void
*
IoPush
(
IpcIo
*
io
,
size_t
size
)
{
IPC_IO_RETURN_IF_FAIL
(
io
!=
NULL
);
IPC_IO_RETURN_IF_FAIL
(
IpcIoAvailable
(
io
));
size
=
IPC_IO_ALIGN
(
size
);
if
(
size
>
io
->
bufferLeft
)
{
io
->
flag
|=
IPC_IO_OVERFLOW
;
RPC_LOG_ERROR
(
"IoPush IPC_IO_OVERFLOW."
);
return
NULL
;
}
else
{
void
*
ptr
=
io
->
bufferCur
;
io
->
bufferCur
+=
size
;
io
->
bufferLeft
-=
size
;
return
ptr
;
}
}
static
void
*
IoPop
(
IpcIo
*
io
,
size_t
size
)
{
IPC_IO_RETURN_IF_FAIL
(
io
!=
NULL
);
IPC_IO_RETURN_IF_FAIL
(
IpcIoAvailable
(
io
));
size
=
IPC_IO_ALIGN
(
size
);
if
(
io
->
bufferLeft
<
size
)
{
io
->
bufferLeft
=
0
;
io
->
flag
|=
IPC_IO_OVERFLOW
;
return
NULL
;
}
else
{
void
*
ptr
=
io
->
bufferCur
;
io
->
bufferCur
+=
size
;
io
->
bufferLeft
-=
size
;
return
ptr
;
}
}
#ifdef __LINUX__
static
struct
flat_binder_object
*
IoPushBinderObj
(
IpcIo
*
io
)
{
IPC_IO_RETURN_IF_FAIL
(
io
!=
NULL
);
IPC_IO_RETURN_IF_FAIL
(
io
->
offsetsCur
!=
NULL
);
struct
flat_binder_object
*
ptr
=
NULL
;
ptr
=
IoPush
(
io
,
sizeof
(
struct
flat_binder_object
));
if
((
ptr
!=
NULL
)
&&
io
->
offsetsLeft
)
{
io
->
offsetsLeft
--
;
*
(
io
->
offsetsCur
)
=
(
char
*
)
ptr
-
(
char
*
)
io
->
bufferBase
;
io
->
offsetsCur
++
;
return
ptr
;
}
else
{
io
->
flag
|=
IPC_IO_OVERFLOW
;
return
NULL
;
}
}
static
bool
IpcIoPushObject
(
IpcIo
*
io
,
uint32_t
token
,
uint32_t
cookie
)
{
struct
flat_binder_object
*
ptr
=
IoPushBinderObj
(
io
);
if
(
ptr
==
NULL
)
{
RPC_LOG_ERROR
(
"Io push object IPC_IO_OVERFLOW."
);
return
false
;
}
ptr
->
flags
=
0x7f
|
FLAT_BINDER_FLAG_ACCEPTS_FDS
;
ptr
->
type
=
BINDER_TYPE_BINDER
;
ptr
->
binder
=
(
uintptr_t
)
cookie
;
ptr
->
cookie
=
cookie
;
return
true
;
}
static
bool
IpcIoPushRef
(
IpcIo
*
io
,
uint32_t
handle
,
uint32_t
cookie
)
{
struct
flat_binder_object
*
ptr
=
IoPushBinderObj
(
io
);
if
(
ptr
==
NULL
)
{
RPC_LOG_ERROR
(
"Io push ref IPC_IO_OVERFLOW."
);
return
false
;
}
ptr
->
flags
=
0x7f
|
FLAT_BINDER_FLAG_ACCEPTS_FDS
;
ptr
->
type
=
BINDER_TYPE_HANDLE
;
ptr
->
handle
=
handle
;
ptr
->
cookie
=
cookie
;
return
true
;
}
struct
flat_binder_object
*
IpcIoPopRef
(
IpcIo
*
io
)
{
IPC_IO_RETURN_IF_FAIL
(
io
!=
NULL
);
IPC_IO_RETURN_IF_FAIL
(
io
->
offsetsCur
!=
NULL
);
if
(
io
->
offsetsLeft
==
0
)
{
io
->
flag
|=
IPC_IO_OVERFLOW
;
return
NULL
;
}
struct
flat_binder_object
*
obj
=
(
struct
flat_binder_object
*
)
IoPop
(
io
,
sizeof
(
struct
flat_binder_object
));
if
(
obj
!=
NULL
)
{
io
->
offsetsCur
++
;
io
->
offsetsLeft
--
;
return
obj
;
}
return
NULL
;
}
bool
WriteRemoteObject
(
IpcIo
*
io
,
const
SvcIdentity
*
svc
)
{
if
(
io
==
NULL
||
svc
==
NULL
)
{
RPC_LOG_ERROR
(
"push io or svc is NULL ..."
);
return
false
;
}
bool
res
;
if
(
svc
->
handle
<=
0
)
{
res
=
IpcIoPushObject
(
io
,
svc
->
token
,
svc
->
cookie
);
}
else
{
res
=
IpcIoPushRef
(
io
,
svc
->
handle
,
svc
->
cookie
);
}
return
res
;
}
bool
ReadRemoteObject
(
IpcIo
*
io
,
SvcIdentity
*
svc
)
{
if
(
io
==
NULL
||
svc
==
NULL
)
{
return
false
;
}
struct
flat_binder_object
*
obj
=
IpcIoPopRef
(
io
);
if
(
obj
==
NULL
)
{
RPC_LOG_ERROR
(
"ReadRemoteObject failed: obj is null"
);
return
false
;
}
if
(
obj
->
type
==
BINDER_TYPE_BINDER
)
{
svc
->
token
=
obj
->
binder
;
svc
->
handle
=
MIN_BINDER_HANDLE
;
svc
->
cookie
=
obj
->
cookie
;
}
else
{
WaitForProxyInit
(
obj
->
handle
);
svc
->
handle
=
obj
->
handle
;
svc
->
cookie
=
obj
->
cookie
;
}
return
true
;
}
bool
WriteFileDescriptor
(
IpcIo
*
io
,
uint32_t
fd
)
{
if
(
io
==
NULL
)
{
RPC_LOG_ERROR
(
"push fd io is NULL."
);
return
false
;
}
struct
flat_binder_object
*
ptr
=
IoPushBinderObj
(
io
);
if
(
ptr
==
NULL
)
{
RPC_LOG_ERROR
(
"Io push fd IPC_IO_OVERFLOW.
\n
"
);
return
false
;
}
ptr
->
flags
=
0x7f
|
FLAT_BINDER_FLAG_ACCEPTS_FDS
;
ptr
->
type
=
BINDER_TYPE_FD
;
ptr
->
binder
=
0
;
ptr
->
cookie
=
1
;
ptr
->
handle
=
fd
;
return
true
;
}
int32_t
ReadFileDescriptor
(
IpcIo
*
io
)
{
if
(
io
==
NULL
)
{
return
-
1
;
}
struct
flat_binder_object
*
obj
=
IpcIoPopRef
(
io
);
if
(
obj
==
NULL
)
{
RPC_LOG_ERROR
(
"ReadFileDescriptor failed: obj is null"
);
return
-
1
;
}
if
(
obj
->
type
==
BINDER_TYPE_FD
)
{
return
obj
->
handle
;
}
RPC_LOG_ERROR
(
"ReadFileDescriptor failed: type:%d"
,
obj
->
type
);
return
-
1
;
}
#else
bool
WriteRemoteObject
(
IpcIo
*
io
,
const
SvcIdentity
*
svc
)
{
(
void
)
io
;
(
void
)
svc
;
return
false
;
}
bool
WriteFileDescriptor
(
IpcIo
*
io
,
uint32_t
fd
)
{
(
void
)
io
;
(
void
)
fd
;
return
false
;
}
bool
ReadRemoteObject
(
IpcIo
*
io
,
SvcIdentity
*
svc
)
{
(
void
)
io
;
(
void
)
svc
;
return
false
;
}
int32_t
ReadFileDescriptor
(
IpcIo
*
io
)
{
(
void
)
io
;
return
-
1
;
}
#endif
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录