已合并
fix(init/ueventd): PID 1 稳定性修复 — waitpid 超时(高-5/6) + ueventd NULL 守卫(高-10) + 单测 #4960
fix(init/ueventd): PID 1 稳定性修复 — waitpid 超时(高-5/6) + ueventd NULL 守卫(高-10) + 单测 #4960
已合并
chenjinxiang3创建于 5 天前
9 个文件变更+137-23
@@ -214,6 +214,8 @@ void *OH_ExtendableStrDictGet(void **strDict, int dictSize, const char *target,
214 214 
215long long GetUptimeInMicroSeconds(const struct timespec *uptime);215long long GetUptimeInMicroSeconds(const struct timespec *uptime);
216 216 
217+INIT_LOCAL_API int WaitPidTimeout(pid_t pid, int timeoutMs);
218+ 
217#ifdef __cplusplus219#ifdef __cplusplus
218#if __cplusplus220#if __cplusplus
219}221}
@@ -23,6 +23,7 @@
23#include <time.h>23#include <time.h>
24 24 
25#include "cJSON.h"25#include "cJSON.h"
26+#include "beget_ext.h"
26#include "init_cmdexecutor.h"27#include "init_cmdexecutor.h"
27#ifdef __cplusplus28#ifdef __cplusplus
28#if __cplusplus29#if __cplusplus
@@ -128,6 +129,7 @@ void PluginExecCmdByCmdIndex(int index, const char *cmdContent, const ConfigCont
128const char *PluginGetCmdIndex(const char *cmdStr, int *index);129const char *PluginGetCmdIndex(const char *cmdStr, int *index);
129const char *GetPluginCmdNameByIndex(int index);130const char *GetPluginCmdNameByIndex(int index);
130int AddCareContextCmdExecutor(const char *cmdName, CmdExecutor executor);131int AddCareContextCmdExecutor(const char *cmdName, CmdExecutor executor);
132+INIT_LOCAL_API int SyncExecCommand(int argc, char * const *argv);
131 133 
132#ifdef __cplusplus134#ifdef __cplusplus
133#if __cplusplus135#if __cplusplus
@@ -1447,13 +1447,17 @@ static void StopWorkingset(const char *workingsetPath)
1447 close(workingsetFd);1447 close(workingsetFd);
1448}1448}
1449 1449 
1450+#ifndef STARTUP_INIT_TEST
1451+#define APPSPAWN_WAIT_TIMEOUT_MS 5000
1452+#endif
1453+ 
1450static void StopAppSpawnBeforeReboot(void)1454static void StopAppSpawnBeforeReboot(void)
1451{1455{
1452 Service *service = GetServiceByName("appspawn");1456 Service *service = GetServiceByName("appspawn");
1453 if (service != NULL && service->pid > 0) { // notify appspawn stop1457 if (service != NULL && service->pid > 0) { // notify appspawn stop
1454#ifndef STARTUP_INIT_TEST1458#ifndef STARTUP_INIT_TEST
1455 kill(service->pid, SIGTERM);1459 kill(service->pid, SIGTERM);
1456- waitpid(service->pid, 0, 0);1460+ WaitPidTimeout(service->pid, APPSPAWN_WAIT_TIMEOUT_MS);
1457 service->pid = -1;1461 service->pid = -1;
1458#endif1462#endif
1459 }1463 }
@@ -152,7 +152,15 @@ int GetParamValue(const char *symValue, unsigned int symLen, char *paramValue, u
152 return 0;152 return 0;
153}153}
154 154 
155-static int SyncExecCommand(int argc, char * const *argv)155+#ifdef STARTUP_INIT_TEST
156+#define SYNC_EXEC_TIMEOUT_MS 200
157+#define FD_DUMP_TIMEOUT_MS 200
158+#else
159+#define SYNC_EXEC_TIMEOUT_MS 30000
160+#define FD_DUMP_TIMEOUT_MS 5000
161+#endif
162+ 
163+int SyncExecCommand(int argc, char * const *argv)
156{164{
157 INIT_LOGI("Sync exec: %s", argv[0]);165 INIT_LOGI("Sync exec: %s", argv[0]);
158 pid_t pid = fork();166 pid_t pid = fork();
@@ -161,9 +169,8 @@ static int SyncExecCommand(int argc, char * const *argv)
161 INIT_CHECK_ONLY_ELOG(execv(argv[0], argv) == 0, "execv %s failed! err %d.", argv[0], errno);169 INIT_CHECK_ONLY_ELOG(execv(argv[0], argv) == 0, "execv %s failed! err %d.", argv[0], errno);
162 exit(-1);170 exit(-1);
163 }171 }
164- int status;172+ int status = WaitPidTimeout(pid, SYNC_EXEC_TIMEOUT_MS);
165- pid_t ret = waitpid(pid, &status, 0);173+ if (status < 0) {
166- if (ret != pid) {
167 INIT_LOGE("failed wait pid %d, errno %d", pid, errno);174 INIT_LOGE("failed wait pid %d, errno %d", pid, errno);
168 return -1;175 return -1;
169 }176 }
@@ -821,9 +828,8 @@ static void DumpFdInfo()
821 INIT_LOGE("fork failed, err is %d", errno);828 INIT_LOGE("fork failed, err is %d", errno);
822 return;829 return;
823 }830 }
824- int status;831+ int status = WaitPidTimeout(pid, FD_DUMP_TIMEOUT_MS);
825- pid_t ret = waitpid(pid, &status, 0);832+ if (status < 0) {
826- if (ret != pid) {
827 INIT_LOGE("failed wait pid %d, errno is %d", pid, errno);833 INIT_LOGE("failed wait pid %d, errno is %d", pid, errno);
828 }834 }
829 INIT_LOGI("dump fd info end");835 INIT_LOGI("dump fd info end");
@@ -21,10 +21,12 @@
21#include <grp.h>21#include <grp.h>
22#include <limits.h>22#include <limits.h>
23#include <pwd.h>23#include <pwd.h>
24+#include <signal.h>
24#include <stdlib.h>25#include <stdlib.h>
25#include <string.h>26#include <string.h>
26#include <sys/ioctl.h>27#include <sys/ioctl.h>
27#include <sys/stat.h>28#include <sys/stat.h>
29+#include <sys/wait.h>
28#include <unistd.h>30#include <unistd.h>
29#include <time.h>31#include <time.h>
30 32 
@@ -951,3 +953,25 @@ long long GetUptimeInMicroSeconds(const struct timespec *uptime)
951 return ((long long)uptime->tv_sec * SECOND_TO_MICRO_SECOND) +953 return ((long long)uptime->tv_sec * SECOND_TO_MICRO_SECOND) +
952 (uptime->tv_nsec / MICRO_SECOND_TO_NANOSECOND);954 (uptime->tv_nsec / MICRO_SECOND_TO_NANOSECOND);
953}955}
956+ 
957+#define WAIT_POLL_INTERVAL_MS 10
958+#define WAIT_POLL_INTERVAL_US (WAIT_POLL_INTERVAL_MS * 1000)
959+int WaitPidTimeout(pid_t pid, int timeoutMs)
960+{
961+ int status = 0;
962+ int retry = timeoutMs / WAIT_POLL_INTERVAL_MS;
963+ while (retry-- > 0) {
964+ pid_t r = waitpid(pid, &status, WNOHANG);
965+ if (r == pid) {
966+ return status;
967+ }
968+ if (r < 0) {
969+ return -1;
970+ }
971+ usleep(WAIT_POLL_INTERVAL_US);
972+ }
973+ INIT_LOGE("wait pid %d timeout, force kill", pid);
974+ kill(pid, SIGKILL);
975+ waitpid(pid, &status, 0);
976+ return -1;
977+}
@@ -15,10 +15,14 @@
15 15 
16#include <cerrno>16#include <cerrno>
17#include <cstdint>17#include <cstdint>
18+#include <csignal>
18#include <dlfcn.h>19#include <dlfcn.h>
19#include <fcntl.h>20#include <fcntl.h>
20#include <sys/ioctl.h>21#include <sys/ioctl.h>
21#include <sys/statvfs.h>22#include <sys/statvfs.h>
23+#include <sys/types.h>
24+#include <sys/wait.h>
25+#include <unistd.h>
22#include "func_wrapper.h"26#include "func_wrapper.h"
23#include "init_cmds.h"27#include "init_cmds.h"
24#include "init_param.h"28#include "init_param.h"
@@ -617,4 +621,43 @@ HWTEST_F(CmdsUnitTest, TestDeInitEswapSpace, TestSize.Level1)
617 EXPECT_EQ(ret, true);621 EXPECT_EQ(ret, true);
618 }622 }
619}623}
624+ 
625+// Branch 1: child exits quickly → returns the child's exit status.
626+HWTEST_F(CmdsUnitTest, WaitPidTimeout_ChildExits, TestSize.Level1)
627+{
628+ constexpr int testExitCode = 42;
629+ constexpr int testWaitTimeoutMs = 3000;
630+ pid_t pid = fork();
631+ ASSERT_GE(pid, 0);
632+ if (pid == 0) {
633+ _exit(testExitCode);
634+ }
635+ int status = WaitPidTimeout(pid, testWaitTimeoutMs);
636+ EXPECT_NE(status, -1);
637+ EXPECT_EQ(WEXITSTATUS(status), testExitCode);
638+}
639+ 
640+// Branch 2: invalid pid → waitpid returns -1 → returns -1 immediately.
641+HWTEST_F(CmdsUnitTest, WaitPidTimeout_InvalidPid, TestSize.Level1)
642+{
643+ constexpr pid_t invalidTestPid = 999999;
644+ constexpr int testShortTimeoutMs = 1000;
645+ int status = WaitPidTimeout(invalidTestPid, testShortTimeoutMs);
646+ EXPECT_EQ(status, -1);
647+}
648+ 
649+// Branch 3: child hangs → timeout → SIGKILL + reap → returns -1.
650+HWTEST_F(CmdsUnitTest, WaitPidTimeout_TimeoutKill, TestSize.Level1)
651+{
652+ constexpr int testKillTimeoutMs = 300;
653+ pid_t pid = fork();
654+ ASSERT_GE(pid, 0);
655+ if (pid == 0) {
656+ for (;;) {}
657+ }
658+ int status = WaitPidTimeout(pid, testKillTimeoutMs);
659+ EXPECT_EQ(status, -1);
660+ EXPECT_EQ(kill(pid, 0), -1);
661+ EXPECT_EQ(errno, ESRCH);
662+}
620} // namespace init_ut663} // namespace init_ut
@@ -787,4 +787,28 @@ HWTEST_F(UeventdEventUnitTest, Init_BootDeviceIsMatchedTest_DefaultBootDevice001
787 EXPECT_EQ(ret, 0);787 EXPECT_EQ(ret, 0);
788}788}
789 789 
790+// Branch 1: loop matches a required name → return true.
791+HWTEST_F(UeventdEventUnitTest, IsRequiredPartitionName_Match, TestSize.Level1)
792+{
793+ EXPECT_TRUE(IsRequiredPartitionName("vendor"));
794+ EXPECT_TRUE(IsRequiredPartitionName("system"));
795+ EXPECT_TRUE(IsRequiredPartitionName("ramdisk"));
796+ EXPECT_TRUE(IsRequiredPartitionName("myvendor"));
797+}
798+ 
799+// Branch 2: loop exhausts, IsOtherPartitionName returns true → return true.
800+HWTEST_F(UeventdEventUnitTest, IsRequiredPartitionName_OtherMatch, TestSize.Level1)
801+{
802+ EXPECT_TRUE(IsRequiredPartitionName("patch_a"));
803+ EXPECT_TRUE(IsRequiredPartitionName("version_b"));
804+ EXPECT_TRUE(IsRequiredPartitionName("cust_a"));
805+}
806+ 
807+// Branch 3: neither in requiredNames nor IsOtherPartitionName → return false.
808+HWTEST_F(UeventdEventUnitTest, IsRequiredPartitionName_NoMatch, TestSize.Level1)
809+{
810+ EXPECT_FALSE(IsRequiredPartitionName("unknownpart"));
811+ EXPECT_FALSE(IsRequiredPartitionName("xyz"));
812+}
813+ 
790} // UeventdUt814} // UeventdUt
@@ -17,6 +17,7 @@
17#define BASE_STARTUP_INITLITE_UEVENTD_H17#define BASE_STARTUP_INITLITE_UEVENTD_H
18#include <stdbool.h>18#include <stdbool.h>
19#include <unistd.h>19#include <unistd.h>
20+#include "beget_ext.h"
20#ifdef __cplusplus21#ifdef __cplusplus
21#if __cplusplus22#if __cplusplus
22extern "C" {23extern "C" {
@@ -85,6 +86,7 @@ void ProcessUevent(int sockFd, char **devices, int num, CompareUevent compare);
85void CloseUeventConfig(void);86void CloseUeventConfig(void);
86char **GetBootDeviceArray(void);87char **GetBootDeviceArray(void);
87int GetBootDeviceNum(void);88int GetBootDeviceNum(void);
89+INIT_LOCAL_API bool IsRequiredPartitionName(const char *partitionName);
88#ifdef __cplusplus90#ifdef __cplusplus
89#if __cplusplus91#if __cplusplus
90}92}
@@ -254,28 +254,34 @@ static void SaveDataUeventInfo(const struct Uevent *uevent)
254}254}
255#endif255#endif
256 256 
257+bool IsRequiredPartitionName(const char *partitionName)
258+{
259+ static const char *requiredNames[] = {
260+ "vendor", "system", "sys_prod", "chip_prod", "chipset", "boot",
261+ "ramdisk", "rvt", "dtbo", "modem_driver", "hyperhold"
262+ };
263+ const size_t count = sizeof(requiredNames) / sizeof(requiredNames[0]);
264+ for (size_t i = 0; i < count; i++) {
265+ if (strstr(partitionName, requiredNames[i]) != NULL) {
266+ return true;
267+ }
268+ }
269+ return IsOtherPartitionName(partitionName);
270+}
271+ 
257static void HandleRequiredBlockDeviceNodes(const struct Uevent *uevent, char **devices, int num)272static void HandleRequiredBlockDeviceNodes(const struct Uevent *uevent, char **devices, int num)
258{273{
259 for (int i = 0; i < num; i++) {274 for (int i = 0; i < num; i++) {
260 if (uevent->partitionName == NULL) {275 if (uevent->partitionName == NULL) {
261- if (strstr(devices[i], uevent->deviceName) != NULL) {276+ if (uevent->deviceName != NULL &&
262- INIT_LOGI("%s match with required partition %s success, now handle it", devices[i], uevent->deviceName);277+ strstr(devices[i], uevent->deviceName) != NULL) {
278+ INIT_LOGI("%s match with required partition %s success, now handle it",
279+ devices[i], uevent->deviceName);
263 HandleBlockDeviceEvent(uevent);280 HandleBlockDeviceEvent(uevent);
264 return;281 return;
265 }282 }
266 } else if (strstr(devices[i], uevent->partitionName) != NULL ||283 } else if (strstr(devices[i], uevent->partitionName) != NULL ||
267- strstr(uevent->partitionName, "vendor") != NULL ||284+ IsRequiredPartitionName(uevent->partitionName)) {
268- strstr(uevent->partitionName, "system") != NULL ||
269- strstr(uevent->partitionName, "sys_prod") != NULL ||
270- strstr(uevent->partitionName, "chip_prod") != NULL ||
271- strstr(uevent->partitionName, "chipset") != NULL ||
272- strstr(uevent->partitionName, "boot") != NULL ||
273- strstr(uevent->partitionName, "ramdisk") != NULL ||
274- strstr(uevent->partitionName, "rvt") != NULL ||
275- strstr(uevent->partitionName, "dtbo") != NULL ||
276- strstr(uevent->partitionName, "modem_driver") != NULL ||
277- strstr(uevent->partitionName, "hyperhold") != NULL ||
278- IsOtherPartitionName(uevent->partitionName)) {
279 INIT_LOGI("Handle required partitionName %s", uevent->partitionName);285 INIT_LOGI("Handle required partitionName %s", uevent->partitionName);
280 HandleBlockDeviceEvent(uevent);286 HandleBlockDeviceEvent(uevent);
281 return;287 return;
@@ -284,7 +290,8 @@ static void HandleRequiredBlockDeviceNodes(const struct Uevent *uevent, char **d
284 return;290 return;
285 }291 }
286 }292 }
287- INIT_LOGW("Not found device for partitionName %s ", uevent->partitionName);293+ INIT_LOGW("Not found device for partitionName %s ",
294+ (uevent->partitionName != NULL) ? uevent->partitionName : "(null)");
288}295}
289 296 
290static void HandleUeventRequired(const struct Uevent *uevent, char **devices, int num)297static void HandleUeventRequired(const struct Uevent *uevent, char **devices, int num)