b94efa4083d22712936e7751c784d853a54bde27
[platform/core/appfw/aul-1.git] / src / aul / aul_proc.cc
1 /*
2  * Copyright (c) 2000 - 2021 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "aul/include/aul_proc.h"
18
19 #include <bundle_cpp.h>
20 #include <bundle_internal.h>
21 #include <fcntl.h>
22 #include <glib-unix.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29
30 #include <memory>
31 #include <mutex>
32 #include <string>
33
34 #include "aul/app_request.h"
35 #include "aul/aul_api.h"
36 #include "aul/aul_util.h"
37 #include "aul/common/file_descriptor.hh"
38 #include "aul/include/aul_sock.h"
39
40 using namespace aul;
41 using namespace aul::internal;
42
43 namespace {
44
45 class ProcContext {
46  public:
47   ProcContext() {}
48   ~ProcContext() {
49     if (source_ != 0)
50       g_source_remove(source_);
51   }
52
53   void SetName(std::string name) {
54     std::lock_guard<std::mutex> lock(mutex_);
55     name_ = std::move(name);
56   }
57
58   const std::string& GetName() {
59     std::lock_guard<std::mutex> lock(mutex_);
60     return name_;
61   }
62
63   void SetExtra(tizen_base::Bundle extra) {
64     std::lock_guard<std::mutex> lock(mutex_);
65     extra_ = std::move(extra);
66   }
67
68   tizen_base::Bundle& GetExtra() {
69     std::lock_guard<std::mutex> lock(mutex_);
70     return extra_;
71   }
72
73   void SetFd(int fd) {
74     std::lock_guard<std::mutex> lock(mutex_);
75     fd_.Set(fd);
76     source_ = g_unix_fd_add(fd, G_IO_IN, UnixFdFunc, this);
77   }
78
79   void Close() {
80     std::lock_guard<std::mutex> lock(mutex_);
81     fd_.Close();
82   }
83
84   bool IsClosed() {
85     std::lock_guard<std::mutex> lock(mutex_);
86     return fd_.IsClosed();
87   }
88
89  private:
90   void Reset() {
91     std::lock_guard<std::mutex> lock(mutex_);
92     name_ = "";
93     fd_.Close();
94     extra_ = tizen_base::Bundle();
95     source_ = 0;
96   }
97
98   static gboolean UnixFdFunc(gint fd, GIOCondition condition,
99                              gpointer user_data) {
100     auto* proc_context = static_cast<ProcContext*>(user_data);
101
102     if (condition & G_IO_IN) {
103       int ret = aul_sock_recv_result_with_fd(fd);
104       if (ret != 0) {
105         _E("Failed to receive result. fd(%d)", fd);
106         proc_context->Reset();
107         return G_SOURCE_REMOVE;
108       }
109       _D("Result(%d) received", ret);
110     } else if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
111       _E("Socket was disconnected. fd(%d)", fd);
112       proc_context->Reset();
113       return G_SOURCE_REMOVE;
114     }
115
116     return G_SOURCE_CONTINUE;
117   }
118
119  private:
120   FileDescriptor fd_;
121   std::string name_;
122   tizen_base::Bundle extra_;
123   mutable std::mutex mutex_;
124   guint source_ = 0;
125 };
126
127 int ReadFromPath(const std::string& path, char* buf, size_t buf_size) {
128   int fd = open(path.c_str(), O_RDONLY);
129   if (fd < 0) {
130     _E("open() is failed. path(%s), errno(%d)", path.c_str(), errno);
131     return AUL_R_ERROR;
132   }
133
134   FileDescriptor fd_closer(fd);
135   ssize_t bytes = read(fd, buf, buf_size - 1);
136   if (bytes <= 0) {
137     _E("read() is failed. errno(%d)", errno);
138     return AUL_R_ERROR;
139   }
140
141   buf[bytes] = '\0';
142   return AUL_R_OK;
143 }
144
145 int SendAndReceive(int cmd, pid_t pid, uid_t uid, bundle** response) {
146   int fd = AppRequest(cmd, uid)
147       .SetPid(pid)
148       .SendSimply(AUL_SOCK_ASYNC);
149   if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
150     _E("Failed to send request. error(%d)", fd);
151     return fd;
152   }
153
154   FileDescriptor fd_closer(fd);
155   app_pkt_t* pkt = nullptr;
156   int ret = aul_sock_recv_reply_pkt(fd, &pkt);
157   if (ret < 0) {
158     _E("Failed to receive reply packet. error(%d)", ret);
159     return AUL_R_ECOMM;
160   }
161
162   std::unique_ptr<app_pkt_t, decltype(std::free)*> pkt_auto(pkt, std::free);
163   if (!(pkt->opt & AUL_SOCK_BUNDLE)) {
164     _E("Invalid protocol");
165     return AUL_R_ECOMM;
166   }
167
168   if (pkt->cmd != APP_GET_INFO_OK) {
169     _E("Failed to get name by pid(%d)", pid);
170     return AUL_R_ERROR;
171   }
172
173   *response = bundle_decode(pkt->data, pkt->len);
174   if (*response == nullptr) {
175     _E("bundle_decode() is failed");
176     return AUL_R_ERROR;
177   }
178
179   return AUL_R_OK;
180 }
181
182 ProcContext context;
183
184 }  // namespace
185
186 extern "C" API int aul_proc_get_uid(pid_t pid, uid_t* uid) {
187   if (pid < 1 || uid == nullptr) {
188     _E("Invalid parameter");
189     return AUL_R_EINVAL;
190   }
191
192   std::string path = "/proc/" + std::to_string(pid);
193   struct stat stat_buf;
194   int ret = stat(path.c_str(), &stat_buf);
195   if (ret < 0) {
196     _E("stat() is failed. path(%s), errno(%d)", path.c_str(), errno);
197     return AUL_R_ERROR;
198   }
199
200   *uid = stat_buf.st_uid;
201   return AUL_R_OK;
202 }
203
204 extern "C" API int aul_proc_get_attr(pid_t pid, char* buf, size_t buf_size) {
205   if (pid < 1 || buf == nullptr || buf_size <= 0) {
206     _E("Invalid parameter");
207     return AUL_R_EINVAL;
208   }
209
210   std::string path = "/proc/" + std::to_string(pid) + "/attr/current";
211   return ReadFromPath(path, buf, buf_size);
212 }
213
214 extern "C" API int aul_proc_get_cmdline(pid_t pid, char* buf, size_t buf_size) {
215   if (pid < 1 || buf == nullptr || buf_size <= 0) {
216     _E("Invalid parameter");
217     return AUL_R_EINVAL;
218   }
219
220   std::string path = "/proc/" + std::to_string(pid) + "/cmdline";
221   return ReadFromPath(path, buf, buf_size);
222 }
223
224 extern "C" API int aul_proc_register(const char* name, bundle* extra) {
225   if (name == nullptr || name[0] == '\0') {
226     _E("Invalid parameter");
227     return AUL_R_EINVAL;
228   }
229
230   if (!context.IsClosed()) {
231     _E("Already registered. Please call aul_proc_deregister() first");
232     return AUL_R_ERROR;
233   }
234
235   tizen_base::Bundle b {{AUL_K_PROC_NAME, name}};
236   if (extra) {
237     tizen_base::Bundle extra_data(extra, false, false);
238     auto raw = extra_data.ToRaw();
239     b.Add(AUL_K_PROC_EXTRA, reinterpret_cast<const char*>(raw.first.get()));
240   }
241
242   int ret = AppRequest(PROC_REGISTER, getuid())
243       .With(b)
244       .SendSimply(AUL_SOCK_ASYNC);
245   if (ret < 0) {
246     _E("Failed to send request. name(%s), error(%d)", name, ret);
247     return ret;
248   }
249
250   context.SetFd(ret);
251   context.SetName(name);
252   if (extra)
253     context.SetExtra(tizen_base::Bundle(extra, true, true));
254
255   return AUL_R_OK;
256 }
257
258 extern "C" API int aul_proc_deregister(void) {
259   if (context.IsClosed()) {
260     _E("Invalid context");
261     return AUL_R_ERROR;
262   }
263
264   int ret = AppRequest(PROC_DEREGISTER, getuid())
265       .SendSimply(AUL_SOCK_NOREPLY);
266   if (ret < 0) {
267     _E("Failed to send request. error(%d)", ret);
268     return ret;
269   }
270
271   context.Close();
272   return AUL_R_OK;
273 }
274
275 extern "C" API int aul_proc_get_name(pid_t pid, char** name) {
276   if (pid < 1 || name == nullptr) {
277     _E("Invalid parameter");
278     return AUL_R_EINVAL;
279   }
280
281   if (pid == getpid() && !context.IsClosed() && !context.GetName().empty()) {
282     *name = strdup(context.GetName().c_str());
283     if (*name == nullptr) {
284       _E("strdup() is failed");
285       return AUL_R_ENOMEM;
286     }
287
288     return AUL_R_OK;
289   }
290
291   bundle* response;
292   int ret = SendAndReceive(PROC_GET_NAME, pid, getuid(), &response);
293   if (ret != AUL_R_OK)
294     return ret;
295
296   tizen_base::Bundle b(response, false, true);
297   std::string val = b.GetString(AUL_K_PROC_NAME);
298   if (val.empty()) {
299     _E("Failed to get name");
300     return AUL_R_ERROR;
301   }
302
303   *name = strdup(val.c_str());
304   if (*name == nullptr) {
305     _E("strdup() is failed");
306     return AUL_R_ENOMEM;
307   }
308
309   return AUL_R_OK;
310 }
311
312 extern "C" API int aul_proc_get_extra(pid_t pid, bundle** extra) {
313   if (pid < 1 || extra == nullptr) {
314     _E("Invalid parameter");
315     return AUL_R_EINVAL;
316   }
317
318   if (pid == getpid() && !context.IsClosed()) {
319     auto& extra_data = context.GetExtra();
320     *extra = bundle_dup(extra_data.GetHandle());
321     if (*extra == nullptr) {
322       _E("bundle_dup() is failed");
323       return AUL_R_ENOMEM;
324     }
325
326     return AUL_R_OK;
327   }
328
329   bundle* response;
330   int ret = SendAndReceive(PROC_GET_EXTRA, pid, getuid(), &response);
331   if (ret != AUL_R_OK)
332     return ret;
333
334   tizen_base::Bundle b(response, false, true);
335   std::string raw = b.GetString(AUL_K_PROC_EXTRA);
336   if (raw.empty()) {
337     _E("Failed to get extra");
338     return AUL_R_ERROR;
339   }
340
341   tizen_base::Bundle extra_data(raw);
342   *extra = extra_data.Detach();
343   return AUL_R_OK;
344 }