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