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