refinement of osp-appfw log messages
[platform/framework/native/appfw.git] / src / app / FApp_AppEntry.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /**
19  * @file        FApp_AppEntry.cpp
20  * @brief       This is the entry point for the application.
21  */
22
23 #include <cstdio>
24 #include <cstring>
25 #include <cstdlib>
26 #include <algorithm>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <dlfcn.h>
33 #include <limits.h>
34 #include <fcntl.h>
35 #include <sys/prctl.h>
36 #include <linux/capability.h>
37
38 #include <unique_ptr.h>
39
40 #include <dlog.h>
41 #include <privilege-control.h>
42 #include <pkgmgr-info.h>
43
44 #include <FOspConfig.h>
45
46
47 #define LOG_IO_TAG  "LOADER"
48 #define MAX_APPID   20
49 #define MAX_APP_EXECUTABLE_NAME 230
50 #define MAX_PACKAGE_NAME        100
51 #define MAX_PR_NAME     16
52
53
54 #ifdef __cplusplus
55 extern "C"
56 {
57 #endif // __cplusplus
58
59
60 extern int OspMain(int argc, char* pArgv[]) __attribute__((weak));
61 //extern void Osp_Initialize();
62 extern void InitAppInfo(const char* appId, const char* exeName, int argc, char* pArgv[], int fd);
63
64 static void
65 AdjustPrivilege(const char* pkgname)
66 {
67         void* handle = dlopen("libprivilege-control.so.0", RTLD_LAZY | RTLD_LOCAL);
68         if (!handle)
69         {
70                 fprintf(stderr, "Cannot open libprivilege-control.so.0\n");
71                 return;
72         }
73
74         char* msg = 0;
75         dlerror();
76
77         int (* ppriv_func)(const char*) = NULL;
78
79         ppriv_func = reinterpret_cast <int (*)(const char*)>(dlsym(handle, "set_privilege"));
80         msg = dlerror();
81         if (msg != NULL)
82         {
83                 fprintf(stderr, "Dlsym error: %s\n", msg);
84
85                 dlclose(handle);
86                 return;
87         }
88
89         int ret = (*ppriv_func)(pkgname);
90         if (ret < 0)
91         {
92                 fprintf(stderr, "set_privilege() returned %d\n", ret);
93         }
94
95         dlclose(handle);
96 }
97
98 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
99
100 static int
101 AdjustCapability(void)
102 {
103         cap_user_header_t   head = 0;
104         cap_user_data_t data = 0;
105
106         head = static_cast<cap_user_header_t>(malloc(sizeof(*head)));
107         if (head == NULL)
108         {
109                 fprintf(stderr, "Memory allocation failure.\n");
110                 return -1;
111         }
112
113         head->version = _LINUX_CAPABILITY_VERSION;
114         head->pid = getpid();
115
116         data = static_cast<cap_user_data_t>(calloc(sizeof(*data), _LINUX_CAPABILITY_U32S));
117         if (data == NULL)
118         {
119                 fprintf(stderr, "Memory allocation failure.\n");
120
121                 free(head);
122                 return -1;
123         }
124
125         data[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
126         data[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
127
128         if (capset(head, data) < 0)
129         {
130                 fprintf(stderr, "Capability setting error\n");
131
132                 free(data);
133                 free(head);
134                 return -1;
135         }
136
137         free(data);
138         free(head);
139
140         return 0;
141 }
142
143
144 static int
145 GetAppIdAppExecutableNameFromPathNew(const char appName[], char* appId, char* exeName)
146 {
147         char buffer[PATH_MAX];
148
149         // path is ".../[appid]/bin/[executable_name]"
150
151         memset(buffer, 0, PATH_MAX);
152         const char* pRet = realpath(appName, buffer);
153         if (pRet == NULL)
154         {
155                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, Improper appname %s", appName);
156                 return -1;
157         }
158
159         const char* p = strrchr(buffer, '/');
160         if (p == NULL)
161         {
162                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, Improper appname %s", appName);
163                 return -1;
164         }
165
166         const size_t pathLen = strlen(buffer);
167         const int execLen = strlen(p);
168         if (execLen <= 0 || execLen > PATH_MAX || pathLen > PATH_MAX)
169         {
170                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, Improper appname %s", appName);
171                 return -1;
172         }
173
174         strncpy(exeName, p + 1, execLen);
175         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, exeName is %s", exeName);
176
177         if (pathLen < 1 + 10 + strlen("/bin/") + execLen)
178         {
179                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, Improper appname %s", appName);
180                 return -1;
181         }
182
183         strncpy(appId, p - strlen("bin/") - 10, 10);
184         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, app is %s", appId);
185
186         return 0;
187 }
188
189 static int
190 GetAppIdAppExecutableNameFromPath(const char appName[], char* appId, char* exeName)
191 {
192         const char* begin = NULL;
193         const char* end = NULL;
194         const int path_len = strlen(appName);
195
196         // Calculate the header
197         const char* p = strstr(appName, "/apps/org.tizen.");
198         if (p == NULL)
199         {
200                 return GetAppIdAppExecutableNameFromPathNew(appName, appId, exeName);
201         }
202
203         begin = p + 15;
204
205         end = strchr(begin + 1, '/');
206         if (end == NULL)
207         {
208                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, Improper appname %s", appName);
209                 return -1;
210         }
211
212         int len = end - begin - 1;
213
214         if (len > MAX_APPID)
215         {
216                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, Improper appname %s with length %d", appName, len);
217                 len = MAX_APPID;
218                 //return -1;
219         }
220
221         strncpy(appId, begin + 1, len);
222         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, app is %s", appId);
223
224         int exe_len = 0;
225
226         if (path_len > len + 21)
227         {
228                 exe_len = std::min(MAX_APP_EXECUTABLE_NAME - 1, path_len - len - 21);
229                 strncpy(exeName, end + 5, exe_len);
230         }
231
232         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, exeName is %s", exeName);
233
234         return 0;
235 }
236
237 static bool
238 GetPackageNameFromAppIdAppExecutableName(const char appId[], const char exeName[], char* pkgName, int maxPkgName)
239 {
240         // package name is "org.tizen.[appid]#[executable]"
241
242         //snprintf(pkgName, maxPkgName, "org.tizen.%s#%s", appId, exeName);
243         snprintf(pkgName, maxPkgName, "%s", appId);
244
245         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::App, packageName is %s", pkgName);
246
247         return true;
248 }
249
250 static void
251 PrintArgs(int argc, char* argv[])
252 {
253         const char* p = NULL;
254         int i = 0;
255         do
256         {
257                 p = argv[i];
258                 LOG(LOG_DEBUG, LOG_IO_TAG, "%dth arg : [%s]", i, p);
259                 i++;
260         }
261         while (p);
262 }
263
264 static int
265 DoPreExec(const char* packageName, const char* bin_path)
266 {
267         void* handle = NULL;
268         char* errormsg = 0;
269         int (* DoPreExecFunc)(const char*, const char*) = NULL;
270         int ret = 0;
271
272         handle = dlopen("libosp-env-config.so", RTLD_LAZY | RTLD_GLOBAL);
273         if (!handle)
274         {
275                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io > Failed to dlopen libosp-env-config.so (%s)", dlerror());
276                 return -1;
277         }
278         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io > dlopen() ok");
279
280         DoPreExecFunc = reinterpret_cast <int (*)(const char*, const char*)>(dlsym(handle, "do_pre_exec"));
281         errormsg = dlerror();
282         if (errormsg != NULL)
283         {
284                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io > Failed to dlsym() (%s)", errormsg);
285                 dlclose(handle);
286                 return -1;
287         }
288         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io > dlsym() ok");
289
290         ret = DoPreExecFunc(packageName, bin_path);
291         if (ret < 0)
292         {
293                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io > Failed to do_pre_exe() (%d)", ret);
294         }
295         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io > do_pre_exe() ok");
296
297         dlclose(handle);
298
299         return 0;
300 }
301
302 static void
303 ChangeProcessName(const char* fullPath, int argc, char** const argv)
304 {
305         // http://stupefydeveloper.blogspot.com/2008/10/linux-change-process-name.html
306         // [INFO] While this implementation may not be portable, most program loader does similar work.
307
308         // fullPath should be less than original size
309         const int size = strlen(argv[0]);
310         char* args = argv[0];
311         memset(args, '\0', size);
312         strncpy(args, fullPath, size - 1);
313
314         const char* fileName = NULL;
315         fileName = strrchr(fullPath, '/') + 1;
316         if (fileName)
317         {
318                 char procName[MAX_PR_NAME];
319                 memset(procName, '\0', MAX_PR_NAME);
320
321                 snprintf(procName, MAX_PR_NAME - 1, "%s", fileName);
322                 prctl(PR_SET_NAME, procName);
323                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, %s, %d > Process name %s.", __func__, __LINE__, procName);
324         }
325 }
326
327 static int
328 GetDirFdFromPath(const char* pPath)
329 {
330         int count = 0;
331         const int len = strlen(pPath);
332         char dname[PATH_MAX];
333         memset(dname, 0, PATH_MAX);
334
335         const char* p = pPath + len;
336         for (int i = 0; i < len; i++, p--)
337         {
338                 if (*p == '/')
339                 {
340                         count++;
341
342                         if (count == 2)
343                         {
344                                 goto OUT;
345                         }
346                 }
347         }
348
349         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, %s, %d > Wrong path format : %s.", __func__, __LINE__, pPath);
350
351         return -1;
352
353 OUT:
354         strncpy(dname, pPath, p - pPath);
355
356         const int fd = open(dname, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
357
358         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::App, %s, %d > Directory path : %s, fd : %d.", __func__, __LINE__, dname, fd);
359
360         return fd;
361 }
362
363
364 static void
365 AdjustHwAccInfo(const char* packageId, const char* execName)
366 {
367         char appId[MAX_APPID + MAX_APP_EXECUTABLE_NAME + 2] = {0, };
368         strncpy(appId, packageId, 10);
369         appId[10] = '.';
370         strncpy(appId + 11, execName, MAX_APP_EXECUTABLE_NAME);
371
372         pkgmgrinfo_appinfo_h appHandle = NULL;
373         int ret = pkgmgrinfo_appinfo_get_appinfo(appId, &appHandle);
374         if (ret != PMINFO_R_OK)
375         {
376                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::App, %s, %d > Getting package info failed for %s.", __func__, __LINE__, appId);
377                 return;
378         }
379
380         pkgmgrinfo_app_hwacceleration hwAcceleration;
381
382         ret = pkgmgrinfo_appinfo_get_hwacceleration(appHandle, &hwAcceleration);
383         if (ret != PMINFO_R_OK)
384         {
385                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::App, %s, %d > Getting hwaccel info failed for %s.", __func__, __LINE__, appId);
386                 pkgmgrinfo_appinfo_destroy_appinfo(appHandle);
387         }
388
389         switch(hwAcceleration)
390         {
391         case PMINFO_HWACCELERATION_NOT_USE_GL:
392                 setenv("HWACC", "NOT_USE", 1);
393                 break;
394         case PMINFO_HWACCELERATION_USE_GL:
395                 setenv("HWACC", "USE", 1);
396                 break;
397         case PMINFO_HWACCELERATION_USE_SYSTEM_SETTING:
398                 break;
399         default:
400                 // no need to handle default
401                 break;
402         }
403
404         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::App, %s, %d > HWACC sets for %s with %d.", __func__, __LINE__, appId, hwAcceleration);
405         pkgmgrinfo_appinfo_destroy_appinfo(appHandle);
406 }
407
408
409 /**
410 * The entry function of SLP application called by the operating system.
411 */
412 int _OSP_EXPORT_
413 main(int argc, char* pArgv[])
414 {
415         bool bCommand = false;
416
417         char appId[MAX_APPID];
418         char exeName[MAX_APP_EXECUTABLE_NAME];
419         char packageName[MAX_PACKAGE_NAME];
420         char fullPath[PATH_MAX];
421
422         memset(appId, 0, MAX_APPID);
423         memset(exeName, 0, MAX_APP_EXECUTABLE_NAME);
424         memset(packageName, 0, MAX_PACKAGE_NAME);
425         memset(fullPath, 0, PATH_MAX);
426
427         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, %s, %d > executable binary path: %s", __func__, __LINE__, pArgv[0]);
428         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, %s, %d > uid: %d, euid: %d", __func__, __LINE__, getuid(), geteuid());
429
430         const int len = strlen(pArgv[0]);
431         bCommand = (len > 4 && (strncmp(pArgv[0] + len - 4, ".exe", 4) == 0));
432         if (bCommand)
433         {
434                 const int path_size = std::min(PATH_MAX - 1, len - 4);
435                 strncpy(fullPath, pArgv[0], path_size);
436         }
437         else
438         {
439                 strncpy(fullPath, pArgv[0], PATH_MAX - 1);
440         }
441         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, %s, %d > processed binary path: %s", __func__, __LINE__, fullPath);
442
443         // convert package path to appId
444         GetAppIdAppExecutableNameFromPath(fullPath, appId, exeName);
445         GetPackageNameFromAppIdAppExecutableName(appId, exeName, packageName, MAX_PACKAGE_NAME);
446
447         if (getuid() == 0)
448         {
449                 // self caging
450                 DoPreExec(packageName, fullPath);
451
452                 // adjust privilege
453                 AdjustPrivilege(packageName);
454         }
455
456         AdjustCapability();
457
458         PrintArgs(argc, pArgv);
459
460         if (bCommand)
461         {
462                 ChangeProcessName(fullPath, argc, pArgv);
463                 pArgv[0] = strdup(fullPath);
464         }
465
466         int fd = GetDirFdFromPath(pArgv[0]);
467         if (fd == -1)
468         {
469                 LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, %s, %d > Failed to open path [%d][%s].", __func__, __LINE__, getpid(), strerror(errno));
470                 return -1;
471         }
472
473         // dlopen will load Osp_Initialize() internally as __attribute__((constructor))
474         //Osp_Initialize();
475         InitAppInfo(appId, exeName, argc, pArgv, fd);
476
477         AdjustHwAccInfo(appId, exeName);
478
479         int r = OspMain(argc, pArgv);
480
481         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, %s, %d > OSP application is terminated.", __func__, __LINE__);
482         LOG(LOG_DEBUG, LOG_IO_TAG, "Tizen::Io, %s, %d > uid: %d, euid: %d", __func__, __LINE__, getuid(), geteuid());
483
484         return r;
485 }
486
487 #ifdef __cplusplus
488 }
489 #endif // __cplusplus