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.
19 * @brief This is the implementation for the _Aul.cpp class.
25 #include <sys/prctl.h>
27 #include <unique_ptr.h>
31 #include <appsvc/appsvc.h>
32 #include <app_manager.h>
35 #include <FBaseObject.h>
36 #include <FBaseString.h>
37 #include <FBaseUtil.h>
38 #include <FBaseSysLog.h>
39 #include <FBaseColHashMapT.h>
40 #include <FAppPkgPackageInfo.h>
42 #include <FBaseRt_Process.h>
43 #include <FBase_StringConverter.h>
44 #include "FAppPkg_PackageManagerImpl.h"
45 #include "FApp_Types.h"
47 #include "FApp_TemplateUtil.h"
52 extern int aul_listen_app_dead_signal(int (* func)(int, void*), void* data);
57 using namespace Tizen::App::Package;
58 using namespace Tizen::Base;
59 using namespace Tizen::Base::Collection;
60 using namespace Tizen::Base::Runtime;
61 using namespace Tizen::Base::Utility;
66 const char _DESKTOP_FILE_PATH[] = "/opt/share/applications";
67 const char _DESKTOP_FILE_PATH_FORMAT[] = "%s/%s.desktop";
69 const char _X_TIZEN_SVC[] = "x-tizen-svc"; //X-TIZEN-SVC=[operation1] | [URI1] | [MIME1] ; [operation2] | [URI2] | [MIME2]
70 const int _MAX_TIZEN_SVC_DESC_LEN = 1024;
72 const int _MAX_CATEGORY = 12;
73 const int _MAX_PACKAGE_ID_LENGTH = 10;
75 // borrowed from app-svc/include/pri_key.h
76 #define APP_SVC_K_RES_VAL "__APP_SVC_K_RES_VAL__"
80 namespace Tizen { namespace App
85 const char category[_MAX_CATEGORY];
89 static const _CategoryList _CATEGORY_LIST[] =
91 {"home-screen", _APP_TYPE_HOME_APP},
92 {"lock-screen", _APP_TYPE_LOCK_APP},
93 {"ime", _APP_TYPE_IME_APP},
96 static const int _NUM_CATEGORY = sizeof(_CATEGORY_LIST) / sizeof(_CategoryList);
99 _Aul::GetConvertedResult(const int aul_ret, const char* pFunctionName)
101 result r = E_SUCCESS;
107 SysLogException(NID_APP, r, "%s : Invalid argument.", pFunctionName);
112 SysLogException(NID_APP, r, "%s : Internal IPC error.", pFunctionName);
117 SysLogException(NID_APP, r, "%s : General error.", pFunctionName);
121 SysLog(NID_APP, "%s : successed.", pFunctionName);
129 _Aul::SendResult(bundle* b, appsvc_result_val res)
131 // to skip error handling, of appsvc_send_result, use aul_send_service_result() directly.
132 //int ret = appsvc_send_result(b, res);
134 char tmp[32] = {0, };
135 snprintf(tmp, 32, "%d", static_cast<int>(res));
136 appsvc_add_data(b, APP_SVC_K_RES_VAL, tmp);
138 const int aul_ret = aul_send_service_result(b);
140 result r = GetConvertedResult(aul_ret, "SendResult");
141 if (r == E_INVALID_ARG)
143 SysLog(NID_APP, "Converting internal exception to E_MAX_EXCEEDED.");
151 _Aul::IsRunning(const AppId& appId, const String& exeName)
153 char slpPackageName[MAX_SLP_PACKAGE_ID] = {0, };
154 bool isRunning = false;
156 _PackageManagerImpl* pPackageManagerImpl = _PackageManagerImpl::GetInstance();
157 SysTryReturn(NID_APP, pPackageManagerImpl != null, false, E_INVALID_STATE, "[E_INVALID_STATE] Invalid package instance.");
159 pPackageManagerImpl->GetPackageName(appId, &exeName, slpPackageName, MAX_SLP_PACKAGE_ID);
161 app_manager_is_running(slpPackageName, &isRunning);
163 SysLog(NID_APP, "'%s' %s running now.", slpPackageName, (isRunning == true) ? "is" : "is NOT");
169 _Aul::IsRunning(const String& packageName)
171 bool isRunning = false;
172 std::unique_ptr<char[]> pSlpPackageName(_StringConverter::CopyToCharArrayN(packageName));
174 app_manager_is_running(pSlpPackageName.get(), &isRunning);
176 SysLog(NID_APP, "'%ls' %s running now.", packageName.GetPointer(), (isRunning) ? "is" : "is NOT");
182 _Aul::SetOnAppTerminatedCb(int (* pf_app_dead_handler)(int pid, void* pData), void* pData)
184 aul_listen_app_dead_signal(pf_app_dead_handler, pData);
185 SysLog(NID_APP, "'app_dead_handler is set.");
190 _Aul::TerminateApplicationByPid(int pid)
192 int ret_aul = aul_terminate_pid(pid);
194 return GetConvertedResult(ret_aul, "TerminateApplicationByPid");
198 TerminateApplicationIterFnCb(const aul_app_info* pAppInfo, void* pData)
200 const char* pStr = static_cast<const char*>(pData);
202 if (pStr && strncmp(pStr, pAppInfo->pkg_name, NATIVE_APP_MAX_APPID_LENGTH) == 0)
204 SysLog(NID_APP, "%s(%d) is terminated.", pAppInfo->pkg_name, pAppInfo->pid);
205 int ret_aul = aul_terminate_pid( pAppInfo->pid );
206 SetLastResult(_Aul::GetConvertedResult(ret_aul, "TerminateApplication"));
212 _Aul::TerminateApplication(const AppId& appId)
214 SetLastResult(E_OBJ_NOT_FOUND);
215 std::unique_ptr<char[]> pAppId(_StringConverter::CopyToCharArrayN(appId));
216 aul_app_get_running_app_info(TerminateApplicationIterFnCb, static_cast<void*>(pAppId.get()));
218 SysLog(NID_APP, "%ls terminated.", appId.GetPointer());
219 return GetLastResult();
223 _Aul::SetOomAdj(int pid, int adj)
225 // set oom_adj to -17 for system service
226 result r = E_SUCCESS;
227 char buf[FILENAME_MAX];
230 snprintf(buf, FILENAME_MAX, "/proc/%d/oom_adj", pid);
231 fP = fopen(buf, "w");
232 SysTryReturnResult(NID_APP, fP != NULL, E_SYSTEM, "oom_adj change failed with %s.", strerror(errno));
234 fprintf(fP, "%d", adj);
241 _Aul::SetPowerOffNotiListener( void (*powerOffCb)(void *pData), void *pData)
243 int heyFd = heynoti_init();
244 SysTryReturnResult(NID_APP, heyFd >= 0, E_SYSTEM, "heynoti_init failed.");
246 int ret = heynoti_subscribe(heyFd, "power_off_start", powerOffCb, pData);
247 SysTryReturnResult(NID_APP, ret >= 0, E_SYSTEM, "heynoti_subscribe failed.");
249 ret = heynoti_attach_handler(heyFd);
250 SysTryReturnResult(NID_APP, ret >= 0, E_SYSTEM, "heynoti_attach_handler failed.");
256 _Aul::GetAppType(const String& category)
260 HashMapT<String, int> map;
263 StringTokenizer strTok(category, L';');
266 while (strTok.HasMoreTokens())
268 result r = strTok.GetNextToken(token);
275 SysLog(NID_APP, "%d category items .", map.GetCount());
279 for (int i = 0; i < _NUM_CATEGORY; i++)
282 key = _CATEGORY_LIST[i].category;
283 result r = map.ContainsKey(key, b);
284 if (r == E_SUCCESS && b)
286 ret |= _CATEGORY_LIST[i].type;
293 bool _Aul::IsInstalled(const AppId& appId)
296 packageId = _PackageManagerImpl::GetPackageIdByAppId(appId);
298 return _PackageManagerImpl::GetInstance()->IsPackageInstalled(packageId);
302 _Aul::_DesktopFile::MakePath(const AppId& appId, char* path, int size)
304 SysTryReturnResult(NID_APP, path != null, E_INVALID_ARG, "");
306 std::unique_ptr<char[]> pAppId(_StringConverter::CopyToCharArrayN(appId));
307 SysTryReturnResult(NID_APP, pAppId != null, E_OUT_OF_MEMORY, "Failed to allocate memory for 'pAppId'");
309 snprintf(path, size, _DESKTOP_FILE_PATH_FORMAT, _DESKTOP_FILE_PATH, pAppId.get());
315 _Aul::_DesktopFile::UpdateService(const AppId& appId, const char* value)
317 char path[FILENAME_MAX] = {0, };
318 MakePath(appId, path, FILENAME_MAX);
320 return UpdateField(path, _X_TIZEN_SVC, value);
325 _Aul::_DesktopFile::RemoveService(const AppId& appId, const char* operationOnlyValue)
327 char path[FILENAME_MAX] = {0, };
328 MakePath(appId, path, FILENAME_MAX);
330 return UpdateField(path, _X_TIZEN_SVC, operationOnlyValue, true);
334 // Update value of specified field.
335 // currently only "x-slp-svc" field is supported.
337 #define BUFFER_SIZE 1024
339 _Aul::_DesktopFile::UpdateField(const char* path, const char* fieldName, const char* value, bool isRemove)
341 SysTryReturnResult(NID_APP, path != null, E_INVALID_ARG, "path should not be null.");
342 SysTryReturnResult(NID_APP, fieldName != null, E_INVALID_ARG, "fieldName should not be null.");
343 SysTryReturnResult(NID_APP, value != null, E_INVALID_ARG, "value should not be null.");
345 FILE* fp = fopen(path, "r+");
346 SysTryReturnResult(NID_APP, fp != null, E_SYSTEM, "falied to open '%s' due to %s", path, strerror(errno));
348 char buffer[BUFFER_SIZE] = {0, };
353 result r = E_SUCCESS;
356 ArrayListT<char*> buffers;
359 char* pCurrent = null;
361 while (fgets(buffer, BUFFER_SIZE, fp) != NULL)
363 len = strlen(buffer);
364 SysTryCatch(NID_APP, len < BUFFER_SIZE, , r = E_INVALID_ARG, "strlen returns invalid value. (%d)", len );
368 pCurrent = new (std::nothrow) char[len + 1];
369 SysTryCatch(NID_APP, pCurrent != null, , r = E_OUT_OF_MEMORY, "failed to allocate mem pCurrent");
371 strncpy(pCurrent, buffer, len);
372 buffers.Add(pCurrent);
376 if (strncmp(buffer, fieldName, len) == 0)
378 int fieldNameLen = strlen(fieldName);
379 SysTryCatch(NID_APP, len > fieldNameLen, , E_INVALID_ARG, "[E_INVALID_ARG] fieldName(%s)", fieldName);
381 pCurrent = UpdateServiceValueN(buffer + fieldNameLen, value, isRemove);
382 SysTryCatch(NID_APP, pCurrent != null, , r = GetLastResult(), "[%s] UpdateServiceValue failed", GetErrorMessage(GetLastResult()));
384 buffers.Add(pCurrent);
396 fsetpos(fp, (fpos_t*) &foundpos);
398 remains = buffers.GetCount(); // prevent infinite loop
399 while (buffers.GetCount() > 0 && remains-- > 0)
402 buffers.GetAt(0, pCurrent);
404 SysTryCatch(NID_APP, pCurrent != null, , r = E_INVALID_STATE, "");
407 len = strlen(pCurrent);
412 int ret = truncate(path, pos);
413 SysTryLog(NID_APP, ret == 0, "Truncate failure (%s).", strerror(errno));
417 char svctext[_MAX_TIZEN_SVC_DESC_LEN] = {0, };
418 snprintf(svctext, _MAX_TIZEN_SVC_DESC_LEN, "%s=%s\n", fieldName, value);
427 remains = buffers.GetCount(); // prevent infinite loop
428 while (buffers.GetCount() > 0 && remains-- > 0)
431 buffers.GetAt(0, pCurrent);
433 if (pCurrent != null)
445 // Tizen service string example
446 // 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
449 _Aul::_DesktopFile::UpdateServiceValueN(char* buffer, const char* newValue, bool isRemove)
451 SysTryReturn(NID_APP, buffer != null, null, E_INVALID_ARG, "");
452 SysTryReturn(NID_APP, newValue != null, null, E_INVALID_ARG, "");
454 SysLog(NID_APP, "current(%s), new(%s), isRemove(%s)", buffer, newValue, (isRemove) ? "true" : "false");
459 const String& servicePattern(L"([A-Za-z&=:/\\.\\-]*);?");
464 Utility::RegularExpression regex;
465 result r = regex.Construct(servicePattern);
466 SysTryReturn(NID_APP, !IsFailed(r), null, r, "");
471 String newService(newValue);
473 if (isRemove == false)
475 ParseService(newService, newOperation, newUrl, newMimeType);
479 newOperation = newValue;
482 services.Construct();
484 while (regex.Consume(buf, &services) == true)
486 String* pCurrentService = (String*) services.GetAt(1);
487 services.RemoveAll(false);
493 ParseService(*pCurrentService, operation, url, mimeType);
495 if (operation == newOperation)
497 if (isRemove == true)
499 SysLog(NID_APP, "opreration '%ls' will be removed", operation.GetPointer());
503 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.");
504 // replace operation.
505 if (found == false) // ( if duplicated operation is already exist, It will be keeped.
508 AppendServiceValueToString(resultString, newService);
509 SysLog(NID_APP, "opreration '%ls;%ls;%ls' will be updated to ;%ls;%ls", operation.GetPointer(), url.GetPointer(), mimeType.GetPointer(), newUrl.GetPointer(), mimeType.GetPointer());
516 // add not specified service.
517 AppendServiceValueToString(resultString, *pCurrentService);
520 delete pCurrentService;
523 if (found == false && isRemove == false)
525 AppendServiceValueToString(resultString, newService);
526 SysLog(NID_APP, "opreration '%ls;%ls;%ls' will be added", newOperation.GetPointer(), newUrl.GetPointer(), newMimeType.GetPointer());
529 SysLog(NID_APP, "updated string is '%ls'", resultString.GetPointer());
530 return _StringConverter::CopyToCharArrayN(resultString);
535 _Aul::_DesktopFile::AppendServiceValueToString(String& serviceString, const String& newVaue)
537 if (serviceString.GetLength() > 0)
539 serviceString += ";";
542 serviceString += newVaue;
547 _Aul::_DesktopFile::ParseService(const String& service, String& operation, String& url, String& mimeType)
549 SysLog(NID_APP, "service(%ls)", service.GetPointer());
551 const String& serviceDetailPattern(L"([A-Za-z&=/\\.\\-]*):(.*://[A-Za-z&=/\\.\\-]*|[A-Za-z&=/\\.\\-]*):([A-Za-z&=/\\.\\-]*)");
553 Utility::RegularExpression regexDetail;
554 result r = regexDetail.Construct(serviceDetailPattern);
555 SysTryReturn(NID_APP, !IsFailed(r), null, r, "[%s] RegularExpression::Construct(L\"%ls\") failed.", GetErrorMessage(r), serviceDetailPattern.GetPointer());
557 ArrayList matchedItems;
558 matchedItems.Construct();
559 regexDetail.Match(service, true, &matchedItems);
561 int matchedCount = matchedItems.GetCount();
562 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());
564 if (matchedCount > 1)
566 operation = *(String*) matchedItems.GetAt(1);
569 if (matchedCount > 2)
571 url = *(String*) matchedItems.GetAt(2);
574 if (matchedCount > 3)
576 mimeType = *(String*) matchedItems.GetAt(3);
579 SysLog(NID_APP, "matched(%d) : (%ls;%ls;%ls)", matchedItems.GetCount(), operation.GetPointer(), url.GetPointer(), mimeType.GetPointer());
580 matchedItems.RemoveAll(true);