Merge pull request !1409 from 杨浩/0824
This commit is contained in:
openharmony_ci 2024-08-24 07:31:34 +00:00 committed by Gitee
commit 7714780968
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
6 changed files with 205 additions and 13 deletions

View File

@ -37,7 +37,7 @@ static void NotifyResToParent(struct AppSpawnContent *content, AppSpawnClient *c
}
}
static void ProcessExit(int code)
void ProcessExit(int code)
{
APPSPAWN_LOGI("App exit code: %{public}d", code);
#ifdef OHOS_LITE
@ -86,7 +86,7 @@ static void SetEncapsFlag(int fdEncaps, uint32_t flag)
}
#endif
APPSPAWN_STATIC int AppSpawnChild(AppSpawnContent *content, AppSpawnClient *client)
int AppSpawnChild(AppSpawnContent *content, AppSpawnClient *client)
{
APPSPAWN_CHECK(content != NULL && client != NULL, return -1, "Invalid arg for appspawn child");
APPSPAWN_LOGI("AppSpawnChild id %{public}u flags: 0x%{public}x", client->id, client->flags);

View File

@ -64,7 +64,13 @@ typedef struct AppSpawnContent {
int fdEncaps;
#endif
RunMode mode;
#ifndef OHOS_LITE
int32_t preforkFd[2];
int32_t parentToChildFd[2];
char *propertyBuffer;
int isPrefork;
pid_t reservedPid;
#endif
// system
void (*runAppSpawn)(struct AppSpawnContent *content, int argc, char *const argv[]);
void (*notifyResToParent)(struct AppSpawnContent *content, AppSpawnClient *client, int result);
@ -85,7 +91,8 @@ int AppSpawnExecutePreReplyHook(AppSpawnContent *content, AppSpawnClient *client
int AppSpawnExecutePostReplyHook(AppSpawnContent *content, AppSpawnClient *client);
void AppSpawnEnvClear(AppSpawnContent *content, AppSpawnClient *client);
int AppSpawnProcessMsg(AppSpawnContent *content, AppSpawnClient *client, pid_t *childPid);
void ProcessExit(int code);
int AppSpawnChild(AppSpawnContent *content, AppSpawnClient *client);
#ifdef __cplusplus
}
#endif

View File

@ -500,6 +500,7 @@ static int CloseFdArgs(AppSpawnMgr *content, AppSpawningCtx *property)
APPSPAWN_STATIC int SetFdEnv(AppSpawnMgr *content, AppSpawningCtx *property)
{
APPSPAWN_CHECK_ONLY_EXPER(property != NULL, return -1);
APPSPAWN_CHECK_ONLY_EXPER(!property->isPrefork, return 0);
AppSpawnMsgNode *message = property->message;
APPSPAWN_CHECK_ONLY_EXPER(message != NULL && message->buffer != NULL && message->connection != NULL, return -1);
APPSPAWN_CHECK_ONLY_EXPER(message->tlvOffset != NULL, return -1);

View File

@ -80,6 +80,7 @@ typedef struct TagAppSpawningCtx {
struct ListNode node;
AppSpawnForkCtx forkCtx;
AppSpawnMsgNode *message;
bool isPrefork;
pid_t pid;
int state;
struct timespec spawnStart;

View File

@ -28,6 +28,7 @@
#include <signal.h>
#include <sys/mount.h>
#include <unistd.h>
#include <sys/prctl.h>
#include "appspawn.h"
#include "appspawn_hook.h"
@ -47,10 +48,10 @@
#ifdef USE_ENCAPS
#include <sys/ioctl.h>
#endif
#define PARAM_BUFFER_SIZE 10
#define PATH_SIZE 256
#define FD_PATH_SIZE 128
#define MAX_MEM_SIZE (4 * 1024)
#ifndef PIDFD_NONBLOCK
#define PIDFD_NONBLOCK O_NONBLOCK
#endif
@ -453,6 +454,8 @@ static char *GetMapMem(uint32_t clientId, const char *processName, uint32_t size
APPSPAWN_STATIC int WriteMsgToChild(AppSpawningCtx *property, bool isNweb)
{
APPSPAWN_CHECK(property != NULL && property->message != NULL, return APPSPAWN_MSG_INVALID,
"Failed to WriteMsgToChild property invalid");
const uint32_t memSize = (property->message->msgHeader.msgLen / 4096 + 1) * 4096; // 4096 4K
char *buffer = GetMapMem(property->client.id, GetProcessName(property), memSize, false, isNweb);
APPSPAWN_CHECK(buffer != NULL, return APPSPAWN_SYSTEM_ERROR,
@ -603,6 +606,186 @@ static bool IsSupportRunHnp()
return false;
}
static int WritePreforkMsg(AppSpawningCtx *property, char* buffer)
{
if (buffer == NULL) {
APPSPAWN_LOGE("buffer is null can not write propery");
return -1;
}
// copy msg header
int ret = memcpy_s(buffer, MAX_MEM_SIZE, &property->message->msgHeader, sizeof(AppSpawnMsg));
if (ret == 0) {
ret = memcpy_s((char *)buffer + sizeof(AppSpawnMsg), MAX_MEM_SIZE - sizeof(AppSpawnMsg),
property->message->buffer, property->message->msgHeader.msgLen - sizeof(AppSpawnMsg));
}
if (ret != 0) {
APPSPAWN_LOGE("Failed to copy msg fileName %{public}s ", GetProcessName(property));
munmap((char *)buffer, MAX_MEM_SIZE);
buffer = NULL;
}
return ret;
}
static int GetAppSpawnMsg(AppSpawningCtx *property)
{
uint8_t *buffer = (uint8_t *)GetMapMem(property->client.id, "prefork", MAX_MEM_SIZE, true, false);
if (buffer == NULL) {
APPSPAWN_LOGE("prefork buffer is null can not write propery");
return -1;
}
uint32_t msgRecvLen = 0;
uint32_t remainLen = 0;
property->forkCtx.childMsg = (char *)buffer;
property->forkCtx.msgSize = MAX_MEM_SIZE;
AppSpawnMsgNode *message = NULL;
int ret = GetAppSpawnMsgFromBuffer(buffer, ((AppSpawnMsg *)buffer)->msgLen, &message, &msgRecvLen, &remainLen);
// release map
APPSPAWN_LOGV("prefork GetAppSpawnMsg ret:%{public}d", ret);
if (ret == 0 && DecodeAppSpawnMsg(message) == 0 && CheckAppSpawnMsg(message) == 0) {
property->message = message;
message = NULL;
return 0;
}
return -1;
}
static void ClearMMAP(int clientId)
{
char path[PATH_MAX];
int ret = snprintf_s(path, sizeof(path), sizeof(path) - 1, APPSPAWN_MSG_DIR "appspawn/prefork_%d", clientId);
APPSPAWN_LOGV("prefork unlink %{public}s ret :%{public}d", path, ret);
AppSpawnContent *content = GetAppSpawnContent();
if (content != NULL && content->propertyBuffer != NULL) {
munmap(content->propertyBuffer, MAX_MEM_SIZE);
content->propertyBuffer = NULL;
}
if (ret > 0) {
errno = 0;
ret = unlink(path);
APPSPAWN_LOGV("prefork unlink result %{public}d %{public}d", ret, errno);
}
}
static void ProcessPreFork(AppSpawnContent *content, AppSpawningCtx *property)
{
APPSPAWN_CHECK(pipe(content->preforkFd) == 0, return, "prefork with prefork pipe failed %{public}d", errno);
content->reservedPid = fork();
APPSPAWN_LOGV("prefork fork finish %{public}d,%{public}d,%{public}d,%{public}d,%{public}d",
content->reservedPid, content->preforkFd[0], content->preforkFd[1], content->parentToChildFd[0],
content->parentToChildFd[1]);
if (content->reservedPid == 0) {
(void)close(property->forkCtx.fd[0]);
(void)close(property->forkCtx.fd[1]);
int isRet = prctl(PR_SET_NAME, "apppool");
APPSPAWN_LOGI("prefork process start wait read msg with set processname %{public}d", isRet);
AppSpawnClient client = {0, 0};
int infoSize = read(content->parentToChildFd[0], &client, sizeof(AppSpawnClient));
if (infoSize != sizeof(AppSpawnClient)) {
APPSPAWN_LOGE("prefork process read msg failed %{public}d,%{public}d", infoSize, errno);
content->notifyResToParent(content, &property->client, APPSPAWN_MSG_INVALID);
ProcessExit(0);
return;
}
property->client.id = client.id;
property->client.flags = client.flags;
property->isPrefork = true;
property->forkCtx.fd[0] = content->preforkFd[0];
property->forkCtx.fd[1] = content->preforkFd[1];
property->state = APP_STATE_SPAWNING;
if (GetAppSpawnMsg(property) == -1) {
APPSPAWN_LOGE("prefork child read GetAppSpawnMsg failed");
ClearMMAP(property->client.id);
content->notifyResToParent(content, &property->client, APPSPAWN_MSG_INVALID);
ProcessExit(0);
return;
}
ClearMMAP(property->client.id);
ProcessExit(AppSpawnChild(content, &property->client));
return;
} else if (content->reservedPid < 0) {
APPSPAWN_LOGE("prefork fork child process failed %{public}d", content->reservedPid);
}
}
static int AppSpawnProcessMsgForPrefork(AppSpawnContent *content, AppSpawnClient *client, pid_t *childPid)
{
int ret = 0;
AppSpawningCtx *property = (AppSpawningCtx *)client;
if (content->reservedPid <= 0) {
APPSPAWN_CHECK(client != NULL, return ret, "client is null");
ret = InitForkContext((AppSpawningCtx *)client);
APPSPAWN_CHECK(ret == 0, return ret, "init fork context failed");
ret = AppSpawnProcessMsg(content, client, childPid);
} else {
APPSPAWN_CHECK_ONLY_EXPER(content->propertyBuffer == NULL, ClearMMAP(client->id));
content->propertyBuffer = GetMapMem(property->client.id, "prefork", MAX_MEM_SIZE, false, false);
APPSPAWN_CHECK(content->propertyBuffer != NULL, return -1, "GetPreforkMem failed")
ret = WritePreforkMsg(property, content->propertyBuffer);
APPSPAWN_CHECK(ret == 0, return ret, "WritePreforkMsg failed")
*childPid = content->reservedPid;
property->forkCtx.fd[0] = content->preforkFd[0];
property->forkCtx.fd[1] = content->preforkFd[1];
int option = fcntl(property->forkCtx.fd[0], F_GETFD);
if (option > 0) {
(void)fcntl(property->forkCtx.fd[0], F_SETFD, option | O_NONBLOCK);
}
ssize_t writesize = write(content->parentToChildFd[1], client, sizeof(AppSpawnClient)) ;
APPSPAWN_CHECK(writesize == sizeof(AppSpawnClient), kill(*childPid, SIGKILL);
*childPid = 0;
ret = -1,
"write msg to child failed %{public}d", errno);
}
ProcessPreFork(content, property);
return ret;
}
static bool IsSupportPrefork(AppSpawnContent *content, AppSpawnClient *client)
{
if (client == NULL || content == NULL) {
return false;
}
if (!content->isPrefork) {
if (pipe(content->parentToChildFd) == 0) {
content->isPrefork = true;
}
}
AppSpawningCtx *property = (AppSpawningCtx *)client;
if (content->mode == MODE_FOR_APP_SPAWN && !(client->flags & APP_COLD_START) && content->isPrefork
&& !CheckAppMsgFlagsSet(property, APP_FLAGS_CHILDPROCESS)) {
return true;
}
return false;
}
static bool IsBootFinished()
{
char buffer[32] = {0}; // 32 max
int ret = GetParameter("bootevent.boot.completed", "false", buffer, sizeof(buffer));
bool isBootCompleted = (ret > 0 && strcmp(buffer, "true") == 0);
return isBootCompleted;
}
static int RunAppSpawnProcessMsg(AppSpawnContent *content, AppSpawnClient *client, pid_t *childPid)
{
int ret = 0;
if (IsBootFinished() && IsSupportPrefork(content, client)) {
ret = AppSpawnProcessMsgForPrefork(content, client, childPid);
} else {
APPSPAWN_CHECK(client != NULL, return ret, "client is null");
ret = InitForkContext((AppSpawningCtx *)client);
APPSPAWN_CHECK(ret == 0, return ret, "init fork context failed");
ret = AppSpawnProcessMsg(content, client, childPid);
}
return ret;
}
static void ProcessSpawnReqMsg(AppSpawnConnection *connection, AppSpawnMsgNode *message)
{
int ret = CheckAppSpawnMsg(message);
@ -637,14 +820,8 @@ static void ProcessSpawnReqMsg(AppSpawnConnection *connection, AppSpawnMsgNode *
DumpAppSpawnMsg(property->message);
}
if (InitForkContext(property) != 0) {
SendResponse(connection, &message->msgHeader, APPSPAWN_SYSTEM_ERROR, 0);
DeleteAppSpawningCtx(property);
return;
}
clock_gettime(CLOCK_MONOTONIC, &property->spawnStart);
ret = AppSpawnProcessMsg(GetAppSpawnContent(), &property->client, &property->pid);
ret = RunAppSpawnProcessMsg(GetAppSpawnContent(), &property->client, &property->pid);
AppSpawnHookExecute(STAGE_PARENT_POST_FORK, 0, GetAppSpawnContent(), &property->client);
if (ret != 0) { // wait child process result
SendResponse(connection, &message->msgHeader, ret, 0);
@ -785,6 +962,12 @@ void AppSpawnDestroyContent(AppSpawnContent *content)
if (content == NULL) {
return;
}
if (content->parentToChildFd[0] > 0) {
close(content->parentToChildFd[0]);
}
if (content->parentToChildFd[1] > 0) {
close(content->parentToChildFd[1]);
}
AppSpawnMgr *appSpawnContent = (AppSpawnMgr *)content;
#ifdef USE_ENCAPS
CloseDevEncaps(appSpawnContent->content.fdEncaps);

View File

@ -363,7 +363,7 @@ HWTEST_F(AppSpawnCommonTest, App_Spawn_Common_014, TestSize.Level0)
DeleteAppSpawningCtx(property);
AppSpawnClientDestroy(clientHandle);
DeleteAppSpawnMgr(mgr);
ASSERT_EQ(ret, -1);
ASSERT_EQ(ret, 0);
}
HWTEST_F(AppSpawnCommonTest, App_Spawn_Common_015, TestSize.Level0)