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