From: Radoslaw Cybulski Date: Fri, 10 May 2019 07:07:45 +0000 (+0200) Subject: add clear_applications function to batch mode X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=05ac4d2e1280039783a93ad8c8edab80edb0f4f4;p=platform%2Fcore%2Faccessibility%2Funiversal-switch.git add clear_applications function to batch mode Change-Id: Iccc6f0b4b79582043834023f0e4b5ecdc76cdaa3 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 87da6180..fbf4ba38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ pkg_check_modules(pkgs REQUIRED atspi-2 capi-appfw-service-application capi-appfw-application + capi-appfw-app-manager capi-media-player capi-media-sound-manager capi-telephony @@ -32,6 +33,7 @@ pkg_check_modules(pkgs REQUIRED storage syspopup-caller tzsh-screensaver-service + rua ) # TODO remove cairo dependency, when there will be available screenshot service. diff --git a/org.tizen.universal-switch.xml b/org.tizen.universal-switch.xml index 586c7c4e..9cc120eb 100644 --- a/org.tizen.universal-switch.xml +++ b/org.tizen.universal-switch.xml @@ -18,6 +18,8 @@ http://tizen.org/privilege/telephony http://tizen.org/privilege/systemsettings.admin http://tizen.org/privilege/appmanager.launch + http://tizen.org/privilege/appmanager.kill + http://tizen.org/privilege/appmanager.kill.bgapp http://tizen.org/privilege/keygrab http://tizen.org/privilege/inputgenerator http://tizen.org/privilege/volume.set diff --git a/packaging/org.tizen.universal-switch.spec b/packaging/org.tizen.universal-switch.spec index f7b2cd15..ad7b264d 100644 --- a/packaging/org.tizen.universal-switch.spec +++ b/packaging/org.tizen.universal-switch.spec @@ -16,6 +16,7 @@ BuildRequires: tts BuildRequires: tts-devel BuildRequires: pkgconfig(capi-appfw-service-application) BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(capi-appfw-app-manager) BuildRequires: pkgconfig(capi-media-player) BuildRequires: pkgconfig(capi-media-sound-manager) BuildRequires: pkgconfig(capi-telephony) @@ -33,6 +34,8 @@ BuildRequires: pkgconfig(tzsh-quickpanel) BuildRequires: pkgconfig(cairo) BuildRequires: pkgconfig(storage) BuildRequires: pkgconfig(syspopup-caller) +BuildRequires: pkgconfig(rua) +BuildRequires: pkgconfig(pkgmgr-info) BuildRequires: gtest-devel BuildRequires: pkgconfig(tzsh-screensaver-service) #Required for tests diff --git a/src/AppControlActivity.cpp b/src/AppControlActivity.cpp index 0297bd34..12875363 100644 --- a/src/AppControlActivity.cpp +++ b/src/AppControlActivity.cpp @@ -69,7 +69,9 @@ private: RETURN_IF(status != APP_CONTROL_ERROR_NONE); status = app_control_send_launch_request(appControlHandle, NULL, NULL); - PRINT_ERROR_IF(status != APP_CONTROL_ERROR_NONE); + if (status != APP_CONTROL_ERROR_NONE) { + ERROR("launching '%s' failed with error code %d", DerivedType::appToLaunch, status); + } } }; diff --git a/src/batch/BatchRunner.cpp b/src/batch/BatchRunner.cpp index bc0f0f07..cc7ef4b1 100644 --- a/src/batch/BatchRunner.cpp +++ b/src/batch/BatchRunner.cpp @@ -36,7 +36,8 @@ #include #include #include - +#include +#include namespace WrapDetails { @@ -442,6 +443,264 @@ namespace } return file.substr(0, pos + 1) + relativePath; } + + std::string errorToStr(int err) + { + std::ostringstream tmp; + bool first = true; +#define Q(a) \ + if (a == err) { \ + if (first) first = false; \ + else tmp << ", "; \ + tmp << #a; \ + } + Q(TIZEN_ERROR_NONE) + Q(TIZEN_ERROR_NOT_PERMITTED) + Q(TIZEN_ERROR_NO_SUCH_FILE) + Q(TIZEN_ERROR_NO_SUCH_PROCESS) + Q(TIZEN_ERROR_INTERRUPTED_SYS_CALL) + Q(TIZEN_ERROR_IO_ERROR) + Q(TIZEN_ERROR_NO_SUCH_DEVICE) + Q(TIZEN_ERROR_ARGUMENT_LIST_TOO_LONG) + Q(TIZEN_ERROR_EXEC_FORMAT_ERROR) + Q(TIZEN_ERROR_BAD_FILE_NUMBER) + Q(TIZEN_ERROR_TRY_AGAIN) + Q(TIZEN_ERROR_OUT_OF_MEMORY) + Q(TIZEN_ERROR_PERMISSION_DENIED) + Q(TIZEN_ERROR_BAD_ADDRESS) + Q(TIZEN_ERROR_BLOCK_DEVICE_REQUIRED) + Q(TIZEN_ERROR_RESOURCE_BUSY) + Q(TIZEN_ERROR_FILE_EXISTS) + Q(TIZEN_ERROR_CROSS_DEVICE_LINK) + Q(TIZEN_ERROR_NOT_A_DIRECTORY) + Q(TIZEN_ERROR_IS_A_DIRECTORY) + Q(TIZEN_ERROR_INVALID_PARAMETER) + Q(TIZEN_ERROR_FILE_TABLE_OVERFLOW) + Q(TIZEN_ERROR_TOO_MANY_OPEN_FILES) + Q(TIZEN_ERROR_TOO_NOT_A_TERMINAL) + Q(TIZEN_ERROR_TOO_TEXT_FILE_BUSY) + Q(TIZEN_ERROR_FILE_TOO_LARGE) + Q(TIZEN_ERROR_FILE_NO_SPACE_ON_DEVICE) + Q(TIZEN_ERROR_ILLEGAL_SEEK) + Q(TIZEN_ERROR_READ_ONLY_FILESYSTEM) + Q(TIZEN_ERROR_NO_DATA) + Q(TIZEN_ERROR_TOO_MANY_LINKS) + Q(TIZEN_ERROR_BROKEN_PIPE) + Q(TIZEN_ERROR_ARGUMENT_OUT_OF_DOMAIN) + Q(TIZEN_ERROR_RESULT_OUT_OF_RANGE) + Q(TIZEN_ERROR_WOULD_CAUSE_DEADLOCK) + Q(TIZEN_ERROR_FILE_NAME_TOO_LONG) + Q(TIZEN_ERROR_FILE_NO_LOCKS_AVAILABLE) + Q(TIZEN_ERROR_INVALID_OPERATION) + Q(TIZEN_ERROR_DIR_NOT_EMPTY) + Q(TIZEN_ERROR_TOO_MANY_SYMBOLIC_LINKS) + Q(TIZEN_ERROR_WOULD_BLOCK) + Q(TIZEN_ERROR_CORRUPTED_SHARED_LIB) + Q(TIZEN_ERROR_LIB_SECTION_CORRUPTED) + Q(TIZEN_ERROR_LINK_TOO_MANY_SHARED_LIB) + Q(TIZEN_ERROR_SHARED_LIB_EXEC) + Q(TIZEN_ERROR_ILLEGAL_BYTE_SEQ) + Q(TIZEN_ERROR_SYSTEM_CALL_RESTART) + Q(TIZEN_ERROR_STREAMS_PIPE) + Q(TIZEN_ERROR_TOO_MANY_USERS) + Q(TIZEN_ERROR_NON_SOCKET) + Q(TIZEN_ERROR_NO_DEST_ADDRESS) + Q(TIZEN_ERROR_MSG_TOO_LONG) + Q(TIZEN_ERROR_PROTOCOL_WRONG_TYPE) + Q(TIZEN_ERROR_PROTOCOL_NOT_AVALIABLE) + Q(TIZEN_ERROR_PROTOCOL_NOT_SUPPORTED) + Q(TIZEN_ERROR_SOCKET_TYPE_NOT_SUPPORTED) + Q(TIZEN_ERROR_ENDPOINT_OPERATIN_NOT_SUPPORTED) + Q(TIZEN_ERROR_PROTOCOL_FAMILY_NOT_SUPPORTED) + Q(TIZEN_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED) + Q(TIZEN_ERROR_ADDRES_IN_USE) + Q(TIZEN_ERROR_CANNOT_ASSIGN_ADDRESS) + Q(TIZEN_ERROR_NETWORK_DOWN) + Q(TIZEN_ERROR_NETWORK_UNREACHABLE) + Q(TIZEN_ERROR_NETWORK_RESET) + Q(TIZEN_ERROR_CONNECTION_ABORTED) + Q(TIZEN_ERROR_CONNECTION_RESET_BY_PEER) + Q(TIZEN_ERROR_BUFFER_SPACE) + Q(TIZEN_ERROR_ENDPOINT_CONNECTED) + Q(TIZEN_ERROR_ENDPOINT_NOT_CONNECTED) + Q(TIZEN_ERROR_ENDPOINT_SHUTDOWN) + Q(TIZEN_ERROR_TOO_MANY_REFERENCES) + Q(TIZEN_ERROR_CONNECTION_TIME_OUT) + Q(TIZEN_ERROR_CONNECTION_REFUSED) + Q(TIZEN_ERROR_HOST_DOWN) + Q(TIZEN_ERROR_NO_ROUTE_TO_HOST) + Q(TIZEN_ERROR_ALREADY_IN_PROGRESS) + Q(TIZEN_ERROR_NOW_IN_PROGRESS) + Q(TIZEN_ERROR_STALE_NFS_FILE_HANDLE) + Q(TIZEN_ERROR_STRUCTURE_UNCLEAN) + Q(TIZEN_ERROR_NOT_XENIX_NAMED_TYPE_FILE) + Q(TIZEN_ERROR_NO_XENIX_SEMAPHORES_AVAILABLE) + Q(TIZEN_ERROR_IS_NAMED_TYPE_FILE) + Q(TIZEN_ERROR_REMOTE_IO) + Q(TIZEN_ERROR_QUOTA_EXCEEDED) + Q(TIZEN_ERROR_NO_MEDIUM) + Q(TIZEN_ERROR_WRONG_MEDIUM_TYPE) + Q(TIZEN_ERROR_CANCELED) + Q(TIZEN_ERROR_KEY_NOT_AVAILABLE) + Q(TIZEN_ERROR_KEY_EXPIRED) + Q(TIZEN_ERROR_KEY_REVOKED) + Q(TIZEN_ERROR_KEY_REJECTED) + Q(TIZEN_ERROR_OWNER_DEAD) + Q(TIZEN_ERROR_UNKNOWN) + Q(TIZEN_ERROR_TIMED_OUT) + Q(TIZEN_ERROR_NOT_SUPPORTED) + Q(TIZEN_ERROR_USER_NOT_CONSENTED) + Q(TIZEN_ERROR_DEVICE_POLICY_RESTRICTION) + Q(TIZEN_ERROR_END_OF_COLLECTION) +#undef Q + return tmp.str(); + } +} + +void BatchExecutor::killApplication(const std::pair &appInstance) +{ + auto &appid = appInstance.first; + auto &instance_id = appInstance.second; + app_context_h context = NULL; + int ret; + + if (appid == "org.tizen.tts-engine-default-sr") + return; + + output << "killing application " << appInstance.first << (appid.empty() ? "" : ":") << instance_id << "\n"; + if (!instance_id.empty()) { + ret = app_manager_get_app_context_by_instance_id(appid.c_str(), instance_id.c_str(), &context); + } else { + bool running = false; + ret = app_manager_is_running(appid.c_str(), &running); + if (ret != APP_MANAGER_ERROR_NONE) { + throw EvaluationFailure{} << "fail to app_manager_is_running[" << ret << "]: " << get_error_message(ret); + } + + if (!running) { + return; + } + ret = app_manager_get_app_context(appid.c_str(), &context); + } + + if (ret != APP_MANAGER_ERROR_NONE) { + throw EvaluationFailure{} << "fail to app_manager_get_app_contextfailed[" << ret << "]: " << get_error_message(ret); + } + + ret = app_manager_terminate_app(context); + app_context_destroy(context); + + if (ret != APP_MANAGER_ERROR_NONE) { + throw EvaluationFailure{} << "fail to terminate_app '" << appid << ":" << instance_id << "'" << + "[" << ret << "]: " << get_error_message(ret); + } +} + +std::pair BatchExecutor::getApplicationInfo(app_info_h app_info, struct rua_rec *record) +{ + if (!app_info) { + return {}; + } + + char *appid = ""; + char *instanceid = ""; + + int ret = app_info_get_app_id(app_info, &appid); + if (ret != APP_MANAGER_ERROR_NONE) { + throw EvaluationFailure{} << "app_info_get_app_id failed[" << ret << "]: " << get_error_message(ret); + } + + if (record->instance_id) { + instanceid = record->instance_id; + } + return { appid, instanceid }; +} + +using ApplicationInfoIterCbDataType = + std::tuple>, BatchExecutor *, std::string>; + +bool BatchExecutor::applicationInfoIterCb(app_info_h app_info, void *user_data) +{ + auto &data = *(ApplicationInfoIterCbDataType *)user_data; + return (std::get<2>(data))->applicationInfoIterCbImpl(app_info, user_data); +} + +bool BatchExecutor::applicationInfoIterCbImpl(app_info_h app_info, void *user_data) +{ + auto &data = *(ApplicationInfoIterCbDataType *)user_data; + + struct rua_rec *record = std::get<0>(data); + + try { + std::get<1>(data).push_back(std::get<2>(data)->getApplicationInfo(app_info, record)); + } catch (EvaluationFailure &ev) { + std::get<3>(data) = ev.message(); + return true; + } + return false; +} + +void BatchExecutor::clearApplications() +{ + char **table = nullptr; + int rows = 0, cols = 0; + struct rua_rec record; + app_info_filter_h filter = nullptr; + + if (rua_init()) { + throw EvaluationFailure{} << "rua_init failed"; + } + + DefferedCall rua_init_cb{ [&]() + { + rua_fini(); + } }; + + if (rua_history_load_db(&table, &rows, &cols) || !table) { + throw EvaluationFailure{} << "rua_history_load_db failed"; + } + DefferedCall rua_history_load_db_cb{ [&]() + { + rua_history_unload_db(&table); + } }; + + int ret = app_info_filter_create(&filter); + if (ret != APP_MANAGER_ERROR_NONE) { + throw EvaluationFailure{} << "filter_create failed"; + } + DefferedCall app_info_filter_create_cb{ [&]() + { + app_info_filter_destroy(filter); + } }; + + ret = app_info_filter_add_bool(filter, PACKAGE_INFO_PROP_APP_TASKMANAGE, true); + if (ret != APP_MANAGER_ERROR_NONE) { + throw EvaluationFailure{} << "app_info_filer_add_bool failed[" << ret << "]: " << get_error_message(ret); + } + + auto data = ApplicationInfoIterCbDataType{ nullptr, {}, this, "" }; + + for (auto row = 0; row < rows; ++row) { + rua_history_get_rec(&record, table, rows, cols, row); + std::get<0>(data) = &record; + + int ret = app_info_filter_add_string(filter, PACKAGE_INFO_PROP_APP_ID, record.pkg_name); + if (ret != APP_MANAGER_ERROR_NONE) { + throw EvaluationFailure{} << "app_info_filter_add_string failed[" << ret << "]: " << get_error_message(ret); + } + + ret = app_info_filter_foreach_appinfo(filter, applicationInfoIterCb, &data); + if (ret != APP_MANAGER_ERROR_NONE) { + throw EvaluationFailure{} << "app_info_filter_foreach_app_info failed[" << ret << "]: " << get_error_message(ret); + } + if (!std::get<3>(data).empty()) { + throw EvaluationFailure{} << std::get<3>(data); + } + } + + for (auto &r : std::get<1>(data)) { + killApplication(r); + } } void BatchExecutor::insertMethods() @@ -515,6 +774,13 @@ void BatchExecutor::insertMethods() if (!condition) throw EvaluationFailure{} << "assertion failed"; return {}; }, { {"condition"} } }; + + variables["clear_applications"] = EvaluationValueFunction{ + [&]() -> EvaluationValue { + clearApplications(); + return {}; + }, {} }; + variables["find_by_name"] = EvaluationValueFunction{ [&](std::string name, std::vector roles, std::vector states) -> EvaluationValue { auto root = getVisibleRoot(); if (!root) throw EvaluationFailure{} << "no visible root (context changed didn't happen)"; diff --git a/src/batch/BatchRunner.hpp b/src/batch/BatchRunner.hpp index 91d1cd61..2c64a977 100644 --- a/src/batch/BatchRunner.hpp +++ b/src/batch/BatchRunner.hpp @@ -28,6 +28,10 @@ #include "EvaluationContext.hpp" #include "Evaluator.hpp" +#include +#include +#include + template class BatchValueOrError { Optional data; @@ -99,6 +103,11 @@ protected: void insertStateConstants(); void insertRoleConstants(); + void clearApplications(); + void killApplication(const std::pair &appInstance); + std::pair getApplicationInfo(app_info_h app_info, struct rua_rec *record); + static bool applicationInfoIterCb(app_info_h app_info, void *user_data); + bool applicationInfoIterCbImpl(app_info_h app_info, void *user_data); void callActivity(const std::string &activityName, const EvaluationValueFunction::Args &args); void findByName(const std::vector &elems, std::string requestedName, std::function>)> callback); void getAllObjects(AtspiAccessiblePtr root, std::function>)> callback, diff --git a/src/utils.hpp b/src/utils.hpp index c80bd8c3..4b224b1f 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -91,4 +91,33 @@ namespace utils }; } +class DefferedCall +{ + std::function f; +public: + DefferedCall() = default; + DefferedCall(std::function f) : f(std::move(f)) { } + ~DefferedCall() + { + if (f) f(); + } + DefferedCall(const DefferedCall &) = delete; + DefferedCall(DefferedCall &&o) + { + f = o.f; + o.f = {}; + } + + DefferedCall &operator = (const DefferedCall &) = delete; + DefferedCall &operator = (DefferedCall &&o) + { + if (this != &o) { + if (f) f(); + f = o.f; + o.f = {}; + } + return *this; + } +}; + #endif