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 <JSTizenExceptionFactory.h>
21 #include <JSTizenException.h>
22 #include <GlobalContextManager.h>
23 #include <PlatformException.h>
25 // to get package name by appid
26 #include <app_manager.h>
28 // To get cert information from package
29 #include <package_manager.h>
30 #include <package_info.h>
32 // To get app size and installed time
33 #include <pkgmgr-info.h>
35 // To use ecore_thread
38 #include "PackageManager.h"
39 #include "PackageInformation.h"
40 #include "JSPackageInformation.h"
43 using namespace WrtDeviceApis::Commons;
44 using namespace WrtDeviceApis::CommonsJavaScript;
45 using namespace DeviceAPI::Common;
51 int package_manager_client_destroy(package_manager_request_h request);
58 PackageInfoCallbackData::PackageInfoCallbackData(JSContextRef globalCtx):
59 CallbackUserData(globalCtx)
61 m_exceptionCode = WrtDeviceApis::Commons::ExceptionCodes::None;
64 PackageInfoCallbackData::~PackageInfoCallbackData()
66 // TODO: Should I clear pkgInfos?
69 vector<PackageInformation> PackageInfoCallbackData::getPackageInfoList()
75 void PackageInfoCallbackData::addPackageInfo(PackageInformation pkgInfo)
77 m_pkgInfos.push_back(pkgInfo);
81 void PackageInfoCallbackData::setExceptionCode(ExceptionCodes::Enumeration exceptionCode)
83 m_exceptionCode = exceptionCode;
86 ExceptionCodes::Enumeration PackageInfoCallbackData::getExceptionCode() const
88 return m_exceptionCode;
91 PackageInfoEventCallback::PackageInfoEventCallback(CallbackUserData* oninstalled, CallbackUserData* onupdated, CallbackUserData* onuninstalled)
93 m_oninstalled = oninstalled;
94 m_onupdated = onupdated;
95 m_onuninstalled = onuninstalled;
99 PackageInfoEventCallback::~PackageInfoEventCallback()
102 delete m_oninstalled;
108 delete m_onuninstalled;
111 CallbackUserData* PackageInfoEventCallback::getOnInstalled()
113 return m_oninstalled;
116 CallbackUserData* PackageInfoEventCallback::getOnUpdated()
121 CallbackUserData* PackageInfoEventCallback::getOnUninstalled()
123 return m_onuninstalled;
126 pkgmgr_client** PackageInfoEventCallback::getEventHandler()
131 void PackageInfoEventCallback::setEventHandler(pkgmgr_client **handler)
133 m_handle_p = handler;
136 PackageInstallEventCallback::PackageInstallEventCallback(JSContextRef globalCtx, CallbackUserData* onprogress, CallbackUserData* oncomplete, CallbackUserData* onerror)
138 m_context = globalCtx;
139 m_onprogress = onprogress;
140 m_oncomplete = oncomplete;
143 m_request_handle = NULL;
146 PackageInstallEventCallback::~PackageInstallEventCallback()
148 if (m_request_handle != NULL) {
149 LoggerD("destroy client handle");
150 //package_manager_request_destroy(m_request_handle);
151 package_manager_client_destroy(m_request_handle);
164 CallbackUserData* PackageInstallEventCallback::getOnProgress()
169 CallbackUserData* PackageInstallEventCallback::getOnComplete()
174 CallbackUserData* PackageInstallEventCallback::getOnError()
179 JSContextRef PackageInstallEventCallback::getContext()
184 void PackageInstallEventCallback::setHandle(package_manager_request_h handle)
186 m_request_handle = handle;
189 package_manager_request_h PackageInstallEventCallback::getHandle()
191 return m_request_handle;
194 static int get_current_pkg_id(char** pkg_id)
196 LoggerD("get_current_pkg_id enter");
197 int parent_pid = getppid();
198 LoggerD("parent pid : " << parent_pid);
202 int ret = app_manager_get_app_id(parent_pid, &app_id);
203 if ((ret != APP_MANAGER_ERROR_NONE) || (app_id == NULL)) {
204 LoggerD("Cannot get app id from pid : " << parent_pid);
207 LoggerD("app_id : " << app_id);
210 ret = app_manager_get_app_info(app_id, &handle);
211 if (ret != APP_MANAGER_ERROR_NONE) {
212 LoggerD("Fail to get appinfo by " << app_id);
216 ret = app_info_get_package(handle, pkg_id);
217 if ((ret != APP_MANAGER_ERROR_NONE) || (*pkg_id == NULL)) {
218 LoggerD("Fail to get pkg_id by " << app_id);
222 ret = app_info_destroy(handle);
223 if (ret != APP_MANAGER_ERROR_NONE) {
224 LoggerD("Fail to get destory appinfo");
231 static bool app_callback(package_info_app_component_type_e comp_type, const char *app_id, void *user_data)
233 //LoggerD("app_callback enter : " << app_id);
234 PackageInformation* pkgInfo = (PackageInformation*)user_data;
235 pkgInfo->m_appIds.push_back(app_id);
239 static PackageInformation* create_pkg_info(pkgmgrinfo_pkginfo_h handle)
243 PackageInformation *pkgInfo = new PackageInformation();
247 char* iconPath = NULL;
248 char* version = NULL;
251 int lastModified = 0;
254 char* description = NULL;
255 vector<string> appIds;
258 ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &id);
259 if ((ret != PMINFO_R_OK) || (id == NULL)) {
260 LoggerD("Fail to get id. return NULL.");
267 ret = pkgmgrinfo_pkginfo_get_label(handle, &name);
268 if ((ret != PMINFO_R_OK) || (name == NULL)) {
269 LoggerD("Fail to get labe");
271 pkgInfo->m_name = name;
274 ret = pkgmgrinfo_pkginfo_get_icon(handle, &iconPath);
275 if ((ret != PMINFO_R_OK) || (iconPath == NULL)) {
276 LoggerD("Fail to get iconPath");
278 pkgInfo->m_iconPath = iconPath;
281 ret = pkgmgrinfo_pkginfo_get_version(handle, &version);
282 if ((ret != PMINFO_R_OK) || (version == NULL)) {
283 LoggerD("Fail to get version");
285 pkgInfo->m_version = version;
288 ret = pkgmgrinfo_pkginfo_get_total_size(handle, &totalSize);
289 if (ret != PMINFO_R_OK) {
290 LoggerD("Fail to get totalSize");
292 pkgInfo->m_totalSize = totalSize;
295 ret = pkgmgrinfo_pkginfo_get_data_size(handle, &dataSize);
296 if (ret != PMINFO_R_OK) {
297 LoggerD("Fail to get dataSize");
299 pkgInfo->m_dataSize = dataSize;
302 ret = pkgmgrinfo_pkginfo_get_installed_time(handle, &lastModified);
303 if (ret != PMINFO_R_OK) {
304 LoggerD("Fail to get lastModified");
306 pkgInfo->m_lastModified = lastModified;
309 ret = pkgmgrinfo_pkginfo_get_type(handle, &type);
310 if ((ret != PMINFO_R_OK) || (type == NULL)) {
311 LoggerD("Fail to get type");
313 pkgInfo->m_type = type;
316 ret = pkgmgrinfo_pkginfo_get_author_name(handle, &author);
317 if ((ret != PMINFO_R_OK) || (author == NULL)) {
318 LoggerD("Fail to get author");
320 pkgInfo->m_author = author;
323 ret = pkgmgrinfo_pkginfo_get_description(handle, &description);
324 if ((ret != PMINFO_R_OK) || (description == NULL)) {
325 LoggerD("Fail to get description");
327 pkgInfo->m_description = description;
330 package_info_h package_info;
332 ret = package_manager_get_package_info(id, &package_info);
333 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
334 LoggerD("Cannot create package info by : " << id);
339 ret = package_info_foreach_app_from_package(package_info, PACKAGE_INFO_ALLAPP, app_callback, (void*)pkgInfo);
340 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
341 LoggerD("failed while getting appids");
344 ret = package_info_destroy(package_info);
345 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
346 LoggerD("Cannot destroy package info");
349 // REMARK: do not destroy handle. because handle is comes from outside!!
353 static gboolean getCompleteCB(void *data)
357 PackageInfoCallbackData *callback = (PackageInfoCallbackData *)data;
358 JSContextRef context = callback->getContext();
360 if (callback->getExceptionCode() == WrtDeviceApis::Commons::ExceptionCodes::None) {
361 vector<PackageInformation> pkgInfoList = callback->getPackageInfoList();
363 JSObjectRef jsResult = JSCreateArrayObject(context, 0, NULL);
364 if (jsResult == NULL) {
365 JSValueRef error = JSTizenExceptionFactory::makeErrorObject(callback->getContext(), JSTizenException::UNKNOWN_ERROR, "platform exception");
366 callback->callErrorCallback(error);
370 for (std::size_t i = 0; i < pkgInfoList.size(); ++i) {
371 JSValueRef tmpVal = JSPackageInformation::createJSObject(context, &pkgInfoList[i]);
372 if (!JSSetArrayElement(context, jsResult, i, tmpVal)) {
373 JSValueRef error = JSTizenExceptionFactory::makeErrorObject(callback->getContext(), JSTizenException::UNKNOWN_ERROR, "platform exception");
374 callback->callErrorCallback(error);
379 callback->callSuccessCallback(jsResult);
382 JSValueRef error = JSTizenExceptionFactory::makeErrorObject(callback->getContext(), JSTizenException::UNKNOWN_ERROR, "platform exception");
383 callback->callErrorCallback(error);
386 // TODO: cleanup each packageInformation items
392 static int get_package_list_cb(pkgmgrinfo_pkginfo_h handle, void *user_data)
394 //LoggerD("entered");
395 PackageInfoCallbackData *callback = (PackageInfoCallbackData *)user_data;
396 PackageInformation* pkgInfo = create_pkg_info(handle);
397 if (pkgInfo != NULL) {
398 callback->addPackageInfo(*pkgInfo);
401 LoggerE("Fail to get pkgInfo");
406 static void getThreadCB(void *data, Ecore_Thread *thread)
410 PackageInfoCallbackData *callback = (PackageInfoCallbackData *)data;
412 int ret = pkgmgrinfo_pkginfo_get_list(get_package_list_cb, data);
413 if (ret != PMINFO_R_OK) {
414 LoggerD("Fail to get package info");
415 callback->setExceptionCode(WrtDeviceApis::Commons::ExceptionCodes::PlatformException);
418 // the operation of ecore_thread_run() is not normal. (the finish callback is not called from main thread.)
419 // so, add complete callback to gmainloop explicitly.
420 g_idle_add(getCompleteCB, data);
424 static void package_event_cb(app_manger_event_type_e event_type, const char *package, void *user_data)
426 PackageInfoEventCallback *eventCB = (PackageInfoEventCallback *)user_data;
429 case APP_MANAGER_EVENT_INSTALLED: {
430 pkgmgrinfo_pkginfo_h handle;
431 int ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle);
432 if (ret != PMINFO_R_OK) {
433 LoggerD("fail to find pkg info with given pkg : " << package);
434 // Do not throw exception. No one can handle exception because this code is called from async callback.
435 //throw NotFoundException("Can't find given package");
439 PackageInformation* pkgInfo = create_pkg_info(handle);
440 pkgmgrinfo_appinfo_destroy_appinfo(handle);
442 if (pkgInfo == NULL) {
443 LoggerD("Fail to get pkg info. skip callback call for pkgid " << package);
445 CallbackUserData *callback = eventCB->getOnInstalled();
447 callback->callSuccessCallback(JSPackageInformation::createJSObject(callback->getContext(), pkgInfo));
452 case APP_MANAGER_EVENT_UNINSTALLED: {
453 LoggerD("uninstall : " << package);
454 CallbackUserData *callback = eventCB->getOnUninstalled();
456 Converter converter(callback->getContext());
457 callback->callSuccessCallback(converter.toJSValueRef(package));
461 case APP_MANAGER_EVENT_UPDATED: {
462 pkgmgrinfo_pkginfo_h handle;
463 int ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle);
464 if (ret != PMINFO_R_OK) {
465 // Do not throw exception. No one can handle exception because this code is called from async callback.
466 //throw NotFoundException("Can't find given package");
470 PackageInformation* pkgInfo = create_pkg_info(handle);
471 pkgmgrinfo_appinfo_destroy_appinfo(handle);
473 if (pkgInfo == NULL) {
474 LoggerD("Fail to get pkg info. skip callback call for pkgid " << package);
476 CallbackUserData *callback = eventCB->getOnUpdated();
478 callback->callSuccessCallback(JSPackageInformation::createJSObject(callback->getContext(), pkgInfo));
484 LoggerD("Fail!! Unknown event type is entered : " << event_type);
491 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)
493 static app_manger_event_type_e event_type;
495 if (!strcasecmp(key, "start"))
498 if (!strcasecmp(val, "install"))
500 event_type = APP_MANAGER_EVENT_INSTALLED;
502 else if (!strcasecmp(val, "uninstall"))
504 event_type = APP_MANAGER_EVENT_UNINSTALLED;
506 else if (!strcasecmp(val, "update"))
508 event_type = APP_MANAGER_EVENT_UPDATED;
511 else if (!strcasecmp(key, "end") && !strcasecmp(val, "ok"))
516 package_event_cb(event_type, package, data);
518 // Check whether handler is freed in the callback function or not.
519 // if freed, return error code to avoid iteration of callback function. (core platform side)
520 PackageInfoEventCallback * callback = (PackageInfoEventCallback *)data;
521 pkgmgr_client ** handler_p = callback->getEventHandler();
522 if (*handler_p == NULL) {
523 LoggerD("handler is NULL");
526 LoggerD("handler is not NULL");
534 void install_request_cb(int id, const char *type, const char *package,
535 package_manager_event_type_e event_type,
536 package_manager_event_state_e event_state,
538 package_manager_error_e error,
541 LoggerD("install_request_cb ");
542 PackageInstallEventCallback *callback = (PackageInstallEventCallback *)user_data;
543 JSContextRef context = callback->getContext();;
545 switch (event_state) {
546 case PACAKGE_MANAGER_EVENT_STATE_COMPLETED: {
547 if (callback->getOnComplete()) {
548 Converter converter(context);
549 callback->getOnComplete()->callSuccessCallback(converter.toJSValueRef(package));
552 LoggerD("destroy client handle");
553 // this api is not supported from platform.
554 //package_manager_request_destroy(callback->getHandle());
555 package_manager_client_destroy(callback->getHandle());
556 callback->setHandle(NULL);
558 //clean-up callback object
563 case PACAKGE_MANAGER_EVENT_STATE_FAILED: {
564 JSValueRef jsError = NULL;
565 if (error == PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE) {
566 jsError = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::NOT_FOUND_ERROR,"given package is not found");
568 jsError = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR,"platform exception");
571 if (callback->getOnError()) {
572 callback->getOnError()->callSuccessCallback(jsError);
575 LoggerD("destroy client handle");
576 // this api is not supported from platform.
577 //package_manager_request_destroy(callback->getHandle());
578 package_manager_client_destroy(callback->getHandle());
579 callback->setHandle(NULL);
581 //clean-up callback object
586 case PACAKGE_MANAGER_EVENT_STATE_STARTED:
587 case PACAKGE_MANAGER_EVENT_STATE_PROCESSING: {
588 if (callback->getOnProgress()) {
589 Converter converter(context);
590 JSValueRef args[2] = {converter.toJSValueRef(package), converter.toJSValueRef(progress)};
591 callback->getOnProgress()->callSuccessCallback(2, args);
596 JSValueRef error = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR,"platform exception");
597 if (callback->getOnError()) {
598 callback->getOnError()->callSuccessCallback(error);
600 LoggerD("destroy client handle");
601 // this api is not supported from platform.
602 //package_manager_request_destroy(callback->getHandle());
603 package_manager_client_destroy(callback->getHandle());
604 callback->setHandle(NULL);
606 //clean-up callback object
614 void PackageManager::install(string pkgPath, PackageInstallEventCallback* callback)
619 package_manager_request_h request_h;
620 JSContextRef globalCtx = callback->getContext();
621 CallbackUserData* errCallback = callback->getOnError();
623 ret = package_manager_request_create(&request_h);
624 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
627 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::UNKNOWN_ERROR, "Platform Error");
628 errCallback->callSuccessCallback(error);
634 ret = package_manager_request_install(request_h, pkgPath.c_str(), &id);
635 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
636 LoggerD("error : " << pkgPath);
639 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::NOT_FOUND_ERROR, "Not proper file");
640 errCallback->callSuccessCallback(error);
646 callback->setHandle(request_h);
648 ret = package_manager_request_set_event_cb(request_h, install_request_cb, callback);
649 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
652 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::UNKNOWN_ERROR, "Platform Error");
653 errCallback->callSuccessCallback(error);
660 void PackageManager::uninstall(string pkgPath, PackageInstallEventCallback* callback)
662 LoggerD("uninstall");
665 package_manager_request_h request_h;
666 JSContextRef globalCtx = callback->getContext();
667 CallbackUserData* errCallback = callback->getOnError();
669 ret = package_manager_request_create(&request_h);
670 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
673 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::UNKNOWN_ERROR, "Platform Error");
674 errCallback->callSuccessCallback(error);
676 //clean-up callback object
681 ret = package_manager_request_uninstall(request_h, pkgPath.c_str(), &id);
682 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
683 LoggerD("error : " << pkgPath);
686 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::NOT_FOUND_ERROR, "Not proper file");
687 // TODO: how can I handle about uninstallable package???
688 errCallback->callSuccessCallback(error);
690 //clean-up callback object
695 callback->setHandle(request_h);
697 ret = package_manager_request_set_event_cb(request_h, install_request_cb, callback);
698 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
701 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::UNKNOWN_ERROR, "Platform Error");
702 errCallback->callSuccessCallback(error);
704 //clean-up callback object
711 PackageInformation* PackageManager::getPackageInfo(string pkgId)
713 if (pkgId.empty() || !pkgId.compare("null")) {
716 int ret = get_current_pkg_id(&pkg_id);
717 if((ret != APP_MANAGER_ERROR_NONE) || (pkg_id == NULL)) {
718 LoggerE("Can not get app id from current pid (" << ret << ")");
719 throw NotFoundException("Can't find given package");
725 pkgmgrinfo_pkginfo_h handle;
726 int ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &handle);
727 if (ret != PMINFO_R_OK) {
728 throw NotFoundException("Can't find given package");
731 PackageInformation* pkgInfo = create_pkg_info(handle);
732 pkgmgrinfo_appinfo_destroy_appinfo(handle);
734 if (pkgInfo == NULL) {
735 throw UnknownException("Can't get pkg info from given package");
742 void PackageManager::getPackagesInfo(PackageInfoCallbackData *user_data)
746 // getting info of all package from other thread. the result callback will be called on main thread
747 ecore_thread_run(getThreadCB, NULL, NULL, user_data);
751 void PackageManager::setPackageInfoEventListener(PackageInfoEventCallback * eventCB)
755 if (m_manager_handle == NULL) {
756 m_manager_handle = pkgmgr_client_new(PC_LISTENING);
757 if (m_manager_handle == NULL) {
758 throw UnknownException("Fail to create package manager handle");
762 eventCB->setEventHandler(&m_manager_handle);
764 pkgmgr_client_listen_status(m_manager_handle, app_list_changed_cb_broker, eventCB);
767 void PackageManager::unsetPackageInfoEventListener()
771 if (m_manager_handle == NULL) {
772 LoggerD("no package manager handle registered");
776 pkgmgr_client_free(m_manager_handle);
777 m_manager_handle = NULL;
780 PackageManager* PackageManager::getInstance(){
781 LoggerD("enter to getInstance()");
782 static PackageManager instance;
786 PackageManager::PackageManager()
788 LoggerD("Create PackageManager");
791 PackageManager::~PackageManager()
793 LoggerD("Destroy PackageManager");
795 if (m_manager_handle != NULL) {
796 pkgmgr_client_free(m_manager_handle);
797 m_manager_handle = NULL;
805 void PackageManager::move(string pkgPath, string target, PackageInstallEventCallback* callback)
807 LoggerD("entered : " << pkgPath);
809 package_manager_move_type_e type = PACAKGE_MANAGER_REQUEST_MOVE_TO_INTERNAL;
811 if (target.compare("INTERNAL") == 0) {
812 type = PACAKGE_MANAGER_REQUEST_MOVE_TO_INTERNAL;
814 type = PACAKGE_MANAGER_REQUEST_MOVE_TO_EXTERNAL;
816 // compare current storage and target storage
818 package_manager_request_h request_h;
820 ret = package_manager_request_create(&request_h);
821 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
822 ThrowMsg(PlatformException, "Unknow exception is occured!!");
825 ret = package_manager_request_move(request_h, pkgPath.c_str(), type);
826 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
827 ThrowMsg(PlatformException, "Unknow exception is occured!!");
830 callback->setHandle(request_h);
832 ret = package_manager_request_set_event_cb(request_h, install_request_cb, callback);
833 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
834 ThrowMsg(PlatformException, "Unknow exception is occured!!");
838 bool PackageManager::isInstalled(string pkgId)
840 LoggerD("pkgId = " << pkgId);
841 package_info_h handle;
844 ret = package_manager_get_package_info(pkgId.c_str(), &handle);
845 if (ret == PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE) {
846 LoggerE("No patched package: " << pkgId);
848 } else if (ret == PACKAGE_MANAGER_ERROR_NONE) {
849 // TODO: Should I exception handling while destory handle? what should I do for that time?
850 package_info_destroy(handle);
853 ThrowMsg(PlatformException, "Unknow exception is occured!!");
857 string PackageManager::getPackageIdFromAppId(string appId)
859 LoggerD("appId = " << appId);
864 ret = package_manager_get_package_id_by_app_id(appId.c_str(), &pkg_id);
865 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
866 LoggerE("Error on get pkgId from appId : " << appId);
867 ThrowMsg(NotFoundException, "Not found pkg");