From 7dd2dffd3fda2a114c83b793d10a0eeb71fa4a4b Mon Sep 17 00:00:00 2001 From: xlei1030 Date: Mon, 11 Apr 2022 19:30:05 +0800 Subject: [PATCH] =?UTF-8?q?appspawn=E5=BD=92=E4=B8=80=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: xlei1030 --- BUILD.gn | 107 +- adapter/appspawn_ace.cpp | 38 + adapter/appspawn_adapter.cpp | 42 + src/main.cpp => adapter/appspawn_adapter.h | 74 +- adapter/appspawn_log.cpp | 83 ++ adapter/appspawn_nweb.cpp | 63 + adapter/appspawn_sandbox.cpp | 330 +++++ appspawn.gni | 4 +- appspawn.rc | 2 +- common/appspawn_server.c | 132 ++ common/appspawn_server.h | 114 ++ interfaces/innerkits/BUILD.gn | 6 +- .../innerkits/client}/appspawn_socket.cpp | 23 +- .../innerkits/client}/client_socket.cpp | 22 +- interfaces/innerkits/include/appspawn_msg.h | 75 ++ interfaces/innerkits/include/client_socket.h | 32 +- lite/BUILD.gn | 80 ++ lite/appspawn_message.c | 204 ++++ lite/appspawn_message.h | 57 + lite/appspawn_process.c | 192 +++ lite/appspawn_service.c | 205 ++++ lite/bundle.json | 44 + lite/main.c | 85 ++ nwebspawn.cfg | 2 +- src/appspawn_msg_peer.cpp | 96 -- src/appspawn_server.cpp | 1077 ----------------- src/include/appspawn_msg_peer.h | 79 -- src/include/appspawn_server.h | 219 ---- src/include/server_socket.h | 132 -- src/socket/server_socket.cpp | 232 ---- standard/appspawn_process.c | 368 ++++++ standard/appspawn_service.c | 410 +++++++ standard/appspawn_service.h | 65 + standard/main.c | 49 + tools/appspawn_start_app.cpp | 11 +- 35 files changed, 2748 insertions(+), 2006 deletions(-) create mode 100644 adapter/appspawn_ace.cpp create mode 100644 adapter/appspawn_adapter.cpp rename src/main.cpp => adapter/appspawn_adapter.h (46%) create mode 100644 adapter/appspawn_log.cpp create mode 100644 adapter/appspawn_nweb.cpp create mode 100644 adapter/appspawn_sandbox.cpp create mode 100644 common/appspawn_server.c create mode 100644 common/appspawn_server.h rename {src/socket => interfaces/innerkits/client}/appspawn_socket.cpp (79%) rename {src/socket => interfaces/innerkits/client}/client_socket.cpp (78%) create mode 100644 interfaces/innerkits/include/appspawn_msg.h create mode 100644 lite/BUILD.gn create mode 100644 lite/appspawn_message.c create mode 100644 lite/appspawn_message.h create mode 100644 lite/appspawn_process.c create mode 100644 lite/appspawn_service.c create mode 100644 lite/bundle.json create mode 100644 lite/main.c delete mode 100644 src/appspawn_msg_peer.cpp delete mode 100644 src/appspawn_server.cpp delete mode 100644 src/include/appspawn_msg_peer.h delete mode 100644 src/include/appspawn_server.h delete mode 100644 src/include/server_socket.h delete mode 100644 src/socket/server_socket.cpp create mode 100644 standard/appspawn_process.c create mode 100644 standard/appspawn_service.c create mode 100644 standard/appspawn_service.h create mode 100644 standard/main.c diff --git a/BUILD.gn b/BUILD.gn index c59f4a43..c7f18d65 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -17,7 +17,9 @@ 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", @@ -32,9 +34,11 @@ config("appspawn_config") { "${aafwk_path}/interfaces/innerkits/base/include", "${aafwk_path}/frameworks/kits/ability/native/include", "${aafwk_path}/services/abilitymgr/include", - "${distributedschedule_path}/services/dtbschedmgr/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/syspara_lite/interfaces/innerkits/native/syspara/include", ] @@ -45,13 +49,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}" @@ -60,33 +73,24 @@ 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 = [ "INIT_AGENT" ] + defines = [ "GRAPHIC_PERMISSION_CHECK" ] 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/syspara_lite/interfaces/innerkits/native/syspara:syspara", + "//third_party/libuv:uv_static", "//utils/native/base:utils", ] - external_deps = [ - "ability_base:want", - "bundle_framework:appexecfwk_base", - "bundle_framework:appexecfwk_core", - "hilog_native:libhilog", - "hiviewdfx_hilog_native:libhilog", - "ipc:ipc_core", - "safwk:system_ability_fwk", - "samgr_standard:samgr_proxy", - ] - + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] if (build_selinux) { external_deps += [ "selinux:libhap_restorecon" ] } @@ -98,10 +102,7 @@ ohos_static_library("appspawn_server") { 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", - ] + deps = [ "${appspawn_path}:appspawn_server" ] external_deps = [ "hiviewdfx_hilog_native:libhilog" ] install_enable = true @@ -118,56 +119,14 @@ ohos_prebuilt_etc("appspawn.rc") { ohos_executable("nwebspawn") { defines = [ "NWEB_SPAWN" ] - sources = [ "${appspawn_path}/src/main.cpp" ] - configs = [ ":appspawn_config" ] - deps = [ - "${appspawn_path}:nwebspawn_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_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", + "${appspawn_path}/adapter/appspawn_nweb.cpp", + "${appspawn_path}/standard/main.c", ] 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", - "bundle_framework:appexecfwk_base", - "bundle_framework:appexecfwk_core", - "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" ] - } + deps = [ "${appspawn_path}:appspawn_server" ] + install_enable = true subsystem_name = "${subsystem_name}" part_name = "${part_name}" } diff --git a/adapter/appspawn_ace.cpp b/adapter/appspawn_ace.cpp new file mode 100644 index 00000000..0a442698 --- /dev/null +++ b/adapter/appspawn_ace.cpp @@ -0,0 +1,38 @@ +/* + * 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) +{ + const char *acelibdir = "/system/lib/libace.z.so"; + void *AceAbilityLib = NULL; + APPSPAWN_LOGI("MainThread::LoadAbilityLibrary. Start calling dlopen acelibdir."); + AceAbilityLib = dlopen(acelibdir, RTLD_NOW | RTLD_GLOBAL); + 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"); + OHOS::AppExecFwk::MainThread::Start(); +} \ No newline at end of file diff --git a/adapter/appspawn_adapter.cpp b/adapter/appspawn_adapter.cpp new file mode 100644 index 00000000..d8319748 --- /dev/null +++ b/adapter/appspawn_adapter.cpp @@ -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 + +#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 +} diff --git a/src/main.cpp b/adapter/appspawn_adapter.h similarity index 46% rename from src/main.cpp rename to adapter/appspawn_adapter.h index 95ae423a..b2f3e5f6 100644 --- a/src/main.cpp +++ b/adapter/appspawn_adapter.h @@ -1,38 +1,36 @@ -/* - * Copyright (c) 2021 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 - -#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(argv[0]); - uintptr_t end = reinterpret_cast(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; -} +/* + * 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 +#include + +#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); + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/adapter/appspawn_log.cpp b/adapter/appspawn_log.cpp new file mode 100644 index 00000000..97c48069 --- /dev/null +++ b/adapter/appspawn_log.cpp @@ -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 +#include +#include +#include +#include +#include + +#include "hilog/log.h" +#include "securec.h" + +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); + fclose(outfile); + return; +} diff --git a/adapter/appspawn_nweb.cpp b/adapter/appspawn_nweb.cpp new file mode 100644 index 00000000..707b560c --- /dev/null +++ b/adapter/appspawn_nweb.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "appspawn_adapter.h" + +#include +#include + +void *g_nwebHandle = NULL; + +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; + typedef void (*FuncType)(const char *cmd); + FuncType funcNWebRenderMain = (FuncType)(dlsym(g_nwebHandle, "NWebRenderMain")); + if (funcNWebRenderMain == NULL) { + APPSPAWN_LOGI("webviewspawn dlsym ERROR=%s", dlerror()); + return; + } + funcNWebRenderMain(appProperty->property.renderCmd); +} \ No newline at end of file diff --git a/adapter/appspawn_sandbox.cpp b/adapter/appspawn_sandbox.cpp new file mode 100644 index 00000000..f038ea75 --- /dev/null +++ b/adapter/appspawn_sandbox.cpp @@ -0,0 +1,330 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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/"; + const std::string oriappdataPath = "/data/accounts/account_0/appdata/"; + 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"; + std::string destappdataPath = rootPath + oriappdataPath; + + int rc = 0; + + std::string bundleName = appProperty.bundleName; + oriInstallPath += bundleName; + oriel1DataPath += bundleName; + oriel2DataPath += bundleName; + oriDatabasePath += bundleName; + + std::map mountMap; + mountMap[destDatabasePath] = oriDatabasePath; + mountMap[destInstallPath] = oriInstallPath; + mountMap[destel1DataPath] = oriel1DataPath; + mountMap[destel2DataPath] = oriel2DataPath; + mountMap[destappdataPath] = oriappdataPath; + + std::map::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 mkdirInfo; + std::string dirPath; + mkdirInfo.push_back("/data/storage/el1/bundle/nweb"); + mkdirInfo.push_back("/data/storage/el1/bundle/ohos.global.systemres"); + + for (int 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 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 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//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/accounts/account_0/appdata/"); + 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(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL); + if (rc) { + APPSPAWN_LOGE("set propagation slave failed"); + return rc; + } + + // bind mount "/" to /mnt/sandbox/ path + // rootfs: to do more resources bind mount here to get more strict resources constraints + rc = mount("/", sandboxPackagePath.c_str(), NULL, MS_BIND | MS_REC, NULL); + if (rc) { + APPSPAWN_LOGE("mount bind / failed"); + return rc; + } + + return 0; +} + +static int32_t DoSandboxRootFolderCreate(const std::string &sandboxPackagePath) +{ + int rc = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL); + 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/ path mkdir + std::map mountMap; + std::vector 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/ path + std::map::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/ path + // bin -> /system/bin + // d -> /sys/kernel/debug + // etc -> /system/etc + // init -> /system/bin/init + // lib -> /system/lib + // sdcard -> /storage/self/primary + std::map symlinkMap; + symlinkMap["/system/bin"] = sandboxPackagePath + "/bin"; + symlinkMap["/sys/kernel/debug"] = sandboxPackagePath + "/d"; + symlinkMap["/system/etc"] = sandboxPackagePath + "/etc"; + symlinkMap["/system/bin/init"] = sandboxPackagePath + "/init"; + symlinkMap["/system/lib"] = sandboxPackagePath + "/lib"; + + for (iter = symlinkMap.begin(); iter != symlinkMap.end(); ++iter) { + symlink(iter->first.c_str(), iter->second.c_str()); + } + + return 0; +} + +int32_t SetAppSandboxProperty(struct AppSpawnContent_ *content, AppSpawnClient *client) +{ + int rc = 0; + AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client; + // create /mnt/sandbox/ path, later put it to rootfs module + std::string sandboxPackagePath = "/mnt/sandbox/"; + mkdir(sandboxPackagePath.c_str(), FILE_MODE); + 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//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; +} diff --git a/appspawn.gni b/appspawn.gni index 6f978961..4dc58471 100644 --- a/appspawn.gni +++ b/appspawn.gni @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Huawei Device Co., Ltd. +# 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 @@ -14,8 +14,6 @@ appspawn_path = "//base/startup/appspawn_standard" appexecfwk_path = "//foundation/appexecfwk/standard" aafwk_path = "//foundation/aafwk/standard" -communication_path = "//foundation/communication/ipc" -distributedschedule_path = "//foundation/distributedschedule/dmsfwk" subsystem_name = "startup" part_name = "appspawn" module_output_path = "${part_name}/appspawn_l2" diff --git a/appspawn.rc b/appspawn.rc index 4f1b82c8..1150046e 100644 --- a/appspawn.rc +++ b/appspawn.rc @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Huawei Device Co., Ltd. +# 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 diff --git a/common/appspawn_server.c b/common/appspawn_server.c new file mode 100644 index 00000000..6d2c76aa --- /dev/null +++ b/common/appspawn_server.c @@ -0,0 +1,132 @@ +/* + * 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 +#include +#include +#ifdef OHOS_DEBUG +#include +#endif // OHOS_DEBUG + +static int NotifyResToParent(struct AppSpawnContent_ *content, AppSpawnClient *client, int result) +{ + if (content->notifyResToParent != NULL) { + content->notifyResToParent(content, client, result); + } + return 0; +} + +void DoStartApp(struct AppSpawnContent_ *content, AppSpawnClient *client, char *longProcName, int64_t longProcNameLen) +{ + APPSPAWN_LOGI("DoStartApp id %d ", client->id); + int32_t ret = 0; + if (content->setAppSandbox) { + ret = content->setAppSandbox(content, client); + APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret); + return, "Failed to set app sandbox"); + } + if (content->setKeepCapabilities) { + ret = content->setKeepCapabilities(content, client); + APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret); + return, "Failed to set KeepCapabilities"); + } + if (content->setProcessName) { + ret = content->setProcessName(content, client, longProcName, longProcNameLen); + APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret); + return, "Failed to set setProcessName"); + } + + if (content->setUidGid) { + ret = content->setUidGid(content, client); + APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret); + return, "Failed to setUidGid"); + } + if (content->setFileDescriptors) { + ret = content->setFileDescriptors(content, client); + APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret); + return, "Failed to setFileDescriptors"); + } + if (content->setCapabilities) { + ret = content->setCapabilities(content, client); + APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret); + return, "Failed to setCapabilities"); + } + // notify success to father process and start app process + NotifyResToParent(content, client, 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); + + 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); + } + if (client->flags & APP_COLD_START) { + if (content->coldStartApp != NULL && content->coldStartApp(content, client) == 0) { + NotifyResToParent(content, client, 0); + _exit(0x7f); + return -1; + } else { + DoStartApp(content, client, content->longProcName, content->longProcNameLen); + } + } else { + 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 (content->runChildProcessor) { + content->runChildProcessor(content, client); + } + APPSPAWN_LOGI("App exit %d.", getpid()); + _exit(0x7f); + } + *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 \ No newline at end of file diff --git a/common/appspawn_server.h b/common/appspawn_server.h new file mode 100644 index 00000000..293401f9 --- /dev/null +++ b/common/appspawn_server.h @@ -0,0 +1,114 @@ +/* + * 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 +#include +#include +#include +#ifdef OHOS_DEBUG +#include +#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; + int64_t longProcNameLen; + + // system + void (*loadExtendLib)(struct AppSpawnContent_ *content); + void (*initAppSpawn)(struct AppSpawnContent_ *content); + void (*runAppSpawn)(struct AppSpawnContent_ *content); + + // for child + void (*clearEnvironment)(struct AppSpawnContent_ *content, AppSpawnClient *client); + int (*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, int64_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); +} AppSpawnContent; + +AppSpawnContent *AppSpawnCreateContent(const char *socketName, char *longProcName, int64_t longProcNameLen, int cold); +int AppSpawnProcessMsg(struct AppSpawnContent_ *content, AppSpawnClient *client, pid_t *childPid); +void DoStartApp(struct AppSpawnContent_ *content, AppSpawnClient *client, char *longProcName, int64_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_LOGI(fmt, ...) AppspawnLogPrint(INFO, FILE_NAME, __LINE__, fmt, ##__VA_ARGS__) +#define APPSPAWN_LOGE(fmt, ...) AppspawnLogPrint(ERROR, FILE_NAME, __LINE__, fmt, ##__VA_ARGS__) +#define APPSPAWN_LOGV(fmt, ...) AppspawnLogPrint(DEBUG, FILE_NAME, __LINE__, fmt, ##__VA_ARGS__) +#define APPSPAWN_LOGW(fmt, ...) AppspawnLogPrint(WARN, FILE_NAME, __LINE__, fmt, ##__VA_ARGS__) + +#define APPSPAWN_CHECK(retCode, exper, ...) \ + if (!(retCode)) { \ + APPSPAWN_LOGE(__VA_ARGS__); \ + exper; \ + } + +#ifdef __cplusplus +} +#endif +#endif // APPSPAWN_SERVER_H diff --git a/interfaces/innerkits/BUILD.gn b/interfaces/innerkits/BUILD.gn index 8e7b6ebd..8060586a 100644 --- a/interfaces/innerkits/BUILD.gn +++ b/interfaces/innerkits/BUILD.gn @@ -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" ] diff --git a/src/socket/appspawn_socket.cpp b/interfaces/innerkits/client/appspawn_socket.cpp similarity index 79% rename from src/socket/appspawn_socket.cpp rename to interfaces/innerkits/client/appspawn_socket.cpp index 4c0caf6a..b1521f0b 100644 --- a/src/socket/appspawn_socket.cpp +++ b/interfaces/innerkits/client/appspawn_socket.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * 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 @@ -66,7 +66,7 @@ int AppSpawnSocket::PackSocketAddr() } socklen_t pathSize = sizeof(socketAddr_.sun_path); if (pathLen >= pathSize) { - HiLog::Error(LABEL, "Invalid socket name: '%s' too long", socketName_.c_str()); + HiLog::Error(LABEL, "Invalid socket name: '%{public}s' too long", socketName_.c_str()); return -1; } @@ -90,20 +90,20 @@ 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: %d", errno); + HiLog::Error(LABEL, "Failed to create socket: %{public}d", errno); return (-errno); } - HiLog::Debug(LABEL, "Created socket with fd %d", socketFd); + HiLog::Debug(LABEL, "Created socket with fd %{public}d", socketFd); return socketFd; } void AppSpawnSocket::CloseSocket(int &socketFd) { if (socketFd >= 0) { - HiLog::Debug(LABEL, "Closed socket with fd %d", socketFd); + HiLog::Debug(LABEL, "Closed socket with fd %{public}d", socketFd); close(socketFd); socketFd = -1; } @@ -112,7 +112,7 @@ void AppSpawnSocket::CloseSocket(int &socketFd) int AppSpawnSocket::ReadSocketMessage(int socketFd, void *buf, int len) { if (socketFd < 0 || len <= 0 || buf == nullptr) { - HiLog::Error(LABEL, "Invalid args: socket %d, len %d, buf might be nullptr", socketFd, len); + HiLog::Error(LABEL, "Invalid args: socket %{public}d, len %{public}d, buf might be nullptr", socketFd, len); return -1; } @@ -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 %d error %zd: %d", socketFd, rLen, errno); + HiLog::Error(LABEL, "Read message from fd %{public}d error %{public}zd: %{public}d", socketFd, rLen, errno); return -EFAULT; } @@ -133,7 +133,7 @@ int AppSpawnSocket::ReadSocketMessage(int socketFd, void *buf, int len) int AppSpawnSocket::WriteSocketMessage(int socketFd, const void *buf, int len) { if (socketFd < 0 || len <= 0 || buf == nullptr) { - HiLog::Error(LABEL, "Invalid args: socket %d, len %d, buf might be nullptr", socketFd, len); + HiLog::Error(LABEL, "Invalid args: socket %{public}d, len %{public}d, buf might be nullptr", socketFd, len); return -1; } @@ -142,9 +142,10 @@ int AppSpawnSocket::WriteSocketMessage(int socketFd, const void *buf, int len) const uint8_t *offset = reinterpret_cast(buf); for (ssize_t wLen = 0; remain > 0; offset += wLen, remain -= wLen, written += wLen) { wLen = write(socketFd, offset, remain); - HiLog::Debug(LABEL, "socket fd %d, wLen %zd", socketFd, wLen); + HiLog::Debug(LABEL, "socket fd %{public}d, wLen %zd", socketFd, wLen); if ((wLen <= 0) && (errno != EINTR)) { - HiLog::Error(LABEL, "Failed to write message to fd %d, error %zd: %d", socketFd, wLen, errno); + HiLog::Error(LABEL, "Failed to write message to fd %{public}d, error %zd: %{public}d", + socketFd, wLen, errno); return (-errno); } } diff --git a/src/socket/client_socket.cpp b/interfaces/innerkits/client/client_socket.cpp similarity index 78% rename from src/socket/client_socket.cpp rename to interfaces/innerkits/client/client_socket.cpp index 308f389c..3c240bde 100644 --- a/src/socket/client_socket.cpp +++ b/interfaces/innerkits/client/client_socket.cpp @@ -40,14 +40,14 @@ int ClientSocket::CreateClient() } } - HiLog::Debug(LABEL, "Client: CreateClient socket fd %d", socketFd_); + HiLog::Debug(LABEL, "Client: CreateClient socket fd %{public}d", socketFd_); return 0; } void ClientSocket::CloseClient() { if (socketFd_ < 0) { - HiLog::Error(LABEL, "Client: Invalid connectFd %d", socketFd_); + HiLog::Error(LABEL, "Client: Invalid connectFd %{public}d", socketFd_); return; } @@ -58,35 +58,37 @@ void ClientSocket::CloseClient() int ClientSocket::ConnectSocket(int connectFd) { if (connectFd < 0) { - HiLog::Error(LABEL, "Client: Invalid socket fd: %d", connectFd); + HiLog::Error(LABEL, "Client: Invalid socket fd: %{public}d", connectFd); return -1; } if (PackSocketAddr() != 0) { - CloseSocket(connectFd); return -1; } if ((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, "Client: Failed to set opt of socket %d, err %d", connectFd, errno); - CloseSocket(connectFd); + HiLog::Warn(LABEL, "Client: Failed to set opt of socket %{public}d, err %{public}d", connectFd, errno); return -1; } if (connect(connectFd, reinterpret_cast(&socketAddr_), socketAddrLen_) < 0) { - HiLog::Warn(LABEL, "Client: Connect on socket fd %d, failed: %d", connectFd, errno); - CloseSocket(connectFd); + HiLog::Warn(LABEL, "Client: Connect on socket fd %{public}d, failed: %{public}d", connectFd, errno); return -1; } - HiLog::Debug(LABEL, "Client: Connected on socket fd %d, name '%s'", connectFd, socketAddr_.sun_path); + HiLog::Debug(LABEL, "Client: Connected on socket fd %{public}d, name '%{public}s'", + connectFd, socketAddr_.sun_path); return 0; } int ClientSocket::ConnectSocket() { - return ConnectSocket(socketFd_); + int ret = ConnectSocket(socketFd_); + if (ret != 0) { + CloseClient(); + } + return ret; } int ClientSocket::WriteSocketMessage(const void *buf, int len) diff --git a/interfaces/innerkits/include/appspawn_msg.h b/interfaces/innerkits/include/appspawn_msg.h new file mode 100644 index 00000000..c8cf40fa --- /dev/null +++ b/interfaces/innerkits/include/appspawn_msg.h @@ -0,0 +1,75 @@ +/* + * 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 +#include +#include +#include + +#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 +}; + +#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; +} AppParameter; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/interfaces/innerkits/include/client_socket.h b/interfaces/innerkits/include/client_socket.h index 85e979a6..029f64f1 100644 --- a/interfaces/innerkits/include/client_socket.h +++ b/interfaces/innerkits/include/client_socket.h @@ -17,6 +17,7 @@ #define APPSPAWN_SOCKET_CLIENT_H #include "appspawn_socket.h" +#include "appspawn_msg.h" #include "nocopyable.h" namespace OHOS { @@ -83,29 +84,16 @@ 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; - - 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; - }; + 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; private: /** * Connects a client socket. diff --git a/lite/BUILD.gn b/lite/BUILD.gn new file mode 100644 index 00000000..0ff0232a --- /dev/null +++ b/lite/BUILD.gn @@ -0,0 +1,80 @@ +# Copyright (c) 2020 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 = [ + "../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", + ] + + 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 += [] + } +} \ No newline at end of file diff --git a/lite/appspawn_message.c b/lite/appspawn_message.c new file mode 100644 index 00000000..81b26d6c --- /dev/null +++ b/lite/appspawn_message.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2020 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 +#include +#include +#include + +#ifdef __LINUX__ +#include +#else +#include +#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; +} diff --git a/lite/appspawn_message.h b/lite/appspawn_message.h new file mode 100644 index 00000000..32c596a1 --- /dev/null +++ b/lite/appspawn_message.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 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 +#include + +#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 diff --git a/lite/appspawn_process.c b/lite/appspawn_process.c new file mode 100644 index 00000000..bc9f5ca7 --- /dev/null +++ b/lite/appspawn_process.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2020 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. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#ifdef __LINUX__ +#include +#include +#include +#include +#else +#include +#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, int64_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; +} \ No newline at end of file diff --git a/lite/appspawn_service.c b/lite/appspawn_service.c new file mode 100644 index 00000000..dcd67327 --- /dev/null +++ b/lite/appspawn_service.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2020 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 +#include +#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; + +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, int64_t longProcNameLen) +{ + 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)); + client->client.id = 100; + 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); + // free(client); + 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); diff --git a/lite/bundle.json b/lite/bundle.json new file mode 100644 index 00000000..382e8c47 --- /dev/null +++ b/lite/bundle.json @@ -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" + ] + } + } +} \ No newline at end of file diff --git a/lite/main.c b/lite/main.c new file mode 100644 index 00000000..ae14476d --- /dev/null +++ b/lite/main.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 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 +#include +#include +#include +#include + +#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() +{ + 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(); + } +} diff --git a/nwebspawn.cfg b/nwebspawn.cfg index 7e5dbc73..7046d9b2 100644 --- a/nwebspawn.cfg +++ b/nwebspawn.cfg @@ -5,7 +5,7 @@ "socket" : [{ "name" : "NWebSpawn", "family" : "AF_LOCAL", - "type" : "SOCK_SEQPACKET", + "type" : "SOCK_STREAM", "protocol" : "default", "permissions" : "0666", "uid" : "root", diff --git a/src/appspawn_msg_peer.cpp b/src/appspawn_msg_peer.cpp deleted file mode 100644 index e658e755..00000000 --- a/src/appspawn_msg_peer.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2021 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 - -#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 &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(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 %d", connectFd_); - return -EINVAL; - } - - if (socket_->WriteSocketMessage(connectFd_, &pid, sizeof(pid)) != sizeof(pid)) { - HiLog::Error(LABEL, "Failed to write message: connectFd %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(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 diff --git a/src/appspawn_server.cpp b/src/appspawn_server.cpp deleted file mode 100644 index 0c6814d4..00000000 --- a/src/appspawn_server.cpp +++ /dev/null @@ -1,1077 +0,0 @@ -/* - * Copyright (c) 2021 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "errors.h" -#include "hilog/log.h" -#include "main_thread.h" -#include "securec.h" -#include "bundle_mgr_interface.h" -#include "if_system_ability_manager.h" -#include "iservice_registry.h" -#include "system_ability_definition.h" -#include "token_setproc.h" -#include "parameter.h" -#include "parameters.h" -#include "beget_ext.h" -#ifdef WITH_SELINUX -#include "hap_restorecon.h" -#endif - -#include -#include -#include -#include -#include - -constexpr static mode_t FILE_MODE = 0711; -constexpr static mode_t NWEB_FILE_MODE = 0511; - -#define APPSPAWN_LOGI(fmt, ...) STARTUP_LOGI("appspawn_server.log", "APPSPAWN", fmt, ##__VA_ARGS__) -#define APPSPAWN_LOGE(fmt, ...) STARTUP_LOGE("appspawn_server.log", "APPSPAWN", fmt, ##__VA_ARGS__) -#define GRAPHIC_PERMISSION_CHECK - -namespace OHOS { -namespace AppSpawn { -namespace { -constexpr int32_t ERR_PIPE_FAIL = -100; -constexpr int32_t MAX_LEN_SHORT_NAME = 16; -constexpr int32_t WAIT_DELAY_US = 100 * 1000; // 100ms -constexpr int32_t GID_USER_DATA_RW = 1008; -constexpr int32_t MAX_GIDS = 64; -constexpr int32_t UID_BASE = 200000; -constexpr int32_t WAIT_PARAM_TIME = 5; - -constexpr std::string_view BUNDLE_NAME_MEDIA_LIBRARY("com.ohos.medialibrary.MediaLibraryDataA"); -constexpr std::string_view BUNDLE_NAME_SCANNER("com.ohos.medialibrary.MediaScannerAbilityA"); -constexpr std::string_view APL_SYSTEM_CORE("system_core"); -constexpr std::string_view APL_SYSTEM_BASIC("system_basic"); -} // namespace - -using namespace OHOS::HiviewDFX; -static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "AppSpawnServer"}; - -#ifdef __cplusplus -extern "C" { -#endif - -static void SignalHandler([[maybe_unused]] int sig) -{ - pid_t pid; - int status; - - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - } -} - -static void InstallSigHandler() -{ - struct sigaction sa = {}; - sa.sa_handler = SignalHandler; - int err = sigaction(SIGCHLD, &sa, nullptr); - if (err < 0) { - HiLog::Error(LABEL, "Error installing SIGCHLD handler: %{public}d", errno); - return; - } - - struct sigaction sah = {}; - sah.sa_handler = SIG_IGN; - err = sigaction(SIGHUP, &sah, nullptr); - if (err < 0) { - HiLog::Error(LABEL, "Error installing SIGHUP handler: %{public}d", errno); - } -} - -static void UninstallSigHandler() -{ - struct sigaction sa = {}; - sa.sa_handler = nullptr; - int err = sigaction(SIGCHLD, &sa, nullptr); - if (err < 0) { - HiLog::Error(LABEL, "Error uninstalling SIGCHLD handler: %d", errno); - } - - struct sigaction sah = {}; - sah.sa_handler = nullptr; - err = sigaction(SIGHUP, &sah, nullptr); - if (err < 0) { - HiLog::Error(LABEL, "Error uninstalling SIGHUP handler: %d", errno); - } -} -#ifdef __cplusplus -} -#endif - -AppSpawnServer::AppSpawnServer(const std::string &socketName) -{ - socketName_ = socketName; - socket_ = std::make_shared(socketName_); - isRunning_ = true; -} - -void AppSpawnServer::MsgPeer(int connectFd) -{ - std::unique_ptr msgPeer = std::make_unique(socket_, connectFd); - if (msgPeer == nullptr || msgPeer->MsgPeer() != 0) { - HiLog::Error(LABEL, "Failed to listen connection %d, %d", connectFd, errno); - return; - } - - std::lock_guard lock(mut_); - appQueue_.push(std::move(msgPeer)); - dataCond_.notify_one(); -} - -void AppSpawnServer::ConnectionPeer() -{ - int connectFd; - - /* AppSpawn keeps receiving msg from AppMgr and never exits */ - while (isRunning_) { - connectFd = socket_->WaitForConnection(); - if (connectFd < 0) { - usleep(WAIT_DELAY_US); - HiLog::Info(LABEL, "AppSpawnServer::ConnectionPeer connectFd is %{public}d", connectFd); - continue; - } - - mut_.lock(); // Ensure that mutex in SaveConnection is unlocked before being forked - socket_->SaveConnection(connectFd); - mut_.unlock(); - std::thread(&AppSpawnServer::MsgPeer, this, connectFd).detach(); - } -} - -void AppSpawnServer::WaitRebootEvent() -{ - APPSPAWN_LOGI("wait 'startup.device.ctl' event"); - while (isRunning_) { - int ret = WaitParameter("startup.device.ctl", "stop", WAIT_PARAM_TIME); - if (ret == 0) { - std::lock_guard lock(mut_); - isStop_ = true; - dataCond_.notify_one(); - break; - } else { - std::string value = OHOS::system::GetParameter("startup.device.ctl", ""); - if (value == "stop") { - std::lock_guard lock(mut_); - isStop_ = true; - dataCond_.notify_one(); - break; - } - } - } -} - -void AppSpawnServer::HandleSignal() -{ - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGCHLD); - sigprocmask(SIG_BLOCK, &mask, nullptr); - int signalFd = signalfd(-1, &mask, SFD_CLOEXEC); - if (signalFd < 0) { - APPSPAWN_LOGE("Error installing SIGHUP handler: %d", errno); - } - while (isRunning_) { - struct signalfd_siginfo fdsi; - ssize_t ret = read(signalFd, &fdsi, sizeof(fdsi)); - if (ret != sizeof(fdsi) || fdsi.ssi_signo != SIGCHLD) { - continue; - } - pid_t pid; - int status; - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - APPSPAWN_LOGE("HandleSignal: %d", pid); - } - - std::lock_guard lock(mut_); - isChildDie_ = true; - childPid_ = fdsi.ssi_pid; - APPSPAWN_LOGI("exit app pid = %d", childPid_); - dataCond_.notify_one(); - } - close(signalFd); - signalFd = -1; -} - -void AppSpawnServer::LoadAceLib() -{ -#ifdef NWEB_SPAWN - 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) { - HiLog::Error(LABEL, "Fail to dlopen libweb_engine.so, [%{public}s]", dlerror()); - } else { - HiLog::Info(LABEL, "Success to dlopen libweb_engine.so"); - } -#ifdef __MUSL__ - nwebHandle = dlopen_ns(&dlns, "libnweb_render.so", RTLD_NOW | RTLD_GLOBAL); -#else - const std::string RENDER_LIB_DIR = LOAD_LIB_DIR + "/libnweb_render.so"; - nwebHandle = dlopen(RENDER_LIB_DIR.c_str(), RTLD_NOW | RTLD_GLOBAL); -#endif - if (nwebHandle == nullptr) { - HiLog::Error(LABEL, "Fail to dlopen libnweb_render.so, [%{public}s]", dlerror()); - } else { - HiLog::Info(LABEL, "Success to dlopen libnweb_render.so"); - } - -#else - std::string acelibdir("/system/lib/libace.z.so"); - void *AceAbilityLib = nullptr; - HiLog::Info(LABEL, "MainThread::LoadAbilityLibrary. Start calling dlopen acelibdir."); - AceAbilityLib = dlopen(acelibdir.c_str(), RTLD_NOW | RTLD_GLOBAL); - if (AceAbilityLib == nullptr) { - HiLog::Error(LABEL, "Fail to dlopen %{public}s, [%{public}s]", acelibdir.c_str(), dlerror()); - } else { - HiLog::Info(LABEL, "Success to dlopen %{public}s", acelibdir.c_str()); - } - HiLog::Info(LABEL, "MainThread::LoadAbilityLibrary. End calling dlopen."); -#endif -} - -static void InitDebugParams(const ClientSocket::AppProperty *appProperty) -{ - if (access("/system/lib/libhidebug.so", F_OK) != 0) { - HiLog::Error(LABEL, "access failed, errno = %{public}d", errno); - return; - } - void* handle = dlopen("/system/lib/libhidebug.so", RTLD_LAZY); - if (handle == nullptr) { - HiLog::Error(LABEL, "Failed to dlopen libhidebug.so, %{public}s", dlerror()); - return; - } - bool (* initParam)(const char *name); - initParam = (bool (*)(const char *name))dlsym(handle, "InitEnvironmentParam"); - if (initParam == nullptr) { - HiLog::Error(LABEL, "Failed to dlsym InitEnvironmentParam, %{public}s", dlerror()); - dlclose(handle); - return; - } - bool ret = (*initParam)(appProperty->processName); - if (!ret) { - HiLog::Error(LABEL, "init parameters failed."); - } - dlclose(handle); -} - -static void ClearEnvironment(void) -{ - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGCHLD); - sigprocmask(SIG_UNBLOCK, &mask, nullptr); - return; -} - -int AppSpawnServer::DoColdStartApp(ClientSocket::AppProperty *appProperty, int fd) -{ - APPSPAWN_LOGI("DoColdStartApp::appName %s", appProperty->processName); - std::vector extractedCmds; - extractedCmds.push_back(const_cast("/system/bin/appspawntools")); - std::string tmp = std::to_string(fd); - APPSPAWN_LOGI("DoColdStartApp::fd %d %s", fd, tmp.c_str()); - extractedCmds.push_back(const_cast(tmp.c_str())); - std::string uid = std::to_string(appProperty->uid); - APPSPAWN_LOGI("DoColdStartApp::uid %d gid %d %s", appProperty->uid, appProperty->gid, uid.c_str()); - extractedCmds.push_back(const_cast(uid.c_str())); - std::string gid = std::to_string(appProperty->gid); - extractedCmds.push_back(const_cast(gid.c_str())); - extractedCmds.push_back(const_cast(appProperty->processName)); - extractedCmds.push_back(const_cast(appProperty->bundleName)); - extractedCmds.push_back(const_cast(appProperty->soPath)); - std::string accessTokenId = std::to_string(appProperty->accessTokenId); - APPSPAWN_LOGI("DoColdStartApp::accessTokenId %d %s", appProperty->accessTokenId, accessTokenId.c_str()); - extractedCmds.push_back(const_cast(accessTokenId.c_str())); - extractedCmds.push_back(const_cast(appProperty->apl)); - APPSPAWN_LOGI("DoColdStartApp renderCmd %s", appProperty->renderCmd); - extractedCmds.push_back(const_cast(appProperty->renderCmd)); - std::string flags = std::to_string(appProperty->flags); - extractedCmds.push_back(const_cast(flags.c_str())); - std::string gidCount = std::to_string(appProperty->gidCount); - APPSPAWN_LOGI("DoColdStartApp gidCount %d %s", appProperty->gidCount, gidCount.c_str()); - extractedCmds.push_back(const_cast(gidCount.c_str())); - for (uint32_t i = 0; i < appProperty->gidCount; i++) { - extractedCmds.push_back(const_cast(std::string(std::to_string(appProperty->gidTable[i])).c_str())); - } - extractedCmds.push_back(nullptr); - APPSPAWN_LOGI("DoColdStartApp extractedCmds %d", extractedCmds.size()); - int ret = execv(extractedCmds[0], extractedCmds.data()); - if (ret) { - HiLog::Error(LABEL, "Failed to execv, errno = %{public}d", errno); - NotifyResToParentProc(fd, -1); - } - return 0; -} - -int AppSpawnServer::StartApp(char *longProcName, int64_t longProcNameLen, - ClientSocket::AppProperty *appProperty, int connectFd, pid_t &pid) -{ - if (!CheckAppProperty(appProperty)) { - return -EINVAL; - } - int32_t fd[FDLEN2] = {FD_INIT_VALUE, FD_INIT_VALUE}; - int32_t buff = 0; - if (pipe(fd) == -1) { - HiLog::Error(LABEL, "create pipe fail, errno = %{public}d", errno); - return ERR_PIPE_FAIL; - } - - InstallSigHandler(); - pid = fork(); - if (pid < 0) { - HiLog::Error(LABEL, "AppSpawnServer::Failed to fork new process, errno = %{public}d", errno); - close(fd[0]); - close(fd[1]); - return -errno; - } else if (pid == 0) { - InitDebugParams(appProperty); - SpecialHandle(appProperty); - // close socket connection and peer socket in child process - if (socket_ != NULL) { - socket_->CloseConnection(connectFd); - socket_->CloseServerMonitor(); - } - close(fd[0]); // close read fd - ClearEnvironment(); - UninstallSigHandler(); - SetAppAccessToken(appProperty); - if ((appProperty->flags == ClientSocket::APPSPAWN_COLD_BOOT) && - OHOS::system::GetBoolParameter("appspawn.cold.boot", false)) { - DoColdStartApp(appProperty, fd[1]); - } else { - SetAppProcProperty(appProperty, longProcName, longProcNameLen, fd[1]); - } - _exit(0); - } - read(fd[0], &buff, sizeof(buff)); // wait child process resutl - close(fd[0]); - close(fd[1]); - - HiLog::Info(LABEL, "child process init %{public}s", (buff == ERR_OK) ? "success" : "fail"); - return (buff == ERR_OK) ? 0 : buff; -} - -void AppSpawnServer::QuickExitMain() -{ -#ifndef TEST_EXIT - quick_exit(0); -#endif - return; -} - -bool AppSpawnServer::ServerMain(char *longProcName, int64_t longProcNameLen) -{ - if (socket_->RegisterServerSocket() != 0) { - HiLog::Error(LABEL, "AppSpawnServer::Failed to register server socket"); - return false; - } - std::thread(&AppSpawnServer::ConnectionPeer, this).detach(); - LoadAceLib(); - - std::thread(&AppSpawnServer::WaitRebootEvent, this).detach(); - std::thread(&AppSpawnServer::HandleSignal, this).detach(); - while (isRunning_) { - std::unique_lock lock(mut_); - dataCond_.wait(lock, [this] { return !this->appQueue_.empty() || isStop_ || isChildDie_;}); - if (isStop_) { // finish - break; - } - if (isChildDie_) { // process child die - isChildDie_ = false; - auto iter = appMap_.find(childPid_); - if (iter != appMap_.end()) { - APPSPAWN_LOGI("delete pid=%d in appMap", iter->first); - appMap_.erase(iter); - } - } - if (this->appQueue_.empty()) { - continue; - } - std::unique_ptr msg = std::move(appQueue_.front()); - appQueue_.pop(); - int connectFd = msg->GetConnectFd(); - ClientSocket::AppProperty *appProperty = msg->GetMsg(); - pid_t pid = 0; - int ret = StartApp(longProcName, longProcNameLen, appProperty, connectFd, pid); - if (ret) { - msg->Response(ret); - } else { - msg->Response(pid); - appMap_[pid] = appProperty->processName; - } - socket_->CloseConnection(connectFd); // close socket connection - APPSPAWN_LOGI("AppSpawnServer::parent process create app finish, pid = %d uid %d %s %s", - pid, appProperty->uid, appProperty->processName, appProperty->bundleName); - } - - while (appMap_.size() > 0) { - auto iter = appMap_.begin(); - APPSPAWN_LOGI("kill app, pid = %d, processName = %s", iter->first, iter->second.c_str()); - kill(iter->first, SIGKILL); - appMap_.erase(iter); - } - QuickExitMain(); - return false; -} - -int32_t AppSpawnServer::SetProcessName( - char *longProcName, int64_t longProcNameLen, const char *processName, int32_t len) -{ - if (longProcName == nullptr || processName == nullptr || len <= 0) { - HiLog::Error(LABEL, "process name is nullptr or length error"); - return -EINVAL; - } - - char shortName[MAX_LEN_SHORT_NAME]; - if (memset_s(shortName, sizeof(shortName), 0, sizeof(shortName)) != EOK) { - HiLog::Error(LABEL, "Failed to memset short name"); - return -EINVAL; - } - - // process short name max length 16 bytes. - if (len > MAX_LEN_SHORT_NAME) { - if (strncpy_s(shortName, MAX_LEN_SHORT_NAME, processName, MAX_LEN_SHORT_NAME - 1) != EOK) { - HiLog::Error(LABEL, "strncpy_s short name error: %{public}d", errno); - return -EINVAL; - } - } else { - if (strncpy_s(shortName, MAX_LEN_SHORT_NAME, processName, len) != EOK) { - HiLog::Error(LABEL, "strncpy_s short name error: %{public}d", errno); - return -EINVAL; - } - } - - // set short name - if (prctl(PR_SET_NAME, shortName) == -1) { - HiLog::Error(LABEL, "prctl(PR_SET_NAME) error: %{public}d", errno); - return (-errno); - } - - // reset longProcName - if (memset_s(longProcName, static_cast(longProcNameLen), 0, static_cast(longProcNameLen)) != EOK) { - HiLog::Error(LABEL, "Failed to memset long process name"); - return -EINVAL; - } - - // set long process name - if (strncpy_s(longProcName, len, processName, len) != EOK) { - HiLog::Error(LABEL, "strncpy_s long name error: %{public}d", errno); - return -EINVAL; - } - - return ERR_OK; -} - -int32_t AppSpawnServer::SetUidGid( - const uint32_t uid, const uint32_t gid, const uint32_t *gitTable, const uint32_t gidCount) -{ - if (gitTable == nullptr) { - HiLog::Error(LABEL, "gitTable is nullptr"); - return (-errno); - } - - // set gids - if (setgroups(gidCount, reinterpret_cast(&gitTable[0])) == -1) { - HiLog::Error(LABEL, "setgroups failed: %{public}d, gids.size=%{public}u", errno, gidCount); - return (-errno); - } - - // set gid - if (setresgid(gid, gid, gid) == -1) { - HiLog::Error(LABEL, "setgid(%{public}u) failed: %{public}d", 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(uid, uid, uid) == -1) { - HiLog::Error(LABEL, "setuid(%{public}u) failed: %{public}d", uid, errno); - return (-errno); - } - - return ERR_OK; -} - -int32_t AppSpawnServer::SetFileDescriptors() -{ - // close stdin stdout stderr - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - - // redirect to /dev/null - int dev_null_fd = open(deviceNull_.c_str(), O_RDWR); - if (dev_null_fd == -1) { - HiLog::Error(LABEL, "open dev_null error: %{public}d", errno); - return (-errno); - } - - // stdin - if (dup2(dev_null_fd, STDIN_FILENO) == -1) { - HiLog::Error(LABEL, "dup2 STDIN error: %{public}d", errno); - return (-errno); - }; - - // stdout - if (dup2(dev_null_fd, STDOUT_FILENO) == -1) { - HiLog::Error(LABEL, "dup2 STDOUT error: %{public}d", errno); - return (-errno); - }; - - // stderr - if (dup2(dev_null_fd, STDERR_FILENO) == -1) { - HiLog::Error(LABEL, "dup2 STDERR error: %{public}d", errno); - return (-errno); - }; - - return ERR_OK; -} - -int32_t AppSpawnServer::SetCapabilities() -{ - // init cap - __user_cap_header_struct cap_header; - - if (memset_s(&cap_header, sizeof(cap_header), 0, sizeof(cap_header)) != EOK) { - HiLog::Error(LABEL, "Failed to memset cap header"); - return -EINVAL; - } - cap_header.version = _LINUX_CAPABILITY_VERSION_3; - cap_header.pid = 0; - - __user_cap_data_struct cap_data[2]; - if (memset_s(&cap_data, sizeof(cap_data), 0, sizeof(cap_data)) != EOK) { - HiLog::Error(LABEL, "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 = static_cast<__u32>(inheriTable); - cap_data[1].inheritable = static_cast<__u32>(inheriTable >> BITLEN32); - cap_data[0].permitted = static_cast<__u32>(permitted); - cap_data[1].permitted = static_cast<__u32>(permitted >> BITLEN32); - cap_data[0].effective = static_cast<__u32>(effective); - cap_data[1].effective = static_cast<__u32>(effective >> BITLEN32); - - // set capabilities - if (capset(&cap_header, &cap_data[0]) == -1) { - HiLog::Error(LABEL, "capset failed: %{public}d", errno); - return (-errno); - } - - return ERR_OK; -} - -void AppSpawnServer::SetRunning(bool isRunning) -{ - isRunning_ = isRunning; -} - -void AppSpawnServer::SetServerSocket(const std::shared_ptr &serverSocket) -{ - socket_ = serverSocket; -} - -int32_t AppSpawnServer::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) { - HiLog::Error(LABEL, "bind mount %{public}s to %{public}s failed %{public}d", originPath.c_str(), - destinationPath.c_str(), errno); - return rc; - } - - rc = mount(NULL, destinationPath.c_str(), NULL, MS_PRIVATE, NULL); - if (rc) { - HiLog::Error(LABEL, "private mount to %{public}s failed %{public}d", destinationPath.c_str(), errno); - return rc; - } - - return 0; -} - -int32_t AppSpawnServer::DoAppSandboxMount(const ClientSocket::AppProperty *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/"; - const std::string oriappdataPath = "/data/accounts/account_0/appdata/"; - 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"; - std::string destappdataPath = rootPath + oriappdataPath; - - int rc = 0; - - std::string bundleName = appProperty->bundleName; - oriInstallPath += bundleName; - oriel1DataPath += bundleName; - oriel2DataPath += bundleName; - oriDatabasePath += bundleName; - - std::map mountMap; - mountMap[destDatabasePath] = oriDatabasePath; - mountMap[destInstallPath] = oriInstallPath; - mountMap[destel1DataPath] = oriel1DataPath; - mountMap[destel2DataPath] = oriel2DataPath; - mountMap[destappdataPath] = oriappdataPath; - - std::map::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 mkdirInfo; - std::string dirPath; - mkdirInfo.push_back("/data/storage/el1/bundle/nweb"); - mkdirInfo.push_back("/data/storage/el1/bundle/ohos.global.systemres"); - - for (int i = 0; i < mkdirInfo.size(); i++) { - dirPath = rootPath + mkdirInfo[i]; - mkdir(dirPath.c_str(), FILE_MODE); - } - - return 0; -} - -int32_t AppSpawnServer::DoAppSandboxMountCustomized(const ClientSocket::AppProperty *appProperty, 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 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; -} - -void AppSpawnServer::DoAppSandboxMkdir(std::string sandboxPackagePath, const ClientSocket::AppProperty *appProperty) -{ - std::vector 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//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/accounts/account_0/appdata/"); - mkdirInfo.push_back("/data/bundles/"); - - for (int i = 0; i < mkdirInfo.size(); i++) { - dirPath = sandboxPackagePath + mkdirInfo[i]; - mkdir(dirPath.c_str(), FILE_MODE); - } -} - -int32_t AppSpawnServer::DoSandboxRootFolderCreateAdapt(std::string sandboxPackagePath) -{ - int rc = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL); - if (rc) { - HiLog::Error(LABEL, "set propagation slave failed"); - return rc; - } - - // bind mount "/" to /mnt/sandbox/ path - // rootfs: to do more resources bind mount here to get more strict resources constraints - rc = mount("/", sandboxPackagePath.c_str(), NULL, MS_BIND | MS_REC, NULL); - if (rc) { - HiLog::Error(LABEL, "mount bind / failed"); - return rc; - } - - return 0; -} - -int32_t AppSpawnServer::DoSandboxRootFolderCreate(std::string sandboxPackagePath) -{ - int rc = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL); - 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/ path mkdir - std::map mountMap; - std::vector 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 (int 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/ path - std::map::iterator iter; - for (iter = mountMap.begin(); iter != mountMap.end(); ++iter) { - rc = DoAppSandboxMountOnce(iter->first.c_str(), iter->second.c_str()); - if (rc) { - HiLog::Error(LABEL, "move root folder failed, %{public}s", sandboxPackagePath.c_str()); - } - } - - // to create symlink at /mnt/sandbox/ path - // bin -> /system/bin - // d -> /sys/kernel/debug - // etc -> /system/etc - // init -> /system/bin/init - // lib -> /system/lib - // sdcard -> /storage/self/primary - std::map symlinkMap; - symlinkMap["/system/bin"] = sandboxPackagePath + "/bin"; - symlinkMap["/sys/kernel/debug"] = sandboxPackagePath + "/d"; - symlinkMap["/system/etc"] = sandboxPackagePath + "/etc"; - symlinkMap["/system/bin/init"] = sandboxPackagePath + "/init"; - symlinkMap["/system/lib"] = sandboxPackagePath + "/lib"; - - for (iter = symlinkMap.begin(); iter != symlinkMap.end(); ++iter) { - symlink(iter->first.c_str(), iter->second.c_str()); - } - - return 0; -} - -int32_t AppSpawnServer::SetAppSandboxProperty(const ClientSocket::AppProperty *appProperty) -{ - int rc = 0; - - // create /mnt/sandbox/ path, later put it to rootfs module - std::string sandboxPackagePath = "/mnt/sandbox/"; - mkdir(sandboxPackagePath.c_str(), FILE_MODE); - sandboxPackagePath += appProperty->bundleName; - mkdir(sandboxPackagePath.c_str(), FILE_MODE); - - // add pid to a new mnt namespace - rc = unshare(CLONE_NEWNS); - if (rc) { - HiLog::Error(LABEL, "unshare failed, packagename is %{public}s", appProperty->processName); - return rc; - } - - // to make wargnar work - if (access("/3rdmodem", F_OK) == 0) { - rc = DoSandboxRootFolderCreateAdapt(sandboxPackagePath); - } else { - rc = DoSandboxRootFolderCreate(sandboxPackagePath); - } - if (rc) { - HiLog::Error(LABEL, "DoSandboxRootFolderCreate failed, %{public}s", appProperty->processName); - return rc; - } - - // to create /mnt/sandbox//data/storage related path - DoAppSandboxMkdir(sandboxPackagePath, appProperty); - - rc = DoAppSandboxMount(appProperty, sandboxPackagePath); - if (rc) { - HiLog::Error(LABEL, "DoAppSandboxMount failed, packagename is %{public}s", appProperty->processName); - return rc; - } - - rc = DoAppSandboxMountCustomized(appProperty, sandboxPackagePath); - if (rc) { - HiLog::Error(LABEL, "DoAppSandboxMountCustomized failed, packagename is %{public}s", appProperty->processName); - return rc; - } - - rc = chdir(sandboxPackagePath.c_str()); - if (rc) { - HiLog::Error(LABEL, "chdir failed, packagename is %{public}s, path is %{public}s", \ - appProperty->processName, sandboxPackagePath.c_str()); - return rc; - } - - rc = syscall(SYS_pivot_root, sandboxPackagePath.c_str(), sandboxPackagePath.c_str()); - if (rc) { - HiLog::Error(LABEL, "pivot root failed, packagename is %{public}s, errno is %{public}d", \ - appProperty->processName, errno); - return rc; - } - - rc = umount2(".", MNT_DETACH); - if (rc) { - HiLog::Error(LABEL, "MNT_DETACH failed, packagename is %{public}s", appProperty->processName); - return rc; - } - - return ERR_OK; -} - -void AppSpawnServer::SetAppAccessToken(const ClientSocket::AppProperty *appProperty) -{ - int32_t ret = SetSelfTokenID(appProperty->accessTokenId); - HiLog::Info(LABEL, "AppSpawnServer::set access token id = %{public}d, ret = %{public}d %{public}d", - appProperty->accessTokenId, ret, getuid()); - -#ifdef WITH_SELINUX - HapContext hapContext; - ret = hapContext.HapDomainSetcontext(appProperty->apl, appProperty->processName); - if (ret) { - HiLog::Error(LABEL, "AppSpawnServer::Failed to hap domain set context, errno = %{public}d %{public}s", - errno, appProperty->apl); - } else { - HiLog::Info(LABEL, "AppSpawnServer::Success to hap domain set context, ret = %{public}d", ret); - } -#endif -} - -bool AppSpawnServer::SetAppProcProperty(const ClientSocket::AppProperty *appProperty, char *longProcName, - int64_t longProcNameLen, const int32_t fd) -{ - HiLog::Debug(LABEL, "AppSpawnServer::Success to fork new process, pid = %{public}d", getpid()); - int32_t ret = SetAppSandboxProperty(appProperty); - if (FAILED(ret)) { - NotifyResToParentProc(fd, ret); - return false; - } - - ret = SetKeepCapabilities(appProperty->uid); - if (FAILED(ret)) { - NotifyResToParentProc(fd, ret); - return false; - } - - ret = SetProcessName(longProcName, longProcNameLen, appProperty->processName, strlen(appProperty->processName) + 1); - if (FAILED(ret)) { - NotifyResToParentProc(fd, ret); - return false; - } - -#ifdef GRAPHIC_PERMISSION_CHECK - ret = SetUidGid(appProperty->uid, appProperty->gid, appProperty->gidTable, appProperty->gidCount); - if (FAILED(ret)) { - NotifyResToParentProc(fd, ret); - return false; - } -#endif - - ret = SetFileDescriptors(); - if (FAILED(ret)) { - NotifyResToParentProc(fd, ret); - return false; - } - - ret = SetCapabilities(); - if (FAILED(ret)) { - NotifyResToParentProc(fd, ret); - return false; - } - // notify success to father process and start app process - NotifyResToParentProc(fd, ret); - -#ifdef NWEB_SPAWN - using FuncType = void (*)(const char *cmd); - FuncType funcNWebRenderMain = reinterpret_cast(dlsym(nwebHandle, "NWebRenderMain")); - if (funcNWebRenderMain == nullptr) { - HiLog::Error(LABEL, "nwebspawn dlsym ERROR=%{public}s", dlerror()); - return false; - } - funcNWebRenderMain(appProperty->renderCmd); -#else - AppExecFwk::MainThread::Start(); -#endif - - HiLog::Error(LABEL, "Failed to start process, pid = %{public}d", getpid()); - return false; -} - -void AppSpawnServer::NotifyResToParentProc(const int32_t fd, const int32_t value) -{ - write(fd, &value, sizeof(value)); - close(fd); -} - -void AppSpawnServer::SpecialHandle(ClientSocket::AppProperty *appProperty) -{ - if (appProperty == nullptr) { - HiLog::Error(LABEL, "appProperty is nullptr"); - return; - } - // special handle bundle name medialibrary and scanner - if ((strcmp(appProperty->processName, BUNDLE_NAME_MEDIA_LIBRARY.data()) == 0) || - (strcmp(appProperty->processName, BUNDLE_NAME_SCANNER.data()) == 0)) { - if (appProperty->gidCount < MAX_GIDS) { - appProperty->gidTable[appProperty->gidCount] = GID_USER_DATA_RW; - appProperty->gidCount++; - } else { - HiLog::Info(LABEL, "gidCount out of bounds !"); - } - } -} - -int32_t AppSpawnServer::SetKeepCapabilities(uint32_t uid) -{ - // set keep capabilities when user not root. - if (uid != 0) { - if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) { - HiLog::Error(LABEL, "set keepcaps failed: %{public}d", errno); - return (-errno); - } - } - - return ERR_OK; -} - -bool AppSpawnServer::CheckAppProperty(const ClientSocket::AppProperty *appProperty) -{ - if (appProperty == nullptr) { - HiLog::Error(LABEL, "appProperty is nullptr"); - return false; - } - - if (appProperty->gidCount > ClientSocket::MAX_GIDS) { - HiLog::Error(LABEL, "gidCount error: %{public}u", appProperty->gidCount); - return false; - } - - if (strlen(appProperty->processName) == 0) { - HiLog::Error(LABEL, "process name length is 0"); - return false; - } - - return true; -} - -int AppSpawnServer::AppColdStart(char *longProcName, - int64_t longProcNameLen, const ClientSocket::AppProperty *appProperty, int fd) -{ - APPSPAWN_LOGI("AppColdStart appName %s", appProperty->bundleName); - LoadAceLib(); - if (!SetAppProcProperty(appProperty, longProcName, longProcNameLen, fd)) { - return -1; - } - APPSPAWN_LOGI("AppColdStart appName %s success", appProperty->bundleName); - return 0; -} -} // namespace AppSpawn -} // namespace OHOS diff --git a/src/include/appspawn_msg_peer.h b/src/include/appspawn_msg_peer.h deleted file mode 100644 index d81b124d..00000000 --- a/src/include/appspawn_msg_peer.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2021 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 - -#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 &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 socket_ = nullptr; - std::unique_ptr buf_ = nullptr; -}; -} // namespace AppSpawn -} // namespace OHOS -#endif diff --git a/src/include/appspawn_server.h b/src/include/appspawn_server.h deleted file mode 100644 index cda398e7..00000000 --- a/src/include/appspawn_server.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2021 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 -#include -#include - -#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); - - 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// - */ - 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(); -private: - const std::string deviceNull_ = "/dev/null"; - std::string socketName_ {}; - std::shared_ptr socket_ = nullptr; - std::mutex mut_ {}; - mutable std::condition_variable dataCond_ {}; - std::queue> appQueue_ {}; - std::function propertyHandler_ = nullptr; - std::function errHandlerHook_ = nullptr; - bool isRunning_ {}; - bool isStop_ { false }; - bool isChildDie_ { false }; - pid_t childPid_ {}; - std::map appMap_; -#ifdef NWEB_SPAWN - void *nwebHandle = nullptr; -#endif -}; -} // namespace AppSpawn -} // namespace OHOS - -#endif diff --git a/src/include/server_socket.h b/src/include/server_socket.h deleted file mode 100644 index 8bfe2ce4..00000000 --- a/src/include/server_socket.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2021 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 -#include -#include -#include - -#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 connectFds_ = {}; - std::mutex mutexConnect_; -}; -} // namespace AppSpawn -} // namespace OHOS -#endif diff --git a/src/socket/server_socket.cpp b/src/socket/server_socket.cpp deleted file mode 100644 index 7a0b1444..00000000 --- a/src/socket/server_socket.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2021 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 -#include -#include - -#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 lock(mutexConnect_); - - std::vector::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 %d", connectFd); - return; - } - - std::lock_guard lock(mutexConnect_); - - std::vector::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 %d from list", connectFd); -} - -void ServerSocket::SaveConnection(int connectFd) -{ - if (connectFd >= 0) { - std::lock_guard lock(mutexConnect_); - connectFds_.push_back(connectFd); - } -} - -void ServerSocket::CloseServer() -{ - std::lock_guard lock(mutexConnect_); - - for (const int &fd : connectFds_) { - HiLog::Debug(LABEL, "Server: Closed connection fd %d", fd); - close(fd); - } - - if ((unlink(socketAddr_.sun_path) != 0) && (errno != ENOENT)) { - HiLog::Error(LABEL, "Server: Failed to unlink, err %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: %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 %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 %d, err %d", connectFd, errno); - return (-errno); - } - - if (bind(connectFd, reinterpret_cast(&socketAddr_), socketAddrLen_) < 0) { - HiLog::Error(LABEL, "Server: Bind socket fd %d, failed: %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 %d, failed: %d", connectFd, errno); - return (-errno); - } - if (chmod(socketAddr_.sun_path, SOCKET_PERM)) { - HiLog::Error(LABEL, "Server: failed to chmod socket fd %d, failed: %d", connectFd, errno); - return (-errno); - } - - HiLog::Debug(LABEL, "Server: Bind socket fd %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 %d with backlog %d error: %d", - connectFd, - listenBacklog_, - errno); - if ((unlink(socketAddr_.sun_path) != 0) && (errno != ENOENT)) { - HiLog::Error(LABEL, "Server: Failed to unlink, err %d", errno); - } - close(connectFd); - connectFd = -1; - return (-errno); - } -#endif - HiLog::Debug(LABEL, "Server: Suc to register server socket fd %d", connectFd); - return 0; -} - -int ServerSocket::RegisterServerSocket() -{ - if (socketFd_ >= 0) { - HiLog::Info(LABEL, "Server: Already register server socket %d", socketFd_); - return 0; - } - - return RegisterServerSocket(socketFd_); -} - -int ServerSocket::WaitForConnection(int connectFd) -{ - if (connectFd < 0) { - HiLog::Error(LABEL, "Server: Invalid args: connectFd %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(&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 %d, err %d", connFd, errno); - close(connFd); - return (-errno); - } - - HiLog::Debug(LABEL, "Server: Connection accepted, connect fd %d", connFd); - return connFd; -} - -int ServerSocket::WaitForConnection() -{ - int connectFd = WaitForConnection(socketFd_); - SaveConnection(connectFd); - - return connectFd; -} -} // namespace AppSpawn -} // namespace OHOS diff --git a/standard/appspawn_process.c b/standard/appspawn_process.c new file mode 100644 index 00000000..da6428ab --- /dev/null +++ b/standard/appspawn_process.c @@ -0,0 +1,368 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "appspawn_adapter.h" +#include "securec.h" + +#define DEVICE_NULL_STR "/dev/null" + +static int SetProcessName(struct AppSpawnContent_ *content, AppSpawnClient *client, + char *longProcName, int64_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 %d", 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; + if (access("/system/lib/libhidebug.so", F_OK) != 0) { + APPSPAWN_LOGE("access failed, errno = %d", errno); + return; + } + void *handle = dlopen("/system/lib/libhidebug.so", 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_LOGE("init parameters failed."); + } + dlclose(handle); +} + +static void ClearEnvironment(AppSpawnContent *content, AppSpawnClient *client) +{ + APPSPAWN_LOGI("ClearEnvironment id %d", client->id); + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + sigaddset(&mask, SIGTERM); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client; + // 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() +{ + // 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 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); + APPSPAWN_CHECK(param != NULL, free(argv); + return -1, "Failed to malloc for param"); + + int ret = -1; + do { + argv[PARAM_INDEX] = param; + argv[0] = strdup("/system/bin/appspawn"); + APPSPAWN_CHECK(argv[0] != NULL, 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"); + + int 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; + ret = execv(argv[0], argv); + if (ret) { + APPSPAWN_LOGE("Failed to execv, errno = %d", errno); + } + } + for (int i = 0; i < NULL_INDEX; i++) { + if (argv[i] != NULL) { + free(argv[i]); + } + } + 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]); + 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; +} diff --git a/standard/appspawn_service.c b/standard/appspawn_service.c new file mode 100644 index 00000000..1d1c24b7 --- /dev/null +++ b/standard/appspawn_service.c @@ -0,0 +1,410 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "appspawn_server.h" +#include "init_hashmap.h" +#include "init_socket.h" +#include "parameter.h" +#include "securec.h" + +static AppSpawnContentExt *g_appSpawnContent = NULL; + +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(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); + memcpy_s(buffer, bufferSize, buff, buffSize); + 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", pid); + RemoveAppInfo(pid); + } + 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 = 60; + 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 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, "Failed to alloc client"); + 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 + if (appProperty->property.flags & 0x01) { + char cold[10] = {0}; // 10 cold + ret = GetParameter("appspawn.cold.boot", "false", cold, sizeof(cold)); + if (ret > 0 && (strcmp(cold, "true") == 0 || strcmp(cold, "1") == 0 || strcmp(cold, "enable") == 0)) { + appProperty->client.flags |= APP_COLD_START; + } + } + + // 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); + pid_t pid = 0; + int result = AppSpawnProcessMsg(g_appSpawnContent, &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; + APPSPAWN_LOGI("NotifyResToParent %s result %d", appProperty->property.processName, result); + write(appProperty->fd[1], &result, sizeof(result)); + // close write + close(appProperty->fd[1]); + return 0; +} + +static void AppSpawnInit(AppSpawnContent *content) +{ + AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content; + APPSPAWN_CHECK(appSpawnContent != NULL, return, "Failed to alloc memory for appspawn"); + + 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, "Failed to alloc memory for appspawn"); + + 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", getpid(), client->property.processName); + + DoStartApp(content, &client->client, content->longProcName, content->longProcNameLen); + if (content->runChildProcessor) { + content->runChildProcessor(content, &client->client); + } + APPSPAWN_LOGI("App exit %d.", getpid()); + free(client); + _exit(0x7f); +} + +static void AppSpawnRun(AppSpawnContent *content) +{ + APPSPAWN_LOGI("AppSpawnRun"); + LE_STATUS status = LE_CreateSignalTask(LE_GetDefaultLoop(), &g_appSpawnContent->sigHandler, SignalHandler); + if (status == 0) { + status = LE_AddSignal(LE_GetDefaultLoop(), g_appSpawnContent->sigHandler, SIGCHLD); + status = LE_AddSignal(LE_GetDefaultLoop(), g_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(), g_appSpawnContent->sigHandler); + // release resource + HashMapDestory(g_appSpawnContent->appMap); + free(content); + g_appSpawnContent = NULL; +} + +AppSpawnContent *AppSpawnCreateContent(const char *socketName, char *longProcName, int64_t longProcNameLen, int cold) +{ + APPSPAWN_CHECK(LE_GetDefaultLoop() != NULL, return NULL, "Invalid default loop"); + APPSPAWN_CHECK(socketName != NULL && longProcName != NULL, return NULL, "Invalid name"); + APPSPAWN_LOGI("AppSpawnCreateContent %s", socketName); + + 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->content.runAppSpawn = AppSpawnRun; + appSpawnContent->content.initAppSpawn = AppSpawnInit; + + if (cold) { + g_appSpawnContent = appSpawnContent; + return &g_appSpawnContent->content; + } + + // create hash for app + HashInfo hashInfo = { + AppInfoHashNodeCompare, + TestHashKeyCompare, + AppInfoHashNodeFunction, + AppInfoHashKeyFunction, + AppInfoHashNodeFree, + APP_HASH_BUTT + }; + int ret = HashMapCreate(&appSpawnContent->appMap, &hashInfo); + APPSPAWN_CHECK(ret == 0, free(appSpawnContent); return NULL, "Failed to create hash for app"); + + char path[128] = {0}; // 128 max path + 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->servcer, &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->servcer)); + g_appSpawnContent = appSpawnContent; + return &g_appSpawnContent->content; +} diff --git a/standard/appspawn_service.h b/standard/appspawn_service.h new file mode 100644 index 00000000..f2016c87 --- /dev/null +++ b/standard/appspawn_service.h @@ -0,0 +1,65 @@ +/* + * 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 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 servcer; + 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 diff --git a/standard/main.c b/standard/main.c new file mode 100644 index 00000000..ce4379c0 --- /dev/null +++ b/standard/main.c @@ -0,0 +1,49 @@ +/* + * 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; + } + // calculate child process long name size + uintptr_t start = (uintptr_t)argv[0]; + uintptr_t end = (uintptr_t)strchr(argv[argc - 1], 0); + int64_t argvSize = end - start; + int cold = (argc > PARAM_INDEX) && (strcmp(argv[START_INDEX], "cold-start") == 0); + + AppSpawnContent *content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, argv[0], argvSize, cold); + APPSPAWN_CHECK(content != NULL, return -1, "Invalid content for appspawn"); + APPSPAWN_CHECK(content->initAppSpawn != NULL, return -1, "Invalid content for appspawn"); + + // set common operation + content->loadExtendLib = LoadExtendLib; + content->runChildProcessor = RunChildProcessor; + + if (cold) { + content->initAppSpawn(content); + AppSpawnColdRun(content, argc, argv); + } else { + APPSPAWN_CHECK(content->runAppSpawn != NULL, return -1, "Invalid content for appspawn"); + content->initAppSpawn(content); + // run, to start loop and wait message + content->runAppSpawn(content); + } + return 0; +} diff --git a/tools/appspawn_start_app.cpp b/tools/appspawn_start_app.cpp index 072e69f9..ee19aa01 100755 --- a/tools/appspawn_start_app.cpp +++ b/tools/appspawn_start_app.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 @@ -14,18 +14,12 @@ */ #include -#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 0 if (argc <= 11) { // 11 min argc HiLog::Error(LABEL, "Invalid argc %{public}d", argc); return -1; @@ -71,5 +65,6 @@ int main(int argc, char *const argv[]) HiLog::Error(LABEL, "Cold start %{public}s fail.", appProperty->bundleName); } } + #endif return 0; } -- Gitee