2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @file FApp_AulServer.cpp
19 * @brief This is the implementation for the _AulServer.cpp class.
25 #include <sys/prctl.h>
27 #include <unique_ptr.h>
31 #include <appsvc/appsvc.h>
34 #include <FBaseObject.h>
35 #include <FBaseString.h>
36 #include <FBaseUtil.h>
37 #include <FBaseSysLog.h>
38 #include <FBaseColHashMapT.h>
39 #include <FAppPkgPackageInfo.h>
41 #include <FBaseRt_Process.h>
42 #include <FBase_StringConverter.h>
43 #include "FAppPkg_PackageManagerImpl.h"
44 #include "FApp_Types.h"
45 #include "FApp_AulServer.h"
46 #include "FApp_TemplateUtil.h"
51 extern int aul_listen_app_dead_signal(int (* func)(int, void*), void* data);
56 using namespace Tizen::App::Package;
57 using namespace Tizen::Base;
58 using namespace Tizen::Base::Collection;
59 using namespace Tizen::Base::Runtime;
60 using namespace Tizen::Base::Utility;
65 const char _DESKTOP_FILE_PATH[] = "/opt/share/applications";
66 const char _DESKTOP_FILE_PATH_FORMAT[] = "%s/%s.desktop";
68 const char _X_TIZEN_SVC[] = "x-tizen-svc"; //X-TIZEN-SVC=[operation1] | [URI1] | [MIME1] ; [operation2] | [URI2] | [MIME2]
69 const int _MAX_TIZEN_SVC_DESC_LEN = 1024;
71 const int _MAX_CATEGORY = 12;
72 const int _MAX_PACKAGE_ID_LENGTH = 10;
74 const char _APP_PATH_FORMAT[] = "/opt/usr/apps/0000000000/bin/%ls";
75 const char _APP_PATH_FORMAT2[] = "/opt/apps/0000000000/bin/%ls";
76 const char PATH_ROOT[] = "/opt/usr/apps/";
77 const char PATH_ROOT2[] = "/opt/apps/";
81 namespace Tizen { namespace App
86 const char category[_MAX_CATEGORY];
90 static const _CategoryList _CATEGORY_LIST[] =
92 {"home-screen", _APP_TYPE_HOME_APP},
93 {"lock-screen", _APP_TYPE_LOCK_APP},
94 {"ime", _APP_TYPE_IME_APP},
97 static const int _NUM_CATEGORY = sizeof(_CATEGORY_LIST) / sizeof(_CategoryList);
101 _AulServer::SendResult(bundle* b, appsvc_result_val res)
103 result r = E_SUCCESS;
105 int ret = appsvc_send_result(b, res);
111 SysLogException(NID_APP, r, "Invalid result bundle.");
116 SysLogException(NID_APP, r, "Internal IPC error.");
121 SysLogException(NID_APP, r, "General error.");
128 SysLog(NID_APP, "SendResult() ok");
135 _AulServer::IsRunning(const AppId& appId, const String& exeName)
137 char slpPackageName[MAX_SLP_PACKAGE_ID] = {0, };
139 _PackageManagerImpl* pPackageManagerImpl = _PackageManagerImpl::GetInstance();
140 SysTryReturn(NID_APP, pPackageManagerImpl != null, false, E_INVALID_STATE, "[E_INVALID_STATE] Invalid package instance.");
142 pPackageManagerImpl->GetPackageName(appId, &exeName, slpPackageName, MAX_SLP_PACKAGE_ID);
144 const bool isRunning = (aul_app_is_running(slpPackageName) > 0);
146 SysLog(NID_APP, "'%s' %s running now.", slpPackageName, (isRunning) ? "is" : "is NOT");
152 _AulServer::IsRunning(const String& packageName)
154 std::unique_ptr<char[]> pPackageId(_StringConverter::CopyToCharArrayN(packageName));
156 const bool isRunning = (aul_app_is_running(pPackageId.get()) > 0);
158 SysLog(NID_APP, "'%ls' %s running now.", packageName.GetPointer(), (isRunning) ? "is" : "is NOT");
164 _AulServer::SetOnAppTerminatedCb(int (* pf_app_dead_handler)(int pid, void* pData), void* pData)
166 aul_listen_app_dead_signal(pf_app_dead_handler, pData);
167 SysLog(NID_APP, "'app_dead_handler is set.");
172 _AulServer::TerminateApplicationByPid(int pid)
174 int ret_aul = aul_subapp_terminate_request_pid(pid);
175 result r = E_SUCCESS;
181 SysLogException(NID_APP, r, "invaild pid.\n");
186 SysLogException(NID_APP, r, "internal AUL IPC error.\n");
191 SysLogException(NID_APP, r, "general error.\n");
195 SysLog(NID_APP, "'%d' is terminated.", pid);
203 _AulServer::SetOomAdj(int pid, int adj)
205 // set oom_adj to -17 for system service
206 result r = E_SUCCESS;
207 char buf[FILENAME_MAX];
210 snprintf(buf, FILENAME_MAX, "/proc/%d/oom_adj", pid);
211 fP = fopen(buf, "w");
212 SysTryReturnResult(NID_APP, fP != NULL, E_SYSTEM, "oom_adj change failed with %s.", strerror(errno));
214 fprintf(fP, "%d", adj);
221 _AulServer::SetPowerOffNotiListener( void (*powerOffCb)(void *pData), void *pData)
223 int heyFd = heynoti_init();
224 SysTryReturnResult(NID_APP, heyFd >= 0, E_SYSTEM, "heynoti_init failed.");
226 int ret = heynoti_subscribe(heyFd, "power_off_start", powerOffCb, pData);
227 SysTryReturnResult(NID_APP, ret >= 0, E_SYSTEM, "heynoti_subscribe failed.");
229 ret = heynoti_attach_handler(heyFd);
230 SysTryReturnResult(NID_APP, ret >= 0, E_SYSTEM, "heynoti_attach_handler failed.");
236 _AulServer::GetAppType(const String& category)
240 HashMapT<String, int> map;
243 StringTokenizer strTok(category, L';');
246 while (strTok.HasMoreTokens())
248 result r = strTok.GetNextToken(token);
255 SysLog(NID_APP, "%d category items .", map.GetCount());
259 for (int i = 0; i < _NUM_CATEGORY; i++)
262 key = _CATEGORY_LIST[i].category;
263 result r = map.ContainsKey(key, b);
264 if (r == E_SUCCESS && b)
266 ret |= _CATEGORY_LIST[i].type;
273 bool _AulServer::IsInstalled(const AppId& appId)
276 packageId = _PackageManagerImpl::GetPackageIdByAppId(appId);
278 return _PackageManagerImpl::GetInstance()->IsPackageInstalled(packageId);
281 int _AulServer::CreateProcess(const AppId& appId)
283 SysTryReturn(NID_APP, appId.GetLength() > 10 && appId[10] == L'.', -1, E_INVALID_ARG, "[E_INVALID_ARG] Wrong appId %ls.", appId.GetPointer());
293 char path[FILENAME_MAX];
294 memset(path, '\0', FILENAME_MAX);
297 snprintf(path, FILENAME_MAX, _APP_PATH_FORMAT2, appId.GetPointer() + 11);
299 int ret = wcstombs(path + strlen(PATH_ROOT2), appId.GetPointer(), 10);
302 SysLogException(NID_APP, E_SYSTEM, "Launching service (%ls)(%s) failed with [%s].", appId.GetPointer(), path, strerror(errno));
306 snprintf(path, FILENAME_MAX, _APP_PATH_FORMAT2, appId.GetPointer() + 11);
308 int ret = wcstombs(path + strlen(PATH_ROOT2), appId.GetPointer(), 10);
311 SysLogException(NID_APP, E_SYSTEM, "Launching service (%ls)(%s) failed with [%s].", appId.GetPointer(), path, strerror(errno));
315 if (euidaccess(path, R_OK) != 0)
317 snprintf(path, FILENAME_MAX, _APP_PATH_FORMAT, appId.GetPointer() + 11);
319 ret = wcstombs(path + strlen(PATH_ROOT), appId.GetPointer(), 10);
322 SysLogException(NID_APP, E_SYSTEM, "Launching service (%ls)(%s) failed with [%s].", appId.GetPointer(), path, strerror(errno));
328 SysLog(NID_APP, "Launching %s.", path);
330 int currentPid = getpid();
332 //SetOomAdj(currentPid, -17); // set oom_adj to -17 for system service
334 prctl(PR_SET_PDEATHSIG, SIGTERM);
336 setpgid(currentPid, currentPid);
338 ret = execl(path, path, static_cast<char*>(NULL));
341 SysLogException(NID_APP, E_SYSTEM, "Launching service (%ls)(%s) failed with [%s].", appId.GetPointer(), path, strerror(errno));
351 _AulServer::IsUserPreferredAppForAppControlResolution(const AppId& appId)
353 std::unique_ptr<char[]> pAppId(_StringConverter::CopyToCharArrayN(appId));
355 int ret = appsvc_is_defapp(pAppId.get());
356 SysTryReturn(NID_APP, ret == 1, false, E_SUCCESS,"%ls is not an UserPreferredAppForAppControlResolution. ret(%d)", appId.GetPointer(), ret);
358 SysLog(NID_APP, "%ls is an UserPreferredAppForAppControlResolution.", appId.GetPointer());
363 _AulServer::ClearUserPreferenceForAppControlResolution(const AppId& appId)
365 std::unique_ptr<char[]> pAppId(_StringConverter::CopyToCharArrayN(appId));
367 int ret_aul = appsvc_unset_defapp(pAppId.get());
368 SysTryReturnResult(NID_APP, ret_aul == APPSVC_RET_OK, E_SYSTEM, "Fail to clear UserPreferredAppForAppControlResolution of %ls. ret_aul(%d)", appId.GetPointer(), ret_aul);
370 SysLog(NID_APP, "Succeed to clear UserPreferredAppForAppControlResolution of %ls.", appId.GetPointer());
375 _AulServer::_DesktopFile::MakePath(const AppId& appId, const String* pExeName, char* path, int size)
377 SysTryReturnResult(NID_APP, path != null, E_INVALID_ARG, "");
379 char packageName[MAX_SLP_PACKAGE_ID] = {0, };
380 result r = E_SUCCESS;
381 _PackageManagerImpl* pPackageManagerImpl = _PackageManagerImpl::GetInstance();
382 SysTryReturnResult(NID_APP, pPackageManagerImpl, E_INVALID_STATE, "Invalid package manager instance.");
384 r = pPackageManagerImpl->GetPackageName(appId, pExeName, packageName, MAX_SLP_PACKAGE_ID);
385 SysTryReturn(NID_APP, !IsFailed(r), r, r, "%s", GetErrorMessage(r));
387 snprintf(path, size, _DESKTOP_FILE_PATH_FORMAT, _DESKTOP_FILE_PATH, packageName);
393 _AulServer::_DesktopFile::UpdateService(const AppId& appId, const char* value)
395 char path[FILENAME_MAX] = {0, };
396 MakePath(appId, null, path, FILENAME_MAX);
398 return UpdateField(path, _X_TIZEN_SVC, value);
403 _AulServer::_DesktopFile::RemoveService(const AppId& appId, const char* operationOnlyValue)
405 char path[FILENAME_MAX] = {0, };
406 MakePath(appId, null, path, FILENAME_MAX);
408 return UpdateField(path, _X_TIZEN_SVC, operationOnlyValue, true);
413 // Update value of specified field.
414 // currently only "x-slp-svc" field is supported.
416 #define BUFFER_SIZE 1024
418 _AulServer::_DesktopFile::UpdateField(const char* path, const char* fieldName, const char* value, bool isRemove)
420 SysTryReturnResult(NID_APP, path != null, E_INVALID_ARG, "path should not be null.");
421 SysTryReturnResult(NID_APP, fieldName != null, E_INVALID_ARG, "fieldName should not be null.");
422 SysTryReturnResult(NID_APP, value != null, E_INVALID_ARG, "value should not be null.");
424 FILE* fp = fopen(path, "r+");
425 SysTryReturnResult(NID_APP, fp != null, E_SYSTEM, "falied to open '%s' due to %s", path, strerror(errno));
427 char buffer[BUFFER_SIZE] = {0, };
432 result r = E_SUCCESS;
435 ArrayListT<char*> buffers;
438 char* pCurrent = null;
440 while (fgets(buffer, BUFFER_SIZE, fp) != NULL)
442 len = strlen(buffer);
443 SysTryCatch(NID_APP, len < BUFFER_SIZE, , r = E_INVALID_ARG, "strlen returns invalid value. (%d)", len );
447 pCurrent = new (std::nothrow) char[len + 1];
448 SysTryCatch(NID_APP, pCurrent != null, , r = E_OUT_OF_MEMORY, "failed to allocate mem pCurrent");
450 strncpy(pCurrent, buffer, len);
451 buffers.Add(pCurrent);
455 if (strncmp(buffer, fieldName, len) == 0)
457 int fieldNameLen = strlen(fieldName);
458 SysTryCatch(NID_APP, len > fieldNameLen, , E_INVALID_ARG, "[E_INVALID_ARG] fieldName(%s)", fieldName);
460 pCurrent = UpdateServiceValueN(buffer + fieldNameLen, value, isRemove);
461 SysTryCatch(NID_APP, pCurrent != null, , r = GetLastResult(), "[%s] UpdateServiceValue failed", GetErrorMessage(GetLastResult()));
463 buffers.Add(pCurrent);
475 fsetpos(fp, (fpos_t*) &foundpos);
477 remains = buffers.GetCount(); // prevent infinite loop
478 while (buffers.GetCount() > 0 && remains-- > 0)
481 buffers.GetAt(0, pCurrent);
483 SysTryCatch(NID_APP, pCurrent != null, , r = E_INVALID_STATE, "");
486 len = strlen(pCurrent);
491 int ret = truncate(path, pos);
492 SysTryLog(NID_APP, ret == 0, "Truncate failure (%s).", strerror(errno));
496 char svctext[_MAX_TIZEN_SVC_DESC_LEN] = {0, };
497 snprintf(svctext, _MAX_TIZEN_SVC_DESC_LEN, "%s=%s\n", fieldName, value);
506 remains = buffers.GetCount(); // prevent infinite loop
507 while (buffers.GetCount() > 0 && remains-- > 0)
510 buffers.GetAt(0, pCurrent);
512 if (pCurrent != null)
524 // Tizen service string example
525 // X-TIZEN-SVC= http://tizen.org/appcontrol/operation/pick|NULL|image/jpge; http://tizen.org/appcontrol/operation/pick|NULL|video/mp4; http://tizen.org/appcontrol/operation/pick|NULL|NULL; http://tizen.org/appcontrol/operation/pview|NULL|NULL
528 _AulServer::_DesktopFile::UpdateServiceValueN(char* buffer, const char* newValue, bool isRemove)
530 SysTryReturn(NID_APP, buffer != null, null, E_INVALID_ARG, "");
531 SysTryReturn(NID_APP, newValue != null, null, E_INVALID_ARG, "");
533 SysLog(NID_APP, "current(%s), new(%s), isRemove(%s)", buffer, newValue, (isRemove) ? "true" : "false");
538 const String& servicePattern(L"([A-Za-z&=:/\\.\\-]*);?");
543 Utility::RegularExpression regex;
544 result r = regex.Construct(servicePattern);
545 SysTryReturn(NID_APP, !IsFailed(r), null, r, "");
550 String newService(newValue);
552 if (isRemove == false)
554 ParseService(newService, newOperation, newUrl, newMimeType);
558 newOperation = newValue;
561 services.Construct();
563 while (regex.Consume(buf, &services) == true)
565 String* pCurrentService = (String*) services.GetAt(1);
566 services.RemoveAll(false);
572 ParseService(*pCurrentService, operation, url, mimeType);
574 if (operation == newOperation)
576 if (isRemove == true)
578 SysLog(NID_APP, "opreration '%ls' will be removed", operation.GetPointer());
582 SysAssertf(found == false, "It's assumed that service doesn't have duplicated operation in tizen desktop file. But it isn't, so now we have to check this case.");
583 // replace operation.
584 if (found == false) // ( if duplicated operation is already exist, It will be keeped.
587 AppendServiceValueToString(resultString, newService);
588 SysLog(NID_APP, "opreration '%ls;%ls;%ls' will be updated to ;%ls;%ls", operation.GetPointer(), url.GetPointer(), mimeType.GetPointer(), newUrl.GetPointer(), mimeType.GetPointer());
595 // add not specified service.
596 AppendServiceValueToString(resultString, *pCurrentService);
599 delete pCurrentService;
602 if (found == false && isRemove == false)
604 AppendServiceValueToString(resultString, newService);
605 SysLog(NID_APP, "opreration '%ls;%ls;%ls' will be added", newOperation.GetPointer(), newUrl.GetPointer(), newMimeType.GetPointer());
608 SysLog(NID_APP, "updated string is '%ls'", resultString.GetPointer());
609 return _StringConverter::CopyToCharArrayN(resultString);
614 _AulServer::_DesktopFile::AppendServiceValueToString(String& serviceString, const String& newVaue)
616 if (serviceString.GetLength() > 0)
618 serviceString += ";";
621 serviceString += newVaue;
626 _AulServer::_DesktopFile::ParseService(const String& service, String& operation, String& url, String& mimeType)
628 SysLog(NID_APP, "service(%ls)", service.GetPointer());
630 const String& serviceDetailPattern(L"([A-Za-z&=/\\.\\-]*):(.*://[A-Za-z&=/\\.\\-]*|[A-Za-z&=/\\.\\-]*):([A-Za-z&=/\\.\\-]*)");
632 Utility::RegularExpression regexDetail;
633 result r = regexDetail.Construct(serviceDetailPattern);
634 SysTryReturn(NID_APP, !IsFailed(r), null, r, "[%s] RegularExpression::Construct(L\"%ls\") failed.", GetErrorMessage(r), serviceDetailPattern.GetPointer());
636 ArrayList matchedItems;
637 matchedItems.Construct();
638 regexDetail.Match(service, true, &matchedItems);
640 int matchedCount = matchedItems.GetCount();
641 SysTryLog(NID_APP, matchedCount == 4, "It's assumed that x-slp-svc value always have operation:url:mime in tizen desktop file. But it isn't or our parser is invalid. so now we have to check this case. %d", matchedItems.GetCount());
643 if (matchedCount > 1)
645 operation = *(String*) matchedItems.GetAt(1);
648 if (matchedCount > 2)
650 url = *(String*) matchedItems.GetAt(2);
653 if (matchedCount > 3)
655 mimeType = *(String*) matchedItems.GetAt(3);
658 SysLog(NID_APP, "matched(%d) : (%ls;%ls;%ls)", matchedItems.GetCount(), operation.GetPointer(), url.GetPointer(), mimeType.GetPointer());
659 matchedItems.RemoveAll(true);