refined boot logic
[platform/framework/native/appfw.git] / src / app / FApp_AppInfo.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_AppInfo.cpp
19  * @brief       This is the implementation for the _AppInfo.cpp class.
20  */
21
22 #include <cstdio>
23 #include <cstring>
24 #include <unistd.h>
25 #include <limits.h>
26 #include <new>
27 #include <fcntl.h>
28
29 #include <appinfo.h>
30
31 #include <FBaseErrors.h>
32 #include <FAppPkgPackageInfo.h>
33 #include <FBaseSysLog.h>
34
35 #include <FBaseRt_Process.h>
36 #include <FBase_StringConverter.h>
37
38 #include "FAppPkg_PackageInfoImpl.h"
39 #include "FApp_AppInfo.h"
40
41 using namespace Tizen::App::Package;
42 using namespace Tizen::Base;
43 using namespace Tizen::Base::Runtime;
44
45 extern "C"
46 {
47 void _OSP_EXPORT_
48 InitAppInfo(const char* packageId, const char* svcId, int argc, char* pArgv[], int fd)
49 {
50         result r = Tizen::App::_AppInfo::GetAppInfo()->Construct(packageId, svcId, argc, pArgv);
51         if (IsFailed(r))
52         {
53                 SysLogException(NID_APP, E_SYSTEM, "Application initialization failure for %s.", packageId);
54                 fprintf(stderr, "Application initialization failure for %s.\n", packageId);
55
56                 _Process::Exit(-1);
57         }
58 }
59
60 void _OSP_EXPORT_
61 InitWebAppInfo(const char* appId, const char* rootPath)
62 {
63         result r = Tizen::App::_AppInfo::GetAppInfo()->Construct(appId, rootPath, Tizen::App::_APP_TYPE_WEB_APP);
64         if (IsFailed(r))
65         {
66                 SysLogException(NID_APP, E_SYSTEM, "Application initialization failure for %s.", appId);
67                 fprintf(stderr, "Application initialization failure for %s.\n", appId);
68
69                 _Process::Exit(-1);
70         }
71 }
72
73 extern void FBase_Initialize(void);
74
75 }
76
77 namespace Tizen { namespace App
78 {
79
80 const int MAX_APIVERSION = 8;
81 const int MAX_APPID = 10;
82 const char PACKAGE_PATH_FORMAT[] = "/opt/usr/apps/0000000000/";
83 const char PATH_ROOT[] = "/opt/usr/apps/";
84 const char APPINFO_FILE_PATH[] = "info/version.info";
85 const char COMPAT_FILE_PATH[] = "info/compat.info";
86 const char VIRTUAL_ROOT_FILE_PATH[] = "info/virtual.info";
87 const char TYPE_FILE_PATH[] = "info/type.info";
88
89
90 _AppInfo::_AppInfo(void)
91         : __appState(TERMINATED)
92         , __appType(_APP_TYPE_NONE)
93         , __appRootDirFd(-1)
94         , __appHandlerType(_APP_HANDLER_NONE)
95         , __parentWindowHandle(-1)
96         , __pAppName(null)
97         , __pAppVersion(null)
98         , __isPackageInfoInitialized(false)
99         , __isSubMode(false)
100         , __isVirtualRoot(false)
101 {
102         SysStaticAssert(sizeof(pid_t) == sizeof(int));
103
104         //FBase_Initialize();
105 }
106
107 _AppInfo::~_AppInfo(void)
108 {
109         delete __pAppName;
110         delete __pAppVersion;
111
112         // closing may or may not succeed
113         close(__appRootDirFd);
114 }
115
116 _AppInfo*
117 _AppInfo::GetAppInfo(void)
118 {
119         static _AppInfo info;
120
121         return &info;
122 }
123
124
125 result
126 _AppInfo::Construct(void)
127 {
128         SysAssertf(appinfo_is_initialized() == 1, "appinfo is not initialized.");
129
130         FBase_Initialize();
131
132         return E_SUCCESS;
133 }
134
135
136 result
137 _AppInfo::Construct(const char* packageId, const char* exeName, int argc, char* argv[])
138 {
139         SysAssertf(packageId != null, "Valid appId required to launch application.");
140         SysAssertf(appinfo_is_initialized() == 1, "appinfo is not initialized.");
141
142         FBase_Initialize();
143
144         __appExecutableName = exeName;
145         __packageId = packageId;
146
147         if (__appExecutableName == L"_AppControl")
148         {
149                 SysLog(NID_APP, "Handling for submode.");
150                 const String& name = _PackageManagerImpl::GetInstance()->GetDefaultAppExecutableName(__packageId);
151
152                 __isSubMode = true;
153                 __appExecutableName = name;
154
155                 std::unique_ptr<char[]> pActualExec(_StringConverter::CopyToCharArrayN(name));
156                 appinfo_update_submode_execname_and_appid(pActualExec.get());
157                 SysLog(NID_APP, "Executable name is changed to %s.", pActualExec.get());
158         }
159
160         __appId = __packageId + L'.' + __appExecutableName;
161
162         result r = E_SUCCESS;
163         FILE* pFile = NULL;
164
165         {
166                 char appInfoPath[PATH_MAX] = {0, };
167
168                 int len = strlen(PACKAGE_PATH_FORMAT);
169                 strncpy(appInfoPath, PACKAGE_PATH_FORMAT, len);
170                 appInfoPath[len] = '\0';
171                 strncpy(appInfoPath + strlen(PATH_ROOT), packageId, MAX_APPID);
172
173                 // app root directory file descriptor
174                 __appRootDirFd = open(appInfoPath, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
175                 __appRootPath = appInfoPath;
176                 
177                 SysLog(NID_APP, "App root directory (%s:%d) open.", appInfoPath, __appRootDirFd);
178
179                 int fd = openat(__appRootDirFd, APPINFO_FILE_PATH, O_RDONLY);
180                 SysAssertf(fd != -1, "Failed to open info file, errno: %d (%s)", errno, strerror(errno));
181
182                 pFile = fdopen(fd, "r");
183                 SysTryCatch(NID_APP, pFile != NULL, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Opening appinfo file (%s) failed : %s.", appInfoPath, strerror(errno));
184
185                 char apiVersion[MAX_APIVERSION] = {0, };
186                 char* pRet = fgets(apiVersion, MAX_APIVERSION - 1, pFile);
187                 SysTryCatch(NID_APP, pRet != NULL, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Reading appinfo file (%s) failed : %s.", appInfoPath, strerror(errno));
188
189                 fclose(pFile);
190                 // fd is closed when the stream is closed by fclose();
191
192                 appinfo_set_api_version(appinfo_get_api_version_from_str(apiVersion));
193
194                 // to reduce package manager overhead, libc API is used
195                 if (faccessat(__appRootDirFd, COMPAT_FILE_PATH, F_OK, 0) == 0)
196                 {
197                         SysLog(NID_APP, "OSP compatibility mode on.");
198                         appinfo_set_compat(1);
199                 }
200
201                 if (faccessat(__appRootDirFd, VIRTUAL_ROOT_FILE_PATH, F_OK, 0) == 0)
202                 {
203                         SysLog(NID_APP, "virtual root mode on.");
204                         __isVirtualRoot = true;
205                 }
206
207                 // type file may does not exist
208                 fd = openat(__appRootDirFd, TYPE_FILE_PATH, O_RDONLY);
209                 if (fd > 0)
210                 {
211                         pFile = fdopen(fd, "r");
212                         if (pFile)
213                         {
214                                 int i;
215                                 int line = fscanf(pFile, "%d", &i);
216
217                                 fclose(pFile);
218                                 // fd is closed when the stream is closed by fclose();
219
220                                 __appType = _APP_TYPE_UI_APP | i;
221                                 SysLog(NID_APP, "Reading app type %d -> %d", i, __appType);
222                         }
223                 }
224
225                 SysLog(NID_APP, "New appinfo [%s][%s.%s].", appinfo_get_appid(), appinfo_get_packageid(), appinfo_get_execname());
226                 SysLog(NID_APP, "AppInfo initialization finished [%ls][%ls.%ls][%d].",
227                                 __appId.GetPointer(), __packageId.GetPointer(), __appExecutableName.GetPointer(), appinfo_get_api_version());
228         }
229
230         return E_SUCCESS;
231
232 CATCH:
233         __appId.Clear();
234         __appExecutableName.Clear();
235
236         delete __pAppName;
237         __pAppName = null;
238
239         delete __pAppVersion;
240         __pAppVersion = null;
241
242         if (pFile != NULL)
243         {
244                 fclose(pFile);
245         }
246
247         return r;
248 }
249
250
251 // initialize app context only
252 result
253 _AppInfo::Construct(const char* appId, const char* appRoot, _AppType type)
254 {
255         SysAssertf(appId != null, "Valid appId required to launch application.");
256
257         FBase_Initialize();
258
259         __appId = appId;
260
261         int index = 0;
262         if (__appId.LastIndexOf(L'.', __appId.GetLength() - 1, index) == E_SUCCESS)
263         {
264                 __appId.SubString(index + 1, __appExecutableName);
265                 __appId.SubString(0, index, __packageId);
266         }
267         else
268         {
269                 __appExecutableName = __appId;
270                 __packageId = __appId;
271         }
272
273         __appRootDirFd = open(appRoot, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
274         appinfo_set_api_version(APP_INFO_VERSION_2_2);
275         __appType = type;
276
277         __appRootPath = appRoot;
278         if (__appRootPath[__appRootPath.GetLength()] != L'/')
279         {
280                 __appRootPath.Append(L'/');
281         }
282
283         SysLog(NID_APP, "AppInfo initialization finished [%ls][%ls.%ls][%ls][%d].", __appId.GetPointer(), __packageId.GetPointer(), __appExecutableName.GetPointer(), __appRootPath.GetPointer(),  appinfo_get_api_version());
284
285         return E_SUCCESS;
286 }
287
288
289 result
290 _AppInfo::UpdateAppInfoFromPackageInfo(const PackageId& packageId)
291 {
292         _PackageManagerImpl* pPkg = null;
293         pPkg = _PackageManagerImpl::GetInstance();
294         SysTryReturnResult(NID_APP, pPkg != null, E_INVALID_STATE, "Invalid PackageManager instance.");
295
296         result r = E_SUCCESS;
297         PackageInfo* pInfo = null;
298         pInfo = pPkg->GetPackageInfoN(packageId);
299         SysTryReturn(NID_APP, pInfo != null, r, r, "[%s] Propagating.", GetErrorMessage(r));
300
301         const _PackageInfoImpl* pPkgInfo = _PackageInfoImpl::GetInstance(pInfo);
302         SysTryReturnResult(NID_APP, pPkgInfo != null, E_INVALID_STATE, "Invalid PackageInfo instance.");
303
304         delete __pAppName;
305         __pAppName = new (std::nothrow) String(pPkgInfo->GetName());
306         SysTryCatch(NID_APP, __pAppName != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] AppName allocation failure.");
307
308         delete __pAppVersion;
309         __pAppVersion = new (std::nothrow) String(pPkgInfo->GetVersion());
310         SysTryCatch(NID_APP, __pAppVersion != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] AppVersion allocation failure.");
311
312         __isPackageInfoInitialized = true;
313
314         delete pInfo;
315
316         SysLog(NID_APP, "AppInfo updated [%ls][%ls].", __pAppName->GetPointer(), __pAppVersion->GetPointer());
317
318         return r;
319
320 CATCH:
321         delete pInfo;
322
323         delete __pAppName;
324         __pAppName = null;
325
326         delete __pAppVersion;
327         __pAppVersion = null;
328
329         return r;
330 }
331
332
333 _ApiVersion
334 _AppInfo::GetApiVersion(void)
335 {
336         return static_cast<_ApiVersion>(appinfo_get_api_version());
337 }
338
339
340 bool
341 _AppInfo::IsOspCompat(void)
342 {
343         return (appinfo_is_compat() == 1);
344 }
345
346 bool
347 _AppInfo::IsVirtualRoot(void)
348 {
349         return GetAppInfo()->__isVirtualRoot;
350 }
351
352 result
353 _AppInfo::SetApiVersion(_ApiVersion v)
354 {
355         appinfo_set_api_version(static_cast<app_info_version_e>(v));
356         return E_SUCCESS;
357 }
358
359
360 int
361 _AppInfo::GetProcessId(void)
362 {
363         static int processId = static_cast<int>(getpid());
364
365         return processId;
366 }
367
368 int
369 _AppInfo::GetAppRootDirFd(void)
370 {
371         return GetAppInfo()->__appRootDirFd;
372 }
373
374
375 AppId
376 _AppInfo::GetApplicationId(void)
377 {
378         const String& appId = GetAppInfo()->__appId;
379
380         SysAssertf(!appId.IsEmpty(), "AppId is not initialized properly.");
381
382         return appId;
383 }
384
385
386 PackageId
387 _AppInfo::GetPackageId(void)
388 {
389         const String& packageId = GetAppInfo()->__packageId;
390
391         SysAssertf(!packageId.IsEmpty(), "PackageId is not initialized properly.");
392
393         return packageId;
394 }
395
396
397 String
398 _AppInfo::GetAppExecutableName(void)
399 {
400         return GetAppInfo()->__appExecutableName;
401 }
402
403
404 bool
405 _AppInfo::IsSubMode(void)
406 {
407         return GetAppInfo()->__isSubMode;
408 }
409
410
411 String
412 _AppInfo::GetAppName(void)
413 {
414         if (!GetAppInfo()->__isPackageInfoInitialized)
415         {
416                 const String& packageId = GetAppInfo()->__packageId;
417
418                 SysAssertf(!packageId.IsEmpty(), "PackageId is not initialized properly.");
419
420                 result r = GetAppInfo()->UpdateAppInfoFromPackageInfo(packageId);
421                 SysAssertf(r == E_SUCCESS, "AppInfo update failure due to package problem.");
422         }
423
424         return *(GetAppInfo()->__pAppName);
425 }
426
427
428 String
429 _AppInfo::GetAppRootPath(void)
430 {
431         return GetAppInfo()->__appRootPath;
432 }
433
434 String
435 _AppInfo::GetAppVersion(void)
436 {
437         if (!GetAppInfo()->__isPackageInfoInitialized)
438         {
439                 const String& packageId = GetAppInfo()->__packageId;
440
441                 SysAssertf(!packageId.IsEmpty(), "PackageId is not initialized properly.");
442
443                 result r = GetAppInfo()->UpdateAppInfoFromPackageInfo(packageId);
444                 SysAssertf(r == E_SUCCESS, "AppInfo update failure due to package problem.");
445         }
446
447         return *(GetAppInfo()->__pAppVersion);
448 }
449
450
451 AppState
452 _AppInfo::GetAppState(void)
453 {
454         return GetAppInfo()->__appState;
455 }
456
457
458 void
459 _AppInfo::SetAppState(AppState appState)
460 {
461         GetAppInfo()->__appState = appState;
462 }
463
464
465 int
466 _AppInfo::GetAppType(void)
467 {
468         return GetAppInfo()->__appType;
469 }
470
471
472 void
473 _AppInfo::SetAppType(_AppType appType)
474 {
475         GetAppInfo()->__appType |= appType;
476 }
477
478
479 int
480 _AppInfo::GetAppHandlerType(void)
481 {
482         return GetAppInfo()->__appHandlerType;
483 }
484
485
486 void
487 _AppInfo::SetAppHandlerType(int appHandlerType)
488 {
489         GetAppInfo()->__appHandlerType = appHandlerType;
490 }
491
492
493 unsigned int
494 _AppInfo::GetParentWindowHandle(void)
495 {
496         return GetAppInfo()->__parentWindowHandle;
497 }
498
499
500 void
501 _AppInfo::SetParentWindowHandle(unsigned int handle)
502 {
503         GetAppInfo()->__parentWindowHandle = handle;
504 }
505
506
507 void
508 _AppInfo::UpdatePackageInfo(bool update)
509 {
510         GetAppInfo()->__isPackageInfoInitialized = !update;
511 }
512
513 }} // Tizen::App