Merge branch 'tizen_2.1' of ssh://tizendev.org:29418/framework/osp/appfw into tizen_2.1
[platform/framework/native/appfw.git] / src / app / FApp_AppControlManager.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_AppControlManager.cpp
19  * @brief       This is the implementation for the _AppControlManager class.
20  */
21
22 #include <stdint.h>
23 #include <cstdio>
24 #include <unique_ptr.h>
25
26 #include <appsvc/appsvc.h>
27 #include <aul/aul.h>
28 #include <bundle.h>
29 #include <content/mime_type.h>
30
31 #include <FBaseInteger.h>
32 #include <FBaseObject.h>
33 #include <FBaseString.h>
34 #include <FBaseColIListT.h>
35 #include <FBaseColArrayList.h>
36 #include <FBaseErrors.h>
37 #include <FAppAppControl.h>
38 #include <FAppAppManager.h>
39 #include <FAppIAppControlListener.h>
40 #include <FAppIAppControlResponseListener.h>
41 #include <FAppIAppFrame.h>
42 #include <FAppSqlDataControl.h>
43 #include <FAppMapDataControl.h>
44 #include <FAppPkgPackageInfo.h>
45
46 #include <FBaseSysLog.h>
47 #include <FBase_StringConverter.h>
48 #include <FBaseRt_LibraryImpl.h>
49 #include <FIo_DataControlResultSetImpl.h>
50
51 #include "FApp_AppArg.h"
52 #include "FApp_AppControlEventArg.h"
53 #include "FApp_AppControlRegistry.h"
54 #include "FApp_AppControlImpl.h"
55 #include "FApp_AppImpl.h"
56 #include "FApp_AppInfo.h"
57 #include "FApp_AppManagerEventArg.h"
58 #include "FApp_Aul.h"
59 #include "FApp_AppControlManager.h"
60 #include "FApp_AppManagerProxy.h"
61 #include "FApp_ConditionManagerProxy.h"
62 #include "FApp_IAppManagerEventListener.h"
63 #include "FApp_MapDataControlImpl.h"
64 #include "FApp_SqlDataControlImpl.h"
65 #include "FAppPkg_PackageManagerImpl.h"
66 #include "FAppPkg_PackageInfoImpl.h"
67 #include "FApp_AppMessageImpl.h"
68 #include "FApp_AppManagerImpl.h"
69 #include "FApp_AppControlResponseEvent.h"
70
71 using namespace Tizen::App::Package;
72 using namespace Tizen::Base;
73 using namespace Tizen::Base::Collection;
74 using namespace Tizen::Base::Runtime;
75 using namespace Tizen::Base::Utility;
76 using namespace Tizen::Io;
77
78 namespace Tizen { namespace App
79 {
80
81 const wchar_t TIZEN_OPERATION_PICK[] = L"http://tizen.org/appcontrol/operation/pick";
82 const wchar_t SELECTOR_NOTI_KEY[] = L"__APP_SVC_CALLER_NOTI__";
83 const int _MAX_PACKAGE_ID_LENGTH = 10;
84
85 _InProcessInfo::~_InProcessInfo(void)
86 {
87         delete pLib;
88 }
89
90 _LaunchInfo::~_LaunchInfo(void)
91 {
92         delete pArg;
93 }
94
95
96 _AppControlManager::_AppControlManager(void)
97 {
98         SysLog(NID_APP, "");
99
100         // AppControl event handling is expected to be performed in the main thread.
101         __appControlEvent.Construct();
102         __appControlEvent.AddListener(*dynamic_cast<_IAppControlSysEventListener*>(this));
103         __listenerList.Construct();
104         __pAppControlResponseEventContainer = new (std::nothrow)HashMapT<int, _AppControlResponseEvent*>;
105         __pAppControlResponseEventContainer->Construct();
106         __appControlResponseEventList.Construct();
107 }
108
109 _AppControlManager::~_AppControlManager(void)
110 {
111         SysLog(NID_APP, "");
112         __appControlEvent.RemoveListener(*dynamic_cast<_IAppControlSysEventListener*>(this));
113         IEnumeratorT<int>* pEnum = __appControlResponseEventList.GetEnumeratorN();
114
115         if (pEnum != null)
116         {
117                 while(pEnum->MoveNext() == E_SUCCESS)
118                 {
119                         int reqId;
120                         pEnum->GetCurrent(reqId);
121                         if (__pAppControlResponseEventContainer != null)
122                         {
123                                 _AppControlResponseEvent* pResponseEvent = null;
124                                 __pAppControlResponseEventContainer->GetValue(reqId, pResponseEvent);
125                                 delete pResponseEvent;
126
127                                 __pAppControlResponseEventContainer->Remove(reqId);
128                                 SysLog(NID_APP, "pResponseEvent gets deleted. reqId(%d)", reqId);
129                         }
130                 }
131         }
132         delete __pAppControlResponseEventContainer;
133         delete pEnum;
134 }
135
136 _AppControlManager*
137 _AppControlManager::GetInstance(void)
138 {
139         static _AppControlManager inst;
140
141         return &inst;
142 }
143
144 result
145 _AppControlManager::GetMimeFromExt(const String& ext, String& out)
146 {
147         std::unique_ptr<char[]> pExtension(_StringConverter::CopyToCharArrayN(ext));
148         SysTryReturnResult(NID_APP, pExtension != null, E_OUT_OF_MEMORY, "String allocation failure.");
149
150         char* mime = NULL;
151         mime_type_get_mime_type(pExtension.get(), &mime);
152
153         SysTryReturnResult(NID_APP, mime != NULL, E_UNSUPPORTED_FORMAT, "MIME type conversion failure for %ls.", ext.GetPointer());
154
155         out = mime;
156         free(mime);
157
158         return E_SUCCESS;
159 }
160
161 void
162 _AppControlManager::OnAppControlEventReceivedN(int reqId, _AppArg* pAppArg, int res)
163 {
164         SysLog(NID_APP, "Received request Id %d, arg 0x%x", reqId, pAppArg);
165
166         //_AppArg::Print(b);
167         // get launch info from request Id
168         _LaunchInfo* pInfo = __launchManager.FindItem(reqId);
169         SysTryReturnVoidResult(NID_APP, pInfo != null, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] request Id %d not found with response %d", reqId,
170                                         res);
171
172         // invoke callback
173         if (pInfo->launchCb)
174         {
175                 if (pInfo->magic == LAUNCH_INFO_MAGIC)
176                 {
177                         SysLog(NID_APP, "Invoking callback 0x%x", pInfo->launchCb);
178                         //pAppArg->Print();
179
180                         if (pInfo->pUserData && (!__listenerList.Contains(pInfo->pUserData)))
181                         {
182                                 (*pInfo->launchCb)(pInfo->pUserData, pInfo->pArg, pAppArg, static_cast<service_result_e>(res), pInfo->property, reqId);
183                         }
184                 }
185                 else
186                 {
187                         SysLogException(NID_APP, E_SYSTEM, "Corrupted data structure.");
188                 }
189         }
190
191         // clean up argument
192         __launchManager.RemoveItem(reqId);
193 }
194
195
196 // callback for out-of-process AppControl start event
197 void
198 _AppControlManager::OnAppControlEventReceivedN(int reqId, const AppId& appId, const String& operationId)
199 {
200         SysLog(NID_APP, "Received request Id %d, app %ls, operationId %ls", reqId, appId.GetPointer(), operationId.GetPointer());
201
202         // get launch info from request Id
203         _LaunchInfo* pInfo = __launchManager.FindItem(reqId);
204         SysTryReturnVoidResult(NID_APP, pInfo != null, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] request Id %d not found.", reqId);
205
206         // at least listener
207         IAppControlResponseListener* pListener = static_cast<IAppControlResponseListener*>(pInfo->pUserData);
208         SysTryReturnVoidResult(NID_APP, typeid(pListener) == typeid(IAppControlResponseListener*), E_SYSTEM, "[E_SYSTEM] Invalid result callback.");
209
210         if (pListener)
211         {
212                 result r = E_SUCCESS;
213                 AppId actualAppId = appId;
214                 if (appId == L'c')
215                 {
216                         actualAppId.Clear();
217                         r = E_OPERATION_CANCELED;
218                 }
219                 SysLog(NID_APP, "Invoking callback 0x%x.", pListener);
220
221                 _AppControlResponseEvent* pResponseEvent = null;
222                 __pAppControlResponseEventContainer->GetValue(reqId, pResponseEvent);
223                 SysLog(NID_APP, "StartResponseReceived Request Id(%d), ResponseEvent 0x%x.", reqId, pResponseEvent);
224                 if (pResponseEvent != null)
225                 {
226                         String oId(operationId);
227                         _AppControlResponseEventArg* pResponseEventArg = new (std::nothrow) _AppControlResponseEventArg(pListener, _APPCONTROL_RESPONSETYPE_START, actualAppId, oId, r, APP_CTRL_RESULT_SUCCEEDED, null, reqId);
228
229                         if (pResponseEventArg != null)
230                         {
231                                 pResponseEvent->Fire(*pResponseEventArg);
232                                 SysLog(NID_APP, "pResponseEvent is Fired");
233                         }
234                 }
235                 else
236                 {
237                         pListener->OnAppControlStartResponseReceived(actualAppId, operationId, r);
238                         SysLog(NID_APP, "OnAppControlStartResponseReceived called directly");
239                 }
240         }
241         else
242         {
243                 SysLog(NID_APP, "No listener registered.");
244         }
245 }
246
247
248 // callback for in-process event handling
249 void
250 _AppControlManager::OnAppControlEventReceivedN(int reqId, int res, const IMap* pArgs)
251 {
252         SysLog(NID_APP, "Received request Id %d, res %d, args 0x%x", reqId, res, pArgs);
253
254         // process proper callback
255         _InProcessInfo* pInfo = __inAppManager.FindItem(reqId);
256         SysTryReturnVoidResult(NID_APP, pInfo != null, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] request Id %d not found with args 0x%x", reqId,
257                                         pArgs);
258
259         if (pInfo->pListener)
260         {
261                 String aId = pInfo->providerId;
262                 String oId = pInfo->operationId;
263
264                 SysLog(NID_APP, "Invoking callback 0x%x for (%ls, %ls).", pInfo->pListener, aId.GetPointer(), oId.GetPointer());
265
266                 if (pInfo->property & _APPCONTROL_PROPERTY_ALIAS)
267                 {
268                         const _AppControlRegistry::_AppControlAliasEntry* pEntry = null;
269                         pEntry = _AppControlRegistry::GetInstance()->GetReverseAppControlAliasEntry(aId, oId);
270                         if (pEntry)
271                         {
272                                 aId = pEntry->provider;
273                                 oId = pEntry->operation;
274
275                                 SysLog(NID_APP, "Legacy AppControl (%ls, %ls).", aId.GetPointer(), oId.GetPointer());
276                         }
277                 }
278
279                 if (pInfo->isLegacy)
280                 {
281                         IAppControlEventListener* pListener = dynamic_cast<IAppControlEventListener*>(pInfo->pListener);
282                         if (pListener)
283                         {
284                                 ArrayList list(SingleObjectDeleter);
285                                 _AppArg::FillLegacyAppControlResult(list, res, pArgs, aId);
286
287                                 pListener->OnAppControlCompleted(aId, oId, &list);
288                         }
289                         else
290                         {
291                                 SysLog(NID_APP, "Wrong AppControl listener type.");
292                         }
293                 }
294                 else
295                 {
296                         IAppControlResponseListener* pListener = dynamic_cast<IAppControlResponseListener*>(pInfo->pListener);
297                         if (pListener && (!__listenerList.Contains(pInfo->pListener)))
298                         {
299                                 _AppControlResponseEvent* pResponseEvent = null;
300                                 int responseEventRequestId = RESPONSE_EVENT_REQID_MAGIC + reqId;
301                                 __pAppControlResponseEventContainer->GetValue(responseEventRequestId, pResponseEvent);
302
303                                 if (pResponseEvent != null)
304                                 {
305                                         _AppControlResponseEventArg* pResponseEventArg = new (std::nothrow) _AppControlResponseEventArg(pListener, _APPCONTROL_RESPONSETYPE_COMPLETE, aId, oId, E_SUCCESS, static_cast<AppCtrlResult>(res), const_cast<IMap*> (pArgs), responseEventRequestId);
306                                         if (pResponseEventArg != null)
307                                         {
308                                                 pResponseEvent->Fire(*pResponseEventArg);
309                                                 SysLog(NID_APP, "pResponseEvent is Fired");
310                                         }
311                                 }
312                                 else
313                                 {
314                                         pListener->OnAppControlCompleteResponseReceived(aId, oId, ConvertAppControlResultCode(res), pArgs);
315                                         SysLog(NID_APP, "OnAppControlCompleteResponseReceived called directly");
316                                         IMap* pMap = const_cast<IMap*> (pArgs);
317                                         delete pMap;
318                                 }
319                         }
320                         else
321                         {
322                                 SysLog(NID_APP, "Wrong AppControl listener type.");
323                         }
324                 }
325         }
326         else
327         {
328                 SysLogException(NID_APP, E_SYSTEM, "Invalid AppControl listener.");
329         }
330
331         // call TerminateAppControl
332         result (* pFunc)(int req) = null;
333         pFunc = reinterpret_cast<result (*)(int)>(pInfo->pLib->GetProcAddress(L"TerminateAppControl"));
334         if (pFunc)
335         {
336                 (*pFunc)(pInfo->reqId);
337         }
338         else
339         {
340                 SysLogException(NID_APP, E_SYSTEM, "No TerminateAppControl() function.");
341         }
342
343         // remove from list and unload dll
344         __inAppManager.RemoveItem(reqId);
345 }
346
347
348 result
349 _AppControlManager::SendAppControlEvent(IEventArg& arg)
350 {
351         return __appControlEvent.FireAsync(arg);
352 }
353
354 Tizen::Base::Collection::IMapT<int,_AppControlResponseEvent*>*
355 _AppControlManager::GetAppControlResponseEventContainer(void)
356 {
357         return __pAppControlResponseEventContainer;
358 }
359
360
361 // generic launch callback
362 static void
363 LaunchResultCb(bundle* b, int request_code, appsvc_result_val res, void* data)
364 {
365         SysLog(NID_APP, "SLP callee result: %d", res);
366
367         _AppControlManager* pImpl = static_cast<_AppControlManager*>(data);
368         if (pImpl == null)
369         {
370                 return;
371         }
372
373         _AppArg* pAppArg = new (std::nothrow) _AppArg;
374         SysTryReturnVoidResult(NID_APP, pAppArg != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] AppControl event argument creation failure.");
375
376         _AppControlEventArg* pArg = null;
377         result r = pAppArg->Construct(b);
378         SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] AppControl event argument creation failure.", GetErrorMessage(r));
379
380         pArg = new (std::nothrow) _AppControlEventArg(request_code, pAppArg, res);
381         SysTryCatch(NID_APP, pArg != null, r = E_OUT_OF_MEMORY, r, "[E_OUT_OF_MEMORY] AppControl event argument creation failure.");
382
383         //_AppArg::Print(b);
384         pImpl->SendAppControlEvent(*pArg);
385
386         return;
387
388 CATCH:
389         delete pAppArg;
390 }
391
392
393 result
394 _AppControlManager::SendAppControlStartResponse(int req, const char* pValue, const char* pOp)
395 {
396         _AppControlStartEventArg* pArg = new (std::nothrow) _AppControlStartEventArg(req, AppId(pValue), String(pOp));
397         SysTryReturnResult(NID_APP, pArg != null, E_OUT_OF_MEMORY, "AppControl start event creation failure.");
398
399         SendAppControlEvent(*pArg);
400
401         return E_SUCCESS;
402 }
403
404
405 result
406 _AppControlManager::LaunchPkg(_AppMessageImpl& msg, const char* pkg_name, const char* op, const char* mime, const char* uri, AppSvcResFn pCb, void* data)
407 {
408         bundle* kb = msg.GetBundle();
409         SysTryReturnResult(NID_APP, kb != NULL, E_OUT_OF_MEMORY, "Bundle allocation failure.");
410
411         if (pkg_name)
412         {
413                 appsvc_set_pkgname(kb, pkg_name);
414         }
415
416         appsvc_set_operation(kb, (op) ? op : APPSVC_OPERATION_DEFAULT);
417
418         if (mime)
419         {
420                 appsvc_set_mime(kb, mime);
421         }
422
423         if (uri)
424         {
425                 appsvc_set_uri(kb, uri);
426         }
427
428         if (_AppImpl::GetInstance() != null)
429         {
430                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
431                 _AppArg::UpdateWindowHandle(kb, handle);
432         }
433
434         SysLog(NID_APP, "MIME(%s), URI(%s).", appsvc_get_mime(kb), appsvc_get_uri(kb));
435         int pid = appsvc_run_service(kb, 0, reinterpret_cast<appsvc_res_fn>(pCb), this);
436
437         result r = E_SUCCESS;
438         if (pid < 0)
439         {
440                 switch (pid)
441                 {
442                 case APPSVC_RET_EILLACC:
443                         r = E_ILLEGAL_ACCESS;
444                         break;
445                 case APPSVC_RET_EINVAL:
446                         r = E_MAX_EXCEEDED;
447                         break;
448                 default:
449                         r = E_SYSTEM;
450                         break;
451                 }
452                 SysLog(NID_APP, "[%s] Launching service %s failure", GetErrorMessage(r), pkg_name);
453         }
454
455         return r;
456 }
457
458
459 int
460 _AppControlManager::Launch(_AppMessageImpl& msg, const char* pkg_name, const char* op, const char* mime, const char* uri, AppSvcResFn pCb, void* data)
461 {
462         bundle* kb = msg.GetBundle();
463         SysTryReturn(NID_APP, kb != NULL, -1, E_OUT_OF_MEMORY, "Bundle allocation failure.");
464
465         if (pkg_name)
466         {
467                 appsvc_set_pkgname(kb, pkg_name);
468         }
469
470         appsvc_set_operation(kb, (op) ? op : APPSVC_OPERATION_DEFAULT);
471
472         if (mime)
473         {
474                 appsvc_set_mime(kb, mime);
475         }
476
477         if (uri)
478         {
479                 appsvc_set_uri(kb, uri);
480         }
481
482         if (_AppImpl::GetInstance() != null)
483         {
484                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
485                 _AppArg::UpdateWindowHandle(kb, handle);
486         }
487
488         SysLog(NID_APP, "MIME(%s), URI(%s).", appsvc_get_mime(kb), appsvc_get_uri(kb));
489         int pid = appsvc_run_service(kb, 0, reinterpret_cast<appsvc_res_fn>(pCb), this);
490
491         result r = E_SUCCESS;
492         if (pid < 0)
493         {
494                 switch (pid)
495                 {
496                 case APPSVC_RET_EILLACC:
497                         r = E_ILLEGAL_ACCESS;
498                         break;
499                 case APPSVC_RET_EINVAL:
500                         r = E_MAX_EXCEEDED;
501                         break;
502                 default:
503                         r = E_SYSTEM;
504                         break;
505                 }
506                 SysLog(NID_APP, "[%s]Launching service %s failure", GetErrorMessage(r), pkg_name);
507         }
508         SetLastResult(r);
509
510         return pid;
511 }
512
513
514 int
515 _AppControlManager::LaunchPkg(_AppMessageImpl& msg, const AppId& appId, const String& opId, const String* pUri, const String* pMime, AppSvcResFn pCb, void* data)
516 {
517         std::unique_ptr<char[]> pPackage(_StringConverter::CopyToCharArrayN(appId));
518         std::unique_ptr<char[]> pOperation(_StringConverter::CopyToCharArrayN(opId));
519
520         const char* pUriData = null;
521         if (pUri)
522         {
523                 pUriData =  _StringConverter::CopyToCharArrayN(*pUri);
524         }
525
526         const char* pMimeData = null;
527         if (pMime)
528         {
529                 pMimeData = _StringConverter::CopyToCharArrayN(*pMime);
530         }
531
532         int pid = Launch(msg, pPackage.get(), pOperation.get(), pMimeData, pUriData, pCb, data);
533
534         delete [] pUriData;
535         delete [] pMimeData;
536
537         return pid;
538 }
539
540
541 result
542 _AppControlManager::LaunchPkg(const char* pkg_name, const char* op, const char* mime, const char* uri, AppSvcResFn pCb, void* data)
543 {
544         _AppMessageImpl msg;
545
546         return LaunchPkg(msg, pkg_name, op, mime, uri, pCb, data);
547 }
548
549 result
550 _AppControlManager::LaunchAppWithCondition(const AppId& appId, const String& condition, IList* pArrayArgs)
551 {
552         result r = E_SUCCESS;
553         _AppArg * pArg = new (std::nothrow) _AppArg();
554         SysTryCatch(NID_APP, pArg != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY]");
555
556         r = pArg->ConstructForAppLaunchCondition(condition, pArrayArgs);
557         SysTryCatch(NID_APP, !IsFailed(r), , r, "[%s] ConstructForAppLaunchCondition(%ls, .. ) fails", GetErrorMessage(r), condition.GetPointer());
558
559         r = _AppControlManager::LaunchApp(appId, pArg);
560 CATCH:
561         delete pArg;
562         return r;
563 }
564
565 result
566 _AppControlManager::LaunchApp(const AppId& appId, _AppArg* pArg, int req)
567 {
568         SysTryReturnResult(NID_APP, pArg != null, E_INVALID_ARG, "Invalid launch argument");
569         SysLog(NID_APP, "App: %ls.", appId.GetPointer());
570
571         String actualAppId = appId;
572         if (appId.GetLength() == 10)
573         {
574                 const String& name = _PackageManagerImpl::GetInstance()->GetDefaultAppExecutableName(appId);
575
576                 if (!name.IsEmpty())
577                 {
578                         actualAppId.Append(L'.');
579                         actualAppId.Append(name);
580                 }
581         }
582
583         pArg->UpdateRequestId(req);
584
585         if (_AppImpl::GetInstance() != null)
586         {
587                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
588                 pArg->UpdateWindowHandle(handle);
589         }
590
591         int pid = -1;
592         bundle* kb = NULL;
593         String tempId;
594         actualAppId.SubString(0, 10, tempId);
595         tempId += L'.';
596         tempId += L"_AppControl";
597
598         // [INFO] Ugly solution for submode support
599         pArg->UpdateAppId(tempId);
600         kb = pArg->GetBundle();
601         
602         pid = appsvc_run_service(kb, req, LaunchResultCb, this);
603         if (pid >= 0)
604         {
605                 SysLog(NID_APP, "Submode launch successful");
606                 return E_SUCCESS;
607         }
608         else if (pid == APPSVC_RET_EINVAL)
609         {
610                 SysLog(NID_APP, "Argument overflow");
611                 return E_MAX_EXCEEDED;
612         }
613
614         pArg->UpdateAppId(actualAppId);
615
616         // retry for possible failure
617         int count = 0;
618         const int TRY_COUNT = 3;
619         const int TRY_SLEEP_TIME = 65;
620         do
621         {
622                 kb = pArg->GetBundle();
623                 pid = appsvc_run_service(kb, req, LaunchResultCb, this);
624                 if (pid >= 0)
625                 {
626                         SysLog(NID_APP, "Application(%d) launched with reqId(%d) and arg(0x%x).", pid, req, pArg);
627                         return E_SUCCESS;
628                 }
629                 else if (pid == APPSVC_RET_EINVAL)
630                 {
631                         SysLog(NID_APP, "Argument overflow");
632                         return E_MAX_EXCEEDED;
633                 }
634
635                 count++;
636                 SysLog(NID_APP, "Waiting %dth time.", count);
637                 Thread::Sleep(TRY_SLEEP_TIME);
638         }
639         while (count < TRY_COUNT);
640
641         result r = E_SUCCESS;
642         switch (pid)
643         {
644         case APPSVC_RET_EILLACC:
645                 r = E_ILLEGAL_ACCESS;
646                 break;
647         default:
648                 r = E_SYSTEM;
649                 break;
650         }
651
652         SysLogException(NID_APP, r, "[%s] Launching service failure for %ls", GetErrorMessage(r), appId.GetPointer());
653
654         return r;
655 }
656
657 static bool
658 _IsDefaultApplication(const AppId& packageId, const String& appId)
659 {
660         const String& execName = _PackageManagerImpl::GetInstance()->GetDefaultAppExecutableName(packageId);
661
662         int index = -1;
663         result r = appId.IndexOf(L'.', 0, index);
664         if (r != E_SUCCESS)
665         {
666                 return false;
667         }
668
669         String tmp;
670         appId.SubString(index + 1, tmp);
671         if (tmp == execName)
672         {
673                 SysLog(NID_APP, "Default application %ls", tmp.GetPointer());
674                 return true;
675         }
676
677         return false;
678 }
679
680
681 int
682 _AppControlManager::Launch(const _AppMessageImpl& msg, const AppId& aId, const String& oId, const String* pUriData, const String* pMimeType, AppSvcResFn pCb, void* pData)
683 {
684         SysLog(NID_APP, "Enter");
685
686         _AppArg arg;
687         arg.Construct(msg, oId, pUriData, pMimeType);
688
689         int pid = Launch(aId, &arg, pCb, pData, -1); 
690         SysTryReturn(NID_APP, pid >= 0, -1, GetLastResult(), "Launching(%ls) is failed", aId.GetPointer());
691
692         SysLog(NID_APP, "Exit");
693
694         return pid;
695 }
696
697
698 int
699 _AppControlManager::Launch(const AppId& appId, _AppArg* pArg, int req)
700 {
701         return Launch(appId, pArg, reinterpret_cast<AppSvcResFn>(LaunchResultCb), this, req);
702 }
703
704
705 int
706 _AppControlManager::Launch(const AppId& appId, _AppArg* pArg, AppSvcResFn pCb, void* pData, int req)
707 {
708         SysTryReturn(NID_APP, pArg != null, -1, E_INVALID_ARG, "[E_INVALID_ARG] Invalid launch argument");
709         SysLog(NID_APP, "App: %ls.", appId.GetPointer());
710
711         String actualAppId = appId;
712         if (appId.GetLength() == 10)
713         {
714                 const String& execName = _PackageManagerImpl::GetInstance()->GetDefaultAppExecutableName(appId);
715
716                 if (!execName.IsEmpty())
717                 {
718                         actualAppId.Append(L'.');
719                         actualAppId.Append(execName);
720                 }
721         }
722
723         pArg->UpdateRequestId(req);
724
725         if (_AppImpl::GetInstance() != null)
726         {
727                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
728                 pArg->UpdateWindowHandle(handle);
729         }
730
731         int pid = -1;
732         bundle* kb = NULL;
733         String tempId;
734
735         actualAppId.SubString(0, 10, tempId);
736
737         if (_IsDefaultApplication(tempId, appId))
738         {
739                 tempId += L'.';
740                 tempId += L"_AppControl";
741
742                 // [INFO] Ugly solution for submode support
743                 pArg->UpdateAppId(tempId);
744                 kb = pArg->GetBundle();
745
746                 pid = appsvc_run_service(kb, req, reinterpret_cast<appsvc_res_fn>(pCb), pData);
747                 if (pid >= 0)
748                 {
749                         SysLog(NID_APP, "Submode launch successful");
750                         SetLastResult(E_SUCCESS);
751                         return pid;
752                 }
753                 else if (pid == APPSVC_RET_EINVAL)
754                 {
755                         SetLastResult(E_MAX_EXCEEDED);
756                         return pid;
757                 }
758         }
759
760         pArg->UpdateAppId(actualAppId);
761
762         // retry for possible failure
763         int count = 0;
764         const int TRY_COUNT = 3;
765         const int TRY_SLEEP_TIME = 65;
766         do
767         {
768                 kb = pArg->GetBundle();
769                 pid = appsvc_run_service(kb, req, reinterpret_cast<appsvc_res_fn>(pCb), pData);
770                 if (pid >= 0)
771                 {
772                         SysLog(NID_APP, "Application(%d) launched with reqId(%d) and arg(0x%x).", pid, req, pArg);
773                         SetLastResult(E_SUCCESS);
774                         return pid;
775                 }
776                 else if (pid == APPSVC_RET_EINVAL)
777                 {
778                         SetLastResult(E_MAX_EXCEEDED);
779                         return pid;
780                 }
781
782                 count++;
783                 SysLog(NID_APP, "Waiting %dth time with %d.", count, pid);
784                 Thread::Sleep(TRY_SLEEP_TIME);
785         }
786         while (count < TRY_COUNT);
787
788         result r = E_SUCCESS;
789         switch (pid)
790         {
791         case APPSVC_RET_EILLACC:
792                 r = E_ILLEGAL_ACCESS;
793                 break;
794         default:
795                 r = E_SYSTEM;
796                 break;
797         }
798
799         SysLogException(NID_APP, r, "[%s] Launching service failure for %ls", GetErrorMessage(r), appId.GetPointer());
800
801         SetLastResult(r);
802
803         return pid;
804 }
805
806 result
807 _AppControlManager::LaunchAppImplicit(_AppArg* pArg, int req)
808 {
809         SysTryReturnResult(NID_APP, pArg != null, E_INVALID_ARG, "Invalid launch argument");
810
811         result r = E_SUCCESS;
812         bundle* kb = pArg->GetBundle();
813
814         if (req >= 0)
815         {
816                 pArg->UpdateRequestId(req);
817                 _AppMessageImpl::AddData(kb, SELECTOR_NOTI_KEY, _AppInfo::GetApplicationId());
818         }
819
820         if (_AppImpl::GetInstance() != null)
821         {
822                 const long handle = _AppImpl::GetInstance()->GetWindowHandle();
823                 _AppArg::UpdateWindowHandle(kb, handle);
824         }
825
826         int pid = appsvc_run_service(kb, req, LaunchResultCb, this);
827         if (pid >= 0)
828         {
829                 if (pid == 0)
830                 {
831                         SysLog(NID_APP, "Sending local process again.");
832                         pid = getpid();
833                 }
834
835                 char pkgname[255] = {0, };
836                 aul_app_get_pkgname_bypid(pid, pkgname, 255);
837
838                 if (strncmp(pkgname, APP_SELECTOR, strlen(APP_SELECTOR)) != 0)
839                 {
840                         const char* pOperation = appsvc_get_operation(kb);
841
842                         SysLog(NID_APP, "Starting application without selector : (%s, %s).", pkgname, pOperation);
843
844                         SendAppControlStartResponse(req, pkgname, pOperation);
845                 }
846         }
847         else
848         {
849                 switch (pid)
850                 {
851                         case APPSVC_RET_EINVAL:
852                                 r = E_OBJ_NOT_FOUND;
853                                 break;
854                         case APPSVC_RET_ENOMATCH:
855                                 r = E_OBJ_NOT_FOUND;
856                                 break;
857                         case APPSVC_RET_EILLACC:
858                                 r = E_ILLEGAL_ACCESS;
859                                 break;
860                         case APPSVC_RET_ERROR:
861                                 // fall through
862                         case APPSVC_RET_ELAUNCH:
863                                 // fall through
864                         default:
865                                 r = E_SYSTEM;
866                                 break;
867                 }
868         }
869
870         SysLog(NID_APP, "[%s] Application(%d) launched with reqId(%d) and arg(0x%x).", GetErrorMessage(r), pid, req, pArg);
871
872         return r;
873 }
874
875 void
876 _AppControlManager::FinishAppControl(int reqId, int res, IMap* pMap)
877 {
878         SysLog(NID_APP, "req %d, res %d.", reqId, res);
879         _NativeAppControlEventArg* pArg = new (std::nothrow) _NativeAppControlEventArg(reqId, res, pMap);
880         SysTryReturnVoidResult(NID_APP, pArg != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Return argument allocation failure.");
881
882         SendAppControlEvent(*pArg);
883         SysLog(NID_APP, "Exit.");
884 }
885
886 const _AppArg*
887 _AppControlManager::FindResultRequest(int reqId) const
888 {
889         const _ResultInfo* pInfo = __resultManager.FindItem(reqId);
890         return (pInfo) ? &(pInfo->arg) : null;
891 }
892
893 int
894 _AppControlManager::AddLaunchRequest(_AppArg* pArg, LaunchCbType pCb, void* pData, int prop)
895 {
896         SysTryReturn(NID_APP, pArg != null, -1, E_INVALID_ARG, "[E_INVALID_ARG] Empty argument.");
897
898         _LaunchInfo* pItem = new (std::nothrow) _LaunchInfo(pArg, pCb, pData, prop);
899         SysTryReturn(NID_APP, pItem != null, -1, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Empty argument.");
900
901         SysLog(NID_APP, "Registering callback 0x%x, 0x%x", pCb, pData);
902
903         return __launchManager.InsertItem(pItem);
904 }
905
906 void
907 _AppControlManager::RemoveLaunchRequest(int req)
908 {
909         __launchManager.RemoveItem(req);
910 }
911
912 result
913 _AppControlManager::RegisterRequest(service_s* service, int& req, _AppHandler& handler)
914 {
915         bundle* b = _AppArg::GetBundleFromSvc(service);
916
917         _AppArg* pArg = new (std::nothrow) _AppArg();
918         SysTryReturnResult(NID_APP, pArg != null, E_OUT_OF_MEMORY, "ArrayList creation failure.");
919         pArg->Construct(b);
920
921         result r = E_SUCCESS;
922
923         // ownership is transfered to RequestManager
924         _ResultInfo* pItem = new (std::nothrow) _ResultInfo(*pArg);
925         SysTryCatch(NID_APP, pItem != null, , r = E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Empty argument.");
926
927         req = __resultManager.InsertItem(pItem);
928         SysTryCatch(NID_APP, req != -1, , r = E_INVALID_STATE, "[E_INVALID_STATE] Invalid argument handling state.");
929
930         handler = _AppArg::GetHandler(b);
931
932         return E_SUCCESS;
933
934 CATCH:
935         delete pArg;
936
937         return r;
938 }
939
940
941 bool
942 _AppControlManager::IsAllowedAppControl(const char aTable[][2][96], int count, const String& aId, const String& oId)
943 {
944         for (int i = 0; i < count; i++)
945         {
946                 if (aId == aTable[i][0] && oId == aTable[i][1])
947                 {
948                         SysLog(NID_APP, "Found entry (%s, %s)", aTable[i][0], aTable[i][1]);
949                         return true;
950                 }
951         }
952
953         return false;
954 }
955
956
957 AppCtrlResult
958 _AppControlManager::ConvertAppControlResultCode(int resCode)
959 {
960         AppCtrlResult ret = APP_CTRL_RESULT_FAILED;
961
962         switch(resCode)
963         {
964                 case SERVICE_RESULT_SUCCEEDED:
965                         ret = APP_CTRL_RESULT_SUCCEEDED;
966                         break;
967                 case SERVICE_RESULT_FAILED:
968                         ret = APP_CTRL_RESULT_CANCELED;
969                         break;
970                 case SERVICE_RESULT_CANCELED:
971                         ret = APP_CTRL_RESULT_ABORTED;
972                         break;
973                 case APPSVC_OSP_RES_FAIL:
974                         ret = APP_CTRL_RESULT_FAILED;
975                         break;
976                 case APPSVC_OSP_RES_TERMINATE:
977                         ret = APP_CTRL_RESULT_TERMINATED;
978                         break;
979                 default:
980                         ret = APP_CTRL_RESULT_FAILED;
981                         break;
982         }
983
984         return ret;
985 }
986
987
988 void
989 _AppControlManager::OnAppControlResponseEventReceivedN(const Tizen::Base::Runtime::IEventArg* arg)
990 {
991         const _AppControlResponseEventArg* pEventArg = dynamic_cast<const _AppControlResponseEventArg*>(arg);
992
993         if (pEventArg != null)
994         {
995                 IAppControlResponseListener* pResponseListener = pEventArg->GetListener();
996
997                 if(pResponseListener != null)
998                 {
999                         if(pEventArg->GetType() == _APPCONTROL_RESPONSETYPE_START)
1000                         {
1001                                 pResponseListener->OnAppControlStartResponseReceived(pEventArg->GetAppId(), pEventArg->GetOperationId(), pEventArg->GetResult());
1002                                 SysLog(NID_APP, "OnAppControlStartResponseReceived called");
1003                         }
1004                         else
1005                         {
1006                                 pResponseListener->OnAppControlCompleteResponseReceived(pEventArg->GetAppId(), pEventArg->GetOperationId(), pEventArg->GetAppControlResult(), pEventArg->GetExtraData());
1007                                 SysLog(NID_APP, "OnAppControlCompleteResponseReceived called");
1008
1009                                 _AppControlResponseEvent* pResponseEvent = null;
1010                                 _AppControlManager::GetInstance()->GetAppControlResponseEventContainer()->GetValue(pEventArg->GetRequestId(), pResponseEvent);
1011                                 _AppControlManager::GetInstance()->GetAppControlResponseEventContainer()->Remove(pEventArg->GetRequestId());
1012
1013                                 delete pResponseEvent;
1014                                 SysLog(NID_APP, "pResponseEvent gets deleted, reqId(%d)", pEventArg->GetRequestId());
1015                         }
1016                 }
1017                 else
1018                 {
1019                         SysLog(NID_APP, "Invalid ResponseListener");
1020                 }
1021         }
1022         else
1023         {
1024                 SysLog(NID_APP, "Invalid AppControl arguments : arg(0x%x)", &arg);
1025         }
1026 }
1027
1028 AppId
1029 _AppControlManager::GetAliasAppId(const AppId& appId)
1030 {
1031         return _AppControlRegistry::GetInstance()->GetAliasAppId(appId);
1032 }
1033
1034 }} // Tizen::App