Tizen 2.1 base
[platform/framework/native/app-service.git] / src / FApp_ContextManager.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_ContextManager.cpp
20  * @brief       This is the implementation for the _ContextManager.cpp class.
21  */
22
23 #include <cstdio>
24 #include <cerrno>
25 #include <dlfcn.h>
26 #include <string>
27
28 #include <FBaseColArrayList.h>
29 #include <FBaseSysLog.h>
30 #include <FIoFile.h>
31
32 #include <FBase_StringConverter.h>
33 #include <FApp_Aul.h>
34 #include <FApp_AppManagerImpl.h>
35 #include <FAppPkg_PackageManagerImpl.h>
36
37 #include "FApp_ContextManager.h"
38 #include "FIo_MmcStorageManagerService.h"
39
40 using namespace Tizen::Base;
41 using namespace Tizen::Base::Collection;
42 using namespace Tizen::Io;
43
44 namespace Tizen { namespace App {
45
46 const unsigned long CONTEXT_MANAGER_MAGIC = 0x585443;   // 'C' 'T' 'X'
47
48 ///////////////////////////////////////////////////
49 // _AppContext
50 ///////////////////////////////////////////////////
51 _AppContext::_AppContext(const String& appId, const String& executableName, _AppType appType, int pid, int ipcClientId, bool isSystemService)
52 : appId(appId)
53 , executableName(executableName)
54 , appType(appType)
55 , pId(pid)
56 , ipcClientId(ipcClientId)
57 , uiState(APP_UI_STATE_BACKGROUND)
58 , isRegistered(true)
59 , isSystemService(isSystemService)
60 {
61 }
62
63 String
64 _AppContext::ToString(void) const
65 {
66         Tizen::Base::String ret;
67         ret.Format(1024, L"%ls.%ls(pid:%d)", appId.GetPointer(), executableName.GetPointer(), pId);
68         return ret;
69 }
70
71
72 ///////////////////////////////////////////////////
73 // _ContextManager
74 ///////////////////////////////////////////////////
75 _ContextManager::_ContextManager()
76         : __magic(CONTEXT_MANAGER_MAGIC)
77         , __pEventListener(null)
78 {
79         //
80 }
81
82 _ContextManager::~_ContextManager()
83 {
84 }
85
86 result
87 _ContextManager::Construct(void)
88 {
89         result r = E_SUCCESS;
90         __errorProneAppIds.Construct();
91         _Aul::SetOnAppTerminatedCb(OnAppTerminate, this);
92
93         return r;
94 }
95
96 void
97 _ContextManager::SetEventListener(_IContextManagerEventListener& listener)
98 {
99         __pEventListener = &listener;
100 }
101
102 result
103 _ContextManager::Register(const PackageId& pkgId, const String& executableName, _AppType appType, int pid, int ipcClientId, bool isSystemService )
104 {
105         if( __appContexts[pid] != null)
106         {
107                 SysAssertf( isSystemService == true, "The application (appid:%ls, pid:%d) is registered twice.", pkgId.GetPointer(), pid);
108                 return E_SUCCESS;
109         }
110
111         _AppContext* pAppContext = new (std::nothrow) _AppContext(pkgId, executableName, appType, pid, ipcClientId, isSystemService);
112
113         __appContexts[pid] = pAppContext;
114
115         String appRoot(L"/opt/usr/apps/");
116         appRoot.Append(pkgId);
117         String compatFile(appRoot);
118         compatFile.Append(L"/info/compat.info");
119
120         bool ospCompat = File::IsFileExist(compatFile);
121         if (GetLastResult() == E_SUCCESS && ospCompat == true)
122         {
123                 _MmcStorageManagerService* pMmcMgr = _MmcStorageManagerService::GetInstance();
124                 String* pAppRoot = new (std::nothrow) String(appRoot);
125
126                 int index = 0;
127                 result r = appRoot.LastIndexOf(L'/', appRoot.GetLength() - 1, index);
128                 SysTryLog(NID_IO, !IsFailed(r), "[E_SYSTEM] The method cannot proceed due to a severe system error.");
129
130                 String pkgId;
131                 r = appRoot.SubString(++index, pkgId);
132                 SysTryLog(NID_IO, !IsFailed(r), "[E_SYSTEM] The method cannot proceed due to a severe system error.");
133
134                 //pMmcMgr->__appList[pid] = pAppRoot;
135                 char* pKey = _StringConverter::CopyToCharArrayN(pkgId);
136                 std::string key(pKey);
137                 delete[] pKey;
138                 pMmcMgr->__appList.insert(_MmcStorageManagerService::_AppListPair(key, pAppRoot));
139                 SysLog(NID_APP, "OSP compatible application (%ls) is registered.", pkgId.GetPointer());
140         }
141
142         // ==== set oom policy for ServiceApp
143         result r = E_SUCCESS;
144         switch (GetOomAppType(pkgId, pid))
145         {
146         case OOM_APP_TYPE_SYSTEM:
147                 break;
148         case OOM_APP_TYPE_LAUNCHING:
149                 break;
150         case OOM_APP_TYPE_FOREGROUND_HIGH:
151                 break;
152         case OOM_APP_TYPE_SERVICE_HIGH:
153                 break;
154         case OOM_APP_TYPE_FOREGROUND:
155                 break;
156         case OOM_APP_TYPE_SERVICE_MID:
157                 r = _Aul::SetOomAdj(pid, -7);
158                 break;
159         case OOM_APP_TYPE_BACKGROUND_HIGH:
160                 break;
161         case OOM_APP_TYPE_SERVICE_LOW:
162                 r = _Aul::SetOomAdj(pid, -3);
163                 break;
164         case OOM_APP_TYPE_BACKGROUND:
165                 break;
166         }
167         SysLog(NID_APP, "Set OOM : result is %s", GetErrorMessage(r));
168
169         SysLog(NID_APP, "The %s (appid:%ls, pid:%d) Registered.", isSystemService ? "application":"system service", pkgId.GetPointer(), pid);
170         Dump();
171         return E_SUCCESS;
172 }
173
174 // see also     OnAppTerminate
175 result
176 _ContextManager::Unregister(int pid)
177 {
178         _AppContext* pAppContext = __appContexts[pid];
179         SysTryReturn(NID_APP, pAppContext != null, E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND, "Unknown pid(%d).", pid);
180
181         pAppContext->isRegistered = false;
182         SysLog(NID_APP, "(appid:%ls, pid:%d) Unregistered.", pAppContext->appId.GetPointer(), pid);
183
184 #if 0
185         _MmcStorageManagerService* pMmcMgr = _MmcStorageManagerService::GetInstance();
186         String* pAppRoot = pMmcMgr->__appList[pid];
187         if (pAppRoot != null)
188         {
189                 pMmcMgr->__appList.erase(pid);
190                 SysLog(NID_APP, "OSP 2.0 application is unregistered.");
191         }
192 #endif
193
194         return E_SUCCESS;
195 }
196
197 // event handler for _Aul::SetOnAppTerminatedCb
198 int
199 _ContextManager::OnAppTerminate(int pid, void *pData)
200 {
201         SysTryReturn(NID_APP, pData != null, -1, E_INVALID_STATE, "");
202
203         _ContextManager* pContextMgr = static_cast<_ContextManager*>(pData);
204         SysTryReturn(NID_APP, pContextMgr->__magic == CONTEXT_MANAGER_MAGIC, -1, E_INVALID_STATE, "Wrong magic number %x(%x)", pContextMgr->__magic, CONTEXT_MANAGER_MAGIC);
205
206         _AppContext* pAppContext = pContextMgr->__appContexts[pid];
207
208         if ( pAppContext == null)
209         {
210 //              SysLog(NID_APP, "Not registered pid(%d), It means this process isn't osp app.", pid);
211                 return 0;
212         }
213
214         if (pAppContext->isRegistered)
215         {
216                 SysLog(NID_APP, "This app is terminated abnormally.");
217                 pContextMgr->AbonormalAppTerminationHanlder( pAppContext->pId, pAppContext->appId, pAppContext->executableName );
218         }
219
220         if (pContextMgr->__pEventListener != null )
221         {
222                 pContextMgr->__pEventListener->OnApplicationTerminated(*pAppContext);
223         }
224
225         int res = pContextMgr->__appContexts.erase(pid);
226         SysTryCatch(NID_APP, res == 1, , E_INVALID_STATE, "[E_INVALID_STATE] __appContexts.erase(%d) returns (%d). It seems to be invalid.", pid, res);
227
228         SysLog(NID_APP, "app info is removed (%ls, %d)", pAppContext->executableName.GetPointer(), pid);
229
230         pContextMgr->Dump();
231
232 CATCH:
233         delete pAppContext;
234         return 0;
235 }
236
237 void
238 _ContextManager::AbonormalAppTerminationHanlder(int pid, const AppId& appId, const String& execName)
239 {
240         this->Unregister(pid);
241
242         const String& needToAutoRestartOnFailure = _Util::QueryFeatureFromPackageManager(appId, execName, L"AutoRestart");
243         if (needToAutoRestartOnFailure == "True")
244         {
245                 if(!IsErrorProneApp(appId))// prevent error prone app being restarted over and over again..
246                 {
247                         SysLog(NID_APP, "The app is configured as AutoRestart, so It will be restarted.");
248
249                         __errorProneAppIds.Add(appId);
250
251                         String realId = appId + L'.' + execName;
252                         _AppManagerImpl::GetInstance()->LaunchApplication(realId, null, AppManager::LAUNCH_OPTION_DEFAULT);
253
254                 }
255                 else
256                 {
257                         SysLog(NID_APP, "The app is configured as AutoRestart, but It won't be restarted. because it was already restarted, and terminated unexpectedly again. ");
258                 }
259         }
260 }
261
262 bool
263 _ContextManager::IsErrorProneApp(const AppId& appId) const
264 {
265         const int count = __errorProneAppIds.GetCount();
266         String errorProneAppId;
267
268         for (int i = 0; i < count; i ++)
269         {
270                 __errorProneAppIds.GetAt(i, errorProneAppId);
271                 if(errorProneAppId == appId)
272                 {
273                         return true;
274                 }
275         }
276         return false;
277 }
278
279
280 const _AppContext*
281 _ContextManager::Find(const AppId& appId, const Tizen::Base::String& executableName) const
282 {
283         AppContexts::const_iterator it;
284
285         for (it = __appContexts.begin(); it != __appContexts.end(); it++)
286         {
287                 const _AppContext* const pAppContext = (*it).second;
288
289                 if (pAppContext != null && pAppContext->appId == appId && pAppContext->executableName == executableName)
290                 {
291                         return pAppContext;
292                 }
293         }
294
295         return null;
296 }
297
298 const _AppContext*
299 _ContextManager::Find(int pid)
300 {
301         return __appContexts[pid];
302 }
303
304 result
305 _ContextManager::GetAppListN(Tizen::Base::Collection::ArrayList* pArray) const
306 {
307         AppContexts::const_iterator it;
308         String logText;
309
310         for (it = __appContexts.begin(); it != __appContexts.end(); it++)
311         {
312                 const _AppContext* const pAppContext = (*it).second;
313
314                 if (pAppContext != null)
315                 {
316                         if ( pArray != null)
317                         {
318                                 pArray->Add(pAppContext->appId);
319                         }
320
321                         logText.Append(pAppContext->appId);
322                         logText.Append(L", ");
323                 }
324         }
325         SysLog(NID_APP, "Total %d apps : %ls", __appContexts.size(), logText.GetPointer() );
326
327         return E_SUCCESS;
328 }
329
330 _OomAppType
331 _ContextManager::GetOomAppType(const AppId& appId, const int pid) const
332 {
333         _OomAppType appType = OOM_APP_TYPE_FOREGROUND;
334
335         // FIX_ME : will be implemented for type checking
336
337         return appType;
338 }
339
340 void
341 _ContextManager::Dump(void) const
342 {
343         AppContexts::const_iterator it;
344
345         SysLog(NID_APP, "registered app count : %d", __appContexts.size());
346
347         for (it = __appContexts.begin(); it != __appContexts.end(); it++)
348         {
349                 const _AppContext* const pAppContext = (*it).second;
350                 if (pAppContext != null)
351                 {
352                         SysLog(NID_APP, "%ls", pAppContext->ToString().GetPointer());
353                 }
354         }
355 }
356
357
358
359 /*
360  * _ContextManager::Util
361  */
362
363 /*String
364 _ContextManager::_Util::GetExecNameFromPackageName(const String& packageName)
365 {
366         String execName;
367         const String prefix(L"org.tizen.1234567890");
368         const int prefixLen = prefix.GetLength();
369         packageName.SubString(prefixLen, execName);
370
371         return execName;
372 }*/
373
374 String
375 _ContextManager::_Util::QueryFeatureFromPackageManager(const String& appId, const String& execName, const String& feature)
376 {
377         ArrayList* pFeatureList = Tizen::App::Package::_PackageManagerImpl::GetInstance()->GetPackageAppFeatureListN(appId, execName);
378         SysTryReturn(NID_APP, pFeatureList != null, L"", E_SYSTEM, "Cannot acquire feature list.");
379
380         String ret = L"";
381
382         for (int i = 0; i < pFeatureList->GetCount(); i++)
383         {
384                 const Tizen::App::Package::_AppFeatureInfoImpl* pInfo = static_cast<const Tizen::App::Package::_AppFeatureInfoImpl*>(pFeatureList->GetAt(i));
385                 SysLog(NID_APP, "%ls, %ls", pInfo->GetName().GetPointer(), pInfo->GetValue().GetPointer());
386                 if (pInfo != null && pInfo->GetName() == feature)
387                 {
388                         ret = pInfo->GetValue();
389                         break;
390                 }
391         }
392
393         pFeatureList->RemoveAll(true);
394         delete pFeatureList;
395
396         return ret;
397 }
398
399 } } // Tizen::App
400