appspawn归一化

Signed-off-by: xlei1030 <xionglei6@huawei.com>
This commit is contained in:
xlei1030 2022-04-27 09:23:43 +08:00
parent f051e55945
commit f7b7dddb2b
57 changed files with 3717 additions and 3577 deletions

119
BUILD.gn
View File

@ -17,20 +17,30 @@ import("//build/ohos.gni")
config("appspawn_config") {
visibility = [ ":*" ]
include_dirs = [
"src/include",
"common",
"standard",
"adapter",
"interfaces/innerkits/include",
"//utils/native/base/include",
"${aafwk_path}/frameworks/kits/appkit/native/app/include",
"${aafwk_path}/interfaces/innerkits/app_manager/include/appmgr",
"${appexecfwk_path}/interfaces/innerkits/libeventhandler/include",
"${appexecfwk_path}/common/log/include",
"${appexecfwk_path}/interfaces/innerkits/appexecfwk_core/include/bundlemgr",
"${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/include",
"${aafwk_path}/interfaces/innerkits/want/include/ohos/aafwk/content",
"${aafwk_path}/interfaces/innerkits/want/include",
"${aafwk_path}/interfaces/innerkits/ability_manager/include",
"${aafwk_path}/interfaces/innerkits/base/include",
"${aafwk_path}/frameworks/kits/ability/native/include",
"${aafwk_path}/services/abilitymgr/include",
"//base/global/resmgr_standard/interfaces/innerkits/include",
"//base/security/access_token/interfaces/innerkits/token_setproc/include",
"//base/startup/init_lite/services/log",
"//base/startup/init_lite/services/include",
"//base/startup/init_lite/services/loopevent/include",
"//base/startup/init_lite/interfaces/innerkits/include",
"//base/startup/init_lite/interfaces/innerkits/sandbox/include",
"//base/startup/syspara_lite/interfaces/innerkits/native/syspara/include",
]
@ -40,13 +50,22 @@ config("appspawn_config") {
}
ohos_executable("appspawn") {
sources = [ "${appspawn_path}/src/main.cpp" ]
sources = [
"${appspawn_path}/adapter/appspawn_ace.cpp",
"${appspawn_path}/standard/main.c",
]
configs = [ ":appspawn_config" ]
deps = [
"${appspawn_path}:appspawn_server",
"//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc",
"//foundation/aafwk/standard/frameworks/kits/appkit:appkit_native",
]
external_deps = [
"ability_base:want",
"ability_runtime:app_manager",
"hiviewdfx_hilog_native:libhilog",
"ipc:ipc_core",
"utils_base:utils",
]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
install_enable = true
subsystem_name = "${subsystem_name}"
@ -55,29 +74,30 @@ ohos_executable("appspawn") {
ohos_static_library("appspawn_server") {
sources = [
"${appspawn_path}/src/appspawn_msg_peer.cpp",
"${appspawn_path}/src/appspawn_server.cpp",
"${appspawn_path}/src/socket/appspawn_socket.cpp",
"${appspawn_path}/src/socket/server_socket.cpp",
"${appspawn_path}/adapter/appspawn_adapter.cpp",
"${appspawn_path}/adapter/appspawn_log.cpp",
"${appspawn_path}/adapter/appspawn_sandbox.cpp",
"${appspawn_path}/common/appspawn_server.c",
"${appspawn_path}/standard/appspawn_process.c",
"${appspawn_path}/standard/appspawn_service.c",
]
defines = [
"GRAPHIC_PERMISSION_CHECK",
"INIT_AGENT",
]
defines = [ "INIT_AGENT" ]
configs = [ ":appspawn_config" ]
ldflags = [ "-Wl,--dynamic-linker,/system/bin/linker64z" ]
deps = [
"${aafwk_path}/frameworks/kits/ability/native:abilitykit_native",
"${aafwk_path}/frameworks/kits/appkit:appkit_native",
"//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc",
"//base/startup/init_lite/interfaces/innerkits:libbegetutil",
"//base/startup/init_lite/services/log:init_log",
"//base/startup/init_lite/interfaces/innerkits/sandbox:libsandbox",
"//base/startup/init_lite/services/loopevent:loopevent",
"//base/startup/init_lite/services/utils:libinit_tools",
"//base/startup/syspara_lite/interfaces/innerkits/native/syspara:syspara",
"//third_party/libuv:uv_static",
"//utils/native/base:utils",
]
external_deps = [
"ability_base:want",
"hilog_native:libhilog",
"hiviewdfx_hilog_native:libhilog",
"ipc:ipc_core",
]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
if (build_selinux) {
external_deps += [ "selinux:libhap_restorecon" ]
}
@ -86,20 +106,6 @@ ohos_static_library("appspawn_server") {
part_name = "${part_name}"
}
ohos_executable("appspawntools") {
sources = [ "${appspawn_path}/tools/appspawn_start_app.cpp" ]
configs = [ ":appspawn_config" ]
deps = [
"${appspawn_path}:appspawn_server",
"//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc",
]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
install_enable = true
subsystem_name = "${subsystem_name}"
part_name = "${part_name}"
}
ohos_prebuilt_etc("appspawn.rc") {
source = "appspawn.cfg"
relative_install_dir = "init"
@ -109,56 +115,21 @@ ohos_prebuilt_etc("appspawn.rc") {
ohos_executable("nwebspawn") {
defines = [ "NWEB_SPAWN" ]
sources = [ "${appspawn_path}/src/main.cpp" ]
sources = [
"${appspawn_path}/adapter/appspawn_nweb.cpp",
"${appspawn_path}/standard/main.c",
]
configs = [ ":appspawn_config" ]
deps = [
"${appspawn_path}:nwebspawn_server",
"//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc",
"${appspawn_path}:appspawn_server",
"//base/startup/init_lite/interfaces/innerkits/sandbox:libsandbox",
]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
install_enable = true
subsystem_name = "${subsystem_name}"
part_name = "${part_name}"
}
ohos_static_library("nwebspawn_server") {
defines = [
"INIT_AGENT",
"NWEB_SPAWN",
]
sources = [
"${appspawn_path}/src/appspawn_msg_peer.cpp",
"${appspawn_path}/src/appspawn_server.cpp",
"${appspawn_path}/src/socket/appspawn_socket.cpp",
"${appspawn_path}/src/socket/server_socket.cpp",
]
configs = [ ":appspawn_config" ]
ldflags = [ "-Wl,--dynamic-linker,/system/bin/linker64z" ]
deps = [
"${aafwk_path}/frameworks/kits/ability/native:abilitykit_native",
"${aafwk_path}/frameworks/kits/appkit:appkit_native",
"//base/startup/init_lite/interfaces/innerkits:libbegetutil",
"//base/startup/init_lite/interfaces/innerkits/socket:libsocket_static",
"//base/startup/init_lite/services/log:init_log",
"//base/startup/syspara_lite/interfaces/innerkits/native/syspara:syspara",
"//utils/native/base:utils",
]
external_deps = [
"ability_base:want",
"hilog_native:libhilog",
"hiviewdfx_hilog_native:libhilog",
"ipc:ipc_core",
]
if (build_selinux) {
external_deps += [ "selinux:libhap_restorecon" ]
}
subsystem_name = "${subsystem_name}"
part_name = "${part_name}"
}
ohos_prebuilt_etc("nwebspawn.rc") {
source = "nwebspawn.cfg"
relative_install_dir = "init"

46
adapter/appspawn_ace.cpp Normal file
View File

@ -0,0 +1,46 @@
/*
* 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 "appspawn_adapter.h"
#include "main_thread.h"
void LoadExtendLib(AppSpawnContent *content)
{
#ifdef __aarch64__
const char *acelibdir("/system/lib64/libace.z.so");
#else
const char *acelibdir("/system/lib/libace.z.so");
#endif
void *AceAbilityLib = NULL;
APPSPAWN_LOGI("MainThread::LoadAbilityLibrary. Start calling dlopen acelibdir.");
#ifndef APPSPAWN_TEST
AceAbilityLib = dlopen(acelibdir, RTLD_NOW | RTLD_GLOBAL);
#endif
if (AceAbilityLib == NULL) {
APPSPAWN_LOGE("Fail to dlopen %s, [%s]", acelibdir, dlerror());
} else {
APPSPAWN_LOGI("Success to dlopen %s", acelibdir);
}
APPSPAWN_LOGI("MainThread::LoadAbilityLibrary. End calling dlopen.");
}
void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
{
APPSPAWN_LOGI("AppExecFwk::MainThread::Start");
#ifndef APPSPAWN_TEST
OHOS::AppExecFwk::MainThread::Start();
#endif
}

View File

@ -0,0 +1,42 @@
/*
* 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 "appspawn_adapter.h"
#include <cerrno>
#include "token_setproc.h"
#ifdef WITH_SELINUX
#include "hap_restorecon.h"
#endif
void SetAppAccessToken(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
int32_t ret = SetSelfTokenID(appProperty->property.accessTokenId);
APPSPAWN_LOGI("AppSpawnServer::set access token id = %d, ret = %d %d",
appProperty->property.accessTokenId, ret, getuid());
#ifdef WITH_SELINUX
HapContext hapContext;
ret = hapContext.HapDomainSetcontext(appProperty->property.apl, appProperty->property.processName);
if (ret != 0) {
APPSPAWN_LOGE("AppSpawnServer::Failed to hap domain set context, errno = %d %s",
errno, appProperty->property.apl);
} else {
APPSPAWN_LOGI("AppSpawnServer::Success to hap domain set context, ret = %d", ret);
}
#endif
}

View File

@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef APPSPAWN_ADPATER_CPP
#define APPSPAWN_ADPATER_CPP
#include "appspawn_service.h"
#include <dlfcn.h>
#ifdef __cplusplus
extern "C" {
#endif
int32_t SetAppSandboxProperty(struct AppSpawnContent_ *content, AppSpawnClient *client);
void SetAppAccessToken(struct AppSpawnContent_ *content, AppSpawnClient *client);
void LoadExtendLib(AppSpawnContent *content);
void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client);
void RegisterAppSandbox(struct AppSpawnContent_ *content, AppSpawnClient *client);
int GetRenderProcessTerminationStatus(int32_t pid, int *status);
void RecordRenderProcessExitedStatus(pid_t pid, int status);
#ifdef __cplusplus
}
#endif
#endif

83
adapter/appspawn_log.cpp Normal file
View File

@ -0,0 +1,83 @@
/*
* 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 "appspawn_server.h"
#include <cerrno>
#include <ctime>
#include <cstdarg>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include "hilog/log.h"
#include "securec.h"
static AppspawnLogLevel g_logLevel = AppspawnLogLevel::INFO;
static constexpr int MAX_LOG_SIZE = 1024;
static constexpr int BASE_YEAR = 1900;
static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0, APPSPAWN_LABEL};
void AppspawnLogPrint(AppspawnLogLevel logLevel, const char *file, int line, const char *fmt, ...)
{
if (logLevel < g_logLevel) {
return;
}
va_list list;
va_start(list, fmt);
char tmpFmt[MAX_LOG_SIZE];
if (vsnprintf_s(tmpFmt, MAX_LOG_SIZE, MAX_LOG_SIZE - 1, fmt, list) == -1) {
va_end(list);
return;
}
va_end(list);
switch (logLevel) {
case AppspawnLogLevel::DEBUG:
OHOS::HiviewDFX::HiLog::Debug(LABEL, "[%{public}s:%{public}d]%{public}s", file, line, tmpFmt);
break;
case AppspawnLogLevel::INFO:
OHOS::HiviewDFX::HiLog::Info(LABEL, "[%{public}s:%{public}d]%{public}s", file, line, tmpFmt);
break;
case AppspawnLogLevel::WARN:
OHOS::HiviewDFX::HiLog::Warn(LABEL, "[%{public}s:%{public}d]%{public}s", file, line, tmpFmt);
break;
case AppspawnLogLevel::ERROR:
OHOS::HiviewDFX::HiLog::Error(LABEL, "[%{public}s:%{public}d]%{public}s", file, line, tmpFmt);
break;
case AppspawnLogLevel::FATAL:
OHOS::HiviewDFX::HiLog::Fatal(LABEL, "[%{public}s:%{public}d]%{public}s", file, line, tmpFmt);
break;
default:
break;
}
time_t second = time(0);
if (second <= 0) {
return;
}
struct tm *t = localtime(&second);
FILE *outfile = fopen("/data/init_agent/appspawn.log", "a+");
if (t == nullptr || outfile == nullptr) {
return;
}
(void)fprintf(outfile, "[%d-%d-%d %d:%d:%d][pid=%d][%s:%d]%s \n",
(t->tm_year + BASE_YEAR), (t->tm_mon + 1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec,
getpid(), file, line, tmpFmt);
(void)fflush(outfile);
(void)fclose(outfile);
return;
}

118
adapter/appspawn_nweb.cpp Normal file
View File

@ -0,0 +1,118 @@
/*
* 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 "appspawn_adapter.h"
#include <dlfcn.h>
#include <string>
#ifdef NWEB_SPAWN
#define RENDER_PROCESS_MAX_NUM 16
#define RENDER_PROCESS_ARRAY_IDLE 0
typedef struct {
int32_t pid;
int exitStatus;
} RenderProcessNode;
static RenderProcessNode g_renderProcessArray[RENDER_PROCESS_MAX_NUM];
#endif
void *g_nwebHandle = nullptr;
void LoadExtendLib(AppSpawnContent *content)
{
const std::string LOAD_LIB_DIR = "/data/app/el1/bundle/public/com.ohos.nweb/libs/arm";
#ifdef __MUSL__
Dl_namespace dlns;
dlns_init(&dlns, "nweb_ns");
dlns_create(&dlns, LOAD_LIB_DIR.c_str());
void *handle = dlopen_ns(&dlns, "libweb_engine.so", RTLD_NOW | RTLD_GLOBAL);
#else
const std::string ENGINE_LIB_DIR = LOAD_LIB_DIR + "/libweb_engine.so";
void *handle = dlopen(ENGINE_LIB_DIR.c_str(), RTLD_NOW | RTLD_GLOBAL);
#endif
if (handle == nullptr) {
APPSPAWN_LOGE("Fail to dlopen libweb_engine.so, [%s]", dlerror());
} else {
APPSPAWN_LOGI("Success to dlopen libweb_engine.so");
}
#ifdef __MUSL__
g_nwebHandle = dlopen_ns(&dlns, "libnweb_render.so", RTLD_NOW | RTLD_GLOBAL);
#else
const std::string RENDER_LIB_DIR = LOAD_LIB_DIR + "/libnweb_render.so";
g_nwebHandle = dlopen(RENDER_LIB_DIR.c_str(), RTLD_NOW | RTLD_GLOBAL);
#endif
if (g_nwebHandle == nullptr) {
APPSPAWN_LOGE("Fail to dlopen libnweb_render.so, [%s]", dlerror());
} else {
APPSPAWN_LOGI("Success to dlopen libnweb_render.so");
}
}
void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
{
AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
using FuncType = void (*)(const char *cmd);
FuncType funcNWebRenderMain = reinterpret_cast<FuncType>(dlsym(g_nwebHandle, "NWebRenderMain"));
if (funcNWebRenderMain == nullptr) {
APPSPAWN_LOGI("webviewspawn dlsym ERROR=%s", dlerror());
return;
}
funcNWebRenderMain(appProperty->property.renderCmd);
}
static void DumpRenderProcessExitedArray()
{
APPSPAWN_LOGI("dump render process exited array:");
for (int i = 0; i < RENDER_PROCESS_MAX_NUM; i++) {
APPSPAWN_LOGI("[pid, exitedStatus] = [%d, %d]",
g_renderProcessArray[i].pid, g_renderProcessArray[i].exitStatus);
}
}
void RecordRenderProcessExitedStatus(pid_t pid, int status)
{
int i = 0;
for (; i < RENDER_PROCESS_MAX_NUM; i++) {
if (g_renderProcessArray[i].pid == RENDER_PROCESS_ARRAY_IDLE) {
g_renderProcessArray[i].exitStatus = status;
g_renderProcessArray[i].pid = pid;
break;
}
}
if (i == RENDER_PROCESS_MAX_NUM) {
APPSPAWN_LOGE("no empty space in render process exited array");
DumpRenderProcessExitedArray();
}
}
int GetRenderProcessTerminationStatus(int32_t pid, int *status)
{
if (status == nullptr) {
return -1;
}
for (int i = 0; i < RENDER_PROCESS_MAX_NUM; i++) {
if (g_renderProcessArray[i].pid == pid) {
*status = g_renderProcessArray[i].exitStatus;
g_renderProcessArray[i].pid = RENDER_PROCESS_ARRAY_IDLE;
return 0;
}
}
APPSPAWN_LOGE("not find pid[%d] in render process exited arrary", pid);
DumpRenderProcessExitedArray();
return -1;
}

View File

@ -0,0 +1,414 @@
/*
* 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 "appspawn_adapter.h"
#include <cerrno>
#include <fcntl.h>
#include <map>
#include <sched.h>
#include <string>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include "sandbox.h"
#include "sandbox_namespace.h"
bool g_isPrivAppSandboxCreated = false;
bool g_isAppSandboxCreated = false;
constexpr std::string_view APL_SYSTEM_CORE("system_core");
constexpr std::string_view APL_SYSTEM_BASIC("system_basic");
constexpr static int UID_BASE = 200000;
constexpr static mode_t FILE_MODE = 0711;
constexpr static mode_t NWEB_FILE_MODE = 0511;
static void RegisterSandbox(AppSpawnContentExt *appSpawnContent, const char *sandbox)
{
if (sandbox == nullptr) {
APPSPAWN_LOGE("AppSpawnServer::invalid parameters");
return;
}
APPSPAWN_LOGE("RegisterSandbox %s", sandbox);
InitDefaultNamespace();
if (!InitSandboxWithName(sandbox)) {
CloseDefaultNamespace();
APPSPAWN_LOGE("AppSpawnServer::Failed to init sandbox with name %s", sandbox);
return;
}
DumpSandboxByName(sandbox);
if (PrepareSandbox(sandbox) != 0) {
APPSPAWN_LOGE("AppSpawnServer::Failed to prepare sandbox %s", sandbox);
DestroySandbox(sandbox);
CloseDefaultNamespace();
return;
}
if (EnterDefaultNamespace() < 0) {
APPSPAWN_LOGE("AppSpawnServer::Failed to set default namespace");
DestroySandbox(sandbox);
CloseDefaultNamespace();
return;
}
CloseDefaultNamespace();
if (strcmp(sandbox, "app") == 0) {
appSpawnContent->flags |= FLAGS_SANDBOX_APP;
} else if (strcmp(sandbox, "priv-app") == 0) {
appSpawnContent->flags |= FLAGS_SANDBOX_PRIVATE;
}
}
void RegisterAppSandbox(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
APPSPAWN_CHECK(appSpawnContent != NULL, return, "Invalid appspawn content");
if ((appSpawnContent->flags & FLAGS_SANDBOX_PRIVATE) != FLAGS_SANDBOX_PRIVATE) {
if (strcmp("system_basic", appProperty->property.apl) == 0) {
RegisterSandbox(appSpawnContent, "priv-app");
}
}
if ((appSpawnContent->flags & FLAGS_SANDBOX_APP) != FLAGS_SANDBOX_APP) {
if (strcmp("normal", appProperty->property.apl) == 0) {
RegisterSandbox(appSpawnContent, "app");
}
}
}
static int32_t DoAppSandboxMountOnce(const std::string originPath, const std::string destinationPath)
{
int rc = 0;
rc = mount(originPath.c_str(), destinationPath.c_str(), NULL, MS_BIND | MS_REC, NULL);
if (rc) {
APPSPAWN_LOGE("bind mount %s to %s failed %d", originPath.c_str(),
destinationPath.c_str(), errno);
return rc;
}
rc = mount(NULL, destinationPath.c_str(), NULL, MS_PRIVATE, NULL);
if (rc) {
APPSPAWN_LOGE("private mount to %s failed %d", destinationPath.c_str(), errno);
return rc;
}
return 0;
}
static int32_t DoAppSandboxMount(const AppParameter &appProperty, std::string rootPath)
{
std::string currentUserId = std::to_string(appProperty.uid / UID_BASE);
std::string oriInstallPath = "/data/app/el1/bundle/public/";
std::string oriel1DataPath = "/data/app/el1/" + currentUserId + "/base/";
std::string oriel2DataPath = "/data/app/el2/" + currentUserId + "/base/";
std::string oriDatabasePath = "/data/app/el2/" + currentUserId + "/database/";
std::string destDatabasePath = rootPath + "/data/storage/el2/database";
std::string destInstallPath = rootPath + "/data/storage/el1/bundle";
std::string destel1DataPath = rootPath + "/data/storage/el1/base";
std::string destel2DataPath = rootPath + "/data/storage/el2/base";
int rc = 0;
std::string bundleName = appProperty.bundleName;
oriInstallPath += bundleName;
oriel1DataPath += bundleName;
oriel2DataPath += bundleName;
oriDatabasePath += bundleName;
std::map<std::string, std::string> mountMap;
mountMap[destDatabasePath] = oriDatabasePath;
mountMap[destInstallPath] = oriInstallPath;
mountMap[destel1DataPath] = oriel1DataPath;
mountMap[destel2DataPath] = oriel2DataPath;
std::map<std::string, std::string>::iterator iter;
for (iter = mountMap.begin(); iter != mountMap.end(); ++iter) {
rc = DoAppSandboxMountOnce(iter->second.c_str(), iter->first.c_str());
if (rc) {
return rc;
}
}
// to create some useful dir when mount point created
std::vector<std::string> mkdirInfo;
std::string dirPath;
mkdirInfo.push_back("/data/storage/el1/bundle/nweb");
mkdirInfo.push_back("/data/storage/el1/bundle/ohos.global.systemres");
for (size_t i = 0; i < mkdirInfo.size(); i++) {
dirPath = rootPath + mkdirInfo[i];
mkdir(dirPath.c_str(), FILE_MODE);
}
return 0;
}
static int32_t DoAppSandboxMountCustomized(const AppParameter &appProperty, const std::string &rootPath)
{
std::string bundleName = appProperty.bundleName;
std::string currentUserId = std::to_string(appProperty.uid / UID_BASE);
std::string destInstallPath = rootPath + "/data/storage/el1/bundle";
bool AuthFlag = false;
const std::vector<std::string> AuthAppList = {"com.ohos.launcher", "com.ohos.permissionmanager"};
if (std::find(AuthAppList.begin(), AuthAppList.end(), bundleName) != AuthAppList.end()) {
AuthFlag = true;
}
if (strcmp(appProperty.apl, APL_SYSTEM_BASIC.data()) == 0 ||
strcmp(appProperty.apl, APL_SYSTEM_CORE.data()) == 0 || AuthFlag) {
// account_0/applications/ dir can still access other packages' data now for compatibility purpose
std::string oriapplicationsPath = "/data/app/el1/bundle/public/";
std::string destapplicationsPath = rootPath + "/data/accounts/account_0/applications/";
DoAppSandboxMountOnce(oriapplicationsPath.c_str(), destapplicationsPath.c_str());
// need permission check for system app here
std::string destbundlesPath = rootPath + "/data/bundles/";
DoAppSandboxMountOnce(oriapplicationsPath.c_str(), destbundlesPath.c_str());
}
std::string orimntHmdfsPath = "/mnt/hmdfs/";
std::string destmntHmdfsPath = rootPath + orimntHmdfsPath;
DoAppSandboxMountOnce(orimntHmdfsPath.c_str(), destmntHmdfsPath.c_str());
// Add distributedfile module support, later reconstruct it
std::string oriDistributedPath = "/mnt/hmdfs/" + currentUserId + "/account/merge_view/data/" + bundleName;
std::string destDistributedPath = rootPath + "/data/storage/el2/distributedfiles";
DoAppSandboxMountOnce(oriDistributedPath.c_str(), destDistributedPath.c_str());
std::string oriDistributedGroupPath = "/mnt/hmdfs/" + currentUserId + "/non_account/merge_view/data/" + bundleName;
std::string destDistributedGroupPath = rootPath + "/data/storage/el2/auth_groups";
DoAppSandboxMountOnce(oriDistributedGroupPath.c_str(), destDistributedGroupPath.c_str());
// do nweb adaption
std::string orinwebPath = "/data/app/el1/bundle/public/com.ohos.nweb";
std::string destnwebPath = destInstallPath + "/nweb";
chmod(destnwebPath.c_str(), NWEB_FILE_MODE);
DoAppSandboxMountOnce(orinwebPath.c_str(), destnwebPath.c_str());
// do systemres adaption
std::string oriSysresPath = "/data/app/el1/bundle/public/ohos.global.systemres";
std::string destSysresPath = destInstallPath + "/ohos.global.systemres";
chmod(destSysresPath.c_str(), NWEB_FILE_MODE);
DoAppSandboxMountOnce(oriSysresPath.c_str(), destSysresPath.c_str());
if (bundleName.find("medialibrary") != std::string::npos) {
std::string oriMediaPath = "/storage/media/" + currentUserId;
std::string destMediaPath = rootPath + "/storage/media";
DoAppSandboxMountOnce(oriMediaPath.c_str(), destMediaPath.c_str());
}
return 0;
}
static void DoAppSandboxMkdir(const std::string &sandboxPackagePath, const AppParameter &appProperty)
{
std::vector<std::string> mkdirInfo;
std::string dirPath;
mkdirInfo.push_back("/mnt/");
mkdirInfo.push_back("/mnt/hmdfs/");
mkdirInfo.push_back("/data/");
mkdirInfo.push_back("/storage/");
mkdirInfo.push_back("/storage/media");
mkdirInfo.push_back("/data/storage");
// to create /mnt/sandbox/<packagename>/data/storage/el1 related path, later should delete this code.
mkdirInfo.push_back("/data/storage/el1");
mkdirInfo.push_back("/data/storage/el1/bundle");
mkdirInfo.push_back("/data/storage/el1/base");
mkdirInfo.push_back("/data/storage/el1/database");
mkdirInfo.push_back("/data/storage/el2");
mkdirInfo.push_back("/data/storage/el2/base");
mkdirInfo.push_back("/data/storage/el2/database");
mkdirInfo.push_back("/data/storage/el2/distributedfiles");
mkdirInfo.push_back("/data/storage/el2/auth_groups");
// create applications folder for compatibility purpose
mkdirInfo.push_back("/data/accounts");
mkdirInfo.push_back("/data/accounts/account_0");
mkdirInfo.push_back("/data/accounts/account_0/applications/");
mkdirInfo.push_back("/data/bundles/");
for (size_t i = 0; i < mkdirInfo.size(); i++) {
dirPath = sandboxPackagePath + mkdirInfo[i];
mkdir(dirPath.c_str(), FILE_MODE);
}
}
static int32_t DoSandboxRootFolderCreateAdapt(const std::string &sandboxPackagePath)
{
int rc = mount(nullptr, "/", nullptr, MS_REC | MS_SLAVE, nullptr);
if (rc) {
APPSPAWN_LOGE("set propagation slave failed");
return rc;
}
// bind mount "/" to /mnt/sandbox/<packageName> path
// rootfs: to do more resources bind mount here to get more strict resources constraints
rc = mount("/", sandboxPackagePath.c_str(), nullptr, MS_BIND | MS_REC, nullptr);
if (rc) {
APPSPAWN_LOGE("mount bind / failed");
return rc;
}
return 0;
}
static int32_t DoSandboxRootFolderCreate(const std::string &sandboxPackagePath)
{
int rc = mount(nullptr, "/", nullptr, MS_REC | MS_SLAVE, nullptr);
if (rc) {
return rc;
}
// bind mount sandboxPackagePath to make it a mount point for pivot_root syscall
DoAppSandboxMountOnce(sandboxPackagePath.c_str(), sandboxPackagePath.c_str());
// do /mnt/sandbox/<packageName> path mkdir
std::map<std::string, std::string> mountMap;
std::vector<std::string> vecInfo;
std::string tmpDir = "";
vecInfo.push_back("/config");
vecInfo.push_back("/dev");
vecInfo.push_back("/proc");
vecInfo.push_back("/sys");
vecInfo.push_back("/sys_prod");
vecInfo.push_back("/system");
for (size_t i = 0; i < vecInfo.size(); i++) {
tmpDir = sandboxPackagePath + vecInfo[i];
mkdir(tmpDir.c_str(), FILE_MODE);
mountMap[vecInfo[i]] = tmpDir;
}
// bind mount root folder to /mnt/sandbox/<packageName> path
std::map<std::string, std::string>::iterator iter;
for (iter = mountMap.begin(); iter != mountMap.end(); ++iter) {
rc = DoAppSandboxMountOnce(iter->first.c_str(), iter->second.c_str());
if (rc) {
APPSPAWN_LOGE("move root folder failed, %s", sandboxPackagePath.c_str());
}
}
// to create symlink at /mnt/sandbox/<packageName> path
// bin -> /system/bin
// d -> /sys/kernel/debug
// etc -> /system/etc
// init -> /system/bin/init
// lib -> /system/lib
// sdcard -> /storage/self/primary
std::map<std::string, std::string> symlinkMap;
symlinkMap["/system/bin"] = sandboxPackagePath + "/bin";
symlinkMap["/sys/kernel/debug"] = sandboxPackagePath + "/d";
symlinkMap["/system/etc"] = sandboxPackagePath + "/etc";
symlinkMap["/system/bin/init"] = sandboxPackagePath + "/init";
#ifdef __aarch64__
symlinkMap["/system/lib64"] = sandboxPackagePath + "/lib64";
#else
symlinkMap["/system/lib"] = sandboxPackagePath + "/lib";
#endif
for (iter = symlinkMap.begin(); iter != symlinkMap.end(); ++iter) {
symlink(iter->first.c_str(), iter->second.c_str());
}
return 0;
}
static void MatchSandbox(AppSpawnClientExt *appProperty)
{
if (appProperty == nullptr) {
return;
}
if (strcmp("system_basic", appProperty->property.apl) == 0) {
EnterSandbox("priv-app");
} else if (strcmp("normal", appProperty->property.apl) == 0) {
EnterSandbox("app");
} else if (strcmp("system_core ", appProperty->property.apl) == 0) {
EnterSandbox("app");
} else {
APPSPAWN_LOGE("AppSpawnServer::Failed to match appspawn sandbox %s", appProperty->property.apl);
EnterSandbox("app");
}
}
int32_t SetAppSandboxProperty(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
int rc = 0;
APPSPAWN_CHECK(client != NULL, return -1, "Invalid appspwn client");
AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
MatchSandbox(appProperty);
// create /mnt/sandbox/<packagename> path<74>?later put it to rootfs module
std::string sandboxPackagePath = "/";
sandboxPackagePath += appProperty->property.bundleName;
mkdir(sandboxPackagePath.c_str(), FILE_MODE);
// add pid to a new mnt namespace
rc = unshare(CLONE_NEWNS);
if (rc) {
APPSPAWN_LOGE("unshare failed, packagename is %s", appProperty->property.processName);
return rc;
}
// to make wargnar work
if (access("/3rdmodem", F_OK) == 0) {
rc = DoSandboxRootFolderCreateAdapt(sandboxPackagePath);
} else {
rc = DoSandboxRootFolderCreate(sandboxPackagePath);
}
if (rc) {
APPSPAWN_LOGE("DoSandboxRootFolderCreate failed, %s", appProperty->property.processName);
return rc;
}
// to create /mnt/sandbox/<packagename>/data/storage related path
DoAppSandboxMkdir(sandboxPackagePath, appProperty->property);
rc = DoAppSandboxMount(appProperty->property, sandboxPackagePath);
if (rc) {
APPSPAWN_LOGE("DoAppSandboxMount failed, packagename is %s", appProperty->property.processName);
return rc;
}
rc = DoAppSandboxMountCustomized(appProperty->property, sandboxPackagePath);
if (rc) {
APPSPAWN_LOGE("DoAppSandboxMountCustomized failed, packagename is %s", appProperty->property.processName);
return rc;
}
rc = chdir(sandboxPackagePath.c_str());
if (rc) {
APPSPAWN_LOGE("chdir failed, packagename is %s, path is %s", \
appProperty->property.processName, sandboxPackagePath.c_str());
return rc;
}
rc = syscall(SYS_pivot_root, sandboxPackagePath.c_str(), sandboxPackagePath.c_str());
if (rc) {
APPSPAWN_LOGE("pivot root failed, packagename is %s, errno is %d", \
appProperty->property.processName, errno);
return rc;
}
rc = umount2(".", MNT_DETACH);
if (rc) {
APPSPAWN_LOGE("MNT_DETACH failed, packagename is %s", appProperty->property.processName);
return rc;
}
return 0;
}

View File

@ -12,8 +12,8 @@
# limitations under the License.
appspawn_path = "//base/startup/appspawn_standard"
appexecfwk_path = "//foundation/appexecfwk/standard"
aafwk_path = "//foundation/aafwk/standard"
communication_path = "//foundation/communication/ipc"
subsystem_name = "startup"
part_name = "appspawn"
module_output_path = "${part_name}/appspawn_l2"

View File

@ -37,7 +37,6 @@
"//base/startup/appspawn_standard:appspawn",
"//base/startup/appspawn_standard:appspawn.rc",
"//base/startup/appspawn_standard:appspawn_server",
"//base/startup/appspawn_standard:appspawntools",
"//base/startup/appspawn_standard:nweb",
"//base/startup/appspawn_standard/interfaces/innerkits:appspawn_socket_client"
],

137
common/appspawn_server.c Normal file
View File

@ -0,0 +1,137 @@
/*
* 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 "appspawn_server.h"
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef OHOS_DEBUG
#include <time.h>
#endif // OHOS_DEBUG
static int NotifyResToParent(struct AppSpawnContent_ *content, AppSpawnClient *client, int result)
{
if (content->notifyResToParent != NULL) {
content->notifyResToParent(content, client, result);
}
return 0;
}
int DoStartApp(struct AppSpawnContent_ *content, AppSpawnClient *client, char *longProcName, uint32_t longProcNameLen)
{
APPSPAWN_LOGI("DoStartApp id %d longProcNameLen %u", client->id, longProcNameLen);
int32_t ret = 0;
if (content->setAppSandbox) {
ret = content->setAppSandbox(content, client);
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
return ret, "Failed to set app sandbox");
}
if (content->setKeepCapabilities) {
ret = content->setKeepCapabilities(content, client);
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
return ret, "Failed to set KeepCapabilities");
}
if (content->setProcessName) {
ret = content->setProcessName(content, client, longProcName, longProcNameLen);
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
return ret, "Failed to set setProcessName");
}
if (content->setUidGid) {
ret = content->setUidGid(content, client);
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
return ret, "Failed to setUidGid");
}
if (content->setFileDescriptors) {
ret = content->setFileDescriptors(content, client);
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
return ret, "Failed to setFileDescriptors");
}
if (content->setCapabilities) {
ret = content->setCapabilities(content, client);
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
return ret, "Failed to setCapabilities");
}
// notify success to father process and start app process
NotifyResToParent(content, client, 0);
return 0;
}
int AppSpawnProcessMsg(struct AppSpawnContent_ *content, AppSpawnClient *client, pid_t *childPid)
{
APPSPAWN_CHECK(content != NULL, return -1, "Invalid content for appspawn");
APPSPAWN_CHECK(client != NULL && childPid != NULL, return -1, "Invalid client for appspawn");
APPSPAWN_LOGI("AppSpawnProcessMsg id %d 0x%x", client->id, client->flags);
if (content->registerAppSandbox != NULL) {
content->registerAppSandbox(content, client);
}
pid_t pid = fork();
if (pid < 0) {
return -errno;
} else if (pid == 0) {
#ifdef OHOS_DEBUG
struct timespec tmStart = {0};
GetCurTime(&tmStart);
#endif // OHOS_DEBUG
// close socket id and signal for child
if (content->clearEnvironment != NULL) {
content->clearEnvironment(content, client);
}
if (content->setAppAccessToken != NULL) {
content->setAppAccessToken(content, client);
}
int ret = -1;
if (client->flags & APP_COLD_START) {
if (content->coldStartApp != NULL && content->coldStartApp(content, client) == 0) {
_exit(0x7f); // 0x7f user exit
return -1;
} else {
ret = DoStartApp(content, client, content->longProcName, content->longProcNameLen);
}
} else {
ret = DoStartApp(content, client, content->longProcName, content->longProcNameLen);
}
#ifdef OHOS_DEBUG
struct timespec tmEnd = {0};
GetCurTime(&tmEnd);
// 1s = 1000000000ns
long timeUsed = (tmEnd.tv_sec - tmStart.tv_sec) * 1000000000L + (tmEnd.tv_nsec - tmStart.tv_nsec);
APPSPAWN_LOGI("App timeused %d %ld ns.", getpid(), timeUsed);
#endif // OHOS_DEBUG
if (ret == 0 && content->runChildProcessor != NULL) {
content->runChildProcessor(content, client);
}
APPSPAWN_LOGI("App exit %d.", getpid());
_exit(0x7f); // 0x7f user exit
}
*childPid = pid;
return 0;
}
#ifdef OHOS_DEBUG
void GetCurTime(struct timespec *tmCur)
{
if (tmCur == NULL) {
return;
}
if (clock_gettime(CLOCK_REALTIME, tmCur) != 0) {
APPSPAWN_LOGE("[appspawn] invoke, get time failed! err %d", errno);
}
}
#endif // OHOS_DEBUG

116
common/appspawn_server.h Normal file
View File

@ -0,0 +1,116 @@
/*
* 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.
*/
#ifndef APPSPAWN_SERVER_H
#define APPSPAWN_SERVER_H
#include "beget_ext.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef OHOS_DEBUG
#include <time.h>
#endif // OHOS_DEBUG
#ifdef __cplusplus
extern "C" {
#endif
#define UNUSED(x) (void)(x)
#define APP_COLD_START 0x01
#define ERR_PIPE_FAIL (-100)
#define MAX_LEN_SHORT_NAME 16
#define WAIT_DELAY_US (100 * 1000) // 100ms
#define GID_USER_DATA_RW 1008
typedef struct AppSpawnClient_ {
uint32_t id;
int32_t flags;
} AppSpawnClient;
#define MAX_SOCKEYT_NAME_LEN 128
typedef struct AppSpawnContent_ {
char *longProcName;
uint32_t longProcNameLen;
// system
void (*loadExtendLib)(struct AppSpawnContent_ *content);
void (*initAppSpawn)(struct AppSpawnContent_ *content);
void (*runAppSpawn)(struct AppSpawnContent_ *content, int argc, char *const argv[]);
// for child
void (*clearEnvironment)(struct AppSpawnContent_ *content, AppSpawnClient *client);
void (*setAppAccessToken)(struct AppSpawnContent_ *content, AppSpawnClient *client);
int (*setAppSandbox)(struct AppSpawnContent_ *content, AppSpawnClient *client);
int (*setKeepCapabilities)(struct AppSpawnContent_ *content, AppSpawnClient *client);
int (*setFileDescriptors)(struct AppSpawnContent_ *content, AppSpawnClient *client);
int (*setProcessName)(struct AppSpawnContent_ *content, AppSpawnClient *client,
char *longProcName, uint32_t longProcNameLen);
int (*setUidGid)(struct AppSpawnContent_ *content, AppSpawnClient *client);
int (*setCapabilities)(struct AppSpawnContent_ *content, AppSpawnClient *client);
int (*notifyResToParent)(struct AppSpawnContent_ *content, AppSpawnClient *client, int result);
void (*runChildProcessor)(struct AppSpawnContent_ *content, AppSpawnClient *client);
// for cold start
int (*coldStartApp)(struct AppSpawnContent_ *content, AppSpawnClient *client);
void (*registerAppSandbox)(struct AppSpawnContent_ *content, AppSpawnClient *client);
} AppSpawnContent;
AppSpawnContent *AppSpawnCreateContent(const char *socketName, char *longProcName, uint32_t longProcNameLen, int cold);
int AppSpawnProcessMsg(struct AppSpawnContent_ *content, AppSpawnClient *client, pid_t *childPid);
int DoStartApp(struct AppSpawnContent_ *content, AppSpawnClient *client, char *longProcName, uint32_t longProcNameLen);
#ifdef OHOS_DEBUG
void GetCurTime(struct timespec* tmCur);
#endif
typedef enum {
DEBUG = 0,
INFO,
WARN,
ERROR,
FATAL,
} AppspawnLogLevel;
void AppspawnLogPrint(AppspawnLogLevel logLevel, const char *file, int line, const char *fmt, ...);
#ifndef FILE_NAME
#define FILE_NAME (strrchr((__FILE__), '/') ? strrchr((__FILE__), '/') + 1 : (__FILE__))
#endif
#define UNUSED(x) (void)(x)
#ifndef APPSPAWN_LABEL
#define APPSPAWN_LABEL "APPSPAWN"
#endif
#define APPSPAWN_DOMAIN (BASE_DOMAIN + 0x11)
#define APPSPAWN_LOGI(fmt, ...) STARTUP_LOGI(APPSPAWN_DOMAIN, APPSPAWN_LABEL, fmt, ##__VA_ARGS__)
#define APPSPAWN_LOGE(fmt, ...) STARTUP_LOGE(APPSPAWN_DOMAIN, APPSPAWN_LABEL, fmt, ##__VA_ARGS__)
#define APPSPAWN_LOGV(fmt, ...) STARTUP_LOGV(APPSPAWN_DOMAIN, APPSPAWN_LABEL, fmt, ##__VA_ARGS__)
#define APPSPAWN_LOGW(fmt, ...) STARTUP_LOGW(APPSPAWN_DOMAIN, APPSPAWN_LABEL, fmt, ##__VA_ARGS__)
#define APPSPAWN_CHECK(retCode, exper, ...) \
if (!(retCode)) { \
APPSPAWN_LOGE(__VA_ARGS__); \
exper; \
}
#ifdef __cplusplus
}
#endif
#endif // APPSPAWN_SERVER_H

View File

@ -21,10 +21,10 @@ config("exported_header_files") {
ohos_static_library("appspawn_socket_client") {
sources = [
"${appspawn_path}/src/socket/appspawn_socket.cpp",
"${appspawn_path}/src/socket/client_socket.cpp",
"client/appspawn_socket.cpp",
"client/client_socket.cpp",
]
include_dirs = [ "${appspawn_path}/include" ]
include_dirs = [ "include" ]
public_configs = [ ":exported_header_files" ]
deps = [ "//utils/native/base:utils" ]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]

View File

@ -90,7 +90,7 @@ int AppSpawnSocket::PackSocketAddr()
int AppSpawnSocket::CreateSocket()
{
int socketFd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
int socketFd = socket(AF_UNIX, SOCK_STREAM, 0); // SOCK_SEQPACKET
if (socketFd < 0) {
HiLog::Error(LABEL, "Failed to create socket: %{public}d", errno);
return (-errno);
@ -123,7 +123,7 @@ int AppSpawnSocket::ReadSocketMessage(int socketFd, void *buf, int len)
ssize_t rLen = TEMP_FAILURE_RETRY(read(socketFd, buf, len));
if (rLen < 0) {
HiLog::Error(LABEL, "Read message from fd %{public}d error %zd: %{public}d", socketFd, rLen, errno);
HiLog::Error(LABEL, "Read message from fd %{public}d error %{public}zd: %{public}d", socketFd, rLen, errno);
return -EFAULT;
}

View File

@ -0,0 +1,80 @@
/*
* 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.
*/
#ifndef APPSPAWN_MSG_H
#define APPSPAWN_MSG_H
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __MUSL__
#define SOCKET_DIR "/dev/unix/socket/"
#else
#define SOCKET_DIR "/dev/socket/"
#endif
#ifdef NWEB_SPAWN
#define APPSPAWN_SOCKET_NAME "NWebSpawn"
#else
#define APPSPAWN_SOCKET_NAME "AppSpawn"
#endif
enum AppType {
APP_TYPE_DEFAULT = 0, // JavaScript app
APP_TYPE_NATIVE // Native C++ app
};
typedef enum AppOperateType_ {
DEFAULT = 0,
GET_RENDER_TERMINATION_STATUS,
} AppOperateType;
#define APP_MSG_MAX_SIZE 4096 // appspawn message max size
#define APP_LEN_PROC_NAME 256 // process name length
#define APP_LEN_BUNDLE_NAME 256 // bundle name length
#define APP_LEN_SO_PATH 256 // load so lib
#define APP_MAX_GIDS 64
#define APP_APL_MAX_LEN 32
#define APP_RENDER_CMD_MAX_LEN 1024
#define APP_COLD_BOOT 0x01
#define BITLEN32 32
#define FDLEN2 2
#define FD_INIT_VALUE 0
typedef struct AppParameter_ {
uint32_t uid; // the UNIX uid that the child process setuid() to after fork()
uint32_t gid; // the UNIX gid that the child process setgid() to after fork()
uint32_t gidTable[APP_MAX_GIDS]; // a list of UNIX gids that the child process setgroups() to after fork()
uint32_t gidCount; // the size of gidTable
char processName[APP_LEN_PROC_NAME]; // process name
char bundleName[APP_LEN_BUNDLE_NAME]; // bundle name
char soPath[APP_LEN_SO_PATH]; // so lib path
uint32_t accessTokenId;
char apl[APP_APL_MAX_LEN];
char renderCmd[APP_RENDER_CMD_MAX_LEN];
uint32_t flags;
int32_t pid; // query render process exited status by render process pid
AppOperateType code;
} AppParameter;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -4,7 +4,7 @@
* 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
* 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,
@ -12,19 +12,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BASE_STARTUP_APPSPAWN_SERVICE_H
#define BASE_STARTUP_APPSPAWN_SERVICE_H
#ifndef FOUNDATION_APPEXECFWK_MAIN_THREAD_H
#define FOUNDATION_APPEXECFWK_MAIN_THREAD_H
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
namespace OHOS {
namespace AppExecFwk {
class MainThread {
public:
MainThread() = default;
virtual ~MainThread() = default;
#define APPSPAWN_SERVICE_NAME "appspawn"
static void Start();
enum APPSPAWN_FUNCID {
ID_CALL_CREATE_SERVICE = 0,
ID_CALL_BUT
};
} // namespace AppExecFwk
} // namespace OHOS
#endif // MOCK_FOUNDATION_APPEXECFWK_MAIN_THREAD_H
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif // BASE_STARTUP_APPSPAWN_SERVICE_H

40
interfaces/innerkits/include/client_socket.h Executable file → Normal file
View File

@ -17,6 +17,7 @@
#define APPSPAWN_SOCKET_CLIENT_H
#include "appspawn_socket.h"
#include "appspawn_msg.h"
#include "nocopyable.h"
namespace OHOS {
@ -83,36 +84,17 @@ public:
APP_TYPE_NATIVE // Native C++ app
};
static constexpr int APPSPAWN_MSG_MAX_SIZE = 4096; // appspawn message max size
static constexpr int LEN_PROC_NAME = 256; // process name length
static constexpr int LEN_BUNDLE_NAME = 256; // bundle name length
static constexpr int LEN_SO_PATH = 256; // load so lib
static constexpr int MAX_GIDS = 64;
static constexpr int APL_MAX_LEN = 32;
static constexpr int RENDER_CMD_MAX_LEN = 1024;
static constexpr int APPSPAWN_COLD_BOOT = 0x01;
enum AppOperateCode {
DEFAULT = 0,
GET_RENDER_TERMINATION_STATUS,
};
struct AppProperty {
uint32_t uid; // the UNIX uid that the child process setuid() to after fork()
uint32_t gid; // the UNIX gid that the child process setgid() to after fork()
uint32_t gidTable[MAX_GIDS]; // a list of UNIX gids that the child process setgroups() to after fork()
uint32_t gidCount; // the size of gidTable
char processName[LEN_PROC_NAME]; // process name
char bundleName[LEN_BUNDLE_NAME]; // bundle name
char soPath[LEN_SO_PATH]; // so lib path
uint32_t accessTokenId;
char apl[APL_MAX_LEN];
char renderCmd[RENDER_CMD_MAX_LEN];
uint32_t flags;
int32_t pid; // query render process exited status by render process pid
AppOperateCode code;
};
static constexpr int APPSPAWN_MSG_MAX_SIZE = APP_MSG_MAX_SIZE; // appspawn message max size
static constexpr int LEN_PROC_NAME = APP_LEN_PROC_NAME; // process name length
static constexpr int LEN_BUNDLE_NAME = APP_LEN_BUNDLE_NAME; // bundle name length
static constexpr int LEN_SO_PATH = APP_LEN_SO_PATH; // load so lib
static constexpr int MAX_GIDS = APP_MAX_GIDS;
static constexpr int APL_MAX_LEN = APP_APL_MAX_LEN;
static constexpr int RENDER_CMD_MAX_LEN = APP_RENDER_CMD_MAX_LEN;
static constexpr int APPSPAWN_COLD_BOOT = APP_COLD_BOOT;
using AppProperty = AppParameter;
using AppOperateCode = AppOperateType;
private:
/**
* Connects a client socket.

83
lite/BUILD.gn Normal file
View File

@ -0,0 +1,83 @@
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/lite/config/component/lite_component.gni")
import("//build/lite/config/subsystem/aafwk/config.gni")
lite_component("appspawn_lite") {
features = [ ":appspawn" ]
}
# feature: appspawn
executable("appspawn") {
sources = [
"../adapter/appspawn_log.cpp",
"../common/appspawn_server.c",
"appspawn_message.c",
"appspawn_process.c",
"appspawn_service.c",
"main.c",
]
ldflags = [
"-lstdc++",
"-ldl",
]
cflags = [
"-Wall",
"-Wno-format",
"-Wno-format-extra-args",
]
defines = [ "_GNU_SOURCE" ]
include_dirs = [
".",
"../common",
"//base/startup/appspawn_standard/interfaces/innerkits/include",
"//base/startup/init_lite/interfaces/innerkits/include",
"//foundation/distributedschedule/samgr_lite/interfaces/kits/samgr",
"//foundation/distributedschedule/samgr_lite/interfaces/kits/registry",
"${aafwk_lite_path}/interfaces/innerkits/abilitymgr_lite",
"//third_party/bounds_checking_function/include/",
"//third_party/cJSON",
"//utils/native/lite/include",
]
deps = [
"${aafwk_lite_path}/frameworks/ability_lite:aafwk_abilitykit_lite",
"//base/startup/init_lite/interfaces/innerkits:libbegetutil",
"//build/lite/config/component/cJSON:cjson_shared",
"//foundation/communication/ipc_lite:liteipc_adapter",
"//foundation/distributedschedule/samgr_lite/samgr:samgr",
"//third_party/bounds_checking_function:libsec_shared",
"//utils/native/lite/kv_store:kv_store",
]
if (enable_ohos_appexecfwk_feature_ability == true) {
deps += [
"//foundation/ace/ace_engine_lite/frameworks:ace_lite",
"//foundation/graphic/surface:lite_surface",
"//foundation/graphic/ui:lite_ui",
"//foundation/graphic/utils:lite_graphic_utils",
]
}
if (ohos_kernel_type == "liteos_a") {
deps += [ "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared" ]
}
if (ohos_kernel_type == "linux") {
include_dirs += []
}
}

204
lite/appspawn_message.c Normal file
View File

@ -0,0 +1,204 @@
/*
* 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 "appspawn_message.h"
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#ifdef __LINUX__
#include <linux/capability.h>
#else
#include <sys/capability.h>
#endif
#include "appspawn_server.h"
#include "cJSON.h"
#include "ohos_errno.h"
#include "securec.h"
static const size_t MAX_BUNDLE_NAME_LEN = 127;
static const size_t MIN_BUNDLE_NAME_LEN = 7;
static const size_t MAX_IDENTITY_ID_LEN = 24;
static const size_t MIN_IDENTITY_ID_LEN = 1;
static const size_t MAX_CAPABILITY_COUNT = 10;
void FreeMessageSt(MessageSt *targetSt)
{
if (targetSt != NULL) {
if (targetSt->bundleName != NULL) {
free(targetSt->bundleName);
targetSt->bundleName = NULL;
}
if (targetSt->identityID != NULL) {
free(targetSt->identityID);
targetSt->identityID = NULL;
}
if (targetSt->caps != NULL) {
free(targetSt->caps);
targetSt->caps = NULL;
}
targetSt->uID = -1;
targetSt->gID = -1;
targetSt->capsCnt = 0;
}
}
static enum OHOSLiteErrorCode ReadStringItem(cJSON *strItem, char **buf, size_t maxLen, size_t minLen)
{
if (strItem == NULL || !cJSON_IsString(strItem)) {
return EC_INVALID;
}
char *strPtr = cJSON_GetStringValue(strItem);
if (strPtr == NULL) {
return EC_PROTOCOL;
}
size_t strLength = strlen(strPtr);
if (strLength > maxLen || strLength < minLen) {
return EC_PROTOCOL;
}
char *bufTmp = (char *)malloc(strLength + 1);
if (bufTmp == NULL) {
return EC_NOMEMORY;
}
if (strLength > 0 && memcpy_s(bufTmp, strLength, strPtr, strLength) != EOK) {
free(bufTmp);
bufTmp = NULL;
return EC_FAILURE;
}
bufTmp[strLength] = '\0';
*buf = bufTmp;
return EC_SUCCESS;
}
static double ReadNumberItem(cJSON *strItem)
{
if (strItem == NULL || !cJSON_IsNumber(strItem)) {
return -1;
}
return cJSON_GetNumberValue(strItem);
}
static int GetCaps(const cJSON *curItem, MessageSt *msgSt)
{
msgSt->capsCnt = 0;
msgSt->caps = NULL;
cJSON *capItem = cJSON_GetObjectItem(curItem, "capability");
if (!cJSON_IsArray(capItem)) {
APPSPAWN_LOGE("[appspawn] GetCaps failed, no caps array found.");
return EC_INVALID;
}
// caps array empty, means do not need any capability
int capsCnt = cJSON_GetArraySize(capItem);
if (capsCnt <= 0) {
return EC_SUCCESS;
}
if (capsCnt > MAX_CAPABILITY_COUNT) {
APPSPAWN_LOGE("[appspawn] GetCaps, too many caps[cnt %d], max %d",
capsCnt, MAX_CAPABILITY_COUNT);
return EC_INVALID;
}
msgSt->caps = (unsigned int *)malloc(sizeof(unsigned int) * capsCnt);
if (msgSt->caps == NULL) {
APPSPAWN_LOGE("[appspawn] GetCaps, malloc failed! capsCnt[cnt %d].", capsCnt);
return EC_NOMEMORY;
}
for (int i = 0; i < capsCnt; ++i) {
cJSON *capJ = cJSON_GetArrayItem(capItem, i);
if (!cJSON_IsNumber(capJ) || cJSON_GetNumberValue(capJ) < 0) {
APPSPAWN_LOGE("[appspawn] GetCaps, invalid cap value detected!");
free(msgSt->caps);
msgSt->caps = NULL;
return EC_INVALID;
}
msgSt->caps[i] = (unsigned int)cJSON_GetNumberValue(capJ);
if (msgSt->caps[i] > CAP_LAST_CAP) {
APPSPAWN_LOGE("[appspawn] GetCaps, invalid cap value %u detected!", \
msgSt->caps[i]);
free(msgSt->caps);
msgSt->caps = NULL;
return EC_INVALID;
}
}
msgSt->capsCnt = capsCnt;
return EC_SUCCESS;
}
int SplitMessage(const char *msg, unsigned int msgLen, MessageSt *msgSt)
{
if (msgSt == NULL) {
return EC_INVALID;
}
if (msg == NULL || msgLen == 0) {
FreeMessageSt(msgSt);
return EC_INVALID;
}
cJSON *rootJ = cJSON_ParseWithLength(msg, msgLen);
if (rootJ == NULL) {
FreeMessageSt(msgSt);
return EC_PROTOCOL;
}
cJSON *bundleNameItem = cJSON_GetObjectItem(rootJ, "bundleName");
int ret = (int)ReadStringItem(bundleNameItem, &(msgSt->bundleName), MAX_BUNDLE_NAME_LEN, MIN_BUNDLE_NAME_LEN);
if (ret != EC_SUCCESS) {
FreeMessageSt(msgSt);
cJSON_Delete(rootJ);
return ret;
}
cJSON *identityIDItem = cJSON_GetObjectItem(rootJ, "identityID");
ret = (int)ReadStringItem(identityIDItem, &(msgSt->identityID), MAX_IDENTITY_ID_LEN, MIN_IDENTITY_ID_LEN);
if (ret != EC_SUCCESS) {
FreeMessageSt(msgSt);
cJSON_Delete(rootJ);
return ret;
}
cJSON *uIDItem = cJSON_GetObjectItem(rootJ, "uID");
cJSON *gIDItem = cJSON_GetObjectItem(rootJ, "gID");
msgSt->uID = (int)ReadNumberItem(uIDItem);
msgSt->gID = (int)ReadNumberItem(gIDItem);
ret = GetCaps(rootJ, msgSt);
if (ret != EC_SUCCESS) {
FreeMessageSt(msgSt);
cJSON_Delete(rootJ);
return ret;
}
cJSON_Delete(rootJ);
if (msgSt->uID <= 0 || msgSt->gID <= 0 || msgSt->uID == INT_MAX || msgSt->gID == INT_MAX) {
FreeMessageSt(msgSt);
return EC_PROTOCOL;
}
return EC_SUCCESS;
}

57
lite/appspawn_message.h Normal file
View File

@ -0,0 +1,57 @@
/*
* 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.
*/
#ifndef BASE_STARTUP_APPSPAWN_MESSAGE_H
#define BASE_STARTUP_APPSPAWN_MESSAGE_H
#include <stdint.h>
#include <stdlib.h>
#include "appspawn_server.h"
#include "appspawn_service.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
typedef struct {
char *bundleName;
char *identityID;
int uID;
int gID;
unsigned int *caps;
unsigned int capsCnt;
} MessageSt;
typedef struct {
AppSpawnClient client;
MessageSt message;
} AppSpawnClientLite;
typedef struct {
AppSpawnContent content;
} AppSpawnContentLite;
void SetContentFunction(AppSpawnContent *content);
int SplitMessage(const char *msg, unsigned int msgLen, MessageSt *msgSt);
void FreeMessageSt(MessageSt *targetSt);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif // BASE_STARTUP_APPSPAWN_SERVICE_H

193
lite/appspawn_process.c Normal file
View File

@ -0,0 +1,193 @@
/*
* 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 <errno.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef __LINUX__
#include <linux/capability.h>
#include <linux/securebits.h>
#include <sys/resource.h>
#include <sys/time.h>
#else
#include <sys/capability.h>
#endif // __LINUX__
#include "ability_main.h"
#include "appspawn_message.h"
#include "appspawn_server.h"
#include "appspawn_service.h"
#include "securec.h"
#define DEFAULT_UMASK 022
#define CAP_NUM 2
#define ENV_TITLE "LD_LIBRARY_PATH="
#define UPPER_BOUND_GID 999
#define LOWER_BOUND_GID 100
#define GRP_NUM 2
#define DEVMGR_GRP 99
static int SetAmbientCapability(int cap)
{
#ifdef __LINUX__
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {
printf("[Init] prctl PR_CAP_AMBIENT failed\n");
return -1;
}
#endif
return 0;
}
static int SetCapability(unsigned int capsCnt, const unsigned int *caps)
{
struct __user_cap_header_struct capHeader;
capHeader.version = _LINUX_CAPABILITY_VERSION_3;
capHeader.pid = 0;
// common user, clear all caps
struct __user_cap_data_struct capData[CAP_NUM] = {0};
for (unsigned int i = 0; i < capsCnt; ++i) {
capData[CAP_TO_INDEX(caps[i])].effective |= CAP_TO_MASK(caps[i]);
capData[CAP_TO_INDEX(caps[i])].permitted |= CAP_TO_MASK(caps[i]);
capData[CAP_TO_INDEX(caps[i])].inheritable |= CAP_TO_MASK(caps[i]);
}
if (capset(&capHeader, capData) != 0) {
APPSPAWN_LOGE("[appspawn] capset failed, err: %d.", errno);
return -1;
}
for (unsigned int i = 0; i < capsCnt; ++i) {
if (SetAmbientCapability(caps[i]) != 0) {
APPSPAWN_LOGE("[appspawn] SetAmbientCapability failed, err: %d.", errno);
return -1;
}
}
return 0;
}
static int SetProcessName(struct AppSpawnContent_ *content, AppSpawnClient *client,
char *longProcName, uint32_t longProcNameLen)
{
AppSpawnClientLite *appProperty = (AppSpawnClientLite *)client;
return prctl(PR_SET_NAME, appProperty->message.bundleName);
}
static int SetKeepCapabilities(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
APPSPAWN_LOGE("SetKeepCapabilities");
#ifdef __LINUX__
if (prctl(PR_SET_SECUREBITS, SECBIT_NO_SETUID_FIXUP | SECBIT_NO_SETUID_FIXUP_LOCKED)) {
printf("prctl failed\n");
return -1;
}
#endif
return 0;
}
static int SetUidGid(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
AppSpawnClientLite *appProperty = (AppSpawnClientLite *)client;
APPSPAWN_LOGE("SetUidGid %d %d", appProperty->message.uID, appProperty->message.gID);
if (setgid(appProperty->message.gID) != 0) {
APPSPAWN_LOGE("[appspawn] setgid failed, gID %u, err: %d.", appProperty->message.gID, errno);
return -1;
}
if (setuid(appProperty->message.uID) != 0) {
APPSPAWN_LOGE("[appspawn] setuid failed, uID %u, err: %d.", appProperty->message.uID, errno);
return -1;
}
gid_t groups[GRP_NUM];
// add device groups for system app
if (appProperty->message.gID >= LOWER_BOUND_GID && appProperty->message.gID <= UPPER_BOUND_GID) {
groups[0] = appProperty->message.gID;
groups[1] = DEVMGR_GRP;
if (setgroups(GRP_NUM, groups)) {
APPSPAWN_LOGE("[appspawn] setgroups failed, uID %u, err: %d.", appProperty->message.uID, errno);
return -1;
}
}
// umask call always succeeds and return the previous mask value which is not needed here
(void)umask(DEFAULT_UMASK);
return 0;
}
static int SetCapabilities(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
AppSpawnClientLite *appProperty = (AppSpawnClientLite *)client;
APPSPAWN_LOGE("SetCapabilities appProperty->message.capsCnt %d", appProperty->message.capsCnt);
// set rlimit
#ifdef __LINUX__
static const rlim_t DEFAULT_RLIMIT = 40;
struct rlimit rlim = {0};
rlim.rlim_cur = DEFAULT_RLIMIT;
rlim.rlim_max = DEFAULT_RLIMIT;
if (setrlimit(RLIMIT_NICE, &rlim) != 0) {
APPSPAWN_LOGE("[appspawn] setrlimit failed, err: %d.", errno);
return -1;
}
unsigned int tmpCaps[] = {17}; // 17 means CAP_SYS_RAWIO
unsigned int tmpsCapCnt = sizeof(tmpCaps) / sizeof(tmpCaps[0]);
if (SetCapability(tmpsCapCnt, tmpCaps) != 0) {
APPSPAWN_LOGE("[appspawn] setrlimit failed, err: %d.", errno);
return -1;
}
#else
if (SetCapability(appProperty->message.capsCnt, appProperty->message.caps) != 0) {
APPSPAWN_LOGE("[appspawn] SetCapability failed, err: %d.", errno);
return -1;
}
#endif // __LINUX__
APPSPAWN_LOGE("SetCapabilities appProperty->message.capsCnt %d", appProperty->message.capsCnt);
return 0;
}
static void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
{
APPSPAWN_LOGI("AbilityMain");
AppSpawnClientLite *appProperty = (AppSpawnClientLite *)client;
APPSPAWN_LOGI("[appspawn] invoke, msg<%s,%s,%d,%d>",
appProperty->message.bundleName, appProperty->message.identityID, appProperty->message.uID,
appProperty->message.gID);
if (AbilityMain(appProperty->message.identityID) != 0) {
APPSPAWN_LOGE("[appspawn] AbilityMain execute failed, pid %d.", getpid());
exit(0x7f); // 0x7f: user specified
}
}
void SetContentFunction(AppSpawnContent *content)
{
APPSPAWN_LOGI("SetContentFunction");
content->setProcessName = SetProcessName;
content->setKeepCapabilities = SetKeepCapabilities;
content->setUidGid = SetUidGid;
content->setCapabilities = SetCapabilities;
content->runChildProcessor = RunChildProcessor;
content->setFileDescriptors = NULL;
content->setAppSandbox = NULL;
content->setAppAccessToken = NULL;
content->notifyResToParent = NULL;
content->loadExtendLib = NULL;
content->initAppSpawn = NULL;
content->runAppSpawn = NULL;
content->clearEnvironment = NULL;
}

206
lite/appspawn_service.c Normal file
View File

@ -0,0 +1,206 @@
/*
* 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.
*/
#ifdef OHOS_DEBUG
#include <errno.h>
#include <time.h>
#endif // OHOS_DEBUG
#include "appspawn_message.h"
#include "appspawn_server.h"
#include "iproxy_server.h"
#include "iunknown.h"
#include "liteipc_adapter.h"
#include "message.h"
#include "ohos_errno.h"
#include "ohos_init.h"
#include "samgr_lite.h"
#include "service.h"
static const int INVALID_PID = -1;
static const int CLIENT_ID = 100;
typedef struct AppSpawnFeatureApi {
INHERIT_SERVER_IPROXY;
} AppSpawnFeatureApi;
typedef struct AppSpawnService {
INHERIT_SERVICE;
INHERIT_IUNKNOWNENTRY(AppSpawnFeatureApi);
Identity identity;
} AppSpawnService;
static const char *GetName(Service *service)
{
(void)service;
APPSPAWN_LOGI("[appspawn] get service name %s.", APPSPAWN_SERVICE_NAME);
return APPSPAWN_SERVICE_NAME;
}
static BOOL Initialize(Service *service, Identity identity)
{
if (service == NULL) {
APPSPAWN_LOGE("[appspawn] initialize, service NULL!");
return FALSE;
}
AppSpawnService *spawnService = (AppSpawnService *)service;
spawnService->identity = identity;
APPSPAWN_LOGI("[appspawn] initialize, identity<%d, %d, %p>", \
identity.serviceId, identity.featureId, identity.queueId);
return TRUE;
}
static BOOL MessageHandle(Service *service, Request *msg)
{
(void)service;
(void)msg;
APPSPAWN_LOGE("[appspawn] message handle not support yet!");
return FALSE;
}
static TaskConfig GetTaskConfig(Service *service)
{
(void)service;
TaskConfig config = {LEVEL_HIGH, PRI_BELOW_NORMAL, 0x800, 20, SHARED_TASK};
return config;
}
static int GetMessageSt(MessageSt *msgSt, IpcIo *req)
{
if (msgSt == NULL || req == NULL) {
return EC_FAILURE;
}
#ifdef __LINUX__
size_t len = 0;
char *str = IpcIoPopString(req, &len);
if (str == NULL || len == 0) {
APPSPAWN_LOGE("[appspawn] invoke, get data failed.");
return EC_FAILURE;
}
int ret = SplitMessage(str, len, msgSt); // after split message, str no need to free(linux version)
#else
BuffPtr *dataPtr = IpcIoPopDataBuff(req);
if (dataPtr == NULL) {
APPSPAWN_LOGE("[appspawn] invoke, get data failed.");
return EC_FAILURE;
}
int ret = SplitMessage((char *)dataPtr->buff, dataPtr->buffSz, msgSt);
// release buffer
if (FreeBuffer(NULL, dataPtr->buff) != LITEIPC_OK) {
APPSPAWN_LOGE("[appspawn] invoke, free buffer failed!");
}
#endif
return ret;
}
static AppSpawnContentLite *g_appSpawnContentLite = NULL;
AppSpawnContent *AppSpawnCreateContent(const char *socketName, char *longProcName, uint32_t longProcNameLen, int cold)
{
UNUSED(longProcName);
UNUSED(longProcNameLen);
APPSPAWN_LOGI("AppSpawnCreateContent %s", socketName);
AppSpawnContentLite *appSpawnContent = (AppSpawnContentLite *)malloc(sizeof(AppSpawnContentLite));
APPSPAWN_CHECK(appSpawnContent != NULL, return NULL, "Failed to alloc memory for appspawn");
appSpawnContent->content.longProcName = NULL;
appSpawnContent->content.longProcNameLen = NULL;
g_appSpawnContentLite = appSpawnContent;
return appSpawnContent;
}
static int Invoke(IServerProxy *iProxy, int funcId, void *origin, IpcIo *req, IpcIo *reply)
{
#ifdef OHOS_DEBUG
struct timespec tmStart = {0};
GetCurTime(&tmStart);
#endif // OHOS_DEBUG
(void)iProxy;
(void)origin;
if (reply == NULL || funcId != ID_CALL_CREATE_SERVICE || req == NULL) {
APPSPAWN_LOGE("[appspawn] invoke, funcId %d invalid, reply %d.", funcId, INVALID_PID);
IpcIoPushInt64(reply, INVALID_PID);
return EC_BADPTR;
}
AppSpawnClientLite *client = (AppSpawnClientLite *)malloc(sizeof(AppSpawnClientLite));
APPSPAWN_CHECK(client != NULL, return -1, "malloc AppSpawnClientLite Failed");
client->client.id = CLIENT_ID;
client->client.flags = 0;
if (GetMessageSt(&client->message, req) != EC_SUCCESS) {
APPSPAWN_LOGE("[appspawn] invoke, parse failed! reply %d.", INVALID_PID);
IpcIoPushInt64(reply, INVALID_PID);
return EC_FAILURE;
}
APPSPAWN_LOGI("[appspawn] invoke, msg<%s,%s,%d,%d %d>", client->message.bundleName, client->message.identityID,
client->message.uID, client->message.gID, client->message.capsCnt);
pid_t newPid = 0;
int ret = AppSpawnProcessMsg(g_appSpawnContentLite, &client->client, &newPid);
if (ret != 0) {
newPid = -1;
}
FreeMessageSt(&client->message);
IpcIoPushInt64(reply, newPid);
#ifdef OHOS_DEBUG
struct timespec tmEnd = {0};
GetCurTime(&tmEnd);
// 1s = 1000000000ns
long timeUsed = (tmEnd.tv_sec - tmStart.tv_sec) * 1000000000L + (tmEnd.tv_nsec - tmStart.tv_nsec);
APPSPAWN_LOGI("[appspawn] invoke, reply pid %d, timeused %ld ns.", newPid, timeUsed);
#else
APPSPAWN_LOGI("[appspawn] invoke, reply pid %d.", newPid);
#endif // OHOS_DEBUG
return ((newPid > 0) ? EC_SUCCESS : EC_FAILURE);
}
static AppSpawnService g_appSpawnService = {
.GetName = GetName,
.Initialize = Initialize,
.MessageHandle = MessageHandle,
.GetTaskConfig = GetTaskConfig,
SERVER_IPROXY_IMPL_BEGIN,
.Invoke = Invoke,
IPROXY_END,
};
void AppSpawnInit(void)
{
if (SAMGR_GetInstance()->RegisterService((Service *)&g_appSpawnService) != TRUE) {
APPSPAWN_LOGE("[appspawn] register service failed!");
return;
}
APPSPAWN_LOGI("[appspawn] register service succeed. %p.", &g_appSpawnService);
if (SAMGR_GetInstance()->RegisterDefaultFeatureApi(APPSPAWN_SERVICE_NAME, \
GET_IUNKNOWN(g_appSpawnService)) != TRUE) {
(void)SAMGR_GetInstance()->UnregisterService(APPSPAWN_SERVICE_NAME);
APPSPAWN_LOGE("[appspawn] register featureapi failed!");
return;
}
APPSPAWN_LOGI("[appspawn] register featureapi succeed.");
}
SYSEX_SERVICE_INIT(AppSpawnInit);

44
lite/bundle.json Normal file
View File

@ -0,0 +1,44 @@
{
"name": "@ohos/startup_appspawn_lite",
"description": "lite app start manager",
"homePage": "https://gitee.com/openharmony",
"version": "3.1",
"license": "Apache License 2.0",
"repository": "https://gitee.com/openharmony/appspawn_standard",
"publishAs": "code-segment",
"segment": {
"destPath": "base/startup/appspawn_standard/lite"
},
"dirs": {},
"scripts": {},
"component": {
"name": "appspawn_lite",
"subsystem": "startup",
"adapted_system_type": [
"small"
],
"rom": "26KB",
"ram": "~1.8M",
"deps": {
"components": [
"hilog_lite",
"samgr_lite",
"ipc_lite",
"kv_store",
"aafwk_lite",
"ace_engine_lite",
"surface",
"ui"
],
"third_party": [
"cJSON",
"bounds_checking_function"
]
},
"build": {
"sub_component": [
"//base/startup/appspawn_standard/lite:appspawn_lite"
]
}
}
}

85
lite/main.c Normal file
View File

@ -0,0 +1,85 @@
/*
* 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 <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "samgr_lite.h"
#include "appspawn_server.h"
#include "appspawn_service.h"
void __attribute__((weak)) HOS_SystemInit(void)
{
SAMGR_Bootstrap();
APPSPAWN_LOGI("[appspawn] HOS_SystemInit is called!");
}
static void SignalHandler(int sig)
{
switch (sig) {
case SIGCHLD: {
pid_t sigPID;
int procStat = 0;
while (1) {
sigPID = waitpid(-1, &procStat, WNOHANG);
if (sigPID <= 0) {
break;
}
APPSPAWN_LOGE("SignalHandler sigPID %d.", sigPID);
}
break;
}
default:
break;
}
}
void SignalRegist(void)
{
struct sigaction act;
act.sa_handler = SignalHandler;
act.sa_flags = SA_RESTART;
if (sigfillset(&act.sa_mask) != 0) {
APPSPAWN_LOGE("[appspawn] sigfillset failed! err %d.", errno);
}
if (sigaction(SIGCHLD, &act, NULL) != 0) {
APPSPAWN_LOGE("[appspawn] sigaction failed! err %d.", errno);
}
}
int main(int argc, char * const argv[])
{
sleep(1);
APPSPAWN_LOGI("[appspawn] main, enter.");
AppSpawnContent *content = AppSpawnCreateContent("AppSpawn", NULL, 0, 0);
SetContentFunction(content);
// 1. ipc module init
HOS_SystemInit();
// 2. register signal for SIGCHLD
SignalRegist();
// 3. keep process alive
APPSPAWN_LOGI("[appspawn] main, entering wait.");
while (1) {
// pause only returns when a signal was caught and the signal-catching function returned.
// pause only returns -1, no need to process the return value.
(void)pause();
}
}

View File

@ -5,7 +5,7 @@
"socket" : [{
"name" : "NWebSpawn",
"family" : "AF_LOCAL",
"type" : "SOCK_SEQPACKET",
"type" : "SOCK_STREAM",
"protocol" : "default",
"permissions" : "0666",
"uid" : "root",

View File

@ -1,96 +0,0 @@
/*
* 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 "appspawn_msg_peer.h"
#include <memory>
#include "hilog/log.h"
#include "securec.h"
namespace OHOS {
namespace AppSpawn {
using namespace OHOS::HiviewDFX;
static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "AppSpawnMain"};
AppSpawnMsgPeer::AppSpawnMsgPeer(const std::shared_ptr<ServerSocket> &socket, int connectFd)
: connectFd_(connectFd), socket_(socket)
{}
AppSpawnMsgPeer::~AppSpawnMsgPeer()
{
if ((socket_ != nullptr) && (connectFd_ >= 0)) {
socket_->CloseConnection(connectFd_);
}
}
ClientSocket::AppProperty *AppSpawnMsgPeer::GetMsg() const
{
return reinterpret_cast<ClientSocket::AppProperty *>(buf_.get());
}
int AppSpawnMsgPeer::GetConnectFd() const
{
return connectFd_;
}
int AppSpawnMsgPeer::Response(pid_t pid)
{
if ((socket_ == nullptr) || (connectFd_ < 0)) {
HiLog::Error(LABEL, "Invalid socket params: connectFd %{public}d", connectFd_);
return -EINVAL;
}
if (socket_->WriteSocketMessage(connectFd_, &pid, sizeof(pid)) != sizeof(pid)) {
HiLog::Error(LABEL, "Failed to write message: connectFd %{public}d", connectFd_);
return (-errno);
}
return 0;
}
int AppSpawnMsgPeer::MsgPeer()
{
if ((socket_ == nullptr) || (connectFd_ < 0)) {
HiLog::Error(LABEL, "Failed to init socket: connectFd %{public}d", connectFd_);
return -EINVAL;
}
int32_t msgLen = sizeof(ClientSocket::AppProperty);
buf_ = std::make_unique<int8_t[]>(msgLen);
if (buf_ == nullptr) {
HiLog::Error(LABEL, "buf_ is null pointer!");
return -EINVAL;
}
int32_t rLen = 0;
for (int8_t *offset = buf_.get(); msgLen > 0; offset += rLen, msgLen -= rLen) {
rLen = socket_->ReadSocketMessage(connectFd_, offset, msgLen);
if (rLen == 0) {
HiLog::Info(LABEL, "AppSpawnMsgPeer::MsgPeer ReadSocketMessage function value is 0.");
break;
}
if ((rLen < 0) || (rLen > msgLen)) {
HiLog::Error(LABEL, "AppSpawnMsgPeer::Failed to read msg from socket %{public}d", connectFd_);
return -EINVAL;
}
}
return 0;
}
} // namespace AppSpawn
} // namespace OHOS

File diff suppressed because it is too large Load Diff

View File

@ -1,79 +0,0 @@
/*
* 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.
*/
#ifndef APPSPAWN_MSG_PEER_H
#define APPSPAWN_MSG_PEER_H
#include <string>
#include "client_socket.h"
#include "server_socket.h"
#include "nocopyable.h"
namespace OHOS {
namespace AppSpawn {
class AppSpawnMsgPeer {
public:
/**
* Constructor used to delete the default constructor.
*/
AppSpawnMsgPeer() = delete;
/**
* Constructor used to create a AppSpawnMsgPeer.
*/
AppSpawnMsgPeer(const std::shared_ptr<ServerSocket> &socket, int connectFd);
/**
* Destructor used to destroy a AppSpawnMsgPeer
*/
~AppSpawnMsgPeer();
/**
* Disables copy and moving of AppSpawnMsgPeer.
*/
DISALLOW_COPY_AND_MOVE(AppSpawnMsgPeer);
/**
* Gets the message about the app property.
*/
ClientSocket::AppProperty *GetMsg() const;
/**
* Returns the PID of the application process in the response sent to the ability manager service
* after AppSpawn forks the application process.
*
* @param pid Indicates the PID of the application process.
*/
int Response(pid_t pid);
/**
* Reads the message from MsgPeer over the socket.
*/
int MsgPeer();
/**
* Gets the connection file description used by the ability manager service to connect to AppSpawn.
*/
int GetConnectFd() const;
private:
int connectFd_ = -1;
std::shared_ptr<ServerSocket> socket_ = nullptr;
std::unique_ptr<int8_t[]> buf_ = nullptr;
};
} // namespace AppSpawn
} // namespace OHOS
#endif

View File

@ -1,224 +0,0 @@
/*
* 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.
*/
#ifndef APPSPAWN_SERVER_H
#define APPSPAWN_SERVER_H
#include <queue>
#include <string>
#include <map>
#include "appspawn_msg_peer.h"
#include "server_socket.h"
#include "nocopyable.h"
namespace OHOS {
namespace AppSpawn {
class AppSpawnServer {
public:
/**
* Constructor used to delete the default constructor.
*/
AppSpawnServer() = delete;
/**
* Constructor used to create a AppSpawnServer.
*/
explicit AppSpawnServer(const std::string &socketName);
/**
* Destructor used to destroy a AppSpawnServer
*/
~AppSpawnServer() = default;
/**
* Disables copying and moving for the AppSpawnServer.
*/
DISALLOW_COPY_AND_MOVE(AppSpawnServer);
/**
* Provides the AppSpawn core function for the server to receive messages from ability manager service.
*
* @param longProcName Indicates the long process name.
* @param longProcNameLen Indicates the length of long process name.
*/
bool ServerMain(char *longProcName, int64_t longProcNameLen);
/**
* Controls the server listening socket.
*
* @param isRunning Indicates whether the server is running. Value false means to stop the server and exit.
*/
void SetRunning(bool isRunning);
/**
* Set its value to the member variable socket_.
*
* @param serverSocket Indicates the server socket.
*/
void SetServerSocket(const std::shared_ptr<ServerSocket> &serverSocket);
int AppColdStart(char *longProcName,
int64_t longProcNameLen, const ClientSocket::AppProperty *appProperty, int fd);
private:
int DoColdStartApp(ClientSocket::AppProperty *appProperty, int fd);
static constexpr uint8_t BITLEN32 = 32;
static constexpr uint8_t FDLEN2 = 2;
static constexpr uint8_t FD_INIT_VALUE = 0;
/**
* Use the MsgPeer method in the AppSpawnMsgPeer class to read message from socket, and notify the ServerMain to
* unlock.
*
* @param connectFd Indicates the connect FDs.
*/
void MsgPeer(int connectFd);
/**
* Gets the connect fd and creates a thread to receive messages.
*/
void ConnectionPeer();
/**
* Sets a name for an application process.
*
* @param longProcName Indicates the length of long process name.
* @param longProcNameLen Indicates the long process name.
* @param processName Indicates the process name from the ability manager service.
* @param len Indicates the size of processName.
*/
int32_t SetProcessName(char *longProcName, int64_t longProcNameLen, const char *processName, int32_t len);
/**
* Sets keep capabilities.
*/
int32_t SetKeepCapabilities(uint32_t uid);
/**
* Sets the uid and gid of an application process.
*
* @param uid Indicates the uid of the application process.
* @param gid Indicates the gid of the application process.
* @param gidTable Indicates an array of application processes.
* @param gidCount Indicates the number of GIDs.
*/
int32_t SetUidGid(const uint32_t uid, const uint32_t gid, const uint32_t *gidTable, const uint32_t gidCount);
/**
* Sets FDs in an application process.
*/
int32_t SetFileDescriptors();
/**
* Sets capabilities of an application process.
*/
int32_t SetCapabilities();
/**
* Create sandbox root folder file
*/
int32_t DoSandboxRootFolderCreate(std::string sandboxPackagePath);
/**
* Create sandbox root folder file with wargnar device
*/
int32_t DoSandboxRootFolderCreateAdapt(std::string sandboxPackagePath);
/**
* Do app sandbox original path mount common
*/
int32_t DoAppSandboxMountOnce(const std::string originPath, const std::string destinationPath);
/**
* Do app sandbox original path mount
*/
int32_t DoAppSandboxMount(const ClientSocket::AppProperty *appProperty, std::string rootPath);
/**
* Do app sandbox original path mount for some customized packages
*/
int32_t DoAppSandboxMountCustomized(const ClientSocket::AppProperty *appProperty, std::string rootPath);
/**
* Do app sandbox mkdir /mnt/sandbox/<packagename>/
*/
void DoAppSandboxMkdir(std::string rootPath, const ClientSocket::AppProperty *appProperty);
/**
* Sets app sandbox property.
*/
int32_t SetAppSandboxProperty(const ClientSocket::AppProperty *appProperty);
/**
* Sets app process property.
*/
bool SetAppProcProperty(const ClientSocket::AppProperty *appProperty, char *longProcName,
int64_t longProcNameLen, const int32_t fd);
/**
* Notify
*/
void NotifyResToParentProc(const int32_t fd, const int32_t value);
/**
* Special app process property.
*/
void SpecialHandle(ClientSocket::AppProperty *appProperty);
/**
* Check app process property.
*/
bool CheckAppProperty(const ClientSocket::AppProperty *appProperty);
void LoadAceLib();
void SetAppAccessToken(const ClientSocket::AppProperty *appProperty);
int StartApp(char *longProcName, int64_t longProcNameLen,
ClientSocket::AppProperty *appProperty, int connectFd, pid_t &pid);
void WaitRebootEvent();
void HandleSignal();
void QuickExitMain();
void ProcessAppSpawnMsg(char *longProcName, int64_t longProcNameLen,
const std::unique_ptr<AppSpawnMsgPeer> &msg);
private:
const std::string deviceNull_ = "/dev/null";
std::string socketName_ {};
std::shared_ptr<ServerSocket> socket_ = nullptr;
std::mutex mut_ {};
mutable std::condition_variable dataCond_ {};
std::queue<std::unique_ptr<AppSpawnMsgPeer>> appQueue_ {};
std::function<int(const ClientSocket::AppProperty &)> propertyHandler_ = nullptr;
std::function<void(const std::string &)> errHandlerHook_ = nullptr;
bool isRunning_ {};
bool isStop_ { false };
bool isChildDie_ { false };
pid_t childPid_ {};
std::map<pid_t, std::string> appMap_;
#ifdef NWEB_SPAWN
void *nwebHandle = nullptr;
#endif
};
} // namespace AppSpawn
} // namespace OHOS
#endif

View File

@ -1,132 +0,0 @@
/*
* 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.
*/
#ifndef APPSPAWN_SOCKET_SERVER_H
#define APPSPAWN_SOCKET_SERVER_H
#include <mutex>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>
#include "appspawn_socket.h"
#include "nocopyable.h"
namespace OHOS {
namespace AppSpawn {
class ServerSocket : public AppSpawnSocket {
public:
/**
* Constructor used to create a ServerSocket
*/
explicit ServerSocket(const std::string &server);
/**
* Destructor used to destroy a ServerSocket
*/
virtual ~ServerSocket();
/**
* Disables copying and moving for ServerSocket.
*/
DISALLOW_COPY_AND_MOVE(ServerSocket);
/**
* Closes a socket connection.
*
* @param connectFd Indicates the connection's file descriptor (FD).
*/
virtual void CloseConnection(int connectFd);
/**
* Saves the connection's FD.
*
* @param connectFd Indicates the connection's file descriptor (FD).
*/
virtual void SaveConnection(int connectFd);
/**
* Closes a server socket.
*/
virtual void CloseServer();
/**
* Closes the server monitor.
*/
virtual void CloseServerMonitor();
/**
* Creates server socket, binds socket and listens it.
*
* @return -1:failed; 0:success
*/
virtual int RegisterServerSocket();
/**
* Sets socket option and waits for connection.
*
* @return -1:failed;other means connection FD.
*/
virtual int WaitForConnection();
/**
* Verifies the connection's FD.
*
* @return -1:failed; 0:success
*/
virtual int VerifyConnection(int connectFd);
/**
* Uses functions of the parent class.
*/
using AppSpawnSocket::CloseSocket;
using AppSpawnSocket::CreateSocket;
using AppSpawnSocket::GetSocketFd;
using AppSpawnSocket::ReadSocketMessage;
using AppSpawnSocket::WriteSocketMessage;
static constexpr uid_t APPSPAWN_ID_ROOT = 0; // chown owner
static constexpr gid_t APPSPAWN_ID_SYSTEM = 1000; // chown group
static constexpr mode_t SOCKET_PERM = 0660; // root system can read and write appspawn socket
private:
/**
* Binds a socket and sets socket attributes.
*
* @param connectFd Indicates the connection's FD.
*/
int BindSocket(int connectFd);
/**
* Creates a socket and binds it.
*
* @param connectFd Indicates the connection's FD.
*/
int RegisterServerSocket(int &connectFd);
/**
* Accepts a socket.
*
* @param connectFd Indicates the connection's FD.
*/
int WaitForConnection(int connectFd);
private:
std::vector<int> connectFds_ = {};
std::mutex mutexConnect_;
};
} // namespace AppSpawn
} // namespace OHOS
#endif

View File

@ -1,38 +0,0 @@
/*
* 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 <cstring>
#include "appspawn_server.h"
#include "hilog/log.h"
int main(int argc, char *const argv[])
{
if (argc > 0) {
// calculate child process long name size
uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
uintptr_t end = reinterpret_cast<uintptr_t>(strchr(argv[argc - 1], 0));
uintptr_t argvSize = end - start;
#ifdef NWEB_SPAWN
OHOS::AppSpawn::AppSpawnServer appspawnServer("/dev/unix/socket/NWebSpawn");
#else
OHOS::AppSpawn::AppSpawnServer appspawnServer("AppSpawn");
#endif
appspawnServer.ServerMain(argv[0], argvSize);
}
return 0;
}

View File

@ -1,232 +0,0 @@
/*
* 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 "server_socket.h"
#include <cerrno>
#include <iostream>
#include <sys/socket.h>
#include "hilog/log.h"
#include "init_socket.h"
#include "securec.h"
namespace OHOS {
namespace AppSpawn {
using namespace OHOS::HiviewDFX;
static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "ServerSocket"};
ServerSocket::ServerSocket(const std::string &server) : AppSpawnSocket(server)
{}
ServerSocket::~ServerSocket()
{
CloseServer();
}
int ServerSocket::VerifyConnection(int connectFd)
{
std::lock_guard<std::mutex> lock(mutexConnect_);
std::vector<int>::iterator it = find(connectFds_.begin(), connectFds_.end(), connectFd);
if (it == connectFds_.end()) {
return -1;
}
return 0;
}
void ServerSocket::CloseConnection(int connectFd)
{
if (connectFd < 0) {
HiLog::Error(LABEL, "Server: Invalid connectFd %{public}d", connectFd);
return;
}
std::lock_guard<std::mutex> lock(mutexConnect_);
std::vector<int>::iterator it = find(connectFds_.begin(), connectFds_.end(), connectFd);
if (it == connectFds_.end()) {
close(connectFd);
return;
}
close(connectFd);
connectFds_.erase(it);
HiLog::Debug(LABEL, "Server: Erase connect fd %{public}d from list", connectFd);
}
void ServerSocket::SaveConnection(int connectFd)
{
if (connectFd >= 0) {
std::lock_guard<std::mutex> lock(mutexConnect_);
connectFds_.push_back(connectFd);
}
}
void ServerSocket::CloseServer()
{
std::lock_guard<std::mutex> lock(mutexConnect_);
for (const int &fd : connectFds_) {
HiLog::Debug(LABEL, "Server: Closed connection fd %{public}d", fd);
close(fd);
}
if ((unlink(socketAddr_.sun_path) != 0) && (errno != ENOENT)) {
HiLog::Error(LABEL, "Server: Failed to unlink, err %{public}d", errno);
}
connectFds_.clear();
if (socketFd_ >= 0) {
CloseSocket(socketFd_);
socketFd_ = -1;
}
}
void ServerSocket::CloseServerMonitor()
{
if (socketFd_ >= 0) {
CloseSocket(socketFd_);
socketFd_ = -1;
}
}
int ServerSocket::BindSocket(int connectFd)
{
if (connectFd < 0) {
HiLog::Error(LABEL, "Server: Invalid socket fd: %{public}d", connectFd);
return -EINVAL;
}
if (PackSocketAddr() != 0) {
return -1;
}
if ((unlink(socketAddr_.sun_path) != 0) && (errno != ENOENT)) {
HiLog::Error(LABEL, "Server: Failed to unlink, err %{public}d", errno);
return (-errno);
}
int reuseAddr = 0;
if ((setsockopt(connectFd, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)) != 0) ||
(setsockopt(connectFd, SOL_SOCKET, SO_RCVTIMEO, &SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT)) != 0) ||
(setsockopt(connectFd, SOL_SOCKET, SO_SNDTIMEO, &SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT)) != 0)) {
HiLog::Warn(LABEL, "Server: Failed to set opt of socket %{public}d, err %{public}d", connectFd, errno);
return (-errno);
}
if (bind(connectFd, reinterpret_cast<struct sockaddr *>(&socketAddr_), socketAddrLen_) < 0) {
HiLog::Error(LABEL, "Server: Bind socket fd %{public}d, failed: %{public}d", connectFd, errno);
return (-errno);
}
if (chown(socketAddr_.sun_path, APPSPAWN_ID_ROOT, APPSPAWN_ID_SYSTEM)) {
HiLog::Error(LABEL, "Server: failed to chown socket fd %{public}d, failed: %{public}d", connectFd, errno);
return (-errno);
}
if (chmod(socketAddr_.sun_path, SOCKET_PERM)) {
HiLog::Error(LABEL, "Server: failed to chmod socket fd %{public}d, failed: %{public}d", connectFd, errno);
return (-errno);
}
HiLog::Debug(LABEL, "Server: Bind socket fd %{public}d success", connectFd);
return 0;
}
int ServerSocket::RegisterServerSocket(int &connectFd)
{
if (socketName_.empty()) {
HiLog::Error(LABEL, "Server: Invalid socket name: empty");
return -EINVAL;
}
#ifdef NWEB_SPAWN
connectFd = GetControlSocket("NWebSpawn");
#else
connectFd = CreateSocket();
#endif
if (connectFd < 0) {
return connectFd;
}
#ifndef NWEB_SPAWN
if ((BindSocket(connectFd) != 0) || (listen(connectFd, listenBacklog_) < 0)) {
HiLog::Error(LABEL,
"Server: Register socket fd %{public}d with backlog %{public}d error: %{public}d",
connectFd,
listenBacklog_,
errno);
if ((unlink(socketAddr_.sun_path) != 0) && (errno != ENOENT)) {
HiLog::Error(LABEL, "Server: Failed to unlink, err %{public}d", errno);
}
close(connectFd);
connectFd = -1;
return (-errno);
}
#endif
HiLog::Debug(LABEL, "Server: Suc to register server socket fd %{public}d", connectFd);
return 0;
}
int ServerSocket::RegisterServerSocket()
{
if (socketFd_ >= 0) {
HiLog::Info(LABEL, "Server: Already register server socket %{public}d", socketFd_);
return 0;
}
return RegisterServerSocket(socketFd_);
}
int ServerSocket::WaitForConnection(int connectFd)
{
if (connectFd < 0) {
HiLog::Error(LABEL, "Server: Invalid args: connectFd %{public}d", connectFd);
return -EINVAL;
}
struct sockaddr_un clientAddr;
socklen_t clientLen = sizeof(clientAddr);
if (memset_s(&clientAddr, clientLen, 0, clientLen) != EOK) {
HiLog::Warn(LABEL, "Server: Failed to memset client addr");
return -EINVAL;
}
int connFd = accept(connectFd, reinterpret_cast<struct sockaddr *>(&clientAddr), &clientLen);
if (connFd < 0) {
return (-errno);
}
if ((setsockopt(connFd, SOL_SOCKET, SO_RCVTIMEO, &SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT)) < 0) ||
(setsockopt(connFd, SOL_SOCKET, SO_SNDTIMEO, &SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT)) < 0)) {
HiLog::Warn(LABEL, "Server: Failed to set opt of Connection %{public}d, err %{public}d", connFd, errno);
close(connFd);
return (-errno);
}
HiLog::Debug(LABEL, "Server: Connection accepted, connect fd %{public}d", connFd);
return connFd;
}
int ServerSocket::WaitForConnection()
{
int connectFd = WaitForConnection(socketFd_);
SaveConnection(connectFd);
return connectFd;
}
} // namespace AppSpawn
} // namespace OHOS

385
standard/appspawn_process.c Normal file
View File

@ -0,0 +1,385 @@
/*
* 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 "appspawn_service.h"
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/capability.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/signalfd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "sandbox.h"
#include "appspawn_adapter.h"
#include "securec.h"
#define DEVICE_NULL_STR "/dev/null"
static int SetProcessName(struct AppSpawnContent_ *content, AppSpawnClient *client,
char *longProcName, uint32_t longProcNameLen)
{
AppSpawnClientExt *appPropertyExt = (AppSpawnClientExt *)client;
AppParameter *appProperty = &appPropertyExt->property;
int len = strlen(appProperty->processName);
if (longProcName == NULL || len <= 0) {
APPSPAWN_LOGE("process name is nullptr or length error");
return -EINVAL;
}
char shortName[MAX_LEN_SHORT_NAME] = {0};
// process short name max length 16 bytes.
if (len >= MAX_LEN_SHORT_NAME) {
if (strncpy_s(shortName, MAX_LEN_SHORT_NAME, appProperty->processName, MAX_LEN_SHORT_NAME - 1) != EOK) {
APPSPAWN_LOGE("strncpy_s short name error: %d", errno);
return -EINVAL;
}
} else {
if (strncpy_s(shortName, MAX_LEN_SHORT_NAME, appProperty->processName, len) != EOK) {
APPSPAWN_LOGE("strncpy_s short name error: %d", errno);
return -EINVAL;
}
}
// set short name
if (prctl(PR_SET_NAME, shortName) == -1) {
APPSPAWN_LOGE("prctl(PR_SET_NAME) error: %d", errno);
return (-errno);
}
// reset longProcName
if (memset_s(longProcName, (size_t)longProcNameLen, 0, (size_t)longProcNameLen) != EOK) {
APPSPAWN_LOGE("Failed to memset long process name");
return -EINVAL;
}
// set long process name
if (strncpy_s(longProcName, sizeof(appProperty->processName) - 1, appProperty->processName, len) != EOK) {
APPSPAWN_LOGE("strncpy_s long name error: %d longProcNameLen %u", errno, longProcNameLen);
return -EINVAL;
}
return 0;
}
static int SetKeepCapabilities(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
// set keep capabilities when user not root.
if (appProperty->property.uid != 0) {
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
APPSPAWN_LOGE("set keepcaps failed: %d", errno);
return (-errno);
}
}
return 0;
}
static int SetCapabilities(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
// init cap
struct __user_cap_header_struct cap_header;
if (memset_s(&cap_header, sizeof(cap_header), 0, sizeof(cap_header)) != EOK) {
APPSPAWN_LOGE("Failed to memset cap header");
return -EINVAL;
}
cap_header.version = _LINUX_CAPABILITY_VERSION_3;
cap_header.pid = 0;
struct __user_cap_data_struct cap_data[2];
if (memset_s(&cap_data, sizeof(cap_data), 0, sizeof(cap_data)) != EOK) {
APPSPAWN_LOGE("Failed to memset cap data");
return -EINVAL;
}
// init inheritable permitted effective zero
#ifdef GRAPHIC_PERMISSION_CHECK
const uint64_t inheriTable = 0;
const uint64_t permitted = 0;
const uint64_t effective = 0;
#else
const uint64_t inheriTable = 0x3fffffffff;
const uint64_t permitted = 0x3fffffffff;
const uint64_t effective = 0x3fffffffff;
#endif
cap_data[0].inheritable = (__u32)(inheriTable);
cap_data[1].inheritable = (__u32)(inheriTable >> BITLEN32);
cap_data[0].permitted = (__u32)(permitted);
cap_data[1].permitted = (__u32)(permitted >> BITLEN32);
cap_data[0].effective = (__u32)(effective);
cap_data[1].effective = (__u32)(effective >> BITLEN32);
// set capabilities
if (capset(&cap_header, &cap_data[0]) == -1) {
APPSPAWN_LOGE("capset failed: %d", errno);
return (-errno);
}
return 0;
}
static void InitDebugParams(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
#ifdef __aarch64__
const char *debugSoPath = "/system/lib64/libhidebug.so";
#else
const char *debugSoPath = "/system/lib/libhidebug.so";
#endif
if (access(debugSoPath, F_OK) != 0) {
APPSPAWN_LOGE("access failed, errno = %d", errno);
return;
}
void *handle = dlopen(debugSoPath, RTLD_LAZY);
if (handle == NULL) {
APPSPAWN_LOGE("Failed to dlopen libhidebug.so, %s", dlerror());
return;
}
bool (*initParam)(const char *name);
initParam = (bool (*)(const char *name))dlsym(handle, "InitEnvironmentParam");
if (initParam == NULL) {
APPSPAWN_LOGE("Failed to dlsym InitEnvironmentParam, %s", dlerror());
dlclose(handle);
return;
}
bool ret = (*initParam)(appProperty->property.processName);
if (!ret) {
APPSPAWN_LOGV("init parameters failed.");
}
dlclose(handle);
}
static void ClearEnvironment(AppSpawnContent *content, AppSpawnClient *client)
{
APPSPAWN_LOGI("ClearEnvironment id %d", client->id);
AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGTERM);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
// close child fd
close(appProperty->fd[0]);
InitDebugParams(content, client);
return;
}
static int SetUidGid(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
#ifdef GRAPHIC_PERMISSION_CHECK
AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
// set gids
if (setgroups(appProperty->property.gidCount, (const gid_t *)(&appProperty->property.gidTable[0])) == -1) {
APPSPAWN_LOGE("setgroups failed: %d, gids.size=%u", errno, appProperty->property.gidCount);
return (-errno);
}
// set gid
if (setresgid(appProperty->property.gid, appProperty->property.gid, appProperty->property.gid) == -1) {
APPSPAWN_LOGE("setgid(%u) failed: %d", appProperty->property.gid, errno);
return (-errno);
}
// If the effective user ID is changed from 0 to nonzero, then all capabilities are cleared from the effective set
if (setresuid(appProperty->property.uid, appProperty->property.uid, appProperty->property.uid) == -1) {
APPSPAWN_LOGE("setuid(%u) failed: %d", appProperty->property.uid, errno);
return (-errno);
}
#endif
return 0;
}
static int32_t SetFileDescriptors(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
// close stdin stdout stderr
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// redirect to /dev/null
int dev_null_fd = open(DEVICE_NULL_STR, O_RDWR);
if (dev_null_fd == -1) {
APPSPAWN_LOGE("open dev_null error: %d", errno);
return (-errno);
}
// stdin
if (dup2(dev_null_fd, STDIN_FILENO) == -1) {
APPSPAWN_LOGE("dup2 STDIN error: %d", errno);
return (-errno);
};
// stdout
if (dup2(dev_null_fd, STDOUT_FILENO) == -1) {
APPSPAWN_LOGE("dup2 STDOUT error: %d", errno);
return (-errno);
};
// stderr
if (dup2(dev_null_fd, STDERR_FILENO) == -1) {
APPSPAWN_LOGE("dup2 STDERR error: %d", errno);
return (-errno);
};
return 0;
}
static void Free(char **argv)
{
argv[0] = NULL;
for (int i = 0; i < NULL_INDEX; i++) {
if (argv[i] != NULL) {
free(argv[i]);
argv[i] = NULL;
}
}
free(argv);
}
static int ColdStartApp(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
AppParameter *appProperty = &((AppSpawnClientExt *)client)->property;
APPSPAWN_LOGI("ColdStartApp::appName %s", appProperty->processName);
char buffer[32] = {0}; // 32 buffer for fd
int len = sprintf_s(buffer, sizeof(buffer), "%d", ((AppSpawnClientExt *)client)->fd[1]);
APPSPAWN_CHECK(len > 0, return -1, "Invalid to format fd");
char **argv = calloc(1, (NULL_INDEX + 1) * sizeof(char *));
APPSPAWN_CHECK(argv != NULL, return -1, "Failed to get argv");
int32_t startLen = 0;
const int32_t originLen = sizeof(AppParameter) + PARAM_BUFFER_LEN;
// param
char *param = malloc(originLen + APP_LEN_PROC_NAME);
APPSPAWN_CHECK(param != NULL, free(argv);
return -1, "Failed to malloc for param");
int ret = -1;
do {
argv[PARAM_INDEX] = param;
argv[0] = param + originLen;
ret = strcpy_s(argv[0], APP_LEN_PROC_NAME, "/system/bin/appspawn");
APPSPAWN_CHECK(ret >= 0, break, "Invalid strdup");
argv[START_INDEX] = strdup("cold-start");
APPSPAWN_CHECK(argv[START_INDEX] != NULL, break, "Invalid strdup");
argv[FD_INDEX] = strdup(buffer);
APPSPAWN_CHECK(argv[FD_INDEX] != NULL, break, "Invalid strdup");
len = sprintf_s(param + startLen, originLen - startLen, "%u:%u:%u:%d",
((AppSpawnClientExt *)client)->client.id,
appProperty->uid, appProperty->gid, appProperty->gidCount);
APPSPAWN_CHECK(len > 0 && (len < (originLen - startLen)), break, "Invalid to format");
startLen += len;
for (uint32_t i = 0; i < appProperty->gidCount; i++) {
len = sprintf_s(param + startLen, originLen - startLen, ":%u", appProperty->gidTable[i]);
APPSPAWN_CHECK(len > 0 && (len < (originLen - startLen)), break, "Invalid to format gid");
startLen += len;
}
// processName
len = sprintf_s(param + startLen, originLen - startLen, ":%s:%s:%s:%u:%s:%s",
appProperty->processName, appProperty->bundleName, appProperty->soPath,
appProperty->accessTokenId, appProperty->apl, appProperty->renderCmd);
APPSPAWN_CHECK(len > 0 && (len < (originLen - startLen)), break, "Invalid to format processName");
startLen += len;
ret = 0;
} while (0);
if (ret == 0) {
argv[NULL_INDEX] = NULL;
#ifndef APPSPAWN_TEST
ret = execv(argv[0], argv);
#endif
if (ret) {
APPSPAWN_LOGE("Failed to execv, errno = %d", errno);
}
}
Free(argv);
return ret;
}
int GetAppSpawnClientFromArg(int argc, char *const argv[], AppSpawnClientExt *client)
{
APPSPAWN_CHECK(argv != NULL, return -1, "Invalid arg");
APPSPAWN_CHECK(argc > PARAM_INDEX, return -1, "Invalid argc %d", argc);
client->fd[1] = atoi(argv[FD_INDEX]);
APPSPAWN_LOGV("GetAppSpawnClientFromArg %s ", argv[PARAM_INDEX]);
char *end = NULL;
char *start = strtok_r(argv[PARAM_INDEX], ":", &end);
// clientid
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get client id");
client->client.id = atoi(start);
start = strtok_r(NULL, ":", &end);
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get uid");
client->property.uid = atoi(start);
start = strtok_r(NULL, ":", &end);
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get gid");
client->property.gid = atoi(start);
// gidCount
start = strtok_r(NULL, ":", &end);
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get gidCount");
client->property.gidCount = atoi(start);
for (uint32_t i = 0; i < client->property.gidCount; i++) {
start = strtok_r(NULL, ":", &end);
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get gidTable");
client->property.gidTable[i] = atoi(start);
}
// processname
start = strtok_r(NULL, ":", &end);
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get processName");
int ret = strcpy_s(client->property.processName, sizeof(client->property.processName), start);
APPSPAWN_CHECK(ret == 0, return -1, "Failed to strcpy processName");
start = strtok_r(NULL, ":", &end);
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get bundleName");
ret = strcpy_s(client->property.bundleName, sizeof(client->property.bundleName), start);
APPSPAWN_CHECK(ret == 0, return -1, "Failed to strcpy bundleName");
start = strtok_r(NULL, ":", &end);
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get soPath");
ret = strcpy_s(client->property.soPath, sizeof(client->property.soPath), start);
APPSPAWN_CHECK(ret == 0, return -1, "Failed to strcpy soPath");
// accesstoken
start = strtok_r(NULL, ":", &end);
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get accessTokenId");
client->property.accessTokenId = atoi(start);
start = strtok_r(NULL, ":", &end);
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get apl");
ret = strcpy_s(client->property.apl, sizeof(client->property.apl), start);
APPSPAWN_CHECK(ret == 0, return -1, "Failed to strcpy apl");
start = strtok_r(NULL, ":", &end);
APPSPAWN_CHECK(start != NULL, return -1, "Failed to get renderCmd");
ret = strcpy_s(client->property.renderCmd, sizeof(client->property.renderCmd), start);
APPSPAWN_CHECK(ret == 0, return -1, "Failed to strcpy renderCmd");
return 0;
}
void SetContentFunction(AppSpawnContent *content)
{
APPSPAWN_LOGI("SetContentFunction");
content->clearEnvironment = ClearEnvironment;
content->setProcessName = SetProcessName;
content->setKeepCapabilities = SetKeepCapabilities;
content->setUidGid = SetUidGid;
content->setCapabilities = SetCapabilities;
content->setFileDescriptors = SetFileDescriptors;
content->setAppSandbox = SetAppSandboxProperty;
content->setAppAccessToken = SetAppAccessToken;
content->coldStartApp = ColdStartApp;
content->registerAppSandbox = RegisterAppSandbox;
}

472
standard/appspawn_service.c Normal file
View File

@ -0,0 +1,472 @@
/*
* 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 "appspawn_service.h"
#include <fcntl.h>
#include <sys/capability.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/signalfd.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "appspawn_server.h"
#include "init_hashmap.h"
#include "init_socket.h"
#include "parameter.h"
#include "securec.h"
static AppSpawnContentExt *g_appSpawnContent = NULL;
static const int TV_SEC = 60;
static int AppInfoHashNodeCompare(const HashNode *node1, const HashNode *node2)
{
AppInfo *testNode1 = HASHMAP_ENTRY(node1, AppInfo, node);
AppInfo *testNode2 = HASHMAP_ENTRY(node2, AppInfo, node);
return testNode1->pid - testNode2->pid;
}
static int TestHashKeyCompare(const HashNode *node1, const void *key)
{
AppInfo *testNode1 = HASHMAP_ENTRY(node1, AppInfo, node);
return testNode1->pid - *(pid_t *)key;
}
static int AppInfoHashNodeFunction(const HashNode *node)
{
AppInfo *testNode = HASHMAP_ENTRY(node, AppInfo, node);
if (testNode == NULL) {
return -1;
}
return testNode->pid % APP_HASH_BUTT;
}
static int AppInfoHashKeyFunction(const void *key)
{
pid_t code = *(pid_t *)key;
return code % APP_HASH_BUTT;
}
static void AppInfoHashNodeFree(const HashNode *node)
{
AppInfo *testNode = HASHMAP_ENTRY(node, AppInfo, node);
APPSPAWN_LOGI("AppInfoHashNodeFree %s\n", testNode->name);
free(testNode);
}
static void AddAppInfo(pid_t pid, const char *processName)
{
size_t len = strlen(processName) + 1;
AppInfo *node = (AppInfo *)malloc(sizeof(AppInfo) + len + 1);
APPSPAWN_CHECK(node != NULL, return, "Failed to malloc for appinfo");
node->pid = pid;
int ret = strcpy_s(node->name, len, processName);
APPSPAWN_CHECK(ret == 0, free(node);
return, "Failed to strcpy process name");
HASHMAPInitNode(&node->node);
ret = HashMapAdd(g_appSpawnContent->appMap, &node->node);
APPSPAWN_CHECK(ret == 0, free(node);
return, "Failed to add appinfo to hash");
APPSPAWN_LOGI("Add %s, pid=%d success", processName, pid);
}
static void RemoveAppInfo(pid_t pid)
{
HashNode *node = HashMapGet(g_appSpawnContent->appMap, (const void *)&pid);
APPSPAWN_CHECK(node != NULL, return, "Invalid node %d", pid);
AppInfo *appInfo = HASHMAP_ENTRY(node, AppInfo, node);
APPSPAWN_CHECK(appInfo != NULL, return, "Invalid node %d", pid);
HashMapRemove(g_appSpawnContent->appMap, (const void *)&pid);
free(appInfo);
}
static void KillProcess(const HashNode *node, const void *context)
{
AppInfo *hashNode = (AppInfo *)node;
kill(hashNode->pid, SIGKILL);
APPSPAWN_LOGI("kill app, pid = %d, processName = %s", hashNode->pid, hashNode->name);
}
static void OnClose(const TaskHandle taskHandle)
{
AppSpawnClientExt *client = (AppSpawnClientExt *)LE_GetUserData(taskHandle);
APPSPAWN_CHECK(client != NULL, return, "Failed to get client");
APPSPAWN_LOGI("OnClose client.id %d ", client->client.id);
}
static void SendMessageComplete(const TaskHandle taskHandle, BufferHandle handle)
{
AppSpawnClientExt *client = (AppSpawnClientExt *)LE_GetUserData(taskHandle);
APPSPAWN_CHECK(client != NULL, return, "Failed to get client");
APPSPAWN_LOGI("SendMessageComplete client.id %d ", client->client.id);
}
static int SendResponse(AppSpawnClientExt *client, const char *buff, size_t buffSize)
{
APPSPAWN_CHECK(buffSize >= 0 && buff != 0, return -1, "Invalid content buffSize %d", buffSize);
uint32_t bufferSize = buffSize;
BufferHandle handle = LE_CreateBuffer(LE_GetDefaultLoop(), bufferSize);
char *buffer = (char *)LE_GetBufferInfo(handle, NULL, &bufferSize);
int ret = memcpy_s(buffer, bufferSize, buff, buffSize);
APPSPAWN_CHECK(ret == 0, return -1, "Failed to memcpy_s bufferSize");
return LE_Send(LE_GetDefaultLoop(), client->stream, handle, buffSize);
}
static void SignalHandler(const struct signalfd_siginfo *siginfo)
{
APPSPAWN_LOGI("SignalHandler signum %d", siginfo->ssi_signo);
switch (siginfo->ssi_signo) {
case SIGCHLD: { // delete pid from app map
pid_t pid;
int status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
APPSPAWN_LOGI("SignalHandler pid %d status %d", pid, status);
RemoveAppInfo(pid);
#ifdef NWEB_SPAWN
RecordRenderProcessExitedStatus(pid, status);
#endif
}
break;
}
case SIGTERM: { // appswapn killed, use kill without parameter
HashMapTraverse(g_appSpawnContent->appMap, KillProcess, NULL);
LE_StopLoop(LE_GetDefaultLoop());
break;
}
default:
APPSPAWN_LOGI("SigHandler, unsupported signal %d.", siginfo->ssi_signo);
break;
}
}
static void ProcessTimer(const TimerHandle taskHandle, void *context)
{
APPSPAWN_LOGI("timeout stop appspawn");
LE_StopLoop(LE_GetDefaultLoop());
}
static void HandleSpecial(AppSpawnClientExt *appProperty)
{
// special handle bundle name medialibrary and scanner
const char *specialBundleNames[] = {
"com.ohos.medialibrary.MediaLibraryDataA",
"com.ohos.medialibrary.MediaScannerAbilityA"
};
for (size_t i = 0; i < sizeof(specialBundleNames) / sizeof(specialBundleNames[0]); i++) {
if (strcmp(appProperty->property.processName, specialBundleNames[i]) == 0) {
if (appProperty->property.gidCount < APP_MAX_GIDS) {
appProperty->property.gidTable[appProperty->property.gidCount] = GID_USER_DATA_RW;
appProperty->property.gidCount++;
} else {
APPSPAWN_LOGE("gidCount out of bounds !");
}
break;
}
}
}
static int WaitChild(int fd, int pid, const AppSpawnClientExt *appProperty)
{
int result = 0;
fd_set rd;
struct timeval tv;
FD_ZERO(&rd);
FD_SET(fd, &rd);
tv.tv_sec = TV_SEC;
tv.tv_usec = 0;
int ret = select(fd + 1, &rd, NULL, NULL, &tv);
if (ret == 0) { // timeout
APPSPAWN_LOGI("Time out for child %s %d fd %d", appProperty->property.processName, pid, fd);
result = 0;
} else if (ret == -1) {
APPSPAWN_LOGI("Error for child %s %d", appProperty->property.processName, pid);
result = 0;
} else {
(void)read(fd, &result, sizeof(result));
}
return result;
}
static void StartColdApp(AppSpawnClientExt *appProperty)
{
if (appProperty == NULL) {
return;
}
if (appProperty->property.flags & 0x01) {
char cold[10] = {0}; // 10 cold
int ret = GetParameter("appspawn.cold.boot", "false", cold, sizeof(cold));
APPSPAWN_LOGV("appspawn.cold.boot %s %d ", cold, ret);
if (ret > 0 && (strcmp(cold, "true") == 0 || strcmp(cold, "1") == 0 || strcmp(cold, "enable") == 0)) {
appProperty->client.flags |= APP_COLD_START;
}
}
}
static int GetProcessTerminationStatus(AppSpawnClientExt *appProperty)
{
#ifdef NWEB_SPAWN
if (appProperty == NULL) {
return -1;
}
if (appProperty->property.code == AppOperateType::GET_RENDER_TERMINATION_STATUS) {
int exitStatus = 0;
int ret = GetRenderProcessTerminationStatus(appProperty->property.pid, &exitStatus);
if (ret) {
SendResponse(appProperty, (char *)&ret, sizeof(ret));
} else {
SendResponse(appProperty, (char *)&exitStatus, sizeof(exitStatus));
}
APPSPAWN_LOGI("AppSpawnServer::get render process termination status, status = %d pid = %d uid %d %s %s",
exitStatus, appProperty->property.pid, appProperty->property.uid,
appProperty->property.processName, appProperty->property.bundleName);
return 0;
}
#endif
return -1;
}
static void OnReceiveRequest(const TaskHandle taskHandle, const uint8_t *buffer, uint32_t buffLen)
{
APPSPAWN_CHECK(buffer != NULL && buffLen >= sizeof(AppParameter), LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
return, "Invalid buffer buffLen %u", buffLen);
AppSpawnClientExt *appProperty = (AppSpawnClientExt *)LE_GetUserData(taskHandle);
APPSPAWN_CHECK(appProperty != NULL, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
return, "alloc client Failed");
int ret = memcpy_s(&appProperty->property, sizeof(appProperty->property), buffer, buffLen);
APPSPAWN_CHECK(ret == 0, LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
return, "Invalid buffer buffLen %u", buffLen);
APPSPAWN_CHECK(appProperty->property.gidCount <= APP_MAX_GIDS && strlen(appProperty->property.processName) > 0,
LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
return, "Invalid property %u", appProperty->property.gidCount);
// special handle bundle name medialibrary and scanner
HandleSpecial(appProperty);
if (g_appSpawnContent->timer != NULL) {
LE_StopTimer(LE_GetDefaultLoop(), g_appSpawnContent->timer);
g_appSpawnContent->timer = NULL;
}
// cold start app
StartColdApp(appProperty);
// create pipe for commication from child
if (pipe(appProperty->fd) == -1) {
APPSPAWN_LOGE("create pipe fail, errno = %d", errno);
LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
return;
}
APPSPAWN_LOGI("OnReceiveRequest client.id %d appProperty %d processname %s buffLen %d flags 0x%x",
appProperty->client.id, appProperty->property.uid, appProperty->property.processName,
buffLen, appProperty->property.flags);
fcntl(appProperty->fd[0], F_SETFL, O_NONBLOCK);
// get render process termination status
APPSPAWN_CHECK(GetProcessTerminationStatus(appProperty) != 0, return, "Invalid appspawn content");
pid_t pid = 0;
int result = AppSpawnProcessMsg(&g_appSpawnContent->content, &appProperty->client, &pid);
if (result == 0) { // wait child process resutl
result = WaitChild(appProperty->fd[0], pid, appProperty);
}
close(appProperty->fd[0]);
close(appProperty->fd[1]);
APPSPAWN_LOGI("child process %s %s pid %d",
appProperty->property.processName, (result == 0) ? "success" : "fail", pid);
// send response
if (result == 0) {
AddAppInfo(pid, appProperty->property.processName);
SendResponse(appProperty, (char *)&pid, sizeof(pid));
} else {
SendResponse(appProperty, (char *)&result, sizeof(result));
}
if (g_appSpawnContent->timer == NULL && ((g_appSpawnContent->flags & FLAGS_ON_DEMAND) == FLAGS_ON_DEMAND)) {
ret = LE_CreateTimer(LE_GetDefaultLoop(), &g_appSpawnContent->timer, ProcessTimer, NULL);
APPSPAWN_CHECK(ret == 0, return, "Failed to create time");
LE_StartTimer(LE_GetDefaultLoop(), g_appSpawnContent->timer, 30000, 1); // 30000 30s
}
}
static int OnConnection(const LoopHandle loopHandle, const TaskHandle server)
{
static uint32_t clientId = 0;
APPSPAWN_LOGI("OnConnection ");
APPSPAWN_CHECK(server != NULL, return -1, "Error server");
TaskHandle stream;
LE_StreamInfo info = {};
info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_CONNECT;
info.baseInfo.close = OnClose;
info.baseInfo.userDataSize = sizeof(AppSpawnClientExt);
info.disConntectComplete = NULL;
info.sendMessageComplete = SendMessageComplete;
info.recvMessage = OnReceiveRequest;
LE_STATUS ret = LE_AcceptStreamClient(LE_GetDefaultLoop(), server, &stream, &info);
APPSPAWN_CHECK(ret == 0, return -1, "Failed to alloc stream");
AppSpawnClientExt *client = (AppSpawnClientExt *)LE_GetUserData(stream);
APPSPAWN_CHECK(client != NULL, return -1, "Failed to alloc stream");
client->stream = stream;
client->client.id = ++clientId;
client->client.flags = 0;
APPSPAWN_LOGI("OnConnection client fd %d Id %d", LE_GetSocketFd(stream), client->client.id);
return 0;
}
static int NotifyResToParent(struct AppSpawnContent_ *content, AppSpawnClient *client, int result)
{
AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
int fd = appProperty->fd[1];
APPSPAWN_LOGI("NotifyResToParent %s fd %d result %d", appProperty->property.processName, fd, result);
write(appProperty->fd[1], &result, sizeof(result));
// close write
close(fd);
return 0;
}
static void AppSpawnInit(AppSpawnContent *content)
{
AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
APPSPAWN_CHECK(appSpawnContent != NULL, return, "Invalid appspawn content");
APPSPAWN_LOGI("AppSpawnInit");
if (content->loadExtendLib) {
content->loadExtendLib(content);
}
content->notifyResToParent = NotifyResToParent;
// set private function
SetContentFunction(content);
}
void AppSpawnColdRun(AppSpawnContent *content, int argc, char *const argv[])
{
AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
APPSPAWN_CHECK(appSpawnContent != NULL, return, "Invalid appspawn content");
AppSpawnClientExt *client = (AppSpawnClientExt *)malloc(sizeof(AppSpawnClientExt));
APPSPAWN_CHECK(client != NULL, return, "Failed to alloc memory for client");
int ret = GetAppSpawnClientFromArg(argc, argv, client);
APPSPAWN_CHECK(ret == 0, free(client);
return, "Failed to get client from arg");
APPSPAWN_LOGI("Cold running %d processName %s %u ", getpid(), client->property.processName,
content->longProcNameLen);
ret = DoStartApp(content, &client->client, content->longProcName, content->longProcNameLen);
if (ret == 0 && content->runChildProcessor != NULL) {
content->runChildProcessor(content, &client->client);
}
APPSPAWN_LOGI("App exit %d.", getpid());
free(client);
free(appSpawnContent);
g_appSpawnContent = NULL;
}
static void AppSpawnRun(AppSpawnContent *content, int argc, char *const argv[])
{
APPSPAWN_LOGI("AppSpawnRun");
AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
APPSPAWN_CHECK(appSpawnContent != NULL, return, "Invalid appspawn content");
LE_STATUS status = LE_CreateSignalTask(LE_GetDefaultLoop(), &appSpawnContent->sigHandler, SignalHandler);
if (status == 0) {
status = LE_AddSignal(LE_GetDefaultLoop(), appSpawnContent->sigHandler, SIGCHLD);
status = LE_AddSignal(LE_GetDefaultLoop(), appSpawnContent->sigHandler, SIGTERM);
}
if (status != 0) {
APPSPAWN_LOGE("Failed to add signal %d", status);
}
LE_RunLoop(LE_GetDefaultLoop());
APPSPAWN_LOGI("AppSpawnRun exit ");
LE_CloseSignalTask(LE_GetDefaultLoop(), appSpawnContent->sigHandler);
// release resource
HashMapDestory(appSpawnContent->appMap);
free(content);
g_appSpawnContent = NULL;
}
static int CreateHashForApp(AppSpawnContentExt *appSpawnContent)
{
HashInfo hashInfo = {
AppInfoHashNodeCompare,
TestHashKeyCompare,
AppInfoHashNodeFunction,
AppInfoHashKeyFunction,
AppInfoHashNodeFree,
APP_HASH_BUTT
};
int ret = HashMapCreate(&appSpawnContent->appMap, &hashInfo);
APPSPAWN_CHECK(ret == 0, free(appSpawnContent); return -1, "Failed to create hash for app");
return 0;
}
AppSpawnContent *AppSpawnCreateContent(const char *socketName, char *longProcName, uint32_t longProcNameLen, int mode)
{
APPSPAWN_CHECK(LE_GetDefaultLoop() != NULL, return NULL, "Invalid default loop");
APPSPAWN_CHECK(socketName != NULL && longProcName != NULL, return NULL, "Invalid name");
APPSPAWN_LOGI("AppSpawnCreateContent %s %u mode %d", socketName, longProcNameLen, mode);
AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)malloc(sizeof(AppSpawnContentExt));
APPSPAWN_CHECK(appSpawnContent != NULL, return NULL, "Failed to alloc memory for appspawn");
(void)memset_s(&appSpawnContent->content, sizeof(appSpawnContent->content), 0, sizeof(appSpawnContent->content));
appSpawnContent->content.longProcName = longProcName;
appSpawnContent->content.longProcNameLen = longProcNameLen;
appSpawnContent->timer = NULL;
appSpawnContent->flags = 0;
appSpawnContent->server = NULL;
appSpawnContent->sigHandler = NULL;
appSpawnContent->content.initAppSpawn = AppSpawnInit;
if (mode) {
appSpawnContent->flags |= FLAGS_MODE_COLD;
appSpawnContent->content.runAppSpawn = AppSpawnColdRun;
} else {
appSpawnContent->content.runAppSpawn = AppSpawnRun;
// create hash for app
APPSPAWN_CHECK(CreateHashForApp(appSpawnContent) == 0, return NULL, "Failed to create hash for app");
char path[128] = {0}; // 128 max path
int ret = snprintf_s(path, sizeof(path), sizeof(path) - 1, "%s%s", SOCKET_DIR, socketName);
APPSPAWN_CHECK(ret >= 0, free(appSpawnContent);
return NULL, "Failed to snprintf_s %d", ret);
int socketId = GetControlSocket(socketName);
APPSPAWN_LOGI("get socket form env %s socketId %d", socketName, socketId);
if (socketId > 0) {
appSpawnContent->flags |= FLAGS_ON_DEMAND;
}
LE_StreamServerInfo info = {};
info.baseInfo.flags = TASK_STREAM | TASK_PIPE | TASK_SERVER;
info.socketId = socketId;
info.server = path;
info.baseInfo.close = NULL;
info.incommingConntect = OnConnection;
ret = LE_CreateStreamServer(LE_GetDefaultLoop(), &appSpawnContent->server, &info);
APPSPAWN_CHECK(ret == 0, free(appSpawnContent);
return NULL, "Failed to create socket for %s", path);
// create socket
ret = chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
APPSPAWN_CHECK(ret == 0, free(appSpawnContent);
return NULL, "Failed to chmod %s, err %d. ", path, errno);
APPSPAWN_LOGI("AppSpawnCreateContent path %s fd %d", path, LE_GetSocketFd(appSpawnContent->server));
}
g_appSpawnContent = appSpawnContent;
return &g_appSpawnContent->content;
}

View File

@ -0,0 +1,68 @@
/*
* 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.
*/
#ifndef APPSPAWN_SERVICE_H
#define APPSPAWN_SERVICE_H
#include "appspawn_msg.h"
#include "appspawn_server.h"
#include "init_hashmap.h"
#include "loop_event.h"
#ifdef __cplusplus
extern "C" {
#endif
#define APP_HASH_BUTT 32
#define FLAGS_ON_DEMAND 0x1
#define FLAGS_MODE_COLD 0x2
#define FLAGS_SANDBOX_PRIVATE 0x10
#define FLAGS_SANDBOX_APP 0x20
#define START_INDEX 1
#define FD_INDEX 2
#define PARAM_INDEX 3
#define NULL_INDEX 4
#define PARAM_BUFFER_LEN 128
typedef struct {
AppSpawnClient client;
TaskHandle stream;
int32_t fd[2]; // 2 fd count
AppParameter property;
} AppSpawnClientExt;
typedef struct {
HashNode node;
pid_t pid;
char name[0];
} AppInfo;
typedef struct {
AppSpawnContent content;
uint32_t flags;
TaskHandle server;
SignalHandle sigHandler;
TimerHandle timer;
HashMapHandle appMap; // save app pid and name
} AppSpawnContentExt;
void SetContentFunction(AppSpawnContent *content);
void AppSpawnColdRun(AppSpawnContent *content, int argc, char *const argv[]);
int GetAppSpawnClientFromArg(int argc, char *const argv[], AppSpawnClientExt *client);
#ifdef __cplusplus
}
#endif
#endif // APPSPAWN_SERVICE_H

52
standard/main.c Normal file
View File

@ -0,0 +1,52 @@
/*
* 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 "appspawn_adapter.h"
#include "appspawn_msg.h"
#include "appspawn_server.h"
int main(int argc, char *const argv[])
{
if (argc <= 0) {
return 0;
}
uint32_t argvSize = 0;
char *buffer = (char *)argv[0];
int mode = 0;
if ((argc > PARAM_INDEX) && (strcmp(argv[START_INDEX], "cold-start") == 0)) {
buffer = argv[0];
argvSize = APP_LEN_PROC_NAME;
mode = 1;
} else {
// calculate child process long name size
uintptr_t start = (uintptr_t)argv[0];
uintptr_t end = (uintptr_t)strchr(argv[argc - 1], 0);
if (end <= 0) {
return -1;
}
argvSize = end - start;
}
APPSPAWN_LOGI("AppSpawnCreateContent argc %d mode %d %u", argc, mode, argvSize);
AppSpawnContent *content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, argv[0], argvSize, mode);
APPSPAWN_CHECK(content != NULL, return -1, "Invalid content for appspawn");
APPSPAWN_CHECK(content->initAppSpawn != NULL, return -1, "Invalid content for appspawn");
APPSPAWN_CHECK(content->runAppSpawn != NULL, return -1, "Invalid content for appspawn");
// set common operation
content->loadExtendLib = LoadExtendLib;
content->runChildProcessor = RunChildProcessor;
content->initAppSpawn(content);
content->runAppSpawn(content, argc, argv);
return 0;
}

View File

@ -18,11 +18,9 @@ group("unittest") {
testonly = true
deps = [
"unittest/app_spawn_msg_peer_test:unittest",
"unittest/app_spawn_server_test:unittest",
"unittest/app_spawn_socket_test:unittest",
"unittest/app_spawn_standard_test:unittest",
"unittest/client_socket_test:unittest",
"unittest/server_socket_test:unittest",
]
}
@ -39,7 +37,7 @@ config("appspawn_test_config") {
include_dirs = [
"${appspawn_path}/test/mock/include",
"${appspawn_path}/src/include",
"${appspawn_path}/common",
"${appspawn_path}/interfaces/innerkits/include",
]
}
@ -66,6 +64,8 @@ ohos_source_set("appspawn_test_source") {
external_deps = [
"ability_base:want",
"bundle_framework:appexecfwk_base",
"bundle_framework:appexecfwk_core",
"hiviewdfx_hilog_native:libhilog",
]
}

View File

@ -1,180 +0,0 @@
/*
* 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 "server_socket.h"
#include "client_socket.h"
#include "gmock/gmock.h"
#include "securec.h"
#include "hilog/log.h"
namespace OHOS {
namespace AppSpawn {
using namespace OHOS::HiviewDFX;
static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "MockServerSocket"};
class MockServerSocket : public ServerSocket {
public:
MockServerSocket() = delete;
virtual ~MockServerSocket() = default;
MockServerSocket(const std::string &server) : ServerSocket(server){};
MOCK_METHOD1(SaveConnection, void(int32_t connectFd));
MOCK_METHOD1(CloseConnection, void(int32_t connectFd));
MOCK_METHOD0(CloseServer, void());
MOCK_METHOD0(CloseServerMonitor, void());
MOCK_METHOD0(RegisterServerSocket, int32_t());
MOCK_METHOD0(WaitForConnection, int32_t());
MOCK_METHOD1(VerifyConnection, int32_t(int32_t connectFd));
MOCK_METHOD3(ReadSocketMessage, int32_t(int32_t socketFd, void *buf, int32_t len));
MOCK_METHOD3(WriteSocketMessage, int32_t(int32_t socketFd, const void *buf, int32_t len));
int32_t ReadImplGidCountMax([[maybe_unused]] int32_t socketFd, void *buf, [[maybe_unused]] int32_t len)
{
std::lock_guard<std::mutex> lock(mutex_);
// assign AppProperty
ClientSocket::AppProperty *params = static_cast<ClientSocket::AppProperty *>(buf);
if (params == nullptr) {
return 0;
}
params->uid = 0;
params->gid = 0;
auto ret = memset_s(params->gidTable, sizeof(params->gidTable), 0, sizeof(params->gidTable));
if (ret != EOK) {
HiLog::Info(LABEL, "memset_s failed");
return 0;
}
params->gidCount = ClientSocket::MAX_GIDS + 1;
std::string processName = "processName";
ret = memcpy_s(params->processName, sizeof(params->processName), processName.c_str(), processName.length());
if (ret != EOK) {
HiLog::Info(LABEL, "memcpy_s failed");
return 0;
}
std::string soPath = "soPath";
ret = memcpy_s(params->soPath, sizeof(params->soPath), soPath.c_str(), soPath.length());
if (ret != EOK) {
HiLog::Info(LABEL, "memcpy_s failed");
return 0;
}
return sizeof(ClientSocket::AppProperty);
}
int32_t ReadImplProcessName([[maybe_unused]] int32_t socketFd, void *buf, [[maybe_unused]] int32_t len)
{
std::lock_guard<std::mutex> lock(mutex_);
// assign AppProperty
ClientSocket::AppProperty *params = static_cast<ClientSocket::AppProperty *>(buf);
if (params == nullptr) {
return 0;
}
params->uid = 0;
params->gid = 0;
auto ret = memset_s(params->gidTable, sizeof(params->gidTable), 0, sizeof(params->gidTable));
if (ret != EOK) {
HiLog::Info(LABEL, "memset_s failed");
return 0;
}
params->gidCount = ClientSocket::MAX_GIDS;
std::string processName = "";
ret = memcpy_s(params->processName, sizeof(params->processName), processName.c_str(), processName.length());
if (ret != EOK) {
HiLog::Info(LABEL, "memcpy_s failed");
return 0;
}
std::string soPath = "soPath";
ret = memcpy_s(params->soPath, sizeof(params->soPath), soPath.c_str(), soPath.length());
if (ret != EOK) {
HiLog::Info(LABEL, "memcpy_s failed");
return 0;
}
return sizeof(ClientSocket::AppProperty);
}
int32_t ReadImplValid([[maybe_unused]] int32_t socketFd, void *buf, [[maybe_unused]] int32_t len)
{
std::lock_guard<std::mutex> lock(mutex_);
// assign AppProperty
ClientSocket::AppProperty *params = static_cast<ClientSocket::AppProperty *>(buf);
if (params == nullptr) {
return 0;
}
params->uid = 0;
params->gid = 0;
auto ret = memset_s(params->gidTable, sizeof(params->gidTable), 0, sizeof(params->gidTable));
if (ret != EOK) {
HiLog::Info(LABEL, "memset_s failed");
return 0;
}
params->gidCount = ClientSocket::MAX_GIDS;
std::string processName = "processName";
ret = memcpy_s(params->processName, sizeof(params->processName), processName.c_str(), processName.length());
if (ret != EOK) {
HiLog::Info(LABEL, "memcpy_s failed");
return 0;
}
std::string soPath = "soPath";
ret = memcpy_s(params->soPath, sizeof(params->soPath), soPath.c_str(), soPath.length());
if (ret != EOK) {
HiLog::Info(LABEL, "memcpy_s failed");
return 0;
}
return sizeof(ClientSocket::AppProperty);
}
int32_t ReadImplValidLongProcessName([[maybe_unused]] int32_t socketFd, void *buf, [[maybe_unused]] int32_t len)
{
std::lock_guard<std::mutex> lock(mutex_);
// assign AppProperty
ClientSocket::AppProperty *params = static_cast<ClientSocket::AppProperty *>(buf);
if (params == nullptr) {
return 0;
}
params->uid = 0;
params->gid = 0;
auto ret = memset_s(params->gidTable, sizeof(params->gidTable), 0, sizeof(params->gidTable));
if (ret != EOK) {
HiLog::Info(LABEL, "memset_s failed");
return 0;
}
params->gidCount = ClientSocket::MAX_GIDS;
std::string processName = "ProcessName1234567890";
ret = memcpy_s(params->processName, sizeof(params->processName), processName.c_str(), processName.length());
if (ret != EOK) {
HiLog::Info(LABEL, "memcpy_s failed");
return 0;
}
std::string soPath = "soPath";
ret = memcpy_s(params->soPath, sizeof(params->soPath), soPath.c_str(), soPath.length());
if (ret != EOK) {
HiLog::Info(LABEL, "memcpy_s failed");
return 0;
}
return sizeof(ClientSocket::AppProperty);
}
private:
std::mutex mutex_;
};
} // namespace AppSpawn
} // namespace OHOS

View File

@ -1,91 +0,0 @@
/*
* 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 "appspawn_msg_peer.h"
#include <memory>
#include "hilog/log.h"
#include "securec.h"
namespace OHOS {
namespace AppSpawn {
using namespace OHOS::HiviewDFX;
static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "MockAppSpawnMsgPeer"};
AppSpawnMsgPeer::AppSpawnMsgPeer(const std::shared_ptr<ServerSocket> &socket, int connectFd)
: connectFd_(connectFd), socket_(socket)
{
buf_ = std::make_unique<int8_t[]>(sizeof(ClientSocket::AppProperty));
if (buf_ == nullptr) {
HiLog::Error(LABEL, "buf_ is null pointer!");
}
}
AppSpawnMsgPeer::~AppSpawnMsgPeer()
{
connectFd_ = -1;
}
ClientSocket::AppProperty *AppSpawnMsgPeer::GetMsg() const
{
HiLog::Info(LABEL, "GetMsg");
if (buf_ != nullptr) {
ClientSocket::AppProperty *appProperty = reinterpret_cast<ClientSocket::AppProperty *>(buf_.get());
appProperty->uid = 0;
appProperty->gid = 0;
auto ret = memset_s(appProperty->gidTable, sizeof(appProperty->gidTable), 0, sizeof(appProperty->gidTable));
if (ret != EOK) {
HiLog::Error(LABEL, "memset_s failed!");
return nullptr;
}
appProperty->gidCount = ClientSocket::MAX_GIDS;
std::string processName = "processName";
ret = memcpy_s(
appProperty->processName, sizeof(appProperty->processName), processName.c_str(), processName.length());
if (ret != EOK) {
HiLog::Error(LABEL, "memcpy_s failed!");
return nullptr;
}
std::string soPath = "soPath";
ret = memcpy_s(appProperty->soPath, sizeof(appProperty->soPath), soPath.c_str(), soPath.length());
if (ret != EOK) {
HiLog::Error(LABEL, "memcpy_s failed!");
return nullptr;
}
}
return reinterpret_cast<ClientSocket::AppProperty *>(buf_.get());
}
int AppSpawnMsgPeer::GetConnectFd() const
{
HiLog::Info(LABEL, "GetConnectFd");
return 0;
}
int AppSpawnMsgPeer::Response(pid_t pid)
{
HiLog::Info(LABEL, "Response");
return 0;
}
int AppSpawnMsgPeer::MsgPeer()
{
HiLog::Info(LABEL, "MsgPeer");
return 0;
}
} // namespace AppSpawn
} // namespace OHOS

View File

@ -1,29 +0,0 @@
/*
* 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 "main_thread.h"
#include "hilog/log.h"
namespace OHOS {
namespace AppExecFwk {
using namespace OHOS::HiviewDFX;
static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "MockMainThread"};
void MainThread::Start()
{
HiLog::Info(LABEL, "Start");
}
} // namespace AppExecFwk
} // namespace OHOS

View File

@ -1,93 +0,0 @@
/*
* 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 "server_socket.h"
#include <cerrno>
#include <iostream>
#include <sys/socket.h>
#include "client_socket.h"
#include "hilog/log.h"
#include "securec.h"
namespace OHOS {
namespace AppSpawn {
using namespace OHOS::HiviewDFX;
static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "MockServerSocket"};
ServerSocket::ServerSocket(const std::string &server) : AppSpawnSocket(server)
{}
ServerSocket::~ServerSocket()
{}
int ServerSocket::VerifyConnection(int connectFd)
{
HiLog::Info(LABEL, "VerifyConnection");
return 0;
}
void ServerSocket::CloseConnection(int connectFd)
{
HiLog::Info(LABEL, "CloseConnection");
}
void ServerSocket::SaveConnection(int connectFd)
{
HiLog::Info(LABEL, "CloseConnection");
}
void ServerSocket::CloseServer()
{
HiLog::Info(LABEL, "CloseServer");
}
void ServerSocket::CloseServerMonitor()
{
HiLog::Info(LABEL, "CloseServerMonitor");
}
int ServerSocket::BindSocket(int connectFd)
{
HiLog::Info(LABEL, "BindSocket");
return 0;
}
int ServerSocket::RegisterServerSocket(int &connectFd)
{
HiLog::Info(LABEL, "RegisterServerSocket connectFd");
return 0;
}
int ServerSocket::RegisterServerSocket()
{
HiLog::Info(LABEL, "RegisterServerSocket");
return 0;
}
int ServerSocket::WaitForConnection(int connectFd)
{
HiLog::Info(LABEL, "WaitForConnection connectFd");
return 0;
}
int ServerSocket::WaitForConnection()
{
HiLog::Info(LABEL, "WaitForConnection");
return 0;
}
} // namespace AppSpawn
} // namespace OHOS

View File

@ -23,6 +23,7 @@ ohos_moduletest("AppSpawnModuleTest") {
"//utils/native/base/include",
"//third_party/zlib/contrib/minizip",
"//third_party/zlib",
"${appexecfwk_path}/interfaces/innerkits/appexecfwk_base/include",
]
configs = [
@ -33,6 +34,7 @@ ohos_moduletest("AppSpawnModuleTest") {
deps = [
"${aafwk_path}/interfaces/innerkits/app_manager:app_manager",
"${aafwk_path}/services/appmgr:libams",
"${appexecfwk_path}/interfaces/innerkits/appexecfwk_core:appexecfwk_core",
"${appspawn_path}/interfaces/innerkits:appspawn_socket_client",
"//third_party/googletest:gtest_main",
"//utils/native/base:utils",

View File

@ -72,11 +72,11 @@ bool readFileInfo(char *buffer, const int32_t &pid, const char *fileName)
// Set file path
char filePath[FILE_PATH_SIZE];
if (sprintf_s(filePath, sizeof(filePath), "/proc/%d/%s", pid, fileName) <= 0) {
HiLog::Error(LABEL, "filePath sprintf_s failed.");
HiLog::Error(LABEL, "filePath sprintf_s fail .");
return CHECK_ERROR;
}
if (!checkFileIsExists(filePath)) {
HiLog::Error(LABEL, "file %{public}s not exists.", fileName);
HiLog::Error(LABEL, "file %{public}s is not exists .", fileName);
return CHECK_ERROR;
}
// Open file
@ -207,7 +207,7 @@ bool checkProcName(const int32_t &pid, const AppSpawnStartMsg &params)
FILE *fp = nullptr;
char cmd[CMD_SIZE];
if (sprintf_s(cmd, sizeof(cmd), "ps -o ARGS=CMD -p %d |grep -v CMD", pid) <= 0) {
HiLog::Error(LABEL, "cmd sprintf_s failed.");
HiLog::Error(LABEL, "cmd sprintf_s fail .");
return CHECK_ERROR;
}
if(strlen(cmd) > CMD_SIZE) {
@ -246,12 +246,12 @@ bool checkProcessIsDestroyed(const int32_t &pid)
{
char filePath[FILE_PATH_SIZE];
if (sprintf_s(filePath, sizeof(filePath), "/proc/%d", pid) <= 0) {
HiLog::Error(LABEL, "filePath sprintf_s failed.");
HiLog::Error(LABEL, "filePath sprintf_s fail .");
return CHECK_ERROR;
}
if (checkFileIsExists(filePath)) {
HiLog::Error(LABEL, "File %{public}d not exists.", pid);
HiLog::Error(LABEL, "File %{public}d is not exists .", pid);
return CHECK_ERROR;
}
@ -332,7 +332,8 @@ void AppSpawnModuleTest::TearDownTestCase()
void AppSpawnModuleTest::SetUp()
{
newPid = 0;
if (memset_s(buffer, sizeof(buffer), 0x00, BUFFER_SIZE) != EOK) {
auto ret = memset_s(buffer, sizeof(buffer), 0x00, BUFFER_SIZE);
if (ret != EOK) {
HiLog::Error(LABEL, "memset_s is failed.");
}
}
@ -365,7 +366,7 @@ HWTEST_F(AppSpawnModuleTest, AppSpawn_HF_listen_001, TestSize.Level0)
* FunctionPoints: Process start message monitoring.
* EnvConditions: AppSpawn main process has started.
* The socket server has been established.
* CaseDescription: 1. Establish a socket client and connect with the AppSpawn server
* CaseDescription: 1. Establish a socket client and connect with the Appspawn server
*/
HWTEST_F(AppSpawnModuleTest, AppSpawn_HF_listen_002, TestSize.Level0)
{

View File

@ -0,0 +1,46 @@
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/lite/config/component/lite_component.gni")
import("//build/lite/config/test.gni")
unittest("AppSpawnLiteTest") {
output_extension = "bin"
output_dir = "$root_out_dir/test/unittest/startup"
ldflags = [
"-lstdc++",
"-lpthread",
"-lm",
]
include_dirs = [
"//base/startup/appspawn_standard/lite/",
"//base/hiviewdfx/hilog_lite/interfaces/native/innerkits/hilog",
"//third_party/bounds_checking_function/include/",
"//third_party/cJSON",
]
sources = [
"//base/startup/appspawn_standard/lite/appspawn_message.c",
"app_spawn_lite_test.cpp",
]
deps = [
"//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
"//build/lite/config/component/cJSON:cjson_shared",
"//third_party/bounds_checking_function:libsec_shared",
]
}
group("unittest") {
deps = [ ":appspawn_test" ]
}

View File

@ -0,0 +1,399 @@
/*
* 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 <cerrno>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <sys/types.h>
#include <ctime>
#include <vector>
#include "gtest/gtest.h"
#include "appspawn_message.h"
using namespace testing::ext;
namespace OHOS {
const unsigned int MALLOC_TEST_LENGTH = 10;
const long NANOSECONDS_PER_SECOND = 1000000000;
const int TEST_UID = 999;
const int TEST_GID = 888;
std::vector<std::string> g_badStrings;
std::vector<std::string> g_goodStrings;
class AppSpawnLiteTest : public testing::Test {
public:
static void SetUpTestCase()
{
// empty
g_badStrings.push_back(std::string(""));
// not json
g_badStrings.push_back(std::string("abcdefghijklmnopqrstuvwxyz"));
g_badStrings.push_back(std::string("0123456789876543210"));
g_badStrings.push_back(std::string("xxxx"));
g_badStrings.push_back(std::string("xxxxssssssssssssssssssss"));
g_badStrings.push_back(std::string("\"\"\"\"\"\"\"\"\"\"\"\"\"\"\""));
g_badStrings.push_back(std::string("............................................."));
g_badStrings.push_back(std::string("....%%%....^..***@##.../*--++......$$&&....."));
// looks like json but format error
g_badStrings.push_back(std::string(
"{bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName:\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV,\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID:\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1,\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID:10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID:10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability:[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]"));
g_badStrings.push_back(std::string(
"\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\"\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\"\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\"\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\"\"uID\":10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\"10,\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10\"gID\":10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\"10,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\"[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0]},"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0],}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1\",\"uID\":10,\"gID\":10,\"capability\":[0,]}"));
// json format correct but fields missing
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"uID\":1000,\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"\":1000,\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000}"));
// field value invalid
g_badStrings.push_back(std::string(
"{\"bundleName\":\"\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"\",\"uID\":1000,\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":-1000,\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":-1000,\"capability\":[-7]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":1}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":[0, 3, -9]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":[99999999]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":1234,\"uID\":1000,\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":\"1000\",\"gID\":1000,\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":\"1000\",\"capability\":[0]}"));
g_badStrings.push_back(std::string(
"{\"bundleName\":\"nameV\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":\"0\"}"));
g_badStrings.push_back(std::string(
"{\"bundleName\": 250,\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":[0]}"));
g_goodStrings.push_back(std::string(
"{\"bundleName\":\"testvalid1\",\"identityID\":\"1234\",\"uID\":1000,\"gID\":1000,\"capability\":[0]}"));
g_goodStrings.push_back(std::string(
"{\"bundleName\":\"testvalid2\",\"identityID\":\"5678\",\"uID\":1001,\"gID\":1001,\"capability\":[3,5]}"));
g_goodStrings.push_back(std::string(
"{\"bundleName\":\"testvalid3\",\"identityID\":\"91011\",\"uID\":1002,\"gID\":1002,\"capability\":[8,9]}"));
g_goodStrings.push_back(std::string(
"{\"bundleName\":\"testvalid3\",\"identityID\":\"999\",\"uID\":1002,\"gID\":1002,\"capability\":[]}"));
g_goodStrings.push_back(std::string(
"{\"bundleName\":\"testvalid3\",\"identityID\":\"3\",\"uID\":1002,\"gID\":1002,\"capability\":[1,2]}"));
printf("[----------] AppSpawnLiteTest, message func test setup.\n");
}
static void TearDownTestCase()
{
g_badStrings.clear();
g_goodStrings.clear();
printf("[----------] AppSpawnLiteTest, message func test teardown.\n");
}
void SetUp() {}
void TearDown() {}
};
/*
** @tc.name: msgFuncFreeTest_001
** @tc.desc: free message struct function, nullptr test
** @tc.type: FUNC
** @tc.require: AR000F733K
** @tc.author: ZAL
**/
HWTEST_F(AppSpawnLiteTest, msgFuncFreeTest_001, TestSize.Level1)
{
// do not crash here
FreeMessageSt(nullptr);
MessageSt msgSt = {0};
FreeMessageSt(&msgSt);
EXPECT_EQ(msgSt.bundleName, nullptr);
EXPECT_EQ(msgSt.identityID, nullptr);
EXPECT_EQ(msgSt.caps, nullptr);
EXPECT_EQ(msgSt.uID, -1);
EXPECT_EQ(msgSt.gID, -1);
EXPECT_EQ(msgSt.capsCnt, 0);
}
/*
** @tc.name: msgFuncFreeTest_002
** @tc.desc: free message struct function, function test
** @tc.type: FUNC
** @tc.require: AR000F733K
** @tc.author: ZAL
**/
HWTEST_F(AppSpawnLiteTest, msgFuncFreeTest_002, TestSize.Level1)
{
MessageSt msgSt = {0};
msgSt.capsCnt = MALLOC_TEST_LENGTH;
FreeMessageSt(&msgSt);
EXPECT_EQ(msgSt.capsCnt, 0);
msgSt.uID = TEST_UID;
FreeMessageSt(&msgSt);
EXPECT_EQ(msgSt.uID, -1);
msgSt.gID = TEST_GID;
FreeMessageSt(&msgSt);
EXPECT_EQ(msgSt.gID, -1);
msgSt.bundleName = (char*)malloc(MALLOC_TEST_LENGTH);
EXPECT_TRUE(msgSt.bundleName != nullptr);
FreeMessageSt(&msgSt);
EXPECT_EQ(msgSt.bundleName, nullptr);
msgSt.identityID = (char*)malloc(MALLOC_TEST_LENGTH);
EXPECT_TRUE(msgSt.identityID != nullptr);
FreeMessageSt(&msgSt);
EXPECT_EQ(msgSt.identityID, nullptr);
msgSt.caps = (unsigned int*)malloc(MALLOC_TEST_LENGTH * sizeof(unsigned int));
EXPECT_TRUE(msgSt.caps != nullptr);
FreeMessageSt(&msgSt);
EXPECT_EQ(msgSt.caps, nullptr);
// full test
msgSt.bundleName = (char*)malloc(MALLOC_TEST_LENGTH);
msgSt.identityID = (char*)malloc(MALLOC_TEST_LENGTH);
msgSt.caps = (unsigned int*)malloc(MALLOC_TEST_LENGTH * sizeof(unsigned int));
EXPECT_TRUE(msgSt.bundleName != nullptr);
EXPECT_TRUE(msgSt.identityID != nullptr);
EXPECT_TRUE(msgSt.caps != nullptr);
msgSt.capsCnt = MALLOC_TEST_LENGTH;
msgSt.uID = TEST_UID;
msgSt.gID = TEST_GID;
FreeMessageSt(&msgSt);
EXPECT_EQ(msgSt.bundleName, nullptr);
EXPECT_EQ(msgSt.identityID, nullptr);
EXPECT_EQ(msgSt.caps, nullptr);
EXPECT_EQ(msgSt.capsCnt, 0);
EXPECT_EQ(msgSt.uID, -1);
EXPECT_EQ(msgSt.gID, -1);
}
static void GetCurrentTime(struct timespec* tmCur)
{
if (tmCur == nullptr) {
return;
}
if (clock_gettime(CLOCK_REALTIME, tmCur) != 0) {
printf("[----------] AppSpawnLiteTest, get time failed! err %d.\n", errno);
}
}
/*
** @tc.name: msgFuncSplitTest_001
** @tc.desc: split message function, bad strings test
** @tc.type: FUNC
** @tc.require: AR000F733K
** @tc.author: ZAL
**/
HWTEST_F(AppSpawnLiteTest, msgFuncSplitTest_001, TestSize.Level1)
{
MessageSt msgSt = {0};
EXPECT_NE(SplitMessage(nullptr, 0, nullptr), 0);
EXPECT_NE(SplitMessage(nullptr, 0, &msgSt), 0);
std::string testMsg = "xxxxxxxx";
EXPECT_NE(SplitMessage(testMsg.c_str(), testMsg.length(), nullptr), 0);
struct timespec tmStart = {0};
GetCurrentTime(&tmStart);
for (size_t i = 0; i < g_badStrings.size(); ++i) {
int ret = SplitMessage(g_badStrings[i].c_str(), g_badStrings[i].length(), &msgSt);
EXPECT_NE(ret, 0);
if (ret == 0) {
printf("[----------] AppSpawnLiteTest, msgFuncSplitTest_001 i = %u.\n", i);
FreeMessageSt(&msgSt);
}
}
struct timespec tmEnd = {0};
GetCurrentTime(&tmEnd);
long timeUsed = (tmEnd.tv_sec - tmStart.tv_sec) * NANOSECONDS_PER_SECOND + (tmEnd.tv_nsec - tmStart.tv_nsec);
printf("[----------] AppSpawnLiteTest, msgFuncSplitTest_001, total time %ld ns, strCnt %u.\n", \
timeUsed, g_badStrings.size());
}
/*
** @tc.name: msgFuncSplitTest_002
** @tc.desc: split message function, good strings test
** @tc.type: FUNC
** @tc.require: AR000F733K
** @tc.author: ZAL
**/
HWTEST_F(AppSpawnLiteTest, msgFuncSplitTest_002, TestSize.Level1)
{
MessageSt msgSt = {0};
struct timespec tmStart = {0};
GetCurrentTime(&tmStart);
for (size_t i = 0; i < g_goodStrings.size(); ++i) {
int ret = SplitMessage(g_goodStrings[i].c_str(), g_goodStrings[i].length(), &msgSt);
EXPECT_EQ(ret, 0);
if (ret != 0) {
printf("[----------] AppSpawnLiteTest, msgFuncSplitTest_002 i = %u.\n", i);
} else {
FreeMessageSt(&msgSt);
}
}
struct timespec tmEnd = {0};
GetCurrentTime(&tmEnd);
long timeUsed = (tmEnd.tv_sec - tmStart.tv_sec) * NANOSECONDS_PER_SECOND + (tmEnd.tv_nsec - tmStart.tv_nsec);
printf("[----------] AppSpawnLiteTest, msgFuncSplitTest_002, total time %ld ns, strCnt %u.\n", \
timeUsed, g_goodStrings.size());
// parse one good string and check all results
std::string validStr =
"{\"bundleName\":\"validName\",\"identityID\":\"135\",\"uID\":999,\"gID\":888,\"capability\":[0, 1, 5]}";
int ret = SplitMessage(validStr.c_str(), validStr.length(), &msgSt);
EXPECT_EQ(ret, 0);
std::vector<unsigned int> caps;
caps.push_back(0); // 0, test capability
caps.push_back(1); // 1, test capability
caps.push_back(5); // 5, test capability
EXPECT_NE(msgSt.bundleName, nullptr);
EXPECT_NE(msgSt.identityID, nullptr);
EXPECT_EQ(strcmp("validName", msgSt.bundleName), 0);
EXPECT_EQ(strcmp("135", msgSt.identityID), 0);
EXPECT_EQ(TEST_UID, msgSt.uID);
EXPECT_EQ(TEST_GID, msgSt.gID);
EXPECT_EQ(caps.size(), msgSt.capsCnt);
EXPECT_NE(msgSt.caps, nullptr);
for (size_t i = 0; i < caps.size(); ++i) {
EXPECT_EQ(caps[i], msgSt.caps[i]);
}
FreeMessageSt(&msgSt);
}
HWTEST_F(AppSpawnLiteTest, SetContentFunctionTest_001, TestSize.Level0)
{
GTEST_LOG_(INFO) << "SetContentFunctionTest_001 start";
AppSpawnContent *content = AppSpawnCreateContent("AppSpawn", NULL, 0, 0);
SetContentFunction(content);
char *longProcName = "SetContentFunctionTest_001";
int64_t longProcNameLen = 1024;
std::unique_ptr<AppSpawnClientExt> clientExt = std::make_unique<AppSpawnClientExt>();
clientExt->client.id = 1;
clientExt->client.flag = 0;
clientExt->fd[0] = 123;
clientExt->fd[1] = 456;
clientExt->property.uid = 10002;
clientExt->property.gid = 1000;
clientExt->property.gidCount = 1;
strcpy_s(clientExt->property.processName, APP_LEN_PROC_NAME, "com.ohos.settingsdata");
strcpy_s(clientExt->property.bundleName, APP_LEN_BUNDLE_NAME, "com.ohos.settingsdata");
strcpy_s(clientExt->property.soPath, APP_LEN_SO_PATH, " ");
clientExt->property.accessTokenId = 671201800;
strcpy_s(clientExt->property.apl, APP_APL_MAX_LEN, "system_core");
strcpy_s(clientExt->property.renderCmd, APP_RENDER_CMD_MAX_LEN, " ");
clientExt->property.flags = 0;
content->setProcessName(content, clientExt->client, longProcName, longProcNameLen);
content->setKeepCapabilities(content, clientExt->client);
content->setUidGid(content, clientExt->client);
content->setCapabilities(content, clientExt->client);
content->runChildProcessor(content, clientExt->client);
GTEST_LOG_(INFO) << "SetContentFunctionTest_001 end";
}
} // namespace OHOS

View File

@ -1,39 +0,0 @@
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//base/startup/appspawn_standard/appspawn.gni")
import("//build/test.gni")
ohos_unittest("AppSpawnMsgPeerTest") {
module_out_path = "${module_output_path}"
sources = [
"${appspawn_path}/src/appspawn_msg_peer.cpp",
"${appspawn_path}/src/socket/appspawn_socket.cpp",
"${appspawn_path}/src/socket/server_socket.cpp",
]
sources += [ "app_spawn_msg_peer_test.cpp" ]
configs = [ "${appspawn_path}:appspawn_config" ]
deps = [ "${appspawn_path}/test:appspawn_test_source" ]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
}
group("unittest") {
testonly = true
deps = [ ":AppSpawnMsgPeerTest" ]
}

View File

@ -1,224 +0,0 @@
/*
* 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 "mock_server_socket.h"
#include "appspawn_msg_peer.h"
#include "server_socket.h"
using namespace testing;
using namespace testing::ext;
using namespace OHOS::AppSpawn;
class AppSpawnMsgPeerTest : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
void SetUp();
void TearDown();
};
void AppSpawnMsgPeerTest::SetUpTestCase()
{}
void AppSpawnMsgPeerTest::TearDownTestCase()
{}
void AppSpawnMsgPeerTest::SetUp()
{}
void AppSpawnMsgPeerTest::TearDown()
{}
/*
* Feature: AppSpawn
* Function: AppSpawnMsgPeer
* SubFunction: GetConnectFd & GetMsg
* FunctionPoints: simple function branch coverage
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify if new AppSpawnMsgPeer with the invalid params and the function GetConnectFd and GetMsg will
* return default value.
*/
HWTEST(AppSpawnMsgPeerTest, App_Spawn_Msg_Peer_001, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_001 start";
std::shared_ptr<ServerSocket> serverSocket = std::make_shared<ServerSocket>("ServerSocket");
int32_t connectFd = -1;
std::unique_ptr<AppSpawnMsgPeer> appSpawnMsgPeer = std::make_unique<AppSpawnMsgPeer>(serverSocket, connectFd);
EXPECT_EQ(-1, appSpawnMsgPeer->GetConnectFd());
EXPECT_EQ(nullptr, appSpawnMsgPeer->GetMsg());
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_001 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnMsgPeer
* SubFunction: MsgPeer
* FunctionPoints: check params
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function MsgPeer can check the invalid connect fd.
*/
HWTEST(AppSpawnMsgPeerTest, App_Spawn_Msg_Peer_002, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_002 start";
std::shared_ptr<ServerSocket> serverSocket = std::make_shared<ServerSocket>("ServerSocket");
int32_t connectFd = -1;
std::unique_ptr<AppSpawnMsgPeer> appSpawnMsgPeer = std::make_unique<AppSpawnMsgPeer>(serverSocket, connectFd);
EXPECT_EQ(-EINVAL, appSpawnMsgPeer->MsgPeer());
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_002 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnMsgPeer
* SubFunction: MsgPeer
* FunctionPoints: check params
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function MsgPeer can check the invalid server socket.
*/
HWTEST(AppSpawnMsgPeerTest, App_Spawn_Msg_Peer_003, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_003 start";
std::shared_ptr<ServerSocket> serverSocket = nullptr;
int32_t connectFd = 1;
std::unique_ptr<AppSpawnMsgPeer> appSpawnMsgPeer = std::make_unique<AppSpawnMsgPeer>(serverSocket, connectFd);
EXPECT_EQ(-EINVAL, appSpawnMsgPeer->MsgPeer());
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_003 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnMsgPeer
* SubFunction: Response
* FunctionPoints: check params
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function Response can check the invalid connect fd.
*/
HWTEST(AppSpawnMsgPeerTest, App_Spawn_Msg_Peer_004, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_004 start";
std::shared_ptr<ServerSocket> serverSocket = std::make_shared<ServerSocket>("ServerSocket");
int32_t connectFd = -1;
std::unique_ptr<AppSpawnMsgPeer> appSpawnMsgPeer = std::make_unique<AppSpawnMsgPeer>(serverSocket, connectFd);
EXPECT_EQ(-EINVAL, appSpawnMsgPeer->Response(1));
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_004 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnMsgPeer
* SubFunction: Response
* FunctionPoints: check params
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function Response can check the invalid server socket.
*/
HWTEST(AppSpawnMsgPeerTest, App_Spawn_Msg_Peer_005, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_005 start";
std::shared_ptr<ServerSocket> serverSocket = nullptr;
int32_t connectFd = 1;
std::unique_ptr<AppSpawnMsgPeer> appSpawnMsgPeer = std::make_unique<AppSpawnMsgPeer>(serverSocket, connectFd);
EXPECT_EQ(-EINVAL, appSpawnMsgPeer->Response(1));
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_005 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnMsgPeer
* SubFunction: MsgPeer
* FunctionPoints: read socket message
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function MsgPeer can check the the invalid message read.
*/
HWTEST(AppSpawnMsgPeerTest, App_Spawn_Msg_Peer_006, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_006 start";
std::shared_ptr<MockServerSocket> mockServerSocket = std::make_shared<MockServerSocket>("MockServerSocket");
int32_t connectFd = 1;
std::unique_ptr<AppSpawnMsgPeer> appSpawnMsgPeer = std::make_unique<AppSpawnMsgPeer>(mockServerSocket, connectFd);
EXPECT_CALL(*mockServerSocket, ReadSocketMessage(_, _, _)).WillOnce(Return(-1));
EXPECT_CALL(*mockServerSocket, CloseConnection(_)).WillOnce(Return());
EXPECT_EQ(-EINVAL, appSpawnMsgPeer->MsgPeer());
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_006 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnMsgPeer
* SubFunction: MsgPeer
* FunctionPoints: read socket message
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function MsgPeer can check the the too long message read.
*/
HWTEST(AppSpawnMsgPeerTest, App_Spawn_Msg_Peer_007, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_007 start";
std::shared_ptr<MockServerSocket> mockServerSocket = std::make_shared<MockServerSocket>("MockServerSocket");
int32_t connectFd = 1;
std::unique_ptr<AppSpawnMsgPeer> appSpawnMsgPeer = std::make_unique<AppSpawnMsgPeer>(mockServerSocket, connectFd);
EXPECT_CALL(*mockServerSocket, ReadSocketMessage(_, _, _)).WillOnce(Return(sizeof(ClientSocket::AppProperty) + 1));
EXPECT_CALL(*mockServerSocket, CloseConnection(_)).WillOnce(Return());
EXPECT_EQ(-EINVAL, appSpawnMsgPeer->MsgPeer());
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_007 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnMsgPeer
* SubFunction: MsgPeer
* FunctionPoints: read socket message
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function MsgPeer read socket message.
*/
HWTEST(AppSpawnMsgPeerTest, App_Spawn_Msg_Peer_008, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_008 start";
std::shared_ptr<MockServerSocket> mockServerSocket = std::make_shared<MockServerSocket>("MockServerSocket");
int32_t connectFd = 1;
std::unique_ptr<AppSpawnMsgPeer> appSpawnMsgPeer = std::make_unique<AppSpawnMsgPeer>(mockServerSocket, connectFd);
EXPECT_EQ(nullptr, appSpawnMsgPeer->GetMsg());
EXPECT_CALL(*mockServerSocket, ReadSocketMessage(_, _, _))
.WillOnce(Invoke(mockServerSocket.get(), &MockServerSocket::ReadImplValid));
EXPECT_CALL(*mockServerSocket, CloseConnection(_)).WillOnce(Return());
EXPECT_EQ(0, appSpawnMsgPeer->MsgPeer());
EXPECT_NE(nullptr, appSpawnMsgPeer->GetMsg());
GTEST_LOG_(INFO) << "App_Spawn_Msg_Peer_008 end";
}

View File

@ -1,115 +0,0 @@
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//base/startup/appspawn_standard/appspawn.gni")
import("//build/test.gni")
ohos_unittest("AppSpawnServerOverrideTest") {
module_out_path = "${module_output_path}"
include_dirs = [
"//base/security/access_token/interfaces/innerkits/token_setproc/include",
"//base/startup/init_lite/services/log",
"//base/startup/init_lite/interfaces/innerkits/include",
"//base/startup/syspara_lite/interfaces/innerkits/native/syspara/include",
]
sources = [
"${appspawn_path}/src/appspawn_server.cpp",
"${appspawn_path}/src/socket/appspawn_socket.cpp",
]
sources += [
"${appspawn_path}/test/mock/src/appspawn_msg_peer.cpp",
"${appspawn_path}/test/mock/src/main_thread.cpp",
"${appspawn_path}/test/mock/src/server_socket.cpp",
"app_spawn_server_override_test.cpp",
]
deps = [
"${appspawn_path}/test:appspawn_test_source",
"//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc",
"//base/startup/init_lite/interfaces/innerkits:libbegetutil",
"//base/startup/init_lite/services/log:init_log",
"//base/startup/syspara_lite/interfaces/innerkits/native/syspara:syspara",
]
external_deps = [
"ability_base:want",
"hilog_native:libhilog",
"hiviewdfx_hilog_native:libhilog",
"ipc:ipc_core",
"safwk:system_ability_fwk",
"samgr_standard:samgr_proxy",
]
if (build_selinux) {
external_deps += [ "selinux:libhap_restorecon" ]
cflags = [ "-DWITH_SELINUX" ]
}
}
ohos_unittest("AppSpawnServerMockTest") {
module_out_path = "${module_output_path}"
include_dirs = [
"//base/security/access_token/interfaces/innerkits/token_setproc/include",
"//base/startup/init_lite/services/log",
"//base/startup/init_lite/interfaces/innerkits/include",
"//base/startup/syspara_lite/interfaces/innerkits/native/syspara/include",
]
sources = [
"${appspawn_path}/src/appspawn_msg_peer.cpp",
"${appspawn_path}/src/appspawn_server.cpp",
"${appspawn_path}/src/socket/appspawn_socket.cpp",
"${appspawn_path}/src/socket/server_socket.cpp",
]
sources += [
"${appspawn_path}/test/mock/src/main_thread.cpp",
"app_spawn_server_mock_test.cpp",
]
deps = [
"${appspawn_path}/test:appspawn_test_source",
"//base/security/access_token/interfaces/innerkits/token_setproc:libtoken_setproc",
"//base/startup/init_lite/interfaces/innerkits:libbegetutil",
"//base/startup/init_lite/interfaces/innerkits/socket:libsocket_static",
"//base/startup/init_lite/services/log:init_log",
"//base/startup/syspara_lite/interfaces/innerkits/native/syspara:syspara",
]
external_deps = [
"ability_base:want",
"hilog_native:libhilog",
"hiviewdfx_hilog_native:libhilog",
"ipc:ipc_core",
"safwk:system_ability_fwk",
"samgr_standard:samgr_proxy",
]
if (build_selinux) {
external_deps += [ "selinux:libhap_restorecon" ]
cflags = [ "-DWITH_SELINUX" ]
}
}
group("unittest") {
testonly = true
deps = [
":AppSpawnServerMockTest",
":AppSpawnServerOverrideTest",
]
}

View File

@ -1,162 +0,0 @@
/*
* 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 <thread>
#include <unistd.h>
#include "mock_server_socket.h"
// redefine private and protected since testcase need to invoke and test private function
#define private public
#define protected public
#include "appspawn_server.h"
#undef private
#undef protected
using namespace testing;
using namespace testing::ext;
using namespace OHOS::AppSpawn;
static constexpr int TEST_WAIT_TIME = 50 * 1000; // 50 ms
class AppSpawnServerMockTest : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
void SetUp();
void TearDown();
protected:
std::unique_ptr<AppSpawnServer> appSpawnServer_ = nullptr;
std::shared_ptr<MockServerSocket> mockServerSocket_ = nullptr;
};
void AppSpawnServerMockTest::SetUpTestCase()
{}
void AppSpawnServerMockTest::TearDownTestCase()
{}
void AppSpawnServerMockTest::SetUp()
{
if (mockServerSocket_ == nullptr) {
mockServerSocket_ = std::make_shared<MockServerSocket>("MockServerSocket");
}
if (appSpawnServer_ == nullptr) {
appSpawnServer_ = std::make_unique<AppSpawnServer>("AppSpawnServerMockTest");
appSpawnServer_->SetServerSocket(mockServerSocket_);
}
}
void AppSpawnServerMockTest::TearDown()
{}
/*
* Feature: AppSpawn
* Function: AppSpawnServer
* SubFunction: ServerMain
* FunctionPoints: check params
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify if the socket name is empty, the function ServerMain start fail.
*/
HWTEST_F(AppSpawnServerMockTest, App_Spawn_Server_001, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Server_001 start";
std::unique_ptr<AppSpawnServer> appSpawnServer = std::make_unique<AppSpawnServer>("");
char argv[20] = "LongNameTest";
EXPECT_EQ(false, appSpawnServer->ServerMain(argv, sizeof(argv)));
GTEST_LOG_(INFO) << "App_Spawn_Server_001 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnServer
* SubFunction: ServerMain
* FunctionPoints: check params
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function ServerMain can check the gidcount > max.
*/
HWTEST_F(AppSpawnServerMockTest, App_Spawn_Server_002, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Server_002 start";
char argv[20] = "LongNameTest";
testing::Mock::AllowLeak(mockServerSocket_.get());
EXPECT_CALL(*mockServerSocket_, RegisterServerSocket()).WillOnce(Return(0));
EXPECT_CALL(*mockServerSocket_, WaitForConnection()).WillRepeatedly(Return(1));
EXPECT_CALL(*mockServerSocket_, SaveConnection(_)).WillRepeatedly(Return());
EXPECT_CALL(*mockServerSocket_, ReadSocketMessage(_, _, _))
.WillRepeatedly(Invoke(mockServerSocket_.get(), &MockServerSocket::ReadImplGidCountMax));
EXPECT_CALL(*mockServerSocket_, CloseConnection(_)).WillRepeatedly(Return());
EXPECT_CALL(*mockServerSocket_, CloseServerMonitor()).WillRepeatedly(Return());
EXPECT_CALL(*mockServerSocket_, WriteSocketMessage(_, _, _)).WillRepeatedly(Return(sizeof(pid_t)));
auto func = [&]() {
// wait ServerMain unit test case
usleep(TEST_WAIT_TIME);
appSpawnServer_->SetRunning(false);
};
std::thread(func).detach();
EXPECT_EQ(false, appSpawnServer_->ServerMain(argv, sizeof(argv)));
// wait release
usleep(TEST_WAIT_TIME);
GTEST_LOG_(INFO) << "App_Spawn_Server_002 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnServer
* SubFunction: ServerMain
* FunctionPoints: check params
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function ServerMain can check the process name is empty.
*/
HWTEST_F(AppSpawnServerMockTest, App_Spawn_Server_003, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Server_003 start";
char argv[20] = "LongNameTest";
testing::Mock::AllowLeak(mockServerSocket_.get());
EXPECT_CALL(*mockServerSocket_, RegisterServerSocket()).WillOnce(Return(0));
EXPECT_CALL(*mockServerSocket_, WaitForConnection()).WillRepeatedly(Return(1));
EXPECT_CALL(*mockServerSocket_, SaveConnection(_)).WillRepeatedly(Return());
EXPECT_CALL(*mockServerSocket_, ReadSocketMessage(_, _, _))
.WillRepeatedly(Invoke(mockServerSocket_.get(), &MockServerSocket::ReadImplProcessName));
EXPECT_CALL(*mockServerSocket_, CloseConnection(_)).WillRepeatedly(Return());
EXPECT_CALL(*mockServerSocket_, CloseServerMonitor()).WillRepeatedly(Return());
EXPECT_CALL(*mockServerSocket_, WriteSocketMessage(_, _, _)).WillRepeatedly(Return(sizeof(pid_t)));
auto func = [=]() {
// wait ServerMain unit test case
usleep(TEST_WAIT_TIME);
appSpawnServer_->SetRunning(false);
};
std::thread(func).detach();
EXPECT_EQ(false, appSpawnServer_->ServerMain(argv, sizeof(argv)));
// wait release
usleep(TEST_WAIT_TIME);
GTEST_LOG_(INFO) << "App_Spawn_Server_003 end";
}

View File

@ -1,219 +0,0 @@
/*
* 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 <thread>
#include <unistd.h>
// redefine private and protected since testcase need to invoke and test private function
#define private public
#define protected public
#include "appspawn_server.h"
#undef private
#undef protected
#include <dirent.h>
#include <dlfcn.h>
using namespace testing;
using namespace testing::ext;
using namespace OHOS::AppSpawn;
static constexpr int TEST_WAIT_TIME = 50 * 1000; // 50 ms
class AppSpawnServerOverrideTest : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
void SetUp();
void TearDown();
protected:
std::unique_ptr<AppSpawnServer> appSpawnServer_ = nullptr;
};
void AppSpawnServerOverrideTest::SetUpTestCase()
{}
void AppSpawnServerOverrideTest::TearDownTestCase()
{}
void AppSpawnServerOverrideTest::SetUp()
{
if (appSpawnServer_ == nullptr) {
appSpawnServer_ = std::make_unique<AppSpawnServer>("AppSpawnServerOverrideTest");
}
}
void AppSpawnServerOverrideTest::TearDown()
{}
/*
* Feature: AppSpawn
* Function: AppSpawnServer
* SubFunction: ServerMain
* FunctionPoints: fork app process
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function ServerMain fork app process success.
*/
HWTEST_F(AppSpawnServerOverrideTest, App_Spawn_Server_Override_001, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_001 start";
char argv[20] = "LongNameTest";
auto func = [&]() {
// wait ServerMain unit test case
usleep(TEST_WAIT_TIME);
appSpawnServer_->SetRunning(false);
};
std::thread(func).detach();
EXPECT_EQ(false, appSpawnServer_->ServerMain(argv, sizeof(argv)));
// wait release
usleep(TEST_WAIT_TIME);
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_001 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnServer
* SubFunction: SetProcessName
* FunctionPoints: set process name
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function SetProcessName and longProcName param is nullptr.
*/
HWTEST_F(AppSpawnServerOverrideTest, App_Spawn_Server_Override_002, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_002 start";
char *longProcName = nullptr;
int64_t longProcNameLen = sizeof(longProcName);
char processName[16] = "LongNameTest";
int32_t len = sizeof(processName);
EXPECT_EQ(-EINVAL, appSpawnServer_->SetProcessName(longProcName, longProcNameLen, processName, len));
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_002 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnServer
* SubFunction: SetProcessName
* FunctionPoints: set process name
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function SetProcessName and processName param is nullptr.
*/
HWTEST_F(AppSpawnServerOverrideTest, App_Spawn_Server_Override_003, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_003 start";
char longProcName[20] = "longProcName";
int64_t longProcNameLen = sizeof(longProcName);
char *processName = nullptr;
int32_t len = sizeof(processName);
EXPECT_EQ(-EINVAL, appSpawnServer_->SetProcessName(longProcName, longProcNameLen, processName, len));
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_003 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnServer
* SubFunction: SetProcessName
* FunctionPoints: set process name
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function SetProcessName and len param is 0.
*/
HWTEST_F(AppSpawnServerOverrideTest, App_Spawn_Server_Override_004, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_004 start";
char longProcName[20] = "longProcName";
int64_t longProcNameLen = sizeof(longProcName);
char processName[16] = "processName";
int32_t len = 0;
EXPECT_EQ(-EINVAL, appSpawnServer_->SetProcessName(longProcName, longProcNameLen, processName, len));
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_004 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnServer
* SubFunction: SetProcessName
* FunctionPoints: set process name
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function SetProcessName and len param is -1.
*/
HWTEST_F(AppSpawnServerOverrideTest, App_Spawn_Server_Override_005, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_005 start";
char longProcName[20] = "longProcName";
int64_t longProcNameLen = sizeof(longProcName);
char processName[16] = "processName";
int32_t len = -1;
EXPECT_EQ(-EINVAL, appSpawnServer_->SetProcessName(longProcName, longProcNameLen, processName, len));
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_005 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnServer
* SubFunction: SetProcessName
* FunctionPoints: set process name
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function SetProcessName and processName length < 16.
*/
HWTEST_F(AppSpawnServerOverrideTest, App_Spawn_Server_Override_006, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_006 start";
char longProcName[20] = "longProcName";
int64_t longProcNameLen = sizeof(longProcName);
char processName[16] = "processName";
int32_t len = sizeof(processName);
EXPECT_EQ(0, appSpawnServer_->SetProcessName(longProcName, longProcNameLen, processName, len));
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_006 end";
}
/*
* Feature: AppSpawn
* Function: AppSpawnServer
* SubFunction: SetProcessName
* FunctionPoints: set process name
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function SetProcessName and processName length > 16.
*/
HWTEST_F(AppSpawnServerOverrideTest, App_Spawn_Server_Override_007, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_007 start";
char longProcName[20] = "longProcName";
int64_t longProcNameLen = strlen(longProcName);
char processName[32] = "processName0123456789";
int32_t len = sizeof(processName);
EXPECT_EQ(0, appSpawnServer_->SetProcessName(longProcName, longProcNameLen, processName, len));
GTEST_LOG_(INFO) << "App_Spawn_Server_Override_007 end";
}

View File

@ -17,7 +17,8 @@ import("//build/test.gni")
ohos_unittest("AppSpawnSocketTest") {
module_out_path = "${module_output_path}"
sources = [ "${appspawn_path}/src/socket/appspawn_socket.cpp" ]
sources =
[ "${appspawn_path}/interfaces/innerkits/client/appspawn_socket.cpp" ]
sources += [ "app_spawn_socket_test.cpp" ]

View File

@ -0,0 +1,60 @@
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//base/startup/appspawn_standard/appspawn.gni")
import("//build/test.gni")
ohos_unittest("AppSpawnStandardTest") {
module_out_path = "${module_output_path}"
defines = [
"usleep(time) = MockSleep(time)",
"APPSPAWN_TEST",
]
include_dirs = [
"${appspawn_path}/standard/",
"${appspawn_path}/common/",
]
configs = [ "${appspawn_path}:appspawn_config" ]
sources = [
"${appspawn_path}/adapter/appspawn_ace.cpp",
"${appspawn_path}/standard/appspawn_process.c",
"${appspawn_path}/standard/appspawn_service.c",
"app_spawn_standard_test.cpp",
]
deps = [
"${appspawn_path}:appspawn_server",
"${appspawn_path}/test:appspawn_test_source",
"//base/startup/init_lite/interfaces/innerkits:libbegetutil",
"//base/startup/init_lite/interfaces/innerkits/sandbox:libsandbox",
"//foundation/aafwk/standard/frameworks/kits/appkit:appkit_native",
]
external_deps = [
"ability_base:want",
"ability_runtime:app_manager",
"hiviewdfx_hilog_native:libhilog",
"ipc:ipc_core",
"utils_base:utils",
]
}
group("unittest") {
testonly = true
deps = [ ":AppSpawnStandardTest" ]
}

View File

@ -0,0 +1,189 @@
/*
* 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 <memory>
#include <gtest/gtest.h>
#include <cstring>
#include <cerrno>
// redefine private and protected since testcase need to invoke and test private function
#define private public
#define protected public
#include "appspawn_service.h"
#undef private
#undef protected
#include "securec.h"
#include "appspawn_adapter.h"
#include "appspawn_server.h"
using namespace testing;
using namespace testing::ext;
namespace OHOS {
class AppSpawnStandardTest : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
void SetUp();
void TearDown();
};
void AppSpawnStandardTest::SetUpTestCase()
{}
void AppSpawnStandardTest::TearDownTestCase()
{}
void AppSpawnStandardTest::SetUp()
{}
void AppSpawnStandardTest::TearDown()
{}
HWTEST(AppSpawnStandardTest, App_Spawn_Standard_001, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Standard_001 start";
string longProcName = "AppSpawnStandardTest1";
int64_t longProcNameLen = longProcName.length();
int cold = 1;
AppSpawnContent *content = AppSpawnCreateContent("AppSpawn", (char*)longProcName.c_str(), longProcNameLen, cold);
EXPECT_TRUE(content);
content->loadExtendLib = LoadExtendLib;
content->runChildProcessor = RunChildProcessor;
char *const argv[] = {};
content->initAppSpawn(content);
AppSpawnColdRun(content, 1, argv);
GTEST_LOG_(INFO) << "App_Spawn_Standard_001 end";
}
HWTEST(AppSpawnStandardTest, App_Spawn_Standard_002, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Standard_002 start";
string longProcName = "AppSpawnStandardTest2";
int64_t longProcNameLen = longProcName.length();
AppSpawnClientExt* client = (AppSpawnClientExt*)malloc(sizeof(AppSpawnClientExt));
client->client.id = 1;
client->client.flags = 1;
if (strcpy_s(client->property.apl, APP_APL_MAX_LEN, "system_basic") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
pid_t pid = 100;
AppSpawnContentExt* appSpawnContent = (AppSpawnContentExt*)malloc(sizeof(AppSpawnContentExt));
EXPECT_TRUE(appSpawnContent);
if (strcpy_s(appSpawnContent->content.longProcName, longProcNameLen, longProcName.c_str()) != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
};
appSpawnContent->content.longProcNameLen = longProcNameLen;
appSpawnContent->timer = NULL;
appSpawnContent->content.runAppSpawn = NULL;
appSpawnContent->content.initAppSpawn = NULL;
appSpawnContent->content.registerAppSandbox = NULL;
AppSpawnProcessMsg(&appSpawnContent->content, &client->client, &pid);
free(appSpawnContent);
free(client);
GTEST_LOG_(INFO) << "App_Spawn_Standard_002 end";
}
HWTEST(AppSpawnStandardTest, App_Spawn_Standard_003, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Standard_003 start";
string longProcName = "AppSpawnStandardTest3";
int64_t longProcNameLen = longProcName.length();
std::unique_ptr<AppSpawnClientExt> clientExt = std::make_unique<AppSpawnClientExt>();
clientExt->client.id = 1;
clientExt->client.flags = 0;
clientExt->fd[0] = 123;
clientExt->fd[1] = 456;
clientExt->property.uid = 10002;
clientExt->property.gid = 1000;
clientExt->property.gidCount = 1;
if (strcpy_s(clientExt->property.processName, APP_LEN_PROC_NAME, "com.ohos.settingsdata") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
if (strcpy_s(clientExt->property.bundleName, APP_LEN_BUNDLE_NAME, "com.ohos.settingsdata") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
if (strcpy_s(clientExt->property.soPath, APP_LEN_SO_PATH, "/test") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
clientExt->property.accessTokenId = 671201800;
if (strcpy_s(clientExt->property.apl, APP_APL_MAX_LEN, "system_core") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
if (strcpy_s(clientExt->property.renderCmd, APP_RENDER_CMD_MAX_LEN, "cmd_test") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
clientExt->property.flags = 0;
AppSpawnContent *content = AppSpawnCreateContent("AppSpawn", (char*)longProcName.c_str(), longProcNameLen, 1);
content->loadExtendLib = LoadExtendLib;
content->runChildProcessor = RunChildProcessor;
SetContentFunction(content);
content->clearEnvironment(content, &clientExt->client);
EXPECT_EQ(content->setProcessName(content, &clientExt->client, (char*)longProcName.c_str(), longProcNameLen), 0);
EXPECT_EQ(content->setKeepCapabilities(content, &clientExt->client), 0);
EXPECT_EQ(content->setUidGid(content, &clientExt->client), 0);
EXPECT_EQ(content->setCapabilities(content, &clientExt->client), 0);
content->setAppSandbox(content, &clientExt->client);
content->setAppAccessToken(content, &clientExt->client);
EXPECT_EQ(content->coldStartApp(content, &clientExt->client), 0);
DoStartApp(content, &clientExt->client, (char*)longProcName.c_str(), longProcNameLen);
free(content);
GTEST_LOG_(INFO) << "App_Spawn_Standard_003 end";
}
HWTEST(AppSpawnStandardTest, App_Spawn_Standard_004, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Standard_004 start";
AppSpawnClientExt* client = (AppSpawnClientExt*)malloc(sizeof(AppSpawnClientExt));
client->client.id = 1;
client->client.flags = 0;
client->fd[0] = 1;
client->fd[1] = 2;
client->property.uid = 10000;
client->property.gid = 1000;
client->property.gidCount = 1;
if (strcpy_s(client->property.processName, APP_LEN_PROC_NAME, "test4") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
if (strcpy_s(client->property.bundleName, APP_LEN_BUNDLE_NAME, "test4") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
if (strcpy_s(client->property.soPath, APP_LEN_SO_PATH, "test4") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
client->property.accessTokenId = 671201800;
if (strcpy_s(client->property.apl, APP_APL_MAX_LEN, "system_core") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
if (strcpy_s(client->property.renderCmd, APP_RENDER_CMD_MAX_LEN, "test4") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
client->property.flags = 0;
char* argv[] = {(char*)"AppSpawnStandardTest4", (char*)"test4"};
int argc = sizeof(argv)/sizeof(argv[0]);
EXPECT_EQ(GetAppSpawnClientFromArg(argc, argv, client), -1);
free(client);
GTEST_LOG_(INFO) << "App_Spawn_Standard_004 end";
}
} // namespace OHOS

View File

@ -20,8 +20,8 @@ ohos_unittest("ClientSocketTest") {
defines = [ "usleep(time) = MockSleep(time)" ]
sources = [
"${appspawn_path}/src/socket/appspawn_socket.cpp",
"${appspawn_path}/src/socket/client_socket.cpp",
"${appspawn_path}/interfaces/innerkits/client/appspawn_socket.cpp",
"${appspawn_path}/interfaces/innerkits/client/client_socket.cpp",
]
sources += [ "client_socket_test.cpp" ]

View File

@ -1,40 +0,0 @@
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//base/startup/appspawn_standard/appspawn.gni")
import("//build/test.gni")
ohos_unittest("ServerSocketTest") {
module_out_path = "${module_output_path}"
defines = [ "usleep(time) = MockSleep(time)" ]
sources = [
"${appspawn_path}/src/socket/appspawn_socket.cpp",
"${appspawn_path}/src/socket/server_socket.cpp",
]
sources += [ "server_socket_test.cpp" ]
configs = [ "${appspawn_path}:appspawn_config" ]
deps = [ "${appspawn_path}/test:appspawn_test_source" ]
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
}
group("unittest") {
testonly = true
deps = [ ":ServerSocketTest" ]
}

View File

@ -1,185 +0,0 @@
/*
* 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 <memory>
#include <gtest/gtest.h>
#include <cerrno>
// redefine private and protected since testcase need to invoke and test private function
#define private public
#define protected public
#include "server_socket.h"
#undef private
#undef protected
#include "securec.h"
using namespace testing;
using namespace testing::ext;
using namespace OHOS::AppSpawn;
class ServerSocketTest : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
void SetUp();
void TearDown();
};
void ServerSocketTest::SetUpTestCase()
{}
void ServerSocketTest::TearDownTestCase()
{}
void ServerSocketTest::SetUp()
{}
void ServerSocketTest::TearDown()
{}
/*
* Feature: AppSpawn
* Function: ServerSocket
* SubFunction: RegisterServerSocket
* FunctionPoints: create server socket
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function RegisterServerSocket can called twice, but the socket fd is same.
*/
HWTEST(ServerSocketTest, Server_Socket_001, TestSize.Level0)
{
GTEST_LOG_(INFO) << "Server_Socket_001 start";
std::unique_ptr<ServerSocket> serverSocket = std::make_unique<ServerSocket>("ServerSocketTest");
EXPECT_EQ(-1, serverSocket->GetSocketFd());
EXPECT_EQ(0, serverSocket->RegisterServerSocket());
int32_t socketFd = serverSocket->GetSocketFd();
EXPECT_LE(0, socketFd);
EXPECT_EQ(0, serverSocket->RegisterServerSocket());
EXPECT_EQ(socketFd, serverSocket->GetSocketFd());
GTEST_LOG_(INFO) << "Server_Socket_001 end";
}
/*
* Feature: AppSpawn
* Function: ServerSocket
* SubFunction: RegisterServerSocket
* FunctionPoints: create server socket
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function RegisterServerSocket create server socket fail with the empty socket name.
*/
HWTEST(ServerSocketTest, Server_Socket_002, TestSize.Level0)
{
GTEST_LOG_(INFO) << "Server_Socket_002 start";
std::unique_ptr<ServerSocket> serverSocket = std::make_unique<ServerSocket>("");
EXPECT_EQ(-EINVAL, serverSocket->RegisterServerSocket());
GTEST_LOG_(INFO) << "Server_Socket_002 end";
}
/*
* Feature: AppSpawn
* Function: ServerSocket
* SubFunction: WaitForConnection
* FunctionPoints: accept socket
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function WaitForConnection accept fail when don't create server socket.
*/
HWTEST(ServerSocketTest, Server_Socket_003, TestSize.Level0)
{
GTEST_LOG_(INFO) << "Server_Socket_003 start";
std::unique_ptr<ServerSocket> serverSocket = std::make_unique<ServerSocket>("ServerSocketTest");
EXPECT_EQ(-ENOTSOCK, serverSocket->WaitForConnection(0));
GTEST_LOG_(INFO) << "Server_Socket_003 end";
}
/*
* Feature: AppSpawn
* Function: ServerSocket
* SubFunction: SaveConnection & VerifyConnection & CloseConnection
* FunctionPoints: connect fd
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the connect fd which be saved or not saved, then close the saved connect fd and verify them.
*/
HWTEST(ServerSocketTest, Server_Socket_004, TestSize.Level0)
{
GTEST_LOG_(INFO) << "Server_Socket_004 start";
std::unique_ptr<ServerSocket> serverSocket = std::make_unique<ServerSocket>("ServerSocketTest");
int32_t connectFd1 = 111;
int32_t connectFd2 = 222;
int32_t connectFd3 = 333;
serverSocket->SaveConnection(connectFd1);
serverSocket->SaveConnection(connectFd2);
EXPECT_EQ(0, serverSocket->VerifyConnection(connectFd1));
EXPECT_EQ(0, serverSocket->VerifyConnection(connectFd2));
EXPECT_EQ(-1, serverSocket->VerifyConnection(connectFd3));
serverSocket->CloseConnection(connectFd2);
EXPECT_EQ(-1, serverSocket->VerifyConnection(connectFd2));
GTEST_LOG_(INFO) << "Server_Socket_004 end";
}
/*
* Feature: AppSpawn
* Function: ServerSocket
* SubFunction: CloseServerMonitor
* FunctionPoints: close the server socket
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function CloseServerMonitor which can close the server socket which has created
* successfully.
*/
HWTEST(ServerSocketTest, Server_Socket_005, TestSize.Level0)
{
GTEST_LOG_(INFO) << "Server_Socket_005 start";
std::unique_ptr<ServerSocket> serverSocket = std::make_unique<ServerSocket>("ServerSocketTest");
EXPECT_EQ(0, serverSocket->RegisterServerSocket());
EXPECT_LE(0, serverSocket->GetSocketFd());
serverSocket->CloseServerMonitor();
EXPECT_EQ(-1, serverSocket->GetSocketFd());
GTEST_LOG_(INFO) << "Server_Socket_005 end";
}
/*
* Feature: AppSpawn
* Function: ServerSocket
* SubFunction: RegisterServerSocket
* FunctionPoints: bind socket fail
* EnvConditions: mobile that can run ohos test framework
* CaseDescription: Verify the function RegisterServerSocket BindSocket fail and close the socket fd.
*/
HWTEST(ServerSocketTest, Server_Socket_006, TestSize.Level0)
{
GTEST_LOG_(INFO) << "Server_Socket_006 start";
std::string invalidSocketName =
"InvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalid"
"InvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalidInvalid";
std::unique_ptr<ServerSocket> serverSocket = std::make_unique<ServerSocket>(invalidSocketName.c_str());
EXPECT_EQ(-ENOENT, serverSocket->RegisterServerSocket());
EXPECT_EQ(-1, serverSocket->GetSocketFd());
GTEST_LOG_(INFO) << "Server_Socket_006 end";
}

View File

@ -1,75 +0,0 @@
/*
* 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 <cstring>
#include "appspawn_server.h"
#include "client_socket.h"
#include "hilog/log.h"
#include "securec.h"
using namespace OHOS;
using namespace OHOS::HiviewDFX;
static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "AppSpawnServer"};
static const int DECIMAL = 10;
int main(int argc, char *const argv[])
{
if (argc <= 11) { // 11 min argc
HiLog::Error(LABEL, "Invalid argc %{public}d", argc);
return -1;
}
HiLog::Debug(LABEL, "AppSpawnServer argc %{public}d app:%{public}s", argc, argv[4]); // 4 name index
// calculate child process long name size
uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
uintptr_t end = reinterpret_cast<uintptr_t>(strchr(argv[argc - 1], 0));
if (end == 0) {
return -1;
}
uintptr_t argvSize = end - start;
auto appProperty = std::make_unique<OHOS::AppSpawn::ClientSocket::AppProperty>();
if (appProperty == nullptr) {
HiLog::Error(LABEL, "Failed to create app property %{public}s", argv[4]); // 4 name index
return -1;
}
int index = 1;
int fd = strtoul(argv[index++], nullptr, DECIMAL);
appProperty->uid = strtoul(argv[index++], nullptr, DECIMAL);
appProperty->gid = strtoul(argv[index++], nullptr, DECIMAL);
(void)strcpy_s(appProperty->processName, sizeof(appProperty->processName), argv[index++]);
(void)strcpy_s(appProperty->bundleName, sizeof(appProperty->bundleName), argv[index++]);
(void)strcpy_s(appProperty->soPath, sizeof(appProperty->soPath), argv[index++]);
appProperty->accessTokenId = strtoul(argv[index++], nullptr, DECIMAL);
(void)strcpy_s(appProperty->apl, sizeof(appProperty->apl), argv[index++]);
(void)strcpy_s(appProperty->renderCmd, sizeof(appProperty->renderCmd), argv[index++]);
appProperty->flags = strtoul(argv[index++], nullptr, DECIMAL);
appProperty->gidCount = strtoul(argv[index++], nullptr, DECIMAL);
uint32_t i = 0;
while ((i < appProperty->gidCount) && (i < sizeof(appProperty->gidTable) / sizeof(appProperty->gidTable[0]))) {
if (index >= argc) {
HiLog::Error(LABEL, "Invalid arg %{public}d %{public}d", index, argc);
return -1;
}
appProperty->gidTable[i++] = strtoul(argv[index++], nullptr, DECIMAL);
}
auto appspawnServer = std::make_shared<OHOS::AppSpawn::AppSpawnServer>("AppSpawn");
if (appspawnServer != nullptr) {
int ret = appspawnServer->AppColdStart(argv[0], argvSize, appProperty.get(), fd);
if (ret != 0) {
HiLog::Error(LABEL, "Cold start %{public}s fail.", appProperty->bundleName);
}
}
return 0;
}