1 /*
2 * Copyright (c) 2021 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 <sys/socket.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <cstdlib>
20 #include "init_cmds.h"
21 #include "init_service.h"
22 #include "init_service_manager.h"
23 #include "init_service_socket.h"
24 #include "param_stub.h"
25 #include "init_utils.h"
26 #include "securec.h"
27 #include "init_group_manager.h"
28 #include "trigger_manager.h"
29 #include "bootstage.h"
30 #include "init_hook.h"
31 #include "plugin_adapter.h"
32
DoCmdByName(const char * name,const char * cmdContent)33 static void DoCmdByName(const char *name, const char *cmdContent)
34 {
35 int cmdIndex = 0;
36 (void)GetMatchCmd(name, &cmdIndex);
37 DoCmdByIndex(cmdIndex, cmdContent, nullptr);
38 }
39
40 using namespace testing::ext;
41 using namespace std;
42 namespace init_ut {
43 class ServiceUnitTest : public testing::Test {
44 public:
SetUpTestCase(void)45 static void SetUpTestCase(void)
46 {
47 string svcPath = "/data/init_ut/test_service";
48 auto fp = std::unique_ptr<FILE, decltype(&fclose)>(fopen(svcPath.c_str(), "wb"), fclose);
49 if (fp == nullptr) {
50 cout << "ServiceUnitTest open : " << svcPath << " failed." << errno << endl;
51 }
52 sync();
53 }
54
TearDownTestCase(void)55 static void TearDownTestCase(void) {};
SetUp()56 void SetUp() {};
TearDown()57 void TearDown() {};
58 };
59
60 HWTEST_F(ServiceUnitTest, case01, TestSize.Level1)
61 {
62 const char *jsonStr = "{\"services\":{\"name\":\"test_service\",\"path\":[\"/data/init_ut/test_service\"],"
63 "\"importance\":-20,\"uid\":\"system\",\"writepid\":[\"/dev/test_service\"],\"console\":1,"
64 "\"caps\":[\"TEST_ERR\"],"
65 "\"gid\":[\"system\"], \"critical\":1}}";
66 cJSON* jobItem = cJSON_Parse(jsonStr);
67 ASSERT_NE(nullptr, jobItem);
68 cJSON *serviceItem = cJSON_GetObjectItem(jobItem, "services");
69 ASSERT_NE(nullptr, serviceItem);
70 Service *service = AddService("test_service");
71 int ret = ParseOneService(serviceItem, service);
72 EXPECT_EQ(ret, 0);
73
74 ret = ServiceStart(service, &service->pathArgs);
75 EXPECT_EQ(ret, 0);
76
77 ret = ServiceStop(service);
78 EXPECT_EQ(ret, 0);
79
80 ReleaseService(service);
81 cJSON_Delete(jobItem);
82 }
83
84 HWTEST_F(ServiceUnitTest, case02, TestSize.Level1)
85 {
86 const char *jsonStr = "{\"services\":{\"name\":\"test_service8\",\"path\":[\"/data/init_ut/test_service\"],"
87 "\"importance\":-20,\"uid\":\"system\",\"writepid\":[\"/dev/test_service\"],\"console\":1,"
88 "\"gid\":[\"system\", \"shell\", \"root\"],\"caps\":[10, 4294967295, 10000],\"cpucore\":[1]}}";
89 cJSON* jobItem = cJSON_Parse(jsonStr);
90 ASSERT_NE(nullptr, jobItem);
91 cJSON *serviceItem = cJSON_GetObjectItem(jobItem, "services");
92 ASSERT_NE(nullptr, serviceItem);
93 Service *service = AddService("test_service8");
94 ASSERT_NE(nullptr, service);
95 int ret = ParseOneService(serviceItem, service);
96 EXPECT_EQ(ret, 0);
97
98 int fds[1] = {-1}; // ServiceStop will release fds
99 UpdaterServiceFds(service, fds, 1);
100 service->attribute = SERVICE_ATTR_ONDEMAND;
101 ret = ServiceStart(service, &service->pathArgs);
102 EXPECT_EQ(ret, 0);
103 CmdLines *cmdline = (CmdLines *)malloc(sizeof(CmdLines) + sizeof(CmdLine));
104 ASSERT_NE(nullptr, cmdline);
105 cmdline->cmdNum = 1;
106 cmdline->cmds[0].cmdIndex = 0;
107 service->restartArg = cmdline;
108 ServiceSocket tmpSock = { .next = nullptr, .sockFd = 0 };
109 ServiceSocket tmpSock1 = { .next = &tmpSock, .sockFd = 0 };
110 service->socketCfg = &tmpSock1;
111 ServiceReap(service);
112 service->socketCfg = nullptr;
113 service->attribute &= SERVICE_ATTR_NEED_RESTART;
114 service->firstCrashTime = 0;
115 ServiceReap(service);
116 DoCmdByName("reset ", "test_service8");
117 // reset again
118 DoCmdByName("reset ", "test_service8");
119 service->pid = 0xfffffff; // 0xfffffff is not exist pid
120 service->attribute = SERVICE_ATTR_TIMERSTART;
121 ret = ServiceStop(service);
122 EXPECT_EQ(ret, 0);
123 ReleaseService(service);
124 cJSON_Delete(jobItem);
125 }
126
127 HWTEST_F(ServiceUnitTest, TestServiceStartAbnormal, TestSize.Level1)
128 {
129 const char *jsonStr = "{\"services\":{\"name\":\"test_service1\",\"path\":[\"/data/init_ut/test_service\"],"
130 "\"importance\":-20,\"uid\":\"system\",\"writepid\":[\"/dev/test_service\"],\"console\":1,"
131 "\"gid\":[\"system\"],\"caps\":[\"\"]}}";
132 cJSON* jobItem = cJSON_Parse(jsonStr);
133 ASSERT_NE(nullptr, jobItem);
134 cJSON *serviceItem = cJSON_GetObjectItem(jobItem, "services");
135 ASSERT_NE(nullptr, serviceItem);
136 Service *service = AddService("test_service1");
137 ASSERT_NE(nullptr, service);
138 int ret = ParseOneService(serviceItem, service);
139 EXPECT_EQ(ret, 0);
140
141 ret = ServiceStart(service, &service->pathArgs);
142 EXPECT_EQ(ret, 0);
143
144 service->attribute &= SERVICE_ATTR_INVALID;
145 ret = ServiceStart(service, &service->pathArgs);
146 EXPECT_EQ(ret, 0);
147
148 service->pid = -1;
149 ret = ServiceStop(service);
150 EXPECT_EQ(ret, 0);
151 ReleaseService(service);
152 cJSON_Delete(jobItem);
153 }
154
155 HWTEST_F(ServiceUnitTest, TestServiceReap, TestSize.Level1)
156 {
157 Service *service = AddService("test_service2");
158 ASSERT_NE(nullptr, service);
159 EXPECT_EQ(service->attribute, 0);
160 service->attribute = SERVICE_ATTR_ONDEMAND;
161 ServiceReap(service);
162 service->attribute = 0;
163
164 service->restartArg = (CmdLines *)calloc(1, sizeof(CmdLines));
165 ASSERT_NE(nullptr, service->restartArg);
166 ServiceReap(service);
167 EXPECT_EQ(service->attribute, SERVICE_ATTR_TIMERSTART);
168
169 const int crashCount = 241;
170 service->crashCnt = crashCount;
171 ServiceReap(service);
172 EXPECT_EQ(service->attribute, SERVICE_ATTR_TIMERSTART);
173
174 service->attribute |= SERVICE_ATTR_ONCE;
175 ServiceReap(service);
176 EXPECT_EQ(service->attribute, (SERVICE_ATTR_ONCE | SERVICE_ATTR_TIMERSTART));
177 service->attribute = SERVICE_ATTR_CRITICAL;
178 service->crashCount = 1;
179 ServiceReap(service);
180 ReleaseService(service);
181 }
182
183 HWTEST_F(ServiceUnitTest, TestServiceReapOther, TestSize.Level1)
184 {
185 const char *serviceStr = "{\"services\":{\"name\":\"test_service4\",\"path\":[\"/data/init_ut/test_service\"],"
186 "\"onrestart\":[\"sleep 1\"],\"console\":1,\"writepid\":[\"/dev/test_service\"]}}";
187
188 cJSON* jobItem = cJSON_Parse(serviceStr);
189 ASSERT_NE(nullptr, jobItem);
190 cJSON *serviceItem = cJSON_GetObjectItem(jobItem, "services");
191 ASSERT_NE(nullptr, serviceItem);
192 Service *service = AddService("test_service4");
193 ASSERT_NE(nullptr, service);
194 int ret = ParseOneService(serviceItem, service);
195 EXPECT_EQ(ret, 0);
196
197 ServiceReap(service);
198 EXPECT_NE(service->attribute, 0);
199
200 service->attribute |= SERVICE_ATTR_CRITICAL;
201 ServiceReap(service);
202 EXPECT_NE(service->attribute, 0);
203
204 service->attribute |= SERVICE_ATTR_NEED_STOP;
205 ServiceReap(service);
206 EXPECT_NE(service->attribute, 0);
207
208 service->attribute |= SERVICE_ATTR_INVALID;
209 ServiceReap(service);
210 EXPECT_NE(service->attribute, 0);
211
212 ret = ServiceStop(service);
213 EXPECT_EQ(ret, 0);
214 ReleaseService(service);
215 cJSON_Delete(jobItem);
216 }
217
218 HWTEST_F(ServiceUnitTest, TestServiceManagerRelease, TestSize.Level1)
219 {
220 Service *service = nullptr;
221 ReleaseService(service);
222 EXPECT_TRUE(service == nullptr);
223 service = AddService("test_service5");
224 ASSERT_NE(nullptr, service);
225 service->pathArgs.argv = (char **)malloc(sizeof(char *));
226 ASSERT_NE(nullptr, service->pathArgs.argv);
227 service->pathArgs.count = 1;
228 const char *path = "/data/init_ut/test_service_release";
229 service->pathArgs.argv[0] = strdup(path);
230
231 service->writePidArgs.argv = (char **)malloc(sizeof(char *));
232 ASSERT_NE(nullptr, service->writePidArgs.argv);
233 service->writePidArgs.count = 1;
234 service->writePidArgs.argv[0] = strdup(path);
235
236 service->servPerm.caps = (unsigned int *)malloc(sizeof(unsigned int));
237 ASSERT_NE(nullptr, service->servPerm.caps);
238 service->servPerm.gIDArray = (gid_t *)malloc(sizeof(gid_t));
239 ASSERT_NE(nullptr, service->servPerm.gIDArray);
240 service->socketCfg = (ServiceSocket *)malloc(sizeof(ServiceSocket));
241 ASSERT_NE(nullptr, service->socketCfg);
242 service->socketCfg->sockFd = 0;
243 service->socketCfg->next = nullptr;
244 service->fileCfg = (ServiceFile *)malloc(sizeof(ServiceFile));
245 ASSERT_NE(nullptr, service->fileCfg);
246 service->fileCfg->fd = 0;
247 service->fileCfg->next = nullptr;
248 ReleaseService(service);
249 service = nullptr;
250 }
251
252 HWTEST_F(ServiceUnitTest, TestServiceManagerGetService, TestSize.Level1)
253 {
254 Service *service = GetServiceByPid(1);
255 StopAllServices(1, nullptr, 0, nullptr);
256 EXPECT_TRUE(service == nullptr);
257 const char *jsonStr = "{\"services\":{\"name\":\"test_service2\",\"path\":[\"/data/init_ut/test_service\"],"
258 "\"importance\":-20,\"uid\":\"system\",\"writepid\":[\"/dev/test_service\"],\"console\":1,"
259 "\"gid\":[\"system\"], \"critical\":[1,2]}}";
260 cJSON* jobItem = cJSON_Parse(jsonStr);
261 ASSERT_NE(nullptr, jobItem);
262 cJSON *serviceItem = cJSON_GetObjectItem(jobItem, "services");
263 ASSERT_NE(nullptr, serviceItem);
264 service = AddService("test_service2");
265 ASSERT_NE(nullptr, service);
266 int ret = ParseOneService(serviceItem, service);
267 EXPECT_NE(ret, 0);
268 cJSON_Delete(jobItem);
269 const char *jsonStr1 = "{\"services\":{\"name\":\"test_service3\",\"path\":[\"/data/init_ut/test_service\"],"
270 "\"importance\":-20,\"uid\":\"system\",\"writepid\":[\"/dev/test_service\"],\"console\":1,"
271 "\"gid\":[\"system\"], \"critical\":[\"on\"]}}";
272 jobItem = cJSON_Parse(jsonStr1);
273 ASSERT_NE(nullptr, jobItem);
274 serviceItem = cJSON_GetObjectItem(jobItem, "services");
275 ASSERT_NE(nullptr, serviceItem);
276 service = AddService("test_service3");
277 ASSERT_NE(nullptr, service);
278 ret = ParseOneService(serviceItem, service);
279 EXPECT_NE(ret, 0);
280 cJSON_Delete(jobItem);
281 }
282
283 /**
284 * @tc.name: TestServiceBootEventHook
285 * @tc.desc: test bootevent module exec correct
286 * @tc.type: FUNC
287 * @tc.require: issueI5NTX4
288 * @tc.author:
289 */
290 HWTEST_F(ServiceUnitTest, TestServiceBootEventHook, TestSize.Level1)
291 {
292 const char *serviceStr = "{"
293 "\"services\": [{"
294 "\"name\" : \"test-service\","
295 "\"path\" : [\"/dev/test_service\"],"
296 "\"start-mode\" : \"condition\","
297 "\"writepid\":[\"/dev/test_service\"],"
298 "\"bootevents\" : \"bootevent2\""
299 "},{"
300 "\"name\" : \"test-service\","
301 "\"path\" : [\"/dev/test_service\"],"
302 "\"start-mode\" : \"condition\","
303 "\"writepid\":[\"/dev/test_service\"],"
304 "\"bootevents\" : \"bootevent.bootevent2\""
305 "},{"
306 "\"name\" : \"test-service2\","
307 "\"path\" : [\"/dev/test_service\"],"
308 "\"console\":1,"
309 "\"start-mode\" : \"boot\","
310 "\"writepid\":[\"/dev/test_service\"],"
311 "\"bootevents\" : [\"bootevent.bootevent1\", \"bootevent.bootevent2\"]"
312 "}]"
313 "}";
314
315 SERVICE_INFO_CTX serviceInfoContext;
316 serviceInfoContext.serviceName = "test-service2";
317 serviceInfoContext.reserved = "bootevent";
318 HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, nullptr, nullptr);
319 (void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_DUMP, (void *)(&serviceInfoContext), nullptr);
320 cJSON *fileRoot = cJSON_Parse(serviceStr);
321 ASSERT_NE(nullptr, fileRoot);
322 ConfigContext context = { INIT_CONTEXT_MAIN };
323 ParseAllServices(fileRoot, &context);
324 (void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_FORK_BEFORE, (void *)(&serviceInfoContext), nullptr);
325 serviceInfoContext.reserved = nullptr;
326 (void)HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_FORK_BEFORE, (void *)(&serviceInfoContext), nullptr);
327 const char *initBootevent[] = {"init", "test"};
328 PluginExecCmd("bootevent", ARRAY_LENGTH(initBootevent), initBootevent);
329 const char *initBooteventDup[] = {"init", "test"};
330 PluginExecCmd("bootevent", ARRAY_LENGTH(initBooteventDup), initBooteventDup);
331 const char *initBooteventErr[] = {"init"};
332 PluginExecCmd("bootevent", ARRAY_LENGTH(initBooteventErr), initBooteventErr);
333 SystemWriteParam("bootevent.bootevent1", "true");
334 SystemWriteParam("bootevent.bootevent2", "true");
335 SystemWriteParam("bootevent.bootevent2", "true");
336 SystemWriteParam("persist.init.bootevent.enable", "false");
337 HookMgrExecute(GetBootStageHookMgr(), INIT_POST_PERSIST_PARAM_LOAD, nullptr, nullptr);
338 cJSON_Delete(fileRoot);
339 }
340
341 HWTEST_F(ServiceUnitTest, TestSetServiceContent, TestSize.Level1)
342 {
343 (void)WatchConsoleDevice(nullptr);
344 Service service;
345 (void)WatchConsoleDevice(&service);
346 int fd = open("/dev/console", O_RDWR);
347 if (fd >= 0) {
348 (void)write(fd, "0", 1);
349 (void)close(fd);
350 }
351 PluginExecCmdByName("setServiceContent", "netmanager");
352 StopServiceByName("netmanager");
353 }
354
355 HWTEST_F(ServiceUnitTest, TestServiceExec, TestSize.Level1)
356 {
357 Service *service = AddService("test_service7");
358 ASSERT_NE(nullptr, service);
359
360 service->pathArgs.argv = (char **)malloc(sizeof(char *));
361 ASSERT_NE(service->pathArgs.argv, nullptr);
362 service->pathArgs.count = 1;
363 const char *path = "/data/init_ut/test_service_release";
364 service->pathArgs.argv[0] = strdup(path);
365 service->importance = 20;
366 service->servPerm.gIDCnt = -1;
367 service->servPerm.uID = 0;
368 unsigned int *caps = (unsigned int *)calloc(1, sizeof(unsigned int) * 1);
369 ASSERT_NE(nullptr, caps);
370 caps[0] = FULL_CAP;
371 service->servPerm.caps = caps;
372 service->servPerm.capsCnt = 1;
373 IsEnableSandbox();
374 EnterServiceSandbox(service);
375 int ret = ServiceExec(service, &service->pathArgs);
376 EXPECT_EQ(ret, 0);
377
378 const int invalidImportantValue = 20;
379 ret = SetImportantValue(service, "", invalidImportantValue, 1);
380 EXPECT_EQ(ret, -1);
381 ReleaseService(service);
382 }
383 } // namespace init_ut
384