diff --git a/interfaces/innerkits/client/appspawn_socket.cpp b/interfaces/innerkits/client/appspawn_socket.cpp new file mode 100755 index 0000000000000000000000000000000000000000..a42a8a8923f2529d20a490b86fe8596f468d6ec5 --- /dev/null +++ b/interfaces/innerkits/client/appspawn_socket.cpp @@ -0,0 +1,155 @@ +/* + * 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_socket.h" + +#include +#include +#include + +#include "hilog/log.h" +#include "pubdef.h" +#include "securec.h" + +namespace OHOS { +namespace AppSpawn { +using namespace OHOS::HiviewDFX; +static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "AppSpawnSocket"}; + +AppSpawnSocket::AppSpawnSocket(const std::string &name) +{ + socketName_ = name; +} + +AppSpawnSocket::~AppSpawnSocket() +{ + if (socketFd_ > 0) { + CloseSocket(socketFd_); + socketFd_ = -1; + } +} + +int AppSpawnSocket::GetSocketFd() const +{ + return socketFd_; +} + +int AppSpawnSocket::PackSocketAddr() +{ + if (socketName_.empty()) { + HiLog::Error(LABEL, "Invalid socket name: empty"); + return -EINVAL; + } + + if (memset_s(&socketAddr_, sizeof(socketAddr_), 0, sizeof(socketAddr_)) != EOK) { + HiLog::Error(LABEL, "Failed to memset socket addr"); + return -1; + } + + socklen_t pathLen = 0; + if (socketName_[0] == '/') { + pathLen = socketName_.length(); + } else { + pathLen = socketDir_.length() + socketName_.length(); + } + socklen_t pathSize = sizeof(socketAddr_.sun_path); + if (pathLen >= pathSize) { + HiLog::Error(LABEL, "Invalid socket name: '%s' too long", socketName_.c_str()); + return -1; + } + + int len = 0; + if (socketName_[0] == '/') { + len = snprintf_s(socketAddr_.sun_path, pathSize, (pathSize - 1), "%s", socketName_.c_str()); + } else { + len = snprintf_s(socketAddr_.sun_path, pathSize, (pathSize - 1), "%s%s", + socketDir_.c_str(), socketName_.c_str()); + } + if (static_cast(pathLen) != len) { + HiLog::Error(LABEL, "Failed to copy socket path"); + return -1; + } + + socketAddr_.sun_family = AF_LOCAL; + socketAddrLen_ = offsetof(struct sockaddr_un, sun_path) + pathLen + 1; + + return 0; +} + +int AppSpawnSocket::CreateSocket() +{ + int socketFd = socket(AF_UNIX, SOCK_STREAM, 0); // SOCK_SEQPACKET + if (socketFd < 0) { + HiLog::Error(LABEL, "Failed to create socket: %d", errno); + return (-errno); + } + + HiLog::Debug(LABEL, "Created socket with fd %d", socketFd); + return socketFd; +} + +void AppSpawnSocket::CloseSocket(int &socketFd) +{ + if (socketFd >= 0) { + HiLog::Debug(LABEL, "Closed socket with fd %d", socketFd); + close(socketFd); + socketFd = -1; + } +} + +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); + return -1; + } + + if (memset_s(buf, len, 0, len) != EOK) { + HiLog::Warn(LABEL, "Failed to memset read buf"); + return -1; + } + + 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); + return -EFAULT; + } + + return rLen; +} + +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); + return -1; + } + + ssize_t written = 0; + ssize_t remain = static_cast(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); + if ((wLen <= 0) && (errno != EINTR)) { + HiLog::Error(LABEL, "Failed to write message to fd %d, error %zd: %d", socketFd, wLen, errno); + return (-errno); + } + } + + return written; +} +} // namespace AppSpawn +} // namespace OHOS diff --git a/interfaces/innerkits/client/client_socket.cpp b/interfaces/innerkits/client/client_socket.cpp new file mode 100755 index 0000000000000000000000000000000000000000..308f389c8cfe4ff81912de40121bec9c9d633d8c --- /dev/null +++ b/interfaces/innerkits/client/client_socket.cpp @@ -0,0 +1,102 @@ +/* + * 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 "client_socket.h" + +#include +#include +#include + +#include "hilog/log.h" +#include "securec.h" + +namespace OHOS { +namespace AppSpawn { +using namespace OHOS::HiviewDFX; +static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "ClientSocket"}; + +ClientSocket::ClientSocket(const std::string &client) : AppSpawnSocket(client) +{} + +int ClientSocket::CreateClient() +{ + if (socketFd_ < 0) { + socketFd_ = CreateSocket(); + if (socketFd_ < 0) { + HiLog::Error(LABEL, "Client: Create socket failed"); + return socketFd_; + } + } + + HiLog::Debug(LABEL, "Client: CreateClient socket fd %d", socketFd_); + return 0; +} + +void ClientSocket::CloseClient() +{ + if (socketFd_ < 0) { + HiLog::Error(LABEL, "Client: Invalid connectFd %d", socketFd_); + return; + } + + CloseSocket(socketFd_); + socketFd_ = -1; +} + +int ClientSocket::ConnectSocket(int connectFd) +{ + if (connectFd < 0) { + HiLog::Error(LABEL, "Client: Invalid socket fd: %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); + 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); + return -1; + } + + HiLog::Debug(LABEL, "Client: Connected on socket fd %d, name '%s'", connectFd, socketAddr_.sun_path); + return 0; +} + +int ClientSocket::ConnectSocket() +{ + return ConnectSocket(socketFd_); +} + +int ClientSocket::WriteSocketMessage(const void *buf, int len) +{ + return WriteSocketMessage(socketFd_, buf, len); +} + +int ClientSocket::ReadSocketMessage(void *buf, int len) +{ + return ReadSocketMessage(socketFd_, buf, len); +} +} // namespace AppSpawn +} // namespace OHOS diff --git a/interfaces/innerkits/include/appspawn_msg.h b/interfaces/innerkits/include/appspawn_msg.h new file mode 100755 index 0000000000000000000000000000000000000000..f7ca8dff41803fafc48dceda3acb41020c9d25b5 --- /dev/null +++ b/interfaces/innerkits/include/appspawn_msg.h @@ -0,0 +1,75 @@ +/* + * 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_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/appspawn_socket.h b/interfaces/innerkits/include/appspawn_socket.h index 6edf8b7280850698d2e187ab2d8fee549b70e15a..ceb1800aeae87efbb30209d4143a8a2ec7d16b63 100644 --- a/interfaces/innerkits/include/appspawn_socket.h +++ b/interfaces/innerkits/include/appspawn_socket.h @@ -108,7 +108,7 @@ protected: const std::string socketDir_ = "/dev/socket/"; #endif const unsigned int listenBacklog_ = 50; // 50: max num of clients - static constexpr struct timeval SOCKET_TIMEOUT = {5, 0}; // 5, 0: { 5 sec, 0 msec } for timeout + static constexpr struct timeval SOCKET_TIMEOUT = {2, 0}; // 2, 0: { 2 sec, 0 msec } for timeout }; } // namespace AppSpawn } // namespace OHOS diff --git a/interfaces/innerkits/include/client_socket.h b/interfaces/innerkits/include/client_socket.h index dc459bc778869272552f405f535ea73936cb30df..85e979a6e27909a0c65bcbe8464253ba7c293a79 100644 --- a/interfaces/innerkits/include/client_socket.h +++ b/interfaces/innerkits/include/client_socket.h @@ -29,7 +29,7 @@ public: explicit ClientSocket(const std::string &client); /** - * Destructor used to destory a ClientSocket + * Destructor used to destroy a ClientSocket */ virtual ~ClientSocket() = default; diff --git a/src/appspawn_msg_peer.cpp b/src/appspawn_msg_peer.cpp index e658e75520c62916fa2668ae2062dd447a4f8835..dec21fb6f99f8f2a66de93d08329c24f5905cc1e 100644 --- a/src/appspawn_msg_peer.cpp +++ b/src/appspawn_msg_peer.cpp @@ -49,12 +49,12 @@ int AppSpawnMsgPeer::GetConnectFd() const int AppSpawnMsgPeer::Response(pid_t pid) { if ((socket_ == nullptr) || (connectFd_ < 0)) { - HiLog::Error(LABEL, "Invalid socket params: connectFd %d", connectFd_); + HiLog::Error(LABEL, "Invalid socket params: connectFd %{public}d", connectFd_); return -EINVAL; } if (socket_->WriteSocketMessage(connectFd_, &pid, sizeof(pid)) != sizeof(pid)) { - HiLog::Error(LABEL, "Failed to write message: connectFd %d", connectFd_); + HiLog::Error(LABEL, "Failed to write message: connectFd %{public}d", connectFd_); return (-errno); } diff --git a/src/appspawn_server.cpp b/src/appspawn_server.cpp index 38008a3300caf4de59411fcf4b7f5f1018c3b9da..55fd04c5aefd341942b4af4669cd3dce5d021c0f 100644 --- a/src/appspawn_server.cpp +++ b/src/appspawn_server.cpp @@ -15,6 +15,7 @@ #include "appspawn_server.h" +#include #include #include #include @@ -72,6 +73,8 @@ 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; @@ -114,14 +117,14 @@ static void UninstallSigHandler() sa.sa_handler = nullptr; int err = sigaction(SIGCHLD, &sa, nullptr); if (err < 0) { - HiLog::Error(LABEL, "Error uninstalling SIGCHLD handler: %d", errno); + HiLog::Error(LABEL, "Error uninstalling SIGCHLD handler: %{public}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); + HiLog::Error(LABEL, "Error uninstalling SIGHUP handler: %{public}d", errno); } } #ifdef __cplusplus @@ -139,7 +142,7 @@ 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); + HiLog::Error(LABEL, "Failed to listen connection %{public}d, %{public}d", connectFd, errno); return; } @@ -266,6 +269,31 @@ void AppSpawnServer::LoadAceLib() #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; @@ -308,13 +336,37 @@ int AppSpawnServer::DoColdStartApp(ClientSocket::AppProperty *appProperty, int f extractedCmds.push_back(nullptr); APPSPAWN_LOGI("DoColdStartApp extractedCmds %d", extractedCmds.size()); int ret = execv(extractedCmds[0], extractedCmds.data()); - if (ret != 0) { + if (ret) { HiLog::Error(LABEL, "Failed to execv, errno = %{public}d", errno); NotifyResToParentProc(fd, -1); } return 0; } +static int WaitChild(int fd, int pid, ClientSocket::AppProperty *appProperty) +{ + int result = ERR_OK; + fd_set rd; + struct timeval tv; + FD_ZERO(&rd); + FD_SET(fd, &rd); + tv.tv_sec = 1; + tv.tv_usec = 0; + int ret = select(1, &rd, nullptr, nullptr, &tv); + if (ret == 0) { // timeout + APPSPAWN_LOGI("Time out for child %d %s ", appProperty->processName, pid); + result = ERR_OK; + } else if (ret == -1) { + APPSPAWN_LOGI("Error for child %d %s ", appProperty->processName, pid); + result = ERR_OK; + } else { + ret = read(fd, &result, sizeof(result)); + } + APPSPAWN_LOGI("child process %s %s pid %d", + appProperty->processName, (result == ERR_OK) ? "success" : "fail", pid); + return (result == ERR_OK) ? 0 : result; +} + int AppSpawnServer::StartApp(char *longProcName, int64_t longProcNameLen, ClientSocket::AppProperty *appProperty, int connectFd, pid_t &pid) { @@ -322,11 +374,11 @@ int AppSpawnServer::StartApp(char *longProcName, int64_t longProcNameLen, 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; } + fcntl(fd[0], F_SETFL, O_NDELAY); InstallSigHandler(); pid = fork(); @@ -336,6 +388,7 @@ int AppSpawnServer::StartApp(char *longProcName, int64_t longProcNameLen, 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) { @@ -354,12 +407,10 @@ int AppSpawnServer::StartApp(char *longProcName, int64_t longProcNameLen, } _exit(0); } - read(fd[0], &buff, sizeof(buff)); // wait child process resutl + int ret = WaitChild(fd[0], pid, appProperty); 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; + return ret; } void AppSpawnServer::QuickExitMain() @@ -404,7 +455,7 @@ bool AppSpawnServer::ServerMain(char *longProcName, int64_t longProcNameLen) ClientSocket::AppProperty *appProperty = msg->GetMsg(); pid_t pid = 0; int ret = StartApp(longProcName, longProcNameLen, appProperty, connectFd, pid); - if (ret != 0) { + if (ret) { msg->Response(ret); } else { msg->Response(pid); @@ -620,12 +671,10 @@ int32_t AppSpawnServer::DoAppSandboxMount(const ClientSocket::AppProperty *appPr 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; @@ -640,7 +689,6 @@ int32_t AppSpawnServer::DoAppSandboxMount(const ClientSocket::AppProperty *appPr mountMap[destInstallPath] = oriInstallPath; mountMap[destel1DataPath] = oriel1DataPath; mountMap[destel2DataPath] = oriel2DataPath; - mountMap[destappdataPath] = oriappdataPath; std::map::iterator iter; for (iter = mountMap.begin(); iter != mountMap.end(); ++iter) { @@ -654,6 +702,7 @@ int32_t AppSpawnServer::DoAppSandboxMount(const ClientSocket::AppProperty *appPr 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]; @@ -668,15 +717,23 @@ int32_t AppSpawnServer::DoAppSandboxMountCustomized(const ClientSocket::AppPrope 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; + } - // 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()); + 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()); + // 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; @@ -697,6 +754,12 @@ int32_t AppSpawnServer::DoAppSandboxMountCustomized(const ClientSocket::AppPrope 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"; @@ -731,7 +794,6 @@ void AppSpawnServer::DoAppSandboxMkdir(std::string sandboxPackagePath, const Cli 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++) { @@ -749,7 +811,7 @@ int32_t AppSpawnServer::DoSandboxRootFolderCreateAdapt(std::string sandboxPackag } // bind mount "/" to /mnt/sandbox/ path - // rootfs: to do more resouces bind mount here to get more strict resources constraints + // 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"); @@ -778,7 +840,7 @@ int32_t AppSpawnServer::DoSandboxRootFolderCreate(std::string sandboxPackagePath vecInfo.push_back("/dev"); vecInfo.push_back("/proc"); vecInfo.push_back("/sys"); - vecInfo.push_back("/sys-prod"); + vecInfo.push_back("/sys_prod"); vecInfo.push_back("/system"); for (int i = 0; i < vecInfo.size(); i++) { @@ -892,7 +954,7 @@ void AppSpawnServer::SetAppAccessToken(const ClientSocket::AppProperty *appPrope #ifdef WITH_SELINUX HapContext hapContext; ret = hapContext.HapDomainSetcontext(appProperty->apl, appProperty->processName); - if (ret != 0) { + if (ret) { HiLog::Error(LABEL, "AppSpawnServer::Failed to hap domain set context, errno = %{public}d %{public}s", errno, appProperty->apl); } else { diff --git a/src/include/appspawn_msg_peer.h b/src/include/appspawn_msg_peer.h index 0aa10c1999737cfaadcc2e180e890e8f6074e0be..d81b124df96ad2ed6dbb3b8c4f63c87d917c5bcc 100644 --- a/src/include/appspawn_msg_peer.h +++ b/src/include/appspawn_msg_peer.h @@ -37,7 +37,7 @@ public: AppSpawnMsgPeer(const std::shared_ptr &socket, int connectFd); /** - * Destructor used to destory a AppSpawnMsgPeer + * Destructor used to destroy a AppSpawnMsgPeer */ ~AppSpawnMsgPeer(); diff --git a/src/include/appspawn_server.h b/src/include/appspawn_server.h index 5836b32d065d7c21c2c54d74ac6282d14f4e8358..cda398e7b458cc0702e3f990fc7bff8fe638ee7c 100644 --- a/src/include/appspawn_server.h +++ b/src/include/appspawn_server.h @@ -39,7 +39,7 @@ public: explicit AppSpawnServer(const std::string &socketName); /** - * Destructor used to destory a AppSpawnServer + * Destructor used to destroy a AppSpawnServer */ ~AppSpawnServer() = default; @@ -93,7 +93,7 @@ private: void ConnectionPeer(); /** - * Sets a name for an applicaiton process. + * Sets a name for an application process. * * @param longProcName Indicates the length of long process name. * @param longProcNameLen Indicates the long process name. diff --git a/src/include/server_socket.h b/src/include/server_socket.h index 84c965cf7b1dff6b4f6b6e199bf61f332f80613b..8bfe2ce46ba9fc67962dd2ad69e6ef665909ccec 100644 --- a/src/include/server_socket.h +++ b/src/include/server_socket.h @@ -34,7 +34,7 @@ public: explicit ServerSocket(const std::string &server); /** - * Destructor used to destory a ServerSocket + * Destructor used to destroy a ServerSocket */ virtual ~ServerSocket(); diff --git a/src/socket/appspawn_socket.cpp b/src/socket/appspawn_socket.cpp index 4c0caf6a3461c85ae32ab4714386d11273d73ea4..096fed0024f4f4f34f225686960567a98152c5f6 100755 --- a/src/socket/appspawn_socket.cpp +++ b/src/socket/appspawn_socket.cpp @@ -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; } @@ -92,18 +92,18 @@ int AppSpawnSocket::CreateSocket() { int socketFd = socket(AF_LOCAL, SOCK_SEQPACKET, 0); 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 %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/src/socket/client_socket.cpp index 308f389c8cfe4ff81912de40121bec9c9d633d8c..3c240bde54bc08c9b1c1c1e0ea4f6131c3c06a82 100644 --- a/src/socket/client_socket.cpp +++ b/src/socket/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/src/socket/server_socket.cpp b/src/socket/server_socket.cpp index 7a0b14440a81d7cf1aa309f696abb45b3b9a7057..0917613c74addc130715757ed0b2b4d02408bb2a 100644 --- a/src/socket/server_socket.cpp +++ b/src/socket/server_socket.cpp @@ -51,7 +51,7 @@ int ServerSocket::VerifyConnection(int connectFd) void ServerSocket::CloseConnection(int connectFd) { if (connectFd < 0) { - HiLog::Error(LABEL, "Server: Invalid connectFd %d", connectFd); + HiLog::Error(LABEL, "Server: Invalid connectFd %{public}d", connectFd); return; } @@ -65,7 +65,7 @@ void ServerSocket::CloseConnection(int connectFd) close(connectFd); connectFds_.erase(it); - HiLog::Debug(LABEL, "Server: Erase connect fd %d from list", connectFd); + HiLog::Debug(LABEL, "Server: Erase connect fd %{public}d from list", connectFd); } void ServerSocket::SaveConnection(int connectFd) @@ -81,12 +81,12 @@ void ServerSocket::CloseServer() std::lock_guard lock(mutexConnect_); for (const int &fd : connectFds_) { - HiLog::Debug(LABEL, "Server: Closed connection fd %d", fd); + HiLog::Debug(LABEL, "Server: Closed connection fd %{public}d", fd); close(fd); } if ((unlink(socketAddr_.sun_path) != 0) && (errno != ENOENT)) { - HiLog::Error(LABEL, "Server: Failed to unlink, err %d", errno); + HiLog::Error(LABEL, "Server: Failed to unlink, err %{public}d", errno); } connectFds_.clear(); @@ -107,7 +107,7 @@ void ServerSocket::CloseServerMonitor() int ServerSocket::BindSocket(int connectFd) { if (connectFd < 0) { - HiLog::Error(LABEL, "Server: Invalid socket fd: %d", connectFd); + HiLog::Error(LABEL, "Server: Invalid socket fd: %{public}d", connectFd); return -EINVAL; } @@ -116,7 +116,7 @@ int ServerSocket::BindSocket(int connectFd) } if ((unlink(socketAddr_.sun_path) != 0) && (errno != ENOENT)) { - HiLog::Error(LABEL, "Server: Failed to unlink, err %d", errno); + HiLog::Error(LABEL, "Server: Failed to unlink, err %{public}d", errno); return (-errno); } @@ -124,25 +124,25 @@ int ServerSocket::BindSocket(int connectFd) 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); + HiLog::Warn(LABEL, "Server: Failed to set opt of socket %{public}d, err %{public}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); + HiLog::Error(LABEL, "Server: Bind socket fd %{public}d, failed: %{public}d", connectFd, errno); return (-errno); } if (chown(socketAddr_.sun_path, APPSPAWN_ID_ROOT, APPSPAWN_ID_SYSTEM)) { - HiLog::Error(LABEL, "Server: failed to chown socket fd %d, failed: %d", connectFd, errno); + HiLog::Error(LABEL, "Server: failed to chown socket fd %{public}d, failed: %{public}d", connectFd, errno); return (-errno); } if (chmod(socketAddr_.sun_path, SOCKET_PERM)) { - HiLog::Error(LABEL, "Server: failed to chmod socket fd %d, failed: %d", connectFd, errno); + HiLog::Error(LABEL, "Server: failed to chmod socket fd %{public}d, failed: %{public}d", connectFd, errno); return (-errno); } - HiLog::Debug(LABEL, "Server: Bind socket fd %d success", connectFd); + HiLog::Debug(LABEL, "Server: Bind socket fd %{public}d success", connectFd); return 0; } @@ -165,26 +165,26 @@ int ServerSocket::RegisterServerSocket(int &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", + "Server: Register socket fd %{public}d with backlog %{public}d error: %{public}d", connectFd, listenBacklog_, errno); if ((unlink(socketAddr_.sun_path) != 0) && (errno != ENOENT)) { - HiLog::Error(LABEL, "Server: Failed to unlink, err %d", errno); + HiLog::Error(LABEL, "Server: Failed to unlink, err %{public}d", errno); } close(connectFd); connectFd = -1; return (-errno); } #endif - HiLog::Debug(LABEL, "Server: Suc to register server socket fd %d", connectFd); + HiLog::Debug(LABEL, "Server: Suc to register server socket fd %{public}d", connectFd); return 0; } int ServerSocket::RegisterServerSocket() { if (socketFd_ >= 0) { - HiLog::Info(LABEL, "Server: Already register server socket %d", socketFd_); + HiLog::Info(LABEL, "Server: Already register server socket %{public}d", socketFd_); return 0; } @@ -194,7 +194,7 @@ int ServerSocket::RegisterServerSocket() int ServerSocket::WaitForConnection(int connectFd) { if (connectFd < 0) { - HiLog::Error(LABEL, "Server: Invalid args: connectFd %d", connectFd); + HiLog::Error(LABEL, "Server: Invalid args: connectFd %{public}d", connectFd); return -EINVAL; } @@ -212,12 +212,12 @@ int ServerSocket::WaitForConnection(int connectFd) 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); + HiLog::Warn(LABEL, "Server: Failed to set opt of Connection %{public}d, err %{public}d", connFd, errno); close(connFd); return (-errno); } - HiLog::Debug(LABEL, "Server: Connection accepted, connect fd %d", connFd); + HiLog::Debug(LABEL, "Server: Connection accepted, connect fd %{public}d", connFd); return connFd; } diff --git a/standard/appspawn_process.c b/standard/appspawn_process.c new file mode 100755 index 0000000000000000000000000000000000000000..2db0f2588977b0d1cf227ed3e9f58fe1288691cc --- /dev/null +++ b/standard/appspawn_process.c @@ -0,0 +1,184 @@ +/* + * 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_service.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "appspawn_server.h" +#include "securec.h" + +int setProcessName(struct AppSpawnContent_ *content, AppSpawnClient *client, + char *longProcName, int64_t longProcNameLen) +{ + AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client; + size_t len = strlen(appProperty->property.processName) + 1; + if (longProcName == NULL || longProcNameLen <= 0 || len <= 1) { + 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->property.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->property.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->property.processName), appProperty->property.processName, len) != EOK) { + APPSPAWN_LOGE("strncpy_s long name error: %d longProcNameLen %d", errno, longProcNameLen); + return -EINVAL; + } + + return 0; +} + +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; +} + +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 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]); + return; +} + +int setUidGid(struct AppSpawnContent_ *content, AppSpawnClient *client) +{ + AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client; + if (strlen(appProperty->property.gidTable) == 0) { + APPSPAWN_LOGE("gitTable is nullptr"); + return (-errno); + } + + // 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); + } + + return 0; +} + +void SetContentFunction(AppSpawnContent *content) +{ + APPSPAWN_LOGI("SetContentFunction"); + content->clearEnvironment = ClearEnvironment; + content->setProcessName = setProcessName; + content->setKeepCapabilities = setKeepCapabilities; + content->setUidGid = setUidGid; +} diff --git a/standard/appspawn_service.c b/standard/appspawn_service.c new file mode 100755 index 0000000000000000000000000000000000000000..8d3dcc5b74d510bbe4d7fd21af856952dac8d294 --- /dev/null +++ b/standard/appspawn_service.c @@ -0,0 +1,270 @@ +/* + * 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_service.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "appspawn_server.h" +#include "init_socket.h" +#include "parameter.h" +#include "securec.h" + +static AppSpawnContentExt *g_appSpawnContent = NULL; + +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 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 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; + int count = 0; + while (count < RETRY_TIME) { // wait child process resutl + int readLen = read(fd, &result, sizeof(result)); + if (readLen == sizeof(result)) { + break; + } + usleep(DELAY_US); + count++; + } + if (count >= RETRY_TIME) { + APPSPAWN_LOGI("Time out for child %d %s ", appProperty->property.processName, pid); + result = 0; + } + APPSPAWN_LOGI("child process %s %s pid %d", + appProperty->property.processName, (result == 0) ? "success" : "fail", pid); + 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, LE_CloseTask(LE_GetDefaultLoop(), taskHandle); + return, "Invalid gidCount %u", appProperty->property.gidCount); + APPSPAWN_CHECK(strlen(appProperty->property.processName) > 0, LE_CloseTask(LE_GetDefaultLoop(), taskHandle); + return, "Invalid processName %s", appProperty->property.processName); + APPSPAWN_LOGI("OnReceiveRequest client.id %d appProperty %d processname %s", + appProperty->client.id, appProperty->property.uid, appProperty->property.processName); + // special handle bundle name medialibrary and scanner + HandleSpecial(appProperty); + + // 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; + } + fcntl(appProperty->fd[0], F_SETFL, O_NONBLOCK); + + int 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]); + // send response + if (result == 0) { + SendResponse(appProperty, (char *)&pid, sizeof(pid)); + } else { + SendResponse(appProperty, (char *)&result, sizeof(result)); + } + // release + LE_CloseTask(LE_GetDefaultLoop(), taskHandle); +} + +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 = NULL; + 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; + APPSPAWN_LOGI("OnConnection client fd %d Id %d", LE_GetSocketFd(stream), client->client.id); + return 0; +} + +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); + } + break; + } + case SIGTERM: { // appswapn killed, use kill without parameter + LE_StopLoop(LE_GetDefaultLoop()); + break; + } + default: + APPSPAWN_LOGI("SigHandler, unsupported signal %d.", siginfo->ssi_signo); + break; + } +} + +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"); + + LE_STATUS ret = LE_CreateSignalTask(LE_GetDefaultLoop(), &appSpawnContent->sigHandler, SignalHandler); + if (ret == 0) { + ret = LE_AddSignal(LE_GetDefaultLoop(), appSpawnContent->sigHandler, SIGCHLD); + ret = LE_AddSignal(LE_GetDefaultLoop(), appSpawnContent->sigHandler, SIGTERM); + } + + APPSPAWN_LOGI("AppSpawnInit"); + if (content->loadExtendLib) { + content->loadExtendLib(content); + } + content->notifyResToParent = NotifyResToParent; + // set private function + SetContentFunction(content); +} + +static void AppSpawnRun(AppSpawnContent *content) +{ + APPSPAWN_LOGI("AppSpawnRun"); + LE_RunLoop(LE_GetDefaultLoop()); + + APPSPAWN_LOGI("AppSpawnRun exit "); + // release resource + free(content); + g_appSpawnContent = NULL; +} + +AppSpawnContent *AppSpawnCreateContent(const char *socketName, char *longProcName, int64_t longProcNameLen) +{ + 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; + int ret = strcpy_s(appSpawnContent->content.socketName, sizeof(appSpawnContent->content.socketName), socketName); + APPSPAWN_CHECK(ret >= 0, free(appSpawnContent); return NULL, "Failed to strcpy_s %d", ret); + + 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); + + 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); + appSpawnContent->content.runAppSpawn = AppSpawnRun; + appSpawnContent->content.initAppSpawn = AppSpawnInit; + 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 100755 index 0000000000000000000000000000000000000000..567943379a0f0ad68e54bf83806e23867305cfca --- /dev/null +++ b/standard/appspawn_service.h @@ -0,0 +1,56 @@ +/* + * 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_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 RETRY_TIME 10 +#define DELAY_US 10 * 1000 // 10ms + +typedef struct { + AppSpawnClient client; + TaskHandle stream; + int32_t fd[2]; // 2 fd count + AppParameter property; +} AppSpawnClientExt; + +typedef struct { + HashNode hashNode; + uint32_t pid; + char *appName; +} AppInfo; + +typedef struct { + AppSpawnContent content; + TaskHandle servcer; + SignalHandle sigHandler; + HashMapHandle appMap; // save app pid and name +} AppSpawnContentExt; + +void SetContentFunction(AppSpawnContent *content); + +#ifdef __cplusplus +} +#endif +#endif // APPSPAWN_SERVICE_H diff --git a/standard/main.c b/standard/main.c new file mode 100755 index 0000000000000000000000000000000000000000..2aaf0920bd7939d0990bcc5b6517297600c96a1d --- /dev/null +++ b/standard/main.c @@ -0,0 +1,83 @@ +/* + * 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 "appspawn_msg.h" +#include "appspawn_adapter.h" + +extern void * g_nwebHandle; + +#ifdef NWEB_SPAWN +void LoadExtendLib(AppSpawnContent *content) +{ + LoadAceLib(); +} + +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); +} + +#else +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) +{ + StartMainThread(); +} +#endif + +int main(int argc, char *const argv[]) +{ + SetInitLogLevel(1); + if (argc > 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; + AppSpawnContent *content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, argv[0], argvSize); + APPSPAWN_CHECK(content != NULL, return -1, "Invalid content for appspawn"); + APPSPAWN_CHECK(content->runAppSpawn != 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; + + content->initAppSpawn(content); + // run, to start loop and wait message + content->runAppSpawn(content); + } + return 0; +} diff --git a/test/clienttest/appspawn_sample.cpp b/test/clienttest/appspawn_sample.cpp new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/clienttest/appspawn_sample.h b/test/clienttest/appspawn_sample.h new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/clienttest/main.cpp b/test/clienttest/main.cpp new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tools/appspawn_start_app.cpp b/tools/appspawn_start_app.cpp index 3f91515fe4c8333d0023769231c62794a045160e..072e69f9c671e1b808ff5448ba239f7db40696fc 100644 --- a/tools/appspawn_start_app.cpp +++ b/tools/appspawn_start_app.cpp @@ -1,75 +1,75 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#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 (argc <= 11) { // 11 min argc - HiLog::Error(LABEL, "Invalid argc %{public}d", argc); - return -1; - } - HiLog::Debug(LABEL, "AppSpawnServer argc %{public}d app:%{public}s", argc, argv[4]); // 4 name index - // calculate child process long name size - uintptr_t start = reinterpret_cast(argv[0]); - uintptr_t end = reinterpret_cast(strchr(argv[argc - 1], 0)); - if (end == 0) { - return -1; - } - uintptr_t argvSize = end - start; - - auto appProperty = std::make_unique(); - if (appProperty == nullptr) { - HiLog::Error(LABEL, "Failed to create app property %{public}s", argv[4]); // 4 name index - return -1; - } - int index = 1; - int fd = strtoul(argv[index++], nullptr, DECIMAL); - appProperty->uid = strtoul(argv[index++], nullptr, DECIMAL); - appProperty->gid = strtoul(argv[index++], nullptr, DECIMAL); - (void)strcpy_s(appProperty->processName, sizeof(appProperty->processName), argv[index++]); - (void)strcpy_s(appProperty->bundleName, sizeof(appProperty->bundleName), argv[index++]); - (void)strcpy_s(appProperty->soPath, sizeof(appProperty->soPath), argv[index++]); - appProperty->accessTokenId = strtoul(argv[index++], nullptr, DECIMAL); - (void)strcpy_s(appProperty->apl, sizeof(appProperty->apl), argv[index++]); - (void)strcpy_s(appProperty->renderCmd, sizeof(appProperty->renderCmd), argv[index++]); - appProperty->flags = strtoul(argv[index++], nullptr, DECIMAL); - appProperty->gidCount = strtoul(argv[index++], nullptr, DECIMAL); - uint32_t i = 0; - while ((i < appProperty->gidCount) && (i < sizeof(appProperty->gidTable) / sizeof(appProperty->gidTable[0]))) { - if (index >= argc) { - HiLog::Error(LABEL, "Invalid arg %{public}d %{public}d", index, argc); - return -1; - } - appProperty->gidTable[i++] = strtoul(argv[index++], nullptr, DECIMAL); - } - auto appspawnServer = std::make_shared("AppSpawn"); - if (appspawnServer != nullptr) { - int ret = appspawnServer->AppColdStart(argv[0], argvSize, appProperty.get(), fd); - if (ret != 0) { - HiLog::Error(LABEL, "Cold start %{public}s fail.", appProperty->bundleName); - } - } - return 0; -} \ No newline at end of file +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#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 (argc <= 11) { // 11 min argc + HiLog::Error(LABEL, "Invalid argc %{public}d", argc); + return -1; + } + HiLog::Debug(LABEL, "AppSpawnServer argc %{public}d app:%{public}s", argc, argv[4]); // 4 name index + // calculate child process long name size + uintptr_t start = reinterpret_cast(argv[0]); + uintptr_t end = reinterpret_cast(strchr(argv[argc - 1], 0)); + if (end == 0) { + return -1; + } + uintptr_t argvSize = end - start; + + auto appProperty = std::make_unique(); + if (appProperty == nullptr) { + HiLog::Error(LABEL, "Failed to create app property %{public}s", argv[4]); // 4 name index + return -1; + } + int index = 1; + int fd = strtoul(argv[index++], nullptr, DECIMAL); + appProperty->uid = strtoul(argv[index++], nullptr, DECIMAL); + appProperty->gid = strtoul(argv[index++], nullptr, DECIMAL); + (void)strcpy_s(appProperty->processName, sizeof(appProperty->processName), argv[index++]); + (void)strcpy_s(appProperty->bundleName, sizeof(appProperty->bundleName), argv[index++]); + (void)strcpy_s(appProperty->soPath, sizeof(appProperty->soPath), argv[index++]); + appProperty->accessTokenId = strtoul(argv[index++], nullptr, DECIMAL); + (void)strcpy_s(appProperty->apl, sizeof(appProperty->apl), argv[index++]); + (void)strcpy_s(appProperty->renderCmd, sizeof(appProperty->renderCmd), argv[index++]); + appProperty->flags = strtoul(argv[index++], nullptr, DECIMAL); + appProperty->gidCount = strtoul(argv[index++], nullptr, DECIMAL); + uint32_t i = 0; + while ((i < appProperty->gidCount) && (i < sizeof(appProperty->gidTable) / sizeof(appProperty->gidTable[0]))) { + if (index >= argc) { + HiLog::Error(LABEL, "Invalid arg %{public}d %{public}d", index, argc); + return -1; + } + appProperty->gidTable[i++] = strtoul(argv[index++], nullptr, DECIMAL); + } + auto appspawnServer = std::make_shared("AppSpawn"); + if (appspawnServer != nullptr) { + int ret = appspawnServer->AppColdStart(argv[0], argvSize, appProperty.get(), fd); + if (ret != 0) { + HiLog::Error(LABEL, "Cold start %{public}s fail.", appProperty->bundleName); + } + } + return 0; +}