2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an AS IS BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
20 #include <JSWebAPIErrorFactory.h>
21 #include <GlobalContextManager.h>
22 #include <PlatformException.h>
24 // to get package name by appid
25 #include <app_manager.h>
27 // To get cert information from package
28 #include <package_manager.h>
29 #include <package_info.h>
31 // To get app size and installed time
32 #include <pkgmgr-info.h>
34 // To use ecore_thread
37 #include "PackageManager.h"
38 #include "PackageInformation.h"
39 #include "JSPackageInformation.h"
42 using namespace WrtDeviceApis::Commons;
43 using namespace WrtDeviceApis::CommonsJavaScript;
44 using namespace DeviceAPI::Common;
50 int package_manager_client_destroy(package_manager_request_h request);
57 PackageInfoCallbackData::PackageInfoCallbackData(JSContextRef globalCtx):
58 CallbackUserData(globalCtx)
60 m_exceptionCode = WrtDeviceApis::Commons::ExceptionCodes::None;
63 PackageInfoCallbackData::~PackageInfoCallbackData()
65 // TODO: Should I clear pkgInfos?
68 vector<PackageInformation> PackageInfoCallbackData::getPackageInfoList()
74 void PackageInfoCallbackData::addPackageInfo(PackageInformation pkgInfo)
76 m_pkgInfos.push_back(pkgInfo);
80 void PackageInfoCallbackData::setExceptionCode(ExceptionCodes::Enumeration exceptionCode)
82 m_exceptionCode = exceptionCode;
85 ExceptionCodes::Enumeration PackageInfoCallbackData::getExceptionCode() const
87 return m_exceptionCode;
90 PackageInfoEventCallback::PackageInfoEventCallback(CallbackUserData* oninstalled, CallbackUserData* onupdated, CallbackUserData* onuninstalled)
92 m_oninstalled = oninstalled;
93 m_onupdated = onupdated;
94 m_onuninstalled = onuninstalled;
98 PackageInfoEventCallback::~PackageInfoEventCallback()
101 delete m_oninstalled;
107 delete m_onuninstalled;
110 CallbackUserData* PackageInfoEventCallback::getOnInstalled()
112 return m_oninstalled;
115 CallbackUserData* PackageInfoEventCallback::getOnUpdated()
120 CallbackUserData* PackageInfoEventCallback::getOnUninstalled()
122 return m_onuninstalled;
125 pkgmgr_client** PackageInfoEventCallback::getEventHandler()
130 void PackageInfoEventCallback::setEventHandler(pkgmgr_client **handler)
132 m_handle_p = handler;
135 PackageInstallEventCallback::PackageInstallEventCallback(JSContextRef globalCtx, CallbackUserData* onprogress, CallbackUserData* oncomplete, CallbackUserData* onerror)
137 m_context = globalCtx;
138 m_onprogress = onprogress;
139 m_oncomplete = oncomplete;
142 m_request_handle = NULL;
145 PackageInstallEventCallback::~PackageInstallEventCallback()
147 if (m_request_handle != NULL) {
148 //package_manager_request_destroy(m_request_handle);
149 package_manager_client_destroy(m_request_handle);
162 CallbackUserData* PackageInstallEventCallback::getOnProgress()
167 CallbackUserData* PackageInstallEventCallback::getOnComplete()
172 CallbackUserData* PackageInstallEventCallback::getOnError()
177 JSContextRef PackageInstallEventCallback::getContext()
182 void PackageInstallEventCallback::setHandle(package_manager_request_h handle)
184 m_request_handle = handle;
187 package_manager_request_h PackageInstallEventCallback::getHandle()
189 return m_request_handle;
192 static int get_current_pkg_id(char** pkg_id)
196 string appId = PackageManager::getInstance()->getCurrentAppId();
198 int ret = app_manager_get_app_info(appId.c_str(), &handle);
199 if (ret != APP_MANAGER_ERROR_NONE) {
200 LoggerE("Fail to get appinfo");
204 ret = app_info_get_package(handle, pkg_id);
205 if ((ret != APP_MANAGER_ERROR_NONE) || (*pkg_id == NULL)) {
206 LoggerE("Fail to get pkg_id");
210 ret = app_info_destroy(handle);
211 if (ret != APP_MANAGER_ERROR_NONE) {
212 LoggerE("Fail to get destory appinfo");
219 static bool app_callback(package_info_app_component_type_e comp_type, const char *app_id, void *user_data)
221 PackageInformation* pkgInfo = (PackageInformation*)user_data;
222 pkgInfo->m_appIds.push_back(app_id);
226 static PackageInformation* create_pkg_info(pkgmgrinfo_pkginfo_h handle)
228 PackageInformation *pkgInfo = new PackageInformation();
232 char* iconPath = NULL;
233 char* version = NULL;
236 int lastModified = 0;
239 char* description = NULL;
240 vector<string> appIds;
243 ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &id);
244 if ((ret != PMINFO_R_OK) || (id == NULL)) {
245 LoggerE("Fail to get id. return NULL.");
252 ret = pkgmgrinfo_pkginfo_get_label(handle, &name);
253 if ((ret != PMINFO_R_OK) || (name == NULL)) {
254 LoggerE("Fail to get labe");
256 pkgInfo->m_name = name;
259 ret = pkgmgrinfo_pkginfo_get_icon(handle, &iconPath);
260 if ((ret != PMINFO_R_OK) || (iconPath == NULL)) {
261 LoggerE("Fail to get iconPath");
263 pkgInfo->m_iconPath = iconPath;
266 ret = pkgmgrinfo_pkginfo_get_version(handle, &version);
267 if ((ret != PMINFO_R_OK) || (version == NULL)) {
268 LoggerE("Fail to get version");
270 pkgInfo->m_version = version;
273 ret = pkgmgrinfo_pkginfo_get_total_size(handle, &totalSize);
274 if (ret != PMINFO_R_OK) {
275 LoggerE("Fail to get totalSize");
277 pkgInfo->m_totalSize = totalSize;
280 ret = pkgmgrinfo_pkginfo_get_data_size(handle, &dataSize);
281 if (ret != PMINFO_R_OK) {
282 LoggerE("Fail to get dataSize");
284 pkgInfo->m_dataSize = dataSize;
287 ret = pkgmgrinfo_pkginfo_get_installed_time(handle, &lastModified);
288 if (ret != PMINFO_R_OK) {
289 LoggerE("Fail to get lastModified");
291 pkgInfo->m_lastModified = lastModified;
294 ret = pkgmgrinfo_pkginfo_get_type(handle, &type);
295 if ((ret != PMINFO_R_OK) || (type == NULL)) {
296 LoggerE("Fail to get type");
298 pkgInfo->m_type = type;
301 ret = pkgmgrinfo_pkginfo_get_author_name(handle, &author);
302 if ((ret != PMINFO_R_OK) || (author == NULL)) {
303 LoggerE("Fail to get author");
305 pkgInfo->m_author = author;
308 ret = pkgmgrinfo_pkginfo_get_description(handle, &description);
309 if ((ret != PMINFO_R_OK) || (description == NULL)) {
310 LoggerE("Fail to get description");
312 pkgInfo->m_description = description;
315 package_info_h package_info;
317 ret = package_manager_get_package_info(id, &package_info);
318 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
319 LoggerE("Cannot create package info");
324 ret = package_info_foreach_app_from_package(package_info, PACKAGE_INFO_ALLAPP, app_callback, (void*)pkgInfo);
325 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
326 LoggerE("failed while getting appids");
329 ret = package_info_destroy(package_info);
330 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
331 LoggerE("Cannot destroy package info");
334 // REMARK: do not destroy handle. because handle is comes from outside!!
338 static gboolean getCompleteCB(void *data)
340 PackageInfoCallbackData *callback = (PackageInfoCallbackData *)data;
341 JSContextRef context = callback->getContext();
343 if (callback->getExceptionCode() == WrtDeviceApis::Commons::ExceptionCodes::None) {
344 vector<PackageInformation> pkgInfoList = callback->getPackageInfoList();
346 JSObjectRef jsResult = JSCreateArrayObject(context, 0, NULL);
347 if (jsResult == NULL) {
348 JSValueRef error = JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), JSWebAPIErrorFactory::UNKNOWN_ERROR, "platform exception");
349 callback->callErrorCallback(error);
353 for (size_t i = 0; i < pkgInfoList.size(); ++i) {
354 JSValueRef tmpVal = JSPackageInformation::createJSObject(context, &pkgInfoList[i]);
355 if (!JSSetArrayElement(context, jsResult, i, tmpVal)) {
356 JSValueRef error = JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), JSWebAPIErrorFactory::UNKNOWN_ERROR, "platform exception");
357 callback->callErrorCallback(error);
362 callback->callSuccessCallback(jsResult);
364 JSValueRef error = JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), JSWebAPIErrorFactory::UNKNOWN_ERROR, "platform exception");
365 callback->callErrorCallback(error);
373 static int get_package_list_cb(pkgmgrinfo_pkginfo_h handle, void *user_data)
375 PackageInfoCallbackData *callback = (PackageInfoCallbackData *)user_data;
376 PackageInformation* pkgInfo = create_pkg_info(handle);
377 if (pkgInfo != NULL) {
378 callback->addPackageInfo(*pkgInfo);
381 LoggerE("Fail to get pkgInfo");
386 static void getThreadCB(void *data, Ecore_Thread *thread)
388 PackageInfoCallbackData *callback = (PackageInfoCallbackData *)data;
390 int ret = pkgmgrinfo_pkginfo_get_list(get_package_list_cb, data);
391 if (ret != PMINFO_R_OK) {
392 LoggerE("Fail to get package info");
393 callback->setExceptionCode(WrtDeviceApis::Commons::ExceptionCodes::PlatformException);
396 // the operation of ecore_thread_run() is not normal. (the finish callback is not called from main thread.)
397 // so, add complete callback to gmainloop explicitly.
398 g_idle_add(getCompleteCB, data);
402 static void package_event_cb(app_manger_event_type_e event_type, const char *package, void *user_data)
404 PackageInfoEventCallback *eventCB = (PackageInfoEventCallback *)user_data;
407 case APP_MANAGER_EVENT_INSTALLED: {
408 pkgmgrinfo_pkginfo_h handle;
409 int ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle);
410 if (ret != PMINFO_R_OK) {
411 LoggerE("fail to find pkg info with given pkg");
412 // Do not throw exception. No one can handle exception because this code is called from async callback.
413 //throw NotFoundException("Can't find given package");
417 PackageInformation* pkgInfo = create_pkg_info(handle);
418 pkgmgrinfo_appinfo_destroy_appinfo(handle);
420 if (pkgInfo == NULL) {
421 LoggerE("Fail to get pkg info. skip callback call");
423 CallbackUserData *callback = eventCB->getOnInstalled();
425 callback->callSuccessCallback(JSPackageInformation::createJSObject(callback->getContext(), pkgInfo));
430 case APP_MANAGER_EVENT_UNINSTALLED: {
431 CallbackUserData *callback = eventCB->getOnUninstalled();
433 Converter converter(callback->getContext());
434 callback->callSuccessCallback(converter.toJSValueRef(package));
438 case APP_MANAGER_EVENT_UPDATED: {
439 pkgmgrinfo_pkginfo_h handle;
440 int ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle);
441 if (ret != PMINFO_R_OK) {
442 // Do not throw exception. No one can handle exception because this code is called from async callback.
443 //throw NotFoundException("Can't find given package");
447 PackageInformation* pkgInfo = create_pkg_info(handle);
448 pkgmgrinfo_appinfo_destroy_appinfo(handle);
450 if (pkgInfo == NULL) {
451 LoggerE("Fail to get pkg info. skip callback call");
453 CallbackUserData *callback = eventCB->getOnUpdated();
455 callback->callSuccessCallback(JSPackageInformation::createJSObject(callback->getContext(), pkgInfo));
461 LoggerE("Fail!! Unknown event type is entered : " << event_type);
468 static int app_list_changed_cb_broker(int id, const char *type, const char *package, const char *key, const char *val, const void *msg, void *data)
470 static app_manger_event_type_e event_type;
472 if (!strcasecmp(key, "start"))
475 if (!strcasecmp(val, "install"))
477 event_type = APP_MANAGER_EVENT_INSTALLED;
479 else if (!strcasecmp(val, "uninstall"))
481 event_type = APP_MANAGER_EVENT_UNINSTALLED;
483 else if (!strcasecmp(val, "update"))
485 event_type = APP_MANAGER_EVENT_UPDATED;
488 else if (!strcasecmp(key, "end") && !strcasecmp(val, "ok"))
493 package_event_cb(event_type, package, data);
495 // Check whether handler is freed in the callback function or not.
496 // if freed, return error code to avoid iteration of callback function. (core platform side)
497 PackageInfoEventCallback * callback = (PackageInfoEventCallback *)data;
498 pkgmgr_client ** handler_p = callback->getEventHandler();
499 if (*handler_p == NULL) {
500 LoggerE("handler is NULL");
503 LoggerE("handler is not NULL");
511 void install_request_cb(int id, const char *type, const char *package,
512 package_manager_event_type_e event_type,
513 package_manager_event_state_e event_state,
515 package_manager_error_e error,
518 PackageInstallEventCallback *callback = (PackageInstallEventCallback *)user_data;
519 JSContextRef context = callback->getContext();;
521 switch (event_state) {
522 case PACAKGE_MANAGER_EVENT_STATE_COMPLETED: {
523 if (callback->getOnComplete()) {
524 Converter converter(context);
525 callback->getOnComplete()->callSuccessCallback(converter.toJSValueRef(package));
528 LoggerD("destroy client handle");
529 // this api is not supported from platform.
530 //package_manager_request_destroy(callback->getHandle());
531 package_manager_client_destroy(callback->getHandle());
532 callback->setHandle(NULL);
534 //clean-up callback object
539 case PACAKGE_MANAGER_EVENT_STATE_FAILED: {
540 JSValueRef jsError = NULL;
541 if (error == PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE) {
542 jsError = JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::NOT_FOUND_ERROR,"given package is not found");
544 jsError = JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::UNKNOWN_ERROR,"platform exception");
547 if (callback->getOnError()) {
548 callback->getOnError()->callSuccessCallback(jsError);
551 LoggerD("destroy client handle");
552 // this api is not supported from platform.
553 //package_manager_request_destroy(callback->getHandle());
554 package_manager_client_destroy(callback->getHandle());
555 callback->setHandle(NULL);
557 //clean-up callback object
562 case PACAKGE_MANAGER_EVENT_STATE_STARTED:
563 case PACAKGE_MANAGER_EVENT_STATE_PROCESSING: {
564 if (callback->getOnProgress()) {
565 Converter converter(context);
566 JSValueRef args[2] = {converter.toJSValueRef(package), converter.toJSValueRef(progress)};
567 callback->getOnProgress()->callSuccessCallback(2, args);
572 JSValueRef error = JSWebAPIErrorFactory::makeErrorObject(context, JSWebAPIErrorFactory::UNKNOWN_ERROR,"platform exception");
573 if (callback->getOnError()) {
574 callback->getOnError()->callSuccessCallback(error);
576 LoggerD("destroy client handle");
577 // this api is not supported from platform.
578 //package_manager_request_destroy(callback->getHandle());
579 package_manager_client_destroy(callback->getHandle());
580 callback->setHandle(NULL);
582 //clean-up callback object
590 static string ltrim(const string s)
594 for (i = str.begin(); i != str.end(); i++) {
599 if (i == str.end()) {
602 str.erase(str.begin(), i);
608 static string convertUriToPath(const string str)
611 string schema ("file://");
612 string _str = ltrim(str);
614 string _schema = _str.substr(0,schema.size());
615 if(_schema == schema) {
616 result = _str.substr(schema.size());
624 void PackageManager::install(string pkgPath, PackageInstallEventCallback* callback)
628 package_manager_request_h request_h;
629 JSContextRef globalCtx = callback->getContext();
630 CallbackUserData* errCallback = callback->getOnError();
632 ret = package_manager_request_create(&request_h);
633 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
636 JSWebAPIErrorFactory::makeErrorObject(globalCtx, JSWebAPIErrorFactory::UNKNOWN_ERROR, "Platform Error");
637 errCallback->callSuccessCallback(error);
643 ret = package_manager_request_install(request_h, convertUriToPath(pkgPath).c_str(), &id);
644 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
647 JSWebAPIErrorFactory::makeErrorObject(globalCtx, JSWebAPIErrorFactory::NOT_FOUND_ERROR, "Not proper file");
648 errCallback->callSuccessCallback(error);
654 callback->setHandle(request_h);
656 ret = package_manager_request_set_event_cb(request_h, install_request_cb, callback);
657 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
660 JSWebAPIErrorFactory::makeErrorObject(globalCtx, JSWebAPIErrorFactory::UNKNOWN_ERROR, "Platform Error");
661 errCallback->callSuccessCallback(error);
668 void PackageManager::uninstall(string pkgPath, PackageInstallEventCallback* callback)
672 package_manager_request_h request_h;
673 JSContextRef globalCtx = callback->getContext();
674 CallbackUserData* errCallback = callback->getOnError();
676 ret = package_manager_request_create(&request_h);
677 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
680 JSWebAPIErrorFactory::makeErrorObject(globalCtx, JSWebAPIErrorFactory::UNKNOWN_ERROR, "Platform Error");
681 errCallback->callSuccessCallback(error);
683 //clean-up callback object
688 ret = package_manager_request_uninstall(request_h, pkgPath.c_str(), &id);
689 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
692 JSWebAPIErrorFactory::makeErrorObject(globalCtx, JSWebAPIErrorFactory::NOT_FOUND_ERROR, "Not proper file");
693 // TODO: how can I handle about uninstallable package???
694 errCallback->callSuccessCallback(error);
696 //clean-up callback object
701 callback->setHandle(request_h);
703 ret = package_manager_request_set_event_cb(request_h, install_request_cb, callback);
704 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
707 JSWebAPIErrorFactory::makeErrorObject(globalCtx, JSWebAPIErrorFactory::UNKNOWN_ERROR, "Platform Error");
708 errCallback->callSuccessCallback(error);
710 //clean-up callback object
717 PackageInformation* PackageManager::getPackageInfo(string pkgId)
719 if (pkgId.empty() || !pkgId.compare("null")) {
722 int ret = get_current_pkg_id(&pkg_id);
723 if((ret != APP_MANAGER_ERROR_NONE) || (pkg_id == NULL)) {
724 LoggerE("Can not get app id from current pid");
725 throw NotFoundException("Can't find given package");
731 pkgmgrinfo_pkginfo_h handle;
732 int ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &handle);
733 if (ret != PMINFO_R_OK) {
734 throw NotFoundException("Can't find given package");
737 PackageInformation* pkgInfo = create_pkg_info(handle);
738 pkgmgrinfo_appinfo_destroy_appinfo(handle);
740 if (pkgInfo == NULL) {
741 throw UnknownException("Can't get pkg info from given package");
748 void PackageManager::getPackagesInfo(PackageInfoCallbackData *user_data)
750 // getting info of all package from other thread. the result callback will be called on main thread
751 ecore_thread_run(getThreadCB, NULL, NULL, user_data);
755 void PackageManager::setPackageInfoEventListener(PackageInfoEventCallback * eventCB)
757 if (m_manager_handle == NULL) {
758 m_manager_handle = pkgmgr_client_new(PC_LISTENING);
759 if (m_manager_handle == NULL) {
760 throw UnknownException("Fail to create package manager handle");
764 eventCB->setEventHandler(&m_manager_handle);
766 pkgmgr_client_listen_status(m_manager_handle, app_list_changed_cb_broker, eventCB);
769 void PackageManager::unsetPackageInfoEventListener()
771 if (m_manager_handle == NULL) {
772 LoggerE("no package manager handle registered");
776 pkgmgr_client_free(m_manager_handle);
777 m_manager_handle = NULL;
780 PackageManager* PackageManager::getInstance()
782 static PackageManager instance;
786 void PackageManager::setCurrentAppId(string appId)
788 m_curr_app_id = appId;
791 string PackageManager::getCurrentAppId() const
793 return m_curr_app_id;
796 PackageManager::PackageManager()
800 PackageManager::~PackageManager()
802 if (m_manager_handle != NULL) {
803 pkgmgr_client_free(m_manager_handle);
804 m_manager_handle = NULL;
812 void PackageManager::move(string pkgPath, string target, PackageInstallEventCallback* callback)
815 package_manager_move_type_e type = PACAKGE_MANAGER_REQUEST_MOVE_TO_INTERNAL;
817 if (target.compare("INTERNAL") == 0) {
818 type = PACAKGE_MANAGER_REQUEST_MOVE_TO_INTERNAL;
820 type = PACAKGE_MANAGER_REQUEST_MOVE_TO_EXTERNAL;
822 // compare current storage and target storage
824 package_manager_request_h request_h;
826 ret = package_manager_request_create(&request_h);
827 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
828 ThrowMsg(PlatformException, "Unknow exception is occured!!");
831 ret = package_manager_request_move(request_h, pkgPath.c_str(), type);
832 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
833 ThrowMsg(PlatformException, "Unknow exception is occured!!");
836 callback->setHandle(request_h);
838 ret = package_manager_request_set_event_cb(request_h, install_request_cb, callback);
839 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
840 ThrowMsg(PlatformException, "Unknow exception is occured!!");
844 bool PackageManager::isInstalled(string pkgId)
846 package_info_h handle;
849 ret = package_manager_get_package_info(pkgId.c_str(), &handle);
850 if (ret == PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE) {
852 } else if (ret == PACKAGE_MANAGER_ERROR_NONE) {
853 // TODO: Should I exception handling while destory handle? what should I do for that time?
854 package_info_destroy(handle);
857 ThrowMsg(PlatformException, "Unknow exception is occured!!");
861 string PackageManager::getPackageIdFromAppId(string appId)
867 ret = package_manager_get_package_id_by_app_id(appId.c_str(), &pkg_id);
868 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
869 ThrowMsg(NotFoundException, "Not found pkg");