mirror of
https://gitee.com/openharmony/startup_appspawn
synced 2024-10-07 00:03:33 +00:00
appspawn归一化
Signed-off-by: xlei1030 <xionglei6@huawei.com>
This commit is contained in:
parent
f051e55945
commit
f7b7dddb2b
119
BUILD.gn
119
BUILD.gn
@ -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
46
adapter/appspawn_ace.cpp
Normal 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
|
||||
}
|
42
adapter/appspawn_adapter.cpp
Normal file
42
adapter/appspawn_adapter.cpp
Normal 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
|
||||
}
|
37
adapter/appspawn_adapter.h
Normal file
37
adapter/appspawn_adapter.h
Normal 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
83
adapter/appspawn_log.cpp
Normal 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
118
adapter/appspawn_nweb.cpp
Normal 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;
|
||||
}
|
414
adapter/appspawn_sandbox.cpp
Normal file
414
adapter/appspawn_sandbox.cpp
Normal 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;
|
||||
}
|
@ -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"
|
||||
|
@ -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
137
common/appspawn_server.c
Normal 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
116
common/appspawn_server.h
Normal 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
|
@ -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" ]
|
||||
|
@ -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;
|
||||
}
|
||||
|
80
interfaces/innerkits/include/appspawn_msg.h
Normal file
80
interfaces/innerkits/include/appspawn_msg.h
Normal 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
|
@ -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
40
interfaces/innerkits/include/client_socket.h
Executable file → Normal 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
83
lite/BUILD.gn
Normal 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
204
lite/appspawn_message.c
Normal 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
57
lite/appspawn_message.h
Normal 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
193
lite/appspawn_process.c
Normal 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
206
lite/appspawn_service.c
Normal 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
44
lite/bundle.json
Normal 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
85
lite/main.c
Normal 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();
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
"socket" : [{
|
||||
"name" : "NWebSpawn",
|
||||
"family" : "AF_LOCAL",
|
||||
"type" : "SOCK_SEQPACKET",
|
||||
"type" : "SOCK_STREAM",
|
||||
"protocol" : "default",
|
||||
"permissions" : "0666",
|
||||
"uid" : "root",
|
||||
|
@ -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
@ -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
|
@ -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
|
@ -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
|
38
src/main.cpp
38
src/main.cpp
@ -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;
|
||||
}
|
@ -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
385
standard/appspawn_process.c
Normal 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
472
standard/appspawn_service.c
Normal 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;
|
||||
}
|
68
standard/appspawn_service.h
Normal file
68
standard/appspawn_service.h
Normal 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
52
standard/main.c
Normal 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;
|
||||
}
|
@ -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",
|
||||
]
|
||||
}
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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",
|
||||
|
@ -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 ¶ms)
|
||||
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)
|
||||
{
|
||||
|
46
test/unittest/app_spawn_lite_test/BUILD.gn
Normal file
46
test/unittest/app_spawn_lite_test/BUILD.gn
Normal 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" ]
|
||||
}
|
399
test/unittest/app_spawn_lite_test/app_spawn_lite_test.cpp
Normal file
399
test/unittest/app_spawn_lite_test/app_spawn_lite_test.cpp
Normal 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
|
@ -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" ]
|
||||
}
|
@ -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";
|
||||
}
|
@ -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",
|
||||
]
|
||||
}
|
@ -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";
|
||||
}
|
@ -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";
|
||||
}
|
@ -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" ]
|
||||
|
||||
|
60
test/unittest/app_spawn_standard_test/BUILD.gn
Normal file
60
test/unittest/app_spawn_standard_test/BUILD.gn
Normal 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" ]
|
||||
}
|
@ -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
|
@ -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" ]
|
||||
|
@ -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" ]
|
||||
}
|
@ -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";
|
||||
}
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user