1 /*
2  * Copyright (c) 2024 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 <cerrno>
17 #include <cstdlib>
18 #include <cstring>
19 #include <memory>
20 #include <string>
21 #include <unistd.h>
22 #include <gtest/gtest.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 
26 #include "appspawn_modulemgr.h"
27 #include "appspawn_server.h"
28 #include "appspawn_manager.h"
29 #include "app_spawn_stub.h"
30 #include "app_spawn_test_helper.h"
31 #include "json_utils.h"
32 #include "parameter.h"
33 #include "securec.h"
34 
35 using namespace testing;
36 using namespace testing::ext;
37 using namespace OHOS;
38 
39 namespace OHOS {
40 static AppSpawnTestHelper g_testHelper;
41 class AppSpawnCGroupTest : public testing::Test {
42 public:
SetUpTestCase()43     static void SetUpTestCase() {}
TearDownTestCase()44     static void TearDownTestCase() {}
SetUp()45     void SetUp() {}
TearDown()46     void TearDown() {}
47 };
48 
CreateTestAppInfo(const char * name)49 static AppSpawnedProcess *CreateTestAppInfo(const char *name)
50 {
51     AppSpawnedProcess *appInfo = reinterpret_cast<AppSpawnedProcess *>(
52         malloc(sizeof(AppSpawnedProcess) + strlen(name) + 1));
53     APPSPAWN_CHECK(appInfo != nullptr, return nullptr, "Failed to create appInfo");
54     appInfo->pid = 33;                 // 33
55     appInfo->uid = 200000 * 200 + 21;  // 200000 200 21
56     appInfo->max = 0;
57     appInfo->exitStatus = 0;
58     int ret = strcpy_s(appInfo->name, strlen(name) + 1, name);
59     APPSPAWN_CHECK(ret == 0,
60         free(appInfo); return nullptr, "Failed to strcpy process name");
61     OH_ListInit(&appInfo->node);
62     return appInfo;
63 }
64 
GetTestCGroupFilePath(const AppSpawnedProcess * appInfo,const char * fileName,char * path,bool create)65 static int GetTestCGroupFilePath(const AppSpawnedProcess *appInfo, const char *fileName, char *path, bool create)
66 {
67     int ret = GetCgroupPath(appInfo, path, PATH_MAX);
68     APPSPAWN_CHECK(ret == 0, return errno, "Failed to get real path errno: %{public}d", errno);
69     (void)CreateSandboxDir(path, 0755);  // 0755 default mode
70     ret = strcat_s(path, PATH_MAX, fileName);
71     APPSPAWN_CHECK(ret == 0, return errno, "Failed to strcat_s errno: %{public}d", errno);
72     if (create) {
73         FILE *file = fopen(path, "w");
74         APPSPAWN_CHECK(file != nullptr, return errno, "Create file fail %{public}s errno: %{public}d", path, errno);
75         fclose(file);
76     }
77     return 0;
78 }
79 
80 HWTEST_F(AppSpawnCGroupTest, App_Spawn_CGroup_001, TestSize.Level0)
81 {
82     int ret = -1;
83     AppSpawnedProcess *appInfo = nullptr;
84     const char name[] = "app-test-001";
85     do {
86         appInfo = CreateTestAppInfo(name);
87         APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
88         char path[PATH_MAX] = {};
89         ret = GetCgroupPath(appInfo, path, sizeof(path));
90         APPSPAWN_CHECK(ret == 0, break, "Failed to get real path errno: %{public}d", errno);
91         APPSPAWN_CHECK(strstr(path, "200") != nullptr && strstr(path, "33") != nullptr && strstr(path, name) != nullptr,
92             break, "Invalid path: %s", path);
93         ret = 0;
94     } while (0);
95     if (appInfo) {
96         free(appInfo);
97     }
98     ASSERT_EQ(ret, 0);
99 }
100 
101 HWTEST_F(AppSpawnCGroupTest, App_Spawn_CGroup_002, TestSize.Level0)
102 {
103     int ret = -1;
104     AppSpawnedProcess *appInfo = nullptr;
105     AppSpawnContent *content = nullptr;
106     FILE *file = nullptr;
107     const char name[] = "app-test-001";
108     do {
109         char path[PATH_MAX] = {};
110         appInfo = CreateTestAppInfo(name);
111         APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
112 
113         ret = GetTestCGroupFilePath(appInfo, "cgroup.procs", path, true);
114         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
115         content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
116         APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
117         // spawn prepare process
118         ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo);
119 
120         // add success
121         ret = GetTestCGroupFilePath(appInfo, "cgroup.procs", path, false);
122         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
123         // write pid
124         pid_t pids[] = {100, 101, 102};
125         ret = WriteToFile(path, 0, pids, 3);
126         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
127 
128         ret = -1;
129         file = fopen(path, "r");
130         APPSPAWN_CHECK(file != nullptr, break, "Open file fail %{public}s errno: %{public}d", path, errno);
131         pid_t pid = 0;
132         ret = -1;
133         while (fscanf_s(file, "%d\n", &pid) == 1 && pid > 0) {
134             APPSPAWN_LOGV("pid %{public}d %{public}d", pid, appInfo->pid);
135             if (pid == appInfo->pid) {
136                 ret = 0;
137                 break;
138             }
139         }
140         APPSPAWN_CHECK(ret == 0, break, "Error no pid write to path errno: %{public}d", errno);
141 
142     } while (0);
143     if (appInfo) {
144         free(appInfo);
145     }
146     if (file) {
147         fclose(file);
148     }
149     AppSpawnDestroyContent(content);
150     LE_StopLoop(LE_GetDefaultLoop());
151     LE_CloseLoop(LE_GetDefaultLoop());
152     ASSERT_EQ(ret, 0);
153 }
154 
155 HWTEST_F(AppSpawnCGroupTest, App_Spawn_CGroup_003, TestSize.Level0)
156 {
157     int ret = -1;
158     AppSpawnedProcess *appInfo = nullptr;
159     AppSpawnContent *content = nullptr;
160     const char name[] = "app-test-001";
161     do {
162         char path[PATH_MAX] = {};
163         appInfo = CreateTestAppInfo(name);
164         APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
165 
166         content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
167         APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
168         ProcessMgrHookExecute(STAGE_SERVER_APP_DIED, content, appInfo);
169         ret = 0;
170     } while (0);
171     if (appInfo) {
172         free(appInfo);
173     }
174     AppSpawnDestroyContent(content);
175     LE_StopLoop(LE_GetDefaultLoop());
176     LE_CloseLoop(LE_GetDefaultLoop());
177     ASSERT_EQ(ret, 0);
178 }
179 
180 HWTEST_F(AppSpawnCGroupTest, App_Spawn_CGroup_004, TestSize.Level0)
181 {
182     int ret = -1;
183     AppSpawnedProcess *appInfo = nullptr;
184     AppSpawnContent *content = nullptr;
185     FILE *file = nullptr;
186     const char name[] = "app-test-001";
187     do {
188         char path[PATH_MAX] = {};
189         appInfo = CreateTestAppInfo(name);
190         APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
191         appInfo->pid = 44;  // 44 test pid
192 
193         content = AppSpawnCreateContent(NWEBSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_NWEB_SPAWN);
194         APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
195         ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo);
196         // add success
197         ret = GetCgroupPath(appInfo, path, sizeof(path));
198         APPSPAWN_CHECK(ret == 0, break, "Failed to get real path errno: %{public}d", errno);
199         ret = strcat_s(path, sizeof(path), "cgroup.procs");
200         APPSPAWN_CHECK(ret == 0, break, "Failed to strcat_s errno: %{public}d", errno);
201         // do not write for nwebspawn, so no file
202         file = fopen(path, "r");
203         APPSPAWN_CHECK(file == nullptr, break, "Find file %{public}s ", path);
204     } while (0);
205     if (appInfo) {
206         free(appInfo);
207     }
208     if (file) {
209         fclose(file);
210     }
211     AppSpawnDestroyContent(content);
212     LE_StopLoop(LE_GetDefaultLoop());
213     LE_CloseLoop(LE_GetDefaultLoop());
214     ASSERT_EQ(ret, 0);
215 }
216 
217 HWTEST_F(AppSpawnCGroupTest, App_Spawn_CGroup_005, TestSize.Level0)
218 {
219     int ret = -1;
220     AppSpawnedProcess *appInfo = nullptr;
221     AppSpawnContent *content = nullptr;
222     const char name[] = "app-test-001";
223     do {
224         char path[PATH_MAX] = {};
225         appInfo = CreateTestAppInfo(name);
226         APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
227 
228         content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_NWEB_SPAWN);
229         APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
230         ProcessMgrHookExecute(STAGE_SERVER_APP_DIED, content, appInfo);
231         ret = 0;
232     } while (0);
233     if (appInfo) {
234         free(appInfo);
235     }
236     AppSpawnDestroyContent(content);
237     LE_StopLoop(LE_GetDefaultLoop());
238     LE_CloseLoop(LE_GetDefaultLoop());
239     ASSERT_EQ(ret, 0);
240 }
241 
242 /**
243  * @brief in appspawn service, add and delete app
244  *
245  */
246 HWTEST_F(AppSpawnCGroupTest, App_Spawn_CGroup_006, TestSize.Level0)
247 {
248     int ret = -1;
249     AppSpawnedProcess *appInfo = nullptr;
250     AppSpawnContent *content = nullptr;
251     const char name[] = "app-test-001";
252     do {
253         char path[PATH_MAX] = {};
254         appInfo = CreateTestAppInfo(name);
255         APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
256 
257         ret = GetTestCGroupFilePath(appInfo, "cgroup.procs", path, true);
258         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
259         content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
260         APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
261         ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo);
262 
263         // add success
264         ret = GetTestCGroupFilePath(appInfo, "cgroup.procs", path, false);
265         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
266         // write pid
267         pid_t pids[] = {100, 101, 102};
268         ret = WriteToFile(path, 0, pids, 3);
269         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
270 
271         AppSpawnedProcess *appInfo2 = CreateTestAppInfo(name);
272         APPSPAWN_CHECK(appInfo2 != nullptr, break, "Failed to create appInfo");
273         OH_ListAddTail(&GetAppSpawnMgr()->appQueue, &appInfo2->node);
274         appInfo2->pid = 102;
275         ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo2);
276         // died
277         ProcessMgrHookExecute(STAGE_SERVER_APP_DIED, content, appInfo);
278         OH_ListRemove(&appInfo2->node);
279         free(appInfo2);
280     } while (0);
281     if (appInfo) {
282         free(appInfo);
283     }
284     AppSpawnDestroyContent(content);
285     LE_StopLoop(LE_GetDefaultLoop());
286     LE_CloseLoop(LE_GetDefaultLoop());
287     ASSERT_EQ(ret, 0);
288 }
289 
290 /**
291  * @brief in appspawn service, max write
292  *
293  */
294 HWTEST_F(AppSpawnCGroupTest, App_Spawn_CGroup_007, TestSize.Level0)
295 {
296     int ret = -1;
297     AppSpawnedProcess *appInfo = nullptr;
298     AppSpawnContent *content = nullptr;
299     const char name[] = "app-test-001";
300     do {
301         char path[PATH_MAX] = {};
302         appInfo = CreateTestAppInfo(name);
303         APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
304         appInfo->max = 10;  // 10 test max
305         ret = GetTestCGroupFilePath(appInfo, "pids.max", path, true);
306         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
307         content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
308         APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
309         ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo);
310 
311         // add success
312         ret = GetTestCGroupFilePath(appInfo, "pids.max", path, false);
313         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
314         ret = -1;
315         FILE *file = fopen(path, "r");
316         APPSPAWN_CHECK(file != nullptr, break, "Open file fail %{public}s errno: %{public}d", path, errno);
317         uint32_t max = 0;
318         ret = -1;
319         while (fscanf_s(file, "%d\n", &max) == 1 && max > 0) {
320             APPSPAWN_LOGV("max %{public}d %{public}d", max, appInfo->max);
321             if (max == appInfo->max) {
322                 ret = 0;
323                 break;
324             }
325         }
326         fclose(file);
327     } while (0);
328     if (appInfo) {
329         free(appInfo);
330     }
331     AppSpawnDestroyContent(content);
332     LE_StopLoop(LE_GetDefaultLoop());
333     LE_CloseLoop(LE_GetDefaultLoop());
334     ASSERT_EQ(ret, 0);
335 }
336 
337 HWTEST_F(AppSpawnCGroupTest, App_Spawn_CGroup_008, TestSize.Level0)
338 {
339     int ret = -1;
340     AppSpawnedProcess *appInfo = nullptr;
341     const char name[] = "app-test-001";
342     do {
343         appInfo = CreateTestAppInfo(name);
344         APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
345         char path[PATH_MAX] = {};
346         ret = GetCgroupPath(appInfo, path, -1);
347     } while (0);
348     if (appInfo) {
349         free(appInfo);
350     }
351     ASSERT_NE(ret, 0);
352 }
353 
354 HWTEST_F(AppSpawnCGroupTest, App_Spawn_CGroup_009, TestSize.Level0)
355 {
356     pid_t pids[] = {100, 101, 102};
357     int ret = WriteToFile(nullptr, -1, pids, 3);
358     ASSERT_NE(ret, 0);
359 }
360 
361 HWTEST_F(AppSpawnCGroupTest, App_Spawn_CGroup_010, TestSize.Level0)
362 {
363     int ret = -1;
364     AppSpawnedProcess *appInfo = nullptr;
365     AppSpawnContent *content = nullptr;
366     const char name[] = "app-test-001";
367     do {
368         char path[PATH_MAX] = {};
369         appInfo = CreateTestAppInfo(name);
370         APPSPAWN_CHECK(appInfo != nullptr, break, "Failed to create appInfo");
371 
372         ret = GetTestCGroupFilePath(appInfo, "cgroup.procs", path, true);
373         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
374         content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, path, sizeof(path), MODE_FOR_APP_SPAWN);
375         APPSPAWN_CHECK_ONLY_EXPER(content != nullptr, break);
376         // spawn prepare process
377         ProcessMgrHookExecute(STAGE_SERVER_APP_ADD, content, appInfo);
378 
379         // add success
380         ret = GetTestCGroupFilePath(appInfo, "cgroup.procs", path, false);
381         APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
382         // write pid
383         pid_t pids[] = {100, 101, 102, 103};
384         ret = WriteToFile(path, 0, pids, 3);
385 
386     } while (0);
387     if (appInfo) {
388         free(appInfo);
389     }
390     AppSpawnDestroyContent(content);
391     LE_StopLoop(LE_GetDefaultLoop());
392     LE_CloseLoop(LE_GetDefaultLoop());
393     ASSERT_EQ(ret, 0);
394 }
395 }  // namespace OHOS