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