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 <errno.h>
17 #include <limits.h>
18 #include <sched.h>
19 #include <signal.h>
20 #include <stdlib.h>
21 #include <sys/prctl.h>
22 #include <sys/resource.h>
23 #include <getopt.h>
24
25 #include "securec.h"
26 #include "parameter.h"
27 #include "malloc.h"
28 #include "devhost_dump.h"
29 #include "devhost_service.h"
30 #include "devhost_service_full.h"
31 #include "hdf_base.h"
32 #include "hdf_core_log.h"
33 #include "hdf_power_manager.h"
34
35 #define HDF_LOG_TAG hdf_device_host
36 #define DEVHOST_MIN_INPUT_PARAM_NUM 5
37 #define DEVHOST_INPUT_PARAM_HOSTID_POS 1
38 #define DEVHOST_HOST_NAME_POS 2
39 #define DEVHOST_PROCESS_PRI_POS 3
40 #define DEVHOST_THREAD_PRI_POS 4
41 #define PARAM_BUF_LEN 128
42 #define MALLOPT_PARA_CNT 2
43 #define INVALID_PRIORITY "0"
44 #define DEVHOST_ARGUMENT 2
45
46 typedef struct {
47 int hostId;
48 const char *hostName;
49 int schedPriority;
50 int processPriority;
51 int malloptKey;
52 int malloptValue;
53 } HostConfig;
54
HdfStringToInt(const char * str,int * value)55 bool HdfStringToInt(const char *str, int *value)
56 {
57 if (str == NULL || value == NULL) {
58 return false;
59 }
60
61 char *end = NULL;
62 errno = 0;
63 const int base = 10;
64 long result = strtol(str, &end, base);
65 if (end == str || end[0] != '\0' || errno == ERANGE || result > INT_MAX || result < INT_MIN) {
66 return false;
67 }
68
69 *value = (int)result;
70 return true;
71 }
72
SetMallopt(int32_t malloptKey,int32_t malloptValue)73 static void SetMallopt(int32_t malloptKey, int32_t malloptValue)
74 {
75 int ret = mallopt(malloptKey, malloptValue);
76 if (ret != 1) {
77 HDF_LOGE("mallopt failed, malloptKey:%{public}d, malloptValue:%{public}d, ret:%{public}d",
78 malloptKey, malloptValue, ret);
79 return;
80 }
81 HDF_LOGI("host set mallopt succeed, mallopt:%{public}d %{public}d", malloptKey, malloptValue);
82 }
83
84 typedef int32_t (*CommandFunc)(const char *key, const char *value, HostConfig *config);
85 typedef struct CommandToFunc {
86 const char *opt;
87 CommandFunc func;
88 }CommandToFunc;
89
CommandIFunc(const char * key,const char * value,HostConfig * config)90 static int32_t CommandIFunc(const char *key, const char *value, HostConfig *config)
91 {
92 (void)key;
93 if (!HdfStringToInt(value, &config->hostId)) {
94 HDF_LOGE("Invalid process ID: %{public}s", value);
95 return HDF_ERR_INVALID_PARAM;
96 }
97 return HDF_SUCCESS;
98 }
99
CommandNFunc(const char * key,const char * value,HostConfig * config)100 static int32_t CommandNFunc(const char *key, const char *value, HostConfig *config)
101 {
102 (void)key;
103 config->hostName = value;
104 return HDF_SUCCESS;
105 }
106
CommandPFunc(const char * key,const char * value,HostConfig * config)107 static int32_t CommandPFunc(const char *key, const char *value, HostConfig *config)
108 {
109 (void)key;
110 if (!HdfStringToInt(value, &config->processPriority)) {
111 HDF_LOGE("Invalid process ID: %{public}s", value);
112 }
113 return HDF_SUCCESS;
114 }
115
CommandSFunc(const char * key,const char * value,HostConfig * config)116 static int32_t CommandSFunc(const char *key, const char *value, HostConfig *config)
117 {
118 (void)key;
119 if (!HdfStringToInt(value, &config->schedPriority)) {
120 HDF_LOGE("Invalid process ID: %{public}s", value);
121 }
122 return HDF_SUCCESS;
123 }
124
CommandMFunc(const char * key,const char * value,HostConfig * config)125 static int32_t CommandMFunc(const char *key, const char *value, HostConfig *config)
126 {
127 (void)key;
128 if (!HdfStringToInt(value, &config->malloptKey)) {
129 HDF_LOGE("Invalid process ID: %{public}s", value);
130 }
131 return HDF_SUCCESS;
132 }
133
CommandVFunc(const char * key,const char * value,HostConfig * config)134 static int32_t CommandVFunc(const char *key, const char *value, HostConfig *config)
135 {
136 (void)key;
137 if (!HdfStringToInt(value, &config->malloptValue)) {
138 HDF_LOGE("Invalid process ID: %{public}s", value);
139 }
140 return HDF_SUCCESS;
141 }
142
CommandNumFunc(const char * key,const char * value,HostConfig * config)143 static int32_t CommandNumFunc(const char *key, const char *value, HostConfig *config)
144 {
145 int32_t malloptKey = 0;
146 int32_t malloptValue = 0;
147 if (!HdfStringToInt(value, &malloptValue)) {
148 HDF_LOGE("Invalid value: %{public}s", value);
149 }
150 if (!HdfStringToInt(key, &malloptKey)) {
151 HDF_LOGE("Invalid key: %{public}s", key);
152 }
153 SetMallopt(malloptKey, malloptValue);
154 return HDF_SUCCESS;
155 }
156
157 static struct CommandToFunc g_commandFuncs[] = {
158 {"-i", CommandIFunc},
159 {"-n", CommandNFunc},
160 {"-p", CommandPFunc},
161 {"-s", CommandSFunc},
162 {"-m", CommandMFunc},
163 {"-v", CommandVFunc},
164 {"-1005", CommandNumFunc},
165 {"-1006", CommandNumFunc},
166 {"-1007", CommandNumFunc},
167 {"-1008", CommandNumFunc},
168 {"-1009", CommandNumFunc},
169 {"-1010", CommandNumFunc},
170 {"-1011", CommandNumFunc},
171 {"-1012", CommandNumFunc},
172 {"-1013", CommandNumFunc},
173 {"-1014", CommandNumFunc},
174 };
175
StartMemoryHook(const char * processName)176 static void StartMemoryHook(const char* processName)
177 {
178 const char defaultValue[PARAM_BUF_LEN] = { 0 };
179 const char targetPrefix[] = "startup:";
180 const int targetPrefixLen = strlen(targetPrefix);
181 char paramValue[PARAM_BUF_LEN] = { 0 };
182 int retParam = GetParameter("libc.hook_mode", defaultValue, paramValue, sizeof(paramValue));
183 if (retParam <= 0 || strncmp(paramValue, targetPrefix, targetPrefixLen) != 0) {
184 return;
185 }
186 if (strstr(paramValue + targetPrefixLen, processName) != NULL) {
187 const int hookSignal = 36; // 36: native memory hooked signal
188 HDF_LOGE("raise hook signal %{public}d to %{public}s", hookSignal, processName);
189 raise(hookSignal);
190 }
191 }
192
SetProcTitle(char ** argv,const char * newTitle)193 static void SetProcTitle(char **argv, const char *newTitle)
194 {
195 if (newTitle == NULL) {
196 HDF_LOGE("failed because newTitle is NULL");
197 return;
198 }
199 size_t len = strlen(argv[0]); // 获取原始进程标题的长度
200 if (strlen(newTitle) > len) { // 如果新标题的长度超过原始标题的长度
201 HDF_LOGE("failed to set new process title because the '%{public}s' is too long", newTitle); // 打印错误日志
202 return; // 退出函数
203 }
204 (void)memset_s(argv[0], len, 0, len); // 将原始标题的内存清零
205 if (strcpy_s(argv[0], len + 1, newTitle) != EOK) { // 将新标题复制到原始标题的位置
206 HDF_LOGE("failed to set new process title"); // 如果复制失败,打印错误日志
207 return; // 退出函数
208 }
209 prctl(PR_SET_NAME, newTitle); // 使用 prctl 系统调用设置进程的名字
210 }
211
HdfSetProcPriority(int32_t procPriority,int32_t schedPriority)212 static void HdfSetProcPriority(int32_t procPriority, int32_t schedPriority)
213 {
214 if (setpriority(PRIO_PROCESS, 0, procPriority) != 0) {
215 HDF_LOGE("host setpriority failed: %{public}d", errno);
216 }
217
218 struct sched_param param = {0};
219 param.sched_priority = schedPriority;
220 if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) {
221 HDF_LOGE("host sched_setscheduler failed: %{public}d", errno);
222 } else {
223 HDF_LOGI("host sched_setscheduler succeed:%{public}d %{public}d", procPriority, schedPriority);
224 }
225 }
226
FindFunc(const char * arg,const char * value,HostConfig * config)227 static int FindFunc(const char* arg, const char* value, HostConfig *config)
228 {
229 for (size_t i = 0; i < sizeof(g_commandFuncs) / sizeof(g_commandFuncs[0]); ++i) {
230 if (strcmp(g_commandFuncs[i].opt, arg) == 0) {
231 return g_commandFuncs[i].func(arg, value, config);
232 }
233 }
234 HDF_LOGE("FindFunc failed: %{public}s", arg);
235 return HDF_ERR_INVALID_PARAM;
236 }
237
ParseCommandLineArgs(int argc,char ** argv,HostConfig * config)238 static int ParseCommandLineArgs(int argc, char **argv, HostConfig *config)
239 {
240 for (int i = 1; i < argc; i += DEVHOST_ARGUMENT) {
241 const char* arg = argv[i];
242
243 if (arg == NULL) {
244 HDF_LOGE("NULL argument:arg");
245 continue;
246 }
247
248 int valueIndex = i + 1;
249 if (valueIndex >= argc) {
250 HDF_LOGE("Missing argument for -%{public}s", arg);
251 continue;
252 }
253 const char* value = argv[valueIndex];
254 if (value == NULL) {
255 HDF_LOGE("NULL argument: value");
256 continue;
257 }
258 if (FindFunc(arg, value, config) != HDF_SUCCESS) {
259 HDF_LOGE("argument Parse failed for -%s", arg);
260 }
261 }
262 return HDF_SUCCESS;
263 }
264
InitializeHost(const HostConfig * config,char ** argv)265 static int InitializeHost(const HostConfig *config, char **argv)
266 {
267 prctl(PR_SET_PDEATHSIG, SIGKILL); // host process should exit with devmgr process
268
269 HDF_LOGI("hdf device host %{public}s %{public}d start", config->hostName, config->hostId);
270 SetProcTitle(argv, config->hostName);
271 StartMemoryHook(config->hostName);
272 if ((config->processPriority != 0) && (config->schedPriority != 0)) {
273 HdfSetProcPriority(config->processPriority, config->schedPriority);
274 }
275 if ((config->malloptKey != 0) && (config->malloptValue != 0)) {
276 SetMallopt(config->malloptKey, config->malloptValue);
277 }
278 return HDF_SUCCESS;
279 }
280
StartHostService(const HostConfig * config)281 static int StartHostService(const HostConfig *config)
282 {
283 struct IDevHostService *instance = DevHostServiceNewInstance(config->hostId, config->hostName);
284 if (instance == NULL || instance->StartService == NULL) {
285 HDF_LOGE("DevHostServiceGetInstance fail");
286 return HDF_ERR_INVALID_OBJECT;
287 }
288 HDF_LOGD("create IDevHostService of %{public}s success", config->hostName);
289
290 DevHostDumpInit();
291 HDF_LOGD("%{public}s start device service begin", config->hostName);
292 int status = instance->StartService(instance);
293 if (status != HDF_SUCCESS) {
294 HDF_LOGE("Devhost StartService fail, return: %{public}d", status);
295 DevHostServiceFreeInstance(instance);
296 DevHostDumpDeInit();
297 return status;
298 }
299
300 HdfPowerManagerInit();
301 struct DevHostServiceFull *fullService = (struct DevHostServiceFull *)instance;
302 struct HdfMessageLooper *looper = &fullService->looper;
303 if ((looper != NULL) && (looper->Start != NULL)) {
304 HDF_LOGI("%{public}s start loop", config->hostName);
305 looper->Start(looper);
306 }
307
308 DevHostServiceFreeInstance(instance);
309 HdfPowerManagerExit();
310 DevHostDumpDeInit();
311 return HDF_SUCCESS;
312 }
313
main(int argc,char ** argv)314 int main(int argc, char **argv)
315 {
316 if (argc < DEVHOST_MIN_INPUT_PARAM_NUM) {
317 HDF_LOGE("Devhost main parameter error, argc: %{public}d", argc);
318 return HDF_ERR_INVALID_PARAM;
319 }
320
321 HostConfig config = {0};
322 if (ParseCommandLineArgs(argc, argv, &config) != HDF_SUCCESS) {
323 HDF_LOGE("ParseCommandLineArgs(argc, argv, &config) != HDF_SUCCESS");
324 return HDF_ERR_INVALID_PARAM;
325 }
326
327 if (InitializeHost(&config, argv) != HDF_SUCCESS) {
328 return HDF_ERR_INVALID_PARAM;
329 }
330
331 int status = StartHostService(&config);
332 HDF_LOGI("hdf device host %{public}s %{public}d exit", config.hostName, config.hostId);
333 return status;
334 }
335