mirror of
https://gitee.com/openharmony/startup_appspawn
synced 2024-11-23 07:00:17 +00:00
add appspawn sandbox and test code
Signed-off-by: zhongning5 <zhongning5@huawei.com>
This commit is contained in:
parent
fb1a87eda0
commit
3b62419de0
@ -97,7 +97,8 @@
|
||||
],
|
||||
"test": [
|
||||
"//base/startup/appspawn/test:moduletest",
|
||||
"//base/startup/appspawn/test:unittest"
|
||||
"//base/startup/appspawn/test:unittest",
|
||||
"//base/startup/appspawn/test:fuzztest"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
2
modules/ace_adapter/BUILD.gn
Executable file → Normal file
2
modules/ace_adapter/BUILD.gn
Executable file → Normal file
@ -28,7 +28,6 @@ ohos_shared_library("appspawn_ace") {
|
||||
deps = [
|
||||
"${appspawn_path}/modules/module_engine:libappspawn_module_engine",
|
||||
"${appspawn_path}/util:libappspawn_util",
|
||||
"//third_party/cJSON:cjson",
|
||||
]
|
||||
defines = []
|
||||
if (asan_detector || is_asan) {
|
||||
@ -41,6 +40,7 @@ ohos_shared_library("appspawn_ace") {
|
||||
"ability_runtime:runtime",
|
||||
"access_token:libtoken_setproc",
|
||||
"ace_engine:ace_forward_compatibility",
|
||||
"cJSON:cjson",
|
||||
"c_utils:utils",
|
||||
"common_event_service:cesfwk_innerkits",
|
||||
"config_policy:configpolicy_util",
|
||||
|
11
modules/ace_adapter/ace_adapter.cpp
Executable file → Normal file
11
modules/ace_adapter/ace_adapter.cpp
Executable file → Normal file
@ -24,6 +24,7 @@
|
||||
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "command_lexer.h"
|
||||
#include "config_policy_utils.h"
|
||||
@ -48,9 +49,9 @@ static const bool DEFAULT_PRELOAD_VALUE = true;
|
||||
#endif
|
||||
static const std::string PRELOAD_JSON_CONFIG("/appspawn_preload.json");
|
||||
|
||||
typedef struct TagAppSpawnSandboxCfg {
|
||||
typedef struct TagParseJsonContext {
|
||||
std::set<std::string> modules;
|
||||
} AppSpawnSandboxCfg;
|
||||
} ParseJsonContext;
|
||||
|
||||
static void GetModules(const cJSON *root, std::set<std::string> &modules)
|
||||
{
|
||||
@ -73,7 +74,7 @@ static void GetModules(const cJSON *root, std::set<std::string> &modules)
|
||||
}
|
||||
}
|
||||
|
||||
static int GetModuleSet(const cJSON *root, AppSpawnSandboxCfg *context)
|
||||
static int GetModuleSet(const cJSON *root, ParseJsonContext *context)
|
||||
{
|
||||
GetModules(root, context->modules);
|
||||
return 0;
|
||||
@ -92,8 +93,8 @@ static void PreloadModule(void)
|
||||
return;
|
||||
}
|
||||
|
||||
AppSpawnSandboxCfg context = {};
|
||||
(void)ParseSandboxConfig("etc/appspawn", PRELOAD_JSON_CONFIG.c_str(), GetModuleSet, &context);
|
||||
ParseJsonContext context = {};
|
||||
(void)ParseJsonConfig("etc/appspawn", PRELOAD_JSON_CONFIG.c_str(), GetModuleSet, &context);
|
||||
for (std::string moduleName : context.modules) {
|
||||
APPSPAWN_LOGI("moduleName %{public}s", moduleName.c_str());
|
||||
runtime->PreloadSystemModule(moduleName);
|
||||
|
0
modules/ace_adapter/command_lexer.cpp
Executable file → Normal file
0
modules/ace_adapter/command_lexer.cpp
Executable file → Normal file
0
modules/ace_adapter/command_lexer.h
Executable file → Normal file
0
modules/ace_adapter/command_lexer.h
Executable file → Normal file
0
modules/asan/BUILD.gn
Executable file → Normal file
0
modules/asan/BUILD.gn
Executable file → Normal file
1
modules/asan/asan_detector.c
Executable file → Normal file
1
modules/asan/asan_detector.c
Executable file → Normal file
@ -14,6 +14,7 @@
|
||||
*/
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_msg.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
7
modules/common/BUILD.gn
Executable file → Normal file
7
modules/common/BUILD.gn
Executable file → Normal file
@ -19,6 +19,7 @@ ohos_shared_library("appspawn_common") {
|
||||
"appspawn_adapter.cpp",
|
||||
"appspawn_cgroup.c",
|
||||
"appspawn_common.c",
|
||||
"appspawn_namespace.c",
|
||||
]
|
||||
include_dirs = [
|
||||
".",
|
||||
@ -26,14 +27,12 @@ ohos_shared_library("appspawn_common") {
|
||||
"${appspawn_path}/standard",
|
||||
]
|
||||
cflags = []
|
||||
deps = [
|
||||
"${appspawn_path}/modules/module_engine:libappspawn_module_engine",
|
||||
"//third_party/cJSON:cjson",
|
||||
]
|
||||
deps = [ "${appspawn_path}/modules/module_engine:libappspawn_module_engine" ]
|
||||
defines = [ "GRAPHIC_PERMISSION_CHECK" ]
|
||||
external_deps = [
|
||||
"access_token:libtoken_setproc",
|
||||
"access_token:libtokenid_sdk",
|
||||
"cJSON:cjson",
|
||||
"c_utils:utils",
|
||||
"hilog:libhilog",
|
||||
"init:libbegetutil",
|
||||
|
2
modules/common/appspawn_adapter.cpp
Executable file → Normal file
2
modules/common/appspawn_adapter.cpp
Executable file → Normal file
@ -17,6 +17,7 @@
|
||||
|
||||
#include "access_token.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "cJSON.h"
|
||||
#include "token_setproc.h"
|
||||
@ -164,5 +165,6 @@ int32_t SetEnvInfo(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
APPSPAWN_CHECK(ret == 0, break, "setenv failed, errno: %{public}d", errno);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
APPSPAWN_LOGV("SetEnvInfo success");
|
||||
return ret;
|
||||
}
|
||||
|
2
modules/common/appspawn_adapter.h
Executable file → Normal file
2
modules/common/appspawn_adapter.h
Executable file → Normal file
@ -16,6 +16,8 @@
|
||||
#ifndef APPSPAWN_ADPATER_CPP
|
||||
#define APPSPAWN_ADPATER_CPP
|
||||
|
||||
#include "appspawn_manager.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
1
modules/common/appspawn_cgroup.c
Executable file → Normal file
1
modules/common/appspawn_cgroup.c
Executable file → Normal file
@ -27,6 +27,7 @@
|
||||
|
||||
#include "appspawn_adapter.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "securec.h"
|
||||
|
||||
|
34
modules/common/appspawn_common.c
Executable file → Normal file
34
modules/common/appspawn_common.c
Executable file → Normal file
@ -40,6 +40,7 @@
|
||||
#include "appspawn_adapter.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_msg.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "init_param.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
@ -178,7 +179,9 @@ static void ClearEnvironment(const AppSpawnMgr *content, const AppSpawningCtx *p
|
||||
sigaddset(&mask, SIGTERM);
|
||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||
// close child fd
|
||||
close(property->forkCtx.fd[0]);
|
||||
AppSpawningCtx *ctx = (AppSpawningCtx *)property;
|
||||
close(ctx->forkCtx.fd[0]);
|
||||
ctx->forkCtx.fd[0] = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -425,39 +428,10 @@ static int SpawnGetSpawningFlag(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int PreLoadEnablePidNs(AppSpawnMgr *content)
|
||||
{
|
||||
APPSPAWN_LOGI("Enable pid namespace %{public}d %{public}d sandboxNsFlags: %{public}x",
|
||||
IsNWebSpawnMode(content), IsColdRunMode(content), content->content.sandboxNsFlags);
|
||||
if (IsNWebSpawnMode(content) || IsColdRunMode(content)) {
|
||||
return 0;
|
||||
}
|
||||
if (!(content->content.sandboxNsFlags & CLONE_NEWPID)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = unshare(CLONE_NEWPID);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "unshare CLONE_NWEPID failed, errno=%{public}d", errno);
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
setuid(PID_NS_INIT_UID);
|
||||
setgid(PID_NS_INIT_GID);
|
||||
#ifdef WITH_SELINUX
|
||||
setcon("u:r:pid_ns_init:s0");
|
||||
#endif
|
||||
char *argv[] = {"/system/bin/pid_ns_init", NULL};
|
||||
execve("/system/bin/pid_ns_init", argv, NULL);
|
||||
_exit(0x7f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
APPSPAWN_LOGV("Load common module ...");
|
||||
AddPreloadHook(HOOK_PRIO_COMMON, PreLoadSetSeccompFilter);
|
||||
AddPreloadHook(HOOK_PRIO_LOWEST, PreLoadEnablePidNs);
|
||||
|
||||
AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_HIGHEST, SpawnGetSpawningFlag);
|
||||
AddAppSpawnHook(STAGE_CHILD_PRE_COLDBOOT, HOOK_PRIO_HIGHEST, SpawnInitSpawningEnv);
|
||||
|
261
modules/common/appspawn_namespace.c
Normal file
261
modules/common/appspawn_namespace.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* 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 <dirent.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "appspawn_adapter.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "securec.h"
|
||||
#ifdef WITH_SELINUX
|
||||
#include "selinux/selinux.h"
|
||||
#endif
|
||||
|
||||
#define PID_NS_INIT_UID 100000 // reserved for pid_ns_init process, avoid app, render proc, etc.
|
||||
#define PID_NS_INIT_GID 100000
|
||||
|
||||
typedef struct {
|
||||
AppSpawnExtData extData;
|
||||
int nsSelfPidFd; // ns pid fd of appspawn
|
||||
int nsInitPidFd; // ns pid fd of pid_ns_init
|
||||
} AppSpawnNamespace;
|
||||
|
||||
static int AppSpawnExtDataCompareDataId(ListNode *node, void *data)
|
||||
{
|
||||
AppSpawnExtData *extData = (AppSpawnExtData *)ListEntry(node, AppSpawnExtData, node);
|
||||
return extData->dataId - *(uint32_t *)data;
|
||||
}
|
||||
|
||||
static AppSpawnNamespace *GetAppSpawnNamespace(const AppSpawnMgr *content)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return NULL);
|
||||
uint32_t dataId = EXT_DATA_NAMESPACE;
|
||||
ListNode *node = OH_ListFind(&content->extData, (void *)&dataId, AppSpawnExtDataCompareDataId);
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return (AppSpawnNamespace *)ListEntry(node, AppSpawnNamespace, extData);
|
||||
}
|
||||
|
||||
static void DeleteAppSpawnNamespace(AppSpawnNamespace *namespace)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(namespace != NULL, return);
|
||||
APPSPAWN_LOGV("DeleteAppSpawnNamespace");
|
||||
OH_ListRemove(&namespace->extData.node);
|
||||
OH_ListInit(&namespace->extData.node);
|
||||
|
||||
if (namespace->nsInitPidFd > 0) {
|
||||
close(namespace->nsInitPidFd);
|
||||
namespace->nsInitPidFd = -1;
|
||||
}
|
||||
if (namespace->nsSelfPidFd > 0) {
|
||||
close(namespace->nsSelfPidFd);
|
||||
namespace->nsSelfPidFd = -1;
|
||||
}
|
||||
free(namespace);
|
||||
}
|
||||
|
||||
static void FreeAppSpawnNamespace(struct TagAppSpawnExtData *data)
|
||||
{
|
||||
AppSpawnNamespace *namespace = ListEntry(data, AppSpawnNamespace, extData);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(namespace != NULL, return);
|
||||
DeleteAppSpawnNamespace(namespace);
|
||||
}
|
||||
|
||||
static AppSpawnNamespace *CreateAppSpawnNamespace(void)
|
||||
{
|
||||
APPSPAWN_LOGV("CreateAppSpawnNamespace");
|
||||
AppSpawnNamespace *namespace = (AppSpawnNamespace *)calloc(1, sizeof(AppSpawnNamespace));
|
||||
APPSPAWN_CHECK(namespace != NULL, return NULL, "Failed to create sandbox");
|
||||
namespace->nsInitPidFd = -1;
|
||||
namespace->nsSelfPidFd = -1;
|
||||
// ext data init
|
||||
OH_ListInit(&namespace->extData.node);
|
||||
namespace->extData.dataId = EXT_DATA_NAMESPACE;
|
||||
namespace->extData.freeNode = FreeAppSpawnNamespace;
|
||||
namespace->extData.dumpNode = NULL;
|
||||
return namespace;
|
||||
}
|
||||
|
||||
static pid_t GetPidByName(const char *name)
|
||||
{
|
||||
int pid = -1; // initial pid set to -1
|
||||
DIR *dir = opendir("/proc");
|
||||
if (dir == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (entry->d_type != DT_DIR) {
|
||||
continue;
|
||||
}
|
||||
long pidNum = strtol(entry->d_name, NULL, 10); // pid will not exceed a 10-digit decimal number
|
||||
if (pidNum <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char path[32]; // path that contains the process name
|
||||
if (snprintf_s(path, sizeof(path), sizeof(path) - 1, "/proc/%s/comm", entry->d_name) < 0) {
|
||||
continue;
|
||||
}
|
||||
FILE *file = fopen(path, "r");
|
||||
if (file == NULL) {
|
||||
continue;
|
||||
}
|
||||
char buffer[32]; // read the process name
|
||||
if (fgets(buffer, sizeof(buffer), file) == NULL) {
|
||||
(void)fclose(file);
|
||||
continue;
|
||||
}
|
||||
buffer[strcspn(buffer, "\n")] = 0;
|
||||
if (strcmp(buffer, name) != 0) {
|
||||
(void)fclose(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
APPSPAWN_LOGI("get pid of %{public}s success", name);
|
||||
pid = (int)pidNum;
|
||||
(void)fclose(file);
|
||||
break;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return pid;
|
||||
}
|
||||
|
||||
static int NsInitFunc()
|
||||
{
|
||||
setuid(PID_NS_INIT_UID);
|
||||
setgid(PID_NS_INIT_GID);
|
||||
setcon("u:r:pid_ns_init:s0");
|
||||
char *argv[] = {"/system/bin/pid_ns_init", NULL};
|
||||
execve("/system/bin/pid_ns_init", argv, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GetNsPidFd(pid_t pid)
|
||||
{
|
||||
char nsPath[256]; // filepath of ns pid
|
||||
int ret = snprintf_s(nsPath, sizeof(nsPath), sizeof(nsPath) - 1, "/proc/%d/ns/pid", pid);
|
||||
if (ret < 0) {
|
||||
APPSPAWN_LOGE("SetPidNamespace failed, snprintf_s error:%{public}s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
int nsFd = open(nsPath, O_RDONLY);
|
||||
if (nsFd < 0) {
|
||||
APPSPAWN_LOGE("open ns pid:%{public}d failed, err:%{public}s", pid, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return nsFd;
|
||||
}
|
||||
|
||||
static int PreLoadEnablePidNs(AppSpawnMgr *content)
|
||||
{
|
||||
APPSPAWN_LOGI("Enable pid namespace flags: 0x%{public}x", content->content.sandboxNsFlags);
|
||||
if (IsColdRunMode(content)) {
|
||||
return 0;
|
||||
}
|
||||
if (!(content->content.sandboxNsFlags & CLONE_NEWPID)) {
|
||||
return 0;
|
||||
}
|
||||
AppSpawnNamespace *namespace = CreateAppSpawnNamespace();
|
||||
APPSPAWN_CHECK(namespace != NULL, return -1, "Failed to create namespace");
|
||||
|
||||
#ifndef APPSPAWN_TEST
|
||||
int ret = 0;
|
||||
#else
|
||||
int ret = 0;
|
||||
#endif
|
||||
// check if process pid_ns_init exists, this is the init process for pid namespace
|
||||
pid_t pid = GetPidByName("pid_ns_init");
|
||||
if (pid == -1) {
|
||||
APPSPAWN_LOGI("Start Create pid_ns_init");
|
||||
pid = clone(NsInitFunc, NULL, CLONE_NEWPID, NULL);
|
||||
if (pid < 0) {
|
||||
APPSPAWN_LOGE("clone pid ns init failed");
|
||||
DeleteAppSpawnNamespace(namespace);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
APPSPAWN_LOGI("pid_ns_init exists, no need to create");
|
||||
}
|
||||
|
||||
namespace->nsSelfPidFd = GetNsPidFd(getpid());
|
||||
if (namespace->nsSelfPidFd < 0) {
|
||||
APPSPAWN_LOGE("open ns pid of appspawn fail");
|
||||
DeleteAppSpawnNamespace(namespace);
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace->nsInitPidFd = GetNsPidFd(pid);
|
||||
if (namespace->nsInitPidFd < 0) {
|
||||
APPSPAWN_LOGE("open ns pid of pid_ns_init fail");
|
||||
DeleteAppSpawnNamespace(namespace);
|
||||
return ret;
|
||||
}
|
||||
OH_ListAddTail(&namespace->extData.node, &content->extData);
|
||||
APPSPAWN_LOGI("Enable pid namespace success.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// after calling setns, new process will be in the same pid namespace of the input pid
|
||||
static int SetPidNamespace(int nsPidFd, int nsType)
|
||||
{
|
||||
APPSPAWN_LOGI("SetPidNamespace 0x%{public}x", nsType);
|
||||
if (setns(nsPidFd, nsType) < 0) {
|
||||
APPSPAWN_LOGE("set pid namespace nsType:%{pudblic}d failed", nsType);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int PreForkSetPidNamespace(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
AppSpawnNamespace *namespace = GetAppSpawnNamespace(content);
|
||||
if (namespace == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (content->content.sandboxNsFlags & CLONE_NEWPID) {
|
||||
SetPidNamespace(namespace->nsInitPidFd, CLONE_NEWPID); // pid_ns_init is the init process
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int PostForkSetPidNamespace(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
AppSpawnNamespace *namespace = GetAppSpawnNamespace(content);
|
||||
if (namespace == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (content->content.sandboxNsFlags & CLONE_NEWPID) {
|
||||
SetPidNamespace(namespace->nsSelfPidFd, 0); // go back to original pid namespace
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
AddPreloadHook(HOOK_PRIO_LOWEST, PreLoadEnablePidNs);
|
||||
AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_LOWEST, PreForkSetPidNamespace);
|
||||
AddAppSpawnHook(STAGE_PARENT_POST_FORK, HOOK_PRIO_HIGHEST, PostForkSetPidNamespace);
|
||||
}
|
0
modules/module_engine/BUILD.gn
Executable file → Normal file
0
modules/module_engine/BUILD.gn
Executable file → Normal file
91
modules/module_engine/include/appspawn_hook.h
Executable file → Normal file
91
modules/module_engine/include/appspawn_hook.h
Executable file → Normal file
@ -38,31 +38,32 @@ typedef struct AppSpawnClient AppSpawnClient;
|
||||
typedef struct TagAppSpawnedProcess AppSpawnedProcessInfo;
|
||||
|
||||
typedef enum {
|
||||
EXT_DATA_SANDBOX
|
||||
EXT_DATA_SANDBOX,
|
||||
EXT_DATA_NAMESPACE,
|
||||
} ExtDataType;
|
||||
|
||||
struct TagAppSpawnExtData;
|
||||
typedef void (*AppSpawnExtDataFree)(struct TagAppSpawnExtData *data);
|
||||
typedef void (*AppSpawnExtDataDump)(struct TagAppSpawnExtData *data);
|
||||
typedef void (*AppSpawnExtDataClear)(struct TagAppSpawnExtData *data);
|
||||
typedef struct TagAppSpawnExtData {
|
||||
ListNode node;
|
||||
uint32_t dataId;
|
||||
AppSpawnExtDataFree freeNode;
|
||||
AppSpawnExtDataClear clearNode;
|
||||
AppSpawnExtDataDump dumpNode;
|
||||
} AppSpawnExtData;
|
||||
|
||||
typedef enum TagAppSpawnHookStage {
|
||||
// run in init
|
||||
// 服务状态处理
|
||||
STAGE_SERVER_PRELOAD = 10,
|
||||
STAGE_SERVER_EXIT,
|
||||
// 应用状态处理
|
||||
STAGE_SERVER_APP_ADD,
|
||||
STAGE_SERVER_APP_DIED,
|
||||
|
||||
// run before fork
|
||||
STAGE_PARENT_PRE_FORK = 20,
|
||||
STAGE_PARENT_PRE_RELY = 21,
|
||||
STAGE_PARENT_POST_RELY = 22,
|
||||
STAGE_PARENT_POST_FORK = 21,
|
||||
STAGE_PARENT_PRE_RELY = 22,
|
||||
STAGE_PARENT_POST_RELY = 23,
|
||||
|
||||
// run in child process
|
||||
STAGE_CHILD_PRE_COLDBOOT = 30, // clear env, set token before cold boot
|
||||
@ -80,11 +81,72 @@ typedef enum TagAppSpawnHookPrio {
|
||||
HOOK_PRIO_LOWEST = 5000,
|
||||
} AppSpawnHookPrio;
|
||||
|
||||
typedef int (*PreloadHook)(AppSpawnMgr *content);
|
||||
/**
|
||||
* @brief 预加载处理函数
|
||||
*
|
||||
* @param content appspawn appspawn管理数据
|
||||
* @return int
|
||||
*/
|
||||
typedef int (*ServerStageHook)(AppSpawnMgr *content);
|
||||
|
||||
/**
|
||||
* @brief 应用孵化各阶段注册函数
|
||||
*
|
||||
* @param content appspawn appspawn管理数据
|
||||
* @param property 业务孵化数据
|
||||
* @return int
|
||||
*/
|
||||
typedef int (*AppSpawnHook)(AppSpawnMgr *content, AppSpawningCtx *property);
|
||||
|
||||
/**
|
||||
* @brief 业务进程变化注册函数
|
||||
*
|
||||
* @param content appspawn appspawn管理数据
|
||||
* @param appInfo 业务进程信息
|
||||
* @return int
|
||||
*/
|
||||
typedef int (*ProcessChangeHook)(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo);
|
||||
int AddPreloadHook(int prio, PreloadHook hook);
|
||||
|
||||
/**
|
||||
* @brief 添加服务阶段的处理函数
|
||||
*
|
||||
* @param stage 阶段信息
|
||||
* @param prio 优先级
|
||||
* @param hook 预加载处理函数
|
||||
* @return int
|
||||
*/
|
||||
int AddServerStageHook(AppSpawnHookStage stage, int prio, ServerStageHook hook);
|
||||
|
||||
/**
|
||||
* @brief 添加预加载处理函数
|
||||
*
|
||||
* @param prio 优先级
|
||||
* @param hook 预加载处理函数
|
||||
* @return int
|
||||
*/
|
||||
__attribute__((always_inline)) inline int AddPreloadHook(int prio, ServerStageHook hook)
|
||||
{
|
||||
return AddServerStageHook(STAGE_SERVER_PRELOAD, prio, hook);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 按阶段添加应用孵化处理函数
|
||||
*
|
||||
* @param stage 阶段信息
|
||||
* @param prio 优先级
|
||||
* @param hook 应用孵化阶段处理函数
|
||||
* @return int
|
||||
*/
|
||||
int AddAppSpawnHook(AppSpawnHookStage stage, int prio, AppSpawnHook hook);
|
||||
|
||||
/**
|
||||
* @brief 添加业务进程处理函数
|
||||
*
|
||||
* @param stage 阶段信息
|
||||
* @param prio 优先级
|
||||
* @param hook 业务进程变化处理函数
|
||||
* @return int
|
||||
*/
|
||||
int AddProcessMgrHook(AppSpawnHookStage stage, int prio, ProcessChangeHook hook);
|
||||
|
||||
typedef int (*ChildLoop)(AppSpawnContent *content, AppSpawnClient *client);
|
||||
@ -110,17 +172,6 @@ __attribute__((always_inline)) inline int CreateSandboxDir(const char *path, mod
|
||||
return MakeDirRec(path, mode, 1);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *originPath;
|
||||
const char *destinationPath;
|
||||
const char *fsType;
|
||||
unsigned long mountFlags;
|
||||
const char *options;
|
||||
mode_t mountSharedFlag;
|
||||
} MountArg;
|
||||
|
||||
int SandboxMountPath(const MountArg *arg);
|
||||
|
||||
// 扩展变量
|
||||
typedef struct TagSandboxContext SandboxContext;
|
||||
typedef struct TagVarExtraData VarExtraData;
|
||||
|
0
modules/module_engine/include/appspawn_msg.h
Executable file → Normal file
0
modules/module_engine/include/appspawn_msg.h
Executable file → Normal file
0
modules/module_engine/stub/libappspawn.stub.empty.json
Executable file → Normal file
0
modules/module_engine/stub/libappspawn.stub.empty.json
Executable file → Normal file
6
modules/module_engine/stub/libappspawn.stub.json
Executable file → Normal file
6
modules/module_engine/stub/libappspawn.stub.json
Executable file → Normal file
@ -1,5 +1,5 @@
|
||||
[
|
||||
{ "name": "AddPreloadHook" },
|
||||
{ "name": "AddServerStageHook" },
|
||||
{ "name": "AddProcessMgrHook" },
|
||||
{ "name": "AddAppSpawnHook" },
|
||||
{ "name": "AppSpawnHookExecute" },
|
||||
@ -10,10 +10,10 @@
|
||||
{ "name": "SetAppSpawnMsgFlag" },
|
||||
{ "name": "RegChildLooper" },
|
||||
{ "name": "MakeDirRec" },
|
||||
{ "name": "SandboxMountPath" },
|
||||
{ "name": "AddVariableReplaceHandler" },
|
||||
{ "name": "GetSpawnedProcess" },
|
||||
{ "name": "DumpAppSpawnMsg" },
|
||||
{ "name": "AppSpawnDump" },
|
||||
{ "name": "RegisterExpandSandboxCfgHandler" }
|
||||
{ "name": "RegisterExpandSandboxCfgHandler"},
|
||||
{ "name": "GetAppSpawnMgr" }
|
||||
]
|
||||
|
39
modules/modulemgr/appspawn_modulemgr.c
Executable file → Normal file
39
modules/modulemgr/appspawn_modulemgr.c
Executable file → Normal file
@ -16,6 +16,7 @@
|
||||
#include "appspawn_modulemgr.h"
|
||||
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "hookmgr.h"
|
||||
#include "modulemgr.h"
|
||||
@ -100,10 +101,10 @@ void DeleteAppSpawnHookMgr(void)
|
||||
g_appspawnHookMgr = NULL;
|
||||
}
|
||||
|
||||
static int PreloadHookRun(const HOOK_INFO *hookInfo, void *executionContext)
|
||||
static int ServerStageHookRun(const HOOK_INFO *hookInfo, void *executionContext)
|
||||
{
|
||||
AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
|
||||
PreloadHook realHook = (PreloadHook)hookInfo->hookCookie;
|
||||
ServerStageHook realHook = (ServerStageHook)hookInfo->hookCookie;
|
||||
return realHook((void *)arg->content);
|
||||
}
|
||||
|
||||
@ -125,8 +126,11 @@ static void PostHookExec(const HOOK_INFO *hookInfo, void *executionContext, int
|
||||
hookInfo->stage, hookInfo->prio, diff, executionRetVal);
|
||||
}
|
||||
|
||||
int PreloadHookExecute(AppSpawnContent *content)
|
||||
int ServerStageHookExecute(AppSpawnHookStage stage, AppSpawnContent *content)
|
||||
{
|
||||
APPSPAWN_CHECK(content != NULL, return APPSPAWN_ARG_INVALID, "Invalid content");
|
||||
APPSPAWN_CHECK((stage >= STAGE_SERVER_PRELOAD) && (stage <= STAGE_SERVER_EXIT),
|
||||
return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
|
||||
AppSpawnHookArg arg;
|
||||
arg.content = content;
|
||||
arg.client = NULL;
|
||||
@ -134,20 +138,22 @@ int PreloadHookExecute(AppSpawnContent *content)
|
||||
options.flags = TRAVERSE_STOP_WHEN_ERROR;
|
||||
options.preHook = PreHookExec;
|
||||
options.postHook = PostHookExec;
|
||||
int ret = HookMgrExecute(GetAppSpawnHookMgr(), STAGE_SERVER_PRELOAD, (void *)(&arg), &options);
|
||||
APPSPAWN_LOGI("Execute hook [%{public}d] result %{public}d", STAGE_SERVER_PRELOAD, ret);
|
||||
int ret = HookMgrExecute(GetAppSpawnHookMgr(), stage, (void *)(&arg), &options);
|
||||
APPSPAWN_LOGV("Execute hook [%{public}d] result %{public}d", stage, ret);
|
||||
return ret == ERR_NO_HOOK_STAGE ? 0 : ret;
|
||||
}
|
||||
|
||||
int AddPreloadHook(int prio, PreloadHook hook)
|
||||
int AddServerStageHook(AppSpawnHookStage stage, int prio, ServerStageHook hook)
|
||||
{
|
||||
APPSPAWN_CHECK(hook != NULL, return APPSPAWN_ARG_INVALID, "Invalid hook");
|
||||
APPSPAWN_CHECK((stage >= STAGE_SERVER_PRELOAD) && (stage <= STAGE_SERVER_EXIT),
|
||||
return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
|
||||
HOOK_INFO info;
|
||||
info.stage = STAGE_SERVER_PRELOAD;
|
||||
info.stage = stage;
|
||||
info.prio = prio;
|
||||
info.hook = PreloadHookRun;
|
||||
info.hook = ServerStageHookRun;
|
||||
info.hookCookie = (void *)hook;
|
||||
APPSPAWN_LOGI("AddPreloadHook prio: %{public}d", prio);
|
||||
APPSPAWN_LOGI("AddServerStageHook prio: %{public}d", prio);
|
||||
return HookMgrAddEx(GetAppSpawnHookMgr(), &info);
|
||||
}
|
||||
|
||||
@ -162,7 +168,7 @@ static void PreAppSpawnHookExec(const HOOK_INFO *hookInfo, void *executionContex
|
||||
{
|
||||
AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
|
||||
clock_gettime(CLOCK_MONOTONIC, &arg->tmStart);
|
||||
APPSPAWN_LOGI("Hook stage: %{public}d prio: %{public}d start", hookInfo->stage, hookInfo->prio);
|
||||
APPSPAWN_LOGV("Hook stage: %{public}d prio: %{public}d start", hookInfo->stage, hookInfo->prio);
|
||||
}
|
||||
|
||||
static void PostAppSpawnHookExec(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
|
||||
@ -170,13 +176,16 @@ static void PostAppSpawnHookExec(const HOOK_INFO *hookInfo, void *executionConte
|
||||
AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
|
||||
clock_gettime(CLOCK_MONOTONIC, &arg->tmEnd);
|
||||
uint64_t diff = DiffTime(&arg->tmStart, &arg->tmEnd);
|
||||
APPSPAWN_LOGI("Hook stage: %{public}d prio: %{public}d end time %{public}" PRId64 " ns result: %{public}d",
|
||||
APPSPAWN_LOGV("Hook stage: %{public}d prio: %{public}d end time %{public}" PRId64 " ns result: %{public}d",
|
||||
hookInfo->stage, hookInfo->prio, diff, executionRetVal);
|
||||
}
|
||||
|
||||
int AppSpawnHookExecute(AppSpawnHookStage stage, uint32_t flags, AppSpawnContent *content, AppSpawnClient *client)
|
||||
{
|
||||
APPSPAWN_CHECK(content != NULL && client != NULL, return APPSPAWN_ARG_INVALID, "Invalid arg");
|
||||
APPSPAWN_LOGV("Execute hook [%{public}d] for app: %{public}s", stage, GetProcessName((AppSpawningCtx *)client));
|
||||
APPSPAWN_CHECK((stage >= STAGE_PARENT_PRE_FORK) && (stage <= STAGE_CHILD_PRE_RUN),
|
||||
return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
|
||||
AppSpawnHookArg forkArg;
|
||||
forkArg.client = client;
|
||||
forkArg.content = content;
|
||||
@ -216,6 +225,8 @@ void AppSpawnEnvClear(AppSpawnContent *content, AppSpawnClient *client)
|
||||
int AddAppSpawnHook(AppSpawnHookStage stage, int prio, AppSpawnHook hook)
|
||||
{
|
||||
APPSPAWN_CHECK(hook != NULL, return APPSPAWN_ARG_INVALID, "Invalid hook");
|
||||
APPSPAWN_CHECK((stage >= STAGE_PARENT_PRE_FORK) && (stage <= STAGE_CHILD_PRE_RUN),
|
||||
return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
|
||||
HOOK_INFO info;
|
||||
info.stage = stage;
|
||||
info.prio = prio;
|
||||
@ -228,6 +239,10 @@ int AddAppSpawnHook(AppSpawnHookStage stage, int prio, AppSpawnHook hook)
|
||||
int ProcessMgrHookExecute(AppSpawnHookStage stage, const AppSpawnContent *content,
|
||||
const AppSpawnedProcessInfo *appInfo)
|
||||
{
|
||||
APPSPAWN_CHECK(content != NULL && appInfo != NULL, return APPSPAWN_ARG_INVALID, "Invalid hook");
|
||||
APPSPAWN_CHECK((stage >= STAGE_SERVER_APP_ADD) && (stage <= STAGE_SERVER_APP_DIED),
|
||||
return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
|
||||
|
||||
AppSpawnAppArg arg;
|
||||
arg.appInfo = appInfo;
|
||||
arg.content = content;
|
||||
@ -245,6 +260,8 @@ static int ProcessMgrHookRun(const HOOK_INFO *hookInfo, void *executionContext)
|
||||
int AddProcessMgrHook(AppSpawnHookStage stage, int prio, ProcessChangeHook hook)
|
||||
{
|
||||
APPSPAWN_CHECK(hook != NULL, return APPSPAWN_ARG_INVALID, "Invalid hook");
|
||||
APPSPAWN_CHECK((stage >= STAGE_SERVER_APP_ADD) && (stage <= STAGE_SERVER_APP_DIED),
|
||||
return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
|
||||
HOOK_INFO info;
|
||||
info.stage = stage;
|
||||
info.prio = prio;
|
||||
|
3
modules/modulemgr/appspawn_modulemgr.h
Executable file → Normal file
3
modules/modulemgr/appspawn_modulemgr.h
Executable file → Normal file
@ -49,9 +49,10 @@ int AppSpawnModuleMgrInstall(const char *mgrName);
|
||||
int AppSpawnLoadAutoRunModules(int type);
|
||||
void AppSpawnModuleMgrUnInstall(int type);
|
||||
void DeleteAppSpawnHookMgr(void);
|
||||
int PreloadHookExecute(AppSpawnContent *content);
|
||||
int ServerStageHookExecute(AppSpawnHookStage stage, AppSpawnContent *content);
|
||||
int ProcessMgrHookExecute(AppSpawnHookStage stage, const AppSpawnContent *content, const AppSpawnedProcessInfo *appInfo);
|
||||
int AppSpawnHookExecute(AppSpawnHookStage stage, uint32_t flags, AppSpawnContent *content, AppSpawnClient *client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
0
modules/nweb_adapter/BUILD.gn
Executable file → Normal file
0
modules/nweb_adapter/BUILD.gn
Executable file → Normal file
1
modules/nweb_adapter/nwebspawn_adapter.cpp
Executable file → Normal file
1
modules/nweb_adapter/nwebspawn_adapter.cpp
Executable file → Normal file
@ -28,6 +28,7 @@
|
||||
#endif
|
||||
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_manager.h"
|
||||
|
||||
#ifdef WITH_SECCOMP
|
||||
#include "seccomp_policy.h"
|
||||
|
3
modules/sandbox/BUILD.gn
Executable file → Normal file
3
modules/sandbox/BUILD.gn
Executable file → Normal file
@ -29,7 +29,6 @@ ohos_shared_library("appspawn_sandbox") {
|
||||
".",
|
||||
"${appspawn_path}/common",
|
||||
"${appspawn_path}/standard",
|
||||
"${appspawn_path}/modules//module_engine//include",
|
||||
]
|
||||
|
||||
configs = [ "${appspawn_path}:appspawn_config" ]
|
||||
@ -38,9 +37,9 @@ ohos_shared_library("appspawn_sandbox") {
|
||||
deps = [
|
||||
"${appspawn_path}/modules/module_engine:libappspawn_module_engine",
|
||||
"${appspawn_path}/util:libappspawn_util",
|
||||
"//third_party/cJSON:cjson",
|
||||
]
|
||||
external_deps = [
|
||||
"cJSON:cjson",
|
||||
"c_utils:utils",
|
||||
"hilog:libhilog",
|
||||
"init:libbegetutil",
|
||||
|
5
modules/sandbox/appspawn_mount_template.c
Executable file → Normal file
5
modules/sandbox/appspawn_mount_template.c
Executable file → Normal file
@ -36,7 +36,8 @@ default MS_BIND MS_REC
|
||||
rdonly MS_NODEV MS_RDONLY 只读挂载
|
||||
epfs epfs MS_NODEV 待讨论
|
||||
dac_override MS_NODEV MS_RDONLY "support_overwrite=1"
|
||||
开启const.filemanager.full_mount.enable fuse fuse MS_NOSUID MS_NODEV MS_NOEXEC MS_NOATIME MS_LAZYTIME
|
||||
开启const.filemanager.full_mount.enable
|
||||
fuse fuse MS_NOSUID MS_NODEV MS_NOEXEC MS_NOATIME MS_LAZYTIME
|
||||
dlp_fuse fuse MS_NOSUID MS_NODEV MS_NOEXEC MS_NOATIME MS_LAZYTIME 为dlpmanager管理应用专用的挂载参数
|
||||
shared MS_BIND MS_REC root
|
||||
namespace上是MS_SHARED方式挂载
|
||||
@ -182,6 +183,6 @@ void DumpMountPathMountNode(const PathMountNode *pathNode)
|
||||
APPSPAPWN_DUMP(" sandbox node options: %{public}s", tmp->options ? tmp->options : "null");
|
||||
APPSPAPWN_DUMP(" sandbox node fsType: %{public}s", tmp->fsType ? tmp->fsType : "null");
|
||||
DumpMode(" sandbox node destMode: ", pathNode->destMode);
|
||||
APPSPAPWN_DUMP(" sandbox node mountSharedFlag: %{public}s",
|
||||
APPSPAPWN_DUMP(" sandbox node config mountSharedFlag: %{public}s",
|
||||
pathNode->mountSharedFlag ? "MS_SHARED" : "MS_SLAVE");
|
||||
}
|
5
modules/sandbox/appspawn_permission.c
Executable file → Normal file
5
modules/sandbox/appspawn_permission.c
Executable file → Normal file
@ -52,6 +52,11 @@ static int PermissionNodeCompareProc(ListNode *node, ListNode *newNode)
|
||||
int AddSandboxPermissionNode(const char *name, SandboxQueue *queue)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(name != NULL && queue != NULL, return APPSPAWN_ARG_INVALID);
|
||||
APPSPAWN_LOGV("Add permission name %{public}s ", name);
|
||||
if (GetPermissionNodeInQueue(queue, name) != NULL) {
|
||||
APPSPAWN_LOGW("Permission name %{public}s has been exist", name);
|
||||
return 0;
|
||||
}
|
||||
#ifndef APPSPAWN_CLIENT
|
||||
size_t len = sizeof(SandboxPermissionNode);
|
||||
SandboxPermissionNode *node = (SandboxPermissionNode *)CreateSandboxSection(
|
||||
|
0
modules/sandbox/appspawn_permission.h
Executable file → Normal file
0
modules/sandbox/appspawn_permission.h
Executable file → Normal file
602
modules/sandbox/appspawn_sandbox.c
Executable file → Normal file
602
modules/sandbox/appspawn_sandbox.c
Executable file → Normal file
@ -15,8 +15,6 @@
|
||||
|
||||
#include "appspawn_sandbox.h"
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
@ -36,6 +34,11 @@
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
static inline void SetMountPathOperation(uint32_t *operation, uint32_t index)
|
||||
{
|
||||
*operation |= (1 << index);
|
||||
}
|
||||
|
||||
static inline bool CheckSpawningMsgFlagSet(const SandboxContext *context, uint32_t index)
|
||||
{
|
||||
APPSPAWN_CHECK(context->message != NULL, return false, "Invalid property for type %{public}u", TLV_MSG_FLAGS);
|
||||
@ -49,6 +52,86 @@ static inline bool CheckSpawningPermissionFlagSet(const SandboxContext *context,
|
||||
return CheckAppSpawnMsgFlag(context->message, TLV_PERMISSION, index);
|
||||
}
|
||||
|
||||
static void CheckDirRecursive(const char *path)
|
||||
{
|
||||
char buffer[PATH_MAX] = {0};
|
||||
const char slash = '/';
|
||||
const char *p = path;
|
||||
char *curPos = strchr(path, slash);
|
||||
while (curPos != NULL) {
|
||||
int len = curPos - p;
|
||||
p = curPos + 1;
|
||||
if (len == 0) {
|
||||
curPos = strchr(p, slash);
|
||||
continue;
|
||||
}
|
||||
int ret = memcpy_s(buffer, PATH_MAX, path, p - path - 1);
|
||||
APPSPAWN_CHECK(ret == 0, return, "Failed to copy path");
|
||||
ret = access(buffer, F_OK);
|
||||
APPSPAWN_CHECK(ret == 0, return, "Dir not exit %{public}s errno: %{public}d", buffer, errno);
|
||||
curPos = strchr(p, slash);
|
||||
}
|
||||
int ret = access(path, F_OK);
|
||||
APPSPAWN_CHECK(ret == 0, return, "Dir not exit %{public}s errno: %{public}d", buffer, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
int SandboxMountPath(const MountArg *arg)
|
||||
{
|
||||
APPSPAWN_CHECK(arg != NULL && arg->originPath != NULL && arg->destinationPath != NULL,
|
||||
return APPSPAWN_ARG_INVALID, "Invalid arg ");
|
||||
|
||||
APPSPAWN_LOGV("Bind mount arg: '%{public}s' '%{public}s' %{public}x '%{public}s' %{public}s => %{public}s",
|
||||
arg->fsType, arg->mountSharedFlag == MS_SHARED ? "MS_SHARED" : "MS_SLAVE",
|
||||
(uint32_t)arg->mountFlags, arg->options, arg->originPath, arg->destinationPath);
|
||||
|
||||
int ret = mount(arg->originPath, arg->destinationPath, arg->fsType, arg->mountFlags, arg->options);
|
||||
if (ret != 0) {
|
||||
if (arg->originPath != NULL && strstr(arg->originPath, "/data/app/el2/") != NULL) {
|
||||
CheckDirRecursive(arg->originPath);
|
||||
}
|
||||
APPSPAWN_LOGW("errno is: %{public}d, bind mount %{public}s => %{public}s",
|
||||
errno, arg->originPath, arg->destinationPath);
|
||||
return errno;
|
||||
}
|
||||
ret = mount(NULL, arg->destinationPath, NULL, arg->mountSharedFlag, NULL);
|
||||
if (ret != 0) {
|
||||
APPSPAWN_LOGW("errno is: %{public}d, bind mount %{public}s => %{public}s",
|
||||
errno, arg->originPath, arg->destinationPath);
|
||||
return errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int BuildRootPath(char *buffer, uint32_t bufferLen, const AppSpawnSandboxCfg *sandbox, uid_t uid)
|
||||
{
|
||||
int ret = 0;
|
||||
int len = 0;
|
||||
uint32_t currLen = 0;
|
||||
uint32_t userIdLen = sizeof(PARAMETER_USER_ID) - 1;
|
||||
uint32_t rootLen = strlen(sandbox->rootPath);
|
||||
char *rootPath = strstr(sandbox->rootPath, PARAMETER_USER_ID);
|
||||
if (rootPath == NULL) {
|
||||
len = sprintf_s(buffer, bufferLen, "%s/%d", sandbox->rootPath, uid);
|
||||
} else {
|
||||
ret = memcpy_s(buffer, bufferLen, sandbox->rootPath, rootPath - sandbox->rootPath);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to copy root path %{public}s", sandbox->rootPath);
|
||||
currLen = rootPath - sandbox->rootPath;
|
||||
|
||||
if (rootLen > (currLen + userIdLen)) {
|
||||
len = sprintf_s(buffer + currLen, bufferLen - currLen, "%d%s",
|
||||
uid, sandbox->rootPath + currLen + userIdLen);
|
||||
} else {
|
||||
len = sprintf_s(buffer + currLen, bufferLen - currLen, "%d", uid);
|
||||
}
|
||||
APPSPAWN_CHECK(len > 0 && (uint32_t)(len < (bufferLen - currLen)), return ret,
|
||||
"Failed to format root path %{public}s", sandbox->rootPath);
|
||||
currLen += (uint32_t)len;
|
||||
}
|
||||
buffer[currLen] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SandboxContext *g_sandboxContext = NULL;
|
||||
|
||||
SandboxContext *GetSandboxContext(void)
|
||||
@ -71,8 +154,6 @@ SandboxContext *GetSandboxContext(void)
|
||||
context->sandboxShared = false;
|
||||
context->message = NULL;
|
||||
context->rootPath = NULL;
|
||||
context->sandboxPackagePath = NULL;
|
||||
|
||||
g_sandboxContext = context;
|
||||
}
|
||||
return g_sandboxContext;
|
||||
@ -85,10 +166,6 @@ void DeleteSandboxContext(SandboxContext *context)
|
||||
free(context->rootPath);
|
||||
context->rootPath = NULL;
|
||||
}
|
||||
if (context->sandboxPackagePath) {
|
||||
free(context->sandboxPackagePath);
|
||||
context->sandboxPackagePath = NULL;
|
||||
}
|
||||
if (context == g_sandboxContext) {
|
||||
g_sandboxContext = NULL;
|
||||
}
|
||||
@ -116,6 +193,15 @@ static int InitSandboxContext(SandboxContext *context,
|
||||
context->sandboxShared = packageNode->section.sandboxShared;
|
||||
}
|
||||
context->message = property->message;
|
||||
// root path
|
||||
const char *rootPath = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, sandbox->rootPath, NULL, NULL);
|
||||
if (rootPath) {
|
||||
context->rootPath = strdup(rootPath);
|
||||
}
|
||||
if (context->rootPath == NULL) {
|
||||
DeleteSandboxContext(context);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -124,61 +210,43 @@ static VarExtraData *GetVarExtraData(const SandboxContext *context, const Sandbo
|
||||
static VarExtraData extraData;
|
||||
(void)memset_s(&extraData, sizeof(extraData), 0, sizeof(extraData));
|
||||
extraData.sandboxTag = GetSectionType(section);
|
||||
if (extraData.sandboxTag == SANDBOX_TAG_NAME_GROUP) {
|
||||
if (GetSectionType(section) == SANDBOX_TAG_NAME_GROUP) {
|
||||
SandboxNameGroupNode *groupNode = (SandboxNameGroupNode *)section;
|
||||
extraData.data.depNode = groupNode->depNode;
|
||||
}
|
||||
return &extraData;
|
||||
}
|
||||
|
||||
static int BuildPackagePath(SandboxContext *sandboxContext, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
const char *packagePath = GetSandboxRealVar(sandboxContext, BUFFER_FOR_SOURCE, sandbox->rootPath, NULL, NULL);
|
||||
if (packagePath) {
|
||||
sandboxContext->sandboxPackagePath = strdup(packagePath);
|
||||
}
|
||||
APPSPAWN_CHECK(sandboxContext->sandboxPackagePath != NULL,
|
||||
return APPSPAWN_SYSTEM_ERROR, "Failed to format path app: %{public}s", sandboxContext->bundleName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int BuildRootPath(SandboxContext *context, const AppSpawnSandboxCfg *sandbox, const SandboxSection *section)
|
||||
{
|
||||
const char *rootPath = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, sandbox->rootPath, NULL, NULL);
|
||||
if (rootPath) {
|
||||
context->rootPath = strdup(rootPath);
|
||||
}
|
||||
APPSPAWN_CHECK(context->rootPath != NULL, return -1,
|
||||
"Failed to build root path app: %{public}s", context->bundleName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t GetMountArgs(const SandboxContext *context, const PathMountNode *sandboxNode, MountArg *args)
|
||||
static uint32_t GetMountArgs(const SandboxContext *context,
|
||||
const PathMountNode *sandboxNode, uint32_t operation, MountArg *args)
|
||||
{
|
||||
uint32_t category = sandboxNode->category;
|
||||
if ((category == MOUNT_TMP_DLP_FUSE) && !context->appFullMountEnable) { // use default
|
||||
category = MOUNT_TMP_DEFAULT;
|
||||
}
|
||||
const MountArgTemplate *tmp = GetMountArgTemplate(category);
|
||||
if (tmp == 0) {
|
||||
return MOUNT_TMP_DEFAULT;
|
||||
}
|
||||
args->mountFlags = tmp->mountFlags;
|
||||
args->fsType = tmp->fsType;
|
||||
args->options = tmp->options;
|
||||
args->mountFlags = tmp->mountFlags;
|
||||
if (CHECK_FLAGS_BY_INDEX(operation, SANDBOX_TAG_PERMISSION)) {
|
||||
if (!((category == MOUNT_TMP_DAC_OVERRIDE) && context->appFullMountEnable)) {
|
||||
args->fsType = "";
|
||||
args->options = "";
|
||||
}
|
||||
}
|
||||
args->mountSharedFlag = (sandboxNode->mountSharedFlag) ? MS_SHARED : tmp->mountSharedFlag;
|
||||
return category;
|
||||
}
|
||||
|
||||
static int CheckSandboxMountNode(const SandboxContext *context,
|
||||
const SandboxSection *section, const PathMountNode *sandboxNode)
|
||||
const SandboxSection *section, const PathMountNode *sandboxNode, uint32_t operation)
|
||||
{
|
||||
if (sandboxNode->source == NULL || sandboxNode->target == NULL) {
|
||||
APPSPAWN_LOGW("Invalid mount config section %{public}s", section->name);
|
||||
return 0;
|
||||
}
|
||||
// special handle wps and don't use /data/app/xxx/<Package> config
|
||||
if (GetSectionType(section) == SANDBOX_TAG_SPAWN_FLAGS) { // flags-point
|
||||
if (CHECK_FLAGS_BY_INDEX(operation, SANDBOX_TAG_SPAWN_FLAGS)) { // flags-point
|
||||
if (context->bundleHasWps &&
|
||||
(strstr(sandboxNode->source, "/data/app") != NULL) &&
|
||||
(strstr(sandboxNode->source, "/base") != NULL || strstr(sandboxNode->source, "/database") != NULL) &&
|
||||
@ -200,7 +268,7 @@ static int CheckSandboxMountNode(const SandboxContext *context,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t DoDlpAppMountStrategy(const SandboxContext *context, const MountArg *args)
|
||||
static int32_t SandboxMountFusePath(const SandboxContext *context, const MountArg *args)
|
||||
{
|
||||
AppSpawnMsgDacInfo *info = (AppSpawnMsgDacInfo *)GetSpawningMsgInfo(context, TLV_DAC_INFO);
|
||||
APPSPAWN_CHECK(info != NULL, return APPSPAWN_TLV_NONE,
|
||||
@ -219,6 +287,11 @@ static int32_t DoDlpAppMountStrategy(const SandboxContext *context, const MountA
|
||||
"context=\"u:object_r:dlp_fuse_file:s0\","
|
||||
"fscontext=u:object_r:dlp_fuse_file:s0", fd, info->uid, info->gid);
|
||||
|
||||
APPSPAWN_LOGV("Bind mount dlp fuse \n "
|
||||
"mount arg: '%{public}s' '%{public}s' %{public}x '%{public}s' %{public}s => %{public}s",
|
||||
args->fsType, args->mountSharedFlag == MS_SHARED ? "MS_SHARED" : "MS_SLAVE",
|
||||
(uint32_t)args->mountFlags, options, args->originPath, args->destinationPath);
|
||||
|
||||
// To make sure destinationPath exist
|
||||
CreateSandboxDir(args->destinationPath, FILE_MODE);
|
||||
MountArg mountArg = {args->originPath, args->destinationPath, args->fsType, args->mountFlags, options, MS_SHARED};
|
||||
@ -250,21 +323,52 @@ static void CheckAndCreateSandboxFile(const char *file)
|
||||
return;
|
||||
}
|
||||
|
||||
static int DoSandboxPathNodeMount(const SandboxContext *context,
|
||||
const SandboxSection *section, const PathMountNode *sandboxNode, int operation)
|
||||
static void CreateDemandSrc(const SandboxContext *context, const PathMountNode *sandboxNode, const MountArg *args)
|
||||
{
|
||||
if (CheckSandboxMountNode(context, section, sandboxNode) == 0) {
|
||||
if (!sandboxNode->createDemand) {
|
||||
return;
|
||||
}
|
||||
CheckAndCreateSandboxFile(args->originPath);
|
||||
AppSpawnMsgDacInfo *info = (AppSpawnMsgDacInfo *)GetSpawningMsgInfo(context, TLV_DAC_INFO);
|
||||
APPSPAWN_CHECK(info != NULL, return,
|
||||
"No tlv %{public}d in msg %{public}s", TLV_DAC_INFO, context->bundleName);
|
||||
|
||||
// chmod
|
||||
uid_t uid = sandboxNode->demandInfo->uid != INVALID_UID ? sandboxNode->demandInfo->uid : info->uid;
|
||||
gid_t gid = sandboxNode->demandInfo->gid != INVALID_UID ? sandboxNode->demandInfo->gid : info->gid;
|
||||
int ret = chown(args->originPath, uid, gid);
|
||||
if (ret != 0) {
|
||||
APPSPAWN_LOGE("Failed to chown %{public}s errno: %{public}d", args->originPath, errno);
|
||||
}
|
||||
if (sandboxNode->demandInfo->mode != INVALID_UID) {
|
||||
ret = chmod(args->originPath, sandboxNode->demandInfo->mode);
|
||||
if (ret != 0) {
|
||||
APPSPAWN_LOGE("Failed to chmod %{public}s errno: %{public}d", args->originPath, errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int DoSandboxPathNodeMount(const SandboxContext *context,
|
||||
const SandboxSection *section, const PathMountNode *sandboxNode, uint32_t operation)
|
||||
{
|
||||
if (CheckSandboxMountNode(context, section, sandboxNode, operation) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
MountArg args = {};
|
||||
uint32_t category = GetMountArgs(context, sandboxNode, &args);
|
||||
|
||||
args.originPath = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, sandboxNode->source, NULL, NULL);
|
||||
// only destinationPath
|
||||
uint32_t category = GetMountArgs(context, sandboxNode, operation, &args);
|
||||
VarExtraData *extraData = GetVarExtraData(context, section);
|
||||
args.destinationPath = GetSandboxRealVar(context,
|
||||
BUFFER_FOR_TARGET, sandboxNode->target, context->rootPath, extraData);
|
||||
args.originPath = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, sandboxNode->source, NULL, extraData);
|
||||
// dest
|
||||
extraData->operation = operation; // only destinationPath
|
||||
// 对namespace的节点,需要对目的沙盒进行特殊处理,不能带root-dir
|
||||
if (CHECK_FLAGS_BY_INDEX(operation, SANDBOX_TAG_NAME_GROUP) &&
|
||||
CHECK_FLAGS_BY_INDEX(operation, MOUNT_PATH_OP_ONLY_SANDBOX)) {
|
||||
args.destinationPath = GetSandboxRealVar(context, BUFFER_FOR_TARGET, sandboxNode->target, NULL, extraData);
|
||||
} else {
|
||||
args.destinationPath = GetSandboxRealVar(context,
|
||||
BUFFER_FOR_TARGET, sandboxNode->target, context->rootPath, extraData);
|
||||
}
|
||||
APPSPAWN_CHECK(args.originPath != NULL && args.destinationPath != NULL,
|
||||
return APPSPAWN_ARG_INVALID, "Invalid path %{public}s %{public}s", args.originPath, args.destinationPath);
|
||||
|
||||
@ -273,30 +377,24 @@ static int DoSandboxPathNodeMount(const SandboxContext *context,
|
||||
} else {
|
||||
CreateSandboxDir(args.destinationPath, FILE_MODE);
|
||||
}
|
||||
APPSPAWN_LOGV("Bind mount category %{public}u op %{public}x \n "
|
||||
"mount arg: %{public}s %{public}s %{public}x %{public}s \n %{public}s => %{public}s",
|
||||
category, operation, args.fsType, args.mountSharedFlag == MS_SHARED ? "MS_SHARED" : "MS_SLAVE",
|
||||
(uint32_t)args.mountFlags, args.options, args.originPath, args.destinationPath);
|
||||
CreateDemandSrc(context, sandboxNode, &args);
|
||||
|
||||
if ((operation & MOUNT_PATH_OP_UNMOUNT) == MOUNT_PATH_OP_UNMOUNT) {
|
||||
// unmount this deps
|
||||
APPSPAWN_LOGV("DoSandboxPathNodeMount umount2 %{public}s", args.destinationPath);
|
||||
if (CHECK_FLAGS_BY_INDEX(operation, MOUNT_PATH_OP_UNMOUNT)) { // unmount this deps
|
||||
APPSPAWN_LOGV("umount2 %{public}s", args.destinationPath);
|
||||
umount2(args.destinationPath, MNT_DETACH);
|
||||
}
|
||||
int ret = 0;
|
||||
if (category == MOUNT_TMP_DLP_FUSE || category == MOUNT_TMP_DLP_FUSE) {
|
||||
ret = DoDlpAppMountStrategy(context, &args);
|
||||
if (category == MOUNT_TMP_DLP_FUSE || category == MOUNT_TMP_FUSE) {
|
||||
ret = SandboxMountFusePath(context, &args);
|
||||
} else {
|
||||
ret = SandboxMountPath(&args);
|
||||
}
|
||||
|
||||
if (ret != 0 && sandboxNode->checkErrorFlag) {
|
||||
APPSPAWN_LOGE("Failed to mount config, section: %{public}s result: %{public}d category: %{public}d",
|
||||
section->name, ret, category);
|
||||
return ret;
|
||||
}
|
||||
if (sandboxNode->destMode != 0) {
|
||||
chmod(context->rootPath, sandboxNode->destMode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -323,15 +421,11 @@ static int DoSandboxPathSymLink(const SandboxContext *context,
|
||||
APPSPAWN_LOGV("symlink failed, errno: %{public}d link info %{public}s %{public}s",
|
||||
errno, sandboxNode->target, sandboxNode->linkName);
|
||||
}
|
||||
if (sandboxNode->destMode != 0) {
|
||||
chmod(context->rootPath, sandboxNode->destMode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DoSandboxNodeMount(const SandboxContext *context, const SandboxSection *section, int operation)
|
||||
static int DoSandboxNodeMount(const SandboxContext *context, const SandboxSection *section, uint32_t operation)
|
||||
{
|
||||
APPSPAWN_LOGV("DoSandboxNodeMount section %{public}s operation %{public}x", section->name, operation);
|
||||
ListNode *node = section->front.next;
|
||||
while (node != §ion->front) {
|
||||
int ret = 0;
|
||||
@ -342,7 +436,7 @@ static int DoSandboxNodeMount(const SandboxContext *context, const SandboxSectio
|
||||
ret = DoSandboxPathNodeMount(context, section, (PathMountNode *)sandboxNode, operation);
|
||||
break;
|
||||
case SANDBOX_TAG_SYMLINK:
|
||||
if ((operation & MOUNT_PATH_OP_NO_SYMLINK) == MOUNT_PATH_OP_NO_SYMLINK) {
|
||||
if (!CHECK_FLAGS_BY_INDEX(operation, MOUNT_PATH_OP_SYMLINK)) {
|
||||
break;
|
||||
}
|
||||
ret = DoSandboxPathSymLink(context, section, (SymbolLinkNode *)sandboxNode);
|
||||
@ -386,51 +480,38 @@ static int UpdateMountPathDepsPath(const SandboxContext *context, SandboxNameGro
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool CheckAndCreateDepPath(const SandboxContext *context, const SandboxNameGroupNode *sandboxNode)
|
||||
static bool CheckAndCreateDepPath(const SandboxContext *context, const SandboxNameGroupNode *groupNode)
|
||||
{
|
||||
if (sandboxNode->mountMode != MOUNT_MODE_NOT_EXIST) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PathMountNode *mountNode = (PathMountNode *)GetFirstSandboxMountNode(&sandboxNode->section);
|
||||
PathMountNode *mountNode = (PathMountNode *)GetFirstSandboxMountNode(&groupNode->section);
|
||||
if (mountNode == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *srcPath = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, mountNode->source, NULL, NULL);
|
||||
// 这里可能需要替换deps的数据
|
||||
VarExtraData *extraData = GetVarExtraData(context, &groupNode->section);
|
||||
const char *srcPath = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, mountNode->source, NULL, extraData);
|
||||
if (srcPath == NULL) {
|
||||
return false;
|
||||
}
|
||||
APPSPAWN_LOGV("Mount depended to check src: %{public}s", srcPath);
|
||||
if (access(srcPath, F_OK) == 0) {
|
||||
APPSPAWN_LOGV("Src path %{public}s exist, do not mount", srcPath);
|
||||
return true;
|
||||
}
|
||||
// 这里已经是实际路径了,不需要转化
|
||||
APPSPAWN_LOGV("Mount depended source: %{public}s", sandboxNode->depNode->source);
|
||||
CreateSandboxDir(sandboxNode->depNode->source, FILE_MODE);
|
||||
// 不存在,则创建并挂载
|
||||
APPSPAWN_LOGV("Mount depended source: %{public}s", groupNode->depNode->source);
|
||||
CreateSandboxDir(groupNode->depNode->source, FILE_MODE);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int MountNameGroupPath(const SandboxContext *context,
|
||||
const AppSpawnSandboxCfg *sandbox, const SandboxNameGroupNode *sandboxNode)
|
||||
{
|
||||
int ret = 0;
|
||||
APPSPAWN_LOGV("Set name-group: '%{public}s' root path: '%{public}s' global %{public}s",
|
||||
sandboxNode->section.name, context->rootPath, sandbox->rootPath);
|
||||
|
||||
ret = DoSandboxNodeMount(context, &sandboxNode->section, 0);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Mount name group %{public}s fail result: %{public}d", sandboxNode->section.name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int MountSandboxConfig(const SandboxContext *context,
|
||||
const AppSpawnSandboxCfg *sandbox, const SandboxSection *section, int operation)
|
||||
const AppSpawnSandboxCfg *sandbox, const SandboxSection *section, uint32_t op)
|
||||
{
|
||||
uint32_t operation = (op != MOUNT_PATH_OP_NONE) ? op : 0;
|
||||
SetMountPathOperation(&operation, section->sandboxNode.type);
|
||||
// if sandbox switch is off, don't do symlink work again
|
||||
operation |= !(context->sandboxSwitch && sandbox->topSandboxSwitch) ? MOUNT_PATH_OP_NO_SYMLINK : 0;
|
||||
APPSPAWN_LOGV("Set config section: %{public}s root path: '%{public}s' symlinkDo: %{public}x",
|
||||
section->name, context->rootPath, operation);
|
||||
if (context->sandboxSwitch && sandbox->topSandboxSwitch) {
|
||||
SetMountPathOperation(&operation, MOUNT_PATH_OP_SYMLINK);
|
||||
}
|
||||
|
||||
int ret = DoSandboxNodeMount(context, section, operation);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
@ -445,7 +526,10 @@ static int MountSandboxConfig(const SandboxContext *context,
|
||||
continue;
|
||||
}
|
||||
SandboxNameGroupNode *groupNode = (SandboxNameGroupNode *)section->nameGroups[i];
|
||||
MountNameGroupPath(context, sandbox, groupNode);
|
||||
SetMountPathOperation(&operation, SANDBOX_TAG_NAME_GROUP);
|
||||
ret = DoSandboxNodeMount(context, &groupNode->section, operation);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Mount name group %{public}s fail result: %{public}d", groupNode->section.name, ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -468,7 +552,7 @@ static int SetExpandSandboxConfig(const SandboxContext *context, const AppSpawnS
|
||||
if (mountDestBundlePath || (CheckSpawningMsgFlagSet(context, APP_FLAGS_ACCESS_BUNDLE_DIR) != 0)) {
|
||||
// need permission check for system app here
|
||||
const char *destBundlesPath = GetSandboxRealVar(context,
|
||||
BUFFER_FOR_TARGET, "/data/bundles/", context->sandboxPackagePath, NULL);
|
||||
BUFFER_FOR_TARGET, "/data/bundles/", context->rootPath, NULL);
|
||||
CreateSandboxDir(destBundlesPath, FILE_MODE);
|
||||
MountArg mountArg = {PHYSICAL_APP_INSTALL_PATH, destBundlesPath, NULL, MS_REC | MS_BIND, NULL, MS_SLAVE};
|
||||
ret = SandboxMountPath(&mountArg);
|
||||
@ -482,7 +566,7 @@ static int SetSandboxPackageNameConfig(const SandboxContext *context, const AppS
|
||||
SandboxPackageNameNode *sandboxNode =
|
||||
(SandboxPackageNameNode *)GetSandboxSection(&sandbox->packageNameQueue, context->bundleName);
|
||||
if (sandboxNode != NULL) {
|
||||
int ret = MountSandboxConfig(context, sandbox, &sandboxNode->section, 0);
|
||||
int ret = MountSandboxConfig(context, sandbox, &sandboxNode->section, MOUNT_PATH_OP_NONE);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
}
|
||||
return 0;
|
||||
@ -490,16 +574,16 @@ static int SetSandboxPackageNameConfig(const SandboxContext *context, const AppS
|
||||
|
||||
static int SetSandboxSpawnFlagsConfig(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_LOGV("Set spawning flags config");
|
||||
ListNode *node = sandbox->spawnFlagsQueue.front.next;
|
||||
while (node != &sandbox->spawnFlagsQueue.front) {
|
||||
SandboxFlagsNode *sandboxNode = (SandboxFlagsNode *)ListEntry(node, SandboxMountNode, node);
|
||||
if (!CheckSpawningMsgFlagSet(context, sandboxNode->flagIndex)) { // match flags point
|
||||
// match flags point
|
||||
if (sandboxNode->flagIndex == 0 || !CheckSpawningMsgFlagSet(context, sandboxNode->flagIndex)) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
int ret = MountSandboxConfig(context, sandbox, &sandboxNode->section, 0);
|
||||
int ret = MountSandboxConfig(context, sandbox, &sandboxNode->section, MOUNT_PATH_OP_NONE);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
node = node->next;
|
||||
}
|
||||
@ -517,8 +601,9 @@ static int SetSandboxPermissionConfig(const SandboxContext *context, const AppSp
|
||||
continue;
|
||||
}
|
||||
|
||||
APPSPAWN_LOGV("SetSandboxPermissionConfig permission %{public}s", permissionNode->section.name);
|
||||
int ret = MountSandboxConfig(context, sandbox, &permissionNode->section, 0);
|
||||
APPSPAWN_LOGV("SetSandboxPermissionConfig permission %{public}d %{public}s",
|
||||
permissionNode->permissionIndex, permissionNode->section.name);
|
||||
int ret = MountSandboxConfig(context, sandbox, &permissionNode->section, MOUNT_PATH_OP_NONE);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
node = node->next;
|
||||
}
|
||||
@ -541,7 +626,7 @@ static int SetBundleResourceSandboxConfig(const SandboxContext *context, const A
|
||||
return 0;
|
||||
}
|
||||
const char *destPath = GetSandboxRealVar(context,
|
||||
BUFFER_FOR_TARGET, "/data/storage/bundle_resources/", context->sandboxPackagePath, NULL);
|
||||
BUFFER_FOR_TARGET, "/data/storage/bundle_resources/", context->rootPath, NULL);
|
||||
CreateSandboxDir(destPath, FILE_MODE);
|
||||
MountArg mountArg = {
|
||||
"/data/service/el1/public/bms/bundle_resources/", destPath, NULL, MS_REC | MS_BIND, NULL, MS_SLAVE
|
||||
@ -553,39 +638,39 @@ static int SetBundleResourceSandboxConfig(const SandboxContext *context, const A
|
||||
static int32_t ChangeCurrentDir(const SandboxContext *context)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
ret = chdir(context->sandboxPackagePath);
|
||||
ret = chdir(context->rootPath);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"chdir failed, app: %{public}s, path: %{public}s errno: %{public}d",
|
||||
context->bundleName, context->sandboxPackagePath, errno);
|
||||
context->bundleName, context->rootPath, errno);
|
||||
|
||||
if (context->sandboxShared) {
|
||||
ret = chroot(context->sandboxPackagePath);
|
||||
ret = chroot(context->rootPath);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"chroot failed, path: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
"chroot failed, path: %{public}s errno: %{public}d", context->rootPath, errno);
|
||||
return ret;
|
||||
}
|
||||
ret = syscall(SYS_pivot_root, context->sandboxPackagePath, context->sandboxPackagePath);
|
||||
ret = syscall(SYS_pivot_root, context->rootPath, context->rootPath);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"pivot root failed, path: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
"pivot root failed, path: %{public}s errno: %{public}d", context->rootPath, errno);
|
||||
ret = umount2(".", MNT_DETACH);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"MNT_DETACH failed, path: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
APPSPAWN_LOGV("ChangeCurrentDir %{public}s ", context->sandboxPackagePath);
|
||||
"MNT_DETACH failed, path: %{public}s errno: %{public}d", context->rootPath, errno);
|
||||
APPSPAWN_LOGV("ChangeCurrentDir %{public}s ", context->rootPath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int SandboxRootFolderCreateNoShare(
|
||||
const SandboxContext *context, const AppSpawnSandboxCfg *sandbox, bool remountProc)
|
||||
{
|
||||
APPSPAWN_LOGV("SandboxRootFolderCreateNoShare %{public}s ", context->sandboxPackagePath);
|
||||
APPSPAWN_LOGV("SandboxRootFolderCreateNoShare %{public}s ", context->rootPath);
|
||||
int ret = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"set propagation slave failed, app: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
"set propagation slave failed, app: %{public}s errno: %{public}d", context->rootPath, errno);
|
||||
|
||||
MountArg arg = {context->sandboxPackagePath, context->sandboxPackagePath, NULL, BASIC_MOUNT_FLAGS, NULL, MS_SLAVE};
|
||||
MountArg arg = {context->rootPath, context->rootPath, NULL, BASIC_MOUNT_FLAGS, NULL, MS_SLAVE};
|
||||
ret = SandboxMountPath(&arg);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"mount path failed, app: %{public}s errno: %{public}d", context->sandboxPackagePath, ret);
|
||||
"mount path failed, app: %{public}s errno: %{public}d", context->rootPath, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -598,12 +683,12 @@ static int SandboxRootFolderCreate(const SandboxContext *context, const AppSpawn
|
||||
if (sandbox->topSandboxSwitch == 0 || context->sandboxSwitch == 0) {
|
||||
ret = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"set propagation slave failed, app: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
"set propagation slave failed, app: %{public}s errno: %{public}d", context->rootPath, errno);
|
||||
// bind mount "/" to /mnt/sandbox/<packageName> path
|
||||
// rootfs: to do more resources bind mount here to get more strict resources constraints
|
||||
ret = mount("/", context->sandboxPackagePath, NULL, BASIC_MOUNT_FLAGS, NULL);
|
||||
ret = mount("/", context->rootPath, NULL, BASIC_MOUNT_FLAGS, NULL);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"mount bind / failed, app: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
"mount bind / failed, app: %{public}s errno: %{public}d", context->rootPath, errno);
|
||||
} else if (!context->sandboxShared) {
|
||||
bool remountProc = !context->nwebspawn && ((sandbox->sandboxNsFlags & CLONE_NEWPID) == CLONE_NEWPID);
|
||||
ret = SandboxRootFolderCreateNoShare(context, sandbox, remountProc);
|
||||
@ -611,78 +696,99 @@ static int SandboxRootFolderCreate(const SandboxContext *context, const AppSpawn
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DumpCurrentDir(SandboxContext *context, const char *dirPath)
|
||||
static bool IsSandboxMounted(const AppSpawnSandboxCfg *sandbox, const char *name, const char *rootPath)
|
||||
{
|
||||
DIR *pDir = opendir(dirPath);
|
||||
APPSPAWN_CHECK(pDir != NULL, return -1, "Read dir :%{public}s failed.%{public}d", dirPath, errno);
|
||||
char path[PATH_MAX] = {};
|
||||
int len = sprintf_s(path, sizeof(path), "%s%s", rootPath, SANDBOX_STAMP_FILE_SUFFIX);
|
||||
APPSPAWN_CHECK(len > 0, return false, "Failed to format path");
|
||||
|
||||
struct dirent *dp;
|
||||
while ((dp = readdir(pDir)) != NULL) {
|
||||
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
if (dp->d_type == DT_DIR) {
|
||||
APPSPAWN_LOGV(" Current path %{public}s/%{public}s ", dirPath, dp->d_name);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(snprintf_s(context->buffer[1].buffer, context->buffer[1].bufferLen, context->buffer[1].bufferLen - 1,
|
||||
"%s/%s", dirPath, dp->d_name) != -1, return -1);
|
||||
char *path = strdup(context->buffer[1].buffer);
|
||||
DumpCurrentDir(context, path);
|
||||
free(path);
|
||||
}
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (f != NULL) {
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int SetSandboxMounted(const AppSpawnSandboxCfg *sandbox, const char *name, char *rootPath)
|
||||
{
|
||||
APPSPAWN_LOGW("SetSystemConstMounted %{public}s ", rootPath);
|
||||
char path[PATH_MAX] = {};
|
||||
int len = sprintf_s(path, sizeof(path), "%s%s", rootPath, SANDBOX_STAMP_FILE_SUFFIX);
|
||||
APPSPAWN_CHECK(len > 0, return 0, "Failed to format path");
|
||||
|
||||
FILE *f = fopen(path, "wb");
|
||||
if (f != NULL) {
|
||||
fclose(f);
|
||||
}
|
||||
closedir(pDir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MountSandboxConfigs(const AppSpawnSandboxCfg *sandbox, const AppSpawningCtx *property, int nwebspawn)
|
||||
static void UnmountPath(char *rootPath, uint32_t len, const SandboxMountNode *sandboxNode)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != NULL, return -1);
|
||||
APPSPAWN_CHECK(sandbox != NULL, return -1, "Failed to get sandbox for %{public}s", GetProcessName(property));
|
||||
|
||||
SandboxContext *context = GetSandboxContext();
|
||||
APPSPAWN_CHECK_ONLY_EXPER(context != NULL, return APPSPAWN_SYSTEM_ERROR);
|
||||
int ret = InitSandboxContext(context, sandbox, property, nwebspawn);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
do {
|
||||
ret = BuildRootPath((SandboxContext *)context, sandbox, NULL);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
ret = BuildPackagePath(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
APPSPAWN_LOGV("Set sandbox config %{public}s", context->sandboxPackagePath);
|
||||
|
||||
ret = StagedMountPreUnShare(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
CreateSandboxDir(context->sandboxPackagePath, FILE_MODE);
|
||||
// add pid to a new mnt namespace
|
||||
ret = unshare(CLONE_NEWNS);
|
||||
APPSPAWN_CHECK(ret == 0, break,
|
||||
"unshare failed, app: %{public}s errno: %{public}d", context->bundleName, errno);
|
||||
|
||||
ret = SandboxRootFolderCreate(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
ret = StagedMountPostUnshare(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
ret = SetOverlayAppSandboxConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
ret = SetBundleResourceSandboxConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
ret = ChangeCurrentDir(context);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
APPSPAWN_LOGV("Change root dir success %{public}s ", context->sandboxPackagePath);
|
||||
} while (0);
|
||||
|
||||
if (getcwd(context->buffer[0].buffer, context->buffer[0].bufferLen) != NULL) {
|
||||
APPSPAWN_LOGE("current_path %{public}s\n", context->buffer[0].buffer);
|
||||
if (sandboxNode->type == SANDBOX_TAG_MOUNT_PATH) {
|
||||
PathMountNode *pathNode = (PathMountNode *)sandboxNode;
|
||||
int ret = strcat_s(rootPath, len, pathNode->target);
|
||||
APPSPAWN_CHECK(ret == 0, return, "Failed to format");
|
||||
APPSPAWN_LOGV("Unmount sandbox config sandbox path %{public}s ", rootPath);
|
||||
ret = umount2(rootPath, MNT_DETACH);
|
||||
APPSPAWN_CHECK_ONLY_LOG(ret == 0, "Failed to umount2 %{public}s errno: %{public}d", rootPath, errno);
|
||||
}
|
||||
APPSPAWN_LOGV("current_path %{public}s \n", context->buffer[0].buffer);
|
||||
DumpCurrentDir(context, "/data");
|
||||
DeleteSandboxContext(context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int UnmountDepPaths(const AppSpawnSandboxCfg *sandbox, uid_t uid)
|
||||
{
|
||||
APPSPAWN_CHECK(sandbox != NULL, return -1, "Invalid sandbox or context");
|
||||
APPSPAWN_LOGI("Unmount sandbox mount-paths-deps %{public}u ", sandbox->depNodeCount);
|
||||
char path[PATH_MAX] = {};
|
||||
int ret = BuildRootPath(path, sizeof(path), sandbox, uid / UID_BASE);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return -1);
|
||||
uint32_t rootLen = strlen(path);
|
||||
for (uint32_t i = 0; i < sandbox->depNodeCount; i++) {
|
||||
SandboxNameGroupNode *groupNode = sandbox->depGroupNodes[i];
|
||||
if (groupNode == NULL || groupNode->depNode == NULL) {
|
||||
continue;
|
||||
}
|
||||
// unmount this deps
|
||||
UnmountPath(path, sizeof(path), &groupNode->depNode->sandboxNode);
|
||||
path[rootLen] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UnmountSandboxConfigs(const AppSpawnSandboxCfg *sandbox, uid_t uid, const char *name)
|
||||
{
|
||||
APPSPAWN_CHECK(sandbox != NULL, return -1, "Invalid sandbox or context");
|
||||
APPSPAWN_CHECK(name != NULL, return -1, "Invalid name");
|
||||
char path[PATH_MAX] = {};
|
||||
int ret = BuildRootPath(path, sizeof(path), sandbox, uid / UID_BASE);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return -1);
|
||||
uint32_t rootLen = strlen(path);
|
||||
APPSPAWN_LOGI("Unmount sandbox %{public}s root: %{public}s", name, path);
|
||||
|
||||
if (!IsSandboxMounted(sandbox, name, path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SandboxSection *section = GetSandboxSection(&sandbox->requiredQueue, name);
|
||||
if (section == NULL) {
|
||||
return 0;
|
||||
}
|
||||
ListNode *node = section->front.next;
|
||||
while (node != §ion->front) {
|
||||
SandboxMountNode *sandboxNode = (SandboxMountNode *)ListEntry(node, SandboxMountNode, node);
|
||||
UnmountPath(path, sizeof(path), sandboxNode);
|
||||
path[rootLen] = '\0';
|
||||
// get next
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
// delete stamp file
|
||||
ret = strcat_s(path, sizeof(path), SANDBOX_STAMP_FILE_SUFFIX);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return 0);
|
||||
APPSPAWN_LOGI("Unmount sandbox %{public}s ", path);
|
||||
unlink(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StagedMountSystemConst(const AppSpawnSandboxCfg *sandbox, const AppSpawningCtx *property, int nwebspawn)
|
||||
@ -699,7 +805,7 @@ int StagedMountSystemConst(const AppSpawnSandboxCfg *sandbox, const AppSpawningC
|
||||
* 检查type,必须是 system-const
|
||||
* 如果存在 mount-paths-deps
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-paths-deps.sandbox-path + mount-path.sandbox-path
|
||||
* dst = mount-path.sandbox-path --> 存在依赖时,配置<deps-path>、<deps-sandbox-path>、<deps-src-path>
|
||||
* 否则:
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-path.sandbox-path
|
||||
@ -708,12 +814,20 @@ int StagedMountSystemConst(const AppSpawnSandboxCfg *sandbox, const AppSpawningC
|
||||
APPSPAWN_CHECK_ONLY_EXPER(context != NULL, return APPSPAWN_SYSTEM_ERROR);
|
||||
int ret = InitSandboxContext(context, sandbox, property, nwebspawn);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
BuildRootPath((SandboxContext *)context, sandbox, NULL);
|
||||
|
||||
if (IsSandboxMounted(sandbox, "system-const", context->rootPath)) {
|
||||
APPSPAWN_LOGV("Sandbox system-const %{public}s has been mount", context->rootPath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APPSPAWN_LOGV("Set sandbox system-const %{public}s", context->rootPath);
|
||||
uint32_t operation = 0;
|
||||
SetMountPathOperation(&operation, MOUNT_PATH_OP_REPLACE_BY_SANDBOX); // 首次挂载,使用sandbox替换
|
||||
SandboxSection *section = GetSandboxSection(&sandbox->requiredQueue, "system-const");
|
||||
if (section != NULL) {
|
||||
ret = MountSandboxConfig(context, sandbox, section, 0);
|
||||
ret = MountSandboxConfig(context, sandbox, section, operation);
|
||||
}
|
||||
SetSandboxMounted(sandbox, "system-const", context->rootPath);
|
||||
DeleteSandboxContext(context);
|
||||
return ret;
|
||||
}
|
||||
@ -729,7 +843,7 @@ int StagedMountPreUnShare(const SandboxContext *context, const AppSpawnSandboxCf
|
||||
* src-dir "/mnt/sandbox/app-common/<currentUserId>"
|
||||
* 遍历mount-paths-deps,处理mount-paths-deps
|
||||
* src = mount-paths-deps.src-path
|
||||
* dst = mount-paths-deps.sandbox-path
|
||||
* dst = root-dir + mount-paths-deps.sandbox-path
|
||||
* 如果设置no-exist,检查mount-paths 的src(实际路径) 是否不存在,
|
||||
则安mount-paths-deps.src-path 创建。 按shared方式挂载mount-paths-deps
|
||||
* 如果是 always,按shared方式挂载mount-paths-deps
|
||||
@ -748,50 +862,58 @@ int StagedMountPreUnShare(const SandboxContext *context, const AppSpawnSandboxCf
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Failed to update deps path name group %{public}s", groupNode->section.name);
|
||||
|
||||
if (CheckAndCreateDepPath(context, groupNode)) {
|
||||
if (groupNode->depMode == MOUNT_MODE_NOT_EXIST && CheckAndCreateDepPath(context, groupNode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = DoSandboxPathNodeMount(context, &groupNode->section, groupNode->depNode, 0);
|
||||
uint32_t operation = 0;
|
||||
SetMountPathOperation(&operation, MOUNT_PATH_OP_UNMOUNT);
|
||||
groupNode->depMounted = 1;
|
||||
ret = DoSandboxPathNodeMount(context, &groupNode->section, groupNode->depNode, operation);
|
||||
if (ret != 0) {
|
||||
APPSPAWN_LOGE("Mount deps root fail %{public}s", groupNode->section.name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (groupNode->destType == SANDBOX_TAG_SYSTEM_CONST) {
|
||||
ret = MountSandboxConfig(context, sandbox, &groupNode->section, MOUNT_PATH_OP_UNMOUNT);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Set system-const config fail result: %{public}d, app: %{public}s", ret, context->bundleName);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SetAppVariableConfig(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
/**
|
||||
* app-variable 处理逻辑
|
||||
* root-dir global.sandbox-root
|
||||
* app-variabl, 处理mount path
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-path.src-path
|
||||
* 遍历name-groups,处理mount path
|
||||
* 如果存在 mount-paths-deps
|
||||
* dst = mount-path.sandbox-path --> 存在依赖时,配置<deps-path>、<deps-sandbox-path>、<deps-src-path>
|
||||
* 否则:
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-path.sandbox-path
|
||||
*/
|
||||
int ret = 0;
|
||||
// 首次挂载,使用sandbox替换
|
||||
uint32_t operation = 0;
|
||||
SetMountPathOperation(&operation, MOUNT_PATH_OP_REPLACE_BY_SANDBOX);
|
||||
SandboxSection *section = GetSandboxSection(&sandbox->requiredQueue, "app-variable");
|
||||
if (section == NULL) {
|
||||
return 0;
|
||||
}
|
||||
ret = MountSandboxConfig(context, sandbox, section, operation);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Set app-variable config fail result: %{public}d, app: %{public}s", ret, context->bundleName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StagedMountPostUnshare(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_CHECK(sandbox != NULL && context != NULL, return -1, "Invalid sandbox or context");
|
||||
APPSPAWN_LOGV("Set sandbox config after unshare ");
|
||||
/**
|
||||
* app-variable 处理逻辑
|
||||
* root-dir global.sandbox-root
|
||||
* app-variabl, 处理mount path
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-path.sandbox-path
|
||||
* 遍历name-groups,处理mount path
|
||||
* 如果存在 mount-paths-deps
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-paths-deps.sandbox-path + mount-path.sandbox-path
|
||||
* 否则:
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-path.sandbox-path
|
||||
*/
|
||||
int ret = 0;
|
||||
SandboxSection *section = GetSandboxSection(&sandbox->requiredQueue, "app-variable");
|
||||
if (section != NULL) {
|
||||
ret = MountSandboxConfig(context, sandbox, section, 0);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Set app-variable config fail result: %{public}d, app: %{public}s", ret, context->bundleName);
|
||||
}
|
||||
|
||||
int ret = SetAppVariableConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
if (!context->nwebspawn) {
|
||||
ret = SetExpandSandboxConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
@ -808,17 +930,43 @@ int StagedMountPostUnshare(const SandboxContext *context, const AppSpawnSandboxC
|
||||
return ret;
|
||||
}
|
||||
|
||||
int UnmountSandboxConfigs(const AppSpawnSandboxCfg *sandbox)
|
||||
int MountSandboxConfigs(const AppSpawnSandboxCfg *sandbox, const AppSpawningCtx *property, int nwebspawn)
|
||||
{
|
||||
APPSPAWN_CHECK(sandbox != NULL, return -1, "Invalid sandbox or context");
|
||||
for (uint32_t i = 0; i < sandbox->depNodeCount; i++) {
|
||||
SandboxNameGroupNode *groupNode = sandbox->depGroupNodes[i];
|
||||
if (groupNode == NULL || groupNode->depNode == NULL) {
|
||||
continue;
|
||||
}
|
||||
APPSPAWN_LOGV("Unmount sandbox config sandbox path %{public}s ", groupNode->depNode->target);
|
||||
// unmount this deps
|
||||
umount2(groupNode->depNode->target, MNT_DETACH);
|
||||
}
|
||||
return 0;
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != NULL, return -1);
|
||||
APPSPAWN_CHECK(sandbox != NULL, return -1, "Failed to get sandbox for %{public}s", GetProcessName(property));
|
||||
|
||||
SandboxContext *context = GetSandboxContext();
|
||||
APPSPAWN_CHECK_ONLY_EXPER(context != NULL, return APPSPAWN_SYSTEM_ERROR);
|
||||
int ret = InitSandboxContext(context, sandbox, property, nwebspawn);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
do {
|
||||
APPSPAWN_LOGV("Set sandbox config %{public}s", context->rootPath);
|
||||
|
||||
ret = StagedMountPreUnShare(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
CreateSandboxDir(context->rootPath, FILE_MODE);
|
||||
// add pid to a new mnt namespace
|
||||
ret = unshare(CLONE_NEWNS);
|
||||
APPSPAWN_CHECK(ret == 0, break,
|
||||
"unshare failed, app: %{public}s errno: %{public}d", context->bundleName, errno);
|
||||
|
||||
ret = SandboxRootFolderCreate(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
ret = StagedMountPostUnshare(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
ret = SetOverlayAppSandboxConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
ret = SetBundleResourceSandboxConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
ret = ChangeCurrentDir(context);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
APPSPAWN_LOGV("Change root dir success %{public}s ", context->rootPath);
|
||||
} while (0);
|
||||
DeleteSandboxContext(context);
|
||||
return ret;
|
||||
}
|
||||
|
62
modules/sandbox/appspawn_sandbox.h
Executable file → Normal file
62
modules/sandbox/appspawn_sandbox.h
Executable file → Normal file
@ -17,9 +17,10 @@
|
||||
#define APPSPAWN_SANDBOX_H
|
||||
|
||||
#include <limits.h>
|
||||
#include ""
|
||||
|
||||
#include "appspawn.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "list.h"
|
||||
|
||||
@ -27,6 +28,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SANDBOX_STAMP_FILE_SUFFIX ".stamp"
|
||||
#define JSON_FLAGS_INTERNAL "__internal__"
|
||||
#define SANDBOX_NWEBSPAWN_ROOT_PATH APPSPAWN_BASE_DIR "/mnt/sandbox/com.ohos.render/"
|
||||
#define OHOS_RENDER "__internal__.com.ohos.render"
|
||||
@ -59,9 +61,12 @@ extern "C" {
|
||||
#define MOUNT_MODE_ALWAYS 1 // "always"
|
||||
#define MOUNT_MODE_NOT_EXIST 2 // "not-exists"
|
||||
|
||||
#define MOUNT_PATH_OP_NO_SYMLINK 0x01
|
||||
#define MOUNT_PATH_OP_UNMOUNT 0x02
|
||||
|
||||
#define MOUNT_PATH_OP_NONE ((uint32_t)-1)
|
||||
#define MOUNT_PATH_OP_SYMLINK SANDBOX_TAG_INVALID
|
||||
#define MOUNT_PATH_OP_UNMOUNT (SANDBOX_TAG_INVALID + 1)
|
||||
#define MOUNT_PATH_OP_ONLY_SANDBOX (SANDBOX_TAG_INVALID + 2)
|
||||
#define MOUNT_PATH_OP_REPLACE_BY_SANDBOX (SANDBOX_TAG_INVALID + 3)
|
||||
#define MOUNT_PATH_OP_REPLACE_BY_SRC (SANDBOX_TAG_INVALID + 4)
|
||||
#define FILE_CROSS_APP_MODE "ohos.permission.FILE_CROSS_APP"
|
||||
|
||||
typedef enum SandboxTag {
|
||||
@ -89,15 +94,30 @@ typedef struct TagSandboxQueue {
|
||||
uint32_t type;
|
||||
} SandboxQueue;
|
||||
|
||||
/*
|
||||
"create-on-demand": {
|
||||
"uid": "userId", // 默认使用消息的uid、gid
|
||||
"gid": "groupId",
|
||||
"ugo": 750
|
||||
}
|
||||
*/
|
||||
typedef struct {
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
uint32_t mode;
|
||||
} PathDemandInfo;
|
||||
|
||||
typedef struct TagPathMountNode {
|
||||
SandboxMountNode sandboxNode;
|
||||
char *source; // source 目录,一般是全局的fs 目录
|
||||
char *target; // 沙盒化后的目录
|
||||
mode_t destMode; // "dest-mode": "S_IRUSR | S_IWOTH | S_IRWXU " 默认值:0
|
||||
uint32_t mountSharedFlag : 1; // "mount-shared-flag" : "true", 默认值:false
|
||||
uint32_t createDemand : 1;
|
||||
uint32_t checkErrorFlag : 1;
|
||||
uint32_t category;
|
||||
char *appAplName;
|
||||
PathDemandInfo demandInfo[0];
|
||||
} PathMountNode;
|
||||
|
||||
typedef struct TagSymbolLinkNode {
|
||||
@ -131,10 +151,10 @@ typedef struct {
|
||||
|
||||
typedef struct TagSandboxGroupNode {
|
||||
SandboxSection section;
|
||||
uint32_t caps; // "caps": [ "shared" ],
|
||||
uint32_t destType;
|
||||
PathMountNode *depNode;
|
||||
uint32_t mountMode;
|
||||
uint32_t depMode;
|
||||
uint32_t depMounted : 1; // 是否执行了挂载
|
||||
} SandboxNameGroupNode;
|
||||
|
||||
typedef struct TagPermissionNode {
|
||||
@ -157,13 +177,14 @@ typedef struct TagAppSpawnSandboxCfg {
|
||||
uint32_t topSandboxSwitch : 1; // "top-sandbox-switch": "ON",
|
||||
uint32_t appFullMountEnable : 1;
|
||||
uint32_t pidNamespaceSupport : 1;
|
||||
uint32_t systemUids[10];
|
||||
uint32_t mounted : 1;
|
||||
char *rootPath;
|
||||
} AppSpawnSandboxCfg;
|
||||
|
||||
enum {
|
||||
BUFFER_FOR_SOURCE,
|
||||
BUFFER_FOR_TARGET,
|
||||
BUFFER_FOR_TMP,
|
||||
MAX_BUFFER
|
||||
};
|
||||
|
||||
@ -185,7 +206,6 @@ typedef struct TagSandboxContext {
|
||||
uint32_t appFullMountEnable : 1;
|
||||
uint32_t nwebspawn : 1;
|
||||
char *rootPath;
|
||||
char *sandboxPackagePath;
|
||||
} SandboxContext;
|
||||
|
||||
/**
|
||||
@ -220,6 +240,8 @@ SandboxMountNode *CreateSandboxMountNode(uint32_t dataLen, uint32_t type);
|
||||
SandboxMountNode *GetFirstSandboxMountNode(const SandboxSection *section);
|
||||
void DeleteSandboxMountNode(SandboxMountNode *mountNode);
|
||||
void AddSandboxMountNode(SandboxMountNode *node, SandboxSection *section);
|
||||
PathMountNode *GetPathMountNode(const SandboxSection *section, int type, const char *source, const char *target);
|
||||
SymbolLinkNode *GetSymbolLinkNode(const SandboxSection *section, const char *target, const char *linkName);
|
||||
|
||||
/**
|
||||
* @brief sandbox mount interface
|
||||
@ -229,7 +251,9 @@ int MountSandboxConfigs(const AppSpawnSandboxCfg *sandbox, const AppSpawningCtx
|
||||
int StagedMountSystemConst(const AppSpawnSandboxCfg *sandbox, const AppSpawningCtx *property, int nwebspawn);
|
||||
int StagedMountPreUnShare(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox);
|
||||
int StagedMountPostUnshare(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox);
|
||||
int UnmountSandboxConfigs(const AppSpawnSandboxCfg *sandbox);
|
||||
// 在子进程退出时,由父进程发起unmount操作
|
||||
int UnmountDepPaths(const AppSpawnSandboxCfg *sandbox, uid_t uid);
|
||||
int UnmountSandboxConfigs(const AppSpawnSandboxCfg *sandbox, uid_t uid, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Variable op
|
||||
@ -243,6 +267,7 @@ typedef struct {
|
||||
|
||||
typedef struct TagVarExtraData {
|
||||
uint32_t sandboxTag;
|
||||
uint32_t operation;
|
||||
union {
|
||||
PathMountNode *depNode;
|
||||
} data;
|
||||
@ -319,6 +344,25 @@ int GetPathMode(const char *name);
|
||||
|
||||
void DumpMountPathMountNode(const PathMountNode *pathNode);
|
||||
|
||||
typedef struct {
|
||||
const char *originPath;
|
||||
const char *destinationPath;
|
||||
const char *fsType;
|
||||
unsigned long mountFlags;
|
||||
const char *options;
|
||||
mode_t mountSharedFlag;
|
||||
} MountArg;
|
||||
|
||||
int SandboxMountPath(const MountArg *arg);
|
||||
|
||||
__attribute__((always_inline)) inline int IsPathEmpty(const char *path)
|
||||
{
|
||||
if (path == NULL || path[0] == '\0') {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
94
modules/sandbox/sandbox_cfgvar.c
Executable file → Normal file
94
modules/sandbox/sandbox_cfgvar.c
Executable file → Normal file
@ -13,6 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_sandbox.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "modulemgr.h"
|
||||
@ -57,10 +58,10 @@ static int VarCurrentUseIdReplace(const SandboxContext *context,
|
||||
APPSPAWN_CHECK(info != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No tlv %{public}d in msg %{public}s", TLV_DAC_INFO, context->bundleName);
|
||||
int len = 0;
|
||||
if (extraData == NULL || extraData->sandboxTag != SANDBOX_TAG_PERMISSION) {
|
||||
if (extraData == NULL || !CHECK_FLAGS_BY_INDEX(extraData->operation, SANDBOX_TAG_PERMISSION)) {
|
||||
len = sprintf_s((char *)buffer, bufferLen, "%u", info->uid / UID_BASE);
|
||||
} else if (context->appFullMountEnable && strlen(info->userName) > 0) {
|
||||
len = sprintf_s((char *)buffer, bufferLen, "%s", info->userName);
|
||||
len = sprintf_s((char *)buffer, bufferLen, "%s", "currentUser");
|
||||
} else {
|
||||
len = sprintf_s((char *)buffer, bufferLen, "%s", "currentUser");
|
||||
}
|
||||
@ -96,15 +97,43 @@ static int ReplaceVariableByParameter(const char *varData, SandboxBuffer *sandbo
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ReplaceVariableForDeps(const SandboxContext *context,
|
||||
SandboxBuffer *sandboxBuffer, const VarExtraData *extraData)
|
||||
static int ReplaceVariableForDepSandboxPath(const SandboxContext *context,
|
||||
const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
|
||||
{
|
||||
APPSPAWN_CHECK(extraData != NULL, return -1, "Invalid extra data ");
|
||||
uint32_t len = strlen(extraData->data.depNode->target);
|
||||
int ret = memcpy_s(sandboxBuffer->buffer + sandboxBuffer->current,
|
||||
sandboxBuffer->bufferLen - sandboxBuffer->current, extraData->data.depNode->target, len);
|
||||
int ret = memcpy_s((char *)buffer, bufferLen, extraData->data.depNode->target, len);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
|
||||
sandboxBuffer->current += len;
|
||||
*realLen = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ReplaceVariableForDepSrcPath(const SandboxContext *context,
|
||||
const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
|
||||
{
|
||||
APPSPAWN_CHECK(extraData != NULL, return -1, "Invalid extra data ");
|
||||
uint32_t len = strlen(extraData->data.depNode->source);
|
||||
int ret = memcpy_s((char *)buffer, bufferLen, extraData->data.depNode->source, len);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
|
||||
*realLen = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ReplaceVariableForDepPath(const SandboxContext *context,
|
||||
const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
|
||||
{
|
||||
APPSPAWN_CHECK(extraData != NULL, return -1, "Invalid extra data ");
|
||||
char *path = extraData->data.depNode->source;
|
||||
if (CHECK_FLAGS_BY_INDEX(extraData->operation, MOUNT_PATH_OP_REPLACE_BY_SANDBOX)) {
|
||||
path = extraData->data.depNode->target;
|
||||
} else if (CHECK_FLAGS_BY_INDEX(extraData->operation, MOUNT_PATH_OP_REPLACE_BY_SRC) && IsPathEmpty(path)) {
|
||||
path = extraData->data.depNode->target;
|
||||
}
|
||||
APPSPAWN_CHECK(path != NULL, return -1, "Invalid path %{public}x ", extraData->operation);
|
||||
uint32_t len = strlen(path);
|
||||
int ret = memcpy_s((char *)buffer, bufferLen, path, len);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
|
||||
*realLen = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -129,12 +158,12 @@ static int GetVariableName(char *varData, uint32_t len, const char *varStart, ui
|
||||
static int ReplaceVariable(const SandboxContext *context,
|
||||
const char *varStart, SandboxBuffer *sandboxBuffer, uint32_t *varLen, const VarExtraData *extraData)
|
||||
{
|
||||
char varData[128] = {0}; // 128 max len for var
|
||||
int ret = GetVariableName(varData, sizeof(varData), varStart, varLen);
|
||||
char varName[128] = {0}; // 128 max len for var
|
||||
int ret = GetVariableName(varName, sizeof(varName), varStart, varLen);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to get variable name");
|
||||
|
||||
uint32_t valueLen = 0;
|
||||
AppSandboxVarNode *node = GetAppSandboxVarNode(varData);
|
||||
AppSandboxVarNode *node = GetAppSandboxVarNode(varName);
|
||||
if (node != NULL) {
|
||||
ret = node->replaceVar(context, sandboxBuffer->buffer + sandboxBuffer->current,
|
||||
sandboxBuffer->bufferLen - sandboxBuffer->current - 1, &valueLen, extraData);
|
||||
@ -144,32 +173,28 @@ static int ReplaceVariable(const SandboxContext *context,
|
||||
return 0;
|
||||
}
|
||||
// "<param:persist.nweb.sandbox.src_path>"
|
||||
if (strncmp(varData, "<param:", sizeof("<param:") - 1) == 0) { // retry param:
|
||||
varData[*varLen - 1] = '\0'; // erase last >
|
||||
return ReplaceVariableByParameter(varData, sandboxBuffer);
|
||||
if (strncmp(varName, "<param:", sizeof("<param:") - 1) == 0) { // retry param:
|
||||
varName[*varLen - 1] = '\0'; // erase last >
|
||||
return ReplaceVariableByParameter(varName, sandboxBuffer);
|
||||
}
|
||||
if (strncmp(varData, "<lib>", sizeof("<lib>") - 1) == 0) { // retry lib
|
||||
if (strncmp(varName, "<lib>", sizeof("<lib>") - 1) == 0) { // retry lib
|
||||
ret = memcpy_s(sandboxBuffer->buffer + sandboxBuffer->current,
|
||||
sandboxBuffer->bufferLen - sandboxBuffer->current, APPSPAWN_LIB_NAME, strlen(APPSPAWN_LIB_NAME));
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
|
||||
sandboxBuffer->current += strlen(APPSPAWN_LIB_NAME);
|
||||
return 0;
|
||||
}
|
||||
// <deps-sandbox-path>
|
||||
if (strncmp(varData, "<deps-sandbox-path>", sizeof("<deps-sandbox-path>") - 1) == 0) {
|
||||
return ReplaceVariableForDeps(context, sandboxBuffer, extraData);
|
||||
}
|
||||
// no match revered origin data
|
||||
APPSPAWN_LOGE("ReplaceVariable var '%{public}s' no match variable", varData);
|
||||
APPSPAWN_LOGE("ReplaceVariable var '%{public}s' no match variable", varName);
|
||||
ret = memcpy_s(sandboxBuffer->buffer + sandboxBuffer->current,
|
||||
sandboxBuffer->bufferLen - sandboxBuffer->current, varData, *varLen);
|
||||
sandboxBuffer->bufferLen - sandboxBuffer->current, varName, *varLen);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
|
||||
sandboxBuffer->current += *varLen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int HandleVariableReplace(const SandboxContext *context, SandboxBuffer *sandboxBuffer,
|
||||
const char *source, const VarExtraData *extraData)
|
||||
static int HandleVariableReplace(const SandboxContext *context,
|
||||
SandboxBuffer *sandboxBuffer, const char *source, const VarExtraData *extraData)
|
||||
{
|
||||
size_t sourceLen = strlen(source);
|
||||
for (size_t i = 0; i < sourceLen; i++) {
|
||||
@ -195,6 +220,7 @@ const char *GetSandboxRealVar(const SandboxContext *context,
|
||||
APPSPAWN_CHECK_ONLY_EXPER(context != NULL, return NULL);
|
||||
APPSPAWN_CHECK(bufferType < ARRAY_LENGTH(context->buffer), return NULL, "Invalid index for buffer");
|
||||
SandboxBuffer *sandboxBuffer = &((SandboxContext *)context)->buffer[bufferType];
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandboxBuffer != NULL && sandboxBuffer->buffer != NULL, return NULL);
|
||||
const char *tmp = source;
|
||||
int ret = 0;
|
||||
if (prefix != NULL) { // copy prefix data
|
||||
@ -212,6 +238,18 @@ const char *GetSandboxRealVar(const SandboxContext *context,
|
||||
sandboxBuffer->buffer[sandboxBuffer->current] = '\0';
|
||||
// restore buffer
|
||||
sandboxBuffer->current = 0;
|
||||
|
||||
// For the depNode scenario, if there are variables in the deps path, a secondary replacement is required
|
||||
if (extraData != NULL && extraData->sandboxTag == SANDBOX_TAG_NAME_GROUP && extraData->data.depNode != NULL) {
|
||||
if (strstr(sandboxBuffer->buffer, "<") != NULL) {
|
||||
SandboxBuffer *tmpBuffer = &((SandboxContext *)context)->buffer[BUFFER_FOR_TMP];
|
||||
ret = HandleVariableReplace(context, tmpBuffer, sandboxBuffer->buffer, extraData);
|
||||
APPSPAWN_CHECK(ret == 0, return NULL, "Failed to replace source %{public}s ", sandboxBuffer->buffer);
|
||||
tmpBuffer->buffer[tmpBuffer->current] = '\0';
|
||||
ret = strcpy_s(sandboxBuffer->buffer, sandboxBuffer->bufferLen, tmpBuffer->buffer);
|
||||
APPSPAWN_CHECK(ret == 0, return NULL, "Failed to copy source %{public}s ", sandboxBuffer->buffer);
|
||||
}
|
||||
}
|
||||
return sandboxBuffer->buffer;
|
||||
}
|
||||
|
||||
@ -239,6 +277,18 @@ void AddDefaultVariable(void)
|
||||
AddVariableReplaceHandler(PARAMETER_PACKAGE_NAME, VarPackageNameReplace);
|
||||
AddVariableReplaceHandler(PARAMETER_USER_ID, VarCurrentUseIdReplace);
|
||||
AddVariableReplaceHandler(PARAMETER_PACKAGE_INDEX, VarPackageNameIndexReplace);
|
||||
/*
|
||||
deps-path路径变量的含义:
|
||||
1)首次挂载时,表示mount-paths-deps->sandbox-path 【STAGE_GLOBAL或者应用孵化时的挂载】
|
||||
使用 MOUNT_PATH_OP_REPLACE_BY_SANDBOX 标记
|
||||
2)二次挂载时,表示mount-paths-deps->src-path;
|
||||
如果mount-paths-deps->src-path为空,则使用mount-paths-deps->sandbox-path
|
||||
使用 MOUNT_PATH_OP_ONLY_SANDBOX + MOUNT_PATH_OP_REPLACE_BY_SRC,只使用源目录,不添加root-dir
|
||||
【RemountByName时,如el2解锁或nweb更新时】
|
||||
*/
|
||||
AddVariableReplaceHandler("<deps-sandbox-path>", ReplaceVariableForDepSandboxPath);
|
||||
AddVariableReplaceHandler("<deps-src-path>", ReplaceVariableForDepSrcPath);
|
||||
AddVariableReplaceHandler("<deps-path>", ReplaceVariableForDepPath);
|
||||
}
|
||||
|
||||
void ClearVariable(void)
|
||||
|
6
modules/sandbox/sandbox_expand.c
Executable file → Normal file
6
modules/sandbox/sandbox_expand.c
Executable file → Normal file
@ -62,7 +62,7 @@ static int MountAllHsp(const SandboxContext *context, const cJSON *hsps)
|
||||
APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path");
|
||||
// sandbox path
|
||||
len = sprintf_s(context->buffer[1].buffer, context->buffer[1].bufferLen, "%s%s%s/%s",
|
||||
context->sandboxPackagePath, SANDBOX_INSTALL_PATH, libBundleName, libModuleName);
|
||||
context->rootPath, SANDBOX_INSTALL_PATH, libBundleName, libModuleName);
|
||||
APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path");
|
||||
|
||||
CreateSandboxDir(context->buffer[1].buffer, FILE_MODE);
|
||||
@ -105,7 +105,7 @@ static int MountAllGroup(const SandboxContext *context, const cJSON *groups)
|
||||
|
||||
char *dataGroupUuid = GetLastPath(libPhysicalPath);
|
||||
int len = sprintf_s(context->buffer[0].buffer, context->buffer[0].bufferLen, "%s%s%s",
|
||||
context->sandboxPackagePath, SANDBOX_GROUP_PATH, dataGroupUuid);
|
||||
context->rootPath, SANDBOX_GROUP_PATH, dataGroupUuid);
|
||||
APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path");
|
||||
APPSPAWN_LOGV("MountAllGroup src: '%{public}s' =>'%{public}s'", libPhysicalPath, context->buffer[0].buffer);
|
||||
|
||||
@ -153,7 +153,7 @@ static int SetOverlayAppPath(const char *hapPath, void *context)
|
||||
return 0;
|
||||
}
|
||||
int len = sprintf_s(sandboxContext->buffer[1].buffer, sandboxContext->buffer[1].bufferLen, "%s%s",
|
||||
sandboxContext->sandboxPackagePath, SANDBOX_OVERLAY_PATH);
|
||||
sandboxContext->rootPath, SANDBOX_OVERLAY_PATH);
|
||||
APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path");
|
||||
ret = strcat_s(sandboxContext->buffer[1].buffer, sandboxContext->buffer[1].bufferLen - len, tmp + 1);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret);
|
||||
|
179
modules/sandbox/sandbox_load.c
Executable file → Normal file
179
modules/sandbox/sandbox_load.c
Executable file → Normal file
@ -57,9 +57,10 @@ static const SandboxFlagInfo NAME_GROUP_TYPE_MAP[] = {
|
||||
{"app-variable", (unsigned long)SANDBOX_TAG_APP_VARIABLE}
|
||||
};
|
||||
|
||||
static inline PathMountNode *CreatePathMountNode(uint32_t type)
|
||||
static inline PathMountNode *CreatePathMountNode(uint32_t type, uint32_t hasDemandInfo)
|
||||
{
|
||||
return (PathMountNode *)CreateSandboxMountNode(sizeof(PathMountNode), type);
|
||||
uint32_t len = hasDemandInfo ? sizeof(PathDemandInfo) : 0;
|
||||
return (PathMountNode *)CreateSandboxMountNode(sizeof(PathMountNode) + len, type);
|
||||
}
|
||||
|
||||
static inline SymbolLinkNode *CreateSymbolLinkNode(void)
|
||||
@ -80,15 +81,13 @@ static inline SandboxFlagsNode *CreateSandboxFlagsNode(const char *name)
|
||||
|
||||
static inline SandboxNameGroupNode *CreateSandboxNameGroupNode(const char *name)
|
||||
{
|
||||
return (SandboxNameGroupNode *)CreateSandboxSection(name,
|
||||
sizeof(SandboxNameGroupNode), SANDBOX_TAG_NAME_GROUP);
|
||||
return (SandboxNameGroupNode *)CreateSandboxSection(name, sizeof(SandboxNameGroupNode), SANDBOX_TAG_NAME_GROUP);
|
||||
}
|
||||
|
||||
static inline SandboxPermissionNode *CreateSandboxPermissionNode(const char *name)
|
||||
{
|
||||
size_t len = sizeof(SandboxPermissionNode);
|
||||
SandboxPermissionNode *node = (SandboxPermissionNode *)
|
||||
CreateSandboxSection(name, len, SANDBOX_TAG_PERMISSION);
|
||||
SandboxPermissionNode *node = (SandboxPermissionNode *)CreateSandboxSection(name, len, SANDBOX_TAG_PERMISSION);
|
||||
APPSPAWN_CHECK(node != NULL, return NULL, "Failed to create permission node");
|
||||
node->permissionIndex = 0;
|
||||
return node;
|
||||
@ -187,16 +186,31 @@ static uint32_t GetFlagIndexFromJson(const cJSON *config)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PathMountNode *DecodeMountPathConfig(const cJSON *config, uint32_t type)
|
||||
static void FillPathDemandInfo(const cJSON *config, PathMountNode *sandboxNode)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(config != NULL, return);
|
||||
sandboxNode->demandInfo->uid = GetIntValueFromJsonObj(config, "uid", -1);
|
||||
sandboxNode->demandInfo->gid = GetIntValueFromJsonObj(config, "gid", -1);
|
||||
sandboxNode->demandInfo->mode = GetIntValueFromJsonObj(config, "ugo", -1);
|
||||
}
|
||||
|
||||
static PathMountNode *DecodeMountPathConfig(const SandboxSection *section, const cJSON *config, uint32_t type)
|
||||
{
|
||||
char *srcPath = GetStringFromJsonObj(config, "src-path");
|
||||
char *dstPath = GetStringFromJsonObj(config, "sandbox-path");
|
||||
if (srcPath == NULL || dstPath == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PathMountNode *tmp = GetPathMountNode(section, type, srcPath, dstPath);
|
||||
if (tmp != NULL) { // 删除老的节点,保存新的节点
|
||||
DeleteSandboxMountNode((SandboxMountNode *)tmp);
|
||||
APPSPAWN_LOGW("path %{public}s %{public}s repeat config, delete old", srcPath, dstPath);
|
||||
}
|
||||
|
||||
PathMountNode *sandboxNode = CreatePathMountNode(type);
|
||||
cJSON *demandInfo = cJSON_GetObjectItemCaseSensitive(config, "create-on-demand");
|
||||
PathMountNode *sandboxNode = CreatePathMountNode(type, demandInfo != NULL);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandboxNode != NULL, return NULL);
|
||||
sandboxNode->createDemand = demandInfo != NULL;
|
||||
sandboxNode->source = strdup(srcPath);
|
||||
sandboxNode->target = strdup(dstPath);
|
||||
|
||||
@ -209,6 +223,7 @@ static PathMountNode *DecodeMountPathConfig(const cJSON *config, uint32_t type)
|
||||
if (value != NULL) {
|
||||
sandboxNode->appAplName = strdup(value);
|
||||
}
|
||||
FillPathDemandInfo(demandInfo, sandboxNode);
|
||||
|
||||
if (sandboxNode->source == NULL || sandboxNode->target == NULL) {
|
||||
APPSPAWN_LOGE("Failed to get sourc or target path");
|
||||
@ -229,14 +244,14 @@ static int ParseMountPathsConfig(AppSpawnSandboxCfg *sandbox,
|
||||
if (mntJson == NULL) {
|
||||
continue;
|
||||
}
|
||||
PathMountNode *sandboxNode = DecodeMountPathConfig(mntJson, type);
|
||||
PathMountNode *sandboxNode = DecodeMountPathConfig(section, mntJson, type);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandboxNode != NULL, continue);
|
||||
AddSandboxMountNode(&sandboxNode->sandboxNode, section);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SymbolLinkNode *DecodeSymbolLinksConfig(const cJSON *config)
|
||||
static SymbolLinkNode *DecodeSymbolLinksConfig(const SandboxSection *section, const cJSON *config)
|
||||
{
|
||||
const char *target = GetStringFromJsonObj(config, "target-name");
|
||||
const char *linkName = GetStringFromJsonObj(config, "link-name");
|
||||
@ -244,6 +259,12 @@ static SymbolLinkNode *DecodeSymbolLinksConfig(const cJSON *config)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SymbolLinkNode *tmp = GetSymbolLinkNode(section, target, linkName);
|
||||
if (tmp != NULL) { // 删除老的节点,保存新的节点
|
||||
DeleteSandboxMountNode((SandboxMountNode *)tmp);
|
||||
APPSPAWN_LOGW("SymbolLink %{public}s %{public}s repeat config, delete old", target, linkName);
|
||||
}
|
||||
|
||||
SymbolLinkNode *node = CreateSymbolLinkNode();
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
|
||||
node->destMode = GetChmodFromJson(config);
|
||||
@ -258,8 +279,7 @@ static SymbolLinkNode *DecodeSymbolLinksConfig(const cJSON *config)
|
||||
return node;
|
||||
}
|
||||
|
||||
static int ParseSymbolLinksConfig(AppSpawnSandboxCfg *sandbox,
|
||||
const cJSON *symbolLinkConfigs, SandboxSection *section)
|
||||
static int ParseSymbolLinksConfig(AppSpawnSandboxCfg *sandbox, const cJSON *symbolLinkConfigs, SandboxSection *section)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(symbolLinkConfigs != NULL && cJSON_IsArray(symbolLinkConfigs), return -1);
|
||||
uint32_t symlinkPointSize = cJSON_GetArraySize(symbolLinkConfigs);
|
||||
@ -268,7 +288,7 @@ static int ParseSymbolLinksConfig(AppSpawnSandboxCfg *sandbox,
|
||||
if (symConfig == NULL) {
|
||||
continue;
|
||||
}
|
||||
SymbolLinkNode *node = DecodeSymbolLinksConfig(symConfig);
|
||||
SymbolLinkNode *node = DecodeSymbolLinksConfig(section, symConfig);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
|
||||
AddSandboxMountNode(&node->sandboxNode, section);
|
||||
}
|
||||
@ -282,12 +302,24 @@ static int ParseGidTableConfig(AppSpawnSandboxCfg *sandbox, const cJSON *configs
|
||||
APPSPAWN_CHECK_ONLY_EXPER(arrayLen > 0, return 0);
|
||||
APPSPAWN_CHECK(arrayLen < APP_MAX_GIDS, arrayLen = APP_MAX_GIDS, "More gid in gids json.");
|
||||
|
||||
// 配置存在,以后面的配置为准
|
||||
if (section->gidTable) {
|
||||
free(section->gidTable);
|
||||
section->gidTable = NULL;
|
||||
section->gidCount = 0;
|
||||
}
|
||||
section->gidTable = (gid_t *)calloc(1, sizeof(gid_t) * arrayLen);
|
||||
APPSPAWN_CHECK(section->gidTable != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory.");
|
||||
|
||||
for (uint32_t i = 0; i < arrayLen; i++) {
|
||||
char *value = cJSON_GetStringValue(cJSON_GetArrayItem(configs, i));
|
||||
gid_t gid = DecodeGid(value);
|
||||
cJSON *item = cJSON_GetArrayItem(configs, i);
|
||||
gid_t gid = 0;
|
||||
if (cJSON_IsNumber(item)) {
|
||||
gid = (gid_t)cJSON_GetNumberValue(item);
|
||||
} else {
|
||||
char *value = cJSON_GetStringValue(item);
|
||||
gid = DecodeGid(value);
|
||||
}
|
||||
if (gid <= 0) {
|
||||
continue;
|
||||
}
|
||||
@ -301,13 +333,27 @@ static int ParseMountGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *grou
|
||||
APPSPAWN_CHECK(cJSON_IsArray(groupConfig),
|
||||
return APPSPAWN_SANDBOX_INVALID, "Invalid mount-groups config %{public}s", section->name);
|
||||
|
||||
// 合并name-group
|
||||
uint32_t count = (uint32_t)cJSON_GetArraySize(groupConfig);
|
||||
section->nameGroups = (SandboxMountNode **)malloc(sizeof(SandboxMountNode *) * count);
|
||||
APPSPAWN_CHECK(section->nameGroups != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory for group name");
|
||||
APPSPAWN_LOGV("mount-group in section %{public}s %{public}u", section->name, count);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(count > 0, return 0);
|
||||
count += section->number;
|
||||
SandboxMountNode **nameGroups = (SandboxMountNode **)calloc(1, sizeof(SandboxMountNode *) * count);
|
||||
APPSPAWN_CHECK(nameGroups != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory for group name");
|
||||
|
||||
uint32_t j = 0;
|
||||
uint32_t number = 0;
|
||||
for (j = 0; j < section->number; j++) { // copy old
|
||||
if (section->nameGroups[j] == NULL) {
|
||||
continue;
|
||||
}
|
||||
nameGroups[number++] = section->nameGroups[j];
|
||||
}
|
||||
|
||||
SandboxNameGroupNode *mountNode = NULL;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
section->nameGroups[i] = NULL;
|
||||
nameGroups[number] = NULL;
|
||||
|
||||
char *name = cJSON_GetStringValue(cJSON_GetArrayItem(groupConfig, i));
|
||||
mountNode = (SandboxNameGroupNode *)GetSandboxSection(&sandbox->nameGroupsQueue, name);
|
||||
if (mountNode == NULL) {
|
||||
@ -319,8 +365,25 @@ static int ParseMountGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *grou
|
||||
APPSPAWN_LOGE("Invalid name-group %{public}s", name);
|
||||
continue;
|
||||
}
|
||||
section->nameGroups[section->number++] = (SandboxMountNode *)mountNode;
|
||||
// 过滤重复的节点
|
||||
for (j = 0; j < section->number; j++) {
|
||||
if (section->nameGroups[j] != NULL && section->nameGroups[j] == (SandboxMountNode *)mountNode) {
|
||||
APPSPAWN_LOGE("Name-group %{public}s bas been set", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < section->number) {
|
||||
continue;
|
||||
}
|
||||
nameGroups[number++] = (SandboxMountNode *)mountNode;
|
||||
APPSPAWN_LOGV("Name-group %{public}d %{public}s set", section->number, name);
|
||||
}
|
||||
if (section->nameGroups != NULL) {
|
||||
free(section->nameGroups);
|
||||
}
|
||||
section->nameGroups = nameGroups;
|
||||
section->number = number;
|
||||
APPSPAWN_LOGV("mount-group in section %{public}s %{public}u", section->name, section->number);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -367,7 +430,10 @@ static int ParseBaseConfig(AppSpawnSandboxCfg *sandbox, SandboxSection *section,
|
||||
static int ParsePackageNameConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *packageNameConfigs)
|
||||
{
|
||||
APPSPAWN_LOGV("Parse package-name config %{public}s", name);
|
||||
SandboxPackageNameNode *node = CreateSandboxPackageNameNode(name);
|
||||
SandboxPackageNameNode *node = (SandboxPackageNameNode *)GetSandboxSection(&sandbox->packageNameQueue, name);
|
||||
if (node == NULL) {
|
||||
node = CreateSandboxPackageNameNode(name);
|
||||
}
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
|
||||
|
||||
int ret = ParseBaseConfig(sandbox, &node->section, packageNameConfigs);
|
||||
@ -384,8 +450,10 @@ static int ParseSpawnFlagsConfig(AppSpawnSandboxCfg *sandbox, const char *name,
|
||||
{
|
||||
uint32_t flagIndex = GetFlagIndexFromJson(flagsConfig);
|
||||
APPSPAWN_LOGV("Parse spawn-flags config %{public}s flagIndex %{public}u", name, flagIndex);
|
||||
|
||||
SandboxFlagsNode *node = CreateSandboxFlagsNode(name);
|
||||
SandboxFlagsNode *node = (SandboxFlagsNode *)GetSandboxSection(&sandbox->spawnFlagsQueue, name);
|
||||
if (node == NULL) {
|
||||
node = CreateSandboxFlagsNode(name);
|
||||
}
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
|
||||
node->flagIndex = flagIndex;
|
||||
|
||||
@ -402,7 +470,10 @@ static int ParseSpawnFlagsConfig(AppSpawnSandboxCfg *sandbox, const char *name,
|
||||
static int ParsePermissionConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *permissionConfig)
|
||||
{
|
||||
APPSPAWN_LOGV("Parse permission config %{public}s", name);
|
||||
SandboxPermissionNode *node = CreateSandboxPermissionNode(name);
|
||||
SandboxPermissionNode *node = (SandboxPermissionNode *)GetSandboxSection(&sandbox->permissionQueue, name);
|
||||
if (node == NULL) {
|
||||
node = CreateSandboxPermissionNode(name);
|
||||
}
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
|
||||
|
||||
int ret = ParseBaseConfig(sandbox, &node->section, permissionConfig);
|
||||
@ -421,18 +492,24 @@ static SandboxNameGroupNode *ParseNameGroup(AppSpawnSandboxCfg *sandbox, const c
|
||||
char *name = GetStringFromJsonObj(groupConfig, "name");
|
||||
APPSPAWN_CHECK(name != NULL, return NULL, "No name in name group config");
|
||||
APPSPAWN_LOGV("Parse name-group config %{public}s", name);
|
||||
SandboxNameGroupNode *node = CreateSandboxNameGroupNode(name);
|
||||
SandboxNameGroupNode *node = (SandboxNameGroupNode *)GetSandboxSection(&sandbox->nameGroupsQueue, name);
|
||||
if (node == NULL) {
|
||||
node = CreateSandboxNameGroupNode(name);
|
||||
}
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
|
||||
|
||||
cJSON *obj = cJSON_GetObjectItemCaseSensitive(groupConfig, "mount-paths-deps");
|
||||
if (obj) {
|
||||
node->depNode = DecodeMountPathConfig(obj, SANDBOX_TAG_MOUNT_PATH);
|
||||
if (node->depNode) { // free repeat
|
||||
DeleteSandboxMountNode((SandboxMountNode *)node->depNode);
|
||||
}
|
||||
node->depNode = DecodeMountPathConfig(NULL, obj, SANDBOX_TAG_MOUNT_PATH);
|
||||
if (node->depNode == NULL) {
|
||||
DeleteSandboxSection((SandboxSection *)node);
|
||||
return NULL;
|
||||
}
|
||||
// "mount-mode": "not-exists"
|
||||
node->mountMode = GetMountModeFromConfig(obj, "mount-mode", MOUNT_MODE_ALWAYS);
|
||||
// "deps-mode": "not-exists"
|
||||
node->depMode = GetMountModeFromConfig(groupConfig, "deps-mode", MOUNT_MODE_ALWAYS);
|
||||
}
|
||||
|
||||
ret = ParseBaseConfig(sandbox, &node->section, groupConfig);
|
||||
@ -457,8 +534,6 @@ static int ParseNameGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *root)
|
||||
int count = cJSON_GetArraySize(configs);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(count > 0, return 0);
|
||||
|
||||
sandbox->depGroupNodes = (SandboxNameGroupNode **)calloc(1, sizeof(SandboxNameGroupNode *) * count);
|
||||
APPSPAWN_CHECK(sandbox->depGroupNodes != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed alloc memory ");
|
||||
sandbox->depNodeCount = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
cJSON *json = cJSON_GetArrayItem(configs, i);
|
||||
@ -468,7 +543,7 @@ static int ParseNameGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *root)
|
||||
SandboxNameGroupNode *node = ParseNameGroup(sandbox, json);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return APPSPAWN_SANDBOX_INVALID);
|
||||
if (node->depNode) {
|
||||
sandbox->depGroupNodes[sandbox->depNodeCount++] = node;
|
||||
sandbox->depNodeCount++;
|
||||
}
|
||||
}
|
||||
APPSPAWN_LOGV("ParseNameGroupsConfig depNodeCount %{public}d", sandbox->depNodeCount);
|
||||
@ -506,6 +581,9 @@ static int ParseGlobalSandboxConfig(AppSpawnSandboxCfg *sandbox, const cJSON *ro
|
||||
sandbox->sandboxNsFlags = GetSandboxNsFlags(json);
|
||||
char *rootPath = GetStringFromJsonObj(json, "sandbox-root");
|
||||
APPSPAWN_CHECK(rootPath != NULL, return APPSPAWN_SYSTEM_ERROR, "No root path in config");
|
||||
if (sandbox->rootPath) {
|
||||
free(sandbox->rootPath);
|
||||
}
|
||||
sandbox->rootPath = strdup(rootPath);
|
||||
APPSPAWN_CHECK(sandbox->rootPath != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to copy root path");
|
||||
sandbox->topSandboxSwitch = GetBoolValueFromJsonObj(json, "top-sandbox-switch", true);
|
||||
@ -513,9 +591,15 @@ static int ParseGlobalSandboxConfig(AppSpawnSandboxCfg *sandbox, const cJSON *ro
|
||||
return 0;
|
||||
}
|
||||
|
||||
APPSPAWN_STATIC int ParseAppSandboxConfig(const cJSON *root, AppSpawnSandboxCfg *sandbox)
|
||||
typedef struct TagParseJsonContext {
|
||||
AppSpawnSandboxCfg *sandboxCfg;
|
||||
}ParseJsonContext;
|
||||
|
||||
APPSPAWN_STATIC int ParseAppSandboxConfig(const cJSON *root, ParseJsonContext *context)
|
||||
{
|
||||
APPSPAWN_CHECK(root != NULL && sandbox, return APPSPAWN_SYSTEM_ERROR, "Invalid json");
|
||||
APPSPAWN_CHECK(root != NULL && context != NULL && context->sandboxCfg != NULL,
|
||||
return APPSPAWN_SYSTEM_ERROR, "Invalid json");
|
||||
AppSpawnSandboxCfg *sandbox = context->sandboxCfg;
|
||||
int ret = ParseGlobalSandboxConfig(sandbox, root); // "global":
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return APPSPAWN_SANDBOX_INVALID);
|
||||
ret = ParseNameGroupsConfig(sandbox, root); // name-groups
|
||||
@ -525,10 +609,13 @@ APPSPAWN_STATIC int ParseAppSandboxConfig(const cJSON *root, AppSpawnSandboxCfg
|
||||
cJSON *required = cJSON_GetObjectItemCaseSensitive(root, "required");
|
||||
if (required) {
|
||||
cJSON *config = NULL;
|
||||
cJSON_ArrayForEach(config, required) {
|
||||
cJSON_ArrayForEach(config, required)
|
||||
{
|
||||
APPSPAWN_LOGI("Sandbox required config: %{public}s", config->string);
|
||||
SandboxSection *section = CreateSandboxSection(config->string, sizeof(SandboxSection),
|
||||
SANDBOX_TAG_REQUIRED);
|
||||
SandboxSection *section = GetSandboxSection(&sandbox->requiredQueue, config->string);
|
||||
if (section == NULL) {
|
||||
section = CreateSandboxSection(config->string, sizeof(SandboxSection), SANDBOX_TAG_REQUIRED);
|
||||
}
|
||||
APPSPAWN_CHECK_ONLY_EXPER(section != NULL, return -1);
|
||||
|
||||
int ret = ParseBaseConfig(sandbox, section, config);
|
||||
@ -564,7 +651,10 @@ int LoadAppSandboxConfig(AppSpawnSandboxCfg *sandbox, int nwebSpawn)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandbox != NULL, return APPSPAWN_ARG_INVALID);
|
||||
const char *sandboxName = nwebSpawn ? WEB_SANDBOX_FILE_NAME : APP_SANDBOX_FILE_NAME;
|
||||
int ret = ParseSandboxConfig("etc/sandbox", sandboxName, ParseAppSandboxConfig, sandbox);
|
||||
|
||||
ParseJsonContext context = {};
|
||||
context.sandboxCfg = sandbox;
|
||||
int ret = ParseJsonConfig("etc/sandbox", sandboxName, ParseAppSandboxConfig, &context);
|
||||
if (ret == APPSPAWN_SANDBOX_NONE) {
|
||||
APPSPAWN_LOGW("No sandbox config");
|
||||
ret = 0;
|
||||
@ -574,5 +664,22 @@ int LoadAppSandboxConfig(AppSpawnSandboxCfg *sandbox, int nwebSpawn)
|
||||
sandbox->appFullMountEnable = CheckAppFullMountEnable();
|
||||
APPSPAWN_LOGI("Sandbox pidNamespaceSupport: %{public}d appFullMountEnable: %{public}d",
|
||||
sandbox->pidNamespaceSupport, sandbox->appFullMountEnable);
|
||||
|
||||
uint32_t depNodeCount = sandbox->depNodeCount;
|
||||
APPSPAWN_CHECK_ONLY_EXPER(depNodeCount > 0, return ret);
|
||||
|
||||
sandbox->depGroupNodes = (SandboxNameGroupNode **)calloc(1, sizeof(SandboxNameGroupNode *) * depNodeCount);
|
||||
APPSPAWN_CHECK(sandbox->depGroupNodes != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed alloc memory ");
|
||||
sandbox->depNodeCount = 0;
|
||||
ListNode *node = sandbox->nameGroupsQueue.front.next;
|
||||
while (node != &sandbox->nameGroupsQueue.front) {
|
||||
SandboxNameGroupNode *groupNode = (SandboxNameGroupNode *)ListEntry(node, SandboxMountNode, node);
|
||||
if (groupNode->depNode) {
|
||||
sandbox->depGroupNodes[sandbox->depNodeCount++] = groupNode;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
APPSPAWN_LOGI("LoadAppSandboxConfig depNodeCount %{public}d", sandbox->depNodeCount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
190
modules/sandbox/sandbox_manager.c
Executable file → Normal file
190
modules/sandbox/sandbox_manager.c
Executable file → Normal file
@ -17,6 +17,7 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_permission.h"
|
||||
#include "appspawn_sandbox.h"
|
||||
#include "appspawn_utils.h"
|
||||
@ -79,8 +80,58 @@ void AddSandboxMountNode(SandboxMountNode *node, SandboxSection *queue)
|
||||
OH_ListAddWithOrder(&queue->front, &node->node, SandboxNodeCompareProc);
|
||||
}
|
||||
|
||||
static int PathMountNodeCompare(ListNode *node, void *data)
|
||||
{
|
||||
PathMountNode *node1 = (PathMountNode *)ListEntry(node, SandboxMountNode, node);
|
||||
PathMountNode *node2 = (PathMountNode *)data;
|
||||
return (node1->sandboxNode.type == node2->sandboxNode.type) &&
|
||||
(strcmp(node1->source, node2->source) == 0) &&
|
||||
(strcmp(node1->target, node2->target) == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int SymbolLinkNodeCompare(ListNode *node, void *data)
|
||||
{
|
||||
SymbolLinkNode *node1 = (SymbolLinkNode *)ListEntry(node, SandboxMountNode, node);
|
||||
SymbolLinkNode *node2 = (SymbolLinkNode *)data;
|
||||
return (node1->sandboxNode.type == node2->sandboxNode.type) &&
|
||||
(strcmp(node1->target, node2->target) == 0) &&
|
||||
(strcmp(node1->linkName, node2->linkName) == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
PathMountNode *GetPathMountNode(const SandboxSection *section, int type, const char *source, const char *target)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(section != NULL, return NULL);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(source != NULL && target != NULL, return NULL);
|
||||
PathMountNode pathNode = {};
|
||||
pathNode.sandboxNode.type = type;
|
||||
pathNode.source = (char *)source;
|
||||
pathNode.target = (char *)target;
|
||||
ListNode *node = OH_ListFind(§ion->front, (void *)&pathNode, PathMountNodeCompare);
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return (PathMountNode *)ListEntry(node, SandboxMountNode, node);
|
||||
}
|
||||
|
||||
SymbolLinkNode *GetSymbolLinkNode(const SandboxSection *section, const char *target, const char *linkName)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(section != NULL, return NULL);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(linkName != NULL && target != NULL, return NULL);
|
||||
SymbolLinkNode linkNode = {};
|
||||
linkNode.sandboxNode.type = SANDBOX_TAG_SYMLINK;
|
||||
linkNode.target = (char *)target;
|
||||
linkNode.linkName = (char *)linkName;
|
||||
ListNode *node = OH_ListFind(§ion->front, (void *)&linkNode, SymbolLinkNodeCompare);
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return (SymbolLinkNode *)ListEntry(node, SandboxMountNode, node);
|
||||
}
|
||||
|
||||
void DeleteSandboxMountNode(SandboxMountNode *sandboxNode)
|
||||
{
|
||||
OH_ListRemove(&sandboxNode->node);
|
||||
OH_ListInit(&sandboxNode->node);
|
||||
switch (sandboxNode->type) {
|
||||
case SANDBOX_TAG_MOUNT_PATH:
|
||||
case SANDBOX_TAG_MOUNT_FILE:
|
||||
@ -161,7 +212,17 @@ static void ClearSandboxSection(SandboxSection *section)
|
||||
free(section->nameGroups);
|
||||
section->nameGroups = NULL;
|
||||
}
|
||||
|
||||
if (section->name) {
|
||||
free(section->name);
|
||||
section->name = NULL;
|
||||
}
|
||||
if (section->sandboxNode.type == SANDBOX_TAG_NAME_GROUP) {
|
||||
SandboxNameGroupNode *groupNode = (SandboxNameGroupNode *)section;
|
||||
APPSPAWN_LOGV("Free deps %p ", groupNode->depNode);
|
||||
if (groupNode->depNode) {
|
||||
DeleteSandboxMountNode((SandboxMountNode *)groupNode->depNode);
|
||||
}
|
||||
}
|
||||
// free mount path
|
||||
ListNode *node = section->front.next;
|
||||
while (node != §ion->front) {
|
||||
@ -191,8 +252,6 @@ static void DumpSandboxQueue(const ListNode *front,
|
||||
|
||||
static void DumpSandboxSection(const SandboxSection *section)
|
||||
{
|
||||
APPSPAPWN_DUMP(" ========================================= ");
|
||||
APPSPAPWN_DUMP(" Section %{public}s", section->name);
|
||||
APPSPAPWN_DUMP(" sandboxSwitch %{public}s", section->sandboxSwitch ? "true" : "false");
|
||||
APPSPAPWN_DUMP(" sandboxShared %{public}s", section->sandboxShared ? "true" : "false");
|
||||
APPSPAPWN_DUMP(" gidCount: %{public}u", section->gidCount);
|
||||
@ -253,7 +312,9 @@ SandboxSection *GetSandboxSection(const SandboxQueue *queue, const char *name)
|
||||
void AddSandboxSection(SandboxSection *node, SandboxQueue *queue)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL && queue != NULL, return);
|
||||
OH_ListAddWithOrder(&queue->front, &node->sandboxNode.node, SandboxConditionalNodeCompareNode);
|
||||
if (ListEmpty(node->sandboxNode.node)) {
|
||||
OH_ListAddWithOrder(&queue->front, &node->sandboxNode.node, SandboxConditionalNodeCompareNode);
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteSandboxSection(SandboxSection *section)
|
||||
@ -307,19 +368,47 @@ void DeleteAppSpawnSandbox(AppSpawnSandboxCfg *sandbox)
|
||||
SandboxQueueClear(&sandbox->packageNameQueue);
|
||||
SandboxQueueClear(&sandbox->spawnFlagsQueue);
|
||||
SandboxQueueClear(&sandbox->nameGroupsQueue);
|
||||
if (sandbox->rootPath) {
|
||||
free(sandbox->rootPath);
|
||||
}
|
||||
free(sandbox->depGroupNodes);
|
||||
sandbox->depGroupNodes = NULL;
|
||||
|
||||
free(sandbox);
|
||||
sandbox = NULL;
|
||||
}
|
||||
|
||||
static void DumpSandboxSectionNode(const SandboxMountNode *node, uint32_t index)
|
||||
static void DumpSandboxPermission(const SandboxMountNode *node, uint32_t index)
|
||||
{
|
||||
SandboxPermissionNode *permissionNode = (SandboxPermissionNode *)node;
|
||||
APPSPAPWN_DUMP(" ========================================= ");
|
||||
APPSPAPWN_DUMP(" Section %{public}s", permissionNode->section.name);
|
||||
APPSPAPWN_DUMP(" Section permission index %{public}d", permissionNode->permissionIndex);
|
||||
DumpSandboxSection(&permissionNode->section);
|
||||
}
|
||||
|
||||
static void DumpSandboxSectionNode(const SandboxMountNode *node, uint32_t index)
|
||||
{
|
||||
SandboxSection *section = (SandboxSection *)node;
|
||||
APPSPAPWN_DUMP(" ========================================= ");
|
||||
APPSPAPWN_DUMP(" Section %{public}s", section->name);
|
||||
DumpSandboxSection(section);
|
||||
}
|
||||
|
||||
static void DumpSandboxNameGroupNode(const SandboxMountNode *node, uint32_t index)
|
||||
{
|
||||
SandboxNameGroupNode *nameGroupNode = (SandboxNameGroupNode *)node;
|
||||
APPSPAPWN_DUMP(" ========================================= ");
|
||||
APPSPAPWN_DUMP(" Section %{public}s", nameGroupNode->section.name);
|
||||
APPSPAPWN_DUMP(" Section dep mode %{public}s",
|
||||
nameGroupNode->depMode == MOUNT_MODE_ALWAYS ? "always" : "not-exists");
|
||||
if (nameGroupNode->depNode != NULL) {
|
||||
APPSPAPWN_DUMP(" mount-paths-deps: ");
|
||||
DumpMountPathMountNode(nameGroupNode->depNode);
|
||||
}
|
||||
DumpSandboxSection(&nameGroupNode->section);
|
||||
}
|
||||
|
||||
|
||||
static void DumpSandbox(struct TagAppSpawnExtData *data)
|
||||
{
|
||||
AppSpawnSandboxCfg *sandbox = (AppSpawnSandboxCfg *)data;
|
||||
@ -335,16 +424,10 @@ static inline void InitSandboxQueue(SandboxQueue *queue, uint32_t type)
|
||||
static void FreeAppSpawnSandbox(struct TagAppSpawnExtData *data)
|
||||
{
|
||||
AppSpawnSandboxCfg *sandbox = ListEntry(data, AppSpawnSandboxCfg, extData);
|
||||
UnmountSandboxConfigs(sandbox);
|
||||
// delete all var
|
||||
DeleteAppSpawnSandbox(sandbox);
|
||||
}
|
||||
|
||||
static void ClearAppSpawnSandbox(struct TagAppSpawnExtData *data)
|
||||
{
|
||||
// clear no use sand box config
|
||||
}
|
||||
|
||||
AppSpawnSandboxCfg *CreateAppSpawnSandbox(void)
|
||||
{
|
||||
// create sandbox
|
||||
@ -355,7 +438,6 @@ AppSpawnSandboxCfg *CreateAppSpawnSandbox(void)
|
||||
OH_ListInit(&sandbox->extData.node);
|
||||
sandbox->extData.dataId = EXT_DATA_SANDBOX;
|
||||
sandbox->extData.freeNode = FreeAppSpawnSandbox;
|
||||
sandbox->extData.clearNode = ClearAppSpawnSandbox;
|
||||
sandbox->extData.dumpNode = DumpSandbox;
|
||||
|
||||
// queue
|
||||
@ -374,10 +456,6 @@ AppSpawnSandboxCfg *CreateAppSpawnSandbox(void)
|
||||
sandbox->depNodeCount = 0;
|
||||
sandbox->depGroupNodes = NULL;
|
||||
|
||||
for (uint32_t i = 0; i < ARRAY_LENGTH(sandbox->systemUids); i++) {
|
||||
sandbox->systemUids[i] = INVALID_UID;
|
||||
}
|
||||
|
||||
AddDefaultVariable();
|
||||
AddDefaultExpandAppSandboxConfigHandle();
|
||||
return sandbox;
|
||||
@ -386,17 +464,17 @@ AppSpawnSandboxCfg *CreateAppSpawnSandbox(void)
|
||||
void DumpAppSpawnSandboxCfg(AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandbox != NULL, return);
|
||||
APPSPAPWN_DUMP("Sandbox root path: %{public}s", sandbox->rootPath);
|
||||
APPSPAPWN_DUMP("Sandbox sandboxNsFlags: %{public}x ", sandbox->sandboxNsFlags);
|
||||
APPSPAPWN_DUMP("Sandbox topSandboxSwitch: %{public}s", sandbox->topSandboxSwitch ? "true" : "false");
|
||||
APPSPAPWN_DUMP("Sandbox appFullMountEnable: %{public}s", sandbox->appFullMountEnable ? "true" : "false");
|
||||
APPSPAPWN_DUMP("Sandbox pidNamespaceSupport: %{public}s", sandbox->pidNamespaceSupport ? "true" : "false");
|
||||
APPSPAPWN_DUMP("Sandbox common info: ");
|
||||
|
||||
DumpSandboxQueue(&sandbox->requiredQueue.front, DumpSandboxSectionNode);
|
||||
DumpSandboxQueue(&sandbox->packageNameQueue.front, DumpSandboxSectionNode);
|
||||
DumpSandboxQueue(&sandbox->permissionQueue.front, DumpSandboxSectionNode);
|
||||
DumpSandboxQueue(&sandbox->permissionQueue.front, DumpSandboxPermission);
|
||||
DumpSandboxQueue(&sandbox->spawnFlagsQueue.front, DumpSandboxSectionNode);
|
||||
DumpSandboxQueue(&sandbox->nameGroupsQueue.front, DumpSandboxSectionNode);
|
||||
DumpSandboxQueue(&sandbox->nameGroupsQueue.front, DumpSandboxNameGroupNode);
|
||||
}
|
||||
|
||||
static int PreLoadSandboxCfg(AppSpawnMgr *content)
|
||||
@ -419,6 +497,14 @@ static int PreLoadSandboxCfg(AppSpawnMgr *content)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SandboxHandleServerExit(AppSpawnMgr *content)
|
||||
{
|
||||
AppSpawnSandboxCfg *sandbox = GetAppSpawnSandbox(content);
|
||||
APPSPAWN_CHECK(sandbox != NULL, return 0, "Sandbox not load");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SpawnBuildSandboxEnv(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
AppSpawnSandboxCfg *appSandbox = GetAppSpawnSandbox(content);
|
||||
@ -432,6 +518,7 @@ int SpawnBuildSandboxEnv(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
}
|
||||
}
|
||||
int ret = MountSandboxConfigs(appSandbox, property, IsNWebSpawnMode(content));
|
||||
appSandbox->mounted = 1;
|
||||
// for module test do not create sandbox
|
||||
if (strncmp(GetBundleName(property), MODULE_TEST_BUNDLE_NAME, strlen(MODULE_TEST_BUNDLE_NAME)) == 0) {
|
||||
return 0;
|
||||
@ -445,6 +532,7 @@ static int AppendPermissionGid(const AppSpawnSandboxCfg *sandbox, AppSpawningCtx
|
||||
APPSPAWN_CHECK(dacInfo != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No tlv %{public}d in msg %{public}s", TLV_DAC_INFO, GetProcessName(property));
|
||||
|
||||
APPSPAWN_LOGV("AppendPermissionGid %{public}s", GetProcessName(property));
|
||||
ListNode *node = sandbox->permissionQueue.front.next;
|
||||
while (node != &sandbox->permissionQueue.front) {
|
||||
SandboxPermissionNode *permissionNode = (SandboxPermissionNode *)ListEntry(node, SandboxMountNode, node);
|
||||
@ -456,9 +544,9 @@ static int AppendPermissionGid(const AppSpawnSandboxCfg *sandbox, AppSpawningCtx
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
APPSPAWN_LOGV("Append permission gid %{public}s to %{public}s permission: %{public}u message: %{public}u",
|
||||
permissionNode->section.name, GetProcessName(property), permissionNode->section.gidCount,
|
||||
dacInfo->gidCount);
|
||||
APPSPAWN_LOGV("Add permission %{public}s gid %{public}d to %{public}s",
|
||||
permissionNode->section.name, permissionNode->section.gidTable[0], GetProcessName(property));
|
||||
|
||||
size_t copyLen = permissionNode->section.gidCount;
|
||||
if ((permissionNode->section.gidCount + dacInfo->gidCount) > APP_MAX_GIDS) {
|
||||
APPSPAWN_LOGW("More gid for %{public}s msg count %{public}u permission %{public}u",
|
||||
@ -470,35 +558,15 @@ static int AppendPermissionGid(const AppSpawnSandboxCfg *sandbox, AppSpawningCtx
|
||||
if (ret != EOK) {
|
||||
APPSPAWN_LOGW("Failed to append permission %{public}s gid to %{public}s",
|
||||
permissionNode->section.name, GetProcessName(property));
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
dacInfo->gidCount += copyLen;
|
||||
node = node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool IsSystemConstMounted(const AppSpawnSandboxCfg *sandbox, AppSpawnMsgDacInfo *info)
|
||||
{
|
||||
uid_t uid = info->uid / UID_BASE;
|
||||
for (uint32_t i = 0; i < ARRAY_LENGTH(sandbox->systemUids); i++) {
|
||||
if (sandbox->systemUids[i] == uid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int SetSystemConstMounted(AppSpawnSandboxCfg *sandbox, AppSpawnMsgDacInfo *info)
|
||||
{
|
||||
uid_t uid = info->uid / UID_BASE;
|
||||
for (uint32_t i = 0; i < ARRAY_LENGTH(sandbox->systemUids); i++) {
|
||||
if (sandbox->systemUids[i] == INVALID_UID) {
|
||||
sandbox->systemUids[i] = uid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SpawnPrepareSandboxCfg(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return -1);
|
||||
@ -515,26 +583,28 @@ int SpawnPrepareSandboxCfg(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
}
|
||||
int ret = AppendPermissionGid(sandbox, property);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to add gid for %{public}s", GetProcessName(property));
|
||||
|
||||
AppSpawnMsgDacInfo *info = (AppSpawnMsgDacInfo *)GetAppProperty(property, TLV_DAC_INFO);
|
||||
APPSPAWN_CHECK(info != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No tlv %{public}d in msg %{public}s", TLV_DAC_INFO, GetProcessName(property));
|
||||
if (!IsSystemConstMounted(sandbox, info)) {
|
||||
ret = StagedMountSystemConst(sandbox, property, IsNWebSpawnMode(content));
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to mount system-const for %{public}s", GetProcessName(property));
|
||||
SetSystemConstMounted(sandbox, info);
|
||||
} else {
|
||||
APPSPAWN_LOGW("System-const config [uid: %{public}u] has been set", info->uid / UID_BASE);
|
||||
}
|
||||
ret = StagedMountSystemConst(sandbox, property, IsNWebSpawnMode(content));
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to mount system-const for %{public}s", GetProcessName(property));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SandboxUnmountPath(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return -1);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(appInfo != NULL, return -1);
|
||||
APPSPAWN_LOGV("Sandbox process %{public}s %{public}u exit", appInfo->name, appInfo->uid);
|
||||
AppSpawnSandboxCfg *sandbox = GetAppSpawnSandbox(content);
|
||||
return UnmountDepPaths(sandbox, appInfo->uid);
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
APPSPAWN_LOGV("Load sandbox module ...");
|
||||
AddPreloadHook(HOOK_PRIO_SANDBOX, PreLoadSandboxCfg);
|
||||
AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_SANDBOX, SpawnPrepareSandboxCfg);
|
||||
AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_SANDBOX, SpawnBuildSandboxEnv);
|
||||
(void)AddServerStageHook(STAGE_SERVER_PRELOAD, HOOK_PRIO_SANDBOX, PreLoadSandboxCfg);
|
||||
(void)AddServerStageHook(STAGE_SERVER_EXIT, HOOK_PRIO_SANDBOX, SandboxHandleServerExit);
|
||||
(void)AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_SANDBOX, SpawnPrepareSandboxCfg);
|
||||
(void)AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_SANDBOX, SpawnBuildSandboxEnv);
|
||||
(void)AddProcessMgrHook(STAGE_SERVER_APP_DIED, 0, SandboxUnmountPath);
|
||||
}
|
||||
|
||||
MODULE_DESTRUCTOR(void)
|
||||
|
0
modules/sysevent/BUILD.gn
Executable file → Normal file
0
modules/sysevent/BUILD.gn
Executable file → Normal file
0
modules/sysevent/event_reporter.cpp
Executable file → Normal file
0
modules/sysevent/event_reporter.cpp
Executable file → Normal file
404
standard/appspawn_appmgr.c
Executable file
404
standard/appspawn_appmgr.c
Executable file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* 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 <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_msg.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "securec.h"
|
||||
|
||||
static AppSpawnMgr *g_appSpawnMgr = NULL;
|
||||
|
||||
AppSpawnMgr *CreateAppSpawnMgr(int mode)
|
||||
{
|
||||
AppSpawnMgr *appMgr = (AppSpawnMgr *)calloc(1, sizeof(AppSpawnMgr));
|
||||
APPSPAWN_CHECK(appMgr != NULL, return NULL, "Failed to alloc memory for appspawn");
|
||||
appMgr->content.longProcName = NULL;
|
||||
appMgr->content.longProcNameLen = 0;
|
||||
appMgr->content.mode = mode;
|
||||
appMgr->content.sandboxNsFlags = 0;
|
||||
appMgr->servicePid = getpid();
|
||||
appMgr->server = NULL;
|
||||
appMgr->sigHandler = NULL;
|
||||
OH_ListInit(&appMgr->appQueue);
|
||||
OH_ListInit(&appMgr->diedQueue);
|
||||
OH_ListInit(&appMgr->appSpawnQueue);
|
||||
appMgr->diedAppCount = 0;
|
||||
OH_ListInit(&appMgr->extData);
|
||||
g_appSpawnMgr = appMgr;
|
||||
return appMgr;
|
||||
}
|
||||
|
||||
AppSpawnMgr *GetAppSpawnMgr(void)
|
||||
{
|
||||
return g_appSpawnMgr;
|
||||
}
|
||||
|
||||
AppSpawnContent *GetAppSpawnContent(void)
|
||||
{
|
||||
return g_appSpawnMgr == NULL ? NULL : &g_appSpawnMgr->content;
|
||||
}
|
||||
|
||||
static void SpawningQueueDestroy(ListNode *node)
|
||||
{
|
||||
AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node);
|
||||
DeleteAppSpawningCtx(property);
|
||||
}
|
||||
|
||||
static void ExtDataDestroy(ListNode *node)
|
||||
{
|
||||
AppSpawnExtData *extData = ListEntry(node, AppSpawnExtData, node);
|
||||
AppSpawnExtDataFree freeNode = extData->freeNode;
|
||||
if (freeNode) {
|
||||
freeNode(extData);
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteAppSpawnMgr(AppSpawnMgr *mgr)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(mgr != NULL, return);
|
||||
OH_ListRemoveAll(&mgr->appQueue, NULL);
|
||||
OH_ListRemoveAll(&mgr->diedQueue, NULL);
|
||||
OH_ListRemoveAll(&mgr->appSpawnQueue, SpawningQueueDestroy);
|
||||
OH_ListRemoveAll(&mgr->extData, ExtDataDestroy);
|
||||
|
||||
APPSPAWN_LOGV("DeleteAppSpawnMgr %{public}d %{public}d", mgr->servicePid, getpid());
|
||||
free(mgr);
|
||||
if (g_appSpawnMgr == mgr) {
|
||||
g_appSpawnMgr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void TraversalSpawnedProcess(AppTraversal traversal, void *data)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && traversal != NULL, return);
|
||||
ListNode *node = g_appSpawnMgr->appQueue.next;
|
||||
while (node != &g_appSpawnMgr->appQueue) {
|
||||
ListNode *next = node->next;
|
||||
AppSpawnedProcess *appInfo = ListEntry(node, AppSpawnedProcess, node);
|
||||
traversal(g_appSpawnMgr, appInfo, data);
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
static int AppInfoPidComparePro(ListNode *node, void *data)
|
||||
{
|
||||
AppSpawnedProcess *node1 = ListEntry(node, AppSpawnedProcess, node);
|
||||
pid_t pid = *(pid_t *)data;
|
||||
return node1->pid - pid;
|
||||
}
|
||||
|
||||
static int AppInfoNameComparePro(ListNode *node, void *data)
|
||||
{
|
||||
AppSpawnedProcess *node1 = ListEntry(node, AppSpawnedProcess, node);
|
||||
return strcmp(node1->name, (char *)data);
|
||||
}
|
||||
|
||||
static int AppInfoCompareProc(ListNode *node, ListNode *newNode)
|
||||
{
|
||||
AppSpawnedProcess *node1 = ListEntry(node, AppSpawnedProcess, node);
|
||||
AppSpawnedProcess *node2 = ListEntry(newNode, AppSpawnedProcess, node);
|
||||
return node1->pid - node2->pid;
|
||||
}
|
||||
|
||||
AppSpawnedProcess *AddSpawnedProcess(pid_t pid, const char *processName)
|
||||
{
|
||||
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);
|
||||
size_t len = strlen(processName) + 1;
|
||||
AppSpawnedProcess *node = (AppSpawnedProcess *)calloc(1, sizeof(AppSpawnedProcess) + len + 1);
|
||||
APPSPAWN_CHECK(node != NULL, return NULL, "Failed to malloc for appinfo");
|
||||
|
||||
node->pid = pid;
|
||||
node->max = 0;
|
||||
node->uid = 0;
|
||||
node->exitStatus = 0;
|
||||
int ret = strcpy_s(node->name, len, processName);
|
||||
APPSPAWN_CHECK(ret == 0, free(node);
|
||||
return NULL, "Failed to strcpy process name");
|
||||
|
||||
OH_ListInit(&node->node);
|
||||
APPSPAWN_LOGI("Add %{public}s, pid=%{public}d success", processName, pid);
|
||||
OH_ListAddWithOrder(&g_appSpawnMgr->appQueue, &node->node, AppInfoCompareProc);
|
||||
return node;
|
||||
}
|
||||
|
||||
void TerminateSpawnedProcess(AppSpawnedProcess *node)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && node != NULL, return);
|
||||
if (!IsNWebSpawnMode(g_appSpawnMgr)) {
|
||||
OH_ListRemove(&node->node);
|
||||
free(node);
|
||||
return;
|
||||
}
|
||||
if (g_appSpawnMgr->diedAppCount >= MAX_DIED_PROCESS_COUNT) {
|
||||
AppSpawnedProcess *oldApp = ListEntry(g_appSpawnMgr->diedQueue.next, AppSpawnedProcess, node);
|
||||
OH_ListRemove(&oldApp->node);
|
||||
free(node);
|
||||
g_appSpawnMgr->diedAppCount--;
|
||||
}
|
||||
OH_ListRemove(&node->node);
|
||||
OH_ListInit(&node->node);
|
||||
APPSPAWN_LOGI("ProcessAppDied %{public}s, pid=%{public}d", node->name, node->pid);
|
||||
OH_ListAddTail(&g_appSpawnMgr->diedQueue, &node->node);
|
||||
g_appSpawnMgr->diedAppCount++;
|
||||
}
|
||||
|
||||
AppSpawnedProcess *GetSpawnedProcess(pid_t pid)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return NULL);
|
||||
ListNode *node = OH_ListFind(&g_appSpawnMgr->appQueue, &pid, AppInfoPidComparePro);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
|
||||
return ListEntry(node, AppSpawnedProcess, node);
|
||||
}
|
||||
|
||||
AppSpawnedProcess *GetSpawnedProcessByName(const char *name)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return NULL);
|
||||
ListNode *node = OH_ListFind(&g_appSpawnMgr->appQueue, (void *)name, AppInfoNameComparePro);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
|
||||
return ListEntry(node, AppSpawnedProcess, node);
|
||||
}
|
||||
|
||||
int KillAndWaitStatus(pid_t pid, int sig)
|
||||
{
|
||||
int exitStatus = 0;
|
||||
if (kill(pid, sig) != 0) {
|
||||
APPSPAWN_LOGE("unable to kill process, pid: %{public}d ret %{public}d", pid, errno);
|
||||
}
|
||||
|
||||
pid_t exitPid = waitpid(pid, &exitStatus, 0);
|
||||
if (exitPid != pid) {
|
||||
APPSPAWN_LOGE("waitpid failed, pid: %{public}d %{public}d, status: %{public}d", exitPid, pid, exitStatus);
|
||||
return -1;
|
||||
}
|
||||
return exitStatus;
|
||||
}
|
||||
|
||||
static int GetProcessTerminationStatus(pid_t pid)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return -1);
|
||||
APPSPAWN_LOGV("GetProcessTerminationStatus pid: %{public}d ", pid);
|
||||
if (pid <= 0) {
|
||||
return 0;
|
||||
}
|
||||
int exitStatus = 0;
|
||||
ListNode *node = OH_ListFind(&g_appSpawnMgr->diedQueue, &pid, AppInfoPidComparePro);
|
||||
if (node != NULL) {
|
||||
AppSpawnedProcess *info = ListEntry(node, AppSpawnedProcess, node);
|
||||
exitStatus = info->exitStatus;
|
||||
OH_ListRemove(node);
|
||||
free(info);
|
||||
return exitStatus;
|
||||
}
|
||||
return KillAndWaitStatus(pid, SIGKILL);
|
||||
}
|
||||
|
||||
AppSpawningCtx *CreateAppSpawningCtx(void)
|
||||
{
|
||||
static uint32_t requestId = 0;
|
||||
AppSpawningCtx *property = (AppSpawningCtx *)malloc(sizeof(AppSpawningCtx));
|
||||
APPSPAWN_CHECK(property != NULL, return NULL, "Failed to create AppSpawningCtx ");
|
||||
property->client.id = ++requestId;
|
||||
property->client.flags = 0;
|
||||
property->forkCtx.watcherHandle = NULL;
|
||||
property->forkCtx.coldRunPath = NULL;
|
||||
property->forkCtx.timer = NULL;
|
||||
property->forkCtx.fd[0] = -1;
|
||||
property->forkCtx.fd[1] = -1;
|
||||
property->forkCtx.shmId = -1;
|
||||
property->message = NULL;
|
||||
property->pid = 0;
|
||||
property->state = APP_STATE_IDLE;
|
||||
OH_ListInit(&property->node);
|
||||
if (g_appSpawnMgr) {
|
||||
OH_ListAddTail(&g_appSpawnMgr->appSpawnQueue, &property->node);
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
void DeleteAppSpawningCtx(AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != NULL, return);
|
||||
DeleteAppSpawnMsg(property->message);
|
||||
APPSPAWN_LOGV("DeleteAppSpawningCtx %{public}d %{public}d", property->forkCtx.fd[0], property->forkCtx.fd[1]);
|
||||
OH_ListRemove(&property->node);
|
||||
if (property->forkCtx.timer) {
|
||||
LE_StopTimer(LE_GetDefaultLoop(), property->forkCtx.timer);
|
||||
property->forkCtx.timer = NULL;
|
||||
}
|
||||
if (property->forkCtx.watcherHandle) {
|
||||
LE_RemoveWatcher(LE_GetDefaultLoop(), property->forkCtx.watcherHandle);
|
||||
property->forkCtx.watcherHandle = NULL;
|
||||
}
|
||||
if (property->forkCtx.coldRunPath) {
|
||||
free(property->forkCtx.coldRunPath);
|
||||
property->forkCtx.coldRunPath = NULL;
|
||||
}
|
||||
if (property->forkCtx.fd[0] >= 0) {
|
||||
close(property->forkCtx.fd[0]);
|
||||
}
|
||||
if (property->forkCtx.fd[1] >= 0) {
|
||||
close(property->forkCtx.fd[1]);
|
||||
}
|
||||
if (property->forkCtx.shmId >= 0) {
|
||||
(void)shmctl(property->forkCtx.shmId, IPC_RMID, NULL);
|
||||
property->forkCtx.shmId = -1;
|
||||
}
|
||||
free(property);
|
||||
}
|
||||
|
||||
static int AppPropertyComparePid(ListNode *node, void *data)
|
||||
{
|
||||
AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node);
|
||||
if (property->pid == *(pid_t *)data) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
AppSpawningCtx *GetAppSpawningCtxByPid(pid_t pid)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL, return NULL);
|
||||
ListNode *node = OH_ListFind(&g_appSpawnMgr->appSpawnQueue, (void *)&pid, AppPropertyComparePid);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
|
||||
return ListEntry(node, AppSpawningCtx, node);
|
||||
}
|
||||
|
||||
void AppSpawningCtxTraversal(ProcessTraversal traversal, void *data)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && traversal != NULL, return);
|
||||
ListNode *node = g_appSpawnMgr->appSpawnQueue.next;
|
||||
while (node != &g_appSpawnMgr->appSpawnQueue) {
|
||||
ListNode *next = node->next;
|
||||
AppSpawningCtx *ctx = ListEntry(node, AppSpawningCtx, node);
|
||||
traversal(g_appSpawnMgr, ctx, data);
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int SetSpawnMsgFlags(AppSpawnMsgFlags *msgFlags, uint32_t index)
|
||||
{
|
||||
uint32_t blockIndex = index / 32; // 32 max bit in int
|
||||
uint32_t bitIndex = index % 32; // 32 max bit in int
|
||||
if (blockIndex >= msgFlags->count) {
|
||||
return -1;
|
||||
}
|
||||
msgFlags->flags[blockIndex] |= (1 << bitIndex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetAppSpawnMsgFlag(const AppSpawnMsgNode *message, uint32_t type, uint32_t index)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(message != NULL, return -1);
|
||||
AppSpawnMsgFlags *msgFlags = (AppSpawnMsgFlags *)GetAppSpawnMsgInfo(message, type);
|
||||
APPSPAWN_CHECK(msgFlags != NULL, return -1,
|
||||
"No tlv %{public}d in msg %{public}s", type, message->msgHeader.processName);
|
||||
return SetSpawnMsgFlags(msgFlags, index);
|
||||
}
|
||||
|
||||
static int DumpAppSpawnQueue(ListNode *node, void *data)
|
||||
{
|
||||
AppSpawningCtx *property = ListEntry(node, AppSpawningCtx, node);
|
||||
APPSPAPWN_DUMP("app property id: %{public}u flags: %{public}x",
|
||||
property->client.id, property->client.flags);
|
||||
APPSPAPWN_DUMP("app property state: %{public}d", property->state);
|
||||
|
||||
DumpAppSpawnMsg(property->message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DumpAppQueue(ListNode *node, void *data)
|
||||
{
|
||||
AppSpawnedProcess *appInfo = ListEntry(node, AppSpawnedProcess, node);
|
||||
int64_t diff = DiffTime(&appInfo->spawnStart, &appInfo->spawnEnd);
|
||||
APPSPAPWN_DUMP("App info uid: %{public}u pid: %{public}x", appInfo->uid, appInfo->pid);
|
||||
APPSPAPWN_DUMP("App info name: %{public}s exitStatus: 0x%{public}x spawn time: %{public}" PRId64 " us ",
|
||||
appInfo->name, appInfo->exitStatus, diff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DumpExtData(ListNode *node, void *data)
|
||||
{
|
||||
AppSpawnExtData *extData = ListEntry(node, AppSpawnExtData, node);
|
||||
extData->dumpNode(extData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ProcessAppSpawnDumpMsg(const AppSpawnMsgNode *message)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && message != NULL, return);
|
||||
FILE *stream = NULL;
|
||||
uint32_t len = 0;
|
||||
char *ptyName = GetAppSpawnMsgExtInfo(message, "pty-name", &len);
|
||||
if (ptyName != NULL) { //
|
||||
APPSPAWN_LOGI("Dump info to file '%{public}s'", ptyName);
|
||||
stream = fopen(ptyName, "w");
|
||||
SetDumpToStream(stream);
|
||||
} else {
|
||||
SetDumpToStream(stdout);
|
||||
}
|
||||
APPSPAPWN_DUMP("Dump appspawn info start ... ");
|
||||
APPSPAPWN_DUMP("APP spawning queue: ");
|
||||
OH_ListTraversal((ListNode *)&g_appSpawnMgr->appSpawnQueue, NULL, DumpAppSpawnQueue, 0);
|
||||
APPSPAPWN_DUMP("APP queue: ");
|
||||
OH_ListTraversal((ListNode *)&g_appSpawnMgr->appQueue, "App queue", DumpAppQueue, 0);
|
||||
APPSPAPWN_DUMP("APP died queue: ");
|
||||
OH_ListTraversal((ListNode *)&g_appSpawnMgr->diedQueue, "App died queue", DumpAppQueue, 0);
|
||||
APPSPAPWN_DUMP("Ext data: ");
|
||||
OH_ListTraversal((ListNode *)&g_appSpawnMgr->extData, "Ext data", DumpExtData, 0);
|
||||
APPSPAPWN_DUMP("Dump appspawn info finish ");
|
||||
if (stream != NULL) {
|
||||
(void)fflush(stream);
|
||||
fclose(stream);
|
||||
#ifdef APPSPAWN_TEST
|
||||
SetDumpToStream(stdout);
|
||||
#else
|
||||
SetDumpToStream(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int ProcessTerminationStatusMsg(const AppSpawnMsgNode *message, AppSpawnResult *result)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(g_appSpawnMgr != NULL && message != NULL, return -1);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(result != NULL, return -1);
|
||||
if (!IsNWebSpawnMode(g_appSpawnMgr)) {
|
||||
return APPSPAWN_MSG_INVALID;
|
||||
}
|
||||
result->result = -1;
|
||||
result->pid = 0;
|
||||
pid_t *pid = (pid_t *)GetAppSpawnMsgInfo(message, TLV_RENDER_TERMINATION_INFO);
|
||||
if (pid == NULL) {
|
||||
return -1;
|
||||
}
|
||||
// get render process termination status, only nwebspawn need this logic.
|
||||
result->pid = *pid;
|
||||
result->result = GetProcessTerminationStatus(*pid);
|
||||
return 0;
|
||||
}
|
98
standard/appspawn_main.c
Executable file
98
standard/appspawn_main.c
Executable file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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 <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_modulemgr.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_service.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
#define APPSPAWN_PRELOAD "libappspawn_helper.z.so"
|
||||
|
||||
static void CheckPreload(char *const argv[])
|
||||
{
|
||||
char *preload = getenv("LD_PRELOAD");
|
||||
if (preload && strstr(preload, APPSPAWN_PRELOAD)) {
|
||||
return;
|
||||
}
|
||||
char buf[128] = APPSPAWN_PRELOAD; // 128 is enough in most cases
|
||||
if (preload && preload[0]) {
|
||||
int len = sprintf_s(buf, sizeof(buf), "%s:" APPSPAWN_PRELOAD, preload);
|
||||
APPSPAWN_CHECK(len > 0, return, "preload too long: %{public}s", preload);
|
||||
}
|
||||
int ret = setenv("LD_PRELOAD", buf, true);
|
||||
APPSPAWN_CHECK(ret == 0, return, "setenv fail: %{public}s", buf);
|
||||
ssize_t nread = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
|
||||
APPSPAWN_CHECK(nread != -1, return, "readlink fail: /proc/self/exe: %{public}d", errno);
|
||||
buf[nread] = 0;
|
||||
ret = execv(buf, argv);
|
||||
APPSPAWN_LOGE("execv fail: %{public}s: %{public}d: %{public}d", buf, errno, ret);
|
||||
}
|
||||
|
||||
// appspawn -mode appspawn | cold | nwebspawn -param app_property -fd clientFd
|
||||
int main(int argc, char *const argv[])
|
||||
{
|
||||
APPSPAWN_LOGE("main argc: %{public}d", argc);
|
||||
if (argc <= 0) {
|
||||
return 0;
|
||||
}
|
||||
uintptr_t start = (uintptr_t)argv[0];
|
||||
uintptr_t end = (uintptr_t)strchr(argv[argc - 1], 0);
|
||||
if (end == 0) {
|
||||
return 0;
|
||||
}
|
||||
CheckPreload(argv);
|
||||
(void)signal(SIGPIPE, SIG_IGN);
|
||||
uint32_t argvSize = end - start;
|
||||
AppSpawnStartArg arg = {};
|
||||
arg.mode = MODE_FOR_APP_SPAWN;
|
||||
arg.socketName = APPSPAWN_SOCKET_NAME;
|
||||
arg.serviceName = APPSPAWN_SERVER_NAME;
|
||||
arg.moduleType = MODULE_APPSPAWN;
|
||||
arg.initArg = 1;
|
||||
if (argc <= MODE_VALUE_INDEX) { // appspawn start
|
||||
arg.mode = MODE_FOR_APP_SPAWN;
|
||||
} else if (strcmp(argv[MODE_VALUE_INDEX], "app_cold") == 0) { // cold start
|
||||
APPSPAWN_CHECK(argc > PARAM_VALUE_INDEX, return 0, "Invalid arg for cold start %{public}d", argc);
|
||||
arg.mode = MODE_FOR_APP_COLD_RUN;
|
||||
arg.initArg = 0;
|
||||
} else if (strcmp(argv[MODE_VALUE_INDEX], "nweb_cold") == 0) { // cold start
|
||||
APPSPAWN_CHECK(argc > PARAM_VALUE_INDEX, return 0, "Invalid arg for cold start %{public}d", argc);
|
||||
arg.mode = MODE_FOR_NWEB_COLD_RUN;
|
||||
arg.moduleType = MODULE_NWEBSPAWN;
|
||||
arg.serviceName = NWEBSPAWN_SERVER_NAME;
|
||||
arg.initArg = 0;
|
||||
} else if (strcmp(argv[MODE_VALUE_INDEX], NWEBSPAWN_SERVER_NAME) == 0) { // nweb spawn start
|
||||
APPSPAWN_CHECK(argvSize >= APP_LEN_PROC_NAME,
|
||||
return 0, "Invalid arg size for service %{public}s", arg.serviceName);
|
||||
arg.mode = MODE_FOR_NWEB_SPAWN;
|
||||
arg.moduleType = MODULE_NWEBSPAWN;
|
||||
arg.socketName = NWEBSPAWN_SOCKET_NAME;
|
||||
arg.serviceName = NWEBSPAWN_SERVER_NAME;
|
||||
} else {
|
||||
APPSPAWN_CHECK(argvSize >= APP_LEN_PROC_NAME,
|
||||
return 0, "Invalid arg size for service %{public}s", arg.serviceName);
|
||||
}
|
||||
AppSpawnContent *content = StartSpawnService(&arg, argvSize, argc, argv);
|
||||
if (content != NULL) {
|
||||
content->runAppSpawn(content, argc, argv);
|
||||
}
|
||||
return 0;
|
||||
}
|
248
standard/appspawn_manager.h
Executable file
248
standard/appspawn_manager.h
Executable file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* 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 APPSPAWN_MANAGER_H
|
||||
#define APPSPAWN_MANAGER_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "appspawn.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_msg.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "list.h"
|
||||
#include "loop_event.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MODE_ID_INDEX 1
|
||||
#define MODE_VALUE_INDEX 2
|
||||
#define FD_ID_INDEX 3
|
||||
#define FD_VALUE_INDEX 4
|
||||
#define FLAGS_VALUE_INDEX 5
|
||||
#define SHM_ID_INDEX 6
|
||||
#define PARAM_ID_INDEX 7
|
||||
#define PARAM_VALUE_INDEX 8
|
||||
|
||||
#define MAX_DIED_PROCESS_COUNT 5
|
||||
|
||||
#define INVALID_OFFSET 0xffffffff
|
||||
|
||||
#define APP_STATE_IDLE 1
|
||||
#define APP_STATE_SPAWNING 2
|
||||
|
||||
#define APPSPAWN_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
typedef struct AppSpawnContent AppSpawnContent;
|
||||
typedef struct AppSpawnClient AppSpawnClient;
|
||||
typedef struct TagAppSpawnConnection AppSpawnConnection;
|
||||
|
||||
typedef struct TagAppSpawnMsgNode {
|
||||
AppSpawnConnection *connection;
|
||||
AppSpawnMsg msgHeader;
|
||||
uint32_t tlvCount;
|
||||
uint32_t *tlvOffset; // 记录属性的在msg中的偏移,不完全拷贝试消息完整
|
||||
uint8_t *buffer;
|
||||
} AppSpawnMsgNode;
|
||||
|
||||
typedef struct {
|
||||
int32_t fd[2]; // 2 fd count
|
||||
WatcherHandle watcherHandle;
|
||||
TimerHandle timer;
|
||||
int shmId;
|
||||
uint32_t memSize;
|
||||
char *coldRunPath;
|
||||
} AppSpawnForkCtx;
|
||||
|
||||
typedef struct TagAppSpawningCtx {
|
||||
AppSpawnClient client;
|
||||
struct ListNode node;
|
||||
AppSpawnForkCtx forkCtx;
|
||||
AppSpawnMsgNode *message;
|
||||
pid_t pid;
|
||||
int state;
|
||||
struct timespec spawnStart;
|
||||
} AppSpawningCtx;
|
||||
|
||||
typedef struct TagAppSpawnedProcess {
|
||||
struct ListNode node;
|
||||
uid_t uid;
|
||||
pid_t pid;
|
||||
uint32_t max;
|
||||
int exitStatus;
|
||||
struct timespec spawnStart;
|
||||
struct timespec spawnEnd;
|
||||
char name[0];
|
||||
} AppSpawnedProcess;
|
||||
|
||||
typedef struct TagAppSpawnMgr {
|
||||
AppSpawnContent content;
|
||||
TaskHandle server;
|
||||
SignalHandle sigHandler;
|
||||
pid_t servicePid;
|
||||
struct ListNode appQueue; // save app pid and name
|
||||
uint32_t diedAppCount;
|
||||
struct ListNode diedQueue; // save app pid and name
|
||||
struct ListNode appSpawnQueue; // save app pid and name
|
||||
struct timespec perLoadStart;
|
||||
struct timespec perLoadEnd;
|
||||
struct ListNode extData;
|
||||
} AppSpawnMgr;
|
||||
|
||||
/**
|
||||
* @brief App Spawn Mgr object op
|
||||
*
|
||||
*/
|
||||
AppSpawnMgr *CreateAppSpawnMgr(int mode);
|
||||
AppSpawnMgr *GetAppSpawnMgr(void);
|
||||
void DeleteAppSpawnMgr(AppSpawnMgr *mgr);
|
||||
AppSpawnContent *GetAppSpawnContent(void);
|
||||
|
||||
/**
|
||||
* @brief 孵化成功后进程或者app实例的操作
|
||||
*
|
||||
*/
|
||||
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 *GetSpawnedProcess(pid_t pid);
|
||||
AppSpawnedProcess *GetSpawnedProcessByName(const char *name);
|
||||
void TerminateSpawnedProcess(AppSpawnedProcess *node);
|
||||
|
||||
/**
|
||||
* @brief 孵化过程中的ctx对象的操作
|
||||
*
|
||||
*/
|
||||
typedef void (*ProcessTraversal)(const AppSpawnMgr *mgr, AppSpawningCtx *ctx, void *data);
|
||||
void AppSpawningCtxTraversal(ProcessTraversal traversal, void *data);
|
||||
AppSpawningCtx *GetAppSpawningCtxByPid(pid_t pid);
|
||||
AppSpawningCtx *CreateAppSpawningCtx();
|
||||
void DeleteAppSpawningCtx(AppSpawningCtx *property);
|
||||
int KillAndWaitStatus(pid_t pid, int sig);
|
||||
|
||||
/**
|
||||
* @brief 消息解析、处理
|
||||
*
|
||||
*/
|
||||
void ProcessAppSpawnDumpMsg(const AppSpawnMsgNode *message);
|
||||
int ProcessTerminationStatusMsg(const AppSpawnMsgNode *message, AppSpawnResult *result);
|
||||
|
||||
void DeleteAppSpawnMsg(AppSpawnMsgNode *msgNode);
|
||||
int CheckAppSpawnMsg(const AppSpawnMsgNode *message);
|
||||
int DecodeAppSpawnMsg(AppSpawnMsgNode *message);
|
||||
int GetAppSpawnMsgFromBuffer(const uint8_t *buffer, uint32_t bufferLen,
|
||||
AppSpawnMsgNode **outMsg, uint32_t *msgRecvLen, uint32_t *reminder);
|
||||
int SendAppSpawnMsgToChild(AppSpawningCtx *forkCtx, AppSpawnMsgNode *message);
|
||||
|
||||
/**
|
||||
* @brief 消息内容操作接口
|
||||
*
|
||||
*/
|
||||
void DumpAppSpawnMsg(const AppSpawnMsgNode *message);
|
||||
void *GetAppSpawnMsgInfo(const AppSpawnMsgNode *message, int type);
|
||||
void *GetAppSpawnMsgExtInfo(const AppSpawnMsgNode *message, const char *name, uint32_t *len);
|
||||
int CheckAppSpawnMsgFlag(const AppSpawnMsgNode *message, uint32_t type, uint32_t index);
|
||||
int SetAppSpawnMsgFlag(const AppSpawnMsgNode *message, uint32_t type, uint32_t index);
|
||||
|
||||
APPSPAWN_INLINE int IsSpawnServer(const AppSpawnMgr *content)
|
||||
{
|
||||
return (content != NULL) && (content->servicePid == getpid());
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE int IsNWebSpawnMode(const AppSpawnMgr *content)
|
||||
{
|
||||
return (content != NULL) &&
|
||||
(content->content.mode == MODE_FOR_NWEB_SPAWN || content->content.mode == MODE_FOR_NWEB_COLD_RUN);
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE int IsColdRunMode(const AppSpawnMgr *content)
|
||||
{
|
||||
return (content != NULL) &&
|
||||
(content->content.mode == MODE_FOR_APP_COLD_RUN || content->content.mode == MODE_FOR_NWEB_COLD_RUN);
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE int IsDeveloperModeOn(const AppSpawningCtx *property)
|
||||
{
|
||||
return (property != NULL && ((property->client.flags & APP_DEVELOPER_MODE) == APP_DEVELOPER_MODE));
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE int GetAppSpawnMsgType(const AppSpawningCtx *appProperty)
|
||||
{
|
||||
return (appProperty != NULL && appProperty->message != NULL) ?
|
||||
appProperty->message->msgHeader.msgType : MAX_TYPE_INVALID;
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE const char *GetProcessName(const AppSpawningCtx *property)
|
||||
{
|
||||
if (property == NULL || property->message == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return property->message->msgHeader.processName;
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE const char *GetBundleName(const AppSpawningCtx *property)
|
||||
{
|
||||
AppSpawnMsgBundleInfo *info = (AppSpawnMsgBundleInfo *)GetAppSpawnMsgInfo(property->message, TLV_BUNDLE_INFO);
|
||||
if (info != NULL) {
|
||||
return info->bundleName;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE void *GetAppProperty(const AppSpawningCtx *property, uint32_t type)
|
||||
{
|
||||
APPSPAWN_CHECK(property != NULL && property->message != NULL,
|
||||
return NULL, "Invalid property for type %{public}u", type);
|
||||
return GetAppSpawnMsgInfo(property->message, type);
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE void *GetAppPropertyExt(const AppSpawningCtx *property, const char *name, uint32_t *len)
|
||||
{
|
||||
APPSPAWN_CHECK(name != NULL, return NULL, "Invalid name ");
|
||||
APPSPAWN_CHECK(property != NULL && property->message != NULL,
|
||||
return NULL, "Invalid property for name %{public}s", name);
|
||||
return GetAppSpawnMsgExtInfo(property->message, name, len);
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE int CheckAppMsgFlagsSet(const AppSpawningCtx *property, uint32_t index)
|
||||
{
|
||||
APPSPAWN_CHECK(property != NULL && property->message != NULL,
|
||||
return 0, "Invalid property for name %{public}u", TLV_MSG_FLAGS);
|
||||
return CheckAppSpawnMsgFlag(property->message, TLV_MSG_FLAGS, index);
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE int CheckAppPermissionFlagSet(const AppSpawningCtx *property, uint32_t index)
|
||||
{
|
||||
APPSPAWN_CHECK(property != NULL && property->message != NULL,
|
||||
return 0, "Invalid property for name %{public}u", TLV_PERMISSION);
|
||||
return CheckAppSpawnMsgFlag(property->message, TLV_PERMISSION, index);
|
||||
}
|
||||
|
||||
APPSPAWN_INLINE int SetAppPermissionFlags(const AppSpawningCtx *property, uint32_t index)
|
||||
{
|
||||
APPSPAWN_CHECK(property != NULL && property->message != NULL,
|
||||
return -1, "Invalid property for name %{public}u", TLV_PERMISSION);
|
||||
return SetAppSpawnMsgFlag(property->message, TLV_PERMISSION, index);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // APPSPAWN_MANAGER_H
|
@ -34,3 +34,10 @@ group("unittest") {
|
||||
deps = [ "unittest/app_spawn_lite_test:unittest" ]
|
||||
}
|
||||
}
|
||||
|
||||
group("fuzztest") {
|
||||
if (!defined(ohos_lite)) {
|
||||
testonly = true
|
||||
deps = [ "fuzztest:app_spawn_fuzztest" ]
|
||||
}
|
||||
}
|
||||
|
43
test/fuzztest/BUILD.gn
Normal file
43
test/fuzztest/BUILD.gn
Normal file
@ -0,0 +1,43 @@
|
||||
# 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.
|
||||
|
||||
#####################appspawn-fuzz###################
|
||||
import("//base/startup/appspawn/appspawn.gni")
|
||||
import("//build/config/features.gni")
|
||||
import("//build/ohos.gni")
|
||||
import("//build/test.gni")
|
||||
##############################fuzztest##########################################
|
||||
ohos_fuzztest("AppSpawnClientFuzzTest") {
|
||||
module_out_path = module_output_path
|
||||
fuzz_config_file = "${appspawn_path}/test/fuzztest/appspawnclient_fuzzer"
|
||||
|
||||
include_dirs = [ "${appspawn_path}/interfaces/innerkits_new/include" ]
|
||||
|
||||
deps = [ "${appspawn_path}/interfaces/innerkits_new/client:appspawn_client" ]
|
||||
external_deps = [ "bounds_checking_function:libsec_static" ]
|
||||
|
||||
cflags = [
|
||||
"-g",
|
||||
"-O0",
|
||||
"-Wno-unused-variable",
|
||||
"-fno-omit-frame-pointer",
|
||||
]
|
||||
sources = [ "appspawnclient_fuzzer/appspawnclient_fuzzer.cpp" ]
|
||||
}
|
||||
|
||||
group("app_spawn_fuzztest") {
|
||||
testonly = true
|
||||
deps = []
|
||||
deps += [ ":AppSpawnClientFuzzTest" ]
|
||||
}
|
||||
###############################################################################
|
317
test/fuzztest/appspawnclient_fuzzer/appspawnclient_fuzzer.cpp
Normal file
317
test/fuzztest/appspawnclient_fuzzer/appspawnclient_fuzzer.cpp
Normal file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* 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 "appspawnclient_fuzzer.h"
|
||||
#include <string>
|
||||
#include "appspawn.h"
|
||||
|
||||
namespace OHOS {
|
||||
int FuzzAppSpawnClientInit(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
return AppSpawnClientInit(name, &handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnClientDestroy(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgCreate(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgAddStringInfo(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
(void)AppSpawnReqMsgAddStringInfo(reqHandle, processName.c_str(), processName.c_str());
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnTerminateMsgCreate(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
pid_t pid = static_cast<pid_t>(size);
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
(void)AppSpawnTerminateMsgCreate(pid, &reqHandle);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnClientSendMsg(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnResult appResult = {static_cast<int>(size), 0};
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
(void)AppSpawnClientSendMsg(handle, reqHandle, &appResult);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgFree(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgSetBundleInfo(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
uint32_t bundleIndex = static_cast<uint32_t>(size);
|
||||
std::string bundleName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgSetBundleInfo(reqHandle, bundleIndex, bundleName.c_str());
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgSetAppFlag(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
AppFlagsIndex flagIndex = static_cast<AppFlagsIndex>(size);
|
||||
(void)AppSpawnReqMsgSetAppFlag(reqHandle, flagIndex);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgSetAppDacInfo(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
AppDacInfo dacInfo = {};
|
||||
(void)AppSpawnReqMsgSetAppDacInfo(reqHandle, &dacInfo);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgSetAppDomainInfo(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
std::string apl(reinterpret_cast<const char*>(data), size);
|
||||
uint32_t hapFlags = static_cast<uint32_t>(size);
|
||||
(void)AppSpawnReqMsgSetAppDomainInfo(reqHandle, hapFlags, apl.c_str());
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgSetAppInternetPermissionInfo(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
uint8_t allow = static_cast<uint8_t>(size);
|
||||
uint8_t setAllow = static_cast<uint8_t>(size);
|
||||
(void)AppSpawnReqMsgSetAppInternetPermissionInfo(reqHandle, allow, setAllow);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgSetAppAccessToken(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
uint64_t accessTokenIdEx = static_cast<uint64_t>(size);
|
||||
(void)AppSpawnReqMsgSetAppAccessToken(reqHandle, accessTokenIdEx);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgSetAppOwnerId(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
std::string ownerId(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgSetAppOwnerId(reqHandle, ownerId.c_str());
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgAddPermission(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
std::string permission(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgAddPermission(reqHandle, permission.c_str());
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzAppSpawnReqMsgAddExtInfo(const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *name = APPSPAWN_SERVER_NAME;
|
||||
AppSpawnClientHandle handle = nullptr;
|
||||
if (AppSpawnClientInit(name, &handle) != 0) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnReqMsgHandle reqHandle = nullptr;
|
||||
AppSpawnMsgType msgType = static_cast<AppSpawnMsgType>(size);
|
||||
std::string processName(reinterpret_cast<const char*>(data), size);
|
||||
(void)AppSpawnReqMsgCreate(msgType, processName.c_str(), &reqHandle);
|
||||
(void)AppSpawnReqMsgAddExtInfo(reqHandle, processName.c_str(), data, static_cast<uint32_t>(size));
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return AppSpawnClientDestroy(handle);
|
||||
}
|
||||
|
||||
int FuzzGetPermissionIndex(const uint8_t *data, size_t size)
|
||||
{
|
||||
std::string permission(reinterpret_cast<const char*>(data), size);
|
||||
return GetPermissionIndex(permission.c_str());
|
||||
}
|
||||
|
||||
int FuzzGetMaxPermissionIndex(const uint8_t *data, size_t size)
|
||||
{
|
||||
return GetMaxPermissionIndex();
|
||||
}
|
||||
|
||||
int FuzzGetPermissionByIndex(const uint8_t *data, size_t size)
|
||||
{
|
||||
int32_t index = static_cast<int32_t>(size);
|
||||
if (GetPermissionByIndex(index) == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fuzzer entry point */
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
/* Run your code on data */
|
||||
OHOS::FuzzAppSpawnClientInit(data, size);
|
||||
OHOS::FuzzAppSpawnClientDestroy(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgCreate(data, size);
|
||||
OHOS::FuzzAppSpawnTerminateMsgCreate(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgFree(data, size);
|
||||
OHOS::FuzzAppSpawnClientSendMsg(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgSetBundleInfo(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgSetAppFlag(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgSetAppDacInfo(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgSetAppDomainInfo(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgSetAppInternetPermissionInfo(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgSetAppAccessToken(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgSetAppOwnerId(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgAddPermission(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgAddExtInfo(data, size);
|
||||
OHOS::FuzzAppSpawnReqMsgAddStringInfo(data, size);
|
||||
OHOS::FuzzGetPermissionIndex(data, size);
|
||||
OHOS::FuzzGetMaxPermissionIndex(data, size);
|
||||
OHOS::FuzzGetPermissionByIndex(data, size);
|
||||
return 0;
|
||||
}
|
19
test/fuzztest/appspawnclient_fuzzer/appspawnclient_fuzzer.h
Normal file
19
test/fuzztest/appspawnclient_fuzzer/appspawnclient_fuzzer.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 APPSPAWNCLIENT_FUZZER
|
||||
#define APPSPAWNCLIENT_FUZZER
|
||||
#define FUZZ_PROJECT_NAME "appspawnclient_fuzzer"
|
||||
#endif // APPSPAWNCLIENT_FUZZER
|
14
test/fuzztest/appspawnclient_fuzzer/corpus/init
Normal file
14
test/fuzztest/appspawnclient_fuzzer/corpus/init
Normal file
@ -0,0 +1,14 @@
|
||||
# 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.
|
||||
|
||||
FUZZ
|
25
test/fuzztest/appspawnclient_fuzzer/project.xml
Normal file
25
test/fuzztest/appspawnclient_fuzzer/project.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<fuzz_config>
|
||||
<fuzztest>
|
||||
<!-- maximum length of a test input -->
|
||||
<max_len>100</max_len>
|
||||
<!-- maximum total time in seconds to run the fuzzer -->
|
||||
<max_total_time>30</max_total_time>
|
||||
<!-- memory usage limit in Mb -->
|
||||
<rss_limit_mb>2048</rss_limit_mb>
|
||||
</fuzztest>
|
||||
</fuzz_config>
|
159
test/mock/app_spawn_stub.cpp
Normal file
159
test/mock/app_spawn_stub.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "app_spawn_stub.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <csignal>
|
||||
#include <cstdarg>
|
||||
#include <cstdbool>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "access_token.h"
|
||||
#include "hilog/log.h"
|
||||
#include "securec.h"
|
||||
#include "token_setproc.h"
|
||||
#include "tokenid_kit.h"
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
#include "hap_restorecon.h"
|
||||
#endif
|
||||
#ifdef WITH_SECCOMP
|
||||
#include "seccomp_policy.h"
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
namespace OHOS {
|
||||
namespace system {
|
||||
bool GetIntParameter(const std::string &key, bool def, bool arg1 = false, bool arg2 = false)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
|
||||
bool GetBoolParameter(const std::string &key, bool def)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
} // namespace system
|
||||
|
||||
namespace Security {
|
||||
namespace AccessToken {
|
||||
uint64_t TokenIdKit::GetRenderTokenID(uint64_t tokenId)
|
||||
{
|
||||
return tokenId;
|
||||
}
|
||||
} // namespace AccessToken
|
||||
} // namespace Security
|
||||
} // namespace OHOS
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
HapContext::HapContext() {}
|
||||
HapContext::~HapContext() {}
|
||||
int HapContext::HapDomainSetcontext(HapDomainInfo &hapDomainInfo)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void ResetParamSecurityLabel() {}
|
||||
|
||||
int SetSelfTokenID(uint64_t tokenId)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetTraceDisabled(int disable) {}
|
||||
|
||||
#ifdef WITH_SECCOMP
|
||||
bool SetSeccompPolicyWithName(SeccompFilterType filter, const char *filterName)
|
||||
{
|
||||
static int result = 0;
|
||||
result++;
|
||||
return true; // (result % 3) == 0; // 3 is test data
|
||||
}
|
||||
|
||||
bool IsEnableSeccomp(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
int setcon(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetControlSocket(const char *name)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool g_developerMode = true;
|
||||
void SetDeveloperMode(bool mode)
|
||||
{
|
||||
g_developerMode = mode;
|
||||
}
|
||||
|
||||
int GetParameter(const char *key, const char *def, char *value, uint32_t len)
|
||||
{
|
||||
if (strcmp(key, "startup.appspawn.cold.boot") == 0) {
|
||||
return strcpy_s(value, len, "true") == 0 ? strlen("true") : -1;
|
||||
}
|
||||
if (strcmp(key, "persist.appspawn.reqMgr.timeout") == 0) {
|
||||
return strcpy_s(value, len, "2") == 0 ? 1 : -1;
|
||||
}
|
||||
if (strcmp(key, "const.security.developermode.state") == 0) {
|
||||
return g_developerMode ? (strcpy_s(value, len, "true") == 0 ? strlen("true") : -1) : -1;
|
||||
}
|
||||
if (strcmp(key, "persist.nweb.sandbox.src_path") == 0) {
|
||||
return strcpy_s(value, len, def) == 0 ? strlen(def) : -1;
|
||||
}
|
||||
if (strcmp(key, "test.variable.001") == 0) {
|
||||
return strcpy_s(value, len, "test.variable.001") == 0 ? strlen("test.variable.001") : -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SetParameter(const char *key, const char *value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int InUpdaterMode(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
82
test/mock/app_spawn_stub.h
Normal file
82
test/mock/app_spawn_stub.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 APPSPAWN_TEST_STUB_H
|
||||
#define APPSPAWN_TEST_STUB_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct AppSpawnContent AppSpawnContent;
|
||||
typedef struct AppSpawnClient AppSpawnClient;
|
||||
typedef struct TagAppSpawnReqMsgNode AppSpawnReqMsgNode;
|
||||
typedef void *AppSpawnClientHandle;
|
||||
typedef struct TagAppSpawnReqMsgMgr AppSpawnReqMsgMgr;
|
||||
typedef struct TagAppSpawningCtx AppSpawningCtx;
|
||||
typedef struct TagAppSpawnMsg AppSpawnMsg;
|
||||
typedef struct TagAppSpawnSandboxCfg AppSpawnSandboxCfg;
|
||||
typedef struct TagAppSpawnExtData AppSpawnExtData;
|
||||
typedef struct TagSandboxContext SandboxContext;
|
||||
typedef struct TagAppSpawnedProcess AppSpawnedProcess;
|
||||
typedef struct TagAppSpawnForkArg AppSpawnForkArg;
|
||||
typedef struct TagAppSpawnMsgNode AppSpawnMsgNode;
|
||||
|
||||
void SetHapDomainSetcontextResult(int result);
|
||||
|
||||
void ProcessSignal(const struct signalfd_siginfo *siginfo);
|
||||
|
||||
int CreateClientSocket(uint32_t type, int block);
|
||||
void CloseClientSocket(int socketId);
|
||||
|
||||
int ParseAppSandboxConfig(const cJSON *appSandboxConfig, AppSpawnSandboxCfg *sandbox);
|
||||
AppSpawnSandboxCfg *CreateAppSpawnSandbox(void);
|
||||
void AddDefaultVariable(void);
|
||||
|
||||
int AppSpawnChild(AppSpawnContent *content, AppSpawnClient *client);
|
||||
|
||||
int WriteToFile(const char *path, int truncated, pid_t pids[], uint32_t count);
|
||||
int GetCgroupPath(const AppSpawnedProcess *appInfo, char *buffer, uint32_t buffLen);
|
||||
|
||||
void SetDeveloperMode(bool mode);
|
||||
|
||||
#define STUB_NEED_CHECK 0x01
|
||||
typedef int (*ExecvFunc)(const char *pathname, char *const argv[]);
|
||||
enum {
|
||||
STUB_MOUNT,
|
||||
STUB_EXECV,
|
||||
STUB_MAX,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
int result;
|
||||
void *arg;
|
||||
} StubNode;
|
||||
StubNode *GetStubNode(int type);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // APPSPAWN_TEST_STUB_H
|
291
test/mock/app_system_stub.c
Normal file
291
test/mock/app_system_stub.c
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* 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 "app_spawn_stub.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/capability.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "appspawn_sandbox.h"
|
||||
#include "hilog/log.h"
|
||||
#include "securec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
StubNode g_stubNodes[] = {
|
||||
{STUB_MOUNT, 0, 0, NULL},
|
||||
{STUB_EXECV, 0, 0, NULL},
|
||||
};
|
||||
|
||||
StubNode *GetStubNode(int type)
|
||||
{
|
||||
if (type >= (int)(sizeof(g_stubNodes) / sizeof(g_stubNodes[0]))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &g_stubNodes[type];
|
||||
}
|
||||
|
||||
void *DlopenStub(const char *pathname, int mode)
|
||||
{
|
||||
UNUSED(pathname);
|
||||
UNUSED(mode);
|
||||
static size_t index = 0;
|
||||
return &index;
|
||||
}
|
||||
|
||||
static bool InitEnvironmentParamStub(const char *name)
|
||||
{
|
||||
UNUSED(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SetRendererSecCompPolicyStub(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void NWebRenderMainStub(const char *cmd)
|
||||
{
|
||||
printf("NWebRenderMainStub cmd %s \n", cmd);
|
||||
}
|
||||
|
||||
uint32_t g_dlsymResultFlags = 0;
|
||||
#define DLSYM_FAIL_SET_SEC_POLICY 0x01
|
||||
#define DLSYM_FAIL_NWEB_MAIN 0x02
|
||||
#define DLSYM_FAIL_INIT_ENV 0x04
|
||||
void SetDlsymResult(uint32_t flags, bool success)
|
||||
{
|
||||
if (success) {
|
||||
g_dlsymResultFlags &= ~flags;
|
||||
} else {
|
||||
g_dlsymResultFlags |= flags;
|
||||
}
|
||||
}
|
||||
|
||||
void *DlsymStub(void *handle, const char *symbol)
|
||||
{
|
||||
printf("DlsymStub %s \n", symbol);
|
||||
UNUSED(handle);
|
||||
if (strcmp(symbol, "InitEnvironmentParam") == 0) {
|
||||
return ((g_dlsymResultFlags & DLSYM_FAIL_INIT_ENV) == 0) ? (void *)(InitEnvironmentParamStub) : NULL;
|
||||
}
|
||||
if (strcmp(symbol, "SetRendererSeccompPolicy") == 0) {
|
||||
return ((g_dlsymResultFlags & DLSYM_FAIL_SET_SEC_POLICY) == 0) ? (void *)(SetRendererSecCompPolicyStub) : NULL;
|
||||
}
|
||||
if (strcmp(symbol, "NWebRenderMain") == 0) {
|
||||
return ((g_dlsymResultFlags & DLSYM_FAIL_NWEB_MAIN) == 0) ? (void *)(NWebRenderMainStub) : NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int DlcloseStub(void *handle)
|
||||
{
|
||||
UNUSED(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DisallowInternet(void)
|
||||
{
|
||||
}
|
||||
|
||||
bool may_init_gwp_asan(bool forceInit)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int SetgroupsStub(size_t size, const gid_t *list)
|
||||
{
|
||||
UNUSED(size);
|
||||
UNUSED(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetresuidStub(uid_t ruid, uid_t euid, uid_t suid)
|
||||
{
|
||||
UNUSED(ruid);
|
||||
UNUSED(euid);
|
||||
UNUSED(suid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetresgidStub(gid_t rgid, gid_t egid, gid_t sgid)
|
||||
{
|
||||
UNUSED(rgid);
|
||||
UNUSED(egid);
|
||||
UNUSED(sgid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CapsetStub(cap_user_header_t hdrp, const cap_user_data_t datap)
|
||||
{
|
||||
UNUSED(hdrp);
|
||||
UNUSED(datap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UnshareStub(int flags)
|
||||
{
|
||||
printf("UnshareStub %x \n", flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MountStub(const char *originPath, const char *destinationPath,
|
||||
const char *fsType, unsigned long mountFlags, const char *options, mode_t mountSharedFlag)
|
||||
{
|
||||
StubNode *node = GetStubNode(STUB_MOUNT);
|
||||
if (node == NULL || node->arg == NULL || (node->flags & STUB_NEED_CHECK) != STUB_NEED_CHECK) {
|
||||
return 0;
|
||||
}
|
||||
MountArg *args = (MountArg *)node->arg;
|
||||
|
||||
printf("args->originPath %s == %s \n", args->originPath, originPath);
|
||||
printf("args->destinationPath %s == %s \n", args->destinationPath, destinationPath);
|
||||
printf("args->fsType %s == %s \n", args->fsType, fsType);
|
||||
printf("args->options %s == %s \n", args->options, options);
|
||||
printf("mountFlags %lx args->mountFlags %lx \n", mountFlags, args->mountFlags);
|
||||
printf("mountSharedFlag 0x%x args->mountSharedFlag 0x%x \n", mountSharedFlag, args->mountSharedFlag);
|
||||
|
||||
if (originPath != NULL && (strcmp(originPath, args->originPath) == 0)) {
|
||||
int result = (destinationPath != NULL && (strcmp(destinationPath, args->destinationPath) == 0) &&
|
||||
(mountFlags == args->mountFlags) &&
|
||||
(args->fsType == NULL || (fsType != NULL && strcmp(fsType, args->fsType) == 0)) &&
|
||||
(args->options == NULL || (options != NULL && strcmp(options, args->options) == 0)));
|
||||
errno = result ? 0 : -EINVAL;
|
||||
node->result = result ? 0 : -EINVAL;
|
||||
printf("MountStub result %d node->result %d \n", result, node->result);
|
||||
return errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SymlinkStub(const char *target, const char *linkName)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ChdirStub(const char *path)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ChrootStub(const char *path)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
long int SyscallStub(long int type, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Umount2Stub(const char *path, int type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UmountStub(const char *path)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mallopt(int param, int value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AccessStub(const char *pathName, int mode)
|
||||
{
|
||||
printf(" AccessStub pathName %s \n", pathName);
|
||||
if (strstr(pathName, "/data/app/el2/50/base") != NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (strstr(pathName, "/mnt/sandbox/50/com.example.myapplication/data/storage/el2") != NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (strstr(pathName, "/data/app/el5/100/base/com.example.myapplication") != NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ExecvStub(const char *pathName, char *const argv[])
|
||||
{
|
||||
printf("ExecvStub %s \n", pathName);
|
||||
StubNode *node = GetStubNode(STUB_EXECV);
|
||||
if (node == NULL || node->arg == NULL || (node->flags & STUB_NEED_CHECK) != STUB_NEED_CHECK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExecvFunc func = (ExecvFunc)node->arg;
|
||||
func(pathName, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ExecvpStub(const char *pathName, char *const argv[])
|
||||
{
|
||||
printf("ExecvpStub %s \n", pathName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetprocpidStub()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CloneStub(int (*fn)(void *), void *stack, int flags, void *arg, ...)
|
||||
{
|
||||
printf("CloneStub 11 %d \n", getpid());
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
fn(arg);
|
||||
_exit(0x7f); // 0x7f user exit
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
int SetuidStub(uid_t uid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetgidStub(gid_t gid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
93
test/mock/js_runtime.h
Normal file
93
test/mock/js_runtime.h
Normal 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.
|
||||
*/
|
||||
|
||||
#ifndef STUB_JS_RUNTIME_H
|
||||
#define STUB_JS_RUNTIME_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace OHOS {
|
||||
namespace AbilityRuntime {
|
||||
class Runtime {
|
||||
public:
|
||||
enum class Language {
|
||||
JS = 0,
|
||||
};
|
||||
|
||||
struct Options {
|
||||
Language lang = Language::JS;
|
||||
std::string bundleName;
|
||||
std::string moduleName;
|
||||
bool loadAce = true;
|
||||
bool preload = false;
|
||||
bool isBundle = true;
|
||||
bool isDebugVersion = false;
|
||||
bool isJsFramework = false;
|
||||
bool isStageModel = true;
|
||||
bool isTestFramework = false;
|
||||
int32_t uid = -1;
|
||||
// ArkTsCard start
|
||||
bool isUnique = false;
|
||||
};
|
||||
|
||||
static std::unique_ptr<Runtime> Create(const Options &options)
|
||||
{
|
||||
return std::make_unique<Runtime>();
|
||||
}
|
||||
static void SavePreloaded(std::unique_ptr<Runtime> &&instance) {}
|
||||
|
||||
Runtime() {};
|
||||
~Runtime() {};
|
||||
|
||||
void PreloadSystemModule(const std::string &moduleName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Runtime(const Runtime &) = delete;
|
||||
Runtime(Runtime &&) = delete;
|
||||
Runtime &operator=(const Runtime &) = delete;
|
||||
Runtime &operator=(Runtime &&) = delete;
|
||||
};
|
||||
} // namespace AbilityRuntime
|
||||
namespace Ace {
|
||||
class AceForwardCompatibility {
|
||||
public:
|
||||
AceForwardCompatibility() {}
|
||||
~AceForwardCompatibility() {}
|
||||
|
||||
static const char *GetAceLibName()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
};
|
||||
} // namespace Ace
|
||||
|
||||
namespace AppExecFwk {
|
||||
class MainThread {
|
||||
public:
|
||||
MainThread() {}
|
||||
~MainThread() {}
|
||||
|
||||
static void PreloadExtensionPlugin() {}
|
||||
static void Start() {}
|
||||
};
|
||||
} // namespace AppExecFwk
|
||||
|
||||
} // namespace OHOS
|
||||
#endif // STUB_JS_RUNTIME_H
|
72
test/mock/resource_manager.h
Normal file
72
test/mock/resource_manager.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 OHOS_RESOURCE_MANAGER_RESOURCEMANAGER_H
|
||||
#define OHOS_RESOURCE_MANAGER_RESOURCEMANAGER_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace OHOS {
|
||||
namespace Global {
|
||||
namespace Resource {
|
||||
enum FunctionType {
|
||||
SYNC = 0,
|
||||
ASYNC = 1
|
||||
};
|
||||
class ResourceManager {
|
||||
public:
|
||||
typedef struct {
|
||||
/** the raw file fd */
|
||||
int fd;
|
||||
|
||||
/** the offset from where the raw file starts in the HAP */
|
||||
int64_t offset;
|
||||
|
||||
/** the length of the raw file in the HAP. */
|
||||
int64_t length;
|
||||
} RawFileDescriptor;
|
||||
|
||||
struct Resource {
|
||||
/** the hap bundle name */
|
||||
std::string bundleName;
|
||||
|
||||
/** the hap module name */
|
||||
std::string moduleName;
|
||||
|
||||
/** the resource id in hap */
|
||||
int32_t id;
|
||||
};
|
||||
|
||||
enum class NapiValueType {
|
||||
NAPI_NUMBER = 0,
|
||||
NAPI_STRING = 1
|
||||
};
|
||||
|
||||
ResourceManager() {}
|
||||
~ResourceManager() {};
|
||||
};
|
||||
|
||||
ResourceManager g_resourceManager;
|
||||
ResourceManager *GetSystemResourceManagerNoSandBox()
|
||||
{
|
||||
return &g_resourceManager;
|
||||
}
|
||||
} // namespace Resource
|
||||
} // namespace Global
|
||||
} // namespace OHOS
|
||||
|
||||
#endif
|
@ -18,6 +18,7 @@
|
||||
#include "securec.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace testing;
|
||||
using namespace testing::ext;
|
||||
|
||||
@ -41,16 +42,16 @@ static AppSpawnReqMsgHandle CreateMsg(AppSpawnClientHandle handle, const char *b
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create req %{public}s", bundleName);
|
||||
|
||||
AppDacInfo dacInfo = {};
|
||||
dacInfo.uid = 20010029; // 20010029 test data
|
||||
dacInfo.gid = 20010029; // 20010029 test data
|
||||
dacInfo.gidCount = 2; // 2 count
|
||||
dacInfo.gidTable[0] = 20010029; // 20010029 test data
|
||||
dacInfo.gidTable[1] = 20010029 + 1; // 20010029 test data
|
||||
dacInfo.uid = 20010029; // 20010029 test data
|
||||
dacInfo.gid = 20010029; // 20010029 test data
|
||||
dacInfo.gidCount = 2; // 2 count
|
||||
dacInfo.gidTable[0] = 20010029; // 20010029 test data
|
||||
dacInfo.gidTable[1] = 20010029 + 1; // 20010029 test data
|
||||
(void)strcpy_s(dacInfo.userName, sizeof(dacInfo.userName), "test-app-name");
|
||||
ret = AppSpawnReqMsgSetAppDacInfo(reqHandle, &dacInfo);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add dac %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, static_cast<AppFlagsIndex>(10)); // 10 test
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, static_cast<AppFlagsIndex>(10)); // 10 test
|
||||
|
||||
ret = AppSpawnReqMsgSetAppAccessToken(reqHandle, 12345678); // 12345678
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add access token %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
0
test/moduletest/appspawn_module_test.cpp
Executable file → Normal file
0
test/moduletest/appspawn_module_test.cpp
Executable file → Normal file
0
test/moduletest/appspawn_test_cmder.cpp
Executable file → Normal file
0
test/moduletest/appspawn_test_cmder.cpp
Executable file → Normal file
0
test/moduletest/appspawn_test_cmder.h
Executable file → Normal file
0
test/moduletest/appspawn_test_cmder.h
Executable file → Normal file
0
test/moduletest/appspawn_test_main.cpp
Executable file → Normal file
0
test/moduletest/appspawn_test_main.cpp
Executable file → Normal file
30
test/moduletest/plugin-sample/BUILD.gn
Normal file
30
test/moduletest/plugin-sample/BUILD.gn
Normal file
@ -0,0 +1,30 @@
|
||||
# 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")
|
||||
|
||||
ohos_shared_library("appspawn_plugin_sample") {
|
||||
sources = [ "appspawn_plugin_sample.c" ]
|
||||
include_dirs = [
|
||||
".",
|
||||
"${appspawn_path}/common",
|
||||
"${appspawn_path}/standard",
|
||||
]
|
||||
external_deps = [
|
||||
"hilog:libhilog",
|
||||
"init:libbegetutil",
|
||||
]
|
||||
deps = [ "${appspawn_path}/modules/module_engine:libappspawn_module_engine" ]
|
||||
subsystem_name = "${subsystem_name}"
|
||||
part_name = "${part_name}"
|
||||
}
|
101
test/moduletest/plugin-sample/appspawn_plugin_sample.c
Normal file
101
test/moduletest/plugin-sample/appspawn_plugin_sample.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 "appspawn_hook.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_utils.h"
|
||||
|
||||
static int TestPluginReportProcessExit(const AppSpawnMgr *content, const AppSpawnedProcess *appInfo)
|
||||
{
|
||||
APPSPAWN_LOGV("Process %{public}s exit", appInfo->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestPluginReportProcessAdd(const AppSpawnMgr *content, const AppSpawnedProcess *appInfo)
|
||||
{
|
||||
APPSPAWN_LOGV("Process %{public}s add", appInfo->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestPluginPreload(AppSpawnMgr *content)
|
||||
{
|
||||
APPSPAWN_LOGV("TestPlugin preload");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestPluginPreFork(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("TestPlugin pre fork for %{public}s ", GetProcessName(property));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestPluginPreReply(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("TestPlugin pre reply to client for %{public}s ", GetProcessName(property));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestPluginPostReply(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("TestPlugin post reply to client for %{public}s ", GetProcessName(property));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ChildPreColdBoot(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("TestPlugin pre cold boot for %{public}s ", GetProcessName(property));
|
||||
return 0;
|
||||
}
|
||||
static int ChildExecute(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("TestPlugin set app property for %{public}s ", GetProcessName(property));
|
||||
return 0;
|
||||
}
|
||||
static int ChildPreRely(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("TestPlugin pre reply to parent for %{public}s ", GetProcessName(property));
|
||||
return 0;
|
||||
}
|
||||
static int ChildPostRely(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("TestPlugin post reply to parent for %{public}s ", GetProcessName(property));
|
||||
return 0;
|
||||
}
|
||||
static int ChildPreRun(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("TestPlugin pre child run for %{public}s ", GetProcessName(property));
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
APPSPAWN_LOGV("Load test plugin module ...");
|
||||
AddProcessMgrHook(STAGE_SERVER_APP_DIED, 0, TestPluginReportProcessExit);
|
||||
AddProcessMgrHook(STAGE_SERVER_APP_ADD, 0, TestPluginReportProcessAdd);
|
||||
AddPreloadHook(HOOK_PRIO_LOWEST - 1, TestPluginPreload);
|
||||
AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_COMMON - 1, TestPluginPreFork);
|
||||
AddAppSpawnHook(STAGE_PARENT_POST_RELY, HOOK_PRIO_COMMON - 1, TestPluginPostReply);
|
||||
AddAppSpawnHook(STAGE_PARENT_PRE_RELY, HOOK_PRIO_COMMON - 1, TestPluginPreReply);
|
||||
AddAppSpawnHook(STAGE_CHILD_PRE_COLDBOOT, HOOK_PRIO_COMMON - 1, ChildPreColdBoot);
|
||||
AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_HIGHEST - 1, ChildExecute);
|
||||
AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_COMMON - 1, ChildExecute);
|
||||
AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_SANDBOX - 1, ChildExecute);
|
||||
AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_SANDBOX + 1, ChildExecute);
|
||||
AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_PROPERTY - 1, ChildExecute);
|
||||
AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_PROPERTY + 1, ChildExecute);
|
||||
AddAppSpawnHook(STAGE_CHILD_PRE_RELY, HOOK_PRIO_COMMON - 1, ChildPreRely);
|
||||
AddAppSpawnHook(STAGE_CHILD_POST_RELY, HOOK_PRIO_COMMON - 1, ChildPostRely);
|
||||
AddAppSpawnHook(STAGE_CHILD_PRE_RUN, HOOK_PRIO_COMMON - 1, ChildPreRun);
|
||||
}
|
40
test/moduletest/test_app_info.json
Normal file
40
test/moduletest/test_app_info.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"msg-type": 0,
|
||||
"msg-flags": [1, 2 ],
|
||||
"process-name" : "com.example.myapplication",
|
||||
"pid": 328018,
|
||||
"dac-info" : {
|
||||
"uid" : 20010043,
|
||||
"gid" : 20010043,
|
||||
"gid-table" : [20010043],
|
||||
"user-name" : ""
|
||||
},
|
||||
"access-token": {
|
||||
"accessTokenIdEx": 537854093
|
||||
},
|
||||
"permission": [
|
||||
"ohos.permission.READ_IMAGEVIDEO",
|
||||
"ohos.permission.FILE_CROSS_APP",
|
||||
"ohos.permission.ACTIVATE_THEME_PACKAGE"
|
||||
],
|
||||
"internet-permission": {
|
||||
"set-allow-internet": 0,
|
||||
"allow-internet": 0
|
||||
},
|
||||
"bundle-info": {
|
||||
"bundle-index": 0,
|
||||
"bundle-name": "com.example.myapplication"
|
||||
},
|
||||
"owner-id": "",
|
||||
"render-cmd": "1234567890",
|
||||
"domain-info": {
|
||||
"hap-flags": 0,
|
||||
"apl": "system_core"
|
||||
},
|
||||
"ext-info": [
|
||||
{
|
||||
"name": "hiplist",
|
||||
"value": "{ \"bundles\": [\"test.bundle1\", \"test.bundle2\"],\"modules\":[\"module1\", \"module2\"],\"versions\":[\"v10001\", \"v10002\"] }"
|
||||
}
|
||||
]
|
||||
}
|
0
test/moduletest/threadpool/BUILD.gn
Executable file → Normal file
0
test/moduletest/threadpool/BUILD.gn
Executable file → Normal file
0
test/moduletest/threadpool/thread_manager.c
Executable file → Normal file
0
test/moduletest/threadpool/thread_manager.c
Executable file → Normal file
0
test/moduletest/threadpool/thread_manager.h
Executable file → Normal file
0
test/moduletest/threadpool/thread_manager.h
Executable file → Normal file
0
test/unittest/app_spawn_client_test/BUILD.gn
Executable file → Normal file
0
test/unittest/app_spawn_client_test/BUILD.gn
Executable file → Normal file
691
test/unittest/app_spawn_client_test/app_spawn_client_test.cpp
Normal file
691
test/unittest/app_spawn_client_test/app_spawn_client_test.cpp
Normal file
@ -0,0 +1,691 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#include "appspawn_client.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_mount_permission.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "json_utils.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
#include "app_spawn_stub.h"
|
||||
#include "app_spawn_test_helper.h"
|
||||
|
||||
using namespace testing;
|
||||
using namespace testing::ext;
|
||||
|
||||
#define TEST_PID 100
|
||||
namespace OHOS {
|
||||
static AppSpawnTestHelper g_testHelper;
|
||||
class AppSpawnClientTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase() {}
|
||||
static void TearDownTestCase() {}
|
||||
void SetUp() {}
|
||||
void TearDown() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 测试服务端报文不完整,关闭连接。客户端超时
|
||||
* 消息测试时,不能在中间执行assert,必须执行stop后执行assert检查,否则会导致消息异常
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Communication_001, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn", false);
|
||||
testServer.Start([](TestConnection *connection, const uint8_t *buffer, uint32_t buffLen) {
|
||||
LE_CloseStreamTask(LE_GetDefaultLoop(), connection->stream);
|
||||
});
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgHandle reqHandle = testServer.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, APPSPAWN_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试收到报文后,消息错误,直接回复
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Communication_002, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn", false);
|
||||
testServer.Start(
|
||||
[](TestConnection *connection, const uint8_t *buffer, uint32_t buffLen) {
|
||||
connection->SendResponse(
|
||||
reinterpret_cast<AppSpawnMsg *>(const_cast<uint8_t *>(buffer)), APPSPAWN_MSG_INVALID, 0);
|
||||
},
|
||||
3000); // 3000 3s
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgHandle reqHandle = testServer.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
|
||||
AppSpawnResult result = {};
|
||||
(void)AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
ret = result.result;
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, APPSPAWN_MSG_INVALID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试多线程报文发送
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Communication_003, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
auto sendMsg = [&clientHandle]() {
|
||||
int ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
AppSpawnReqMsgHandle reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
ASSERT_EQ(ret, 0);
|
||||
ASSERT_EQ(result.result, 0);
|
||||
ASSERT_NE(result.pid, 0);
|
||||
if (result.pid > 0) {
|
||||
kill(result.pid, SIGKILL);
|
||||
}
|
||||
};
|
||||
|
||||
std::thread thread1(sendMsg);
|
||||
std::thread thread2(sendMsg);
|
||||
std::thread thread3(sendMsg);
|
||||
thread1.join();
|
||||
thread3.join();
|
||||
thread2.join();
|
||||
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试收到报文后,不回复,消息超时
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Communication_004, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn", false);
|
||||
testServer.Start(
|
||||
[](TestConnection *connection, const uint8_t *buffer, uint32_t buffLen) {
|
||||
},
|
||||
3000); // 3000 3s
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgHandle reqHandle = testServer.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
|
||||
AppSpawnResult result = {};
|
||||
(void)AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
ret = result.result;
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, APPSPAWN_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,msg flags
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_001, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
ret = AppSpawnReqMsgCreate(MSG_APP_SPAWN, "com.example.myapplication", &reqHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
// flags test
|
||||
const uint32_t testFlags[] = {10, 20, 31, 32, 34};
|
||||
uint32_t max = sizeof(testFlags) / sizeof(testFlags[0]);
|
||||
for (size_t i = 0; i < max; i++) {
|
||||
ret = AppSpawnReqMsgSetAppFlag(reqHandle, static_cast<AppFlagsIndex>(testFlags[i]));
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
ret = AppSpawnReqMsgSetAppFlag(reqHandle, MAX_FLAGS_INDEX);
|
||||
ASSERT_NE(ret, 0);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
|
||||
APPSPAWN_CHECK(reqNode != nullptr, break, "Invalid reqNode");
|
||||
APPSPAWN_CHECK(reqNode->msgFlags != nullptr, break, "Invalid reqNode");
|
||||
uint32_t maxUnit = (MAX_FLAGS_INDEX % 32) == 0 ? MAX_FLAGS_INDEX / 32 : MAX_FLAGS_INDEX / 32 + 1; // 32 bits
|
||||
APPSPAWN_CHECK(reqNode->msgFlags->count == maxUnit,
|
||||
break, "Invalid reqNode %{public}d", reqNode->msgFlags->count);
|
||||
|
||||
for (size_t i = 0; i < max; i++) {
|
||||
uint32_t index = testFlags[i] / 32; // 32 bits
|
||||
uint32_t bits = 1 << testFlags[i] % 32; // 32 bits
|
||||
APPSPAWN_LOGV("AppSpawnClientTest index %{public}u bits 0x%{public}x", index, bits);
|
||||
uint32_t result = (reqNode->msgFlags->flags[index] & bits) == bits;
|
||||
ASSERT_EQ(result == 1, 1);
|
||||
}
|
||||
ret = 0;
|
||||
} while (0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,dac 测试
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_002, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
void *tlvValue = GetAppProperty(property, TLV_DAC_INFO);
|
||||
AppDacInfo *info = static_cast<AppDacInfo *>(tlvValue);
|
||||
APPSPAWN_CHECK(info != nullptr, break, "Can not find dac info in msg");
|
||||
APPSPAWN_CHECK(info->uid == g_testHelper.GetTestUid(), break, "Invalid uid %{public}d", info->uid);
|
||||
APPSPAWN_CHECK(info->gid == g_testHelper.GetTestGid(), break, "Invalid gid %{public}d", info->gid);
|
||||
APPSPAWN_CHECK(info->gidCount == 2, break, "Invalid gidCount %{public}d", info->gidCount); // 2 default
|
||||
APPSPAWN_CHECK(info->gidTable[1] == g_testHelper.GetTestGidGroup() + 1,
|
||||
break, "Invalid uid %{public}d", info->gidTable[1]);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,bundle name 测试
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_003, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
do {
|
||||
g_testHelper.SetProcessName("test222222222222222234512345678test222222222222222234512345678"
|
||||
"test222222222222222234512345678test222222222222222234512345678"
|
||||
"test222222222222222234512345678test222222222222222234512345678"
|
||||
"test222222222222222234512345678test2222222222222222345123456781234567");
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
void *tlvValue = GetAppProperty(property, TLV_BUNDLE_INFO);
|
||||
AppSpawnMsgBundleInfo *info = static_cast<AppSpawnMsgBundleInfo *>(tlvValue);
|
||||
APPSPAWN_CHECK(info != nullptr, break, "Can not find dac info in msg");
|
||||
APPSPAWN_CHECK(info->bundleIndex == g_testHelper.GetTestBundleIndex(),
|
||||
break, "Invalid bundleIndex %{public}d", info->bundleIndex);
|
||||
APPSPAWN_LOGV("info->bundleName %{public}s", info->bundleName);
|
||||
APPSPAWN_CHECK(strcmp(info->bundleName, g_testHelper.GetDefaultTestAppBundleName()) == 0,
|
||||
break, "Invalid bundleName %{public}s", info->bundleName);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
g_testHelper.SetDefaultTestData();
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,render cmd
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_004, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
// save render cmd to req
|
||||
const char *renderCmd = "test 222222222222222222222222222222222222222222222222 \
|
||||
222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222 \
|
||||
333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334456789";
|
||||
ret = AppSpawnReqMsgAddStringInfo(reqHandle, MSG_EXT_NAME_RENDER_CMD, renderCmd);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add render cmd %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
DumpAppSpawnMsg(property->message);
|
||||
uint32_t len = 0;
|
||||
char *renderCmdMsg = reinterpret_cast<char *>(GetAppPropertyExt(property, MSG_EXT_NAME_RENDER_CMD, &len));
|
||||
APPSPAWN_CHECK(renderCmdMsg != nullptr, break, "Can not find render cmd in msg");
|
||||
APPSPAWN_LOGV("info->bundleName %{public}s", renderCmdMsg);
|
||||
APPSPAWN_CHECK(strcmp(renderCmdMsg, renderCmd) == 0,
|
||||
break, "Invalid renderCmd %{public}s", renderCmd);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,ownerId cmd
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_005, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
// save owner to req
|
||||
const char *ownerId = "test 2222222222222222222222222222222222222222222222223451234567";
|
||||
ret = AppSpawnReqMsgSetAppOwnerId(reqHandle, ownerId);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add owner %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
void *tlvValue = GetAppProperty(property, TLV_OWNER_INFO);
|
||||
AppSpawnMsgOwnerId *owner = static_cast<AppSpawnMsgOwnerId *>(tlvValue);
|
||||
APPSPAWN_CHECK(owner != nullptr, break, "Can not find owner cmd in msg");
|
||||
APPSPAWN_LOGV("owner->ownerId %{public}s", owner->ownerId);
|
||||
APPSPAWN_CHECK(strcmp(owner->ownerId, ownerId) == 0, break, "Invalid ownerId %{public}s", ownerId);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,internet permission
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_006, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = AppSpawnReqMsgSetAppInternetPermissionInfo(reqHandle, 101, 102); // 101 102 test
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add owner %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
void *tlvValue = GetAppProperty(property, TLV_INTERNET_INFO);
|
||||
AppSpawnMsgInternetInfo *interInfo = static_cast<AppSpawnMsgInternetInfo *>(tlvValue);
|
||||
APPSPAWN_CHECK(interInfo != nullptr, break, "Can not find interInfo in msg");
|
||||
APPSPAWN_CHECK(102 == interInfo->setAllowInternet, // 102 test
|
||||
break, "Invalid setAllowInternet %{public}d", interInfo->setAllowInternet);
|
||||
APPSPAWN_CHECK(101 == interInfo->allowInternet, // 101 test
|
||||
break, "Invalid allowInternet %{public}d", interInfo->allowInternet);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,domain info
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_007, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
const char *apl = "test222222222222222234512345678";
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = AppSpawnReqMsgSetAppDomainInfo(reqHandle, 1, apl);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add domain %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
void *tlvValue = GetAppProperty(property, TLV_DOMAIN_INFO);
|
||||
AppSpawnMsgDomainInfo *domainInfo = static_cast<AppSpawnMsgDomainInfo *>(tlvValue);
|
||||
APPSPAWN_CHECK(domainInfo != nullptr, break, "Can not find owner cmd in msg");
|
||||
APPSPAWN_CHECK(1 == domainInfo->hapFlags, break, "Invalid hapFlags %{public}d", domainInfo->hapFlags);
|
||||
APPSPAWN_LOGV("Test apl: %{public}s", domainInfo->apl);
|
||||
APPSPAWN_CHECK(strcmp(domainInfo->apl, apl) == 0, break, "Invalid apl %{public}s", domainInfo->apl);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,access token
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_008, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = AppSpawnReqMsgSetAppAccessToken(reqHandle, 12345678); // 12345678
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add access token %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
void *tlvValue = GetAppProperty(property, TLV_ACCESS_TOKEN_INFO);
|
||||
AppSpawnMsgAccessToken *tokenInfo = static_cast<AppSpawnMsgAccessToken *>(tlvValue);
|
||||
APPSPAWN_CHECK(tokenInfo != nullptr, break, "Can not find owner cmd in msg");
|
||||
APPSPAWN_CHECK(12345678 == tokenInfo->accessTokenIdEx, break, "Invalid accessTokenIdEx");
|
||||
ret = 0;
|
||||
} while (0);
|
||||
ASSERT_EQ(ret, 0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,测试扩展tlv
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_009, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
const char *tlvName = "tlv-name-2";
|
||||
const uint32_t testDataLen = 10; // 10
|
||||
AppSpawningCtx *property = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
std::vector<char> testData(testDataLen, '1');
|
||||
testData.push_back('1');
|
||||
testData.push_back('2');
|
||||
testData.push_back('3');
|
||||
testData.push_back('4');
|
||||
testData.push_back('5');
|
||||
testData.push_back('6');
|
||||
testData.push_back('7');
|
||||
testData.push_back('8');
|
||||
testData.push_back('9');
|
||||
testData.push_back('\0');
|
||||
ret = AppSpawnReqMsgAddExtInfo(reqHandle, tlvName,
|
||||
reinterpret_cast<uint8_t *>(const_cast<char *>(testData.data())), testData.size());
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to ext tlv %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = AppSpawnReqMsgSetAppAccessToken(reqHandle, 12345678); // 12345678
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add access token %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
uint32_t tlvLen = 0;
|
||||
uint8_t *tlvValue = reinterpret_cast<uint8_t *>(GetAppPropertyExt(property, tlvName, &tlvLen));
|
||||
APPSPAWN_CHECK(tlvValue != nullptr, break, "Can not find tlv in msg");
|
||||
APPSPAWN_CHECK(tlvLen == testData.size(), break, "Invalid tlv len %{public}u", tlvLen);
|
||||
APPSPAWN_CHECK(strncmp(reinterpret_cast<char *>(tlvValue), testData.data(), testData.size()) == 0,
|
||||
break, "Invalid ext tlv %{public}s ", reinterpret_cast<char *>(tlvValue + testDataLen));
|
||||
ret = 0;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,测试扩展tlv-超长
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_010, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
const char *tlvName = "tlv-name-3";
|
||||
const uint32_t testDataLen = 7416; // 7416
|
||||
AppSpawningCtx *property = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
std::vector<char> testData(testDataLen, '1');
|
||||
testData.push_back('1');
|
||||
testData.push_back('2');
|
||||
testData.push_back('3');
|
||||
testData.push_back('4');
|
||||
testData.push_back('5');
|
||||
testData.push_back('6');
|
||||
testData.push_back('7');
|
||||
testData.push_back('8');
|
||||
testData.push_back('9');
|
||||
testData.push_back('\0');
|
||||
ret = AppSpawnReqMsgAddExtInfo(reqHandle, tlvName,
|
||||
reinterpret_cast<uint8_t *>(const_cast<char *>(testData.data())), testData.size());
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to ext tlv %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = AppSpawnReqMsgSetAppAccessToken(reqHandle, 12345678); // 12345678
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add access token %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
uint32_t tlvLen = 0;
|
||||
uint8_t *tlvValue = reinterpret_cast<uint8_t *>(GetAppPropertyExt(property, tlvName, &tlvLen));
|
||||
APPSPAWN_CHECK(tlvValue != nullptr, break, "Can not find tlv in msg");
|
||||
APPSPAWN_CHECK(tlvLen == testData.size(), break, "Invalid tlv len %{public}u", tlvLen);
|
||||
APPSPAWN_CHECK(strncmp(reinterpret_cast<char *>(tlvValue), testData.data(), testData.size()) == 0,
|
||||
break, "Invalid ext tlv %{public}s ", reinterpret_cast<char *>(tlvValue + testDataLen));
|
||||
ret = 0;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,测试扩展tlv-最大
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_011, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
const char *tlvName = "tlv-name-4";
|
||||
const uint32_t testDataLen = EXTRAINFO_TOTAL_LENGTH_MAX - 10; // EXTRAINFO_TOTAL_LENGTH_MAX - 10 最大扩展
|
||||
AppSpawningCtx *property = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
std::vector<char> testData(testDataLen, '1');
|
||||
testData.push_back('1');
|
||||
testData.push_back('2');
|
||||
testData.push_back('3');
|
||||
testData.push_back('4');
|
||||
testData.push_back('5');
|
||||
testData.push_back('6');
|
||||
testData.push_back('7');
|
||||
testData.push_back('8');
|
||||
testData.push_back('9');
|
||||
testData.push_back('\0');
|
||||
ret = AppSpawnReqMsgAddExtInfo(reqHandle, tlvName,
|
||||
reinterpret_cast<uint8_t *>(const_cast<char *>(testData.data())), testData.size());
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to ext tlv %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = AppSpawnReqMsgSetAppAccessToken(reqHandle, 12345678); // 12345678
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add access token %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
uint32_t tlvLen = 0;
|
||||
uint8_t *tlvValue = reinterpret_cast<uint8_t *>(GetAppPropertyExt(property, tlvName, &tlvLen));
|
||||
APPSPAWN_CHECK(tlvValue != nullptr, break, "Can not find tlv in msg");
|
||||
APPSPAWN_CHECK(tlvLen == testData.size(), break, "Invalid tlv len %{public}u", tlvLen);
|
||||
APPSPAWN_CHECK(strncmp(reinterpret_cast<char *>(tlvValue), testData.data(), testData.size()) == 0,
|
||||
break, "Invalid ext tlv %{public}s ", reinterpret_cast<char *>(tlvValue + testDataLen));
|
||||
ret = 0;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,permission flags
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_012, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
ret = AppSpawnReqMsgCreate(MSG_APP_SPAWN, "com.example.myapplication", &reqHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
// flags test
|
||||
int max = GetMaxPermissionIndex();
|
||||
for (int i = 0; i < max; i++) {
|
||||
ret = AppSpawnReqMsgAddPermission(reqHandle, GetPermissionByIndex(i));
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
ret = 0;
|
||||
for (size_t i = 0; i < max; i++) {
|
||||
if (!CheckAppPermissionFlagSet(property, (uint32_t)i)) {
|
||||
APPSPAWN_LOGE("Invalid permission not set %{public}d %{public}s", i, GetPermissionByIndex(i));
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试消息构建及解析,测试terminate msg
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnClientTest, App_Client_Msg_013, TestSize.Level0)
|
||||
{
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
ret = AppSpawnTerminateMsgCreate(100, &reqHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
ret = AppSpawnReqMsgSetAppAccessToken(reqHandle, 12345678); // 12345678
|
||||
ASSERT_NE(ret, 0);
|
||||
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
ASSERT_NE(result.result, 0);
|
||||
} while (0);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
}
|
||||
} // namespace OHOS
|
0
test/unittest/app_spawn_client_test/app_spawn_interface_test.cpp
Executable file → Normal file
0
test/unittest/app_spawn_client_test/app_spawn_interface_test.cpp
Executable file → Normal file
167
test/unittest/app_spawn_standard_test/BUILD.gn
Normal file
167
test/unittest/app_spawn_standard_test/BUILD.gn
Normal file
@ -0,0 +1,167 @@
|
||||
# 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/test.gni")
|
||||
|
||||
ohos_unittest("AppSpawn_ut") {
|
||||
module_out_path = "${module_output_path}"
|
||||
deps = []
|
||||
defines = [
|
||||
"APPSPAWN_BASE_DIR=\"/data/appspawn_ut\"",
|
||||
"APPSPAWN_LABEL=\"APPSPAWN_UT\"",
|
||||
"APPSPAWN_TEST",
|
||||
"APPSPAWN_DEBUG",
|
||||
"USER_TIMER_TO_CHECK",
|
||||
"OHOS_DEBUG",
|
||||
"GRAPHIC_PERMISSION_CHECK",
|
||||
"capset=CapsetStub",
|
||||
"unshare=UnshareStub",
|
||||
"mount=MountStub",
|
||||
"symlink=SymlinkStub",
|
||||
"chdir=ChdirStub",
|
||||
"chroot=ChrootStub",
|
||||
"syscall=SyscallStub",
|
||||
"umount2=Umount2Stub",
|
||||
"access=AccessStub",
|
||||
"dlopen=DlopenStub",
|
||||
"dlsym=DlsymStub",
|
||||
"dlclose=DlcloseStub",
|
||||
"execv=ExecvStub",
|
||||
"getprocpid=GetprocpidStub",
|
||||
"setgroups=SetgroupsStub",
|
||||
"setresgid=SetresgidStub",
|
||||
"setresuid=SetresuidStub",
|
||||
"setuid=SetuidStub",
|
||||
"setgid=SetgidStub",
|
||||
"execvp=ExecvpStub",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"${appspawn_path}",
|
||||
"${appspawn_path}/common",
|
||||
"${appspawn_path}/standard",
|
||||
"${appspawn_path}/modules/modulemgr",
|
||||
"${appspawn_path}/modules/ace_adapter",
|
||||
"${appspawn_path}/modules/common",
|
||||
"${appspawn_path}/modules/sandbox",
|
||||
"${appspawn_innerkits_path}/client",
|
||||
"${appspawn_innerkits_path}/include",
|
||||
"${appspawn_innerkits_path}/permission",
|
||||
"${appspawn_path}/modules/module_engine/include",
|
||||
"${appspawn_path}/test/mock",
|
||||
"${appspawn_path}/test/unittest",
|
||||
"${appspawn_path}/util/include",
|
||||
]
|
||||
sources = [
|
||||
"${appspawn_path}/common/appspawn_server.c",
|
||||
"${appspawn_path}/modules/modulemgr/appspawn_modulemgr.c",
|
||||
"${appspawn_path}/standard/appspawn_appmgr.c",
|
||||
"${appspawn_path}/standard/appspawn_msgmgr.c",
|
||||
"${appspawn_path}/standard/appspawn_service.c",
|
||||
"${appspawn_path}/standard/nwebspawn_launcher.c",
|
||||
"${appspawn_path}/util/src/appspawn_base64.c",
|
||||
"${appspawn_path}/util/src/appspawn_utils.c",
|
||||
]
|
||||
|
||||
# client
|
||||
sources += [
|
||||
"${appspawn_innerkits_path}/client/appspawn_client.c",
|
||||
"${appspawn_innerkits_path}/client/appspawn_msg.c",
|
||||
"${appspawn_innerkits_path}/permission/appspawn_mount_permission.c",
|
||||
]
|
||||
|
||||
# modules sources
|
||||
sources += [
|
||||
"${appspawn_path}/modules/ace_adapter/ace_adapter.cpp",
|
||||
"${appspawn_path}/modules/ace_adapter/command_lexer.cpp",
|
||||
"${appspawn_path}/modules/common/appspawn_adapter.cpp",
|
||||
"${appspawn_path}/modules/common/appspawn_cgroup.c",
|
||||
"${appspawn_path}/modules/common/appspawn_common.c",
|
||||
"${appspawn_path}/modules/common/appspawn_namespace.c",
|
||||
"${appspawn_path}/modules/nweb_adapter/nwebspawn_adapter.cpp",
|
||||
"${appspawn_path}/modules/sandbox/appspawn_mount_template.c",
|
||||
"${appspawn_path}/modules/sandbox/appspawn_permission.c",
|
||||
"${appspawn_path}/modules/sandbox/appspawn_sandbox.c",
|
||||
"${appspawn_path}/modules/sandbox/sandbox_cfgvar.c",
|
||||
"${appspawn_path}/modules/sandbox/sandbox_expand.c",
|
||||
"${appspawn_path}/modules/sandbox/sandbox_load.c",
|
||||
"${appspawn_path}/modules/sandbox/sandbox_manager.c",
|
||||
]
|
||||
|
||||
# add stub
|
||||
include_dirs += [ "${appspawn_path}/test/mock" ]
|
||||
sources += [
|
||||
"${appspawn_path}/test/mock/app_spawn_stub.cpp",
|
||||
"${appspawn_path}/test/mock/app_system_stub.c",
|
||||
]
|
||||
|
||||
# add test
|
||||
include_dirs += [ "${appspawn_path}/test/unittest" ]
|
||||
sources += [
|
||||
"${appspawn_path}/test/unittest/app_spawn_standard_test/app_spawn_cgroup_test.cpp",
|
||||
"${appspawn_path}/test/unittest/app_spawn_standard_test/app_spawn_cold_run_test.cpp",
|
||||
"${appspawn_path}/test/unittest/app_spawn_standard_test/app_spawn_command_lexer_test.cpp",
|
||||
"${appspawn_path}/test/unittest/app_spawn_standard_test/app_spawn_sandbox_test.cpp",
|
||||
"${appspawn_path}/test/unittest/app_spawn_standard_test/app_spawn_service_test.cpp",
|
||||
"${appspawn_path}/test/unittest/app_spawn_standard_test/nweb_spawn_service_test.cpp",
|
||||
"${appspawn_path}/test/unittest/app_spawn_test_helper.cpp",
|
||||
]
|
||||
|
||||
configs = [ "${appspawn_path}:appspawn_config" ]
|
||||
external_deps = [
|
||||
"ability_base:want",
|
||||
"ability_runtime:app_manager",
|
||||
"ability_runtime:appkit_native",
|
||||
"ability_runtime:runtime",
|
||||
"access_token:libtoken_setproc",
|
||||
"access_token:libtokenid_sdk",
|
||||
"ace_engine:ace_forward_compatibility",
|
||||
"bundle_framework:appexecfwk_base",
|
||||
"bundle_framework:appexecfwk_core",
|
||||
"cJSON:cjson",
|
||||
"c_utils:utils",
|
||||
"config_policy:configpolicy_util",
|
||||
"eventhandler:libeventhandler",
|
||||
"hilog:libhilog",
|
||||
"hitrace:hitrace_meter",
|
||||
"init:libbegetutil",
|
||||
"init:seccomp",
|
||||
"ipc:ipc_core",
|
||||
"napi:ace_napi",
|
||||
"os_account:os_account_innerkits",
|
||||
"resource_management:global_resmgr",
|
||||
]
|
||||
|
||||
if (asan_detector || is_asan) {
|
||||
defines += [ "ASAN_DETECTOR" ]
|
||||
sources += [ "${appspawn_path}/modules/asan_detector/asan_detector.c" ]
|
||||
}
|
||||
|
||||
if (build_selinux) {
|
||||
defines += [ "WITH_SELINUX" ]
|
||||
deps += [ "//third_party/selinux:libselinux" ]
|
||||
external_deps += [ "selinux_adapter:libhap_restorecon" ]
|
||||
}
|
||||
|
||||
if (appspawn_report_event) {
|
||||
defines += [ "REPORT_EVENT" ]
|
||||
sources += [ "${appspawn_path}/modules/sysevent/event_reporter.cpp" ]
|
||||
external_deps += [ "hisysevent:libhisysevent" ]
|
||||
}
|
||||
|
||||
if (target_cpu == "arm64" || target_cpu == "x86_64" ||
|
||||
target_cpu == "riscv64") {
|
||||
defines += [ "APPSPAWN_64" ]
|
||||
}
|
||||
}
|
338
test/unittest/app_spawn_standard_test/app_spawn_cgroup_test.cpp
Normal file
338
test/unittest/app_spawn_standard_test/app_spawn_cgroup_test.cpp
Normal file
@ -0,0 +1,338 @@
|
||||
/*
|
||||
* 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 <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "appspawn_modulemgr.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "json_utils.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
#include "app_spawn_stub.h"
|
||||
#include "app_spawn_test_helper.h"
|
||||
|
||||
using namespace testing;
|
||||
using namespace testing::ext;
|
||||
using namespace OHOS;
|
||||
|
||||
namespace OHOS {
|
||||
static AppSpawnTestHelper g_testHelper;
|
||||
class AppSpawnCGroupTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase() {}
|
||||
static void TearDownTestCase() {}
|
||||
void SetUp() {}
|
||||
void TearDown() {}
|
||||
};
|
||||
|
||||
static AppSpawnedProcess *CreateTestAppInfo(const char *name)
|
||||
{
|
||||
AppSpawnedProcess *appInfo = reinterpret_cast<AppSpawnedProcess *>(
|
||||
malloc(sizeof(AppSpawnedProcess) + strlen(name) + 1));
|
||||
APPSPAWN_CHECK(appInfo != nullptr, return nullptr, "Failed to create appInfo");
|
||||
appInfo->pid = 33; // 33
|
||||
appInfo->uid = 200000 * 200 + 21; // 200000 200 21
|
||||
appInfo->max = 0;
|
||||
appInfo->exitStatus = 0;
|
||||
int ret = strcpy_s(appInfo->name, strlen(name) + 1, name);
|
||||
APPSPAWN_CHECK(ret == 0,
|
||||
free(appInfo); return nullptr, "Failed to strcpy process name");
|
||||
OH_ListInit(&appInfo->node);
|
||||
return appInfo;
|
||||
}
|
||||
|
||||
static int GetTestCGroupFilePath(const AppSpawnedProcess *appInfo, const char *fileName, char *path, bool create)
|
||||
{
|
||||
int ret = GetCgroupPath(appInfo, path, PATH_MAX);
|
||||
APPSPAWN_CHECK(ret == 0, return errno, "Failed to get real path errno: %{public}d", errno);
|
||||
(void)CreateSandboxDir(path, 0755); // 0755 default mode
|
||||
ret = strcat_s(path, PATH_MAX, fileName);
|
||||
APPSPAWN_CHECK(ret == 0, return errno, "Failed to strcat_s errno: %{public}d", errno);
|
||||
if (create) {
|
||||
FILE *file = fopen(path, "w");
|
||||
APPSPAWN_CHECK(file != NULL, return errno, "Create file fail %{public}s errno: %{public}d", path, errno);
|
||||
fclose(file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnCGroupTest, App_Spawn_CGroup_001, TestSize.Level0)
|
||||
{
|
||||
int ret = -1;
|
||||
AppSpawnedProcess *appInfo = nullptr;
|
||||
const char name[] = "app-test-001";
|
||||
do {
|
||||
appInfo = CreateTestAppInfo(name);
|
||||
APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
|
||||
char path[PATH_MAX] = {};
|
||||
ret = GetCgroupPath(appInfo, path, sizeof(path));
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to get real path errno: %d", errno);
|
||||
APPSPAWN_CHECK(strstr(path, "200") != nullptr && strstr(path, "33") != nullptr && strstr(path, name) != nullptr,
|
||||
break, "Invalid path: %s", path);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
if (appInfo) {
|
||||
free(appInfo);
|
||||
}
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnCGroupTest, App_Spawn_CGroup_002, TestSize.Level0)
|
||||
{
|
||||
int ret = -1;
|
||||
AppSpawnedProcess *appInfo = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
FILE *file = nullptr;
|
||||
const char name[] = "app-test-001";
|
||||
do {
|
||||
char path[PATH_MAX] = {};
|
||||
appInfo = CreateTestAppInfo(name);
|
||||
APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
|
||||
|
||||
ret = GetTestCGroupFilePath(appInfo, "cgroup.procs", path, true);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
// spawn prepare process
|
||||
ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo);
|
||||
|
||||
// add success
|
||||
ret = GetTestCGroupFilePath(appInfo, "cgroup.procs", path, false);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
// write pid
|
||||
pid_t pids[] = {100, 101, 102};
|
||||
ret = WriteToFile(path, 0, pids, 3);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
ret = -1;
|
||||
file = fopen(path, "r");
|
||||
APPSPAWN_CHECK(file != NULL, break, "Open file fail %{public}s errno: %{public}d", path, errno);
|
||||
pid_t pid = 0;
|
||||
ret = -1;
|
||||
while (fscanf_s(file, "%d\n", &pid) == 1 && pid > 0) {
|
||||
APPSPAWN_LOGV("pid %d %d", pid, appInfo->pid);
|
||||
if (pid == appInfo->pid) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
APPSPAWN_CHECK(ret == 0, break, "Error no pid write to path errno: %{public}d", errno);
|
||||
|
||||
} while (0);
|
||||
if (appInfo) {
|
||||
free(appInfo);
|
||||
}
|
||||
if (file) {
|
||||
fclose(file);
|
||||
}
|
||||
AppSpawnDestroyContent(content);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnCGroupTest, App_Spawn_CGroup_003, TestSize.Level0)
|
||||
{
|
||||
int ret = -1;
|
||||
AppSpawnedProcess *appInfo = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
const char name[] = "app-test-001";
|
||||
do {
|
||||
char path[PATH_MAX] = {};
|
||||
appInfo = CreateTestAppInfo(name);
|
||||
APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
|
||||
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ProcessMgrHookExecute(STAGE_SERVER_APP_DIED, content, appInfo);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
if (appInfo) {
|
||||
free(appInfo);
|
||||
}
|
||||
AppSpawnDestroyContent(content);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnCGroupTest, App_Spawn_CGroup_004, TestSize.Level0)
|
||||
{
|
||||
int ret = -1;
|
||||
AppSpawnedProcess *appInfo = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
FILE *file = nullptr;
|
||||
const char name[] = "app-test-001";
|
||||
do {
|
||||
char path[PATH_MAX] = {};
|
||||
appInfo = CreateTestAppInfo(name);
|
||||
APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
|
||||
appInfo->pid = 44; // 44 test pid
|
||||
|
||||
content = AppSpawnCreateContent(NWEBSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_NWEB_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo);
|
||||
// add success
|
||||
ret = GetCgroupPath(appInfo, path, sizeof(path));
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to get real path errno: %{public}d", errno);
|
||||
ret = strcat_s(path, sizeof(path), "cgroup.procs");
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to strcat_s errno: %{public}d", errno);
|
||||
// do not write for nwebspawn, so no file
|
||||
file = fopen(path, "r");
|
||||
APPSPAWN_CHECK(file == NULL, break, "Find file %{public}s ", path);
|
||||
} while (0);
|
||||
if (appInfo) {
|
||||
free(appInfo);
|
||||
}
|
||||
if (file) {
|
||||
fclose(file);
|
||||
}
|
||||
AppSpawnDestroyContent(content);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnCGroupTest, App_Spawn_CGroup_005, TestSize.Level0)
|
||||
{
|
||||
int ret = -1;
|
||||
AppSpawnedProcess *appInfo = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
const char name[] = "app-test-001";
|
||||
do {
|
||||
char path[PATH_MAX] = {};
|
||||
appInfo = CreateTestAppInfo(name);
|
||||
APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
|
||||
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_NWEB_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ProcessMgrHookExecute(STAGE_SERVER_APP_DIED, content, appInfo);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
if (appInfo) {
|
||||
free(appInfo);
|
||||
}
|
||||
AppSpawnDestroyContent(content);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief in appspawn service, add and delete app
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnCGroupTest, App_Spawn_CGroup_006, TestSize.Level0)
|
||||
{
|
||||
int ret = -1;
|
||||
AppSpawnedProcess *appInfo = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
const char name[] = "app-test-001";
|
||||
do {
|
||||
char path[PATH_MAX] = {};
|
||||
appInfo = CreateTestAppInfo(name);
|
||||
APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
|
||||
|
||||
ret = GetTestCGroupFilePath(appInfo, "cgroup.procs", path, true);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo);
|
||||
|
||||
// add success
|
||||
ret = GetTestCGroupFilePath(appInfo, "cgroup.procs", path, false);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
// write pid
|
||||
pid_t pids[] = {100, 101, 102};
|
||||
ret = WriteToFile(path, 0, pids, 3);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
AppSpawnedProcess *appInfo2 = CreateTestAppInfo(name);
|
||||
APPSPAWN_CHECK(appInfo2 != nullptr, break, "Failed to create appInfo");
|
||||
OH_ListAddTail(&GetAppSpawnMgr()->appQueue, &appInfo2->node);
|
||||
appInfo2->pid = 102;
|
||||
ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo2);
|
||||
// died
|
||||
ProcessMgrHookExecute(STAGE_SERVER_APP_DIED, content, appInfo);
|
||||
OH_ListRemove(&appInfo2->node);
|
||||
free(appInfo2);
|
||||
} while (0);
|
||||
if (appInfo) {
|
||||
free(appInfo);
|
||||
}
|
||||
AppSpawnDestroyContent(content);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief in appspawn service, max write
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnCGroupTest, App_Spawn_CGroup_007, TestSize.Level0)
|
||||
{
|
||||
int ret = -1;
|
||||
AppSpawnedProcess *appInfo = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
const char name[] = "app-test-001";
|
||||
do {
|
||||
char path[PATH_MAX] = {};
|
||||
appInfo = CreateTestAppInfo(name);
|
||||
APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
|
||||
appInfo->max = 10; // 10 test max
|
||||
ret = GetTestCGroupFilePath(appInfo, "pids.max", path, true);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo);
|
||||
|
||||
// add success
|
||||
ret = GetTestCGroupFilePath(appInfo, "pids.max", path, false);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
ret = -1;
|
||||
FILE *file = fopen(path, "r");
|
||||
APPSPAWN_CHECK(file != NULL, break, "Open file fail %{public}s errno: %{public}d", path, errno);
|
||||
uint32_t max = 0;
|
||||
ret = -1;
|
||||
while (fscanf_s(file, "%d\n", &max) == 1 && max > 0) {
|
||||
APPSPAWN_LOGV("max %d %d", max, appInfo->max);
|
||||
if (max == appInfo->max) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
} while (0);
|
||||
if (appInfo) {
|
||||
free(appInfo);
|
||||
}
|
||||
AppSpawnDestroyContent(content);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
} // namespace OHOS
|
@ -0,0 +1,593 @@
|
||||
/*
|
||||
* 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 <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "appspawn_modulemgr.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "json_utils.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
#include "app_spawn_stub.h"
|
||||
#include "app_spawn_test_helper.h"
|
||||
|
||||
using namespace testing;
|
||||
using namespace testing::ext;
|
||||
using namespace OHOS;
|
||||
|
||||
namespace OHOS {
|
||||
static AppSpawnTestHelper g_testHelper;
|
||||
class AppSpawnColdRunTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase() {}
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
StubNode *stub = GetStubNode(STUB_MOUNT);
|
||||
if (stub) {
|
||||
stub->flags &= ~STUB_NEED_CHECK;
|
||||
}
|
||||
}
|
||||
void SetUp() {}
|
||||
void TearDown() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* 接管启动的exec 过程
|
||||
*
|
||||
*/
|
||||
static int ExecvAbortStub(const char *pathName, char *const argv[])
|
||||
{
|
||||
if (!(strcmp(pathName, "/system/bin/appspawn") == 0 || strcmp(pathName, "/system/asan/bin/appspawn") == 0)) {
|
||||
return 0;
|
||||
}
|
||||
APPSPAWN_LOGV("ExecvAbortStub pathName: %{public}s ", pathName);
|
||||
_exit(0x7f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ExecvLocalProcessStub(const char *pathName, char *const argv[])
|
||||
{
|
||||
if (!(strcmp(pathName, "/system/bin/appspawn") == 0 || strcmp(pathName, "/system/asan/bin/appspawn") == 0)) {
|
||||
return 0;
|
||||
}
|
||||
APPSPAWN_LOGV("ExecvLocalProcessStub pathName: %{public}s ", pathName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ExecvTimeoutStub(const char *pathName, char *const argv[])
|
||||
{
|
||||
if (!(strcmp(pathName, "/system/bin/appspawn") == 0 || strcmp(pathName, "/system/asan/bin/appspawn") == 0)) {
|
||||
return 0;
|
||||
}
|
||||
APPSPAWN_LOGV("ExecvLocalProcessStub pathName: %{public}s ", pathName);
|
||||
usleep(500000); // 500000 500ms
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int HandleExecvStub(const char *pathName, char *const argv[])
|
||||
{
|
||||
if (!(strcmp(pathName, "/system/bin/appspawn") == 0 || strcmp(pathName, "/system/asan/bin/appspawn") == 0)) {
|
||||
return 0;
|
||||
}
|
||||
std::string cmd;
|
||||
int index = 0;
|
||||
do {
|
||||
cmd += argv[index];
|
||||
cmd += " ";
|
||||
index++;
|
||||
} while (argv[index] != nullptr);
|
||||
APPSPAWN_LOGV("HandleExecvStub cmd: %{public}s ", cmd.c_str());
|
||||
|
||||
CmdArgs *args = nullptr;
|
||||
AppSpawnContent *content = AppSpawnTestHelper::StartSpawnServer(cmd, args);
|
||||
if (content == nullptr) {
|
||||
free(args);
|
||||
return -1;
|
||||
}
|
||||
content->runAppSpawn(content, args->argc, args->argv);
|
||||
free(args);
|
||||
APPSPAWN_LOGV("HandleExecvStub %{public}s exit", pathName);
|
||||
_exit(0x7f); // 0x7f user exit
|
||||
return 0;
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Cold_Run_001, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
StubNode *node = GetStubNode(STUB_EXECV);
|
||||
ASSERT_NE(node != nullptr, 0);
|
||||
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_APP_SPAWN, 0);
|
||||
// set cold start flags
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_COLD_BOOT);
|
||||
|
||||
ret = -1;
|
||||
node->flags |= STUB_NEED_CHECK;
|
||||
node->arg = reinterpret_cast<void *>(HandleExecvStub);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
if (ret == 0 && result.pid > 0) {
|
||||
APPSPAWN_LOGI("App_Spawn_Cold_Run_001 Kill pid %{public}d ", result.pid);
|
||||
kill(result.pid, SIGKILL);
|
||||
}
|
||||
ret = 0;
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Cold_Run_002, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
StubNode *node = GetStubNode(STUB_EXECV);
|
||||
ASSERT_NE(node != nullptr, 0);
|
||||
do {
|
||||
ret = AppSpawnClientInit(NWEBSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create client %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgHandle reqHandle = testServer.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
// set cold start flags
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_COLD_BOOT);
|
||||
|
||||
ret = -1;
|
||||
node->flags |= STUB_NEED_CHECK;
|
||||
node->arg = reinterpret_cast<void *>(HandleExecvStub);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
if (ret == 0 && result.pid > 0) {
|
||||
APPSPAWN_LOGI("App_Spawn_Cold_Run_002 Kill pid %{public}d ", result.pid);
|
||||
kill(result.pid, SIGKILL);
|
||||
}
|
||||
ret = 0;
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
node->flags &= ~STUB_NEED_CHECK;
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
static std::string GetColdRunArgs(AppSpawningCtx *property, const char *arg)
|
||||
{
|
||||
std::string argStr = arg;
|
||||
const uint32_t memSize = (property->message->msgHeader.msgLen % 1024 + 1) * 1024; // 1024
|
||||
property->forkCtx.shmId = shmget(IPC_PRIVATE, memSize, 0600); // 0600 mask
|
||||
APPSPAWN_CHECK(property->forkCtx.shmId >= 0, return nullptr,
|
||||
"Failed to get shm for %{public}s errno %{public}d", GetProcessName(property), errno);
|
||||
property->forkCtx.memSize = memSize;
|
||||
SendAppSpawnMsgToChild(property, property->message);
|
||||
argStr += "null";
|
||||
argStr += " -fd -1 0 ";
|
||||
argStr += std::to_string(property->forkCtx.shmId);
|
||||
return argStr;
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Cold_Run_003, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
CmdArgs *args = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
// set cold start flags
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_COLD_BOOT);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
std::string cmd = GetColdRunArgs(property, "appspawn -mode app_cold -param ");
|
||||
content = AppSpawnTestHelper::StartSpawnServer(cmd, args);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
AppSpawnHookExecute(STAGE_CHILD_PRE_COLDBOOT, 0, content, &property->client);
|
||||
content->runAppSpawn(content, args->argc, args->argv);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
if (args) {
|
||||
free(args);
|
||||
}
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Cold_Run_004, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
CmdArgs *args = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(NWEBSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req ");
|
||||
// set cold start flags
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_COLD_BOOT);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
std::string cmd = GetColdRunArgs(property, "appspawn -mode nweb_cold -param ");
|
||||
content = AppSpawnTestHelper::StartSpawnServer(cmd, args);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ASSERT_EQ(content->mode, MODE_FOR_NWEB_COLD_RUN);
|
||||
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
AppSpawnHookExecute(STAGE_CHILD_PRE_COLDBOOT, 0, content, &property->client);
|
||||
content->runAppSpawn(content, args->argc, args->argv);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
if (args) {
|
||||
free(args);
|
||||
}
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Cold_Run_005, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
CmdArgs *args = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
// asan set cold
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ASANENABLED);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_GWP_ENABLED_FORCE);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
std::string cmd = GetColdRunArgs(property, "appspawn -mode app_cold -param ");
|
||||
content = AppSpawnTestHelper::StartSpawnServer(cmd, args);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ASSERT_EQ(content->mode, MODE_FOR_APP_COLD_RUN);
|
||||
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
AppSpawnHookExecute(STAGE_CHILD_PRE_COLDBOOT, 0, content, &property->client);
|
||||
content->runAppSpawn(content, args->argc, args->argv);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
if (args) {
|
||||
free(args);
|
||||
}
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Cold_Run_006, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
CmdArgs *args = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
// asan set cold
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ASANENABLED);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_GWP_ENABLED_NORMAL);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
std::string cmd = GetColdRunArgs(property, "appspawn -mode app_cold -param ");
|
||||
content = AppSpawnTestHelper::StartSpawnServer(cmd, args);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ASSERT_EQ(content->mode, MODE_FOR_APP_COLD_RUN);
|
||||
// add property to content
|
||||
OH_ListAddTail(&GetAppSpawnMgr()->appSpawnQueue, &property->node);
|
||||
ProcessAppSpawnDumpMsg(nullptr);
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
AppSpawnHookExecute(STAGE_CHILD_PRE_COLDBOOT, 0, content, &property->client);
|
||||
content->runAppSpawn(content, args->argc, args->argv);
|
||||
property = nullptr;
|
||||
ret = 0;
|
||||
} while (0);
|
||||
if (args) {
|
||||
free(args);
|
||||
}
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试子进程abort
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Cold_Run_008, TestSize.Level0)
|
||||
{
|
||||
// child abort
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
StubNode *node = GetStubNode(STUB_EXECV);
|
||||
ASSERT_NE(node != nullptr, 0);
|
||||
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_APP_SPAWN, 0);
|
||||
// set cold start flags
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_COLD_BOOT);
|
||||
|
||||
ret = -1;
|
||||
node->flags |= STUB_NEED_CHECK;
|
||||
node->arg = reinterpret_cast<void *>(ExecvAbortStub);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_LOGI("AppSpawnClientSendMsg result %{public}d ", ret);
|
||||
if (ret == 0 && result.pid > 0) {
|
||||
APPSPAWN_LOGI("Kill pid %{public}d ", result.pid);
|
||||
kill(result.pid, SIGKILL);
|
||||
}
|
||||
ret = 0;
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
node->flags &= ~STUB_NEED_CHECK;
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试子进程不回复,导致等到超时
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Cold_Run_009, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
StubNode *node = GetStubNode(STUB_EXECV);
|
||||
ASSERT_NE(node != nullptr, 0);
|
||||
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_APP_SPAWN, 0);
|
||||
// set cold start flags
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_COLD_BOOT);
|
||||
|
||||
ret = -1;
|
||||
node->flags |= STUB_NEED_CHECK;
|
||||
node->arg = reinterpret_cast<void *>(ExecvTimeoutStub);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_LOGI("AppSpawnClientSendMsg result %{public}d ", ret);
|
||||
if (ret == 0 && result.pid > 0) {
|
||||
APPSPAWN_LOGI("Kill pid %{public}d ", result.pid);
|
||||
kill(result.pid, SIGKILL);
|
||||
}
|
||||
ret = 0;
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
node->flags &= ~STUB_NEED_CHECK;
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
static int TestBase64(const char *data)
|
||||
{
|
||||
uint32_t outLen = 0;
|
||||
uint32_t inLen = strlen(data);
|
||||
char *encodeData = nullptr;
|
||||
uint8_t *result = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
encodeData = Base64Encode(reinterpret_cast<const uint8_t *>(data), inLen);
|
||||
APPSPAWN_CHECK(encodeData != nullptr, break, "Failed encode %{public}s", data);
|
||||
result = Base64Decode(encodeData, strlen(encodeData), &outLen);
|
||||
APPSPAWN_CHECK(result != nullptr, break, "Failed decode %{public}s", data);
|
||||
APPSPAWN_CHECK(outLen == inLen, break, "Failed len %{public}s %{public}d %{public}d", data, outLen, inLen);
|
||||
APPSPAWN_CHECK(memcmp(reinterpret_cast<char *>(result), data, outLen) == 0,
|
||||
break, "result %{public}s %{public}s", data, result);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
if (encodeData) {
|
||||
free(encodeData);
|
||||
}
|
||||
if (result) {
|
||||
free(result);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_001, TestSize.Level0)
|
||||
{
|
||||
const char *data = "a";
|
||||
int ret = TestBase64(data);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_002, TestSize.Level0)
|
||||
{
|
||||
const char *data = "ab";
|
||||
int ret = TestBase64(data);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_003, TestSize.Level0)
|
||||
{
|
||||
const char *data = "abc";
|
||||
int ret = TestBase64(data);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_004, TestSize.Level0)
|
||||
{
|
||||
const char *data = "abcd";
|
||||
int ret = TestBase64(data);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_005, TestSize.Level0)
|
||||
{
|
||||
const char *data = "abcde";
|
||||
int ret = TestBase64(data);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_006, TestSize.Level0)
|
||||
{
|
||||
const char *data = "abcdedf";
|
||||
int ret = TestBase64(data);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_007, TestSize.Level0)
|
||||
{
|
||||
const char *data = "abcdedf";
|
||||
uint32_t outLen = 0;
|
||||
uint8_t *result = Base64Decode(data, strlen(data), &outLen);
|
||||
ASSERT_EQ(result == nullptr, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_008, TestSize.Level0)
|
||||
{
|
||||
const char *data = "abcdedf";
|
||||
uint32_t outLen = 0;
|
||||
uint8_t *result = Base64Decode(data, strlen(data) + 1, &outLen);
|
||||
ASSERT_EQ(result == nullptr, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_009, TestSize.Level0)
|
||||
{
|
||||
const char *data = "abcdedf{";
|
||||
uint32_t outLen = 0;
|
||||
uint8_t *result = Base64Decode(data, strlen(data), &outLen);
|
||||
ASSERT_EQ(result == nullptr, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_010, TestSize.Level0)
|
||||
{
|
||||
const char *data = "*abcdedf{";
|
||||
uint32_t outLen = 0;
|
||||
uint8_t *result = Base64Decode(data, strlen(data), &outLen);
|
||||
ASSERT_EQ(result == nullptr, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试base64
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnColdRunTest, App_Spawn_Base64_011, TestSize.Level0)
|
||||
{
|
||||
const char *data = "a.bcdedf";
|
||||
uint32_t outLen = 0;
|
||||
uint8_t *result = Base64Decode(data, strlen(data), &outLen);
|
||||
ASSERT_EQ(result == nullptr, 1);
|
||||
}
|
||||
} // namespace OHOS
|
787
test/unittest/app_spawn_standard_test/app_spawn_service_test.cpp
Normal file
787
test/unittest/app_spawn_standard_test/app_spawn_service_test.cpp
Normal file
@ -0,0 +1,787 @@
|
||||
/*
|
||||
* 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 <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "appspawn_modulemgr.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "json_utils.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
#include "app_spawn_stub.h"
|
||||
#include "app_spawn_test_helper.h"
|
||||
|
||||
using namespace testing;
|
||||
using namespace testing::ext;
|
||||
using namespace OHOS;
|
||||
|
||||
namespace OHOS {
|
||||
static AppSpawnTestHelper g_testHelper;
|
||||
class AppSpawnServiceTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase() {}
|
||||
static void TearDownTestCase() {}
|
||||
void SetUp() {}
|
||||
void TearDown() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 正常消息发送和接收,完整应用孵化过程
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_001, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
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_APP_SPAWN, 0);
|
||||
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to send msg %{public}d", ret);
|
||||
if (ret == 0 && result.pid > 0) {
|
||||
APPSPAWN_LOGI("App_Spawn_Msg_001 Kill pid %{public}d ", result.pid);
|
||||
kill(result.pid, SIGKILL);
|
||||
}
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 模拟测试,孵化进程退出后,MSG_GET_RENDER_TERMINATION_STATUS
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_002, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
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_APP_SPAWN, 0);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_LOGV("App_Spawn_002 recv result %{public}d", ret);
|
||||
if (ret != 0 || result.pid == 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
// stop child and termination
|
||||
APPSPAWN_LOGI("App_Spawn_002 Kill pid %{public}d ", result.pid);
|
||||
kill(result.pid, SIGKILL);
|
||||
// MSG_GET_RENDER_TERMINATION_STATUS
|
||||
ret = AppSpawnTerminateMsgCreate(result.pid, &reqHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create termination msg %{public}s", APPSPAWN_SERVER_NAME);
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_LOGV("Send MSG_GET_RENDER_TERMINATION_STATUS %{public}d", ret);
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 模拟测试,MSG_GET_RENDER_TERMINATION_STATUS 关闭孵化进程
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_003, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
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_APP_SPAWN, 0);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_LOGV("App_Spawn_003 recv result %{public}d", ret);
|
||||
if (ret != 0 || result.pid == 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
// MSG_GET_RENDER_TERMINATION_STATUS
|
||||
ret = AppSpawnTerminateMsgCreate(result.pid, &reqHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create termination msg %{public}s", APPSPAWN_SERVER_NAME);
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_LOGV("Send MSG_GET_RENDER_TERMINATION_STATUS %{public}d", ret);
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief dump 消息
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_004, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
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_DUMP, 0);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to send msg %{public}d", ret);
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MSG_SPAWN_NATIVE_PROCESS 正常消息发送和接收,完整应用孵化过程
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_005, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
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);
|
||||
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to send msg %{public}d", ret);
|
||||
if (ret == 0 && result.pid > 0) {
|
||||
APPSPAWN_LOGI("App_Spawn_Msg_001 Kill pid %{public}d ", result.pid);
|
||||
kill(result.pid, SIGKILL);
|
||||
}
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Msg_002, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
int socketId = -1;
|
||||
// 没有tlv的消息,返回错误
|
||||
do {
|
||||
socketId = testServer.CreateSocket();
|
||||
APPSPAWN_CHECK(socketId >= 0, break, "Failed to create socket %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
std::vector<uint8_t> buffer(sizeof(AppSpawnResponseMsg));
|
||||
uint32_t msgLen = 0;
|
||||
ret = testServer.CreateSendMsg(buffer, MSG_APP_SPAWN, msgLen, {});
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
|
||||
int len = write(socketId, buffer.data(), msgLen);
|
||||
APPSPAWN_CHECK(len > 0, break, "Failed to send msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
// recv
|
||||
APPSPAWN_LOGV("Start recv ... ");
|
||||
len = read(socketId, buffer.data(), buffer.size());
|
||||
APPSPAWN_CHECK(len >= static_cast<int>(sizeof(AppSpawnResponseMsg)), ret = -1;
|
||||
break, "Failed to recv msg errno: %{public}d", errno);
|
||||
AppSpawnResponseMsg *respMsg = reinterpret_cast<AppSpawnResponseMsg *>(buffer.data());
|
||||
APPSPAWN_LOGV("Recv msg %{public}s result: %{public}d", respMsg->msgHdr.processName, respMsg->result.result);
|
||||
ret = respMsg->result.result;
|
||||
} while (0);
|
||||
if (socketId >= 0) {
|
||||
CloseClientSocket(socketId);
|
||||
}
|
||||
testServer.Stop();
|
||||
ASSERT_NE(ret, 0);
|
||||
}
|
||||
|
||||
static int RecvMsg(int socketId, uint8_t *buffer, uint32_t buffSize)
|
||||
{
|
||||
ssize_t rLen = TEMP_FAILURE_RETRY(read(socketId, buffer, buffSize));
|
||||
return static_cast<int>(rLen);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Msg_003, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
int socketId = -1;
|
||||
do {
|
||||
socketId = testServer.CreateSocket();
|
||||
APPSPAWN_CHECK(socketId >= 0, break, "Failed to create socket %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
// 消息不完整,断开连接
|
||||
std::vector<uint8_t> buffer(sizeof(AppSpawnResponseMsg));
|
||||
uint32_t msgLen = 0;
|
||||
ret = testServer.CreateSendMsg(buffer, MSG_APP_SPAWN, msgLen, {});
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
|
||||
int len = write(socketId, buffer.data(), msgLen - 10); // 10
|
||||
APPSPAWN_CHECK(len > 0, break, "Failed to send msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
// recv timeout
|
||||
len = RecvMsg(socketId, buffer.data(), buffer.size());
|
||||
APPSPAWN_CHECK(len == 0, ret = -1;
|
||||
break, "Failed to recv msg len: %{public}d", len);
|
||||
} while (0);
|
||||
if (socketId >= 0) {
|
||||
CloseClientSocket(socketId);
|
||||
}
|
||||
testServer.Stop();
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Msg_004, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
int socketId = -1;
|
||||
do {
|
||||
socketId = testServer.CreateSocket();
|
||||
APPSPAWN_CHECK(socketId >= 0, break, "Failed to create socket %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
// 测试异常tlv
|
||||
std::vector<uint8_t> buffer(sizeof(AppSpawnResponseMsg));
|
||||
uint32_t msgLen = 0;
|
||||
ret = testServer.CreateSendMsg(buffer, MSG_APP_SPAWN, msgLen, {});
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
|
||||
int len = write(socketId, buffer.data(), msgLen);
|
||||
APPSPAWN_CHECK(len > 0, break, "Failed to send msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
// recv
|
||||
len = RecvMsg(socketId, buffer.data(), buffer.size());
|
||||
APPSPAWN_CHECK(len >= static_cast<int>(sizeof(AppSpawnResponseMsg)), ret = -1;
|
||||
break, "Failed to recv msg %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnResponseMsg *respMsg = reinterpret_cast<AppSpawnResponseMsg *>(buffer.data());
|
||||
APPSPAWN_LOGV("Recv msg %{public}s result: %{public}d", respMsg->msgHdr.processName, respMsg->result.result);
|
||||
ret = respMsg->result.result;
|
||||
} while (0);
|
||||
if (socketId >= 0) {
|
||||
CloseClientSocket(socketId);
|
||||
}
|
||||
testServer.Stop();
|
||||
ASSERT_NE(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试小包发送,随机获取发送大小,发送数据。消息20时,按33发送
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Msg_005, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
int socketId = -1;
|
||||
do {
|
||||
socketId = testServer.CreateSocket();
|
||||
APPSPAWN_CHECK(socketId >= 0, break, "Failed to create socket %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
// 测试小包发送
|
||||
std::vector<uint8_t> buffer(1024, 0); // 1024 1k
|
||||
uint32_t msgLen = 0;
|
||||
ret = testServer.CreateSendMsg(buffer, MSG_APP_SPAWN, msgLen, {AppSpawnTestHelper::AddBaseTlv});
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
|
||||
// 分片发送
|
||||
uint32_t sendStep = OHOS::AppSpawnTestHelper::GenRandom() % 70; // 70 一次发送的字节数
|
||||
sendStep = (sendStep < 20) ? 33 : sendStep; // 20 33 一次发送的字节数
|
||||
APPSPAWN_LOGV("App_Spawn_Msg_005 msgLen %{public}u sendStep: %{public}u", msgLen, sendStep);
|
||||
uint32_t currIndex = 0;
|
||||
int len = 0;
|
||||
do {
|
||||
if ((currIndex + sendStep) > msgLen) {
|
||||
break;
|
||||
}
|
||||
len = write(socketId, buffer.data() + currIndex, sendStep);
|
||||
APPSPAWN_CHECK(len > 0, break, "Failed to send msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
usleep(2000); // wait recv
|
||||
currIndex += sendStep;
|
||||
} while (1);
|
||||
APPSPAWN_CHECK(len > 0, break, "Failed to send msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
if (msgLen > currIndex) {
|
||||
len = write(socketId, buffer.data() + currIndex, msgLen - currIndex);
|
||||
APPSPAWN_CHECK(len > 0, break, "Failed to send msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
}
|
||||
|
||||
// recv
|
||||
len = RecvMsg(socketId, buffer.data(), buffer.size());
|
||||
APPSPAWN_CHECK(len >= static_cast<int>(sizeof(AppSpawnResponseMsg)), ret = -1;
|
||||
break, "Failed to recv msg %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnResponseMsg *respMsg = reinterpret_cast<AppSpawnResponseMsg *>(buffer.data());
|
||||
APPSPAWN_LOGV("Recv msg %{public}s result: %{public}d", respMsg->msgHdr.processName, respMsg->result.result);
|
||||
ret = respMsg->result.result;
|
||||
} while (0);
|
||||
if (socketId >= 0) {
|
||||
CloseClientSocket(socketId);
|
||||
}
|
||||
testServer.Stop();
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试2个消息一起发送
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Msg_006, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
int socketId = -1;
|
||||
do {
|
||||
socketId = testServer.CreateSocket();
|
||||
APPSPAWN_CHECK(socketId >= 0, break, "Failed to create socket %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
std::vector<uint8_t> buffer1(1024); // 1024
|
||||
std::vector<uint8_t> buffer2(1024); // 1024
|
||||
uint32_t msgLen1 = 0;
|
||||
uint32_t msgLen2 = 0;
|
||||
ret = testServer.CreateSendMsg(buffer1, MSG_APP_SPAWN, msgLen1, {AppSpawnTestHelper::AddBaseTlv});
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
ret = testServer.CreateSendMsg(buffer2, MSG_APP_SPAWN, msgLen2, {AppSpawnTestHelper::AddBaseTlv});
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
|
||||
buffer1.insert(buffer1.begin() + msgLen1, buffer2.begin(), buffer2.end());
|
||||
int len = write(socketId, buffer1.data(), msgLen1 + msgLen2);
|
||||
APPSPAWN_CHECK(len > 0, break, "Failed to send msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
// recv
|
||||
len = RecvMsg(socketId, buffer2.data(), buffer2.size());
|
||||
APPSPAWN_CHECK(len >= static_cast<int>(sizeof(AppSpawnResponseMsg)), ret = -1;
|
||||
break, "Failed to recv msg %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnResponseMsg *respMsg = reinterpret_cast<AppSpawnResponseMsg *>(buffer2.data());
|
||||
APPSPAWN_LOGV("Recv msg %{public}s result: %{public}d", respMsg->msgHdr.processName, respMsg->result.result);
|
||||
ret = respMsg->result.result;
|
||||
(void)RecvMsg(socketId, buffer2.data(), buffer2.size());
|
||||
} while (0);
|
||||
if (socketId >= 0) {
|
||||
CloseClientSocket(socketId);
|
||||
}
|
||||
testServer.Stop();
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试连续2个消息,spawn和dump 消息
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Msg_007, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr, 5000); // 5000 5s
|
||||
int ret = 0;
|
||||
int socketId = -1;
|
||||
do {
|
||||
socketId = testServer.CreateSocket();
|
||||
APPSPAWN_CHECK(socketId >= 0, break, "Failed to create socket %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
std::vector<uint8_t> buffer1(1024); // 1024
|
||||
std::vector<uint8_t> buffer2(1024); // 1024
|
||||
uint32_t msgLen1 = 0;
|
||||
uint32_t msgLen2 = 0;
|
||||
ret = testServer.CreateSendMsg(buffer1, MSG_APP_SPAWN, msgLen1, {AppSpawnTestHelper::AddBaseTlv});
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
ret = testServer.CreateSendMsg(buffer2, MSG_DUMP, msgLen2, {});
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
|
||||
buffer1.insert(buffer1.begin() + msgLen1, buffer2.begin(), buffer2.end());
|
||||
int len = write(socketId, buffer1.data(), msgLen1 + msgLen2);
|
||||
APPSPAWN_CHECK(len > 0, break, "Failed to send msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
// recv
|
||||
len = RecvMsg(socketId, buffer2.data(), buffer2.size());
|
||||
APPSPAWN_CHECK(len >= static_cast<int>(sizeof(AppSpawnResponseMsg)), ret = -1;
|
||||
break, "Failed to recv msg %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnResponseMsg *respMsg = reinterpret_cast<AppSpawnResponseMsg *>(buffer2.data());
|
||||
APPSPAWN_LOGV("App_Spawn_Msg_007 recv msg %{public}s result: %{public}d",
|
||||
respMsg->msgHdr.processName, respMsg->result.result);
|
||||
ret = respMsg->result.result;
|
||||
(void)RecvMsg(socketId, buffer2.data(), buffer2.size());
|
||||
} while (0);
|
||||
if (socketId >= 0) {
|
||||
CloseClientSocket(socketId);
|
||||
}
|
||||
testServer.Stop();
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试连接中断
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Msg_008, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
int socketId = -1;
|
||||
do {
|
||||
socketId = testServer.CreateSocket();
|
||||
APPSPAWN_CHECK(socketId >= 0, break, "Failed to create socket %{public}s", APPSPAWN_SERVER_NAME);
|
||||
std::vector<uint8_t> buffer(1024, 0); // 1024 1k
|
||||
uint32_t msgLen = 0;
|
||||
ret = testServer.CreateSendMsg(buffer, MSG_APP_SPAWN, msgLen, {AppSpawnTestHelper::AddBaseTlv});
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
|
||||
int len = write(socketId, buffer.data(), msgLen);
|
||||
APPSPAWN_CHECK(len > 0, break, "Failed to send msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
// close socket
|
||||
APPSPAWN_LOGV("CloseClientSocket");
|
||||
CloseClientSocket(socketId);
|
||||
socketId = -1;
|
||||
usleep(20000); // 20000 20ms wait conn close
|
||||
} while (0);
|
||||
if (socketId >= 0) {
|
||||
CloseClientSocket(socketId);
|
||||
}
|
||||
testServer.Stop();
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 发送不完整报文,等待超时
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Msg_009, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
int socketId = -1;
|
||||
do {
|
||||
socketId = testServer.CreateSocket();
|
||||
APPSPAWN_CHECK(socketId >= 0, break, "Failed to create socket %{public}s", APPSPAWN_SERVER_NAME);
|
||||
std::vector<uint8_t> buffer(1024, 0); // 1024 1k
|
||||
uint32_t msgLen = 0;
|
||||
ret = testServer.CreateSendMsg(buffer, MSG_APP_SPAWN, msgLen, {AppSpawnTestHelper::AddBaseTlv});
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
int len = write(socketId, buffer.data(), msgLen - 20); // 20 test
|
||||
APPSPAWN_CHECK(len > 0, break, "Failed to send msg %{public}s", testServer.GetDefaultTestAppBundleName());
|
||||
usleep(500000); // 500000 need to wait server timeout
|
||||
// recv
|
||||
len = read(socketId, buffer.data(), buffer.size()); // timeout EAGAIN
|
||||
APPSPAWN_CHECK(len <= 0, ret = -1; break, "Can not receive timeout %{public}d", errno);
|
||||
} while (0);
|
||||
if (socketId >= 0) {
|
||||
CloseClientSocket(socketId);
|
||||
}
|
||||
testServer.Stop();
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Child_001, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
char path[PATH_MAX] = {};
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
|
||||
ServerStageHookExecute(STAGE_SERVER_PRELOAD, content); // 预加载,解析sandbox
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
reqHandle = nullptr;
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
|
||||
// spawn
|
||||
ret = AppSpawnChild(content, &property->client);
|
||||
property = nullptr;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Child_002, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
|
||||
char path[PATH_MAX] = {};
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
|
||||
ServerStageHookExecute(STAGE_SERVER_PRELOAD, content);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
reqHandle = nullptr;
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
// spawn
|
||||
ret = AppSpawnChild(content, &property->client);
|
||||
property = nullptr;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Child_003, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
|
||||
g_testHelper.SetTestUid(10010029); // 10010029
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
|
||||
char path[PATH_MAX] = {};
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
|
||||
ServerStageHookExecute(STAGE_SERVER_PRELOAD, content);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
reqHandle = nullptr;
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
// spawn
|
||||
ret = AppSpawnChild(content, &property->client);
|
||||
property = nullptr;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Child_004, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
// MSG_SPAWN_NATIVE_PROCESS and no render cmd
|
||||
g_testHelper.SetTestUid(10010029); // 10010029
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_SPAWN_NATIVE_PROCESS, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_GWP_ENABLED_NORMAL);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
reqHandle = nullptr;
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
char path[PATH_MAX] = {};
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ServerStageHookExecute(STAGE_SERVER_PRELOAD, content);
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
// spawn
|
||||
ret = AppSpawnChild(content, &property->client);
|
||||
property = nullptr;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Child_005, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
// MSG_SPAWN_NATIVE_PROCESS and render
|
||||
g_testHelper.SetTestUid(10010029); // 10010029
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_SPAWN_NATIVE_PROCESS, 0);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_GWP_ENABLED_NORMAL);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
reqHandle = nullptr;
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
char path[PATH_MAX] = {};
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ServerStageHookExecute(STAGE_SERVER_PRELOAD, content);
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
// spawn
|
||||
ret = AppSpawnChild(content, &property->client);
|
||||
property = nullptr;
|
||||
ASSERT_EQ(ret, 0);
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_Child_006, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME);
|
||||
// MSG_SPAWN_NATIVE_PROCESS and no render cmd
|
||||
g_testHelper.SetTestUid(10010029); // 10010029
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_SPAWN_NATIVE_PROCESS, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req %{public}s", APPSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
const char *appEnv = "{\"test.name1\": \"test.value1\", \"test.name2\": \"test.value2\"}";
|
||||
ret = AppSpawnReqMsgAddExtInfo(reqHandle, "AppEnv",
|
||||
reinterpret_cast<uint8_t *>(const_cast<char *>(appEnv)), strlen(appEnv) + 1);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add ext tlv %{public}s", appEnv);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
reqHandle = nullptr;
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
char path[PATH_MAX] = {};
|
||||
content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
ServerStageHookExecute(STAGE_SERVER_PRELOAD, content);
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
// spawn
|
||||
ret = AppSpawnChild(content, &property->client);
|
||||
property = nullptr;
|
||||
ASSERT_EQ(ret, 0);
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 必须最后一个,kill nwebspawn,appspawn的线程结束
|
||||
*
|
||||
*/
|
||||
HWTEST(AppSpawnServiceTest, App_Spawn_NWebSpawn_001, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode appspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
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_APP_SPAWN, 0);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to send msg %{public}d", ret);
|
||||
// kill nwebspawn
|
||||
APPSPAWN_LOGV("App_Spawn_NWebSpawn_001 Kill nwebspawn");
|
||||
usleep(20000); // 20000 20ms
|
||||
testServer.KillNWebSpawnServer();
|
||||
usleep(20000); // 20000 20ms
|
||||
} while (0);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
testServer.Stop();
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
} // namespace OHOS
|
@ -0,0 +1,333 @@
|
||||
/*
|
||||
* 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 <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "appspawn_client.h"
|
||||
#include "appspawn_modulemgr.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "json_utils.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
#include "app_spawn_stub.h"
|
||||
#include "app_spawn_test_helper.h"
|
||||
|
||||
using namespace testing;
|
||||
using namespace testing::ext;
|
||||
using namespace OHOS;
|
||||
|
||||
namespace OHOS {
|
||||
static AppSpawnTestHelper g_testHelper;
|
||||
using AddTlvFunction = std::function<int(uint8_t *buffer, uint32_t bufferLen, uint32_t &realLen, uint32_t &tlvCount)>;
|
||||
class NWebSpawnServiceTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase() {}
|
||||
static void TearDownTestCase() {}
|
||||
void SetUp() {}
|
||||
void TearDown() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 基本流程测试,启动nwebspawn 处理
|
||||
*
|
||||
*/
|
||||
HWTEST(NWebSpawnServiceTest, NWeb_Spawn_001, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode nwebspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(NWEBSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create client %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgHandle reqHandle = testServer.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_LOGV("NWeb_Spawn_001 recv result %{public}d", ret);
|
||||
if (ret != 0 || result.pid == 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
// stop child and termination
|
||||
APPSPAWN_LOGI("NWeb_Spawn_001 Kill pid %{public}d ", result.pid);
|
||||
kill(result.pid, SIGKILL);
|
||||
|
||||
usleep(2000); // wait,to get exit status
|
||||
// MSG_GET_RENDER_TERMINATION_STATUS
|
||||
AppSpawnReqMsgHandle reqHandle2 = nullptr;
|
||||
ret = AppSpawnTerminateMsgCreate(result.pid, &reqHandle2);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create req %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle2, &result);
|
||||
APPSPAWN_LOGV("Send MSG_GET_RENDER_TERMINATION_STATUS %{public}d", ret);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(NWebSpawnServiceTest, NWeb_Spawn_002, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode nwebspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
do {
|
||||
// 发送消息到nweb spawn
|
||||
ret = AppSpawnClientInit(NWEBSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create client %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
AppSpawnReqMsgHandle reqHandle = testServer.CreateMsg(clientHandle, MSG_APP_SPAWN, 0);
|
||||
AppSpawnResult result = {};
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_LOGV("NWeb_Spawn_002 recv result %{public}d %{public}d", ret, result.pid);
|
||||
if (ret != 0 || result.pid == 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
// MSG_GET_RENDER_TERMINATION_STATUS
|
||||
AppSpawnReqMsgHandle reqHandle2 = nullptr;
|
||||
ret = AppSpawnTerminateMsgCreate(result.pid, &reqHandle2);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to set pid %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle2, &result);
|
||||
APPSPAWN_LOGV("Send MSG_GET_RENDER_TERMINATION_STATUS %{public}d", ret);
|
||||
ret = 0; // ut can not get result
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(NWebSpawnServiceTest, NWeb_Spawn_004, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode nwebspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(NWEBSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create client %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
// MSG_DUMP
|
||||
AppSpawnResult result = {};
|
||||
AppSpawnReqMsgHandle reqHandle = testServer.CreateMsg(clientHandle, MSG_DUMP, 0);
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_LOGV("Send MSG_DUMP %{public}d", ret);
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(NWebSpawnServiceTest, NWeb_Spawn_005, TestSize.Level0)
|
||||
{
|
||||
OHOS::AppSpawnTestServer testServer("appspawn -mode nwebspawn");
|
||||
testServer.Start(nullptr);
|
||||
int ret = 0;
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
do {
|
||||
ret = AppSpawnClientInit(NWEBSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create client %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
// MAX_TYPE_INVALID
|
||||
AppSpawnResult result = {};
|
||||
AppSpawnReqMsgHandle reqHandle = testServer.CreateMsg(clientHandle, MAX_TYPE_INVALID, 0);
|
||||
ret = AppSpawnClientSendMsg(clientHandle, reqHandle, &result);
|
||||
APPSPAWN_LOGV("Send MAX_TYPE_INVALID %{public}d", ret);
|
||||
} while (0);
|
||||
testServer.Stop();
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
ASSERT_NE(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(NWebSpawnServiceTest, NWeb_Spawn_Child_001, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(NWEBSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req ");
|
||||
char path[PATH_MAX] = {};
|
||||
content = AppSpawnCreateContent(NWEBSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_NWEB_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
|
||||
ServerStageHookExecute(STAGE_SERVER_PRELOAD, content); // 预加载,解析sandbox
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
|
||||
// spawn
|
||||
ret = AppSpawnChild(content, &property->client);
|
||||
property = nullptr;
|
||||
content = nullptr;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
AppSpawnDestroyContent(content);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(NWebSpawnServiceTest, NWeb_Spawn_Child_002, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(NWEBSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req");
|
||||
char path[PATH_MAX] = {};
|
||||
content = AppSpawnCreateContent(NWEBSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_NWEB_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
|
||||
ServerStageHookExecute(STAGE_SERVER_PRELOAD, content); // 预加载,解析sandbox
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ASANENABLED);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_GWP_ENABLED_NORMAL);
|
||||
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
|
||||
// spawn
|
||||
ret = AppSpawnChild(content, &property->client);
|
||||
property = nullptr;
|
||||
content = nullptr;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
AppSpawnDestroyContent(content);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(NWebSpawnServiceTest, NWeb_Spawn_Child_004, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(NWEBSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
// MSG_SPAWN_NATIVE_PROCESS and no render cmd
|
||||
g_testHelper.SetTestUid(10010029); // 10010029
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_SPAWN_NATIVE_PROCESS, 1);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req");
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_GWP_ENABLED_NORMAL);
|
||||
|
||||
char path[PATH_MAX] = {};
|
||||
content = AppSpawnCreateContent(NWEBSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_NWEB_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
|
||||
ServerStageHookExecute(STAGE_SERVER_PRELOAD, content);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
// spawn
|
||||
ret = AppSpawnChild(content, &property->client);
|
||||
property = nullptr;
|
||||
content = nullptr;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
AppSpawnDestroyContent(content);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
|
||||
HWTEST(NWebSpawnServiceTest, NWeb_Spawn_Child_005, TestSize.Level0)
|
||||
{
|
||||
AppSpawnClientHandle clientHandle = nullptr;
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
AppSpawningCtx *property = nullptr;
|
||||
AppSpawnContent *content = nullptr;
|
||||
int ret = -1;
|
||||
do {
|
||||
ret = AppSpawnClientInit(NWEBSPAWN_SERVER_NAME, &clientHandle);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", NWEBSPAWN_SERVER_NAME);
|
||||
// MSG_SPAWN_NATIVE_PROCESS and render
|
||||
g_testHelper.SetTestUid(10010029); // 10010029
|
||||
reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_SPAWN_NATIVE_PROCESS, 0);
|
||||
APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, "Failed to create req");
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_DEBUGGABLE);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_NATIVEDEBUG);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_BUNDLE_RESOURCES);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_ACCESS_BUNDLE_DIR);
|
||||
AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_GWP_ENABLED_NORMAL);
|
||||
|
||||
char path[PATH_MAX] = {};
|
||||
content = AppSpawnCreateContent(NWEBSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_NWEB_SPAWN);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
|
||||
|
||||
ServerStageHookExecute(STAGE_SERVER_PRELOAD, content);
|
||||
|
||||
ret = APPSPAWN_ARG_INVALID;
|
||||
property = g_testHelper.GetAppProperty(clientHandle, reqHandle);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break);
|
||||
|
||||
// spawn prepare process
|
||||
AppSpawnHookExecute(STAGE_PARENT_PRE_FORK, 0, content, &property->client);
|
||||
// spawn
|
||||
ret = AppSpawnChild(content, &property->client);
|
||||
property = nullptr;
|
||||
content = nullptr;
|
||||
} while (0);
|
||||
DeleteAppSpawningCtx(property);
|
||||
AppSpawnClientDestroy(clientHandle);
|
||||
AppSpawnDestroyContent(content);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
} // namespace OHOS
|
659
test/unittest/app_spawn_test_helper.cpp
Normal file
659
test/unittest/app_spawn_test_helper.cpp
Normal file
@ -0,0 +1,659 @@
|
||||
/*
|
||||
* 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 "app_spawn_test_helper.h"
|
||||
|
||||
#include <csignal>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "appspawn.h"
|
||||
#include "appspawn_client.h"
|
||||
#include "appspawn_modulemgr.h"
|
||||
#include "appspawn_msg.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "appspawn_service.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "loop_event.h"
|
||||
#include "parameters.h"
|
||||
#include "securec.h"
|
||||
|
||||
#include "app_spawn_stub.h"
|
||||
|
||||
namespace OHOS {
|
||||
typedef struct {
|
||||
int32_t bundleIndex;
|
||||
char bundleName[APP_LEN_BUNDLE_NAME]; // process name
|
||||
} AppBundleInfo;
|
||||
|
||||
uint32_t AppSpawnTestServer::serverId = 0;
|
||||
AppSpawnTestServer::~AppSpawnTestServer()
|
||||
{
|
||||
if (localServer_) {
|
||||
delete localServer_;
|
||||
localServer_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AppSpawnTestServer::CloseCheckHandler(void)
|
||||
{
|
||||
APPSPAWN_LOGV("CloseCheckHandler");
|
||||
#ifdef USER_TIMER_TO_CHECK
|
||||
if (timer_ != nullptr) {
|
||||
LE_StopTimer(LE_GetDefaultLoop(), timer_);
|
||||
timer_ = nullptr;
|
||||
}
|
||||
#else
|
||||
if (idle_) {
|
||||
LE_DelIdle(idle_);
|
||||
idle_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppSpawnTestServer::StartCheckHandler(void)
|
||||
{
|
||||
#ifdef USER_TIMER_TO_CHECK
|
||||
int ret = LE_CreateTimer(LE_GetDefaultLoop(), &timer_, ProcessIdle, this);
|
||||
if (ret == 0) {
|
||||
ret = LE_StartTimer(LE_GetDefaultLoop(), timer_, 100, 10000000); // 100 10000000 repeat
|
||||
}
|
||||
#else
|
||||
LE_AddIdle(LE_GetDefaultLoop(), &idle_, ProcessIdle, this, 10000000); // 10000000 repeat
|
||||
#endif
|
||||
}
|
||||
|
||||
void *AppSpawnTestServer::ServiceThread(void *arg)
|
||||
{
|
||||
CmdArgs *args = nullptr;
|
||||
pid_t pid = getpid();
|
||||
AppSpawnTestServer *server = reinterpret_cast<AppSpawnTestServer *>(arg);
|
||||
APPSPAWN_LOGV("serviceCmd_ %{public}s", server->serviceCmd_.c_str());
|
||||
|
||||
// 测试server时,使用appspawn的server
|
||||
if (server->testServer_) {
|
||||
server->content_ = AppSpawnTestHelper::StartSpawnServer(server->serviceCmd_, args);
|
||||
if (server->content_ == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (pid == getpid()) { // 主进程进行处理
|
||||
APPSPAWN_LOGV("Service start timer %{public}s ", server->serviceCmd_.c_str());
|
||||
server->StartCheckHandler();
|
||||
AppSpawnMgr *content = reinterpret_cast<AppSpawnMgr *>(server->content_);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return nullptr);
|
||||
AppSpawnedProcess *info = GetSpawnedProcessByName(NWEBSPAWN_SERVER_NAME);
|
||||
if (info != NULL) {
|
||||
APPSPAWN_LOGV("Save nwebspawn pid: %{public}d %{public}d", info->pid, server->serverId_);
|
||||
server->appPid_.store(info->pid);
|
||||
}
|
||||
}
|
||||
server->content_->runAppSpawn(server->content_, args->argc, args->argv);
|
||||
if (pid != getpid()) { // 子进程退出
|
||||
exit(0);
|
||||
} else {
|
||||
server->content_ = nullptr;
|
||||
}
|
||||
} else {
|
||||
server->StartCheckHandler();
|
||||
server->localServer_ = new LocalTestServer();
|
||||
server->localServer_->Run(APPSPAWN_SOCKET_NAME, server->recvMsgProcess_);
|
||||
}
|
||||
APPSPAWN_LOGV("Service thread finish %{public}s ", server->serviceCmd_.c_str());
|
||||
if (args) {
|
||||
free(args);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AppSpawnTestServer::Start(void)
|
||||
{
|
||||
Start(nullptr);
|
||||
}
|
||||
|
||||
void AppSpawnTestServer::Start(RecvMsgProcess process, uint32_t time)
|
||||
{
|
||||
protectTime_ = time;
|
||||
if (threadId_ == 0) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &startTime_);
|
||||
recvMsgProcess_ = process;
|
||||
int ret = pthread_create(&threadId_, nullptr, ServiceThread, static_cast<void *>(this));
|
||||
if (ret != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppSpawnTestServer::Stop()
|
||||
{
|
||||
APPSPAWN_LOGV("AppSpawnTestServer::Stop");
|
||||
if (threadId_ != 0) {
|
||||
stop_ = true;
|
||||
pthread_join(threadId_, nullptr);
|
||||
threadId_ = 0;
|
||||
APPSPAWN_LOGV("Stop");
|
||||
}
|
||||
}
|
||||
|
||||
void AppSpawnTestServer::KillNWebSpawnServer()
|
||||
{
|
||||
APPSPAWN_LOGV("Kill nwebspawn %{public}d", serverId_);
|
||||
if (appPid_ > 0) {
|
||||
kill(appPid_, SIGKILL);
|
||||
}
|
||||
}
|
||||
|
||||
void AppSpawnTestServer::StopSpawnService(void)
|
||||
{
|
||||
APPSPAWN_LOGV("StopSpawnService ");
|
||||
if (serverStoped) {
|
||||
CloseCheckHandler();
|
||||
}
|
||||
serverStoped = true;
|
||||
if (testServer_) {
|
||||
struct signalfd_siginfo siginfo = {};
|
||||
siginfo.ssi_signo = SIGTERM;
|
||||
siginfo.ssi_uid = 0;
|
||||
ProcessSignal(&siginfo);
|
||||
} else {
|
||||
localServer_->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USER_TIMER_TO_CHECK
|
||||
void AppSpawnTestServer::ProcessIdle(const TimerHandle taskHandle, void *context)
|
||||
#else
|
||||
void AppSpawnTestServer::ProcessIdle(const IdleHandle taskHandle, void *context)
|
||||
#endif
|
||||
{
|
||||
APPSPAWN_LOGV("AppSpawnTestServer::ProcessIdle");
|
||||
AppSpawnTestServer *server = reinterpret_cast<AppSpawnTestServer *>(const_cast<void *>(context));
|
||||
if (server->stop_) {
|
||||
server->StopSpawnService();
|
||||
return;
|
||||
}
|
||||
|
||||
struct timespec end;
|
||||
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
uint64_t diff = DiffTime(&server->startTime_, &end);
|
||||
if (diff >= (server->protectTime_ * 1000)) { // 1000 ms -> us
|
||||
APPSPAWN_LOGV("AppSpawnTestServer:: timeout %{public}u %{public}llu", server->protectTime_, diff);
|
||||
server->StopSpawnService();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int LocalTestServer::OnConnection(const LoopHandle loopHandle, const TaskHandle server)
|
||||
{
|
||||
static uint32_t connectionId = 0;
|
||||
TaskHandle stream;
|
||||
LE_StreamInfo info = {};
|
||||
info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_CONNECT;
|
||||
info.baseInfo.close = OnClose;
|
||||
info.baseInfo.userDataSize = sizeof(TestConnection);
|
||||
info.disConnectComplete = nullptr;
|
||||
info.sendMessageComplete = SendMessageComplete;
|
||||
info.recvMessage = OnReceiveRequest;
|
||||
|
||||
ServerInfo *serverInfo = (ServerInfo *)LE_GetUserData(server);
|
||||
APPSPAWN_CHECK(serverInfo != nullptr, return -1, "Failed to alloc stream");
|
||||
|
||||
LE_STATUS ret = LE_AcceptStreamClient(loopHandle, server, &stream, &info);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to alloc stream");
|
||||
TestConnection *connection = (TestConnection *)LE_GetUserData(stream);
|
||||
APPSPAWN_CHECK(connection != nullptr, return -1, "Failed to alloc stream");
|
||||
connection->connectionId = ++connectionId;
|
||||
connection->stream = stream;
|
||||
connection->msgRecvLen = 0;
|
||||
(void)memset_s(&connection->msg, sizeof(connection->msg), 0, sizeof(connection->msg));
|
||||
connection->buffer = nullptr;
|
||||
connection->recvMsgProcess = serverInfo->recvMsgProcess;
|
||||
APPSPAWN_LOGI("OnConnection connection.id %{public}d fd %{public}d ",
|
||||
connection->connectionId, LE_GetSocketFd(stream));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LocalTestServer::SendMessageComplete(const TaskHandle taskHandle, BufferHandle handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void LocalTestServer::OnClose(const TaskHandle taskHandle)
|
||||
{
|
||||
TestConnection *connection = (TestConnection *)LE_GetUserData(taskHandle);
|
||||
APPSPAWN_CHECK(connection != nullptr, return, "Invalid connection");
|
||||
APPSPAWN_LOGI("OnClose connection.id %{public}d socket %{public}d",
|
||||
connection->connectionId, LE_GetSocketFd(taskHandle));
|
||||
}
|
||||
|
||||
void LocalTestServer::OnReceiveRequest(const TaskHandle taskHandle, const uint8_t *buffer, uint32_t buffLen)
|
||||
{
|
||||
TestConnection *connection = (TestConnection *)LE_GetUserData(taskHandle);
|
||||
APPSPAWN_CHECK(connection != nullptr, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
|
||||
return, "Failed to get client form socket");
|
||||
|
||||
if (connection->recvMsgProcess) {
|
||||
connection->recvMsgProcess(connection, buffer, buffLen);
|
||||
}
|
||||
}
|
||||
|
||||
int LocalTestServer::Run(const char *socketName, RecvMsgProcess recvMsg)
|
||||
{
|
||||
char path[128] = {0}; // 128 max path
|
||||
int ret = snprintf_s(path, sizeof(path), sizeof(path) - 1, "%s%s", APPSPAWN_SOCKET_DIR, socketName);
|
||||
APPSPAWN_CHECK(ret >= 0, return -1, "Failed to snprintf_s %{public}d", ret);
|
||||
LE_StreamServerInfo info = {};
|
||||
info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_SERVER;
|
||||
info.baseInfo.userDataSize = sizeof(ServerInfo);
|
||||
info.socketId = -1;
|
||||
info.server = path;
|
||||
info.baseInfo.close = nullptr;
|
||||
info.incommingConnect = OnConnection;
|
||||
|
||||
MakeDirRec(path, 0711, 0); // 0711 default mask
|
||||
ret = LE_CreateStreamServer(LE_GetDefaultLoop(), &serverHandle_, &info);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to create socket for %{public}s errno: %{public}d", path, errno);
|
||||
APPSPAWN_LOGI("LocalTestServer path %{public}s fd %{public}d", path, LE_GetSocketFd(serverHandle_));
|
||||
|
||||
ServerInfo *serverInfo = (ServerInfo *)LE_GetUserData(serverHandle_);
|
||||
APPSPAWN_CHECK(serverInfo != nullptr, return -1, "Failed to alloc stream");
|
||||
serverInfo->local = this;
|
||||
serverInfo->recvMsgProcess = recvMsg;
|
||||
LE_RunLoop(LE_GetDefaultLoop());
|
||||
LE_CloseStreamTask(LE_GetDefaultLoop(), serverHandle_);
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
APPSPAWN_LOGI("LocalTestServer exit");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LocalTestServer::Stop()
|
||||
{
|
||||
APPSPAWN_LOGI("Stop LocalTestServer ");
|
||||
LE_StopLoop(LE_GetDefaultLoop());
|
||||
}
|
||||
|
||||
int TestConnection::SendResponse(const AppSpawnMsg *msg, int result, pid_t pid)
|
||||
{
|
||||
APPSPAWN_LOGV("SendResponse result: %{public}d pid: %{public}d", result, pid);
|
||||
uint32_t bufferSize = sizeof(AppSpawnResponseMsg);
|
||||
BufferHandle handle = LE_CreateBuffer(LE_GetDefaultLoop(), bufferSize);
|
||||
AppSpawnResponseMsg *buffer = (AppSpawnResponseMsg *)LE_GetBufferInfo(handle, nullptr, &bufferSize);
|
||||
int ret = memcpy_s(buffer, bufferSize, msg, sizeof(AppSpawnMsg));
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to memcpy_s bufferSize");
|
||||
buffer->result.result = result;
|
||||
buffer->result.pid = pid;
|
||||
return LE_Send(LE_GetDefaultLoop(), stream, handle, bufferSize);
|
||||
}
|
||||
|
||||
uint32_t AppSpawnTestHelper::GenRandom(void)
|
||||
{
|
||||
uint32_t random = 0;
|
||||
int fd = open("/dev/random", O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
read(fd, &random, sizeof(random));
|
||||
close(fd);
|
||||
}
|
||||
return random;
|
||||
}
|
||||
|
||||
CmdArgs *AppSpawnTestHelper::ToCmdList(const char *cmd)
|
||||
{
|
||||
const uint32_t maxArgc = 10;
|
||||
const uint32_t length = sizeof(CmdArgs) + maxArgc * sizeof(char *) + strlen(cmd) + APP_LEN_PROC_NAME + 1 + 2;
|
||||
char *buffer = static_cast<char *>(malloc(length));
|
||||
CmdArgs *args = reinterpret_cast<CmdArgs *>(buffer);
|
||||
APPSPAWN_CHECK(buffer != nullptr, return nullptr, "Failed to alloc args");
|
||||
(void)memset_s(args, length, 0, length);
|
||||
char *start = buffer + sizeof(CmdArgs) + maxArgc * sizeof(char *);
|
||||
char *end = buffer + length;
|
||||
uint32_t index = 0;
|
||||
char *curr = const_cast<char *>(cmd);
|
||||
while (isspace(*curr)) {
|
||||
curr++;
|
||||
}
|
||||
|
||||
while (index < (maxArgc - 1) && *curr != '\0') {
|
||||
if (args->argv[index] == nullptr) {
|
||||
args->argv[index] = start;
|
||||
}
|
||||
*start = *curr;
|
||||
if (isspace(*curr)) {
|
||||
*start = '\0';
|
||||
// 为SetProcessName 预留空间
|
||||
start = (index == 0) ? start + APP_LEN_PROC_NAME : start + 1;
|
||||
while (isspace(*curr) && *curr != '\0') {
|
||||
curr++;
|
||||
}
|
||||
if (*curr != '\0') {
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
start++;
|
||||
curr++;
|
||||
}
|
||||
}
|
||||
|
||||
index++;
|
||||
args->argv[index] = end - 2; // 2 last
|
||||
args->argv[index][0] = '#';
|
||||
args->argv[index][1] = '\0';
|
||||
args->argc = index + 1;
|
||||
return args;
|
||||
}
|
||||
|
||||
AppSpawnReqMsgHandle AppSpawnTestHelper::CreateMsg(AppSpawnClientHandle handle, uint32_t msgType, int base)
|
||||
{
|
||||
AppSpawnReqMsgHandle reqHandle = 0;
|
||||
int ret = AppSpawnReqMsgCreate(static_cast<AppSpawnMsgType>(msgType), processName_.c_str(), &reqHandle);
|
||||
APPSPAWN_CHECK(ret == 0, return INVALID_REQ_HANDLE, "Failed to create req %{public}s", processName_.c_str());
|
||||
APPSPAWN_CHECK_ONLY_EXPER(msgType == MSG_APP_SPAWN || msgType == MSG_SPAWN_NATIVE_PROCESS, return reqHandle);
|
||||
do {
|
||||
ret = AppSpawnReqMsgSetBundleInfo(reqHandle, 100, processName_.c_str()); // 100 test index
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add bundle info req %{public}s", processName_.c_str());
|
||||
|
||||
AppDacInfo dacInfo = {};
|
||||
dacInfo.uid = defaultTestUid_;
|
||||
dacInfo.gid = defaultTestGid_;
|
||||
dacInfo.gidCount = 2; // 2 count
|
||||
dacInfo.gidTable[0] = defaultTestGidGroup_;
|
||||
dacInfo.gidTable[1] = defaultTestGidGroup_ + 1;
|
||||
(void)strcpy_s(dacInfo.userName, sizeof(dacInfo.userName), "test-app-name");
|
||||
ret = AppSpawnReqMsgSetAppDacInfo(reqHandle, &dacInfo);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add dac %{public}s", processName_.c_str());
|
||||
|
||||
ret = AppSpawnReqMsgSetAppAccessToken(reqHandle, 12345678); // 12345678
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to add access token %{public}s", processName_.c_str());
|
||||
|
||||
if (base) {
|
||||
return reqHandle;
|
||||
}
|
||||
const char *testData = "ssssssssssssss sssssssss ssssssss";
|
||||
ret = AppSpawnReqMsgAddExtInfo(reqHandle, "tlv-name-1",
|
||||
reinterpret_cast<uint8_t *>(const_cast<char *>(testData)), strlen(testData));
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to ext tlv %{public}s", processName_.c_str());
|
||||
size_t count = permissions_.size();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
ret = AppSpawnReqMsgAddPermission(reqHandle, permissions_[i]);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to permission %{public}s", permissions_[i]);
|
||||
}
|
||||
|
||||
ret = AppSpawnReqMsgSetAppInternetPermissionInfo(reqHandle, 1, 0);
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to internet info %{public}s", processName_.c_str());
|
||||
|
||||
ret = AppSpawnReqMsgSetAppOwnerId(reqHandle, "ohos.permission.FILE_ACCESS_MANAGER");
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to ownerid %{public}s", processName_.c_str());
|
||||
const char *renderCmd = "/system/bin/sh ls -l ";
|
||||
ret = AppSpawnReqMsgAddExtInfo(reqHandle, MSG_EXT_NAME_RENDER_CMD,
|
||||
reinterpret_cast<const uint8_t *>(renderCmd), strlen(renderCmd));
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to render cmd %{public}s", processName_.c_str());
|
||||
ret = AppSpawnReqMsgSetAppDomainInfo(reqHandle, 1, "system_core");
|
||||
APPSPAWN_CHECK(ret == 0, break, "Failed to domain info %{public}s", processName_.c_str());
|
||||
return reqHandle;
|
||||
} while (0);
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
return INVALID_REQ_HANDLE;
|
||||
}
|
||||
|
||||
AppSpawnMsgNode *AppSpawnTestHelper::CreateAppSpawnMsg(AppSpawnMsg *msg)
|
||||
{
|
||||
AppSpawnMsgNode *msgNode = static_cast<AppSpawnMsgNode *>(calloc(1, sizeof(AppSpawnMsgNode)));
|
||||
APPSPAWN_CHECK(msgNode != NULL, return NULL, "Failed to create receiver");
|
||||
int ret = memcpy_s(&msgNode->msgHeader, sizeof(msgNode->msgHeader), msg, sizeof(msgNode->msgHeader));
|
||||
APPSPAWN_CHECK(ret == 0, free(msgNode);
|
||||
return nullptr, "Failed to memcpy msg");
|
||||
msgNode->buffer = static_cast<uint8_t *>(malloc(msg->msgLen));
|
||||
APPSPAWN_CHECK(msgNode->buffer != NULL, free(msgNode);
|
||||
return nullptr, "Failed to memcpy msg");
|
||||
uint32_t totalCount = msg->tlvCount + TLV_MAX;
|
||||
msgNode->tlvOffset = static_cast<uint32_t *>(malloc(totalCount * sizeof(uint32_t)));
|
||||
APPSPAWN_CHECK(msgNode->tlvOffset != NULL, free(msgNode);
|
||||
return nullptr, "Failed to alloc memory for recv message");
|
||||
for (uint32_t i = 0; i < totalCount; i++) {
|
||||
msgNode->tlvOffset[i] = INVALID_OFFSET;
|
||||
}
|
||||
return msgNode;
|
||||
}
|
||||
|
||||
AppSpawningCtx *AppSpawnTestHelper::GetAppProperty(AppSpawnClientHandle handle, AppSpawnReqMsgHandle reqHandle)
|
||||
{
|
||||
AppSpawnReqMsgNode *reqNode = static_cast<AppSpawnReqMsgNode *>(reqHandle);
|
||||
APPSPAWN_CHECK(reqNode != nullptr && reqNode->msg != nullptr, AppSpawnReqMsgFree(reqHandle);
|
||||
return nullptr, "Invalid reqNode");
|
||||
|
||||
AppSpawnMsgNode *msgNode = CreateAppSpawnMsg(reqNode->msg);
|
||||
APPSPAWN_CHECK(msgNode != nullptr, return nullptr, "Failed to alloc for msg");
|
||||
|
||||
uint32_t bufferSize = reqNode->msg->msgLen;
|
||||
uint32_t currIndex = 0;
|
||||
uint32_t bufferStart = sizeof(AppSpawnMsg);
|
||||
ListNode *node = reqNode->msgBlocks.next;
|
||||
while (node != &reqNode->msgBlocks) {
|
||||
AppSpawnMsgBlock *block = ListEntry(node, AppSpawnMsgBlock, node);
|
||||
int ret = memcpy_s(msgNode->buffer + currIndex, bufferSize - currIndex,
|
||||
block->buffer + bufferStart, block->currentIndex - bufferStart);
|
||||
if (ret != 0) {
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
DeleteAppSpawnMsg(msgNode);
|
||||
return nullptr;
|
||||
}
|
||||
currIndex += block->currentIndex - bufferStart;
|
||||
bufferStart = 0;
|
||||
node = node->next;
|
||||
}
|
||||
APPSPAWN_LOGV("GetAppProperty header magic 0x%{public}x type %{public}u id %{public}u len %{public}u %{public}s",
|
||||
msgNode->msgHeader.magic, msgNode->msgHeader.msgType,
|
||||
msgNode->msgHeader.msgId, msgNode->msgHeader.msgLen, msgNode->msgHeader.processName);
|
||||
|
||||
// delete reqHandle
|
||||
AppSpawnReqMsgFree(reqHandle);
|
||||
int ret = DecodeAppSpawnMsg(msgNode);
|
||||
APPSPAWN_CHECK(ret == 0, DeleteAppSpawnMsg(msgNode);
|
||||
return nullptr, "Decode msg fail");
|
||||
AppSpawningCtx *property = CreateAppSpawningCtx();
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, DeleteAppSpawnMsg(msgNode);
|
||||
return nullptr);
|
||||
property->message = msgNode;
|
||||
return property;
|
||||
}
|
||||
|
||||
void AppSpawnTestHelper::SetDefaultTestData()
|
||||
{
|
||||
processName_ = std::string("com.example.myapplication");
|
||||
defaultTestUid_ = 20010029; // 20010029 test
|
||||
defaultTestGid_ = 20010029; // 20010029 test
|
||||
defaultTestGidGroup_ = 20010029; // 20010029 test
|
||||
defaultTestBundleIndex_ = 100; // 100 test
|
||||
}
|
||||
|
||||
int AppSpawnTestHelper::CreateSocket(void)
|
||||
{
|
||||
const uint32_t maxCount = 10;
|
||||
uint32_t count = 0;
|
||||
int socketId = -1;
|
||||
while ((socketId < 0) && (count < maxCount)) {
|
||||
usleep(20000); // 20000 20ms
|
||||
socketId = CreateClientSocket(0, 2); // 2s
|
||||
if (socketId > 0) {
|
||||
return socketId;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return socketId;
|
||||
}
|
||||
|
||||
int AppSpawnTestHelper::CreateSendMsg(std::vector<uint8_t> &buffer, uint32_t msgType, uint32_t &msgLen,
|
||||
const std::vector<AddTlvFunction> &addTlvFuncs)
|
||||
{
|
||||
if (buffer.size() < sizeof(AppSpawnMsg)) {
|
||||
return -1;
|
||||
}
|
||||
AppSpawnMsg *msg = reinterpret_cast<AppSpawnMsg *>(buffer.data());
|
||||
msg->magic = APPSPAWN_MSG_MAGIC;
|
||||
msg->msgType = msgType;
|
||||
msg->msgLen = sizeof(AppSpawnMsg);
|
||||
msg->msgId = 1;
|
||||
msg->tlvCount = 0;
|
||||
(void)strcpy_s(msg->processName, sizeof(msg->processName), processName_.c_str());
|
||||
// add tlv
|
||||
uint32_t currLen = sizeof(AppSpawnMsg);
|
||||
for (auto addTlvFunc : addTlvFuncs) {
|
||||
uint32_t realLen = 0;
|
||||
uint32_t tlvCount = 0;
|
||||
int ret = addTlvFunc(buffer.data() + currLen, buffer.size() - currLen, realLen, tlvCount);
|
||||
APPSPAWN_CHECK(ret == 0 && (currLen + realLen) < buffer.size(),
|
||||
return -1, "Failed add tlv to msg %{public}s", processName_.c_str());
|
||||
msg->msgLen += realLen;
|
||||
currLen += realLen;
|
||||
msg->tlvCount += tlvCount;
|
||||
}
|
||||
msgLen = msg->msgLen;
|
||||
APPSPAWN_LOGV("CreateSendMsg msgLen %{public}d", msgLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int inline AddOneTlv(uint8_t *buffer, uint32_t bufferLen, const AppSpawnTlv &tlv, const uint8_t *data)
|
||||
{
|
||||
if (tlv.tlvLen > bufferLen) {
|
||||
return -1;
|
||||
}
|
||||
int ret = memcpy_s(buffer, bufferLen, &tlv, sizeof(tlv));
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to memcpy_s bufferSize");
|
||||
ret = memcpy_s(buffer + sizeof(tlv), bufferLen - sizeof(tlv), data, tlv.tlvLen - sizeof(tlv));
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to memcpy_s bufferSize");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AppSpawnTestHelper::AddBaseTlv(uint8_t *buffer, uint32_t bufferLen, uint32_t &realLen, uint32_t &tlvCount)
|
||||
{
|
||||
// add app flage
|
||||
uint32_t currLen = 0;
|
||||
uint32_t flags[2] = {1, 0};
|
||||
AppSpawnTlv tlv = {};
|
||||
tlv.tlvType = TLV_MSG_FLAGS;
|
||||
tlv.tlvLen = sizeof(AppSpawnTlv) + sizeof(flags);
|
||||
int ret = AddOneTlv(buffer + currLen, bufferLen - currLen, tlv, (uint8_t *)flags);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed add tlv %{public}u", tlv.tlvType);
|
||||
currLen += tlv.tlvLen;
|
||||
tlvCount++;
|
||||
|
||||
tlv.tlvType = TLV_PERMISSION;
|
||||
tlv.tlvLen = sizeof(AppSpawnTlv) + sizeof(flags);
|
||||
ret = AddOneTlv(buffer + currLen, bufferLen - currLen, tlv, (uint8_t *)flags);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed add tlv %{public}u", tlv.tlvType);
|
||||
currLen += tlv.tlvLen;
|
||||
tlvCount++;
|
||||
|
||||
AppSpawnMsgAccessToken token = {12345678}; // 12345678
|
||||
tlv.tlvType = TLV_ACCESS_TOKEN_INFO;
|
||||
tlv.tlvLen = sizeof(AppSpawnTlv) + sizeof(token);
|
||||
ret = AddOneTlv(buffer + currLen, bufferLen - currLen, tlv, (uint8_t *)&token);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed add tlv %{public}u", tlv.tlvType);
|
||||
currLen += tlv.tlvLen;
|
||||
tlvCount++;
|
||||
|
||||
// add bundle info
|
||||
AppBundleInfo info = {};
|
||||
(void)strcpy_s(info.bundleName, sizeof(info.bundleName), "test-bundleName");
|
||||
info.bundleIndex = 100; // 100 test index
|
||||
tlv.tlvType = TLV_BUNDLE_INFO;
|
||||
tlv.tlvLen = sizeof(AppSpawnTlv) + sizeof(AppBundleInfo);
|
||||
ret = AddOneTlv(buffer + currLen, bufferLen - currLen, tlv, (uint8_t *)&info);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed add tlv %{public}u", tlv.tlvType);
|
||||
currLen += tlv.tlvLen;
|
||||
tlvCount++;
|
||||
|
||||
// add dac
|
||||
AppDacInfo dacInfo = {};
|
||||
dacInfo.uid = 20010029; // 20010029
|
||||
dacInfo.gid = 20010029; // 20010029
|
||||
dacInfo.gidCount = 2; // 2 count
|
||||
dacInfo.gidTable[0] = 20010029; // 20010029
|
||||
dacInfo.gidTable[1] = 20010029 + 1; // 20010029
|
||||
tlv.tlvType = TLV_DAC_INFO;
|
||||
tlv.tlvLen = sizeof(AppSpawnTlv) + sizeof(dacInfo);
|
||||
ret = AddOneTlv(buffer + currLen, bufferLen - currLen, tlv, (uint8_t *)&dacInfo);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed add tlv %{public}u", tlv.tlvType);
|
||||
currLen += tlv.tlvLen;
|
||||
tlvCount++;
|
||||
realLen = currLen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
AppSpawnContent *AppSpawnTestHelper::StartSpawnServer(std::string &cmd, CmdArgs *&args)
|
||||
{
|
||||
args = AppSpawnTestHelper::ToCmdList(cmd.c_str());
|
||||
APPSPAWN_CHECK(args != nullptr, return NULL, "Failed to alloc args");
|
||||
|
||||
AppSpawnStartArg startRrg = {};
|
||||
startRrg.mode = MODE_FOR_APP_SPAWN;
|
||||
startRrg.socketName = APPSPAWN_SOCKET_NAME;
|
||||
startRrg.serviceName = APPSPAWN_SERVER_NAME;
|
||||
startRrg.moduleType = MODULE_APPSPAWN;
|
||||
startRrg.initArg = 1;
|
||||
if (args->argc <= MODE_VALUE_INDEX) { // appspawn start
|
||||
startRrg.mode = MODE_FOR_APP_SPAWN;
|
||||
} else if (strcmp(args->argv[MODE_VALUE_INDEX], "app_cold") == 0) { // cold start
|
||||
APPSPAWN_CHECK(args->argc > PARAM_VALUE_INDEX, free(args);
|
||||
return NULL, "Invalid arg for cold start %{public}d", args->argc);
|
||||
startRrg.mode = MODE_FOR_APP_COLD_RUN;
|
||||
startRrg.initArg = 0;
|
||||
} else if (strcmp(args->argv[MODE_VALUE_INDEX], "nweb_cold") == 0) { // cold start
|
||||
APPSPAWN_CHECK(args->argc > PARAM_VALUE_INDEX, free(args);
|
||||
return NULL, "Invalid arg for cold start %{public}d", args->argc);
|
||||
startRrg.mode = MODE_FOR_NWEB_COLD_RUN;
|
||||
startRrg.serviceName = NWEBSPAWN_SERVER_NAME;
|
||||
startRrg.initArg = 0;
|
||||
} else if (strcmp(args->argv[MODE_VALUE_INDEX], NWEBSPAWN_SERVER_NAME) == 0) { // nweb spawn start
|
||||
startRrg.mode = MODE_FOR_NWEB_SPAWN;
|
||||
startRrg.moduleType = MODULE_NWEBSPAWN;
|
||||
startRrg.socketName = NWEBSPAWN_SOCKET_NAME;
|
||||
startRrg.serviceName = NWEBSPAWN_SERVER_NAME;
|
||||
}
|
||||
APPSPAWN_LOGV("Start service %{public}s", startRrg.serviceName);
|
||||
AppSpawnContent *content = StartSpawnService(&startRrg, APP_LEN_PROC_NAME, args->argc, args->argv);
|
||||
if (content == nullptr) {
|
||||
free(args);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
} // namespace OHOS
|
||||
|
||||
static int TestChildLoopRun(AppSpawnContent *content, AppSpawnClient *client)
|
||||
{
|
||||
APPSPAWN_LOGV("ChildLoopRun ...");
|
||||
sleep(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestPreLoad(AppSpawnMgr *content)
|
||||
{
|
||||
// register
|
||||
RegChildLooper(&content->content, TestChildLoopRun);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
APPSPAWN_LOGV("Load test module ...");
|
||||
AddPreloadHook(HOOK_PRIO_LOWEST, TestPreLoad);
|
||||
}
|
215
test/unittest/app_spawn_test_helper.h
Normal file
215
test/unittest/app_spawn_test_helper.h
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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 APPSPAWN_TEST_HELPER_H
|
||||
#define APPSPAWN_TEST_HELPER_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#include "appspawn.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "appspawn_service.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "list.h"
|
||||
#include "loop_event.h"
|
||||
|
||||
#include "app_spawn_stub.h"
|
||||
|
||||
namespace OHOS {
|
||||
typedef struct {
|
||||
int argc;
|
||||
char *argv[0];
|
||||
} CmdArgs;
|
||||
|
||||
typedef struct AppSpawnClient AppSpawnClient;
|
||||
struct TestConnection;
|
||||
class LocalTestServer;
|
||||
using RecvMsgProcess = std::function<void(struct TestConnection *connection, const uint8_t *buffer, uint32_t buffLen)>;
|
||||
using AddTlvFunction = std::function<int(uint8_t *buffer, uint32_t bufferLen, uint32_t &realLen, uint32_t &tlvCount)>;
|
||||
|
||||
class AppSpawnTestHelper {
|
||||
public:
|
||||
AppSpawnTestHelper()
|
||||
{
|
||||
SetDefaultTestData();
|
||||
}
|
||||
~AppSpawnTestHelper() {}
|
||||
|
||||
void SetDefaultTestData();
|
||||
const char *GetDefaultTestAppBundleName()
|
||||
{
|
||||
return processName_.c_str();
|
||||
}
|
||||
uid_t GetTestUid()
|
||||
{
|
||||
return defaultTestUid_;
|
||||
}
|
||||
gid_t GetTestGid()
|
||||
{
|
||||
return defaultTestGid_;
|
||||
}
|
||||
gid_t GetTestGidGroup()
|
||||
{
|
||||
return defaultTestGidGroup_;
|
||||
}
|
||||
int32_t GetTestBundleIndex()
|
||||
{
|
||||
return defaultTestBundleIndex_;
|
||||
}
|
||||
|
||||
void SetTestUid(uid_t uid)
|
||||
{
|
||||
defaultTestUid_ = uid;
|
||||
}
|
||||
void SetProcessName(const char *name)
|
||||
{
|
||||
processName_ = std::string(name);
|
||||
}
|
||||
|
||||
AppSpawnReqMsgHandle CreateMsg(AppSpawnClientHandle handle, uint32_t msgType = MSG_APP_SPAWN, int base = 0);
|
||||
AppSpawningCtx *GetAppProperty(AppSpawnClientHandle handle, AppSpawnReqMsgHandle reqHandle);
|
||||
|
||||
int CreateSocket(void);
|
||||
int CreateSendMsg(std::vector<uint8_t> &buffer, uint32_t msgType, uint32_t &msgLen,
|
||||
const std::vector<AddTlvFunction> &addTlvFuncs);
|
||||
const std::vector<const char *> &GetPermissions()
|
||||
{
|
||||
return permissions_;
|
||||
}
|
||||
|
||||
static int AddBaseTlv(uint8_t *buffer, uint32_t bufferLen, uint32_t &realLen, uint32_t &tlvCount);
|
||||
static uint32_t GenRandom(void);
|
||||
static CmdArgs *ToCmdList(const char *cmd);
|
||||
static AppSpawnContent *StartSpawnServer(std::string &cmd, CmdArgs *&args);
|
||||
private:
|
||||
AppSpawnMsgNode *CreateAppSpawnMsg(AppSpawnMsg *msg);
|
||||
|
||||
std::string processName_ = {};
|
||||
uid_t defaultTestUid_;
|
||||
gid_t defaultTestGid_;
|
||||
gid_t defaultTestGidGroup_;
|
||||
int32_t defaultTestBundleIndex_;
|
||||
std::vector<const char *> permissions_ = {
|
||||
const_cast<char *>("ohos.permission.READ_IMAGEVIDEO"),
|
||||
const_cast<char *>("ohos.permission.FILE_CROSS_APP"),
|
||||
const_cast<char *>("ohos.permission.ACTIVATE_THEME_PACKAGE"),
|
||||
const_cast<char *>("ohos.permission.GET_WALLPAPER"),
|
||||
const_cast<char *>("ohos.permission.ACCESS_DATA"),
|
||||
const_cast<char *>("ohos.permission.ACCESS_DEV_FUSE"),
|
||||
const_cast<char *>("ohos.permission.FILE_ACCESS_MANAGER")
|
||||
};
|
||||
};
|
||||
|
||||
class AppSpawnTestServer : public AppSpawnTestHelper {
|
||||
public:
|
||||
explicit AppSpawnTestServer(const char *cmd, bool testServer)
|
||||
: AppSpawnTestHelper(), serviceCmd_(cmd), testServer_(testServer), protectTime_(2000) // 2000 2s
|
||||
{
|
||||
serverId_ = AppSpawnTestServer::serverId;
|
||||
AppSpawnTestServer::serverId++;
|
||||
}
|
||||
|
||||
explicit AppSpawnTestServer(const char *cmd)
|
||||
: AppSpawnTestHelper(), serviceCmd_(cmd), testServer_(true), protectTime_(2000) // 2000 2s
|
||||
{
|
||||
serverId_ = AppSpawnTestServer::serverId;
|
||||
AppSpawnTestServer::serverId++;
|
||||
}
|
||||
~AppSpawnTestServer();
|
||||
|
||||
void Start(void);
|
||||
void Start(RecvMsgProcess process, uint32_t time = 2000); // 2000 default 2s
|
||||
void Stop();
|
||||
void KillNWebSpawnServer();
|
||||
|
||||
private:
|
||||
void CloseCheckHandler(void);
|
||||
void StartCheckHandler(void);
|
||||
void StopSpawnService(void);
|
||||
|
||||
static uint32_t serverId;
|
||||
static void *ServiceThread(void *arg);
|
||||
#ifdef USER_TIMER_TO_CHECK
|
||||
static void ProcessIdle(const TimerHandle taskHandle, void *context);
|
||||
#else
|
||||
static void ProcessIdle(const IdleHandle taskHandle, void *context);
|
||||
#endif
|
||||
|
||||
AppSpawnContent *content_ = nullptr;
|
||||
std::atomic<long> appPid_{-1};
|
||||
std::string serviceCmd_{};
|
||||
#ifdef USER_TIMER_TO_CHECK
|
||||
TimerHandle timer_;
|
||||
#else
|
||||
IdleHandle idle_ = nullptr;
|
||||
#endif
|
||||
pthread_t threadId_ = 0;
|
||||
std::atomic<bool> stop_{false};
|
||||
RecvMsgProcess recvMsgProcess_ = nullptr;
|
||||
bool testServer_ = false;
|
||||
bool serverStoped = false;
|
||||
struct timespec startTime_ {};
|
||||
uint32_t protectTime_;
|
||||
uint32_t serverId_ = 0;
|
||||
LocalTestServer *localServer_ = nullptr;
|
||||
};
|
||||
|
||||
struct TestConnection {
|
||||
uint32_t connectionId;
|
||||
TaskHandle stream;
|
||||
uint32_t msgRecvLen; // 已经接收的长度
|
||||
AppSpawnMsg msg; // 保存不完整的消息,额外保存消息头信息
|
||||
uint8_t *buffer = nullptr;
|
||||
RecvMsgProcess recvMsgProcess = nullptr;
|
||||
int SendResponse(const AppSpawnMsg *msg, int result, pid_t pid);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 用于client端测试,构建服务程序
|
||||
*
|
||||
*/
|
||||
class LocalTestServer {
|
||||
public:
|
||||
LocalTestServer() {}
|
||||
~LocalTestServer() {}
|
||||
|
||||
int Run(const char *serverName, RecvMsgProcess recvMsg);
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
using ServerInfo = struct ServerInfo_ {
|
||||
LocalTestServer *local = nullptr;
|
||||
RecvMsgProcess recvMsgProcess = nullptr;
|
||||
};
|
||||
|
||||
static int OnConnection(const LoopHandle loopHandle, const TaskHandle server);
|
||||
static void SendMessageComplete(const TaskHandle taskHandle, BufferHandle handle);
|
||||
static void OnClose(const TaskHandle taskHandle);
|
||||
static void OnReceiveRequest(const TaskHandle taskHandle, const uint8_t *buffer, uint32_t buffLen);
|
||||
TaskHandle serverHandle_ = 0;
|
||||
};
|
||||
} // namespace OHOS
|
||||
#endif // APPSPAWN_TEST_HELPER_H
|
@ -63,52 +63,6 @@ int MakeDirRec(const char *path, mode_t mode, int lastPath)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void CheckDirRecursive(const char *path)
|
||||
{
|
||||
char buffer[PATH_MAX] = {0};
|
||||
const char slash = '/';
|
||||
const char *p = path;
|
||||
char *curPos = strchr(path, slash);
|
||||
while (curPos != NULL) {
|
||||
int len = curPos - p;
|
||||
p = curPos + 1;
|
||||
if (len == 0) {
|
||||
curPos = strchr(p, slash);
|
||||
continue;
|
||||
}
|
||||
int ret = memcpy_s(buffer, PATH_MAX, path, p - path - 1);
|
||||
APPSPAWN_CHECK(ret == 0, return, "Failed to copy path");
|
||||
ret = access(buffer, F_OK);
|
||||
APPSPAWN_CHECK(ret == 0, return, "Dir not exit %{public}s errno: %{public}d", buffer, errno);
|
||||
curPos = strchr(p, slash);
|
||||
}
|
||||
int ret = access(path, F_OK);
|
||||
APPSPAWN_CHECK(ret == 0, return, "Dir not exit %{public}s errno: %{public}d", buffer, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
int SandboxMountPath(const MountArg *arg)
|
||||
{
|
||||
APPSPAWN_CHECK(arg != NULL && arg->originPath != NULL && arg->destinationPath != NULL,
|
||||
return APPSPAWN_ARG_INVALID, "Invalid arg ");
|
||||
int ret = mount(arg->originPath, arg->destinationPath, arg->fsType, arg->mountFlags, arg->options);
|
||||
if (ret != 0) {
|
||||
if (arg->originPath != NULL && strstr(arg->originPath, "/data/app/el2/") != NULL) {
|
||||
CheckDirRecursive(arg->originPath);
|
||||
}
|
||||
APPSPAWN_LOGW("errno is: %{public}d, bind mount %{public}s => %{public}s",
|
||||
errno, arg->originPath, arg->destinationPath);
|
||||
return errno;
|
||||
}
|
||||
ret = mount(NULL, arg->destinationPath, NULL, arg->mountSharedFlag, NULL);
|
||||
if (ret != 0) {
|
||||
APPSPAWN_LOGW("errno is: %{public}d, bind mount %{public}s => %{public}s",
|
||||
errno, arg->originPath, arg->destinationPath);
|
||||
return errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void TrimTail(char *buffer, uint32_t maxLen)
|
||||
{
|
||||
int32_t index = maxLen - 1;
|
||||
|
Loading…
Reference in New Issue
Block a user