!1484 新增devicedebug二进制,提供devicedebug命令

Merge pull request !1484 from 王达/feature/deviceDebug
This commit is contained in:
openharmony_ci 2024-10-23 06:10:41 +00:00 committed by Gitee
commit 69570cc861
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
19 changed files with 1014 additions and 20 deletions

View File

@ -79,6 +79,7 @@ group("appspawn_all") {
"${appspawn_path}/modules/module_engine:libappspawn_stub_empty",
]
deps += [ "service/hnp:hnp" ]
deps += [ "service/devicedebug:devicedebug" ]
if (appspawn_support_cj) { # for support cj appspawn
deps += [
":cjappspawn.rc",

View File

@ -106,6 +106,7 @@ typedef enum {
MSG_BEGET_SPAWNTIME,
MSG_UPDATE_MOUNT_POINTS,
MSG_RESTART_SPAWNER,
MSG_DEVICE_DEBUG,
MAX_TYPE_INVALID
} AppSpawnMsgType;

View File

@ -0,0 +1,40 @@
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//base/startup/appspawn/appspawn.gni")
import("//build/ohos.gni")
if (!defined(ohos_lite)) {
ohos_executable("devicedebug") {
include_dirs = [
"base",
"kill/include",
]
sources = [
"${appspawn_path}/service/devicedebug/devicedebug_main.c",
"${appspawn_path}/service/devicedebug/kill/src/devicedebug_kill.c",
]
configs = []
cflags = []
deps = [
"${appspawn_path}/interfaces/innerkits/client:appspawn_client",
"${appspawn_path}/util:libappspawn_util",
]
external_deps = [
"cJSON:cjson",
"hilog:libhilog",
]
install_enable = true
subsystem_name = "${subsystem_name}"
part_name = "${part_name}"
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DEVICEDEBUG_BASE_H
#define DEVICEDEBUG_BASE_H
#include "hilog/log.h"
#ifdef __cplusplus
extern "C" {
#endif
#undef LOG_TAG
#define LOG_TAG "APPSPAWN_DEVICEDEBUG"
#undef LOG_DOMAIN
#define LOG_DOMAIN (0xD002C00 + 0x11)
#ifndef APPSPAWN_TEST
#define APPSPAWN_STATIC static
#else
#define APPSPAWN_STATIC
#endif
/* 数字索引 */
enum {
DEVICEDEBUG_NUM_0 = 0,
DEVICEDEBUG_NUM_1,
DEVICEDEBUG_NUM_2,
DEVICEDEBUG_NUM_3,
DEVICEDEBUG_NUM_4,
DEVICEDEBUG_NUM_5,
DEVICEDEBUG_NUM_6,
DEVICEDEBUG_NUM_7
};
// 0x11 操作类型非法
#define DEVICEDEBUG_ERRNO_OPERATOR_TYPE_INVALID 0x11
// 0x12 参数缺失
#define DEVICEDEBUG_ERRNO_OPERATOR_ARGV_MISS 0x12
// 0x13 非开发者模式
#define DEVICEDEBUG_ERRNO_NOT_IN_DEVELOPER_MODE 0x13
// 0x14 创建json对象失败
#define DEVICEDEBUG_ERRNO_JSON_CREATED_FAILED 0x14
// 0x16 参数错误
#define DEVICEDEBUG_ERRNO_PARAM_INVALID 0x16
#define DEVICEDEBUG_LOGI(args, ...) \
HILOG_INFO(LOG_CORE, "[%{public}s:%{public}d]" args, (__FILE_NAME__), (__LINE__), ##__VA_ARGS__)
#define DEVICEDEBUG_LOGE(args, ...) \
HILOG_ERROR(LOG_CORE, "[%{public}s:%{public}d]" args, (__FILE_NAME__), (__LINE__), ##__VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "devicedebug_base.h"
#include "devicedebug_kill.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef int (*DEVICEDEBUG_CMD_PROCESS_FUNC)(int argc, char *argv[]);
typedef struct DeviceDebugManagerCmdInfoStru {
char *cmd;
DEVICEDEBUG_CMD_PROCESS_FUNC process;
} DeviceDebugManagerCmdInfo;
APPSPAWN_STATIC int DeviceDebugShowHelp(int argc, char *argv[])
{
(void)argc;
(void)argv;
printf("\r\nusage: devicedebug <command> <options>\r\n"
"\r\nThese are common devicedebug commands list:\r\n"
"\r\n help list available commands"
"\r\n kill send a signal to a process\r\n");
return 0;
}
DeviceDebugManagerCmdInfo g_deviceDebugManagerCmd[] = {
{"help", DeviceDebugShowHelp},
{"-h", DeviceDebugShowHelp},
{"kill", DeviceDebugCmdKill},
};
APPSPAWN_STATIC DeviceDebugManagerCmdInfo* DeviceDebugCmdCheck(const char *cmd)
{
int cmdNum = sizeof(g_deviceDebugManagerCmd) / sizeof(DeviceDebugManagerCmdInfo);
for (int i = 0; i < cmdNum; i++) {
if (!strcmp(cmd, g_deviceDebugManagerCmd[i].cmd)) {
return &g_deviceDebugManagerCmd[i];
}
}
return NULL;
}
int main(int argc, char *argv[])
{
int ret = 0;
DeviceDebugManagerCmdInfo *cmdInfo = NULL;
if (argc < DEVICEDEBUG_NUM_2) {
DeviceDebugShowHelp(argc, argv);
return DEVICEDEBUG_ERRNO_PARAM_INVALID;
}
DEVICEDEBUG_LOGI("devicedebug manager process start.");
/* 检验用户命令,获取对应的处理函数 */
cmdInfo = DeviceDebugCmdCheck(argv[DEVICEDEBUG_NUM_1]);
if (cmdInfo == NULL) {
DEVICEDEBUG_LOGE("invalid cmd!. cmd:%{public}s\r\n", argv[DEVICEDEBUG_NUM_1]);
return DEVICEDEBUG_ERRNO_OPERATOR_TYPE_INVALID;
}
/* 执行命令 */
ret = cmdInfo->process(argc, argv);
/* 返回值依赖此条log打印切勿随意修改 */
DEVICEDEBUG_LOGI("devicedebug manager process exit. ret=%{public}d \r\n", ret);
return ret;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DEVICEDEBUG_KILL_H
#define DEVICEDEBUG_KILL_H
#ifdef __cplusplus
extern "C" {
#endif
int DeviceDebugCmdKill(int argc, char *argv[]);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "appspawn.h"
#include "appspawn_utils.h"
#include "devicedebug_base.h"
#include "devicedebug_kill.h"
#include "cJSON.h"
#ifdef __cplusplus
extern "C" {
#endif
#define DEVICEDEBUG_KILL_CMD_NUM 4
#define DEVICEDEBUG_KILL_CMD_SIGNAL_INDEX 2
#define DEVICEDEBUG_KILL_CMD_PID_INDEX 3
APPSPAWN_STATIC void DeviceDebugShowKillHelp(void)
{
printf("\r\nusage: devicedebug kill [options] <pid>"
"\r\noptions list:"
"\r\n -h, --help list available commands"
"\r\n kill -<signal> <pid> send a signal to a process\r\n");
}
APPSPAWN_STATIC char* DeviceDebugJsonStringGeneral(int pid, const char *op, cJSON *args)
{
cJSON *root = cJSON_CreateObject();
if (root == NULL) {
DEVICEDEBUG_LOGE("devicedebug json write create root object unsuccess");
return NULL;
}
cJSON_AddNumberToObject(root, "app", pid);
cJSON_AddStringToObject(root, "op", op);
cJSON_AddItemToObject(root, "args", args);
char *jsonString = cJSON_Print(root);
cJSON_Delete(root);
return jsonString;
}
APPSPAWN_STATIC int DeviceDebugKill(int pid, int signal)
{
AppSpawnClientHandle clientHandle;
int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
if (ret != 0) {
DEVICEDEBUG_LOGE("devicedebug appspawn client init unsuccess, ret=%{public}d", ret);
return ret;
}
AppSpawnReqMsgHandle reqHandle;
ret = AppSpawnReqMsgCreate(MSG_DEVICE_DEBUG, "devicedebug", &reqHandle);
if (ret != 0) {
DEVICEDEBUG_LOGE("devicedebug appspawn message create unsuccess, ret=%{public}d", ret);
return ret;
}
cJSON *args = cJSON_CreateObject();
if (args == NULL) {
DEVICEDEBUG_LOGE("devicedebug json write create args object unsuccess");
return DEVICEDEBUG_ERRNO_JSON_CREATED_FAILED;
}
cJSON_AddNumberToObject(args, "signal", signal);
char *jsonString = DeviceDebugJsonStringGeneral(pid, "kill", args);
if (jsonString == NULL) {
cJSON_Delete(args);
return DEVICEDEBUG_ERRNO_JSON_CREATED_FAILED;
}
ret = AppSpawnReqMsgAddExtInfo(reqHandle, "devicedebug", (uint8_t *)jsonString, strlen(jsonString) + 1);
if (ret != 0) {
DEVICEDEBUG_LOGE("devicedebug appspawn message add devicedebug[%{public}s] unsuccess, ret=%{public}d",
jsonString, ret);
return ret;
}
AppSpawnResult result = {0};
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
AppSpawnClientDestroy(clientHandle);
if (ret != 0) {
DEVICEDEBUG_LOGE("devicedebug appspawn send msg unsuccess, ret=%{public}d", ret);
return ret;
}
if (result.result != 0) {
DEVICEDEBUG_LOGE("devicedebug appspawn kill process unsuccess, result=%{public}d", result.result);
return result.result;
}
return 0;
}
int DeviceDebugCmdKill(int argc, char *argv[])
{
if (!IsDeveloperModeOpen()) {
return DEVICEDEBUG_ERRNO_NOT_IN_DEVELOPER_MODE;
}
if (argc <= DEVICEDEBUG_NUM_2 || strcmp(argv[DEVICEDEBUG_NUM_2], "-h") == 0 ||
strcmp(argv[DEVICEDEBUG_NUM_2], "help") == 0) {
DeviceDebugShowKillHelp();
return 0;
}
if (argc < DEVICEDEBUG_KILL_CMD_NUM) {
DEVICEDEBUG_LOGE("devicedebug cmd operator num is %{public}d < %{public}d", argc, DEVICEDEBUG_KILL_CMD_NUM);
DeviceDebugShowKillHelp();
return DEVICEDEBUG_ERRNO_OPERATOR_ARGV_MISS;
}
int signal = atoi(argv[DEVICEDEBUG_KILL_CMD_SIGNAL_INDEX] + 1);
if (signal > SIGRTMAX || signal <= 0) {
DEVICEDEBUG_LOGE("signal is %{public}d > %{public}d", signal, SIGRTMAX);
DeviceDebugShowKillHelp();
return DEVICEDEBUG_ERRNO_PARAM_INVALID;
}
int pid = atoi(argv[DEVICEDEBUG_KILL_CMD_PID_INDEX]);
DEVICEDEBUG_LOGI("devicedebug cmd kill start signal[%{public}d], pid[%{public}d]", signal, pid);
return DeviceDebugKill(pid, signal);
}
#ifdef __cplusplus
}
#endif

View File

@ -72,6 +72,7 @@ ohos_executable("appspawn") {
}
external_deps = [
"cJSON:cjson",
"c_utils:utils",
"config_policy:configpolicy_util",
"hilog:libhilog",
@ -183,6 +184,7 @@ ohos_executable("cjappspawn") {
}
external_deps = [
"cJSON:cjson",
"c_utils:utils",
"config_policy:configpolicy_util",
"hilog:libhilog",
@ -253,6 +255,7 @@ ohos_executable("nativespawn") {
}
external_deps = [
"cJSON:cjson",
"c_utils:utils",
"config_policy:configpolicy_util",
"hilog:libhilog",

View File

@ -137,7 +137,7 @@ static int AppInfoCompareProc(ListNode *node, ListNode *newNode)
return node1->pid - node2->pid;
}
AppSpawnedProcess *AddSpawnedProcess(pid_t pid, const char *processName)
AppSpawnedProcess *AddSpawnedProcess(pid_t pid, const char *processName, bool isDebuggable)
{
APPSPAWN_CHECK(g_appSpawnMgr != NULL && processName != NULL, return NULL, "Invalid mgr or process name");
APPSPAWN_CHECK(pid > 0, return NULL, "Invalid pid for %{public}s", processName);
@ -150,6 +150,7 @@ AppSpawnedProcess *AddSpawnedProcess(pid_t pid, const char *processName)
node->max = 0;
node->uid = 0;
node->exitStatus = 0;
node->isDebuggable = isDebuggable;
int ret = strcpy_s(node->name, len, processName);
APPSPAWN_CHECK(ret == 0, free(node);
return NULL, "Failed to strcpy process name");

View File

@ -97,6 +97,7 @@ typedef struct TagAppSpawnedProcess {
#ifdef DEBUG_BEGETCTL_BOOT
AppSpawnMsgNode *message;
#endif
bool isDebuggable;
char name[0];
} AppSpawnedProcess;
@ -136,7 +137,7 @@ AppSpawnContent *GetAppSpawnContent(void);
*/
typedef void (*AppTraversal)(const AppSpawnMgr *mgr, AppSpawnedProcess *appInfo, void *data);
void TraversalSpawnedProcess(AppTraversal traversal, void *data);
AppSpawnedProcess *AddSpawnedProcess(pid_t pid, const char *processName);
AppSpawnedProcess *AddSpawnedProcess(pid_t pid, const char *processName, bool isDebuggable);
AppSpawnedProcess *GetSpawnedProcess(pid_t pid);
AppSpawnedProcess *GetSpawnedProcessByName(const char *name);
void TerminateSpawnedProcess(AppSpawnedProcess *node);

View File

@ -42,6 +42,7 @@
#include "parameter.h"
#include "appspawn_adapter.h"
#include "securec.h"
#include "cJSON.h"
#ifdef APPSPAWN_HISYSEVENT
#include "appspawn_hisysevent.h"
#endif
@ -52,6 +53,7 @@
#define PATH_SIZE 256
#define FD_PATH_SIZE 128
#define MAX_MEM_SIZE (4 * 1024)
#define APPSPAWN_MSG_USER_CHECK_COUNT 3
#define PREFORK_PROCESS "apppool"
#ifndef PIDFD_NONBLOCK
#define PIDFD_NONBLOCK O_NONBLOCK
@ -340,6 +342,28 @@ static int HandleRecvMessage(const TaskHandle taskHandle, uint8_t * buffer, int
return recvLen;
}
APPSPAWN_STATIC bool OnConnectionUserCheck(uid_t uid)
{
const uid_t uids[APPSPAWN_MSG_USER_CHECK_COUNT] = {
0, // root 0
3350, // app_fwk_update 3350
5523, // foundation 5523
};
for (int i = 0; i < APPSPAWN_MSG_USER_CHECK_COUNT; i++) {
if (uid == uids[i]) {
return true;
}
}
// shell 2000
if (uid == 2000 && IsDeveloperModeOpen()) {
return true;
}
return false;
}
static int OnConnection(const LoopHandle loopHandle, const TaskHandle server)
{
APPSPAWN_CHECK(server != NULL && loopHandle != NULL, return -1, "Error server");
@ -361,8 +385,7 @@ static int OnConnection(const LoopHandle loopHandle, const TaskHandle server)
struct ucred cred = {-1, -1, -1};
socklen_t credSize = sizeof(struct ucred);
if ((getsockopt(LE_GetSocketFd(stream), SOL_SOCKET, SO_PEERCRED, &cred, &credSize) < 0) ||
(cred.uid != DecodeUid("foundation") && cred.uid != DecodeUid("root")
&& cred.uid != DecodeUid("app_fwk_update"))) {
!OnConnectionUserCheck(cred.uid)) {
APPSPAWN_LOGE("Invalid uid %{public}d from client", cred.uid);
LE_CloseStreamTask(LE_GetDefaultLoop(), stream);
return -1;
@ -381,6 +404,27 @@ static int OnConnection(const LoopHandle loopHandle, const TaskHandle server)
return 0;
}
APPSPAWN_STATIC bool MsgDevicedebugCheck(TaskHandle stream, AppSpawnMsgNode *message)
{
struct ucred cred = {0, 0, 0};
socklen_t credSize = sizeof(cred);
if (getsockopt(LE_GetSocketFd(stream), SOL_SOCKET, SO_PEERCRED, &cred, &credSize) < 0) {
return false;
}
if (cred.uid != DecodeUid("shell")) {
return true;
}
AppSpawnMsg *msg = &message->msgHeader;
if (msg->msgType != MSG_DEVICE_DEBUG) {
APPSPAWN_LOGE("appspawn devicedebug msg type is not devicedebug [%{public}d]", msg->msgType);
return false;
}
return true;
}
static void OnReceiveRequest(const TaskHandle taskHandle, const uint8_t *buffer, uint32_t buffLen)
{
AppSpawnConnection *connection = (AppSpawnConnection *)LE_GetUserData(taskHandle);
@ -412,6 +456,10 @@ static void OnReceiveRequest(const TaskHandle taskHandle, const uint8_t *buffer,
LE_StopTimer(LE_GetDefaultLoop(), connection->receiverCtx.timer);
connection->receiverCtx.timer = NULL;
}
APPSPAWN_CHECK_ONLY_EXPER(MsgDevicedebugCheck(connection->stream, message),
LE_CloseTask(LE_GetDefaultLoop(), taskHandle); return);
// decode msg
ret = DecodeAppSpawnMsg(message);
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
@ -922,6 +970,24 @@ static void WaitChildTimeout(const TimerHandle taskHandle, void *context)
DeleteAppSpawningCtx(property);
}
static int ProcessChildFdCheck(int fd, AppSpawningCtx *property, int *pResult)
{
int result = 0;
(void)read(fd, &result, sizeof(result));
APPSPAWN_LOGI("Child process %{public}s success pid %{public}d appId: %{public}d result: %{public}d",
GetProcessName(property), property->pid, property->client.id, result);
APPSPAWN_CHECK(property->message != NULL, return -1, "Invalid message in ctx %{public}d", property->client.id);
if (result != 0) {
SendResponse(property->message->connection, &property->message->msgHeader, result, property->pid);
DeleteAppSpawningCtx(property);
return -1;
}
*pResult = result;
return 0;
}
#define MSG_EXT_NAME_MAX_DECIMAL 10
#define MSG_EXT_NAME 1
static void ProcessChildResponse(const WatcherHandle taskHandle, int fd, uint32_t *events, const void *context)
@ -931,18 +997,13 @@ static void ProcessChildResponse(const WatcherHandle taskHandle, int fd, uint32_
LE_RemoveWatcher(LE_GetDefaultLoop(), (WatcherHandle)taskHandle);
int result = 0;
(void)read(fd, &result, sizeof(result));
APPSPAWN_LOGI("Child process %{public}s success pid %{public}d appId: %{public}d result: %{public}d",
GetProcessName(property), property->pid, property->client.id, result);
APPSPAWN_CHECK(property->message != NULL, return, "Invalid message in ctx %{public}d", property->client.id);
if (result != 0) {
SendResponse(property->message->connection, &property->message->msgHeader, result, property->pid);
DeleteAppSpawningCtx(property);
if (ProcessChildFdCheck(fd, property, &result) != 0) {
return;
}
// success
AppSpawnedProcess *appInfo = AddSpawnedProcess(property->pid, GetBundleName(property));
bool isDebuggable = CheckAppMsgFlagsSet(property, APP_FLAGS_DEBUGGABLE) == 1 ? true : false;
AppSpawnedProcess *appInfo = AddSpawnedProcess(property->pid, GetBundleName(property), isDebuggable);
uint32_t len = 0;
char *pidMaxStr = NULL;
pidMaxStr = GetAppPropertyExt(property, MSG_EXT_NAME_MAX_CHILD_PROCCESS_MAX, &len);
@ -1278,7 +1339,7 @@ AppSpawnContent *StartSpawnService(const AppSpawnStartArg *startArg, uint32_t ar
#endif
AddAppSpawnHook(STAGE_CHILD_PRE_RUN, HOOK_PRIO_LOWEST, AppSpawnClearEnv);
if (arg->mode == MODE_FOR_APP_SPAWN) {
AddSpawnedProcess(pid, NWEBSPAWN_SERVER_NAME);
AddSpawnedProcess(pid, NWEBSPAWN_SERVER_NAME, false);
SetParameter("bootevent.appspawn.started", "true");
}
return content;
@ -1477,6 +1538,85 @@ static void ProcessSpawnRestartMsg(AppSpawnConnection *connection, AppSpawnMsgNo
APPSPAWN_LOGE("Failed to execv, ret %{public}d, errno %{public}d", ret, errno);
}
APPSPAWN_STATIC int AppspawpnDevicedebugKill(int pid, cJSON *args)
{
cJSON *signal = cJSON_GetObjectItem(args, "signal");
if (!cJSON_IsNumber(signal)) {
APPSPAWN_LOGE("appspawn devicedebug json get signal fail");
return -1;
}
AppSpawnedProcess *appInfo = GetSpawnedProcess(pid);
if (appInfo == NULL) {
APPSPAWN_LOGE("appspawn devicedebug get app info unsuccess, pid=%{public}d", pid);
return -1;
}
if (!appInfo->isDebuggable) {
APPSPAWN_LOGE("appspawn devicedebug process is not debuggable, pid=%{public}d", pid);
return -1;
}
APPSPAWN_LOGI("appspawn devicedebug debugable=%{public}d, pid=%{public}d, signal=%{public}d",
appInfo->isDebuggable, pid, signal->valueint);
if (kill(pid, signal->valueint) != 0) {
APPSPAWN_LOGE("appspawn devicedebug unable to kill process, pid: %{public}d ret %{public}d", pid, errno);
return -1;
}
return 0;
}
APPSPAWN_STATIC int AppspawnDevicedebugDeal(const char* op, int pid, cJSON *args)
{
if (strcmp(op, "kill") == 0) {
return AppspawpnDevicedebugKill(pid, args);
}
APPSPAWN_LOGE("appspawn devicedebug op:%{public}s invaild", op);
return -1;
}
APPSPAWN_STATIC int ProcessAppSpawnDeviceDebugMsg(AppSpawnMsgNode *message)
{
APPSPAWN_CHECK_ONLY_EXPER(message != NULL, return -1);
uint32_t len = 0;
const char* jsonString = (char *)GetAppSpawnMsgExtInfo(message, "devicedebug", &len);
if (jsonString == NULL || len == 0) {
APPSPAWN_LOGE("appspawn devicedebug get devicedebug fail");
return -1;
}
cJSON *json = cJSON_Parse(jsonString);
if (json == NULL) {
APPSPAWN_LOGE("appspawn devicedebug json parse fail");
return -1;
}
cJSON *app = cJSON_GetObjectItem(json, "app");
if (!cJSON_IsNumber(app)) {
APPSPAWN_LOGE("appspawn devicedebug json get app fail");
return -1;
}
cJSON *op = cJSON_GetObjectItem(json, "op");
if (!cJSON_IsString(op) || op->valuestring == NULL) {
APPSPAWN_LOGE("appspawn devicedebug json get op fail");
return -1;
}
cJSON *args = cJSON_GetObjectItem(json, "args");
if (!cJSON_IsObject(args)) {
APPSPAWN_LOGE("appspawn devicedebug json get args fail");
return -1;
}
return AppspawnDevicedebugDeal(op->valuestring, app->valueint, args);
}
static void ProcessRecvMsg(AppSpawnConnection *connection, AppSpawnMsgNode *message)
{
AppSpawnMsg *msg = &message->msgHeader;
@ -1521,6 +1661,11 @@ static void ProcessRecvMsg(AppSpawnConnection *connection, AppSpawnMsgNode *mess
case MSG_RESTART_SPAWNER:
ProcessSpawnRestartMsg(connection, message);
break;
case MSG_DEVICE_DEBUG:
ret = ProcessAppSpawnDeviceDebugMsg(message);
SendResponse(connection, msg, ret, 0);
DeleteAppSpawnMsg(message);
break;
default:
SendResponse(connection, msg, APPSPAWN_MSG_INVALID, 0);
DeleteAppSpawnMsg(message);

View File

@ -29,6 +29,7 @@ group("unittest") {
deps += [ "unittest/app_spawn_standard_test:AppSpawn_ut" ]
}
deps += [ "unittest/hnp_test:HnpTest" ]
deps += [ "unittest/devicedebug_test:DevicedebugTest" ]
} else {
testonly = true
deps = [ "unittest/app_spawn_lite_test:unittest" ]

View File

@ -124,7 +124,7 @@ HWTEST_F(AppSpawnAppMgrTest, App_Spawn_AppSpawnedProcess_001, TestSize.Level0)
int result[resultCount] = {0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0};
for (size_t i = 0; i < processNameCount; i++) {
for (size_t j = 0; j < pidCount; j++) {
AppSpawnedProcess *app = AddSpawnedProcess(pidInput[j], processNameInput[i]);
AppSpawnedProcess *app = AddSpawnedProcess(pidInput[j], processNameInput[i], false);
EXPECT_EQ(app != nullptr, result[i * pidCount + j]);
}
}
@ -167,7 +167,7 @@ HWTEST_F(AppSpawnAppMgrTest, App_Spawn_AppSpawnedProcess_002, TestSize.Level0)
int result[resultCount] = {0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0};
for (size_t i = 0; i < processNameCount; i++) {
for (size_t j = 0; j < pidCount; j++) {
AppSpawnedProcess *app = AddSpawnedProcess(pidInput[j], processNameInput[i]);
AppSpawnedProcess *app = AddSpawnedProcess(pidInput[j], processNameInput[i], false);
EXPECT_EQ(app != nullptr, result[i * pidCount + j]);
}
}
@ -205,7 +205,7 @@ HWTEST_F(AppSpawnAppMgrTest, App_Spawn_AppSpawnedProcess_003, TestSize.Level0)
// GetSpawnedProcessByName
size_t processNameCount = ARRAY_LENGTH(processNameInput);
for (size_t i = 0; i < processNameCount; i++) {
AppSpawnedProcess *app = AddSpawnedProcess(1000, processNameInput[i]); // 10000
AppSpawnedProcess *app = AddSpawnedProcess(1000, processNameInput[i], false); // 10000
EXPECT_EQ(app != nullptr, 1);
}
for (size_t i = 0; i < processNameCount; i++) {
@ -492,7 +492,7 @@ HWTEST_F(AppSpawnAppMgrTest, App_Spawn_AppSpawnMsgNode_005, TestSize.Level0)
EXPECT_EQ(memcmp(buffer.data() + sizeof(AppSpawnMsg), outMsg->buffer, msgLen - sizeof(AppSpawnMsg)), 0);
EXPECT_EQ(0, reminder);
AppSpawnedProcess *app = AddSpawnedProcess(9999999, "aaaa"); // 9999999 test
AppSpawnedProcess *app = AddSpawnedProcess(9999999, "aaaa", false); // 9999999 test
EXPECT_EQ(app != nullptr, 1);
TerminateSpawnedProcess(app);
AppSpawnExtData extData;
@ -540,7 +540,7 @@ HWTEST_F(AppSpawnAppMgrTest, App_Spawn_AppSpawnMsgNode_006, TestSize.Level0)
EXPECT_EQ(memcmp(buffer.data() + sizeof(AppSpawnMsg), outMsg->buffer, msgLen - sizeof(AppSpawnMsg)), 0);
EXPECT_EQ(0, reminder);
AppSpawnedProcess *app = AddSpawnedProcess(9999999, "aaaa"); // 9999999 test
AppSpawnedProcess *app = AddSpawnedProcess(9999999, "aaaa", false); // 9999999 test
EXPECT_EQ(app != nullptr, 1);
ret = DecodeAppSpawnMsg(outMsg);

View File

@ -183,7 +183,7 @@ HWTEST_F(AppSpawnModuleInterfaceTest, App_Spawn_Process_Hook_001, TestSize.Level
{
AppSpawnMgr *mgr = CreateAppSpawnMgr(MODE_FOR_NWEB_SPAWN);
EXPECT_EQ(mgr != nullptr, 1);
AppSpawnedProcess *app = AddSpawnedProcess(1000, "test-001");
AppSpawnedProcess *app = AddSpawnedProcess(1000, "test-001", false);
EXPECT_EQ(app != nullptr, 1);
int ret = 0;

View File

@ -31,6 +31,7 @@
#include "json_utils.h"
#include "parameter.h"
#include "securec.h"
#include "cJSON.h"
#include "app_spawn_stub.h"
#include "app_spawn_test_helper.h"
@ -547,6 +548,88 @@ HWTEST_F(AppSpawnServiceTest, App_Spawn_Msg_008, TestSize.Level0)
ASSERT_EQ(ret, 0);
}
HWTEST_F(AppSpawnServiceTest, App_Spawn_Msg_009, TestSize.Level0)
{
int ret = 0;
char pid[16];
AppSpawnClientHandle clientHandle = nullptr;
AppSpawnResult result = {};
do {
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
APPSPAWN_CHECK(ret == 0, break, "Failed to create client %{public}s", APPSPAWN_SERVER_NAME);
AppSpawnReqMsgHandle reqHandle = testServer->CreateMsg(clientHandle, MSG_SPAWN_NATIVE_PROCESS, 0);
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
APPSPAWN_CHECK(ret == 0, break, "Failed to send msg %{public}d", ret);
AppSpawnedProcess *app = GetSpawnedProcessByName(testServer->GetDefaultTestAppBundleName());
EXPECT_NE(app, nullptr);
AppSpawnReqMsgHandle reqHandle2;
ret = AppSpawnReqMsgCreate(MSG_DEVICE_DEBUG, "devicedebug", &reqHandle2);
EXPECT_GT(sprintf_s(pid, 16, "%d", app->pid), 0);
AppSpawnReqMsgAddStringInfo(reqHandle2, "signal", "-9");
AppSpawnReqMsgAddStringInfo(reqHandle2, "pid", pid);
ret = AppSpawnClientSendMsg(clientHandle, reqHandle2, &result);
APPSPAWN_CHECK(ret == 0 && result.result == 0, break, "Failed to send msg ret:%{public}d, result:%{public}d",
ret, result.result);
ASSERT_EQ(kill(app->pid, SIGKILL), 0);
} while (0);
AppSpawnClientDestroy(clientHandle);
ASSERT_EQ(ret, 0);
ASSERT_EQ(result.result, -1);
}
HWTEST_F(AppSpawnServiceTest, App_Spawn_Msg_010, TestSize.Level0)
{
int ret = 0;
AppSpawnClientHandle clientHandle = nullptr;
AppSpawnResult result = {};
do {
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
APPSPAWN_CHECK(ret == 0, break, "Failed to create client %{public}s", APPSPAWN_SERVER_NAME);
AppSpawnReqMsgHandle reqHandle = testServer->CreateMsg(clientHandle, MSG_SPAWN_NATIVE_PROCESS, 0);
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
APPSPAWN_CHECK(ret == 0, break, "Failed to send msg %{public}d", ret);
AppSpawnedProcess *app = GetSpawnedProcessByName(testServer->GetDefaultTestAppBundleName());
EXPECT_NE(app, nullptr);
AppSpawnReqMsgHandle reqHandle2;
ret = AppSpawnReqMsgCreate(MSG_DEVICE_DEBUG, "devicedebug", &reqHandle2);
cJSON *args = cJSON_CreateObject();
EXPECT_NE(args, nullptr);
cJSON_AddNumberToObject(args, "signal", 9);
cJSON *root = cJSON_CreateObject();
EXPECT_NE(root, nullptr);
cJSON_AddNumberToObject(root, "app", app->pid);
cJSON_AddStringToObject(root, "op", "kill");
cJSON_AddItemToObject(root, "args", args);
char *jsonString = cJSON_Print(root);
cJSON_Delete(root);
ret = AppSpawnReqMsgAddExtInfo(reqHandle2, "devicedebug", (uint8_t *)jsonString, strlen(jsonString) + 1);
ASSERT_EQ(ret, 0);
ret = AppSpawnClientSendMsg(clientHandle, reqHandle2, &result);
APPSPAWN_CHECK(ret == 0 && result.result == 0, break, "Failed to send msg ret:%{public}d, result:%{public}d",
ret, result.result);
} while (0);
AppSpawnClientDestroy(clientHandle);
ASSERT_EQ(ret, 0);
ASSERT_EQ(result.result, 0);
}
/**
* @brief kill nwebspawnappspawn的线程结束
*

View File

@ -0,0 +1,63 @@
# Copyright (c) 2021-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.
import("//base/startup/appspawn/appspawn.gni")
import("//build/test.gni")
if (!defined(ohos_lite)) {
ohos_unittest("DevicedebugTest") {
module_out_path = "${module_output_path}"
cflags = [
"-Wno-implicit-fallthrough",
"-Wno-unused-function",
"-Dprivate=public",
"-Dprotected=public",
]
cflags_cc = [
"-Wno-implicit-fallthrough",
"-fexceptions",
]
include_dirs = [
"${appspawn_path}/service/devicedebug/base",
"${appspawn_path}/service/devicedebug/kill/include",
"${appspawn_path}/test/unittest/devicedebug_test",
]
sources = [
"${appspawn_path}/service/devicedebug/kill/src/devicedebug_kill.c",
"${appspawn_path}/test/unittest/devicedebug_test/devicedebug_stub.c",
"devicedebug_kill_test.cpp",
]
defines = [
"IsDeveloperModeOpen=IsDeveloperModeOpenStub",
"AppSpawnClientInit=AppSpawnClientInitStub",
"AppSpawnReqMsgCreate=AppSpawnReqMsgCreateStub",
"AppSpawnReqMsgAddExtInfo=AppSpawnReqMsgAddExtInfoStub",
"AppSpawnClientSendMsg=AppSpawnClientSendMsgStub",
"APPSPAWN_TEST",
]
external_deps = [
"cJSON:cjson",
"hilog:libhilog",
]
deps = [
"${appspawn_path}/interfaces/innerkits/client:appspawn_client",
"${appspawn_path}/service/devicedebug:devicedebug",
"${appspawn_path}/util:libappspawn_util",
]
}
}

View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <csignal>
#include "devicedebug_base.h"
#include "devicedebug_kill.h"
#include "devicedebug_stub.h"
using namespace testing;
using namespace testing::ext;
namespace OHOS {
class DevicedebugKillTest : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
void SetUp();
void TearDown();
};
void DevicedebugKillTest::SetUpTestCase()
{
GTEST_LOG_(INFO) << "Devicedebug_Kill_TEST SetUpTestCase";
}
void DevicedebugKillTest::TearDownTestCase()
{
GTEST_LOG_(INFO) << "Devicedebug_Kill_TEST TearDownTestCase";
}
void DevicedebugKillTest::SetUp()
{
GTEST_LOG_(INFO) << "Devicedebug_Kill_TEST SetUp";
}
void DevicedebugKillTest::TearDown()
{
GTEST_LOG_(INFO) << "Devicedebug_Kill_TEST TearDown";
}
/**
* @tc.name: DevicedebugCmdKill_001
* @tc.desc: Verify develop mode and argc validate.
* @tc.type: FUNC
* @tc.require:issueIASN4F
* @tc.author:
*/
HWTEST_F(DevicedebugKillTest, DevicedebugCmdKill_001, TestSize.Level0)
{
GTEST_LOG_(INFO) << "DevicedebugCmdKill_001 test....";
{
int argc = 3;
char argv0[] = "devicedebug";
char argv1[] = "kill";
char argv2[] = "-9";
char* argv[] = {argv0, argv1, argv2};
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), DEVICEDEBUG_ERRNO_NOT_IN_DEVELOPER_MODE);
DeveloperModeOpenSet(1);
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), DEVICEDEBUG_ERRNO_OPERATOR_ARGV_MISS);
}
{
int argc = 2;
char argv0[] = "devicedebug";
char argv1[] = "-h";
char* argv[] = {argv0, argv1};
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), 0);
}
{
DeveloperModeOpenSet(1);
int argc = 3;
char argv0[] = "devicedebug";
char argv1[] = "kill";
char argv2[] = "-9";
char* argv[] = {argv0, argv1, argv2};
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), DEVICEDEBUG_ERRNO_OPERATOR_ARGV_MISS);
}
}
/**
* @tc.name: DevicedebugCmdKill_002
* @tc.desc: Verify signal validate.
* @tc.type: FUNC
* @tc.require:issueIASN4F
* @tc.author:
*/
HWTEST_F(DevicedebugKillTest, DevicedebugCmdKill_002, TestSize.Level0)
{
GTEST_LOG_(INFO) << "DevicedebugCmdKill_002 test....";
DeveloperModeOpenSet(1);
{
int argc = 4;
char argv0[] = "devicedebug";
char argv1[] = "kill";
char argv2[] = "-0";
char argv3[] = "12111";
char* argv[] = {argv0, argv1, argv2, argv3};
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), DEVICEDEBUG_ERRNO_PARAM_INVALID);
}
{
int argc = 4;
char argv0[] = "devicedebug";
char argv1[] = "kill";
char argv2[] = "-65";
char argv3[] = "12111";
char* argv[] = {argv0, argv1, argv2, argv3};
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), DEVICEDEBUG_ERRNO_PARAM_INVALID);
}
}
/**
* @tc.name: DevicedebugCmdKill_003
* @tc.desc: Verify devicedebug kill success.
* @tc.type: FUNC
* @tc.require:issueIASN4F
* @tc.author:
*/
HWTEST_F(DevicedebugKillTest, DevicedebugCmdKill_003, TestSize.Level0)
{
GTEST_LOG_(INFO) << "DevicedebugCmdKill_003 test....";
DeveloperModeOpenSet(1);
int argc = 4;
char argv0[] = "devicedebug";
char argv1[] = "kill";
char argv2[] = "-9";
char argv3[] = "12111";
char* argv[] = {argv0, argv1, argv2, argv3};
{
AppSpawnClientInitRetSet(-1);
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), -1);
}
AppSpawnClientInitRetSet(0);
{
AppSpawnReqMsgCreateRetSet(-2);
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), -2);
}
AppSpawnReqMsgCreateRetSet(0);
{
AppSpawnReqMsgAddExtInfoRetSet(-3);
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), -3);
}
AppSpawnReqMsgAddExtInfoRetSet(0);
{
AppSpawnClientSendMsgRetSet(-4);
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), -4);
}
AppSpawnClientSendMsgRetSet(0);
{
AppSpawnClientSendMsgResultSet(-5);
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), -5);
}
AppSpawnClientSendMsgResultSet(0);
{
EXPECT_EQ(DeviceDebugCmdKill(argc, argv), 0);
}
}
}

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "devicedebug_stub.h"
#include "appspawn.h"
#ifdef __cplusplus
extern "C" {
#endif
int g_isDeveloperModeOpen = 0;
void DeveloperModeOpenSet(int developerMode)
{
g_isDeveloperModeOpen = developerMode;
}
int IsDeveloperModeOpenStub()
{
return g_isDeveloperModeOpen;
}
int g_appSpawnClientInitRet = 0;
void AppSpawnClientInitRetSet(int appSpawnClientInitRet)
{
g_appSpawnClientInitRet = appSpawnClientInitRet;
}
int AppSpawnClientInitStub(const char *serviceName, AppSpawnClientHandle *handle)
{
(void)serviceName;
(void)handle;
return g_appSpawnClientInitRet;
}
int g_appSpawnReqMsgCreateRet = 0;
void AppSpawnReqMsgCreateRetSet(int appSpawnReqMsgCreateRet)
{
g_appSpawnReqMsgCreateRet = appSpawnReqMsgCreateRet;
}
int AppSpawnReqMsgCreateStub(AppSpawnMsgType msgType, const char *processName, AppSpawnReqMsgHandle *reqHandle)
{
(void)msgType;
(void)processName;
(void)reqHandle;
return g_appSpawnReqMsgCreateRet;
}
int g_appSpawnReqMsgAddExtInfoRet = 0;
void AppSpawnReqMsgAddExtInfoRetSet(int appSpawnReqMsgAddExtInfoRet)
{
g_appSpawnReqMsgAddExtInfoRet = appSpawnReqMsgAddExtInfoRet;
}
int AppSpawnReqMsgAddExtInfoStub(AppSpawnReqMsgHandle reqHandle, const char *name, const uint8_t *value,
uint32_t valueLen)
{
(void)reqHandle;
(void)name;
(void)value;
(void)valueLen;
return g_appSpawnReqMsgAddExtInfoRet;
}
int g_appSpawnClientSendMsgResulte = 0;
int g_appSpawnClientSendMsgRet = 0;
void AppSpawnClientSendMsgResultSet(int appSpawnClientSendMsgResult)
{
g_appSpawnClientSendMsgResulte = appSpawnClientSendMsgResult;
}
void AppSpawnClientSendMsgRetSet(int appSpawnClientSendMsgRet)
{
g_appSpawnClientSendMsgRet = appSpawnClientSendMsgRet;
}
int AppSpawnClientSendMsgStub(AppSpawnClientHandle handle, AppSpawnReqMsgHandle reqHandle, AppSpawnResult *result)
{
(void)handle;
(void)reqHandle;
result->result = g_appSpawnClientSendMsgResulte;
return g_appSpawnClientSendMsgRet;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DEVICEDEBUG_STUB_H
#define DEVICEDEBUG_STUB_H
#ifdef __cplusplus
extern "C" {
#endif
void DeveloperModeOpenSet(int developerMode);
void AppSpawnClientInitRetSet(int appSpawnClientInitRet);
void AppSpawnReqMsgCreateRetSet(int appSpawnClientSendMsgRet);
void AppSpawnReqMsgAddExtInfoRetSet(int appSpawnReqMsgAddExtInfoRet);
void AppSpawnClientSendMsgResultSet(int appSpawnClientSendMsgResult);
void AppSpawnClientSendMsgRetSet(int appSpawnClientSendMsgRet);
#ifdef __cplusplus
}
#endif
#endif