2022-04-27 01:23:43 +00:00
|
|
|
/*
|
|
|
|
* 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"
|
|
|
|
|
2022-05-19 13:13:12 +00:00
|
|
|
#include <stdlib.h>
|
2022-04-27 01:23:43 +00:00
|
|
|
#include <errno.h>
|
2022-07-02 01:19:26 +00:00
|
|
|
#include <sys/stat.h>
|
2022-04-27 01:23:43 +00:00
|
|
|
#include <unistd.h>
|
2022-08-29 14:34:04 +00:00
|
|
|
#include <signal.h>
|
|
|
|
#undef _GNU_SOURCE
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <sched.h>
|
2022-04-27 01:23:43 +00:00
|
|
|
#include <time.h>
|
2023-04-12 13:42:06 +00:00
|
|
|
#include <stdbool.h>
|
2022-04-27 01:23:43 +00:00
|
|
|
|
2023-04-27 14:40:06 +00:00
|
|
|
#include "syspara/parameter.h"
|
|
|
|
#include "securec.h"
|
|
|
|
|
2022-07-02 07:51:04 +00:00
|
|
|
#define DEFAULT_UMASK 0002
|
2022-08-29 14:34:04 +00:00
|
|
|
#define SANDBOX_STACK_SIZE (1024 * 1024 * 8)
|
2023-04-13 15:37:24 +00:00
|
|
|
#define APPSPAWN_CHECK_EXIT "AppSpawnCheckUnexpectedExitCall"
|
2022-08-29 14:34:04 +00:00
|
|
|
|
2022-11-07 12:10:28 +00:00
|
|
|
long long DiffTime(struct timespec *startTime)
|
2022-07-27 04:41:03 +00:00
|
|
|
{
|
2022-11-07 12:10:28 +00:00
|
|
|
struct timespec tmEnd = {0};
|
|
|
|
clock_gettime(CLOCK_REALTIME, &tmEnd);
|
|
|
|
long long diff = (long long)((tmEnd.tv_sec - startTime->tv_sec) * 1000000); // 1000000 1000ms
|
|
|
|
if (tmEnd.tv_nsec > startTime->tv_nsec) {
|
|
|
|
diff += (tmEnd.tv_nsec - startTime->tv_nsec) / 1000; // 1000 ms
|
|
|
|
} else {
|
|
|
|
diff -= (startTime->tv_nsec - tmEnd.tv_nsec) / 1000; // 1000 ms
|
2022-07-27 04:41:03 +00:00
|
|
|
}
|
2022-11-07 12:10:28 +00:00
|
|
|
return diff;
|
2022-07-27 04:41:03 +00:00
|
|
|
}
|
|
|
|
|
2022-06-13 16:10:17 +00:00
|
|
|
static void NotifyResToParent(struct AppSpawnContent_ *content, AppSpawnClient *client, int result)
|
2022-04-27 01:23:43 +00:00
|
|
|
{
|
|
|
|
if (content->notifyResToParent != NULL) {
|
|
|
|
content->notifyResToParent(content, client, result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-12 13:40:08 +00:00
|
|
|
static void ProcessExit(int code)
|
2022-05-19 13:13:12 +00:00
|
|
|
{
|
2023-04-04 01:00:03 +00:00
|
|
|
APPSPAWN_LOGI("App exit: %{public}d", code);
|
2022-05-19 13:13:12 +00:00
|
|
|
#ifdef OHOS_LITE
|
|
|
|
_exit(0x7f); // 0x7f user exit
|
|
|
|
#else
|
2022-11-07 12:10:28 +00:00
|
|
|
#ifndef APPSPAWN_TEST
|
2022-05-19 13:13:12 +00:00
|
|
|
quick_exit(0);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-04-12 13:40:08 +00:00
|
|
|
#ifdef APPSPAWN_HELPER
|
|
|
|
__attribute__((visibility("default")))
|
|
|
|
_Noreturn
|
|
|
|
void exit(int code)
|
|
|
|
{
|
2023-04-13 15:37:24 +00:00
|
|
|
char *checkExit = getenv(APPSPAWN_CHECK_EXIT);
|
2023-04-27 14:40:06 +00:00
|
|
|
if (checkExit && atoi(checkExit) == getpid()) {
|
2023-04-12 13:40:08 +00:00
|
|
|
APPSPAWN_LOGF("Unexpected exit call: %{public}d", code);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
// hook `exit` to `ProcessExit` to ensure app exit in a clean way
|
|
|
|
ProcessExit(code);
|
|
|
|
// should not come here
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-04-27 01:23:43 +00:00
|
|
|
int DoStartApp(struct AppSpawnContent_ *content, AppSpawnClient *client, char *longProcName, uint32_t longProcNameLen)
|
|
|
|
{
|
|
|
|
int32_t ret = 0;
|
2023-04-04 01:00:03 +00:00
|
|
|
APPSPAWN_LOGV("DoStartApp id %{public}d longProcNameLen %{public}u", client->id, longProcNameLen);
|
2022-11-07 12:10:28 +00:00
|
|
|
if (content->handleInternetPermission != NULL) {
|
|
|
|
content->handleInternetPermission(client);
|
|
|
|
}
|
2022-06-10 09:23:02 +00:00
|
|
|
|
2023-04-27 02:08:39 +00:00
|
|
|
if (content->setAppSandbox) {
|
2022-04-27 01:23:43 +00:00
|
|
|
ret = content->setAppSandbox(content, client);
|
|
|
|
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
|
|
|
|
return ret, "Failed to set app sandbox");
|
|
|
|
}
|
2022-06-10 09:23:02 +00:00
|
|
|
|
2022-07-02 06:25:02 +00:00
|
|
|
(void)umask(DEFAULT_UMASK);
|
2022-04-27 01:23:43 +00:00
|
|
|
if (content->setKeepCapabilities) {
|
|
|
|
ret = content->setKeepCapabilities(content, client);
|
|
|
|
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
|
|
|
|
return ret, "Failed to set KeepCapabilities");
|
|
|
|
}
|
2022-06-10 09:23:02 +00:00
|
|
|
|
2022-04-27 01:23:43 +00:00
|
|
|
if (content->setProcessName) {
|
|
|
|
ret = content->setProcessName(content, client, longProcName, longProcNameLen);
|
|
|
|
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
|
|
|
|
return ret, "Failed to set setProcessName");
|
|
|
|
}
|
|
|
|
|
2023-05-04 10:48:19 +00:00
|
|
|
if (content->setXpmRegion) {
|
|
|
|
ret = content->setXpmRegion(content);
|
|
|
|
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
|
|
|
|
return ret, "Failed to set setXpmRegion");
|
|
|
|
}
|
|
|
|
|
2022-04-27 01:23:43 +00:00
|
|
|
if (content->setUidGid) {
|
|
|
|
ret = content->setUidGid(content, client);
|
|
|
|
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
|
|
|
|
return ret, "Failed to setUidGid");
|
|
|
|
}
|
2022-06-10 09:23:02 +00:00
|
|
|
|
2022-04-27 01:23:43 +00:00
|
|
|
if (content->setFileDescriptors) {
|
|
|
|
ret = content->setFileDescriptors(content, client);
|
|
|
|
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
|
|
|
|
return ret, "Failed to setFileDescriptors");
|
|
|
|
}
|
2022-06-10 09:23:02 +00:00
|
|
|
|
2022-04-27 01:23:43 +00:00
|
|
|
if (content->setCapabilities) {
|
|
|
|
ret = content->setCapabilities(content, client);
|
|
|
|
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
|
|
|
|
return ret, "Failed to setCapabilities");
|
|
|
|
}
|
2022-06-10 09:23:02 +00:00
|
|
|
|
2023-04-13 07:47:25 +00:00
|
|
|
if (content->waitForDebugger) {
|
|
|
|
ret = content->waitForDebugger(client);
|
|
|
|
APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
|
|
|
|
return ret, "Failed to waitForDebugger");
|
|
|
|
}
|
|
|
|
|
2022-04-27 01:23:43 +00:00
|
|
|
// notify success to father process and start app process
|
|
|
|
NotifyResToParent(content, client, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-04-12 13:40:08 +00:00
|
|
|
static int AppSpawnChildRun(void *arg)
|
2022-04-27 01:23:43 +00:00
|
|
|
{
|
2022-08-29 14:34:04 +00:00
|
|
|
APPSPAWN_CHECK(arg != NULL, return -1, "Invalid arg for appspawn child");
|
|
|
|
AppSandboxArg *sandbox = (AppSandboxArg *)arg;
|
|
|
|
struct AppSpawnContent_ *content = sandbox->content;
|
|
|
|
AppSpawnClient *client = sandbox->client;
|
|
|
|
|
2022-04-27 01:23:43 +00:00
|
|
|
#ifdef OHOS_DEBUG
|
2022-08-29 14:34:04 +00:00
|
|
|
struct timespec tmStart = {0};
|
2022-11-07 12:10:28 +00:00
|
|
|
clock_gettime(CLOCK_REALTIME, &tmStart);
|
|
|
|
#endif
|
2022-08-29 14:34:04 +00:00
|
|
|
// close socket id and signal for child
|
|
|
|
if (content->clearEnvironment != NULL) {
|
|
|
|
content->clearEnvironment(content, client);
|
|
|
|
}
|
2022-06-10 09:23:02 +00:00
|
|
|
|
2022-08-29 14:34:04 +00:00
|
|
|
if (content->setAppAccessToken != NULL) {
|
|
|
|
content->setAppAccessToken(content, client);
|
|
|
|
}
|
2022-06-10 09:23:02 +00:00
|
|
|
|
2022-08-29 14:34:04 +00:00
|
|
|
int ret = -1;
|
2022-11-07 12:10:28 +00:00
|
|
|
if ((content->getWrapBundleNameValue != NULL && content->getWrapBundleNameValue(content, client) == 0) ||
|
|
|
|
((client->flags & APP_COLD_START) != 0)) {
|
|
|
|
// cold start fail, to start normal
|
2022-08-29 14:34:04 +00:00
|
|
|
if (content->coldStartApp != NULL && content->coldStartApp(content, client) == 0) {
|
2022-11-07 12:10:28 +00:00
|
|
|
return 0;
|
2022-04-27 01:23:43 +00:00
|
|
|
}
|
2022-08-29 14:34:04 +00:00
|
|
|
}
|
2022-11-07 12:10:28 +00:00
|
|
|
ret = DoStartApp(content, client, content->longProcName, content->longProcNameLen);
|
2023-02-20 12:37:37 +00:00
|
|
|
if (content->initDebugParams != NULL) {
|
|
|
|
content->initDebugParams(content, client);
|
|
|
|
}
|
2022-04-27 01:23:43 +00:00
|
|
|
#ifdef OHOS_DEBUG
|
2022-11-07 12:10:28 +00:00
|
|
|
long long diff = DiffTime(&tmStart);
|
2023-04-04 01:00:03 +00:00
|
|
|
APPSPAWN_LOGI("App timeused %{public}d %lld ns.", getpid(), diff);
|
2022-11-07 12:10:28 +00:00
|
|
|
#endif
|
2022-08-29 14:34:04 +00:00
|
|
|
if (ret == 0 && content->runChildProcessor != NULL) {
|
|
|
|
content->runChildProcessor(content, client);
|
2022-04-27 01:23:43 +00:00
|
|
|
}
|
2022-06-14 07:06:32 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-04-12 09:03:18 +00:00
|
|
|
static int AppSpawnChild(void *arg)
|
|
|
|
{
|
2023-04-27 14:40:06 +00:00
|
|
|
char checkExit[16] = ""; // 16 is enough to store an int
|
|
|
|
if (GetIntParameter("persist.init.debug.checkexit", true)) {
|
|
|
|
(void)sprintf_s(checkExit, sizeof(checkExit), "%d", getpid());
|
|
|
|
}
|
|
|
|
setenv(APPSPAWN_CHECK_EXIT, checkExit, true);
|
2023-04-12 13:40:08 +00:00
|
|
|
int ret = AppSpawnChildRun(arg);
|
2023-04-13 15:37:24 +00:00
|
|
|
unsetenv(APPSPAWN_CHECK_EXIT);
|
2023-04-12 13:40:08 +00:00
|
|
|
return ret;
|
2023-04-12 09:03:18 +00:00
|
|
|
}
|
|
|
|
|
2023-05-06 02:37:35 +00:00
|
|
|
static int CloneAppSpawn(void *arg)
|
|
|
|
{
|
|
|
|
int ret = AppSpawnChild(arg);
|
|
|
|
ProcessExit(ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-11-07 12:10:28 +00:00
|
|
|
#ifndef APPSPAWN_TEST
|
|
|
|
pid_t AppSpawnFork(int (*childFunc)(void *arg), void *args)
|
|
|
|
{
|
|
|
|
pid_t pid = fork();
|
|
|
|
if (pid == 0) {
|
2023-04-12 13:40:08 +00:00
|
|
|
ProcessExit(childFunc(args));
|
2022-11-07 12:10:28 +00:00
|
|
|
}
|
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-08-29 14:34:04 +00:00
|
|
|
int AppSpawnProcessMsg(AppSandboxArg *sandbox, pid_t *childPid)
|
2022-06-14 07:06:32 +00:00
|
|
|
{
|
2022-08-29 14:34:04 +00:00
|
|
|
APPSPAWN_CHECK(sandbox != NULL && sandbox->content != NULL, return -1, "Invalid content for appspawn");
|
|
|
|
APPSPAWN_CHECK(sandbox->client != NULL && childPid != NULL, return -1, "Invalid client for appspawn");
|
2023-04-27 02:08:39 +00:00
|
|
|
APPSPAWN_LOGI("AppSpawnProcessMsg id %{public}d 0x%{public}x", sandbox->client->id, sandbox->client->flags);
|
2022-08-29 14:34:04 +00:00
|
|
|
|
2022-11-07 12:10:28 +00:00
|
|
|
#ifndef OHOS_LITE
|
2022-08-29 14:34:04 +00:00
|
|
|
AppSpawnClient *client = sandbox->client;
|
|
|
|
if (client->cloneFlags & CLONE_NEWPID) {
|
|
|
|
APPSPAWN_CHECK(client->cloneFlags & CLONE_NEWNS, return -1, "clone flags error");
|
|
|
|
char *childStack = (char *)malloc(SANDBOX_STACK_SIZE);
|
|
|
|
APPSPAWN_CHECK(childStack != NULL, return -1, "malloc failed");
|
2023-05-06 02:37:35 +00:00
|
|
|
pid_t pid = clone(CloneAppSpawn,
|
2023-04-27 02:08:39 +00:00
|
|
|
childStack + SANDBOX_STACK_SIZE, client->cloneFlags | SIGCHLD, (void *)sandbox);
|
2022-08-29 14:34:04 +00:00
|
|
|
if (pid > 0) {
|
|
|
|
free(childStack);
|
|
|
|
*childPid = pid;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
client->cloneFlags &= ~CLONE_NEWPID;
|
|
|
|
free(childStack);
|
|
|
|
}
|
|
|
|
#endif
|
2022-11-07 12:10:28 +00:00
|
|
|
*childPid = AppSpawnFork(AppSpawnChild, (void *)sandbox);
|
2023-04-04 01:00:03 +00:00
|
|
|
APPSPAWN_CHECK(*childPid >= 0, return -errno, "fork child process error: %{public}d", -errno);
|
2022-04-27 01:23:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|