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