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
24 #include "securec.h"
25 #include "parameter.h"
26 #include "malloc.h"
27 #include "devhost_dump.h"
28 #include "devhost_service.h"
29 #include "devhost_service_full.h"
30 #include "hdf_base.h"
31 #include "hdf_log.h"
32 #include "hdf_power_manager.h"
33
34 #define HDF_LOG_TAG hdf_device_host
35 #define DEVHOST_MIN_INPUT_PARAM_NUM 5
36 #define DEVHOST_INPUT_PARAM_HOSTID_POS 1
37 #define DEVHOST_HOST_NAME_POS 2
38 #define DEVHOST_PROCESS_PRI_POS 3
39 #define DEVHOST_THREAD_PRI_POS 4
40 #define PARAM_BUF_LEN 128
41 #define MALLOPT_PARA_CNT 2
42 #define INVALID_PRIORITY "0"
43
StartMemoryHook(const char * processName)44 static void StartMemoryHook(const char* processName)
45 {
46 const char defaultValue[PARAM_BUF_LEN] = { 0 };
47 const char targetPrefix[] = "startup:";
48 const int targetPrefixLen = strlen(targetPrefix);
49 char paramValue[PARAM_BUF_LEN] = { 0 };
50 int retParam = GetParameter("libc.hook_mode", defaultValue, paramValue, sizeof(paramValue));
51 if (retParam <= 0 || strncmp(paramValue, targetPrefix, targetPrefixLen) != 0) {
52 return;
53 }
54 if (strstr(paramValue + targetPrefixLen, processName) != NULL) {
55 const int hookSignal = 36; // 36: native memory hooked signal
56 HDF_LOGE("raise hook signal %{public}d to %{public}s", hookSignal, processName);
57 raise(hookSignal);
58 }
59 }
60
HdfStringToInt(const char * str,int * value)61 bool HdfStringToInt(const char *str, int *value)
62 {
63 if (str == NULL || value == NULL) {
64 return false;
65 }
66
67 char *end = NULL;
68 errno = 0;
69 const int base = 10;
70 long result = strtol(str, &end, base);
71 if (end == str || end[0] != '\0' || errno == ERANGE || result > INT_MAX || result < INT_MIN) {
72 return false;
73 }
74
75 *value = (int)result;
76 return true;
77 }
78
SetProcTitle(char ** argv,const char * newTitle)79 static void SetProcTitle(char **argv, const char *newTitle)
80 {
81 size_t len = strlen(argv[0]);
82 if (strlen(newTitle) > len) {
83 HDF_LOGE("failed to set new process title because the '%{public}s' is too long", newTitle);
84 return;
85 }
86 (void)memset_s(argv[0], len, 0, len);
87 if (strcpy_s(argv[0], len + 1, newTitle) != EOK) {
88 HDF_LOGE("failed to set new process title");
89 return;
90 }
91 prctl(PR_SET_NAME, newTitle);
92 }
93
HdfSetProcPriority(char ** argv)94 static void HdfSetProcPriority(char **argv)
95 {
96 int32_t schedPriority = 0;
97 int32_t procPriority = 0;
98
99 if (!HdfStringToInt(argv[DEVHOST_PROCESS_PRI_POS], &procPriority)) {
100 HDF_LOGE("procPriority parameter error: %{public}s", argv[DEVHOST_PROCESS_PRI_POS]);
101 return;
102 }
103 if (!HdfStringToInt(argv[DEVHOST_THREAD_PRI_POS], &schedPriority)) {
104 HDF_LOGE("schedPriority parameter error: %{public}s", argv[DEVHOST_THREAD_PRI_POS]);
105 return;
106 }
107
108 if (setpriority(PRIO_PROCESS, 0, procPriority) != 0) {
109 HDF_LOGE("host setpriority failed: %{public}d", errno);
110 }
111
112 struct sched_param param = {0};
113 param.sched_priority = schedPriority;
114 if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) {
115 HDF_LOGE("host sched_setscheduler failed: %{public}d", errno);
116 } else {
117 HDF_LOGI("host sched_setscheduler succeed:%{public}d %{public}d", procPriority, schedPriority);
118 }
119 }
120
SetMallopt(int argc,char ** argv)121 static void SetMallopt(int argc, char **argv)
122 {
123 for (int i = DEVHOST_MIN_INPUT_PARAM_NUM; i < argc - 1; i += MALLOPT_PARA_CNT) {
124 int32_t malloptKey = 0;
125 int32_t malloptValue = 0;
126 int ret = 0;
127 if (!HdfStringToInt(argv[i], &malloptKey)) {
128 HDF_LOGE("malloptKey parameter error:%{public}s", argv[i]);
129 continue;
130 }
131 if (!HdfStringToInt(argv[i + 1], &malloptValue)) {
132 HDF_LOGE("malloptValue parameter error:%{public}s", argv[i + 1]);
133 continue;
134 }
135 ret = mallopt(malloptKey, malloptValue);
136 if (ret != 1) {
137 HDF_LOGE("mallopt failed, malloptKey:%{public}d, malloptValue:%{public}d, ret:%{public}d",
138 malloptKey, malloptValue, ret);
139 continue;
140 }
141 HDF_LOGI("host set mallopt succeed, mallopt:%{public}d %{public}d", malloptKey, malloptValue);
142 }
143 return;
144 }
145
main(int argc,char ** argv)146 int main(int argc, char **argv)
147 {
148 if (argc < DEVHOST_MIN_INPUT_PARAM_NUM) {
149 HDF_LOGE("Devhost main parameter error, argc: %{public}d", argc);
150 return HDF_ERR_INVALID_PARAM;
151 }
152
153 prctl(PR_SET_PDEATHSIG, SIGKILL); // host process should exit with devmgr process
154
155 int hostId = 0;
156 if (!HdfStringToInt(argv[DEVHOST_INPUT_PARAM_HOSTID_POS], &hostId)) {
157 HDF_LOGE("Devhost main parameter error, argv[1]: %{public}s", argv[DEVHOST_INPUT_PARAM_HOSTID_POS]);
158 return HDF_ERR_INVALID_PARAM;
159 }
160
161 const char *hostName = argv[DEVHOST_HOST_NAME_POS];
162 HDF_LOGI("hdf device host %{public}s %{public}d start", hostName, hostId);
163 SetProcTitle(argv, hostName);
164 StartMemoryHook(hostName);
165 if ((strcmp(argv[DEVHOST_PROCESS_PRI_POS], INVALID_PRIORITY) != 0) &&
166 (strcmp(argv[DEVHOST_THREAD_PRI_POS], INVALID_PRIORITY) != 0)) {
167 HdfSetProcPriority(argv);
168 }
169 if (argc > DEVHOST_MIN_INPUT_PARAM_NUM) {
170 SetMallopt(argc, argv);
171 }
172
173 struct IDevHostService *instance = DevHostServiceNewInstance(hostId, hostName);
174 if (instance == NULL || instance->StartService == NULL) {
175 HDF_LOGE("DevHostServiceGetInstance fail");
176 return HDF_ERR_INVALID_OBJECT;
177 }
178 HDF_LOGD("create IDevHostService of %{public}s success", hostName);
179
180 DevHostDumpInit();
181 HDF_LOGD("%{public}s start device service begin", hostName);
182 int status = instance->StartService(instance);
183 if (status != HDF_SUCCESS) {
184 HDF_LOGE("Devhost StartService fail, return: %{public}d", status);
185 DevHostServiceFreeInstance(instance);
186 DevHostDumpDeInit();
187 return status;
188 }
189
190 HdfPowerManagerInit();
191 struct DevHostServiceFull *fullService = (struct DevHostServiceFull *)instance;
192 struct HdfMessageLooper *looper = &fullService->looper;
193 if ((looper != NULL) && (looper->Start != NULL)) {
194 HDF_LOGI("%{public}s start loop", hostName);
195 looper->Start(looper);
196 }
197
198 DevHostServiceFreeInstance(instance);
199 HdfPowerManagerExit();
200 DevHostDumpDeInit();
201 HDF_LOGI("hdf device host %{public}s %{public}d exit", hostName, hostId);
202 return status;
203 }
204