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.
21 #include <JSTizenExceptionFactory.h>
22 #include <JSTizenException.h>
23 #include <GlobalContextManager.h>
24 #include <PlatformException.h>
26 // to get package name by appid
27 #include <app_manager.h>
29 // To get cert information from package
30 #include <package_manager.h>
31 #include <package_info.h>
33 // To get app size and installed time
34 #include <pkgmgr-info.h>
36 // To use ecore_thread
39 #include "PackageManager.h"
40 #include "PackageInformation.h"
41 #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;
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;
126 PackageInstallEventCallback::PackageInstallEventCallback(JSContextRef globalCtx, CallbackUserData* onprogress, CallbackUserData* oncomplete, CallbackUserData* onerror)
128 m_context = globalCtx;
129 m_onprogress = onprogress;
130 m_oncomplete = oncomplete;
133 m_request_handle = NULL;
136 PackageInstallEventCallback::~PackageInstallEventCallback()
138 if (m_request_handle != NULL) {
139 LogDebug("destroy client handle");
140 //package_manager_request_destroy(m_request_handle);
141 package_manager_client_destroy(m_request_handle);
154 CallbackUserData* PackageInstallEventCallback::getOnProgress()
159 CallbackUserData* PackageInstallEventCallback::getOnComplete()
164 CallbackUserData* PackageInstallEventCallback::getOnError()
169 JSContextRef PackageInstallEventCallback::getContext()
174 void PackageInstallEventCallback::setHandle(package_manager_request_h handle)
176 m_request_handle = handle;
179 package_manager_request_h PackageInstallEventCallback::getHandle()
181 return m_request_handle;
184 static int get_current_pkg_id(char** pkg_id)
186 LogDebug("get_current_pkg_id enter");
187 int parent_pid = getppid();
188 LogDebug("parent pid : " << parent_pid);
192 int ret = app_manager_get_app_id(parent_pid, &app_id);
193 if ((ret != APP_MANAGER_ERROR_NONE) || (app_id == NULL)) {
194 LogDebug("Cannot get app id from pid : " << parent_pid);
197 LogDebug("app_id : " << app_id);
200 ret = app_manager_get_app_info(app_id, &handle);
201 if (ret != APP_MANAGER_ERROR_NONE) {
202 LogDebug("Fail to get appinfo by " << app_id);
206 ret = app_info_get_package(handle, pkg_id);
207 if ((ret != APP_MANAGER_ERROR_NONE) || (*pkg_id == NULL)) {
208 LogDebug("Fail to get pkg_id by " << app_id);
212 ret = app_info_destroy(handle);
213 if (ret != APP_MANAGER_ERROR_NONE) {
214 LogDebug("Fail to get destory appinfo");
221 static bool app_callback(package_info_app_component_type_e comp_type, const char *app_id, void *user_data)
223 //LogDebug("app_callback enter : " << app_id);
224 PackageInformation* pkgInfo = (PackageInformation*)user_data;
225 pkgInfo->m_appIds.push_back(app_id);
229 static PackageInformation* create_pkg_info(pkgmgrinfo_pkginfo_h handle)
233 PackageInformation *pkgInfo = new PackageInformation();
237 char* iconPath = NULL;
238 char* version = NULL;
241 int lastModified = 0;
244 char* description = NULL;
245 vector<string> appIds;
248 ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &id);
249 if ((ret != PMINFO_R_OK) || (id == NULL)) {
250 LogDebug("Fail to get id");
255 ret = pkgmgrinfo_pkginfo_get_label(handle, &name);
256 if ((ret != PMINFO_R_OK) || (name == NULL)) {
257 LogDebug("Fail to get labe");
259 pkgInfo->m_name = name;
262 ret = pkgmgrinfo_pkginfo_get_icon(handle, &iconPath);
263 if ((ret != PMINFO_R_OK) || (iconPath == NULL)) {
264 LogDebug("Fail to get iconPath");
266 pkgInfo->m_iconPath = iconPath;
269 ret = pkgmgrinfo_pkginfo_get_version(handle, &version);
270 if ((ret != PMINFO_R_OK) || (version == NULL)) {
271 LogDebug("Fail to get version");
273 pkgInfo->m_version = version;
276 ret = pkgmgrinfo_pkginfo_get_total_size(handle, &totalSize);
277 if (ret != PMINFO_R_OK) {
278 LogDebug("Fail to get totalSize");
280 pkgInfo->m_totalSize = totalSize;
283 ret = pkgmgrinfo_pkginfo_get_data_size(handle, &dataSize);
284 if (ret != PMINFO_R_OK) {
285 LogDebug("Fail to get dataSize");
287 pkgInfo->m_dataSize = dataSize;
290 ret = pkgmgrinfo_pkginfo_get_installed_time(handle, &lastModified);
291 if (ret != PMINFO_R_OK) {
292 LogDebug("Fail to get lastModified");
294 pkgInfo->m_lastModified = lastModified;
297 ret = pkgmgrinfo_pkginfo_get_type(handle, &type);
298 if ((ret != PMINFO_R_OK) || (type == NULL)) {
299 LogDebug("Fail to get type");
301 pkgInfo->m_type = type;
304 ret = pkgmgrinfo_pkginfo_get_author_name(handle, &author);
305 if ((ret != PMINFO_R_OK) || (author == NULL)) {
306 LogDebug("Fail to get author");
308 pkgInfo->m_author = author;
311 ret = pkgmgrinfo_pkginfo_get_description(handle, &description);
312 if ((ret != PMINFO_R_OK) || (description == NULL)) {
313 LogDebug("Fail to get description");
315 pkgInfo->m_description = description;
318 package_info_h package_info;
320 ret = package_manager_get_package_info(id, &package_info);
321 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
322 LogDebug("Cannot create package info by : " << id);
325 ret = package_info_foreach_app_from_package(package_info, PACKAGE_INFO_ALLAPP, app_callback, (void*)pkgInfo);
326 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
327 LogDebug("failed while getting appids");
330 ret = package_info_destroy(package_info);
331 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
332 LogDebug("Cannot destroy package info");
335 // REMARK: do not destroy handle. because handle is comes from outside!!
339 static gboolean getCompleteCB(void *data)
343 PackageInfoCallbackData *callback = (PackageInfoCallbackData *)data;
344 JSContextRef context = callback->getContext();
346 if (callback->getExceptionCode() == WrtDeviceApis::Commons::ExceptionCodes::None) {
347 vector<PackageInformation> pkgInfoList = callback->getPackageInfoList();
349 JSObjectRef jsResult = JSCreateArrayObject(context, 0, NULL);
350 if (jsResult == NULL) {
351 JSValueRef error = JSTizenExceptionFactory::makeErrorObject(callback->getContext(), JSTizenException::UNKNOWN_ERROR, "platform exception");
352 callback->callErrorCallback(error);
356 for (std::size_t i = 0; i < pkgInfoList.size(); ++i) {
357 JSValueRef tmpVal = JSPackageInformation::createJSObject(context, &pkgInfoList[i]);
358 if (!JSSetArrayElement(context, jsResult, i, tmpVal)) {
359 JSValueRef error = JSTizenExceptionFactory::makeErrorObject(callback->getContext(), JSTizenException::UNKNOWN_ERROR, "platform exception");
360 callback->callErrorCallback(error);
365 callback->callSuccessCallback(jsResult);
368 JSValueRef error = JSTizenExceptionFactory::makeErrorObject(callback->getContext(), JSTizenException::UNKNOWN_ERROR, "platform exception");
369 callback->callErrorCallback(error);
372 // TODO: cleanup each packageInformation items
378 static int get_package_list_cb(pkgmgrinfo_pkginfo_h handle, void *user_data)
380 //LogDebug("entered");
381 PackageInfoCallbackData *callback = (PackageInfoCallbackData *)user_data;
382 PackageInformation* pkgInfo = create_pkg_info(handle);
383 if (pkgInfo != NULL) {
384 callback->addPackageInfo(*pkgInfo);
387 LogError("Fail to get pkgInfo");
392 static void getThreadCB(void *data, Ecore_Thread *thread)
396 PackageInfoCallbackData *callback = (PackageInfoCallbackData *)data;
398 int ret = pkgmgrinfo_pkginfo_get_list(get_package_list_cb, data);
399 if (ret != PMINFO_R_OK) {
400 LogDebug("Fail to get package info");
401 callback->setExceptionCode(WrtDeviceApis::Commons::ExceptionCodes::PlatformException);
404 // the operation of ecore_thread_run() is not normal. (the finish callback is not called from main thread.)
405 // so, add complete callback to gmainloop explicitly.
406 g_idle_add(getCompleteCB, data);
409 static void package_event_cb(const char *type, const char *package,
410 package_manager_event_type_e event_type,
411 package_manager_event_state_e event_state,
413 package_manager_error_e error,
416 LogDebug("event callback is called!!! : event_state " << event_state << " : package " << package << " : event_type " << event_type );
417 if (event_state == PACAKGE_MANAGER_EVENT_STATE_COMPLETED) {
418 PackageInfoEventCallback *eventCB = (PackageInfoEventCallback *)user_data;
421 case PACAKGE_MANAGER_EVENT_TYPE_INSTALL: {
422 pkgmgrinfo_pkginfo_h handle;
423 int ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle);
424 if (ret != PMINFO_R_OK) {
425 LogDebug("fail to find pkg info with given pkg : " << package);
426 // Do not throw exception. No one can handle exception because this code is called from async callback.
427 //throw NotFoundException("Can't find given package");
431 PackageInformation* pkgInfo = create_pkg_info(handle);
432 pkgmgrinfo_appinfo_destroy_appinfo(handle);
434 CallbackUserData *callback = eventCB->getOnInstalled();
436 callback->callSuccessCallback(JSPackageInformation::createJSObject(callback->getContext(), pkgInfo));
440 case PACAKGE_MANAGER_EVENT_TYPE_UNINSTALL: {
441 LogDebug("uninstall : " << package);
442 CallbackUserData *callback = eventCB->getOnUninstalled();
444 Converter converter(callback->getContext());
445 callback->callSuccessCallback(converter.toJSValueRef(package));
449 case PACAKGE_MANAGER_EVENT_TYPE_UPDATE: {
450 pkgmgrinfo_pkginfo_h handle;
451 int ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle);
452 if (ret != PMINFO_R_OK) {
453 // Do not throw exception. No one can handle exception because this code is called from async callback.
454 //throw NotFoundException("Can't find given package");
458 PackageInformation* pkgInfo = create_pkg_info(handle);
459 pkgmgrinfo_appinfo_destroy_appinfo(handle);
461 CallbackUserData *callback = eventCB->getOnUpdated();
463 callback->callSuccessCallback(JSPackageInformation::createJSObject(callback->getContext(), pkgInfo));
468 LogDebug("Fail!! Unknown event type is entered : " << event_type);
475 void install_request_cb(int id, const char *type, const char *package,
476 package_manager_event_type_e event_type,
477 package_manager_event_state_e event_state,
479 package_manager_error_e error,
482 LogDebug("install_request_cb ");
483 PackageInstallEventCallback *callback = (PackageInstallEventCallback *)user_data;
484 JSContextRef context = callback->getContext();;
486 switch (event_state) {
487 case PACAKGE_MANAGER_EVENT_STATE_COMPLETED: {
488 LogDebug("destroy client handle");
489 if (callback->getOnComplete()) {
490 Converter converter(context);
491 callback->getOnComplete()->callSuccessCallback(converter.toJSValueRef(package));
494 // this api is not supported from platform.
495 //package_manager_request_destroy(callback->getHandle());
496 package_manager_client_destroy(callback->getHandle());
498 //clean-up callback object
503 case PACAKGE_MANAGER_EVENT_STATE_FAILED: {
504 JSValueRef jsError = NULL;
505 if (error == PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE) {
506 jsError = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::NOT_FOUND_ERROR,"given package is not found");
508 jsError = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR,"platform exception");
511 if (callback->getOnError()) {
512 callback->getOnError()->callSuccessCallback(jsError);
515 LogDebug("destroy client handle");
516 // this api is not supported from platform.
517 //package_manager_request_destroy(callback->getHandle());
518 package_manager_client_destroy(callback->getHandle());
520 //clean-up callback object
525 case PACAKGE_MANAGER_EVENT_STATE_STARTED:
526 case PACAKGE_MANAGER_EVENT_STATE_PROCESSING: {
527 if (callback->getOnProgress()) {
528 Converter converter(context);
529 JSValueRef args[2] = {converter.toJSValueRef(package), converter.toJSValueRef(progress)};
530 callback->getOnProgress()->callSuccessCallback(2, args);
535 JSValueRef error = JSTizenExceptionFactory::makeErrorObject(context, JSTizenException::UNKNOWN_ERROR,"platform exception");
536 if (callback->getOnError()) {
537 callback->getOnError()->callSuccessCallback(error);
539 LogDebug("destroy client handle");
540 // this api is not supported from platform.
541 //package_manager_request_destroy(callback->getHandle());
542 package_manager_client_destroy(callback->getHandle());
544 //clean-up callback object
552 void PackageManager::install(string pkgPath, PackageInstallEventCallback* callback)
557 package_manager_request_h request_h;
558 JSContextRef globalCtx = callback->getContext();
559 CallbackUserData* errCallback = callback->getOnError();
561 ret = package_manager_request_create(&request_h);
562 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
565 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::UNKNOWN_ERROR, "Platform Error");
566 errCallback->callSuccessCallback(error);
571 ret = package_manager_request_install(request_h, pkgPath.c_str(), &id);
572 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
573 LogDebug("error : " << pkgPath);
576 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::NOT_FOUND_ERROR, "Not proper file");
577 errCallback->callSuccessCallback(error);
582 callback->setHandle(request_h);
584 ret = package_manager_request_set_event_cb(request_h, install_request_cb, callback);
585 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
588 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::UNKNOWN_ERROR, "Platform Error");
589 errCallback->callSuccessCallback(error);
595 void PackageManager::uninstall(string pkgPath, PackageInstallEventCallback* callback)
597 LogDebug("uninstall");
600 package_manager_request_h request_h;
601 JSContextRef globalCtx = callback->getContext();
602 CallbackUserData* errCallback = callback->getOnError();
604 ret = package_manager_request_create(&request_h);
605 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
608 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::UNKNOWN_ERROR, "Platform Error");
609 errCallback->callSuccessCallback(error);
611 //clean-up callback object
616 ret = package_manager_request_uninstall(request_h, pkgPath.c_str(), &id);
617 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
618 LogDebug("error : " << pkgPath);
621 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::NOT_FOUND_ERROR, "Not proper file");
622 // TODO: how can I handle about uninstallable package???
623 errCallback->callSuccessCallback(error);
625 //clean-up callback object
630 callback->setHandle(request_h);
632 ret = package_manager_request_set_event_cb(request_h, install_request_cb, callback);
633 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
636 JSTizenExceptionFactory::makeErrorObject(globalCtx, JSTizenException::UNKNOWN_ERROR, "Platform Error");
637 errCallback->callSuccessCallback(error);
639 //clean-up callback object
646 PackageInformation* PackageManager::getPackageInfo(string pkgId)
648 if (pkgId.empty() || !pkgId.compare("null")) {
651 int ret = get_current_pkg_id(&pkg_id);
652 if((ret != APP_MANAGER_ERROR_NONE) || (pkg_id == NULL)) {
653 LogError("Can not get app id from current pid (" << ret << ")");
654 throw NotFoundException("Can't find given package");
660 pkgmgrinfo_pkginfo_h handle;
661 int ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &handle);
662 if (ret != PMINFO_R_OK) {
663 throw NotFoundException("Can't find given package");
666 PackageInformation* pkgInfo = create_pkg_info(handle);
667 pkgmgrinfo_appinfo_destroy_appinfo(handle);
673 void PackageManager::getPackagesInfo(PackageInfoCallbackData *user_data)
677 // getting info of all package from other thread. the result callback will be called on main thread
678 ecore_thread_run(getThreadCB, NULL, NULL, user_data);
682 void PackageManager::setPackageInfoEventListener(PackageInfoEventCallback * eventCB)
687 if (m_manager_handle == NULL) {
688 ret = package_manager_create(&m_manager_handle);
689 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
690 throw UnknownException("Fail to create package manager handle");
694 ret = package_manager_set_event_cb(m_manager_handle, package_event_cb, eventCB);
695 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
696 throw UnknownException("Fail to set event cb");
700 void PackageManager::unsetPackageInfoEventListener()
705 if (m_manager_handle == NULL) {
706 LogDebug("no package manager handle registered");
710 ret = package_manager_unset_event_cb(m_manager_handle);
711 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
712 throw UnknownException("Fail to unset event cb");
715 ret = package_manager_destroy(m_manager_handle);
716 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
717 throw UnknownException("Fail to destroy package manager handle");
719 m_manager_handle = NULL;
723 PackageManager* PackageManager::getInstance(){
724 LogDebug("enter to getInstance()");
725 static PackageManager instance;
729 PackageManager::PackageManager()
731 LogDebug("Create PackageManager");
734 PackageManager::~PackageManager()
736 LogDebug("Destroy PackageManager");
737 if (m_manager_handle != NULL) {
738 package_manager_destroy(m_manager_handle);
745 void PackageManager::move(string pkgPath, string target, PackageInstallEventCallback* callback)
747 LogDebug("entered : " << pkgPath);
749 package_manager_move_type_e type = PACAKGE_MANAGER_REQUEST_MOVE_TO_INTERNAL;
751 if (target.compare("INTERNAL") == 0) {
752 type = PACAKGE_MANAGER_REQUEST_MOVE_TO_INTERNAL;
754 type = PACAKGE_MANAGER_REQUEST_MOVE_TO_EXTERNAL;
756 // compare current storage and target storage
758 package_manager_request_h request_h;
760 ret = package_manager_request_create(&request_h);
761 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
762 ThrowMsg(PlatformException, "Unknow exception is occured!!");
765 ret = package_manager_request_move(request_h, pkgPath.c_str(), type);
766 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
767 ThrowMsg(PlatformException, "Unknow exception is occured!!");
770 callback->setHandle(request_h);
772 ret = package_manager_request_set_event_cb(request_h, install_request_cb, callback);
773 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
774 ThrowMsg(PlatformException, "Unknow exception is occured!!");
778 bool PackageManager::isInstalled(string pkgId)
780 LogDebug("pkgId = " << pkgId);
781 package_info_h handle;
784 ret = package_manager_get_package_info(pkgId.c_str(), &handle);
785 if (ret == PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE) {
786 LogError("No patched package: " << pkgId);
788 } else if (ret == PACKAGE_MANAGER_ERROR_NONE) {
789 // TODO: Should I exception handling while destory handle? what should I do for that time?
790 package_info_destroy(handle);
793 ThrowMsg(PlatformException, "Unknow exception is occured!!");
797 string PackageManager::getPackageIdFromAppId(string appId)
799 LogDebug("appId = " << appId);
804 ret = package_manager_get_package_id_by_app_id(appId.c_str(), &pkg_id);
805 if (ret != PACKAGE_MANAGER_ERROR_NONE) {
806 LogError("Error on get pkgId from appId : " << appId);
807 ThrowMsg(NotFoundException, "Not found pkg");