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