1/*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "appspawn_message.h"
17#include "appspawn_server.h"
18#include <errno.h>
19#include <time.h>
20
21#include "iproxy_server.h"
22#include "iunknown.h"
23#include "ipc_skeleton.h"
24#include "message.h"
25#include "ohos_errno.h"
26#include "ohos_init.h"
27#include "samgr_lite.h"
28#include "service.h"
29#include "securec.h"
30
31static const int INVALID_PID = -1;
32static const int CLIENT_ID = 100;
33
34#ifdef OHOS_DEBUG
35uint64_t DiffTime(const struct timespec *startTime, const struct timespec *endTime)
36{
37    uint64_t diff = (uint64_t)((endTime->tv_sec - startTime->tv_sec) * 1000000);  // 1000000 s-us
38    if (endTime->tv_nsec > startTime->tv_nsec) {
39        diff += (endTime->tv_nsec - startTime->tv_nsec) / 1000;  // 1000 ns - us
40    } else {
41        diff -= (startTime->tv_nsec - endTime->tv_nsec) / 1000;  // 1000 ns - us
42    }
43    return diff;
44}
45#endif
46
47typedef struct AppSpawnFeatureApi {
48    INHERIT_SERVER_IPROXY;
49} AppSpawnFeatureApi;
50
51typedef struct AppSpawnService {
52    INHERIT_SERVICE;
53    INHERIT_IUNKNOWNENTRY(AppSpawnFeatureApi);
54    Identity identity;
55} AppSpawnService;
56
57static const char *GetName(Service *service)
58{
59    UNUSED(service);
60    APPSPAWN_LOGI("[appspawn] get service name %s.", APPSPAWN_SERVICE_NAME);
61    return APPSPAWN_SERVICE_NAME;
62}
63
64static BOOL Initialize(Service *service, Identity identity)
65{
66    if (service == NULL) {
67        APPSPAWN_LOGE("[appspawn] initialize, service NULL!");
68        return FALSE;
69    }
70
71    AppSpawnService *spawnService = (AppSpawnService *)service;
72    spawnService->identity = identity;
73
74    APPSPAWN_LOGI("[appspawn] initialize, identity<%d, %d>", \
75        identity.serviceId, identity.featureId);
76    return TRUE;
77}
78
79static BOOL MessageHandle(Service *service, Request *msg)
80{
81    UNUSED(service);
82    UNUSED(msg);
83    APPSPAWN_LOGE("[appspawn] message handle not support yet!");
84    return FALSE;
85}
86
87static TaskConfig GetTaskConfig(Service *service)
88{
89    UNUSED(service);
90    TaskConfig config = {LEVEL_HIGH, PRI_BELOW_NORMAL, 0x800, 20, SHARED_TASK};
91    return config;
92}
93
94static int GetMessageSt(MessageSt *msgSt, IpcIo *req)
95{
96    if (msgSt == NULL || req == NULL) {
97        return EC_FAILURE;
98    }
99
100    size_t len = 0;
101    char* str = ReadString(req, &len);
102    if (str == NULL || len == 0) {
103        APPSPAWN_LOGE("[appspawn] invoke, get data failed.");
104        return EC_FAILURE;
105    }
106
107    int ret = SplitMessage(str, len, msgSt);  // after split message, str no need to free(linux version)
108    return ret;
109}
110
111static AppSpawnContentLite *g_appSpawnContentLite = NULL;
112AppSpawnContent *AppSpawnCreateContent(const char *socketName, char *longProcName, uint32_t longProcNameLen, int cold)
113{
114    UNUSED(longProcName);
115    UNUSED(longProcNameLen);
116    APPSPAWN_LOGI("AppSpawnCreateContent %s", socketName);
117    AppSpawnContentLite *appSpawnContent = (AppSpawnContentLite *)malloc(sizeof(AppSpawnContentLite));
118    APPSPAWN_CHECK(appSpawnContent != NULL, return NULL, "Failed to alloc memory for appspawn");
119    int ret = memset_s(appSpawnContent, sizeof(AppSpawnContentLite), 0, sizeof(AppSpawnContentLite));
120    APPSPAWN_CHECK(ret == 0, free(appSpawnContent);
121        return NULL, "Failed to memset content");
122    appSpawnContent->content.longProcName = NULL;
123    appSpawnContent->content.longProcNameLen = 0;
124    g_appSpawnContentLite = appSpawnContent;
125    return appSpawnContent;
126}
127
128static int Invoke(IServerProxy *iProxy, int funcId, void *origin, IpcIo *req, IpcIo *reply)
129{
130#ifdef OHOS_DEBUG
131    struct timespec tmStart = {0};
132    clock_gettime(CLOCK_REALTIME, &tmStart);
133#endif
134
135    UNUSED(iProxy);
136    UNUSED(origin);
137
138    if (reply == NULL || funcId != ID_CALL_CREATE_SERVICE || req == NULL) {
139        APPSPAWN_LOGE("[appspawn] invoke, funcId %d invalid, reply %d.", funcId, INVALID_PID);
140        WriteInt64(reply, INVALID_PID);
141        return EC_BADPTR;
142    }
143    APPSPAWN_LOGI("[appspawn] invoke.");
144    AppSpawnClientLite client = {};
145    client.client.id = CLIENT_ID;
146    client.client.flags = 0;
147    if (GetMessageSt(&client.message, req) != EC_SUCCESS) {
148        APPSPAWN_LOGE("[appspawn] invoke, parse failed! reply %d.", INVALID_PID);
149        WriteInt64(reply, INVALID_PID);
150        return EC_FAILURE;
151    }
152
153    APPSPAWN_LOGI("[appspawn] invoke, msg<%s,%s,%d,%d %d>", client.message.bundleName, client.message.identityID,
154        client.message.uID, client.message.gID, client.message.capsCnt);
155    pid_t newPid = 0;
156    int ret = AppSpawnProcessMsg(&g_appSpawnContentLite->content, &client.client, &newPid);
157    if (ret != 0) {
158        newPid = -1;
159    }
160    FreeMessageSt(&client.message);
161    WriteInt64(reply, newPid);
162
163#ifdef OHOS_DEBUG
164    struct timespec tmEnd = {0};
165    clock_gettime(CLOCK_MONOTONIC, &tmEnd);
166    long long diff = DiffTime(&tmStart, &tmEnd);
167    APPSPAWN_LOGI("[appspawn] invoke, reply pid %d, timeused %lld ns.", newPid, diff);
168#else
169    APPSPAWN_LOGI("[appspawn] invoke, reply pid %d.", newPid);
170#endif  // OHOS_DEBUG
171
172    return ((newPid > 0) ? EC_SUCCESS : EC_FAILURE);
173}
174
175static AppSpawnService g_appSpawnService = {
176    .GetName = GetName,
177    .Initialize = Initialize,
178    .MessageHandle = MessageHandle,
179    .GetTaskConfig = GetTaskConfig,
180    SERVER_IPROXY_IMPL_BEGIN,
181    .Invoke = Invoke,
182    IPROXY_END,
183};
184
185void AppSpawnInit(void)
186{
187    if (SAMGR_GetInstance()->RegisterService((Service *)&g_appSpawnService) != TRUE) {
188        APPSPAWN_LOGE("[appspawn] register service failed!");
189        return;
190    }
191
192    APPSPAWN_LOGI("[appspawn] register service succeed.");
193
194    if (SAMGR_GetInstance()->RegisterDefaultFeatureApi(APPSPAWN_SERVICE_NAME, \
195        GET_IUNKNOWN(g_appSpawnService)) != TRUE) {
196        (void)SAMGR_GetInstance()->UnregisterService(APPSPAWN_SERVICE_NAME);
197        APPSPAWN_LOGE("[appspawn] register featureapi failed!");
198        return;
199    }
200
201    APPSPAWN_LOGI("[appspawn] register featureapi succeed.");
202}
203
204SYSEX_SERVICE_INIT(AppSpawnInit);
205