• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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