1 /*
2 * Copyright (c) 2024 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 <fcntl.h>
17 #include <stdio.h>
18 #include "appspawn_kickdog.h"
19
OpenAndWriteToProc(const char * procName,const char * writeStr,size_t writeLen)20 static int OpenAndWriteToProc(const char *procName, const char *writeStr, size_t writeLen)
21 {
22 if (writeStr == NULL) {
23 APPSPAWN_LOGE("Write string is null");
24 return -1;
25 }
26
27 int procFd = open(procName, O_WRONLY | O_CLOEXEC);
28 if (procFd == -1) {
29 APPSPAWN_LOGE("open %{public}s fail,errno:%{public}d", procName, errno);
30 return procFd;
31 }
32
33 int writeResult = write(procFd, writeStr, writeLen);
34 if (writeResult != (int)writeLen) {
35 APPSPAWN_LOGE("write %{public}s fail,result:%{public}d", writeStr, writeResult);
36 } else {
37 APPSPAWN_LOGV("write %{public}s success", writeStr);
38 }
39
40 close(procFd);
41 return writeResult;
42 }
43
GetProcFile(bool isLinux)44 static const char *GetProcFile(bool isLinux)
45 {
46 if (isLinux) {
47 return LINUX_APPSPAWN_WATCHDOG_FILE;
48 }
49 return HM_APPSPAWN_WATCHDOG_FILE;
50 }
51
GetProcContent(bool isLinux,bool isOpen,int mode)52 static const char *GetProcContent(bool isLinux, bool isOpen, int mode)
53 {
54 if (isOpen) {
55 if (isLinux) {
56 return LINUX_APPSPAWN_WATCHDOG_ON;
57 }
58 return (mode == MODE_FOR_NWEB_SPAWN) ? HM_NWEBSPAWN_WATCHDOG_ON : HM_APPSPAWN_WATCHDOG_ON;
59 }
60
61 if (isLinux) {
62 return LINUX_APPSPAWN_WATCHDOG_KICK;
63 }
64 return (mode == MODE_FOR_NWEB_SPAWN) ? HM_NWEBSPAWN_WATCHDOG_KICK : HM_APPSPAWN_WATCHDOG_KICK;
65 }
66
DealSpawnWatchdog(AppSpawnContent * content,bool isOpen)67 static void DealSpawnWatchdog(AppSpawnContent *content, bool isOpen)
68 {
69 int result = 0;
70 const char *procFile = GetProcFile(content->isLinux);
71 const char *procContent = GetProcContent(content->isLinux, isOpen, content->mode);
72 result = OpenAndWriteToProc(procFile, procContent, strlen(procContent));
73 if (isOpen) {
74 content->wdgOpened = (result != -1);
75 }
76 APPSPAWN_LOGI("procFile: %{public}s procContent: %{public}s %{public}s %{public}s watchdog end, result:%{public}d",
77 procFile, procContent, (content->mode == MODE_FOR_NWEB_SPAWN) ?
78 "Nwebspawn" : "Appspawn", isOpen ? "enable" : "kick", result);
79 }
80
ProcessTimerHandle(const TimerHandle taskHandle,void * context)81 static void ProcessTimerHandle(const TimerHandle taskHandle, void *context)
82 {
83 AppSpawnContent *wdgContent = (AppSpawnContent *)context;
84
85 if (!wdgContent->wdgOpened) { //first time deal kernel file
86 DealSpawnWatchdog(wdgContent, true);
87 return;
88 }
89
90 DealSpawnWatchdog(wdgContent, false);
91 }
92
CreateTimerLoopTask(AppSpawnContent * content)93 static void CreateTimerLoopTask(AppSpawnContent *content)
94 {
95 LoopHandle loop = LE_GetDefaultLoop();
96 TimerHandle timer = NULL;
97 int ret = LE_CreateTimer(loop, &timer, ProcessTimerHandle, (void *)content);
98 APPSPAWN_CHECK(ret == 0, return, "Failed to create timerLoopTask ret %{public}d", ret);
99 // start a timer to write kernel file every 10s
100 ret = LE_StartTimer(loop, timer, APPSPAWN_WATCHDOG_KICKTIME, INT64_MAX);
101 APPSPAWN_CHECK(ret == 0, return, "Failed to start timerLoopTask ret %{public}d", ret);
102 }
103
CheckKernelType(bool * isLinux)104 static int CheckKernelType(bool *isLinux)
105 {
106 struct utsname uts;
107 if (uname(&uts) == -1) {
108 APPSPAWN_LOGE("Kernel type get failed,errno:%{public}d", errno);
109 return -1;
110 }
111
112 if (strcmp(uts.sysname, "Linux") == 0) {
113 APPSPAWN_LOGI("Kernel type is linux");
114 *isLinux = true;
115 return 0;
116 }
117
118 *isLinux = false;
119 return 0;
120 }
121
SpawnKickDogStart(AppSpawnMgr * mgrContent)122 APPSPAWN_STATIC int SpawnKickDogStart(AppSpawnMgr *mgrContent)
123 {
124 APPSPAWN_CHECK(mgrContent != NULL, return 0, "content is null");
125 APPSPAWN_CHECK((mgrContent->content.mode == MODE_FOR_APP_SPAWN) ||
126 (mgrContent->content.mode == MODE_FOR_NWEB_SPAWN), return 0, "Mode %{public}u no need enable watchdog",
127 mgrContent->content.mode);
128
129 if (CheckKernelType(&mgrContent->content.isLinux) != 0) {
130 return 0;
131 }
132
133 DealSpawnWatchdog(&mgrContent->content, true);
134 CreateTimerLoopTask(&mgrContent->content);
135
136 return 0;
137 }
138
MODULE_CONSTRUCTOR(void)139 MODULE_CONSTRUCTOR(void)
140 {
141 AddPreloadHook(HOOK_PRIO_COMMON, SpawnKickDogStart);
142 }