add appspawn sandbox and test code

Signed-off-by: zhongning5 <zhongning5@huawei.com>
This commit is contained in:
zhongning5 2024-04-10 17:33:13 +08:00
parent fb1a87eda0
commit 3b62419de0
70 changed files with 7006 additions and 489 deletions

View File

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

0
modules/ace_adapter/command_lexer.h Executable file → Normal file
View File

0
modules/asan/BUILD.gn Executable file → Normal file
View File

1
modules/asan/asan_detector.c Executable file → Normal file
View 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
View 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
View 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
View 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
View 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
View 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);

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

91
modules/module_engine/include/appspawn_hook.h Executable file → Normal file
View 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
View File

0
modules/module_engine/stub/libappspawn.stub.empty.json Executable file → Normal file
View File

6
modules/module_engine/stub/libappspawn.stub.json Executable file → Normal file
View 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
View 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
View 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
View File

1
modules/nweb_adapter/nwebspawn_adapter.cpp Executable file → Normal file
View 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
View 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
View 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
View 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
View File

602
modules/sandbox/appspawn_sandbox.c Executable file → Normal file
View 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 != &section->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 != &section->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-depsmount-paths-deps
* src = mount-paths-deps.src-path
* dst = mount-paths-deps.sandbox-path
* dst = root-dir + mount-paths-deps.sandbox-path
* no-existmount-paths src
mount-paths-deps.src-path shared方式挂载mount-paths-deps
* alwaysshared方式挂载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-groupsmount 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-groupsmount 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
View 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
View 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路径变量的含义
1mount-paths-deps->sandbox-path STAGE_GLOBAL或者应用孵化时的挂载
使 MOUNT_PATH_OP_REPLACE_BY_SANDBOX
2mount-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
View 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
View 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
View 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(&section->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(&section->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 != &section->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
View File

0
modules/sysevent/event_reporter.cpp Executable file → Normal file
View File

404
standard/appspawn_appmgr.c Executable file
View 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
View 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
View 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

View File

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

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

View 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

View 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

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

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#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

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

@ -0,0 +1,93 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#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

View 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

View File

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

0
test/moduletest/appspawn_test_cmder.cpp Executable file → Normal file
View File

0
test/moduletest/appspawn_test_cmder.h Executable file → Normal file
View File

0
test/moduletest/appspawn_test_main.cpp Executable file → Normal file
View File

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

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

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

0
test/moduletest/threadpool/thread_manager.c Executable file → Normal file
View File

0
test/moduletest/threadpool/thread_manager.h Executable file → Normal file
View File

0
test/unittest/app_spawn_client_test/BUILD.gn Executable file → Normal file
View File

View 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
* assertstop后执行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

View File

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

View 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

View File

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

View 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 2033
*
*/
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 2spawn和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 nwebspawnappspawn的线程结束
*
*/
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

View File

@ -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); // waitto 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

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

View 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

View File

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