Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
Startup Init Lite
提交
2a67c7c4
S
Startup Init Lite
项目概览
OpenHarmony
/
Startup Init Lite
1 年多 前同步成功
通知
3
Star
37
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
Startup Init Lite
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
2a67c7c4
编写于
4月 08, 2023
作者:
O
openharmony_ci
提交者:
Gitee
4月 08, 2023
浏览文件
操作
浏览文件
下载
差异文件
!1884 需求:deviceinfo 按需停止
Merge pull request !1884 from cheng_jinsong/deviceinfo
上级
c5f976ea
4a2f9866
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
224 addition
and
8 deletion
+224
-8
device_info/BUILD.gn
device_info/BUILD.gn
+2
-0
device_info/device_info_kits.cpp
device_info/device_info_kits.cpp
+29
-1
device_info/device_info_kits.h
device_info/device_info_kits.h
+15
-0
device_info/device_info_stub.cpp
device_info/device_info_stub.cpp
+43
-0
device_info/idevice_info.h
device_info/idevice_info.h
+7
-3
test/moduletest/BUILD.gn
test/moduletest/BUILD.gn
+13
-0
test/moduletest/deviceinfo_moduleTest.cpp
test/moduletest/deviceinfo_moduleTest.cpp
+94
-0
test/moduletest/service_watcher_moduleTest.cpp
test/moduletest/service_watcher_moduleTest.cpp
+1
-1
test/moduletest/syspara_moduleTest.cpp
test/moduletest/syspara_moduleTest.cpp
+0
-1
test/unittest/deviceinfo/DeviceInfoUnittest.cpp
test/unittest/deviceinfo/DeviceInfoUnittest.cpp
+18
-0
test/unittest/param/watcher_agent_unittest.cpp
test/unittest/param/watcher_agent_unittest.cpp
+2
-2
未找到文件。
device_info/BUILD.gn
浏览文件 @
2a67c7c4
...
...
@@ -48,6 +48,7 @@ if (!defined(ohos_lite)) {
"INIT_AGENT",
"_GNU_SOURCE",
"USE_MBEDTLS",
"DINFO_TAG=\"DeviceInfoService\"",
]
deps = [
"//base/startup/init/interfaces/innerkits:libbegetutil",
...
...
@@ -60,6 +61,7 @@ if (!defined(ohos_lite)) {
"c_utils:utils",
"ipc:ipc_core",
"safwk:system_ability_fwk",
"samgr:samgr_proxy",
]
install_images = [ "system" ]
part_name = "init"
...
...
device_info/device_info_kits.cpp
浏览文件 @
2a67c7c4
...
...
@@ -50,14 +50,24 @@ void DeviceInfoKits::LoadDeviceInfoSa()
int32_t
ret
=
sam
->
LoadSystemAbility
(
SYSPARAM_DEVICE_SERVICE_ID
,
deviceInfoLoad
);
DINFO_CHECK
(
ret
==
ERR_OK
,
return
,
"LoadSystemAbility deviceinfo sa failed"
);
if
(
deathRecipient_
==
nullptr
)
{
deathRecipient_
=
new
DeathRecipient
();
}
// wait_for release lock and block until time out(60s) or match the condition with notice
auto
waitStatus
=
deviceInfoLoadCon_
.
wait_for
(
lock
,
std
::
chrono
::
milliseconds
(
DEVICEINFO_LOAD_SA_TIMEOUT_MS
),
[
this
]()
{
return
deviceInfoService_
!=
nullptr
;
});
if
(
!
waitStatus
)
{
if
(
!
waitStatus
||
deviceInfoService_
==
nullptr
)
{
// time out or loadcallback fail
DINFO_LOGE
(
"tokensync load sa timeout"
);
return
;
}
// for dead
auto
object
=
deviceInfoService_
->
AsObject
();
if
((
object
->
IsProxyObject
())
&&
(
!
object
->
AddDeathRecipient
(
deathRecipient_
)))
{
DINFO_LOGE
(
"Failed to add death recipient"
);
}
}
sptr
<
IDeviceInfo
>
DeviceInfoKits
::
GetService
()
...
...
@@ -97,5 +107,23 @@ int32_t DeviceInfoKits::GetSerialID(std::string& result)
DINFO_CHECK
(
deviceService
!=
nullptr
,
return
-
1
,
"Failed to get deviceinfo manager"
);
return
deviceService
->
GetSerialID
(
result
);
}
void
DeviceInfoKits
::
DeathRecipient
::
OnRemoteDied
(
const
wptr
<
IRemoteObject
>
&
remote
)
{
DelayedRefSingleton
<
DeviceInfoKits
>::
GetInstance
().
ResetService
(
remote
);
}
void
DeviceInfoKits
::
ResetService
(
const
wptr
<
IRemoteObject
>
&
remote
)
{
DINFO_LOGI
(
"Remote is dead, reset service instance"
);
std
::
lock_guard
<
std
::
mutex
>
lock
(
lock_
);
if
(
deviceInfoService_
!=
nullptr
)
{
sptr
<
IRemoteObject
>
object
=
deviceInfoService_
->
AsObject
();
if
((
object
!=
nullptr
)
&&
(
remote
==
object
))
{
object
->
RemoveDeathRecipient
(
deathRecipient_
);
deviceInfoService_
=
nullptr
;
}
}
}
}
// namespace device_info
}
// namespace OHOS
device_info/device_info_kits.h
浏览文件 @
2a67c7c4
...
...
@@ -33,12 +33,27 @@ public:
void
FinishStartSASuccess
(
const
sptr
<
IRemoteObject
>
&
remoteObject
);
void
FinishStartSAFailed
();
void
ResetService
(
const
wptr
<
IRemoteObject
>
&
remote
);
private:
// For death event procession
class
DeathRecipient
final
:
public
IRemoteObject
::
DeathRecipient
{
public:
DeathRecipient
(
void
)
=
default
;
~
DeathRecipient
(
void
)
final
=
default
;
DISALLOW_COPY_AND_MOVE
(
DeathRecipient
);
void
OnRemoteDied
(
const
wptr
<
IRemoteObject
>
&
remote
)
final
;
};
sptr
<
IRemoteObject
::
DeathRecipient
>
GetDeathRecipient
(
void
)
{
return
deathRecipient_
;
}
static
const
int
DEVICEINFO_LOAD_SA_TIMEOUT_MS
=
60000
;
void
LoadDeviceInfoSa
();
sptr
<
IDeviceInfo
>
GetService
();
std
::
mutex
lock_
;
std
::
condition_variable
deviceInfoLoadCon_
;
sptr
<
IRemoteObject
::
DeathRecipient
>
deathRecipient_
{};
sptr
<
IDeviceInfo
>
deviceInfoService_
{};
};
}
// namespace device_info
...
...
device_info/device_info_stub.cpp
浏览文件 @
2a67c7c4
...
...
@@ -15,14 +15,21 @@
#include "device_info_stub.h"
#include <chrono>
#include <signal.h>
#include <unistd.h>
#include "beget_ext.h"
#include "idevice_info.h"
#include "ipc_skeleton.h"
#include "accesstoken_kit.h"
#include "parcel.h"
#include "string_ex.h"
#include "if_system_ability_manager.h"
#include "iservice_registry.h"
#include "system_ability_definition.h"
#include "param_comm.h"
#include "parameter.h"
#include "sysparam_errno.h"
namespace
OHOS
{
...
...
@@ -32,6 +39,31 @@ using namespace Security::AccessToken;
namespace
device_info
{
REGISTER_SYSTEM_ABILITY_BY_ID
(
DeviceInfoService
,
SYSPARAM_DEVICE_SERVICE_ID
,
true
)
static
std
::
mutex
g_lock
;
static
time_t
g_lastTime
;
#ifndef STARTUP_INIT_TEST
static
const
int
DEVICE_INFO_EXIT_TIMEOUT_MS
=
60
;
#else
static
const
int
DEVICE_INFO_EXIT_TIMEOUT_MS
=
2
;
#endif
static
void
UnloadDeviceInfoSa
(
int
signo
)
{
std
::
unique_lock
<
std
::
mutex
>
lock
(
g_lock
);
time_t
currTime
;
(
void
)
time
(
&
currTime
);
if
(
difftime
(
currTime
,
g_lastTime
)
<
DEVICE_INFO_EXIT_TIMEOUT_MS
)
{
alarm
(
DEVICE_INFO_EXIT_TIMEOUT_MS
/
2
);
// 2 half
return
;
}
DINFO_LOGI
(
"DeviceInfoService::UnloadDeviceInfoSa"
);
auto
sam
=
SystemAbilityManagerClient
::
GetInstance
().
GetSystemAbilityManager
();
DINFO_CHECK
(
sam
!=
nullptr
,
return
,
"GetSystemAbilityManager return null"
);
int32_t
ret
=
sam
->
UnloadSystemAbility
(
SYSPARAM_DEVICE_SERVICE_ID
);
DINFO_CHECK
(
ret
==
ERR_OK
,
return
,
"UnLoadSystemAbility deviceinfo sa failed"
);
}
int32_t
DeviceInfoStub
::
OnRemoteRequest
(
uint32_t
code
,
MessageParcel
&
data
,
MessageParcel
&
reply
,
MessageOption
&
option
)
{
...
...
@@ -39,6 +71,11 @@ int32_t DeviceInfoStub::OnRemoteRequest(uint32_t code,
std
::
u16string
remoteDescriptor
=
data
.
ReadInterfaceToken
();
DINFO_CHECK
(
myDescriptor
==
remoteDescriptor
,
return
ERR_FAIL
,
"Invalid remoteDescriptor"
);
{
std
::
unique_lock
<
std
::
mutex
>
lock
(
g_lock
);
(
void
)
time
(
&
g_lastTime
);
}
int
ret
=
ERR_FAIL
;
switch
(
code
)
{
case
COMMAND_GET_UDID
:
{
...
...
@@ -97,16 +134,22 @@ int32_t DeviceInfoService::GetSerialID(std::string& result)
void
DeviceInfoService
::
OnStart
(
void
)
{
int
level
=
GetIntParameter
(
INIT_DEBUG_LEVEL
,
(
int
)
INIT_INFO
);
SetInitLogLevel
((
InitLogLevel
)
level
);
DINFO_LOGI
(
"DeviceInfoService OnStart"
);
bool
res
=
Publish
(
this
);
if
(
!
res
)
{
DINFO_LOGE
(
"DeviceInfoService Publish failed"
);
}
signal
(
SIGALRM
,
UnloadDeviceInfoSa
);
alarm
(
DEVICE_INFO_EXIT_TIMEOUT_MS
/
2
);
// 2 half
return
;
}
void
DeviceInfoService
::
OnStop
(
void
)
{
signal
(
SIGALRM
,
nullptr
);
DINFO_LOGI
(
"DeviceInfoService OnStop"
);
}
int
DeviceInfoService
::
Dump
(
int
fd
,
const
std
::
vector
<
std
::
u16string
>&
args
)
...
...
device_info/idevice_info.h
浏览文件 @
2a67c7c4
...
...
@@ -41,9 +41,13 @@ public:
#define DINFO_DOMAIN (BASE_DOMAIN + 8)
#endif
#define DINFO_LOGI(fmt, ...) STARTUP_LOGI(DINFO_DOMAIN, "DeviceInfoKits", fmt, ##__VA_ARGS__)
#define DINFO_LOGE(fmt, ...) STARTUP_LOGE(DINFO_DOMAIN, "DeviceInfoKits", fmt, ##__VA_ARGS__)
#define DINFO_LOGV(fmt, ...) STARTUP_LOGV(DINFO_DOMAIN, "DeviceInfoKits", fmt, ##__VA_ARGS__)
#ifndef DINFO_TAG
#define DINFO_TAG "DeviceInfoKits"
#endif
#define DINFO_LOGI(fmt, ...) STARTUP_LOGI(DINFO_DOMAIN, DINFO_TAG, fmt, ##__VA_ARGS__)
#define DINFO_LOGE(fmt, ...) STARTUP_LOGE(DINFO_DOMAIN, DINFO_TAG, fmt, ##__VA_ARGS__)
#define DINFO_LOGV(fmt, ...) STARTUP_LOGV(DINFO_DOMAIN, DINFO_TAG, fmt, ##__VA_ARGS__)
#define DINFO_CHECK(ret, exper, ...) \
if
(
!
(
ret
))
{
\
...
...
test/moduletest/BUILD.gn
浏览文件 @
2a67c7c4
...
...
@@ -27,6 +27,7 @@ ohos_shared_library("libparamtestmodule") {
"//base/startup/init/services/loopevent/include",
"//base/startup/init/services/param/include",
"//base/startup/init/ueventd/include",
"//base/startup/init/device_info",
"//third_party/cJSON",
"//third_party/bounds_checking_function/include",
]
...
...
@@ -56,11 +57,16 @@ ohos_moduletest("InitModuleTest") {
"test_utils.cpp",
]
if (enable_ohos_startup_init_feature_deviceinfo) {
sources += [ "deviceinfo_moduleTest.cpp" ]
}
include_dirs = [
"//base/startup/init/interfaces/innerkits/include",
"//base/startup/init/interfaces/innerkits/include/syspara",
"//base/startup/init/interfaces/innerkits/syspara",
"//base/startup/init/services/include/param",
"//base/startup/init/device_info",
".",
]
...
...
@@ -70,6 +76,13 @@ ohos_moduletest("InitModuleTest") {
"//third_party/bounds_checking_function:libsec_shared",
"//third_party/googletest:gtest_main",
]
external_deps = [
"c_utils:utils",
"hilog_native:libhilog_base",
"ipc:ipc_single",
"samgr:samgr_proxy",
]
}
group("moduletest") {
...
...
test/moduletest/deviceinfo_moduleTest.cpp
0 → 100644
浏览文件 @
2a67c7c4
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <thread>
#include <gtest/gtest.h>
#include <cstdint>
#include "if_system_ability_manager.h"
#include "iservice_registry.h"
#include "idevice_info.h"
#include "parameter.h"
#include "system_ability_definition.h"
#include "sysparam_errno.h"
using
namespace
std
;
using
namespace
testing
::
ext
;
using
namespace
OHOS
;
namespace
initModuleTest
{
class
DeviceInfoModuleTest
:
public
testing
::
Test
{
public:
static
void
SetUpTestCase
(
void
)
{};
static
void
TearDownTestCase
(
void
)
{};
void
SetUp
(
void
)
{};
void
TearDown
(
void
)
{};
};
HWTEST_F
(
DeviceInfoModuleTest
,
DeviceInfoGetUdid_001
,
TestSize
.
Level0
)
{
GTEST_LOG_
(
INFO
)
<<
"DeviceInfoGetUdid_001 start"
;
char
udid
[
65
]
=
{};
// 65 udid len
int
ret
=
AclGetDevUdid
(
udid
,
sizeof
(
udid
));
EXPECT_EQ
(
ret
,
SYSPARAM_PERMISSION_DENIED
);
sptr
<
ISystemAbilityManager
>
samgr
=
SystemAbilityManagerClient
::
GetInstance
().
GetSystemAbilityManager
();
BEGET_ERROR_CHECK
(
samgr
!=
nullptr
,
return
,
"Get samgr failed"
);
sptr
<
IRemoteObject
>
object
=
samgr
->
GetSystemAbility
(
SYSPARAM_DEVICE_SERVICE_ID
);
EXPECT_EQ
(
object
!=
nullptr
,
1
);
BEGET_ERROR_CHECK
(
object
!=
nullptr
,
return
,
"Get deviceinfo manager object from samgr failed"
);
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
seconds
(
80
));
// wait sa died 80s
object
=
samgr
->
GetSystemAbility
(
SYSPARAM_DEVICE_SERVICE_ID
);
EXPECT_EQ
(
object
==
nullptr
,
1
);
BEGET_ERROR_CHECK
(
object
==
nullptr
,
return
,
"Get deviceinfo manager object from samgr failed"
);
ret
=
AclGetDevUdid
(
udid
,
sizeof
(
udid
));
EXPECT_EQ
(
ret
,
SYSPARAM_PERMISSION_DENIED
);
object
=
samgr
->
GetSystemAbility
(
SYSPARAM_DEVICE_SERVICE_ID
);
EXPECT_EQ
(
object
!=
nullptr
,
1
);
GTEST_LOG_
(
INFO
)
<<
"DeviceInfoGetUdid_001 end"
;
}
HWTEST_F
(
DeviceInfoModuleTest
,
DeviceInfoGetSerial_001
,
TestSize
.
Level0
)
{
GTEST_LOG_
(
INFO
)
<<
"DeviceInfoGetSerial_001 start"
;
const
char
*
serial
=
AclGetSerial
();
EXPECT_EQ
(
serial
!=
nullptr
,
1
);
sptr
<
ISystemAbilityManager
>
samgr
=
SystemAbilityManagerClient
::
GetInstance
().
GetSystemAbilityManager
();
BEGET_ERROR_CHECK
(
samgr
!=
nullptr
,
return
,
"Get samgr failed"
);
sptr
<
IRemoteObject
>
object
=
samgr
->
GetSystemAbility
(
SYSPARAM_DEVICE_SERVICE_ID
);
EXPECT_EQ
(
object
!=
nullptr
,
1
);
BEGET_ERROR_CHECK
(
object
!=
nullptr
,
return
,
"Get deviceinfo manager object from samgr failed"
);
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
seconds
(
80
));
// wait sa died 80s
object
=
samgr
->
GetSystemAbility
(
SYSPARAM_DEVICE_SERVICE_ID
);
EXPECT_EQ
(
object
==
nullptr
,
1
);
BEGET_ERROR_CHECK
(
object
==
nullptr
,
return
,
"Get deviceinfo manager object from samgr failed"
);
serial
=
AclGetSerial
();
EXPECT_EQ
(
serial
!=
nullptr
,
1
);
object
=
samgr
->
GetSystemAbility
(
SYSPARAM_DEVICE_SERVICE_ID
);
EXPECT_EQ
(
object
!=
nullptr
,
1
);
GTEST_LOG_
(
INFO
)
<<
"DeviceInfoGetSerial_001 end"
;
}
}
\ No newline at end of file
test/moduletest/service_watcher_moduleTest.cpp
浏览文件 @
2a67c7c4
...
...
@@ -80,7 +80,7 @@ HWTEST_F(ServiceWatcherModuleTest, serviceWatcher_test_003, TestSize.Level0)
// start service
char
udid
[
65
]
=
{};
// 65 udid len
ret
=
AclGetDevUdid
(
udid
,
sizeof
(
udid
));
EXPECT_
EQ
(
ret
,
0
);
EXPECT_
NE
(
ret
,
0
);
auto
status1
=
GetServiceStatus
(
serviceName
);
EXPECT_TRUE
(
status1
==
"running"
);
// wait service exit
...
...
test/moduletest/syspara_moduleTest.cpp
浏览文件 @
2a67c7c4
...
...
@@ -413,7 +413,6 @@ HWTEST_F(SysparaModuleTest, Syspara_CacheParameter_test_001, TestSize.Level0)
CachedHandle
cacheHandle
=
CachedParameterCreate
(
name
,
"true"
);
EXPECT_NE
(
cacheHandle
,
nullptr
);
const
char
*
value
=
CachedParameterGet
(
cacheHandle
);
EXPECT_EQ
(
strcmp
(
value
,
"true"
),
0
);
int
ret
=
SetParameter
(
name
,
"false"
);
EXPECT_EQ
(
ret
,
0
);
...
...
test/unittest/deviceinfo/DeviceInfoUnittest.cpp
浏览文件 @
2a67c7c4
...
...
@@ -12,6 +12,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <chrono>
#include <thread>
#include <string>
#include <iostream>
#include <gtest/gtest.h>
...
...
@@ -87,6 +89,21 @@ HWTEST_F(DeviceInfoUnittest, DevInfoAgentTest, TestSize.Level1)
EXPECT_EQ
(
ret
,
SYSPARAM_PERMISSION_DENIED
);
}
HWTEST_F
(
DeviceInfoUnittest
,
DevInfoDiedTest
,
TestSize
.
Level1
)
{
sptr
<
ISystemAbilityManager
>
samgr
=
SystemAbilityManagerClient
::
GetInstance
().
GetSystemAbilityManager
();
DINFO_CHECK
(
samgr
!=
nullptr
,
return
,
"Get samgr failed"
);
sptr
<
IRemoteObject
>
object
=
samgr
->
GetSystemAbility
(
SYSPARAM_DEVICE_SERVICE_ID
);
DINFO_CHECK
(
object
!=
nullptr
,
return
,
"Get deviceinfo manager object from samgr failed"
);
OHOS
::
device_info
::
DeviceInfoKits
&
kits
=
OHOS
::
device_info
::
DeviceInfoKits
::
GetInstance
();
if
(
kits
.
GetDeathRecipient
()
!=
nullptr
)
{
kits
.
GetDeathRecipient
()
->
OnRemoteDied
(
object
);
}
std
::
string
serial
=
{};
int
ret
=
kits
.
GetSerialID
(
serial
);
EXPECT_EQ
(
ret
,
SYSPARAM_PERMISSION_DENIED
);
}
HWTEST_F
(
DeviceInfoUnittest
,
DevInfoAgentFail
,
TestSize
.
Level1
)
{
sptr
<
OHOS
::
device_info
::
DeviceInfoLoad
>
deviceInfoLoad
=
new
(
std
::
nothrow
)
OHOS
::
device_info
::
DeviceInfoLoad
();
...
...
@@ -148,6 +165,7 @@ HWTEST_F(DeviceInfoUnittest, DeviceInfoServiceTest, TestSize.Level1)
deviceInfoService
->
OnRemoteRequest
(
OHOS
::
device_info
::
IDeviceInfo
::
COMMAND_GET_SERIAL_ID
+
1
,
data
,
reply
,
option
);
deviceInfoService
->
OnRemoteRequest
(
OHOS
::
device_info
::
IDeviceInfo
::
COMMAND_GET_SERIAL_ID
+
1
,
data
,
reply
,
option
);
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
seconds
(
3
));
// wait sa unload 3s
deviceInfoService
->
GetUdid
(
result
);
deviceInfoService
->
GetSerialID
(
result
);
deviceInfoService
->
OnStop
();
...
...
test/unittest/param/watcher_agent_unittest.cpp
浏览文件 @
2a67c7c4
...
...
@@ -277,8 +277,8 @@ HWTEST_F(WatcherAgentUnitTest, TestWatcherService, TestSize.Level0)
const
char
*
errstr
=
"111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
;
ServiceWatchForStatus
(
"param_watcher"
,
TestWatcherCallBack
);
ServiceWaitForStatus
(
"param_watcher"
,
SERVICE_STARTED
,
1
);
EXPECT_
EQ
(
ServiceWatchForStatus
(
errstr
,
TestWatcherCallBack
),
-
1
);
EXPECT_
EQ
(
ServiceWatchForStatus
(
NULL
,
TestWatcherCallBack
),
-
1
);
EXPECT_
NE
(
ServiceWatchForStatus
(
errstr
,
TestWatcherCallBack
),
0
);
EXPECT_
NE
(
ServiceWatchForStatus
(
NULL
,
TestWatcherCallBack
),
0
);
WatchParameter
(
"testParam"
,
nullptr
,
nullptr
);
WatchParameter
(
nullptr
,
nullptr
,
nullptr
);
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录