diff options
45 files changed, 1857 insertions, 170 deletions
diff --git a/src/appMain/CMakeLists.txt b/src/appMain/CMakeLists.txt index b821c94260..fe9a6af3f7 100644 --- a/src/appMain/CMakeLists.txt +++ b/src/appMain/CMakeLists.txt @@ -70,9 +70,19 @@ include_directories( ${default_media_inc} ${MESSAGE_BROKER_INCLUDE_DIRECTORY} ${BOOST_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/src ) -collect_sources(SOURCES "${CMAKE_CURRENT_SOURCE_DIR}") +# Create object library +add_library("LowVoltageHandlerObjLibrary" OBJECT ${CMAKE_CURRENT_SOURCE_DIR}/low_voltage_signals_handler.cc +) + +set (SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/life_cycle_impl.cc + ${CMAKE_CURRENT_SOURCE_DIR}/signal_handlers.cc + $<TARGET_OBJECTS:LowVoltageHandlerObjLibrary> +) cmake_policy(PUSH) # make link_directories() treat paths relative to the source dir @@ -243,3 +253,6 @@ else() GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) endif() +if(BUILD_TESTS) + add_subdirectory(test) +endif() diff --git a/src/appMain/life_cycle.h b/src/appMain/life_cycle.h index a9b18e1bd9..ff8fa2cc40 100644 --- a/src/appMain/life_cycle.h +++ b/src/appMain/life_cycle.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, Ford Motor Company +* Copyright (c) 2018, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,77 +32,60 @@ #ifndef SRC_APPMAIN_LIFE_CYCLE_H_ #define SRC_APPMAIN_LIFE_CYCLE_H_ -#include <thread> -#include <unistd.h> -#include "utils/macro.h" -#include "config_profile/profile.h" -#include "hmi_message_handler/hmi_message_handler_impl.h" -#if (defined(MESSAGEBROKER_HMIADAPTER) || defined(PASA_HMI)) -#include "hmi_message_handler/messagebroker_adapter.h" -#endif // #if ( defined (MESSAGEBROKER_HMIADAPTER) || defined(PASA_HMI) ) -#include "application_manager/application_manager_impl.h" -#include "connection_handler/connection_handler_impl.h" -#include "protocol_handler/protocol_handler_impl.h" -#include "transport_manager/transport_manager.h" -#include "transport_manager/transport_manager_default.h" -#include "media_manager/media_manager_impl.h" -#ifdef TELEMETRY_MONITOR -#include "telemetry_monitor/telemetry_monitor.h" -#endif - -#ifdef ENABLE_SECURITY -namespace security_manager { -class CryptoManager; -class SecurityManagerImpl; -} // namespace security_manager -#endif // ENABLE_SECURITY +namespace main_namespace { -namespace utils { -class SystemTimeHandler; -} // namespace utils +/** + * Class responsible for all system components creation, + * start, stop, suspend and restore + */ -namespace main_namespace { class LifeCycle { public: - LifeCycle(const profile::Profile& profile); - bool StartComponents(); + virtual ~LifeCycle() {} /** - * Initialize MessageBroker component - * @return true if success otherwise false. - */ - bool InitMessageSystem(); + * Creates and starts all system components + * @return true if all components started successfully + * otherwise false. + */ + virtual bool StartComponents() = 0; + /** - * \brief Main loop - */ - void Run(); - void StopComponents(); + * Initializes MessageBroker component + * @return true if success otherwise false. + */ + virtual bool InitMessageSystem() = 0; - private: - transport_manager::TransportManagerImpl* transport_manager_; - protocol_handler::ProtocolHandlerImpl* protocol_handler_; - connection_handler::ConnectionHandlerImpl* connection_handler_; - application_manager::ApplicationManagerImpl* app_manager_; -#ifdef ENABLE_SECURITY - security_manager::CryptoManager* crypto_manager_; - security_manager::SecurityManager* security_manager_; -#endif // ENABLE_SECURITY - hmi_message_handler::HMIMessageHandlerImpl* hmi_handler_; - hmi_message_handler::HMIMessageAdapter* hmi_message_adapter_; - media_manager::MediaManagerImpl* media_manager_; - resumption::LastState* last_state_; -#ifdef TELEMETRY_MONITOR - telemetry_monitor::TelemetryMonitor* telemetry_monitor_; -#endif // TELEMETRY_MONITOR + /** + * @brief Main loop + */ + virtual void Run() = 0; -#ifdef MESSAGEBROKER_HMIADAPTER - hmi_message_handler::MessageBrokerAdapter* mb_adapter_; - std::thread* mb_adapter_thread_; -#endif // MESSAGEBROKER_HMIADAPTER + /** + * Stops all system components + */ + virtual void StopComponents() = 0; + + /** + * Makes appropriate actions when Low Voltage signal received: + * Stops all SDL activities except of waiting of UNIX signals + * from HMI + */ + virtual void LowVoltage() = 0; - const profile::Profile& profile_; - DISALLOW_COPY_AND_ASSIGN(LifeCycle); + /** + * Makes appropriate actions when Wake Up signal received: + * Restores all SDL activities stopped due to LOW VOLTAGE + * from HMI + */ + virtual void WakeUp() = 0; + + /** + * Makes appropriate actions when Ignition Off signal received: + * Triggers all SDL components stop and deletion + */ + virtual void IgnitionOff() = 0; }; } // namespace main_namespace diff --git a/src/appMain/life_cycle.cc b/src/appMain/life_cycle_impl.cc index dae70e3318..186be3c829 100644 --- a/src/appMain/life_cycle.cc +++ b/src/appMain/life_cycle_impl.cc @@ -1,5 +1,5 @@ /* -* Copyright (c) 2017, Ford Motor Company +* Copyright (c) 2018, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "life_cycle.h" +#include "appMain/life_cycle_impl.h" #include "utils/signals.h" #include "config_profile/profile.h" #include "application_manager/system_time/system_time_handler_impl.h" @@ -47,13 +47,15 @@ #include "utils/log_message_loop_thread.h" #endif // ENABLE_LOG +#include "appMain/low_voltage_signals_handler.h" + using threads::Thread; namespace main_namespace { CREATE_LOGGERPTR_GLOBAL(logger_, "SDLMain") -LifeCycle::LifeCycle(const profile::Profile& profile) +LifeCycleImpl::LifeCycleImpl(const profile::Profile& profile) : transport_manager_(NULL) , protocol_handler_(NULL) , connection_handler_(NULL) @@ -76,7 +78,7 @@ LifeCycle::LifeCycle(const profile::Profile& profile) , profile_(profile) { } -bool LifeCycle::StartComponents() { +bool LifeCycleImpl::StartComponents() { LOG4CXX_AUTO_TRACE(logger_); DCHECK(!last_state_); last_state_ = new resumption::LastStateImpl(profile_.app_storage_folder(), @@ -165,11 +167,36 @@ bool LifeCycle::StartComponents() { // start transport manager transport_manager_->Visibility(true); + LowVoltageSignalsOffset signals_offset{profile_.low_voltage_signal_offset(), + profile_.wake_up_signal_offset(), + profile_.ignition_off_signal_offset()}; + + low_voltage_signals_handler_.reset( + new LowVoltageSignalsHandler(*this, signals_offset)); + return true; } +void LifeCycleImpl::LowVoltage() { + LOG4CXX_AUTO_TRACE(logger_); + transport_manager_->Visibility(false); + app_manager_->OnLowVoltage(); +} + +void LifeCycleImpl::IgnitionOff() { + LOG4CXX_AUTO_TRACE(logger_); + kill(getpid(), SIGINT); +} + +void LifeCycleImpl::WakeUp() { + LOG4CXX_AUTO_TRACE(logger_); + app_manager_->OnWakeUp(); + transport_manager_->Reinit(); + transport_manager_->Visibility(true); +} + #ifdef MESSAGEBROKER_HMIADAPTER -bool LifeCycle::InitMessageSystem() { +bool LifeCycleImpl::InitMessageSystem() { mb_adapter_ = new hmi_message_handler::MessageBrokerAdapter( hmi_handler_, profile_.server_address(), profile_.server_port()); @@ -206,16 +233,16 @@ void sig_handler(int sig) { } } // namespace -void LifeCycle::Run() { +void LifeCycleImpl::Run() { LOG4CXX_AUTO_TRACE(logger_); // Register signal handlers and wait sys signals // from OS - if (!utils::WaitTerminationSignals(&sig_handler)) { + if (!utils::Signals::WaitTerminationSignals(&sig_handler)) { LOG4CXX_FATAL(logger_, "Fail to catch system signal!"); } } -void LifeCycle::StopComponents() { +void LifeCycleImpl::StopComponents() { LOG4CXX_AUTO_TRACE(logger_); DCHECK_OR_RETURN_VOID(hmi_handler_); @@ -284,6 +311,9 @@ void LifeCycle::StopComponents() { delete app_manager_; app_manager_ = NULL; + LOG4CXX_INFO(logger_, "Destroying Low Voltage Signals Handler."); + low_voltage_signals_handler_.reset(); + LOG4CXX_INFO(logger_, "Destroying HMI Message Handler and MB adapter."); #ifdef MESSAGEBROKER_HMIADAPTER diff --git a/src/appMain/life_cycle_impl.h b/src/appMain/life_cycle_impl.h new file mode 100644 index 0000000000..5dfc4641ab --- /dev/null +++ b/src/appMain/life_cycle_impl.h @@ -0,0 +1,113 @@ +/* +* Copyright (c) 2018, Ford Motor Company +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the +* distribution. +* +* Neither the name of the Ford Motor Company nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SRC_APPMAIN_LIFE_CYCLE_IMPL_H_ +#define SRC_APPMAIN_LIFE_CYCLE_IMPL_H_ + +#include "appMain/life_cycle.h" + +#include <unistd.h> +#include <thread> +#include <memory> +#include "utils/macro.h" + +#include "config_profile/profile.h" +#include "hmi_message_handler/hmi_message_handler_impl.h" +#if (defined(MESSAGEBROKER_HMIADAPTER) || defined(PASA_HMI)) +#include "hmi_message_handler/messagebroker_adapter.h" +#endif // #if ( defined (MESSAGEBROKER_HMIADAPTER) || defined(PASA_HMI) ) +#include "application_manager/application_manager_impl.h" +#include "connection_handler/connection_handler_impl.h" +#include "protocol_handler/protocol_handler_impl.h" +#include "transport_manager/transport_manager.h" +#include "transport_manager/transport_manager_default.h" +#include "media_manager/media_manager_impl.h" +#ifdef TELEMETRY_MONITOR +#include "telemetry_monitor/telemetry_monitor.h" +#endif + +#ifdef ENABLE_SECURITY +namespace security_manager { +class CryptoManager; +class SecurityManagerImpl; +} // namespace security_manager +#endif // ENABLE_SECURITY + +namespace utils { +class SystemTimeHandler; +} // namespace utils + +namespace main_namespace { + +class LowVoltageSignalsHandler; + +class LifeCycleImpl : public LifeCycle { + public: + explicit LifeCycleImpl(const profile::Profile& profile); + + bool StartComponents() OVERRIDE; + bool InitMessageSystem() OVERRIDE; + void Run() OVERRIDE; + void StopComponents() OVERRIDE; + void LowVoltage() OVERRIDE; + void WakeUp() OVERRIDE; + void IgnitionOff() OVERRIDE; + + private: + transport_manager::TransportManagerImpl* transport_manager_; + protocol_handler::ProtocolHandlerImpl* protocol_handler_; + connection_handler::ConnectionHandlerImpl* connection_handler_; + application_manager::ApplicationManagerImpl* app_manager_; + std::unique_ptr<LowVoltageSignalsHandler> low_voltage_signals_handler_; +#ifdef ENABLE_SECURITY + security_manager::CryptoManager* crypto_manager_; + security_manager::SecurityManager* security_manager_; +#endif // ENABLE_SECURITY + hmi_message_handler::HMIMessageHandlerImpl* hmi_handler_; + hmi_message_handler::HMIMessageAdapter* hmi_message_adapter_; + media_manager::MediaManagerImpl* media_manager_; + resumption::LastState* last_state_; +#ifdef TELEMETRY_MONITOR + telemetry_monitor::TelemetryMonitor* telemetry_monitor_; +#endif // TELEMETRY_MONITOR + +#ifdef MESSAGEBROKER_HMIADAPTER + hmi_message_handler::MessageBrokerAdapter* mb_adapter_; + std::thread* mb_adapter_thread_; +#endif // MESSAGEBROKER_HMIADAPTER + + const profile::Profile& profile_; + DISALLOW_COPY_AND_ASSIGN(LifeCycleImpl); +}; +} // namespace main_namespace + +#endif // SRC_APPMAIN_LIFE_CYCLE_IMPL_H_ diff --git a/src/appMain/low_voltage_signals_handler.cc b/src/appMain/low_voltage_signals_handler.cc new file mode 100644 index 0000000000..936d91ba18 --- /dev/null +++ b/src/appMain/low_voltage_signals_handler.cc @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2018, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "appMain/low_voltage_signals_handler.h" + +#include <signal.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <iostream> +#include "appMain/life_cycle.h" +#include "utils/signals.h" +#include "utils/logger.h" +#include "utils/typed_enum_print.h" +#include "config_profile/profile.h" + +namespace main_namespace { + +CREATE_LOGGERPTR_GLOBAL(logger_, "LowVoltageSignalsHandler") + +LowVoltageSignalsHandler::LowVoltageSignalsHandler( + LifeCycle& life_cycle, const LowVoltageSignalsOffset& offset_data) + : notifications_delegate_(new NotificationThreadDelegate(*this)) + , signals_handler_thread_(threads::CreateThread( + "LV_SIGNALS_HANDLER_THREAD", notifications_delegate_.get())) + , life_cycle_(life_cycle) + , SIGLOWVOLTAGE_(offset_data.low_voltage_signal_offset + SIGRTMIN) + , SIGWAKEUP_(offset_data.wake_up_signal_offset + SIGRTMIN) + , SIGIGNOFF_(offset_data.ignition_off_signal_offset + SIGRTMIN) + , cpid_(-1) { + sigemptyset(&lv_mask_); + sigaddset(&lv_mask_, SIGLOWVOLTAGE_); + signals_handler_thread_->start(); +} + +sigset_t LowVoltageSignalsHandler::LowVoltageSignalsMask() const { + return lv_mask_; +} + +int LowVoltageSignalsHandler::low_voltage_signo() const { + return SIGLOWVOLTAGE_; +} + +int LowVoltageSignalsHandler::wake_up_signo() const { + return SIGWAKEUP_; +} + +int LowVoltageSignalsHandler::ignition_off_signo() const { + return SIGIGNOFF_; +} + +void LowVoltageSignalsHandler::Destroy() { + if (signals_handler_thread_) { + signals_handler_thread_->join(); + } + notifications_delegate_.reset(); + threads::DeleteThread(signals_handler_thread_); +} + +LowVoltageSignalsHandler::~LowVoltageSignalsHandler() { + Destroy(); +} + +void LowVoltageSignalsHandler::HandleSignal(const int signo) { + if (SIGLOWVOLTAGE_ == signo) { + LOG4CXX_DEBUG(logger_, "Received LOW_VOLTAGE signal"); + + life_cycle_.LowVoltage(); + cpid_ = utils::Signals::Fork(); + + if (0 > cpid_) { + LOG4CXX_FATAL(logger_, + "Error due fork() call. Error: " << strerror(errno)); + utils::Signals::ExitProcess(EXIT_FAILURE); + } + + if (0 != cpid_) { + // In Parent process + LOG4CXX_DEBUG(logger_, "Child PID: " << cpid_); + utils::Signals::WaitPid(cpid_, nullptr, 0); + LOG4CXX_DEBUG(logger_, "Child process: " << cpid_ << " is stopped"); + life_cycle_.WakeUp(); + } else { + // In Child process + sigset_t signal_set; + sigfillset(&signal_set); + pthread_sigmask(SIG_BLOCK, &signal_set, nullptr); + sigemptyset(&lv_mask_); + sigaddset(&lv_mask_, SIGWAKEUP_); + sigaddset(&lv_mask_, SIGIGNOFF_); + std::cout << "Stopping parent process: " << getppid() << std::endl; + utils::Signals::SendSignal(SIGSTOP, getppid()); + std::cout << "SIGSTOP signal sent to " << getppid() << std::endl; + } + return; + } + + if (SIGWAKEUP_ == signo) { + std::cout << "Received WAKE UP signal" << std::endl; + std::cout << "Waking Up parent process: " << getppid() << std::endl; + utils::Signals::SendSignal(SIGCONT, getppid()); + std::cout << "Stopping child process: " << getpid() << std::endl; + utils::Signals::ExitProcess(0); + } + + if (SIGIGNOFF_ == signo) { + std::cout << "Received IGNITION_OFF signal" << std::endl; + std::cout << "Stopping all SDL processes..." << std::endl; + utils::Signals::SendSignal(SIGKILL, getppid()); + utils::Signals::ExitProcess(0); + } +} + +void NotificationThreadDelegate::threadMain() { + while (true) { + int signo = 0; + const sigset_t lv_mask = + low_voltage_signals_handler_.LowVoltageSignalsMask(); + const int err = sigwait(&lv_mask, &signo); + if (0 != err) { + LOG4CXX_ERROR( + logger_, + "Sigwait() error! Signals set contains an invalid signal number!"); + continue; + } + low_voltage_signals_handler_.HandleSignal(signo); + } +} + +void NotificationThreadDelegate::exitThreadMain() { + LOG4CXX_AUTO_TRACE(logger_); + ThreadDelegate::exitThreadMain(); +} + +} // namespace main_namespace diff --git a/src/appMain/low_voltage_signals_handler.h b/src/appMain/low_voltage_signals_handler.h new file mode 100644 index 0000000000..8c139c6836 --- /dev/null +++ b/src/appMain/low_voltage_signals_handler.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2018, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_APPMAIN_LOW_VOLTAGE_SIGNALS_HANDLER_H_ +#define SRC_APPMAIN_LOW_VOLTAGE_SIGNALS_HANDLER_H_ + +#include <unistd.h> +#include <memory> +#include "utils/threads/thread_delegate.h" +#include "utils/threads/thread.h" + +namespace main_namespace { + +typedef struct LowVoltageSignalsOffset { + int low_voltage_signal_offset; + int wake_up_signal_offset; + int ignition_off_signal_offset; +} LowVoltageSignalsOffset; + +class LifeCycle; +class NotificationThreadDelegate; + +/** + * @brief Class which handles real-time POSIX signals + * dedicated for LOW VOLTAGE functionality + */ +class LowVoltageSignalsHandler { + public: + /** + * @brief Constructor + * @param life_cycle - life_cycle object to interact with other system + * components + * @param offset_data offset data needed to calculate correct SIGNAL numbers + * used for LOW VOLTAGE functionality (as offset from SIGRTMIN) + */ + LowVoltageSignalsHandler(LifeCycle& life_cycle, + const LowVoltageSignalsOffset& offset_data); + /** + * @brief Handles RT signals related to Low Voltage functionality + * @param signal number to handle + */ + void HandleSignal(const int signo); + + /** + * @brief Returns signals mask required for handling + * LOW VOLTAGE functionality + */ + sigset_t LowVoltageSignalsMask() const; + + /** + * @brief Returns LOW VOLTAGE signal number + */ + int low_voltage_signo() const; + + /** + * @brief Returns WAKE UP signal number + */ + int wake_up_signo() const; + + /** + * @brief Returns IGNITION OFF signal number + */ + int ignition_off_signo() const; + + /** + * @brief Destructor + */ + ~LowVoltageSignalsHandler(); + + private: + /** + * @brief Destroys all parts of Low Voltage signals handler + * Invoked from destructor + */ + void Destroy(); + std::unique_ptr<NotificationThreadDelegate> notifications_delegate_; + threads::Thread* signals_handler_thread_; + LifeCycle& life_cycle_; + int SIGLOWVOLTAGE_; + int SIGWAKEUP_; + int SIGIGNOFF_; + pid_t cpid_; + sigset_t lv_mask_; +}; + +class NotificationThreadDelegate : public threads::ThreadDelegate { + public: + NotificationThreadDelegate( + LowVoltageSignalsHandler& low_voltage_signals_handler) + : low_voltage_signals_handler_(low_voltage_signals_handler) {} + + ~NotificationThreadDelegate() {} + + void threadMain() OVERRIDE; + void exitThreadMain() OVERRIDE; + + private: + LowVoltageSignalsHandler& low_voltage_signals_handler_; +}; + +} // namespace main_namespace + +#endif // SRC_APPMAIN_LOW_VOLTAGE_SIGNALS_HANDLER_H_ diff --git a/src/appMain/main.cc b/src/appMain/main.cc index feb5b5830e..752cfb7bb9 100644 --- a/src/appMain/main.cc +++ b/src/appMain/main.cc @@ -35,6 +35,7 @@ #include <signal.h> #include <cstdio> #include <cstdlib> +#include <memory> #include <vector> #include <string> #include <iostream> // cpplint: Streams are highly discouraged. @@ -45,7 +46,7 @@ #include "utils/log_message_loop_thread.h" #include "utils/logger.h" -#include "./life_cycle.h" +#include "appMain/life_cycle_impl.h" #include "signal_handlers.h" #include "utils/signals.h" @@ -94,8 +95,8 @@ bool InitHmi(std::string hmi_link) { * \return EXIT_SUCCESS or EXIT_FAILURE */ int32_t main(int32_t argc, char** argv) { - // Unsibscribe once for all threads - if (!utils::UnsibscribeFromTermination()) { + // Unsubscribe once for all threads + if (!utils::Signals::UnsubscribeFromTermination()) { // Can't use internal logger here exit(EXIT_FAILURE); } @@ -103,13 +104,31 @@ int32_t main(int32_t argc, char** argv) { // -------------------------------------------------------------------------- // Components initialization profile::Profile profile_instance; - main_namespace::LifeCycle life_cycle(profile_instance); + std::unique_ptr<main_namespace::LifeCycle> life_cycle( + new main_namespace::LifeCycleImpl(profile_instance)); + if ((argc > 1) && (0 != argv)) { profile_instance.set_config_file_name(argv[1]); } else { profile_instance.set_config_file_name("smartDeviceLink.ini"); } + // Reading profile offsets for real-time signals dedicated + // for Low Voltage functionality handling + main_namespace::LowVoltageSignalsOffset signals_offset{ + profile_instance.low_voltage_signal_offset(), + profile_instance.wake_up_signal_offset(), + profile_instance.ignition_off_signal_offset()}; + + // Unsubscribe once for all threads + // except specific thread dedicated for + // Low Voltage signals handling + // Thread will be created later + if (!utils::Signals::UnsubscribeFromLowVoltageSignals(signals_offset)) { + // Can't use internal logger here + exit(EXIT_FAILURE); + } + // -------------------------------------------------------------------------- // Logger initialization INIT_LOGGER("log4cxx.properties", profile_instance.logs_enabled()); @@ -134,9 +153,9 @@ int32_t main(int32_t argc, char** argv) { // -------------------------------------------------------------------------- // Components initialization - if (!life_cycle.StartComponents()) { + if (!life_cycle->StartComponents()) { LOG4CXX_FATAL(logger_, "Failed to start components"); - life_cycle.StopComponents(); + life_cycle->StopComponents(); DEINIT_LOGGER(); exit(EXIT_FAILURE); } @@ -145,9 +164,9 @@ int32_t main(int32_t argc, char** argv) { // -------------------------------------------------------------------------- // Third-Party components initialization. - if (!life_cycle.InitMessageSystem()) { + if (!life_cycle->InitMessageSystem()) { LOG4CXX_FATAL(logger_, "Failed to init message system"); - life_cycle.StopComponents(); + life_cycle->StopComponents(); DEINIT_LOGGER(); _exit(EXIT_FAILURE); } @@ -167,10 +186,10 @@ int32_t main(int32_t argc, char** argv) { } // -------------------------------------------------------------------------- - life_cycle.Run(); + life_cycle->Run(); LOG4CXX_INFO(logger_, "Stop SDL due to caught signal"); - life_cycle.StopComponents(); + life_cycle->StopComponents(); LOG4CXX_INFO(logger_, "Application has been stopped successfuly"); DEINIT_LOGGER(); diff --git a/src/appMain/signal_handlers.cc b/src/appMain/signal_handlers.cc index c695467ae2..649f162ec6 100644 --- a/src/appMain/signal_handlers.cc +++ b/src/appMain/signal_handlers.cc @@ -30,8 +30,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "signal_handlers.h" -#include "life_cycle.h" +#include "appMain/signal_handlers.h" +#include "appMain/life_cycle.h" #include "utils/logger.h" namespace main_namespace { diff --git a/src/appMain/smartDeviceLink.ini b/src/appMain/smartDeviceLink.ini index 444affc06c..037a6efb14 100644 --- a/src/appMain/smartDeviceLink.ini +++ b/src/appMain/smartDeviceLink.ini @@ -96,6 +96,12 @@ AppTransportChangeTimer = 500 ; The time used as addition for AppTransportChangeTimer AppTransportChangeTimerAddition = 0 +; Signal offsets used by SDL for setting up real time signals +; used by LOW VOLTAGE functionality +LowVoltageSignal = 1 ; Offset from SIGRTMIN +WakeUpSignal = 2 ; Offset from SIGRTMIN +IgnitionOffSignal = 3 ; Offset from SIGRTMIN + [MEDIA MANAGER] ; where 3 is a number of retries and 1000 is a timeout in milliseconds for request frequency StartStreamRetry = 3, 1000 diff --git a/src/appMain/test/CMakeLists.txt b/src/appMain/test/CMakeLists.txt new file mode 100644 index 0000000000..057e1e9869 --- /dev/null +++ b/src/appMain/test/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (c) 2018, Ford Motor Company +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the +# distribution. +# +# Neither the name of the Ford Motor Company nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +include_directories ( + ${GMOCK_INCLUDE_DIRECTORY} + ${COMPONENTS_DIR}/utils/test/include +) + +set(testSources + $<TARGET_OBJECTS:LowVoltageHandlerObjLibrary> + ${CMAKE_SOURCE_DIR}/src/appMain/test/low_voltage_signals_handler_test.cc + ${COMPONENTS_DIR}/utils/test/mock_signals_posix.cc +) + +set(LIBRARIES + gmock +) + +create_test(low_voltage_signals_handler_test "${testSources}" "${LIBRARIES}") diff --git a/src/appMain/test/low_voltage_signals_handler_test.cc b/src/appMain/test/low_voltage_signals_handler_test.cc new file mode 100644 index 0000000000..14210df71d --- /dev/null +++ b/src/appMain/test/low_voltage_signals_handler_test.cc @@ -0,0 +1,138 @@ +/* +* Copyright (c) 2018, Ford Motor Company +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the +* distribution. +* +* Neither the name of the Ford Motor Company nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "appMain/low_voltage_signals_handler.h" + +#include <memory> +#include "gtest/gtest.h" +#include "appMain/test/mock_life_cycle.h" +#include "utils/mock_signals_posix.h" +#include "config_profile/profile.h" +#include "utils/macro.h" + +namespace test { + +using ::testing::_; +using ::testing::Return; +using ::testing::InSequence; + +class LowVoltageSignalsHandlerTest : public ::testing::Test { + protected: + LowVoltageSignalsHandlerTest() + : mock_life_cycle_(std::make_shared<main_namespace::MockLifeCycle>()) + , mock_signals_posix_(*utils::MockSignalsPosix::signals_posix_mock()) {} + + void SetUp() OVERRIDE { + profile_.set_config_file_name("smartDeviceLink.ini"); + signals_offset_ = {profile_.low_voltage_signal_offset(), + profile_.wake_up_signal_offset(), + profile_.ignition_off_signal_offset()}; + + low_voltage_signals_handler_ = + std::unique_ptr<main_namespace::LowVoltageSignalsHandler>( + new main_namespace::LowVoltageSignalsHandler( + *mock_life_cycle_.get(), signals_offset_)); + } + + profile::Profile profile_; + main_namespace::LowVoltageSignalsOffset signals_offset_; + std::unique_ptr<main_namespace::LowVoltageSignalsHandler> + low_voltage_signals_handler_; + std::shared_ptr<main_namespace::MockLifeCycle> mock_life_cycle_; + utils::MockSignalsPosix& mock_signals_posix_; +}; + +TEST_F( + LowVoltageSignalsHandlerTest, + LowVoltageSignalReceived_CheckParentProcessBehavior_ExpectChildCreationAndtLowVoltageCall) { + // To guarantee strict call orders + InSequence guarantees_calls_sequence; + // Set expectation after LOW VOLTAGE signal + EXPECT_CALL(*mock_life_cycle_, LowVoltage()); + // Expect child process creation + const pid_t cpid = 111; + EXPECT_CALL(mock_signals_posix_, Fork()).WillOnce(Return(cpid)); + // Expect parent process sleep + EXPECT_CALL(mock_signals_posix_, WaitPid(_, nullptr, 0)); + // Expect parent process wakes up + EXPECT_CALL(*mock_life_cycle_, WakeUp()); + const int low_voltage_signo = + low_voltage_signals_handler_->low_voltage_signo(); + // Emulate LOW VOLTAGE signal receipt and handling + low_voltage_signals_handler_->HandleSignal(low_voltage_signo); +} + +TEST_F( + LowVoltageSignalsHandlerTest, + LowVoltageSignalReceived_CheckChildProcessBehavior_ExpectChildSendsStopToParentProcess) { + // To guarantee strict call orders + InSequence guarantees_calls_sequence; + // Set expectation after LOW VOLTAGE signal + EXPECT_CALL(*mock_life_cycle_, LowVoltage()); + // Expect child process creation + const pid_t cpid = 0; + EXPECT_CALL(mock_signals_posix_, Fork()).WillOnce(Return(cpid)); + // Expect SIGCONT signal to be sent to parent process + EXPECT_CALL(mock_signals_posix_, SendSignal(SIGSTOP, _)); + const int low_voltage_signo = + low_voltage_signals_handler_->low_voltage_signo(); + // Emulate LOW VOLTAGE signal receipt and handling + low_voltage_signals_handler_->HandleSignal(low_voltage_signo); +} + +TEST_F(LowVoltageSignalsHandlerTest, + WakeUpSignalReceived_ExpectParentProcessWakeUpAndChildProcessExit) { + // To guarantee strict call orders + InSequence guarantees_calls_sequence; + // Expect SIGCONT signal to be sent to parent process + EXPECT_CALL(mock_signals_posix_, SendSignal(SIGCONT, _)); + // Expect child process exit + EXPECT_CALL(mock_signals_posix_, ExitProcess(0)); + const int wake_up_signo = low_voltage_signals_handler_->wake_up_signo(); + // Emulate WAKE UP signal receipt and handling + low_voltage_signals_handler_->HandleSignal(wake_up_signo); +} + +TEST_F(LowVoltageSignalsHandlerTest, + IgnitionOffSignalReceived_ExpectAllProcessesStopped) { + // To guarantee strict call orders + InSequence guarantees_calls_sequence; + // Expect SIGKILL signal to be sent to parent process + EXPECT_CALL(mock_signals_posix_, SendSignal(SIGKILL, _)); + // Expect child process exit + EXPECT_CALL(mock_signals_posix_, ExitProcess(0)); + const int ign_off_signo = low_voltage_signals_handler_->ignition_off_signo(); + // Emulate IGN OFF signal receipt and handling + low_voltage_signals_handler_->HandleSignal(ign_off_signo); +} + +} // namespace test diff --git a/src/appMain/test/mock_life_cycle.h b/src/appMain/test/mock_life_cycle.h new file mode 100644 index 0000000000..fc24b26080 --- /dev/null +++ b/src/appMain/test/mock_life_cycle.h @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2018, Ford Motor Company +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the +* distribution. +* +* Neither the name of the Ford Motor Company nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SRC_APPMAIN_TEST_MOCK_LIFE_CYCLE_H_ +#define SRC_APPMAIN_TEST_MOCK_LIFE_CYCLE_H_ + +#include "appMain/life_cycle.h" +#include "gmock/gmock.h" + +namespace main_namespace { + +class MockLifeCycle : public LifeCycle { + public: + MOCK_METHOD0(StartComponents, bool()); + MOCK_METHOD0(InitMessageSystem, bool()); + MOCK_METHOD0(Run, void()); + MOCK_METHOD0(StopComponents, void()); + MOCK_METHOD0(LowVoltage, void()); + MOCK_METHOD0(WakeUp, void()); + MOCK_METHOD0(IgnitionOff, void()); +}; + +} // namespace main_namespace + +#endif // SRC_APPMAIN_TEST_MOCK_LIFE_CYCLE_H_ diff --git a/src/components/application_manager/include/application_manager/application_manager_impl.h b/src/components/application_manager/include/application_manager/application_manager_impl.h index d297b09557..539fa8823d 100644 --- a/src/components/application_manager/include/application_manager/application_manager_impl.h +++ b/src/components/application_manager/include/application_manager/application_manager_impl.h @@ -1131,10 +1131,10 @@ class ApplicationManagerImpl */ void SendOnSDLClose(); - /* + /** * @brief returns true if low voltage state is active */ - bool IsLowVoltage(); + bool IsLowVoltage() const OVERRIDE; /** * @brief Allows to process postponed commands for application diff --git a/src/components/application_manager/include/application_manager/resumption/resume_ctrl.h b/src/components/application_manager/include/application_manager/resumption/resume_ctrl.h index 90c6c5c208..f9a60c862b 100644 --- a/src/components/application_manager/include/application_manager/resumption/resume_ctrl.h +++ b/src/components/application_manager/include/application_manager/resumption/resume_ctrl.h @@ -34,7 +34,7 @@ #define SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_RESUMPTION_RESUME_CTRL_H_ #include <stdint.h> - +#include <time.h> #include "application_manager/resumption/resumption_data.h" namespace application_manager { @@ -125,6 +125,16 @@ class ResumeCtrl { virtual void OnAwake() = 0; /** + * @brief Saves Low Voltage signal timestamp + */ + virtual void SaveLowVoltageTime() = 0; + + /** + * @brief Saves Wake Up signal timestamp + */ + virtual void SaveWakeUpTime() = 0; + + /** * @brief Checks if SDL has already received OnExitAllApplication notification * with "SUSPEND" reason * @@ -134,13 +144,19 @@ class ResumeCtrl { virtual bool is_suspended() const = 0; /** - * @brief Method stops timer "RsmCtrlPercist" when SDL + * @brief Method stops timer "RsmCtrlPersist" when SDL * receives OnExitAllApplication notification * with reason "SUSPEND" */ virtual void StopSavePersistentDataTimer() = 0; /** + * @brief Method starts timer "RsmCtrlPersist" when + * SDL receives onAwakeSDL notification + */ + virtual void StartSavePersistentDataTimer() = 0; + + /** * @brief Start timer for resumption applications * Restore D1-D5 data * @param application that is need to be restored diff --git a/src/components/application_manager/include/application_manager/resumption/resume_ctrl_impl.h b/src/components/application_manager/include/application_manager/resumption/resume_ctrl_impl.h index 17aabb6d60..e749118140 100644 --- a/src/components/application_manager/include/application_manager/resumption/resume_ctrl_impl.h +++ b/src/components/application_manager/include/application_manager/resumption/resume_ctrl_impl.h @@ -33,6 +33,8 @@ #ifndef SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_RESUMPTION_RESUME_CTRL_IMPL_H_ #define SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_RESUMPTION_RESUME_CTRL_IMPL_H_ +#include "application_manager/resumption/resume_ctrl.h" + #include <stdint.h> #include <vector> #include <map> @@ -46,7 +48,6 @@ #include "smart_objects/smart_object.h" #include "application_manager/application.h" #include "application_manager/resumption/resumption_data.h" -#include "application_manager/resumption/resume_ctrl.h" #include "utils/timer.h" namespace resumption { @@ -138,6 +139,10 @@ class ResumeCtrlImpl : public ResumeCtrl, */ void OnAwake() OVERRIDE; + void SaveLowVoltageTime() OVERRIDE; + + void SaveWakeUpTime() OVERRIDE; + /** * @brief Checks if SDL has already received OnExitAllApplication notification * with "SUSPEND" reason @@ -155,6 +160,13 @@ class ResumeCtrlImpl : public ResumeCtrl, void StopSavePersistentDataTimer() OVERRIDE; /** + * @brief Check if all IGNITION OFF and IGNITION ON records + * saved in resumption data base + * @return True if all records saved, otherwise False + */ + bool CheckIgnCyclesData() const; + + /** * @brief Method stops restore_hmi_level_timer_ "RsmCtrlRstore" in OnSuspend() */ void StopRestoreHmiLevelTimer(); @@ -300,7 +312,7 @@ class ResumeCtrlImpl : public ResumeCtrl, * @brief Method starts timer "RsmCtrlPercist" when * SDL receives onAwakeSDL notification */ - void StartSavePersistentDataTimer(); + void StartSavePersistentDataTimer() OVERRIDE; #ifdef BUILD_TESTS void set_resumption_storage( @@ -310,6 +322,20 @@ class ResumeCtrlImpl : public ResumeCtrl, #endif // BUILD_TESTS private: /** + * @brief Returns Low Voltage signal timestamp + * @return Low Voltage event timestamp if event LOW VOLTAGE event occures + * otherwise 0 + */ + time_t LowVoltageTime() const; + + /** + * @brief Returns Wake Up signal timestamp + * @return Wake Up timestamp if Wake Up signal occures + * otherwise 0 + */ + time_t WakeUpTime() const; + + /** * @brief restores saved data of application * @param application contains application for which restores data * @return true if success, otherwise return false @@ -390,11 +416,27 @@ class ResumeCtrlImpl : public ResumeCtrl, void AddWayPointsSubscription(app_mngr::ApplicationSharedPtr application, const smart_objects::SmartObject& saved_app); + /** + * @brief Checks if saved HMI level is allowed for resumption + * by Ignition Cycle restrictions + * @param saved_app application specific section from backup file + * @return True if allowed , otherwise - False + */ bool CheckIgnCycleRestrictions(const smart_objects::SmartObject& saved_app); - bool DisconnectedJustBeforeIgnOff( - const smart_objects::SmartObject& saved_app); + /** + * @brief Checks if saved HMI level is allowed for resumption + * by Low Voltage restrictions + * @param saved_app application specific section from backup file + * @return True if allowed , otherwise - False + */ + bool CheckLowVoltageRestrictions(const smart_objects::SmartObject& saved_app); + /** + * @brief Checks if saved HMI level is applicable for resumption + * @param saved_app application specific section from backup file + * @return True fs allowed , otherwise - False + */ bool CheckAppRestrictions(app_mngr::ApplicationConstSharedPtr application, const smart_objects::SmartObject& saved_app); @@ -409,10 +451,38 @@ class ResumeCtrlImpl : public ResumeCtrl, /** * @brief CheckDelayAfterIgnOn should check if SDL was started less - * then N seconds ago. N will be readed from profile. + * than N seconds ago. N will be read from profile. * @return true if SDL started N seconds ago, otherwise return false */ - bool CheckDelayAfterIgnOn(); + bool CheckDelayAfterIgnOn() const; + + /** + * @brief CheckDelayBeforeIgnOff checks if app was unregistered less + * than N seconds before Ignition OFF. N will be read from profile. + * @return true if app was disconnected within timeframe of N seconds before + * Ignition Off, + * otherwise return false + */ + bool CheckDelayBeforeIgnOff( + const smart_objects::SmartObject& saved_app) const; + + /** + * @brief CheckDelayAfterWakeUp should check if app was registered + * during the first N seconds after WakeUp signal. N will be read from + * profile. + * @return true if app registered within N seconds after WakeUp, otherwise + * return false + */ + bool CheckDelayAfterWakeUp() const; + + /** + * @brief CheckDelayBeforeLowVoltage checks if app was unregistered within + * N seconds before Low Voltage signal. N will be read from profile. + * @return true if app was disconnected within timeframe of N seconds before + * Low Voltage , otherwise return false + */ + bool CheckDelayBeforeLowVoltage( + const smart_objects::SmartObject& saved_app) const; typedef std::pair<uint32_t, uint32_t> application_timestamp; @@ -447,7 +517,7 @@ class ResumeCtrlImpl : public ResumeCtrl, * @brief Get the last ignition off time from LastState * @return the last ignition off time from LastState */ - time_t GetIgnOffTime(); + time_t GetIgnOffTime() const; /** * @brief Setup IgnOff time to LastState @@ -535,6 +605,8 @@ class ResumeCtrlImpl : public ResumeCtrl, bool is_data_saved_; bool is_suspended_; time_t launch_time_; + time_t low_voltage_time_; + time_t wake_up_time_; std::shared_ptr<ResumptionData> resumption_storage_; application_manager::ApplicationManager& application_manager_; }; diff --git a/src/components/application_manager/include/application_manager/resumption/resumption_data.h b/src/components/application_manager/include/application_manager/resumption/resumption_data.h index 24dc712607..c2634173a5 100644 --- a/src/components/application_manager/include/application_manager/resumption/resumption_data.h +++ b/src/components/application_manager/include/application_manager/resumption/resumption_data.h @@ -100,6 +100,23 @@ class ResumptionData { virtual void DecrementIgnOffCount() = 0; /** + * @brief Increments global ignition on counter + * by 1 + */ + virtual void IncrementGlobalIgnOnCounter() = 0; + + /** + * @brief Get the global ignition on counter + * @return the global ignition on counter + */ + virtual uint32_t GetGlobalIgnOnCounter() const = 0; + + /** + * @brief Resets global ignition on counter + */ + virtual void ResetGlobalIgnOnCount() = 0; + + /** * @brief Retrieves hash ID for the given mobile app ID * and device ID from stored information. * @param policy_app_id - mobile application id diff --git a/src/components/application_manager/include/application_manager/resumption/resumption_data_db.h b/src/components/application_manager/include/application_manager/resumption/resumption_data_db.h index 2405e39087..2b5a1fdcc9 100644 --- a/src/components/application_manager/include/application_manager/resumption/resumption_data_db.h +++ b/src/components/application_manager/include/application_manager/resumption/resumption_data_db.h @@ -110,6 +110,12 @@ class ResumptionDataDB : public ResumptionData { virtual uint32_t GetHMIApplicationID(const std::string& policy_app_id, const std::string& device_id) const; + void IncrementGlobalIgnOnCounter() OVERRIDE; + + uint32_t GetGlobalIgnOnCounter() const OVERRIDE; + + void ResetGlobalIgnOnCount() OVERRIDE; + /** * @brief Increments ignition counter for all registered applications * and remember ign_off time stamp diff --git a/src/components/application_manager/include/application_manager/resumption/resumption_data_json.h b/src/components/application_manager/include/application_manager/resumption/resumption_data_json.h index ff3414d97a..e2418fd033 100644 --- a/src/components/application_manager/include/application_manager/resumption/resumption_data_json.h +++ b/src/components/application_manager/include/application_manager/resumption/resumption_data_json.h @@ -133,6 +133,12 @@ class ResumptionDataJson : public ResumptionData { */ virtual uint32_t GetIgnOffTime() const; + void IncrementGlobalIgnOnCounter() OVERRIDE; + + uint32_t GetGlobalIgnOnCounter() const OVERRIDE; + + void ResetGlobalIgnOnCount() OVERRIDE; + /** * @brief Checks if saved data have application * @param policy_app_id - mobile application id diff --git a/src/components/application_manager/include/application_manager/resumption/resumption_sql_queries.h b/src/components/application_manager/include/application_manager/resumption/resumption_sql_queries.h index 33d62740f7..eee7650697 100644 --- a/src/components/application_manager/include/application_manager/resumption/resumption_sql_queries.h +++ b/src/components/application_manager/include/application_manager/resumption/resumption_sql_queries.h @@ -57,7 +57,10 @@ extern const std::string kUpdateIgnOffCount; extern const std::string kCountApplicationsIgnOff; extern const std::string kSelectApplicationsIgnOffCount; extern const std::string kUpdateSuspendData; -extern const std::string KUpdateLastIgnOffTime; +extern const std::string kUpdateLastIgnOffTime; +extern const std::string kUpdateGlobalIgnOnCount; +extern const std::string kResetGlobalIgnOnCount; +extern const std::string kSelectGlobalIgnOnCounter; extern const std::string kDeleteFile; extern const std::string kDeleteApplicationFilesArray; extern const std::string kDeleteSubMenu; diff --git a/src/components/application_manager/include/application_manager/smart_object_keys.h b/src/components/application_manager/include/application_manager/smart_object_keys.h index d0a3c1ed96..4646ef5e8f 100644 --- a/src/components/application_manager/include/application_manager/smart_object_keys.h +++ b/src/components/application_manager/include/application_manager/smart_object_keys.h @@ -313,6 +313,8 @@ extern const char* resume_vr_grammars; extern const char* ign_off_count; +extern const char* global_ign_on_counter; + extern const char* connection_info; extern const char* is_download_complete; diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/CMakeLists.txt b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/CMakeLists.txt index da51c3e4e4..1a206c2cce 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/CMakeLists.txt +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories( ${COMPONENTS_DIR}/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/ ${COMPONENTS_DIR}/application_manager/test/include/ ${POLICY_MOCK_INCLUDE_PATH}/ + ${CMAKE_SOURCE_DIR}/src ) diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/hmi_notifications_test.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/hmi_notifications_test.cc index dd51078614..fe82b16f3f 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/hmi_notifications_test.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/hmi_notifications_test.cc @@ -872,7 +872,7 @@ TEST_F(HMICommandsNotificationsTest, SubscribeForSignal(); command->Run(); - utils::WaitTerminationSignals(sig_handler); + utils::Signals::WaitTerminationSignals(sig_handler); EXPECT_EQ(am::mobile_api::AppInterfaceUnregisteredReason::IGNITION_OFF, mob_reason); @@ -914,7 +914,7 @@ TEST_F(HMICommandsNotificationsTest, SubscribeForSignal(); command->Run(); - utils::WaitTerminationSignals(sig_handler); + utils::Signals::WaitTerminationSignals(sig_handler); #endif } } diff --git a/src/components/application_manager/src/application_manager_impl.cc b/src/components/application_manager/src/application_manager_impl.cc index a5e93fbc40..f6960e5583 100644 --- a/src/components/application_manager/src/application_manager_impl.cc +++ b/src/components/application_manager/src/application_manager_impl.cc @@ -178,7 +178,7 @@ ApplicationManagerImpl::ApplicationManagerImpl( , is_low_voltage_(false) , apps_size_(0) , is_stopping_(false) { - std::srand(std::time(0)); + std::srand(std::time(nullptr)); AddPolicyObserver(this); dir_type_to_string_map_ = {{TYPE_STORAGE, "Storage"}, @@ -405,6 +405,7 @@ void ApplicationManagerImpl::OnApplicationSwitched(ApplicationSharedPtr app) { bool ApplicationManagerImpl::IsAppTypeExistsInFullOrLimited( ApplicationConstSharedPtr app) const { + LOG4CXX_AUTO_TRACE(logger_); bool voice_state = app->is_voice_communication_supported(); bool media_state = app->is_media_application(); bool navi_state = app->is_navi(); @@ -2237,7 +2238,10 @@ void ApplicationManagerImpl::ClearAppsPersistentData() { void ApplicationManagerImpl::SendOnSDLClose() { LOG4CXX_AUTO_TRACE(logger_); - + if (IsLowVoltage()) { + LOG4CXX_TRACE(logger_, "SDL is in Low Voltage State"); + return; + } // must be sent to PASA HMI on shutdown synchronously smart_objects::SmartObjectSPtr msg = std::make_shared<smart_objects::SmartObject>( @@ -2427,11 +2431,13 @@ void ApplicationManagerImpl::UnregisterApplication( return; } + if (is_resuming) { resume_controller().SaveApplication(app_to_remove); } else { resume_controller().RemoveApplicationFromSaved(app_to_remove); } + (hmi_capabilities_->get_hmi_language_handler()) .OnUnregisterApplication(app_id); AppV4DevicePredicate finder(handle); @@ -2535,14 +2541,24 @@ bool ApplicationManagerImpl::is_audio_pass_thru_active() const { void ApplicationManagerImpl::OnLowVoltage() { LOG4CXX_AUTO_TRACE(logger_); is_low_voltage_ = true; + resume_ctrl_->SaveLowVoltageTime(); + resume_ctrl_->StopSavePersistentDataTimer(); request_ctrl_.OnLowVoltage(); } -bool ApplicationManagerImpl::IsLowVoltage() { - LOG4CXX_TRACE(logger_, "result: " << is_low_voltage_); +bool ApplicationManagerImpl::IsLowVoltage() const { + LOG4CXX_TRACE(logger_, "Result: " << is_low_voltage_); return is_low_voltage_; } +void ApplicationManagerImpl::OnWakeUp() { + LOG4CXX_AUTO_TRACE(logger_); + is_low_voltage_ = false; + resume_ctrl_->SaveWakeUpTime(); + resume_ctrl_->StartSavePersistentDataTimer(); + request_ctrl_.OnWakeUp(); +} + std::string ApplicationManagerImpl::GetHashedAppID( uint32_t connection_key, const std::string& mobile_app_id) const { connection_handler::DeviceHandle device_id = 0; @@ -2961,12 +2977,6 @@ policy::DeviceConsent ApplicationManagerImpl::GetUserConsentForDevice( return GetPolicyHandler().GetUserConsentForDevice(device_id); } -void ApplicationManagerImpl::OnWakeUp() { - LOG4CXX_AUTO_TRACE(logger_); - is_low_voltage_ = false; - request_ctrl_.OnWakeUp(); -} - mobile_apis::Result::eType ApplicationManagerImpl::SaveBinary( const std::vector<uint8_t>& binary_data, const std::string& file_path, diff --git a/src/components/application_manager/src/resumption/resume_ctrl_impl.cc b/src/components/application_manager/src/resumption/resume_ctrl_impl.cc index 42dc335878..3e77078ee5 100644 --- a/src/components/application_manager/src/resumption/resume_ctrl_impl.cc +++ b/src/components/application_manager/src/resumption/resume_ctrl_impl.cc @@ -74,7 +74,9 @@ ResumeCtrlImpl::ResumeCtrlImpl(ApplicationManager& application_manager) , is_resumption_active_(false) , is_data_saved_(false) , is_suspended_(false) - , launch_time_(time(NULL)) + , launch_time_(time(nullptr)) + , low_voltage_time_(0) + , wake_up_time_(0) , application_manager_(application_manager) {} #ifdef BUILD_TESTS void ResumeCtrlImpl::set_resumption_storage( @@ -128,6 +130,8 @@ bool ResumeCtrlImpl::Init(resumption::LastState& last_state) { application_manager_.get_settings() .app_resumption_save_persistent_data_timeout(), timer::kPeriodic); + + resumption_storage_->IncrementGlobalIgnOnCounter(); return true; } @@ -144,9 +148,13 @@ void ResumeCtrlImpl::SaveAllApplications() { void ResumeCtrlImpl::SaveApplication(ApplicationSharedPtr application) { LOG4CXX_AUTO_TRACE(logger_); DCHECK_OR_RETURN_VOID(application); - LOG4CXX_INFO(logger_, - "application with appID " << application->app_id() - << " will be saved"); + if (application_manager_.IsLowVoltage()) { + LOG4CXX_DEBUG(logger_, "Low Voltage state is active"); + return; + } + LOG4CXX_DEBUG(logger_, + "application with appID " << application->app_id() + << " will be saved"); resumption_storage_->SaveApplication(application); } @@ -310,6 +318,10 @@ uint32_t ResumeCtrlImpl::GetHMIApplicationID( bool ResumeCtrlImpl::RemoveApplicationFromSaved( ApplicationConstSharedPtr application) { + if (application_manager_.IsLowVoltage()) { + LOG4CXX_DEBUG(logger_, "Low Voltage state is active"); + return false; + } const std::string& device_mac = application->mac_address(); return resumption_storage_->RemoveApplicationFromSaved( application->policy_app_id(), device_mac); @@ -323,8 +335,11 @@ void ResumeCtrlImpl::OnSuspend() { void ResumeCtrlImpl::OnIgnitionOff() { LOG4CXX_AUTO_TRACE(logger_); - resumption_storage_->IncrementIgnOffCount(); - FinalPersistData(); + if (!application_manager_.IsLowVoltage()) { + resumption_storage_->IncrementIgnOffCount(); + resumption_storage_->ResetGlobalIgnOnCount(); + FinalPersistData(); + } } void ResumeCtrlImpl::OnAwake() { @@ -334,6 +349,25 @@ void ResumeCtrlImpl::OnAwake() { StartSavePersistentDataTimer(); } +void ResumeCtrlImpl::SaveLowVoltageTime() { + low_voltage_time_ = time(nullptr); + LOG4CXX_DEBUG(logger_, + "Low Voltage timestamp : " << low_voltage_time_ << " saved"); +} + +void ResumeCtrlImpl::SaveWakeUpTime() { + wake_up_time_ = std::time(nullptr); + LOG4CXX_DEBUG(logger_, "Wake Up timestamp : " << wake_up_time_ << " saved"); +} + +time_t ResumeCtrlImpl::LowVoltageTime() const { + return low_voltage_time_; +} + +time_t ResumeCtrlImpl::WakeUpTime() const { + return wake_up_time_; +} + bool ResumeCtrlImpl::is_suspended() const { return is_suspended_; } @@ -440,12 +474,25 @@ void ResumeCtrlImpl::StartAppHmiStateResumption( LOG4CXX_ERROR(logger_, "Application was not saved"); return; } - const uint32_t ign_off_count = saved_app[strings::ign_off_count].asUInt(); - bool restore_data_allowed = false; - restore_data_allowed = - CheckAppRestrictions(application, saved_app) && - ((0 == ign_off_count) || CheckIgnCycleRestrictions(saved_app)); - if (restore_data_allowed) { + + const bool is_hmi_level_applicable_to_resume = + CheckAppRestrictions(application, saved_app); + + if (!is_hmi_level_applicable_to_resume) { + LOG4CXX_DEBUG(logger_, "No applicable HMI level found for resuming"); + return; + } + + const bool is_resume_allowed_by_low_voltage = + CheckLowVoltageRestrictions(saved_app); + + const bool is_hmi_level_allowed_by_ign_cycle = + CheckIgnCycleRestrictions(saved_app); + + const bool restore_hmi_level_allowed = + is_resume_allowed_by_low_voltage && is_hmi_level_allowed_by_ign_cycle; + + if (restore_hmi_level_allowed) { LOG4CXX_INFO(logger_, "Resume application " << application->policy_app_id()); RestoreAppHMIState(application); @@ -716,30 +763,62 @@ void ResumeCtrlImpl::AddSubscriptions( bool ResumeCtrlImpl::CheckIgnCycleRestrictions( const smart_objects::SmartObject& saved_app) { LOG4CXX_AUTO_TRACE(logger_); - bool result = true; if (!CheckDelayAfterIgnOn()) { - LOG4CXX_INFO(logger_, "Application was connected long after ign on"); - result = false; + LOG4CXX_DEBUG(logger_, "Application was connected long after ign on"); + return false; } - if (!DisconnectedJustBeforeIgnOff(saved_app)) { - LOG4CXX_INFO(logger_, "Application was dissconnected long before ign off"); - result = false; + if (!CheckDelayBeforeIgnOff(saved_app)) { + LOG4CXX_DEBUG(logger_, "Application was disconnected long before ign off"); + return false; } - return result; + return true; } -bool ResumeCtrlImpl::DisconnectedJustBeforeIgnOff( +bool ResumeCtrlImpl::CheckLowVoltageRestrictions( const smart_objects::SmartObject& saved_app) { + LOG4CXX_AUTO_TRACE(logger_); + + if (!CheckDelayBeforeLowVoltage(saved_app)) { + LOG4CXX_DEBUG(logger_, + "Application was disconnected long before low voltage"); + return false; + } + + if (!CheckDelayAfterWakeUp()) { + LOG4CXX_DEBUG(logger_, "Application was connected long after wake up"); + return false; + } + + LOG4CXX_DEBUG(logger_, "HMI Level resuming in not restricted by Low Voltage"); + return true; +} + +bool ResumeCtrlImpl::CheckDelayBeforeIgnOff( + const smart_objects::SmartObject& saved_app) const { using namespace date_time; LOG4CXX_AUTO_TRACE(logger_); DCHECK_OR_RETURN(saved_app.keyExists(strings::time_stamp), false); const time_t time_stamp = static_cast<time_t>(saved_app[strings::time_stamp].asInt()); - time_t ign_off_time = + const time_t ign_off_time = static_cast<time_t>(resumption_storage_->GetIgnOffTime()); + + if (CheckIgnCyclesData() && 0 == ign_off_time) { + LOG4CXX_DEBUG( + logger_, "No IGNITION OFF records found: This is first Ignition cycle"); + return true; + } + + // This means that ignition off timestamp was not saved + // Possible reasons: Low Voltage event, core crash etc. + if (ign_off_time < time_stamp) { + LOG4CXX_DEBUG(logger_, "Last IGNITION OFF record missed"); + return true; + } + const uint32_t sec_spent_before_ign = labs(ign_off_time - time_stamp); LOG4CXX_DEBUG( logger_, @@ -752,6 +831,71 @@ bool ResumeCtrlImpl::DisconnectedJustBeforeIgnOff( application_manager_.get_settings().resumption_delay_before_ign(); } +bool ResumeCtrlImpl::CheckDelayBeforeLowVoltage( + const smart_objects::SmartObject& saved_app) const { + using namespace date_time; + LOG4CXX_AUTO_TRACE(logger_); + DCHECK_OR_RETURN(saved_app.keyExists(strings::time_stamp), false); + + if (0 == LowVoltageTime()) { + LOG4CXX_DEBUG(logger_, "No Low Voltage signal timestamp saved"); + return true; + } + + const time_t unregistration_time_stamp = + static_cast<time_t>(saved_app[strings::time_stamp].asInt()); + const time_t low_voltage_timestamp = static_cast<time_t>(LowVoltageTime()); + const int32_t sec_spent_before_low_voltage = + (low_voltage_timestamp - unregistration_time_stamp); + if (0 > sec_spent_before_low_voltage) { + LOG4CXX_DEBUG(logger_, + "Low Voltage time: " + << low_voltage_timestamp + << "; App disconnect time: " << unregistration_time_stamp + << "; Secs between app disconnect and low voltage event " + << sec_spent_before_low_voltage); + return true; + } + + const uint32_t secs_between_app_disconnect_and_low_voltage = + static_cast<uint32_t>(sec_spent_before_low_voltage); + const uint32_t wait_time = + application_manager_.get_settings().resumption_delay_before_ign(); + LOG4CXX_DEBUG(logger_, + "Low Voltage time: " + << low_voltage_timestamp + << "; App disconnect time: " << unregistration_time_stamp + << "; Secs between app disconnect and low voltage event " + << secs_between_app_disconnect_and_low_voltage + << "; Timeout for HMI level resuming: " << wait_time); + return secs_between_app_disconnect_and_low_voltage <= wait_time; +} + +bool ResumeCtrlImpl::CheckDelayAfterWakeUp() const { + using namespace date_time; + LOG4CXX_AUTO_TRACE(logger_); + + if (0 == WakeUpTime()) { + LOG4CXX_DEBUG(logger_, "No WakeUp signal timestamp saved"); + return true; + } + + const time_t current_time = time(nullptr); + const time_t wake_up_timestamp = static_cast<time_t>(WakeUpTime()); + + const uint32_t seconds_from_wake_up_signal = + labs(current_time - wake_up_timestamp); + const uint32_t wait_time = + application_manager_.get_settings().resumption_delay_after_ign(); + LOG4CXX_DEBUG( + logger_, + "Current time: " << current_time << "; WakeUp Signal time: " + << wake_up_timestamp << "; Seconds passed from wake up: " + << seconds_from_wake_up_signal + << "; Timeout for HMI level resuming: " << wait_time); + return seconds_from_wake_up_signal <= wait_time; +} + bool ResumeCtrlImpl::CheckAppRestrictions( ApplicationConstSharedPtr application, const smart_objects::SmartObject& saved_app) { @@ -773,9 +917,10 @@ bool ResumeCtrlImpl::CheckAppRestrictions( ? true : false; LOG4CXX_DEBUG(logger_, - "is_media_app " << application->is_media_application() - << "; hmi_level " << hmi_level << " result " - << result); + "is_media_app: " << application->is_media_application() + << "; hmi_level: " << hmi_level << "; result: " + << (result ? "Applicable for resume" + : "Non-applicable for resume")); return result; } @@ -788,11 +933,36 @@ bool ResumeCtrlImpl::CheckIcons(ApplicationSharedPtr application, return mobile_apis::Result::INVALID_DATA != verify_images; } -bool ResumeCtrlImpl::CheckDelayAfterIgnOn() { +bool ResumeCtrlImpl::CheckIgnCyclesData() const { + LOG4CXX_AUTO_TRACE(logger_); + const uint32_t global_ign_on_count = + resumption_storage_->GetGlobalIgnOnCounter(); + const uint32_t the_first_ignition = 1; + const bool is_emergency_ign_off_occurred = + global_ign_on_count > the_first_ignition; + // global_ign_on_count is reseting to 0 at ignition off + // global_ign_on_count is incrementing at ignition on + // global_ign_on_count > 1 means that correct ignition off was not present. + if (is_emergency_ign_off_occurred) { + LOG4CXX_WARN(logger_, + "Emergency IGN OFF occurred. Possibly after Low Voltage"); + return false; + } + return true; +} + +bool ResumeCtrlImpl::CheckDelayAfterIgnOn() const { using namespace date_time; LOG4CXX_AUTO_TRACE(logger_); - const time_t curr_time = time(NULL); + const time_t ign_off_time = GetIgnOffTime(); + + if (CheckIgnCyclesData() && 0 == ign_off_time) { + LOG4CXX_DEBUG(logger_, "This is first Ignition cycle"); + return true; + } + const time_t curr_time = time(nullptr); const time_t sdl_launch_time = LaunchTime(); + const uint32_t seconds_from_sdl_start = labs(curr_time - sdl_launch_time); const uint32_t wait_time = application_manager_.get_settings().resumption_delay_after_ign(); @@ -808,7 +978,7 @@ time_t ResumeCtrlImpl::LaunchTime() const { return launch_time_; } -time_t ResumeCtrlImpl::GetIgnOffTime() { +time_t ResumeCtrlImpl::GetIgnOffTime() const { return resumption_storage_->GetIgnOffTime(); } @@ -856,6 +1026,8 @@ void ResumeCtrlImpl::AddToResumptionTimerQueue(const uint32_t app_id) { "Application ID " << app_id << " have been added" " to resumption queue."); if (run_resumption) { + LOG4CXX_DEBUG(logger_, + "Application ID " << app_id << " will be restored by timer"); restore_hmi_level_timer_.Start( application_manager_.get_settings().app_resuming_timeout(), timer::kSingleShot); diff --git a/src/components/application_manager/src/resumption/resumption_data_db.cc b/src/components/application_manager/src/resumption/resumption_data_db.cc index f75718af79..1591ce566a 100644 --- a/src/components/application_manager/src/resumption/resumption_data_db.cc +++ b/src/components/application_manager/src/resumption/resumption_data_db.cc @@ -163,11 +163,10 @@ void ResumptionDataDB::SaveApplication( } if (application->is_application_data_changed()) { - if (application_exist) { - if (!DeleteSavedApplication(policy_app_id, device_mac)) { - LOG4CXX_ERROR(logger_, "Deleting of application data is not finished"); - return; - } + if (application_exist && + !DeleteSavedApplication(policy_app_id, device_mac)) { + LOG4CXX_ERROR(logger_, "Deleting of application data is not finished"); + return; } if (!SaveApplicationToDB(application, policy_app_id, device_mac)) { @@ -176,23 +175,15 @@ void ResumptionDataDB::SaveApplication( } LOG4CXX_INFO(logger_, "All data from application were saved successfully"); application->set_is_application_data_changed(false); - } else { - if (application_exist) { - if (!UpdateApplicationData(application, policy_app_id, device_mac)) { - LOG4CXX_ERROR(logger_, "Updating application data is failed"); - return; - } - LOG4CXX_INFO(logger_, "Application data were updated successfully"); - } else { - if (Compare<HMILevel::eType, EQ, ONE>(application->hmi_level(), - HMILevel::HMI_FULL, - HMILevel::HMI_LIMITED)) { - if (!InsertApplicationData(application, policy_app_id, device_mac)) { - LOG4CXX_ERROR(logger_, "Saving data of application is failed"); - return; - } - } + } else if (application_exist) { + if (!UpdateApplicationData(application, policy_app_id, device_mac)) { + LOG4CXX_ERROR(logger_, "Updating application data is failed"); + return; } + LOG4CXX_INFO(logger_, "Application data were updated successfully"); + } else if (!InsertApplicationData(application, policy_app_id, device_mac)) { + LOG4CXX_ERROR(logger_, "Saving data of application is failed"); + return; } WriteDb(); } @@ -238,7 +229,7 @@ void ResumptionDataDB::IncrementIgnOffCount() { } } - if (query_update_last_ign_off_time.Prepare(KUpdateLastIgnOffTime)) { + if (query_update_last_ign_off_time.Prepare(kUpdateLastIgnOffTime)) { query_update_last_ign_off_time.Bind(0, static_cast<int64_t>(time(NULL))); if (query_update_last_ign_off_time.Exec()) { LOG4CXX_INFO(logger_, "Data last_ign_off_time was updated"); @@ -372,10 +363,61 @@ bool ResumptionDataDB::RemoveApplicationFromSaved( uint32_t ResumptionDataDB::GetIgnOffTime() const { LOG4CXX_AUTO_TRACE(logger_); - return SelectIgnOffTime(); } +uint32_t ResumptionDataDB::GetGlobalIgnOnCounter() const { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock autolock(resumption_lock_); + + utils::dbms::SQLQuery query(db()); + if (!query.Prepare(kSelectGlobalIgnOnCounter)) { + LOG4CXX_ERROR(logger_, + "Problem with prepare query : " << kSelectGlobalIgnOnCounter); + return 1; + } + + if (!query.Exec()) { + LOG4CXX_ERROR(logger_, + "Problem with exec query : " << kSelectGlobalIgnOnCounter); + return 1; + } + + const auto global_ign_on_counter = query.GetUInteger(0); + LOG4CXX_DEBUG(logger_, "Global Ign On Counter = " << global_ign_on_counter); + return global_ign_on_counter; +} + +void ResumptionDataDB::IncrementGlobalIgnOnCounter() { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock autolock(resumption_lock_); + + db_->BeginTransaction(); + utils::dbms::SQLQuery query_update_global_ign_on_count(db()); + if (query_update_global_ign_on_count.Prepare(kUpdateGlobalIgnOnCount)) { + if (query_update_global_ign_on_count.Exec()) { + LOG4CXX_DEBUG(logger_, + "Data query_update_global_ign_on_count was updated"); + } + } + db_->CommitTransaction(); + WriteDb(); +} + +void ResumptionDataDB::ResetGlobalIgnOnCount() { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock autolock(resumption_lock_); + + LOG4CXX_DEBUG(logger_, "Global IGN ON counter resetting"); + + utils::dbms::SQLQuery query_update_global_ign_on_count(db()); + if (query_update_global_ign_on_count.Prepare(kResetGlobalIgnOnCount)) { + if (query_update_global_ign_on_count.Exec()) { + LOG4CXX_DEBUG(logger_, "Data was updated"); + } + } +} + ssize_t ResumptionDataDB::IsApplicationSaved( const std::string& policy_app_id, const std::string& device_id) const { LOG4CXX_AUTO_TRACE(logger_); @@ -553,7 +595,6 @@ void ResumptionDataDB::SelectDataForLoadResumeData( using namespace app_mngr; using namespace smart_objects; LOG4CXX_AUTO_TRACE(logger_); - utils::dbms::SQLQuery select_data(db()); utils::dbms::SQLQuery count_application(db()); if (!select_data.Prepare(kSelectDataForLoadResumeData) || diff --git a/src/components/application_manager/src/resumption/resumption_data_json.cc b/src/components/application_manager/src/resumption/resumption_data_json.cc index 4bd5bc8d47..87241c883a 100644 --- a/src/components/application_manager/src/resumption/resumption_data_json.cc +++ b/src/components/application_manager/src/resumption/resumption_data_json.cc @@ -279,6 +279,51 @@ uint32_t ResumptionDataJson::GetIgnOffTime() const { return resumption[strings::last_ign_off_time].asUInt(); } +uint32_t ResumptionDataJson::GetGlobalIgnOnCounter() const { + using namespace app_mngr; + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock autolock(resumption_lock_); + Json::Value& resumption = GetResumptionData(); + if (resumption.isMember(strings::global_ign_on_counter)) { + const uint32_t global_ign_on_counter = + resumption[strings::global_ign_on_counter].asUInt(); + LOG4CXX_DEBUG(logger_, "Global Ign On Counter = " << global_ign_on_counter); + return global_ign_on_counter; + } + return 1; +} + +void ResumptionDataJson::IncrementGlobalIgnOnCounter() { + using namespace app_mngr; + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock autolock(resumption_lock_); + Json::Value& resumption = GetResumptionData(); + if (resumption.isMember(strings::global_ign_on_counter)) { + const uint32_t global_ign_on_counter = + resumption[strings::global_ign_on_counter].asUInt(); + LOG4CXX_DEBUG( + logger_, + "Global IGN ON counter in resumption data: " << global_ign_on_counter); + resumption[strings::global_ign_on_counter] = global_ign_on_counter + 1; + LOG4CXX_DEBUG(logger_, + "Global IGN ON counter new value: " + << resumption[strings::global_ign_on_counter].asUInt()); + } else { + resumption[strings::global_ign_on_counter] = 1; + } + last_state().SaveStateToFileSystem(); +} + +void ResumptionDataJson::ResetGlobalIgnOnCount() { + using namespace app_mngr; + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock autolock(resumption_lock_); + Json::Value& resumption = GetResumptionData(); + + resumption[strings::global_ign_on_counter] = 0; + LOG4CXX_DEBUG(logger_, "Global IGN ON counter resetting"); +} + ssize_t ResumptionDataJson::IsApplicationSaved( const std::string& policy_app_id, const std::string& device_id) const { LOG4CXX_AUTO_TRACE(logger_); diff --git a/src/components/application_manager/src/resumption/resumption_sql_queries.cc b/src/components/application_manager/src/resumption/resumption_sql_queries.cc index 9ca91e859a..4770bafef4 100644 --- a/src/components/application_manager/src/resumption/resumption_sql_queries.cc +++ b/src/components/application_manager/src/resumption/resumption_sql_queries.cc @@ -37,6 +37,7 @@ const std::string kCreateSchema = "BEGIN ; " "CREATE TABLE IF NOT EXISTS `resumption`( " " `idresumption` INTEGER PRIMARY KEY, " + " `global_ign_on_count` INTEGER, " " `last_ign_off_time` INTEGER " " ); " "CREATE TABLE IF NOT EXISTS `subscribedForWayPoints`( " @@ -372,7 +373,9 @@ const std::string kDropSchema = "VACUUM;"; const std::string kInsertInitData = - "INSERT OR IGNORE INTO `resumption` (`last_ign_off_time`) VALUES (0); " + "INSERT OR IGNORE INTO `resumption` " + "(`last_ign_off_time`, `global_ign_on_count`) " + "VALUES (0, 0); " "INSERT OR IGNORE INTO `_internal_data` (`db_version_hash`) VALUES(0); "; const std::string kChecksResumptionData = @@ -410,6 +413,17 @@ const std::string kSelectHashId = const std::string kSelectIgnOffTime = "SELECT `last_ign_off_time` FROM `resumption`"; +const std::string kSelectGlobalIgnOnCounter = + "SELECT `global_ign_on_count` FROM `resumption`"; + +const std::string kResetGlobalIgnOnCount = + "UPDATE `resumption` " + "SET `global_ign_on_count` = 0"; + +const std::string kUpdateGlobalIgnOnCount = + "UPDATE `resumption` " + "SET `global_ign_on_count` = `global_ign_on_count` + 1 "; + const std::string kCheckApplication = "SELECT COUNT (`deviceID`) FROM `application` " "WHERE `deviceID` = ? AND `appID` = ?"; @@ -445,7 +459,7 @@ const std::string kUpdateSuspendData = "UPDATE `application` " "SET `ign_off_count` = `ign_off_count` + 1"; -const std::string KUpdateLastIgnOffTime = +const std::string kUpdateLastIgnOffTime = "UPDATE `resumption` " "SET `last_ign_off_time` = ?"; diff --git a/src/components/application_manager/src/smart_object_keys.cc b/src/components/application_manager/src/smart_object_keys.cc index 006b8c9249..7f742fcd9b 100644 --- a/src/components/application_manager/src/smart_object_keys.cc +++ b/src/components/application_manager/src/smart_object_keys.cc @@ -276,6 +276,7 @@ const char* last_ign_off_time = "last_ign_off_time"; const char* resume_vr_grammars = "resumeVrGrammars"; const char* ign_off_count = "ign_off_count"; +const char* global_ign_on_counter = "global_ign_on_counter"; const char* suspend_count = "suspend_count"; const char* connection_info = "connection_info"; diff --git a/src/components/application_manager/src/state_controller_impl.cc b/src/components/application_manager/src/state_controller_impl.cc index f7a147d6df..3d44709657 100644 --- a/src/components/application_manager/src/state_controller_impl.cc +++ b/src/components/application_manager/src/state_controller_impl.cc @@ -458,6 +458,8 @@ mobile_apis::HMILevel::eType StateControllerImpl::GetAvailableHmiLevel( LOG4CXX_AUTO_TRACE(logger_); mobile_apis::HMILevel::eType result = hmi_level; + LOG4CXX_DEBUG(logger_, "HMI Level: " << hmi_level); + if (!IsStreamableHMILevel(hmi_level)) { return result; } @@ -465,6 +467,7 @@ mobile_apis::HMILevel::eType StateControllerImpl::GetAvailableHmiLevel( const bool is_audio_app = app->IsAudioApplication(); const bool does_audio_app_with_same_type_exist = app_mngr_.IsAppTypeExistsInFullOrLimited(app); + if (mobile_apis::HMILevel::HMI_LIMITED == hmi_level) { if (!is_audio_app || does_audio_app_with_same_type_exist) { result = app_mngr_.GetDefaultHmiLevel(app); diff --git a/src/components/application_manager/test/commands/CMakeLists.txt b/src/components/application_manager/test/commands/CMakeLists.txt index 165b5fc0fb..33258e60db 100644 --- a/src/components/application_manager/test/commands/CMakeLists.txt +++ b/src/components/application_manager/test/commands/CMakeLists.txt @@ -35,6 +35,7 @@ include_directories( ${COMPONENTS_DIR}/application_manager/include/ ${COMPONENTS_DIR}/application_manager/include/application_manager/ ${COMPONENTS_DIR}/application_manager/include/application_manager/commands/ + ${CMAKE_SOURCE_DIR}/src ) set(COMMANDS_TEST_DIR ${AM_TEST_DIR}/commands) diff --git a/src/components/application_manager/test/include/application_manager/mock_resume_ctrl.h b/src/components/application_manager/test/include/application_manager/mock_resume_ctrl.h index 3c4a3806d6..0fa7a898be 100644 --- a/src/components/application_manager/test/include/application_manager/mock_resume_ctrl.h +++ b/src/components/application_manager/test/include/application_manager/mock_resume_ctrl.h @@ -50,8 +50,15 @@ class MockResumeCtrl : public resumption::ResumeCtrl { MOCK_METHOD0(OnSuspend, void()); MOCK_METHOD0(OnIgnitionOff, void()); MOCK_METHOD0(OnAwake, void()); + MOCK_CONST_METHOD0(LowVoltageTime, time_t()); + MOCK_CONST_METHOD0(WakeUpTime, time_t()); + MOCK_METHOD0(SaveLowVoltageTime, void()); + MOCK_METHOD0(SaveWakeUpTime, void()); + MOCK_METHOD0(ResetLowVoltageTime, void()); + MOCK_METHOD0(ResetWakeUpTime, void()); MOCK_CONST_METHOD0(is_suspended, bool()); MOCK_METHOD0(StopSavePersistentDataTimer, void()); + MOCK_METHOD0(StartSavePersistentDataTimer, void()); MOCK_METHOD2(StartResumption, bool(app_mngr::ApplicationSharedPtr application, const std::string& hash)); diff --git a/src/components/application_manager/test/include/application_manager/mock_resumption_data.h b/src/components/application_manager/test/include/application_manager/mock_resumption_data.h index cfec034653..38d1944dba 100644 --- a/src/components/application_manager/test/include/application_manager/mock_resumption_data.h +++ b/src/components/application_manager/test/include/application_manager/mock_resumption_data.h @@ -66,6 +66,10 @@ class MockResumptionData : public ::resumption::ResumptionData { const std::string& device_id, std::string& hash_id)); MOCK_METHOD0(OnAwake, void()); + MOCK_METHOD0(IncrementGlobalIgnOnCounter, void()); + MOCK_CONST_METHOD0(GetGlobalIgnOnCounter, uint32_t()); + MOCK_METHOD0(ResetGlobalIgnOnCount, void()); + MOCK_METHOD0(DecrementIgnOffCount, void()); MOCK_CONST_METHOD3(GetSavedApplication, bool(const std::string& policy_app_id, diff --git a/src/components/application_manager/test/resumption/resume_ctrl_test.cc b/src/components/application_manager/test/resumption/resume_ctrl_test.cc index 54c76fcf94..1c2339096c 100644 --- a/src/components/application_manager/test/resumption/resume_ctrl_test.cc +++ b/src/components/application_manager/test/resumption/resume_ctrl_test.cc @@ -44,6 +44,7 @@ #include "application_manager/application_manager_impl.h" #include "application_manager/application.h" #include "utils/data_accessor.h" +#include "config_profile/profile.h" #include "application_manager/mock_message_helper.h" #include "application_manager/mock_application_manager.h" @@ -89,7 +90,11 @@ class ResumeCtrlTest : public ::testing::Test { , kDefaultDeferredTestLevel_(eType::INVALID_ENUM) , kNaviLowbandwidthLevel_("LIMITED") , kProjectionLowbandwidthLevel_("NONE") - , kMediaLowbandwidthLevel_("NONE") {} + , kMediaLowbandwidthLevel_("NONE") { + profile::Profile profile_; + profile_.set_config_file_name("smartDeviceLink.ini"); + resumption_delay_before_ign_ = profile_.resumption_delay_before_ign(); + } virtual void SetUp() OVERRIDE { Mock::VerifyAndClearExpectations(&mock_app_mngr_); @@ -153,7 +158,7 @@ class ResumeCtrlTest : public ::testing::Test { NiceMock<event_engine_test::MockEventDispatcher> mock_event_dispatcher_; application_manager_test::MockApplicationManagerSettings mock_application_manager_settings_; - application_manager_test::MockApplicationManager mock_app_mngr_; + NiceMock<application_manager_test::MockApplicationManager> mock_app_mngr_; std::shared_ptr<NiceMock<application_manager_test::MockAppExtension> > mock_app_extension_; MockStateController mock_state_controller_; @@ -172,6 +177,7 @@ class ResumeCtrlTest : public ::testing::Test { const std::string kHash_; const uint32_t kAppResumingTimeout_; const uint32_t kTestTimeStamp_; + uint32_t resumption_delay_before_ign_; std::shared_ptr<sync_primitives::Lock> app_set_lock_ptr_; sync_primitives::Lock app_set_lock_; const mobile_apis::HMILevel::eType kDefaultDeferredTestLevel_; @@ -613,8 +619,12 @@ TEST_F(ResumeCtrlTest, StartAppHmiStateResumption_AppInFull) { mobile_apis::HMILevel::eType restored_test_type = eType::HMI_FULL; uint32_t ign_off_count = 0; smart_objects::SmartObject saved_app; + const uint32_t time_offset = 5; + const uint32_t time_stamp = + time(nullptr) - resumption_delay_before_ign_ + time_offset; saved_app[application_manager::strings::ign_off_count] = ign_off_count; saved_app[application_manager::strings::hmi_level] = restored_test_type; + saved_app[application_manager::strings::time_stamp] = time_stamp; application_manager::CommandsMap command; DataAccessor<application_manager::CommandsMap> data_accessor( @@ -661,8 +671,12 @@ TEST_F(ResumeCtrlTest, StartAppHmiStateResumption_AppHasDeferredResumption) { mobile_apis::HMILevel::eType deferred_level = eType::HMI_FULL; uint32_t ign_off_count = 0; smart_objects::SmartObject saved_app; + const uint32_t time_offset = 5; + const uint32_t time_stamp = + time(nullptr) - resumption_delay_before_ign_ + time_offset; saved_app[application_manager::strings::ign_off_count] = ign_off_count; saved_app[application_manager::strings::hmi_level] = restored_test_type; + saved_app[application_manager::strings::time_stamp] = time_stamp; // resume into deferred level instead of restored level EXPECT_CALL(mock_state_controller_, SetRegularState(_, deferred_level)) @@ -693,8 +707,12 @@ TEST_F(ResumeCtrlTest, mobile_apis::HMILevel::eType restored_test_type = eType::HMI_FULL; uint32_t ign_off_count = 0; smart_objects::SmartObject saved_app; + const uint32_t time_offset = 5; + const uint32_t time_stamp = + time(nullptr) - resumption_delay_before_ign_ + time_offset; saved_app[application_manager::strings::ign_off_count] = ign_off_count; saved_app[application_manager::strings::hmi_level] = restored_test_type; + saved_app[application_manager::strings::time_stamp] = time_stamp; EXPECT_CALL(mock_state_controller_, SetRegularState(_, eType::HMI_LIMITED)) .Times(AtLeast(1)); @@ -731,8 +749,12 @@ TEST_F( mobile_apis::HMILevel::eType restored_test_type = eType::HMI_LIMITED; uint32_t ign_off_count = 0; smart_objects::SmartObject saved_app; + const uint32_t time_offset = 5; + const uint32_t time_stamp = + time(nullptr) - resumption_delay_before_ign_ + time_offset; saved_app[application_manager::strings::ign_off_count] = ign_off_count; saved_app[application_manager::strings::hmi_level] = restored_test_type; + saved_app[application_manager::strings::time_stamp] = time_stamp; // in this test, it is expected that the app will resume into LIMITED, which // is the higher level among NONE and LIMITED @@ -869,8 +891,12 @@ TEST_F(ResumeCtrlTest, ApplicationResumptiOnTimer_AppInFull) { mobile_apis::HMILevel::eType restored_test_type = eType::HMI_FULL; const uint32_t ign_off_count = 0u; smart_objects::SmartObject saved_app; + const uint32_t time_offset = 5; + const uint32_t time_stamp = + time(nullptr) - resumption_delay_before_ign_ + time_offset; saved_app[application_manager::strings::ign_off_count] = ign_off_count; saved_app[application_manager::strings::hmi_level] = restored_test_type; + saved_app[application_manager::strings::time_stamp] = time_stamp; MockStateController state_controller; EXPECT_CALL(mock_app_mngr_, state_controller()) @@ -1203,6 +1229,194 @@ TEST_F(ResumeCtrlTest, GetSavedAppHmiLevel_AskedAppFound_INVALID_ENUM) { res_ctrl_->GetSavedAppHmiLevel(kTestPolicyAppId_, kMacAddress_)); } +TEST_F( + ResumeCtrlTest, + ResumptionLowVoltage_AppInFullUnregisteredWithinTimeFrame_HMILevelRestored) { + const mobile_apis::HMILevel::eType restored_test_type = eType::HMI_FULL; + const uint32_t time_offset = 5; + const uint32_t time_stamp = + time(nullptr) - resumption_delay_before_ign_ + time_offset; + smart_objects::SmartObject saved_app; + saved_app[application_manager::strings::hmi_level] = restored_test_type; + saved_app[application_manager::strings::time_stamp] = time_stamp; + + application_manager::CommandsMap command; + DataAccessor<application_manager::CommandsMap> data_accessor( + command, app_set_lock_ptr_); + + EXPECT_CALL(mock_state_controller_, SetRegularState(_, restored_test_type)) + .Times(AtLeast(1)); + GetInfoFromApp(); + EXPECT_CALL(mock_app_mngr_, GetDefaultHmiLevel(const_app_)) + .WillRepeatedly(Return(kDefaultTestLevel_)); + EXPECT_CALL(*mock_app_, commands_map()).WillRepeatedly(Return(data_accessor)); + ON_CALL(*mock_storage_, + GetSavedApplication(kTestPolicyAppId_, kMacAddress_, _)) + .WillByDefault(DoAll(SetArgReferee<2>(saved_app), Return(true))); + + EXPECT_CALL(*mock_storage_, + RemoveApplicationFromSaved(kTestPolicyAppId_, kMacAddress_)) + .WillOnce(Return(true)); + + ON_CALL(mock_app_mngr_, GetUserConsentForDevice("12345")) + .WillByDefault(Return(policy::kDeviceAllowed)); + + NiceMock<MockApplicationManagerSettings> app_mngr_settings_; + EXPECT_CALL(mock_app_mngr_, get_settings()) + .WillOnce(ReturnRef(app_mngr_settings_)); + + EXPECT_CALL(app_mngr_settings_, resumption_delay_before_ign()) + .WillOnce(Return(resumption_delay_before_ign_)); + + res_ctrl_->SaveLowVoltageTime(); + res_ctrl_->StartAppHmiStateResumption(mock_app_); +} + +TEST_F( + ResumeCtrlTest, + ResumptionLowVoltage_AppInFullUnregisteredBeyondTimeFrame_HMILevelNotRestored) { + const mobile_apis::HMILevel::eType restored_test_type = eType::HMI_FULL; + const uint32_t time_offset = 5; + const uint32_t time_stamp = + time(nullptr) - resumption_delay_before_ign_ - time_offset; + smart_objects::SmartObject saved_app; + saved_app[application_manager::strings::hmi_level] = restored_test_type; + saved_app[application_manager::strings::time_stamp] = time_stamp; + + application_manager::CommandsMap command; + DataAccessor<application_manager::CommandsMap> data_accessor( + command, app_set_lock_ptr_); + + EXPECT_CALL(mock_app_mngr_, state_controller()).Times(0); + GetInfoFromApp(); + EXPECT_CALL(mock_app_mngr_, GetDefaultHmiLevel(const_app_)) + .WillRepeatedly(Return(kDefaultTestLevel_)); + EXPECT_CALL(*mock_app_, commands_map()).WillRepeatedly(Return(data_accessor)); + ON_CALL(*mock_storage_, + GetSavedApplication(kTestPolicyAppId_, kMacAddress_, _)) + .WillByDefault(DoAll(SetArgReferee<2>(saved_app), Return(true))); + + ON_CALL(mock_app_mngr_, GetUserConsentForDevice("12345")) + .WillByDefault(Return(policy::kDeviceAllowed)); + + NiceMock<MockApplicationManagerSettings> app_mngr_settings_; + EXPECT_CALL(mock_app_mngr_, get_settings()) + .WillOnce(ReturnRef(app_mngr_settings_)); + + EXPECT_CALL(app_mngr_settings_, resumption_delay_before_ign()) + .WillOnce(Return(resumption_delay_before_ign_)); + + res_ctrl_->SaveLowVoltageTime(); + res_ctrl_->StartAppHmiStateResumption(mock_app_); +} + +TEST_F(ResumeCtrlTest, ResumptionLowVoltage_AppInBackground_NotRestored) { + const mobile_apis::HMILevel::eType restored_test_type = eType::HMI_BACKGROUND; + const uint32_t time_offset = 5; + const uint32_t time_stamp = + time(nullptr) - resumption_delay_before_ign_ - time_offset; + smart_objects::SmartObject saved_app; + saved_app[application_manager::strings::hmi_level] = restored_test_type; + saved_app[application_manager::strings::time_stamp] = time_stamp; + + application_manager::CommandsMap command; + DataAccessor<application_manager::CommandsMap> data_accessor( + command, app_set_lock_ptr_); + + EXPECT_CALL(mock_app_mngr_, state_controller()).Times(0); + GetInfoFromApp(); + EXPECT_CALL(mock_app_mngr_, GetDefaultHmiLevel(const_app_)) + .WillRepeatedly(Return(kDefaultTestLevel_)); + EXPECT_CALL(*mock_app_, commands_map()).WillRepeatedly(Return(data_accessor)); + ON_CALL(*mock_storage_, + GetSavedApplication(kTestPolicyAppId_, kMacAddress_, _)) + .WillByDefault(DoAll(SetArgReferee<2>(saved_app), Return(true))); + + res_ctrl_->SaveLowVoltageTime(); + res_ctrl_->StartAppHmiStateResumption(mock_app_); +} + +TEST_F( + ResumeCtrlTest, + ResumptionLowVoltage_AppInLimitedlUnregisteredWithinTimeFrame_HMILevelRestored) { + const mobile_apis::HMILevel::eType restored_test_type = eType::HMI_LIMITED; + const uint32_t time_offset = 5; + const uint32_t time_stamp = + time(nullptr) - resumption_delay_before_ign_ + time_offset; + smart_objects::SmartObject saved_app; + saved_app[application_manager::strings::hmi_level] = restored_test_type; + saved_app[application_manager::strings::time_stamp] = time_stamp; + + application_manager::CommandsMap command; + DataAccessor<application_manager::CommandsMap> data_accessor( + command, app_set_lock_ptr_); + + EXPECT_CALL(mock_state_controller_, SetRegularState(_, restored_test_type)) + .Times(AtLeast(1)); + GetInfoFromApp(); + EXPECT_CALL(mock_app_mngr_, GetDefaultHmiLevel(const_app_)) + .WillRepeatedly(Return(kDefaultTestLevel_)); + EXPECT_CALL(*mock_app_, commands_map()).WillRepeatedly(Return(data_accessor)); + ON_CALL(*mock_storage_, + GetSavedApplication(kTestPolicyAppId_, kMacAddress_, _)) + .WillByDefault(DoAll(SetArgReferee<2>(saved_app), Return(true))); + + EXPECT_CALL(*mock_storage_, + RemoveApplicationFromSaved(kTestPolicyAppId_, kMacAddress_)) + .WillOnce(Return(true)); + + ON_CALL(mock_app_mngr_, GetUserConsentForDevice("12345")) + .WillByDefault(Return(policy::kDeviceAllowed)); + + NiceMock<MockApplicationManagerSettings> app_mngr_settings_; + EXPECT_CALL(mock_app_mngr_, get_settings()) + .WillOnce(ReturnRef(app_mngr_settings_)); + + EXPECT_CALL(app_mngr_settings_, resumption_delay_before_ign()) + .WillOnce(Return(resumption_delay_before_ign_ + time_offset)); + + res_ctrl_->SaveLowVoltageTime(); + res_ctrl_->StartAppHmiStateResumption(mock_app_); +} + +TEST_F( + ResumeCtrlTest, + ResumptionLowVoltage_AppInLimitedlUnregisteredBeyondTimeFrame_HMILevelNotRestored) { + const mobile_apis::HMILevel::eType restored_test_type = eType::HMI_LIMITED; + const uint32_t time_offset = 5; + const uint32_t time_stamp = + time(nullptr) - resumption_delay_before_ign_ - time_offset; + smart_objects::SmartObject saved_app; + saved_app[application_manager::strings::hmi_level] = restored_test_type; + saved_app[application_manager::strings::time_stamp] = time_stamp; + + application_manager::CommandsMap command; + DataAccessor<application_manager::CommandsMap> data_accessor( + command, app_set_lock_ptr_); + + EXPECT_CALL(mock_app_mngr_, state_controller()).Times(0); + GetInfoFromApp(); + EXPECT_CALL(mock_app_mngr_, GetDefaultHmiLevel(const_app_)) + .WillRepeatedly(Return(kDefaultTestLevel_)); + EXPECT_CALL(*mock_app_, commands_map()).WillRepeatedly(Return(data_accessor)); + ON_CALL(*mock_storage_, + GetSavedApplication(kTestPolicyAppId_, kMacAddress_, _)) + .WillByDefault(DoAll(SetArgReferee<2>(saved_app), Return(true))); + + ON_CALL(mock_app_mngr_, GetUserConsentForDevice("12345")) + .WillByDefault(Return(policy::kDeviceAllowed)); + + NiceMock<MockApplicationManagerSettings> app_mngr_settings_; + EXPECT_CALL(mock_app_mngr_, get_settings()) + .WillOnce(ReturnRef(app_mngr_settings_)); + + EXPECT_CALL(app_mngr_settings_, resumption_delay_before_ign()) + .WillOnce(Return(resumption_delay_before_ign_)); + + res_ctrl_->SaveLowVoltageTime(); + res_ctrl_->StartAppHmiStateResumption(mock_app_); +} + } // namespace resumption_test } // namespace components } // namespace test diff --git a/src/components/application_manager/test/resumption/resumption_data_db_test.cc b/src/components/application_manager/test/resumption/resumption_data_db_test.cc index 953f43e056..8423520b9f 100644 --- a/src/components/application_manager/test/resumption/resumption_data_db_test.cc +++ b/src/components/application_manager/test/resumption/resumption_data_db_test.cc @@ -123,7 +123,7 @@ class ResumptionDataDBTest : public ResumptionDataTest { void SetZeroIgnOffTime() { utils::dbms::SQLQuery query(test_db()); - EXPECT_TRUE(query.Prepare(KUpdateLastIgnOffTime)); + EXPECT_TRUE(query.Prepare(kUpdateLastIgnOffTime)); query.Bind(0, 0); EXPECT_TRUE(query.Exec()); } diff --git a/src/components/config_profile/include/config_profile/profile.h b/src/components/config_profile/include/config_profile/profile.h index 81e38504d7..c6fc2017b9 100644 --- a/src/components/config_profile/include/config_profile/profile.h +++ b/src/components/config_profile/include/config_profile/profile.h @@ -110,6 +110,27 @@ class Profile : public protocol_handler::ProtocolHandlerSettings, const std::string& app_resource_folder() const; /** + * @brief Returns offset from SIGRTMIN for user defined signal + * SIGLOWVOLTAGE + * which is used for handling LOW Voltage functionality + */ + int low_voltage_signal_offset() const; + + /** + * @brief Returns offset from SIGRTMIN for user defined signal + * SIGWAKEUP + * which is used for handling LOW Voltage functionality + */ + int wake_up_signal_offset() const; + + /** + * @brief Returns offset from SIGRTMIN for user defined signal + * SIGIGNITIONOFF + * which is used for handling LOW Voltage functionality + */ + int ignition_off_signal_offset() const; + + /** * @brief Returns application icons folder path */ const std::string& app_icons_folder() const OVERRIDE; @@ -1012,6 +1033,9 @@ class Profile : public protocol_handler::ProtocolHandlerSettings, std::vector<std::string> video_service_transports_; bool error_occured_; std::string error_description_; + int low_voltage_signal_offset_; + int wake_up_signal_offset_; + int ignition_off_signal_offset_; DISALLOW_COPY_AND_ASSIGN(Profile); }; diff --git a/src/components/config_profile/src/profile.cc b/src/components/config_profile/src/profile.cc index cdb9d543f0..e24e0c4481 100644 --- a/src/components/config_profile/src/profile.cc +++ b/src/components/config_profile/src/profile.cc @@ -222,6 +222,9 @@ const char* kEnableAppLaunchIOSKey = "EnableAppLaunchIOS"; const char* kAppTransportChangeTimerKey = "AppTransportChangeTimer"; const char* kAppTransportChangeTimerAdditionKey = "AppTransportChangeTimerAddition"; +const char* kLowVoltageSignalOffsetKey = "LowVoltageSignal"; +const char* kWakeUpSignalOffsetKey = "WakeUpSignal"; +const char* kIgnitionOffSignalOffsetKey = "IgnitionOffSignal"; const char* kMultipleTransportsEnabledKey = "MultipleTransportsEnabled"; const char* kSecondaryTransportForBluetoothKey = "SecondaryTransportForBluetooth"; @@ -372,6 +375,9 @@ const uint16_t kDefaultWaitTimeBetweenApps = 4000; const bool kDefaultEnableAppLaunchIOS = true; const uint32_t kDefaultAppTransportChangeTimer = 500u; const uint32_t kDefaultAppTransportChangeTimerAddition = 0u; +const int32_t kDefaultLowVoltageSignalOffset = 1; +const int32_t kDefaultWakeUpSignalOffset = 2; +const int32_t kDefaultIgnitionOffSignalOffset = 3; const std::string kAllowedSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-"; const bool kDefaultMultipleTransportsEnabled = false; @@ -485,7 +491,10 @@ Profile::Profile() kDefaultAppTransportChangeTimerAddition) , multiple_transports_enabled_(kDefaultMultipleTransportsEnabled) , error_occured_(false) - , error_description_() { + , error_description_() + , low_voltage_signal_offset_(kDefaultLowVoltageSignalOffset) + , wake_up_signal_offset_(kDefaultWakeUpSignalOffset) + , ignition_off_signal_offset_(kDefaultIgnitionOffSignalOffset) { // SDL version ReadStringValue( &sdl_version_, kDefaultSDLVersion, kMainSection, kSDLVersionKey); @@ -530,6 +539,18 @@ const std::string& Profile::app_resource_folder() const { return app_resource_folder_; } +int Profile::low_voltage_signal_offset() const { + return low_voltage_signal_offset_; +} + +int Profile::wake_up_signal_offset() const { + return wake_up_signal_offset_; +} + +int Profile::ignition_off_signal_offset() const { + return ignition_off_signal_offset_; +} + const std::string& Profile::app_icons_folder() const { return app_icons_folder_; } @@ -2120,6 +2141,30 @@ void Profile::UpdateValues() { kAppTransportChangeTimerAdditionKey, kMainSection); + ReadIntValue(&low_voltage_signal_offset_, + kDefaultLowVoltageSignalOffset, + kMainSection, + kLowVoltageSignalOffsetKey); + + LOG_UPDATED_VALUE( + low_voltage_signal_offset_, kLowVoltageSignalOffsetKey, kMainSection); + + ReadIntValue(&wake_up_signal_offset_, + kDefaultWakeUpSignalOffset, + kMainSection, + kWakeUpSignalOffsetKey); + + LOG_UPDATED_VALUE( + wake_up_signal_offset_, kWakeUpSignalOffsetKey, kMainSection); + + ReadIntValue(&ignition_off_signal_offset_, + kDefaultIgnitionOffSignalOffset, + kMainSection, + kIgnitionOffSignalOffsetKey); + + LOG_UPDATED_VALUE( + ignition_off_signal_offset_, kIgnitionOffSignalOffsetKey, kMainSection); + ReadBoolValue(&multiple_transports_enabled_, kDefaultMultipleTransportsEnabled, kMultipleTransportsSection, diff --git a/src/components/include/application_manager/application_manager.h b/src/components/include/application_manager/application_manager.h index 5858178fd8..98bad87bf0 100644 --- a/src/components/include/application_manager/application_manager.h +++ b/src/components/include/application_manager/application_manager.h @@ -33,6 +33,7 @@ #ifndef SRC_COMPONENTS_INCLUDE_APPLICATION_MANAGER_APPLICATION_MANAGER_H_ #define SRC_COMPONENTS_INCLUDE_APPLICATION_MANAGER_APPLICATION_MANAGER_H_ +#include <ctime> #include <string> #include <vector> #include <set> @@ -402,6 +403,11 @@ class ApplicationManager { virtual void EndNaviServices(uint32_t app_id) = 0; /** + * @brief returns true if low voltage state is active + */ + virtual bool IsLowVoltage() const = 0; + + /** * @brief Starts AudioPassThru process by given application * @param app_id ID of the application which starts the process * @return true if AudioPassThru can be started, false otherwise @@ -460,8 +466,6 @@ class ApplicationManager { virtual bool IsStopping() const = 0; - virtual bool IsLowVoltage() = 0; - virtual void RemoveAppFromTTSGlobalPropertiesList(const uint32_t app_id) = 0; virtual mobile_apis::Result::eType SaveBinary( diff --git a/src/components/include/test/application_manager/mock_application_manager.h b/src/components/include/test/application_manager/mock_application_manager.h index 37e38e3ed7..4b824d4ac8 100644 --- a/src/components/include/test/application_manager/mock_application_manager.h +++ b/src/components/include/test/application_manager/mock_application_manager.h @@ -140,6 +140,7 @@ class MockApplicationManager : public application_manager::ApplicationManager { void(const smart_objects::SmartObject& sm_object, const uint32_t connection_key)); MOCK_CONST_METHOD0(is_attenuated_supported, bool()); + MOCK_CONST_METHOD0(IsLowVoltage, bool()); MOCK_CONST_METHOD1(IsAppTypeExistsInFullOrLimited, bool(application_manager::ApplicationConstSharedPtr app)); MOCK_METHOD1(OnApplicationRegistered, @@ -178,7 +179,6 @@ class MockApplicationManager : public application_manager::ApplicationManager { MOCK_CONST_METHOD1(IsAppsQueriedFrom, bool(const connection_handler::DeviceHandle handle)); MOCK_CONST_METHOD0(IsStopping, bool()); - MOCK_METHOD0(IsLowVoltage, bool()); MOCK_METHOD1(RemoveAppFromTTSGlobalPropertiesList, void(const uint32_t app_id)); MOCK_METHOD4( diff --git a/src/components/include/utils/typed_enum_print.h b/src/components/include/utils/typed_enum_print.h new file mode 100644 index 0000000000..e2b903c948 --- /dev/null +++ b/src/components/include/utils/typed_enum_print.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_INCLUDE_UTILS_TYPED_ENUM_PRINT_H_ +#define SRC_COMPONENTS_INCLUDE_UTILS_TYPED_ENUM_PRINT_H_ + +#include <type_traits> +#include <ostream> + +namespace utils { + +// Generic overloaded operator "<<" to be able to send enum class values to +// std::ostream +template <typename T> +std::ostream& operator<<( + typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, + const T& e) { + return stream << static_cast<int>(e); +} + +} // namespace utils + +#endif // SRC_COMPONENTS_INCLUDE_UTILS_TYPED_ENUM_PRINT_H_ diff --git a/src/components/transport_manager/src/transport_manager_impl.cc b/src/components/transport_manager/src/transport_manager_impl.cc index abe4edd812..143498205c 100644 --- a/src/components/transport_manager/src/transport_manager_impl.cc +++ b/src/components/transport_manager/src/transport_manager_impl.cc @@ -532,6 +532,8 @@ int TransportManagerImpl::Reinit() { LOG4CXX_AUTO_TRACE(logger_); DisconnectAllDevices(); TerminateAllAdapters(); + device_to_adapter_map_.clear(); + connection_id_counter_ = 0; int ret = InitAllAdapters(); return ret; } diff --git a/src/components/utils/CMakeLists.txt b/src/components/utils/CMakeLists.txt index ed90c6fb45..a6ded9a186 100644 --- a/src/components/utils/CMakeLists.txt +++ b/src/components/utils/CMakeLists.txt @@ -40,6 +40,7 @@ include_directories ( ${COMPONENTS_DIR}/protocol_handler/include ${JSONCPP_INCLUDE_DIRECTORY} ${LOG4CXX_INCLUDE_DIRECTORY} + ${CMAKE_SOURCE_DIR}/src ) # dbms diff --git a/src/components/utils/include/utils/signals.h b/src/components/utils/include/utils/signals.h index 72d29a9e28..bda83f315f 100644 --- a/src/components/utils/include/utils/signals.h +++ b/src/components/utils/include/utils/signals.h @@ -38,11 +38,61 @@ typedef void (*sighandler_t)(int); #else #include <signal.h> #endif +#include "appMain/low_voltage_signals_handler.h" namespace utils { -bool UnsibscribeFromTermination(); -bool WaitTerminationSignals(sighandler_t sig_handler); +class Signals { + public: + /** + * @brief Unsubscribe thread from termination signals SIGINT and SIGTERM + * @return True if thread unsubscribed successfuly, otherwise false + */ + static bool UnsubscribeFromTermination(); + + /** + * @brief Triggers thread to wait for termination signals SIGINT and SIGTERM + * @param sig_handler - handler to work with signals specidied above + * @return True if handler handles signals successfuly, otherwise false + */ + static bool WaitTerminationSignals(sighandler_t sig_handler); + + /** + * @brief Unsubscribe thread from low voltage signals + * SIGLOWVOLTAGE, SIGWAKEUP and SIGIGNOFF + * @return True if thread unsubscribed successfuly, otherwise false + */ + static bool UnsubscribeFromLowVoltageSignals( + const main_namespace::LowVoltageSignalsOffset& offset_data); + + /** + * @brief Sends signal to specified process + * @param signal to send + * @param destination process signal to be sent to + */ + static void SendSignal(const int signo, const pid_t pid); + + /** + * @brief Creates child process + * @return created process id or -1 in case of error + */ + static pid_t Fork(); + + /** + * @brief Wait for child process to be terminated + * @param cpid - process to wait for termination + * @param status store status information in the int to which it points + * @param options - options for exit form function + * detailed options can be found here: https://linux.die.net/man/2/waitpid + */ + static void WaitPid(pid_t cpid, int* status, int options); + + /** + * @brief Exits for process + * @param status - exit status code + */ + static void ExitProcess(const int status); +}; } // namespace utils diff --git a/src/components/utils/src/signals_posix.cc b/src/components/utils/src/signals_posix.cc index 274c254716..e13dc04f40 100644 --- a/src/components/utils/src/signals_posix.cc +++ b/src/components/utils/src/signals_posix.cc @@ -29,13 +29,16 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/wait.h> #include <csignal> #include <cstdlib> #include <stdint.h> +#include <iostream> #include "utils/signals.h" -bool utils::UnsibscribeFromTermination() { +namespace utils { +bool Signals::UnsubscribeFromTermination() { // Disable some system signals receiving in thread // by blocking those signals // (system signals processes only in the main thread) @@ -51,6 +54,42 @@ bool utils::UnsibscribeFromTermination() { return !pthread_sigmask(SIG_BLOCK, &signal_set, NULL); } +bool Signals::UnsubscribeFromLowVoltageSignals( + const main_namespace::LowVoltageSignalsOffset& offset_data) { + // Disable Low Voltage signals in main thread + // due to all further threads will inherit signals mask + sigset_t signal_set; + sigemptyset(&signal_set); + const int SIGLOWVOLTAGE = SIGRTMIN + offset_data.low_voltage_signal_offset; + const int SIGWAKEUP = SIGRTMIN + offset_data.wake_up_signal_offset; + const int SIGIGNOFF = SIGRTMIN + offset_data.ignition_off_signal_offset; + sigaddset(&signal_set, SIGLOWVOLTAGE); + sigaddset(&signal_set, SIGWAKEUP); + sigaddset(&signal_set, SIGIGNOFF); + + // Set signals mask to be blocked by thread + return !pthread_sigmask(SIG_BLOCK, &signal_set, nullptr); +} + +void Signals::SendSignal(const int signo, const pid_t pid) { + if (kill(pid, signo) == -1) { + std::cerr << "Error sending signal: " << strsignal(signo) << " to " << pid + << " .Error: " << strerror(errno) << std::endl; + } +} + +pid_t Signals::Fork() { + return fork(); +} + +void Signals::ExitProcess(const int status) { + exit(status); +} + +void Signals::WaitPid(pid_t cpid, int* status, int options) { + waitpid(cpid, status, options); +} + namespace { bool CatchSIGSEGV(sighandler_t handler) { struct sigaction act; @@ -63,7 +102,7 @@ bool CatchSIGSEGV(sighandler_t handler) { } } // namespace -bool utils::WaitTerminationSignals(sighandler_t sig_handler) { +bool Signals::WaitTerminationSignals(sighandler_t sig_handler) { sigset_t signal_set; int sig = -1; @@ -81,3 +120,4 @@ bool utils::WaitTerminationSignals(sighandler_t sig_handler) { } return false; } +} // namespace utils diff --git a/src/components/utils/test/include/utils/mock_signals_posix.h b/src/components/utils/test/include/utils/mock_signals_posix.h new file mode 100644 index 0000000000..1aad2d5873 --- /dev/null +++ b/src/components/utils/test/include/utils/mock_signals_posix.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_UTILS_TEST_INCLUDE_UTILS_MOCK_SIGNALS_POSIX_H_ +#define SRC_COMPONENTS_UTILS_TEST_INCLUDE_UTILS_MOCK_SIGNALS_POSIX_H_ + +#include "gmock/gmock.h" +#include "utils/signals.h" +#include <signal.h> +#include "appMain/low_voltage_signals_handler.h" + +namespace utils { + +class MockSignalsPosix { + public: + MOCK_METHOD0(UnsubscribeFromTermination, bool()); + MOCK_METHOD1(WaitTerminationSignals, bool(sighandler_t sig_handler)); + MOCK_METHOD1( + UnsubscribeFromLowVoltageSignals, + bool(const main_namespace::LowVoltageSignalsOffset& offset_data)); + MOCK_METHOD2(SendSignal, void(const int signo, const pid_t pid)); + MOCK_METHOD0(Fork, pid_t()); + MOCK_METHOD1(ExitProcess, void(const int status)); + MOCK_METHOD3(WaitPid, void(pid_t cpid, int* status, int options)); + + static MockSignalsPosix* signals_posix_mock(); +}; + +} // namespace utils +#endif // SRC_COMPONENTS_UTILS_TEST_INCLUDE_UTILS_MOCK_SIGNALS_POSIX_H_ diff --git a/src/components/utils/test/mock_signals_posix.cc b/src/components/utils/test/mock_signals_posix.cc new file mode 100644 index 0000000000..47531b4a9f --- /dev/null +++ b/src/components/utils/test/mock_signals_posix.cc @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "utils/mock_signals_posix.h" +#include "utils/signals.h" + +namespace utils { + +bool Signals::UnsubscribeFromTermination() { + return MockSignalsPosix::signals_posix_mock()->UnsubscribeFromTermination(); +} + +bool Signals::WaitTerminationSignals(sighandler_t sig_handler) { + return MockSignalsPosix::signals_posix_mock()->WaitTerminationSignals( + sig_handler); +} + +bool Signals::UnsubscribeFromLowVoltageSignals( + const main_namespace::LowVoltageSignalsOffset& offset_data) { + return MockSignalsPosix::signals_posix_mock() + ->UnsubscribeFromLowVoltageSignals(offset_data); +} + +void Signals::SendSignal(const int signo, const pid_t pid) { + MockSignalsPosix::signals_posix_mock()->SendSignal(signo, pid); +} + +void Signals::ExitProcess(const int status) { + MockSignalsPosix::signals_posix_mock()->ExitProcess(status); +} + +void Signals::WaitPid(pid_t cpid, int* status, int options) { + MockSignalsPosix::signals_posix_mock()->WaitPid(cpid, status, options); +} + +pid_t Signals::Fork() { + return MockSignalsPosix::signals_posix_mock()->Fork(); +} + +MockSignalsPosix* MockSignalsPosix::signals_posix_mock() { + static ::testing::NiceMock<MockSignalsPosix> signals_posix_mock; + return &signals_posix_mock; +} + +} // namespace utils |