• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "lmks_client.h"
17 
18 #include <cerrno>
19 #include <memory>
20 #include <string>
21 #include <sys/socket.h>
22 #include <sys/time.h>
23 #include <sys/un.h>
24 #include <thread>
25 #include <unistd.h>
26 
27 #include "app_log_wrapper.h"
28 #include "event_handler.h"
29 #include "securec.h"
30 #include "unique_fd.h"
31 
32 namespace OHOS {
33 namespace AppExecFwk {
34 namespace {
35 constexpr int LMKS_SOCKET_TIMEOUT = 3;
36 
37 constexpr size_t LMKS_START_VALUE = 1;
38 constexpr size_t LMKS_MULTIPLE = 2;
39 constexpr size_t LMKS_MAX_TARGETS = 6;
40 
41 constexpr int LMKS_CMD_TARGET = 0;
42 constexpr int LMKS_CMD_PROCPRIO = 1;
43 constexpr int LMKS_CMD_PROCREMOVE = 2;
44 constexpr int LMKS_CMD_PROCPURGE = 3;
45 
46 constexpr int APP_OOM_ADJ_MIN = -1000;
47 constexpr int APP_OOM_ADJ_MAX = 1000;
48 constexpr int LMKS_SOCKET_PATH_MAX = 108;
49 
50 constexpr std::string_view LMKS_SOCKET_PATH("/dev/socket/lmks");
51 static_assert(LMKS_SOCKET_PATH.size() < LMKS_SOCKET_PATH_MAX);
52 }  // namespace
53 
LmksClient()54 LmksClient::LmksClient() : socket_(-1)
55 {}
56 
~LmksClient()57 LmksClient::~LmksClient()
58 {
59     if (IsOpen()) {
60         Close();
61     }
62 }
63 
Open()64 int32_t LmksClient::Open()
65 {
66     APP_LOGI("%{public}s(%{public}d) connecting lmks.", __func__, __LINE__);
67 
68     if (socket_ >= 0) {
69         APP_LOGE("%{public}s(%{public}d) already connected.", __func__, __LINE__);
70         return -1;
71     }
72 
73     UniqueFd sk(socket(PF_LOCAL, SOCK_SEQPACKET, 0));
74     if (sk.Get() < 0) {
75         APP_LOGE("%{public}s(%{public}d) failed to create local socket %{public}d.", __func__, __LINE__, errno);
76         return (-errno);
77     }
78 
79     struct timeval timeOut = {.tv_sec = LMKS_SOCKET_TIMEOUT, .tv_usec = 0};
80     int fd = sk.Get();
81     if (fd < 0) {
82         APP_LOGE("%{public}s(%{public}d) fd is negative.", __func__, __LINE__);
83         return -1;
84     }
85     if ((setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeOut, sizeof(timeOut)) != 0) ||
86         (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeOut, sizeof(timeOut)) != 0)) {
87         APP_LOGE("%{public}s(%{public}d) failed to set local socket timeout %{public}s.",
88             __func__,
89             __LINE__,
90             strerror(errno));
91         return (-errno);
92     }
93 
94     struct sockaddr_un addr;
95     int32_t ret;
96     ret = memset_s(&addr, sizeof(addr), 0, sizeof(addr));
97     if (ret != EOK) {
98         APP_LOGE("%{public}s(%{public}d) failed to clear local socket addr.", __func__, __LINE__);
99         return ret;
100     }
101 
102     ret = memcpy_s(addr.sun_path, LMKS_SOCKET_PATH_MAX, LMKS_SOCKET_PATH.data(), LMKS_SOCKET_PATH.size());
103     if (ret != EOK) {
104         APP_LOGE("%{public}s(%{public}d) failed to make local socket path.", __func__, __LINE__);
105         return ret;
106     }
107 
108     addr.sun_family = AF_LOCAL;
109     socklen_t addrLen = offsetof(struct sockaddr_un, sun_path) + LMKS_SOCKET_PATH.size() + 1;
110     if (connect(sk, reinterpret_cast<struct sockaddr *>(&addr), addrLen) < 0) {
111         APP_LOGE("%{public}s(%{public}d) failed to connect to lmks %{public}s.", __func__, __LINE__, strerror(errno));
112         return (-errno);
113     }
114 
115     socket_ = sk.Release();
116 
117     return ERR_OK;
118 }
119 
Close()120 void LmksClient::Close()
121 {
122     APP_LOGI("%{public}s(%{public}d) closing lmks.", __func__, __LINE__);
123 
124     if (socket_ < 0) {
125         APP_LOGE("%{public}s(%{public}d) not connected.", __func__, __LINE__);
126         return;
127     }
128 
129     close(socket_);
130     socket_ = -1;
131 }
132 
IsOpen() const133 bool LmksClient::IsOpen() const
134 {
135     return socket_ >= 0;
136 }
137 
Target(const Targets & targets)138 int32_t LmksClient::Target(const Targets &targets)
139 {
140     APP_LOGI("Target enter");
141 
142     if (targets.empty() || targets.size() > LMKS_MAX_TARGETS) {
143         APP_LOGE(
144             "%{public}s(%{public}d) empty target or too many targets. %{public}zu", __func__, __LINE__, targets.size());
145         return (-EINVAL);
146     }
147 
148     int i = 0;
149     int32_t buf[LMKS_START_VALUE + LMKS_MULTIPLE * LMKS_MAX_TARGETS];
150     buf[i++] = LMKS_CMD_TARGET;
151 
152     for (auto target : targets) {
153         if (target.first < 0 || !CheckOomAdj(target.second)) {
154             APP_LOGE("%{public}s(%{public}d) invalid target: %{public}d %{public}d",
155                 __func__,
156                 __LINE__,
157                 target.first,
158                 target.second);
159             return (-EINVAL);
160         }
161         buf[i++] = target.first;
162         buf[i++] = target.second;
163     }
164 
165     return Write(buf, i * sizeof(int32_t)) ? ERR_OK : -1;
166 }
167 
ProcPrio(pid_t pid,uid_t uid,int oomAdj)168 int32_t LmksClient::ProcPrio(pid_t pid, uid_t uid, int oomAdj)
169 {
170     APP_LOGI("ProcPrio enter");
171 
172     if (pid < 0 || uid < 0 || !CheckOomAdj(oomAdj)) {
173         APP_LOGE("%{public}s(%{public}d) invalid parameter: %{public}d %{public}d %{public}d.",
174             __func__,
175             __LINE__,
176             pid,
177             uid,
178             oomAdj);
179         return (-EINVAL);
180     }
181 
182     int32_t buf[4] = {LMKS_CMD_PROCPRIO, pid, uid, oomAdj};
183 
184     return Write(buf, sizeof(buf)) ? ERR_OK : -1;
185 }
186 
ProcRemove(pid_t pid)187 int32_t LmksClient::ProcRemove(pid_t pid)
188 {
189     APP_LOGI("ProcRemove enter");
190 
191     if (pid < 1) {
192         APP_LOGE("%{public}s(%{public}d) invalid pid %{public}d.", __func__, __LINE__, pid);
193         return (-EINVAL);
194     }
195 
196     int32_t buf[2] = {LMKS_CMD_PROCREMOVE, pid};
197     if (!Write(buf, sizeof(buf))) {
198         APP_LOGE("failed to write");
199         return -1;
200     }
201 
202     LmksClientMsg msg;
203     if (!Read(msg.resultBuf, sizeof(int32_t))) {
204         APP_LOGE("failed to read");
205         return -1;
206     }
207 
208     if (msg.result != 0) {
209         APP_LOGE("failed to remove process");
210         return -1;
211     }
212 
213     APP_LOGI("success to remove process");
214     return 0;
215 }
216 
ProcPurge()217 bool LmksClient::ProcPurge()
218 {
219     APP_LOGI("ProcPurge enter");
220 
221     int32_t cmd = LMKS_CMD_PROCPURGE;
222 
223     return Write(reinterpret_cast<void *>(&cmd), sizeof(cmd));
224 }
225 
CheckOomAdj(int v)226 bool LmksClient::CheckOomAdj(int v)
227 {
228     return (APP_OOM_ADJ_MIN <= v && v <= APP_OOM_ADJ_MAX);
229 }
230 
Write(const void * buf,size_t len)231 bool LmksClient::Write(const void *buf, size_t len)
232 {
233     if (buf == nullptr || len < 1) {
234         APP_LOGE("%{public}s(%{public}d) invalid parameter.", __func__, __LINE__);
235         return false;
236     }
237 
238     constexpr int retryTimes = 5;
239     for (int i = 0; i < retryTimes; ++i) {
240         if (socket_ < 0 && !Open()) {
241             std::this_thread::yield();
242             continue;
243         }
244         int rLen = TEMP_FAILURE_RETRY(send(socket_, buf, len, 0));
245         if (rLen <= 0) {
246             APP_LOGE("failed to send data to lmks err %{public}s.", strerror(errno));
247             Close();
248             std::this_thread::yield();
249         } else {
250             return true;
251         }
252     }
253 
254     return false;
255 }
256 
Read(void * buf,size_t len)257 bool LmksClient::Read(void *buf, size_t len)
258 {
259     if (buf == nullptr || len < 1) {
260         APP_LOGE("invalid parameter. len %zu", len);
261         return false;
262     }
263 
264     constexpr int retryTimes = 5;
265     for (int i = 0; i < retryTimes; ++i) {
266         if (socket_ < 0 && !Open()) {
267             std::this_thread::yield();
268             continue;
269         }
270         int rLen = TEMP_FAILURE_RETRY(recv(socket_, buf, len, 0));
271         if (rLen <= 0) {
272             APP_LOGE("failed to recv data from lmks err %{public}s.", strerror(errno));
273             Close();
274             std::this_thread::yield();
275         } else {
276             return true;
277         }
278     }
279 
280     return false;
281 }
282 
283 }  // namespace AppExecFwk
284 }  // namespace OHOS
285