diff options
Diffstat (limited to 'src/components/policy/policy_external/src/policy_manager_impl.cc')
-rw-r--r-- | src/components/policy/policy_external/src/policy_manager_impl.cc | 1341 |
1 files changed, 1341 insertions, 0 deletions
diff --git a/src/components/policy/policy_external/src/policy_manager_impl.cc b/src/components/policy/policy_external/src/policy_manager_impl.cc new file mode 100644 index 0000000000..88d810ecc2 --- /dev/null +++ b/src/components/policy/policy_external/src/policy_manager_impl.cc @@ -0,0 +1,1341 @@ +/* + Copyright (c) 2013, 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 "policy/policy_manager_impl.h" + +#include <algorithm> +#include <set> +#include <queue> +#include <iterator> +#include <limits> +#include "json/reader.h" +#include "json/writer.h" +#include "policy/policy_table.h" +#include "policy/pt_representation.h" +#include "policy/policy_helper.h" +#include "utils/file_system.h" +#include "utils/logger.h" +#include "utils/date_time.h" +#include "policy/cache_manager.h" +#include "policy/update_status_manager.h" +#include "config_profile/profile.h" +#include "utils/make_shared.h" + +policy::PolicyManager* CreateManager() { + return new policy::PolicyManagerImpl(); +} +void DeleteManager(policy::PolicyManager* pm) { + delete pm; +} + +namespace policy { + +CREATE_LOGGERPTR_GLOBAL(logger_, "Policy") + +PolicyManagerImpl::PolicyManagerImpl() + : PolicyManager() + , listener_(NULL) + , cache_(new CacheManager) + , retry_sequence_timeout_(60) + , retry_sequence_index_(0) + , ignition_check(true) {} + +PolicyManagerImpl::PolicyManagerImpl(bool in_memory) + : PolicyManager() + , listener_(NULL) + , cache_(new CacheManager(in_memory)) + , retry_sequence_timeout_(60) + , retry_sequence_index_(0) + , ignition_check(true) {} + +void PolicyManagerImpl::set_listener(PolicyListener* listener) { + listener_ = listener; + update_status_manager_.set_listener(listener); +} + +utils::SharedPtr<policy_table::Table> PolicyManagerImpl::Parse( + const BinaryMessage& pt_content) { + std::string json(pt_content.begin(), pt_content.end()); + Json::Value value; + Json::Reader reader; + if (reader.parse(json.c_str(), value)) { + return new policy_table::Table(&value); + } else { + return utils::SharedPtr<policy_table::Table>(); + } +} + +void PolicyManagerImpl::CheckTriggers() { + LOG4CXX_AUTO_TRACE(logger_); + const bool exceed_ignition_cycles = ExceededIgnitionCycles(); + const bool exceed_days = ExceededDays(); + + LOG4CXX_DEBUG( + logger_, + "\nDays exceeded: " << std::boolalpha << exceed_days + << "\nIgnition cycles exceeded: " << std::boolalpha + << exceed_ignition_cycles); + + if (exceed_ignition_cycles || exceed_days) { + update_status_manager_.ScheduleUpdate(); + } +} + +bool PolicyManagerImpl::LoadPT(const std::string& file, + const BinaryMessage& pt_content) { + LOG4CXX_INFO(logger_, "LoadPT of size " << pt_content.size()); + + // Parse message into table struct + utils::SharedPtr<policy_table::Table> pt_update = Parse(pt_content); + if (!pt_update) { + LOG4CXX_WARN(logger_, "Parsed table pointer is NULL."); + update_status_manager_.OnWrongUpdateReceived(); + return false; + } + + file_system::DeleteFile(file); + + if (!IsPTValid(pt_update, policy_table::PT_UPDATE)) { + update_status_manager_.OnWrongUpdateReceived(); + return false; + } + + update_status_manager_.OnValidUpdateReceived(); + cache_->SaveUpdateRequired(false); + + { + sync_primitives::AutoLock lock(apps_registration_lock_); + + // Get current DB data, since it could be updated during awaiting of PTU + utils::SharedPtr<policy_table::Table> policy_table_snapshot = + cache_->GenerateSnapshot(); + if (!policy_table_snapshot) { + LOG4CXX_ERROR(logger_, "Failed to create snapshot of policy table"); + return false; + } + + // Checking of difference between PTU and current policy state + // Must to be done before PTU applying since it is possible, that functional + // groups, which had been present before are absent in PTU and will be + // removed after update. So in case of revoked groups system has to know + // names and ids of revoked groups before they will be removed. + CheckPermissionsChanges(pt_update, policy_table_snapshot); + + // Replace current data with updated + if (!cache_->ApplyUpdate(*pt_update)) { + LOG4CXX_WARN(logger_, "Unsuccessful save of updated policy table."); + return false; + } + + listener_->OnCertificateUpdated( + *(pt_update->policy_table.module_config.certificate)); + + std::map<std::string, StringArray> app_hmi_types; + cache_->GetHMIAppTypeAfterUpdate(app_hmi_types); + if (!app_hmi_types.empty()) { + LOG4CXX_INFO(logger_, "app_hmi_types is full calling OnUpdateHMIAppType"); + listener_->OnUpdateHMIAppType(app_hmi_types); + } else { + LOG4CXX_INFO(logger_, "app_hmi_types empty"); + } + } + + // If there was a user request for policy table update, it should be started + // right after current update is finished + if (update_status_manager_.IsUpdateRequired()) { + StartPTExchange(); + return true; + } + + RefreshRetrySequence(); + return true; +} + +std::string PolicyManagerImpl::GetLockScreenIconUrl() const { + return cache_->GetLockScreenIconUrl(); +} + +void PolicyManagerImpl::CheckPermissionsChanges( + const utils::SharedPtr<policy_table::Table> pt_update, + const utils::SharedPtr<policy_table::Table> snapshot) { + LOG4CXX_INFO(logger_, "Checking incoming permissions."); + + // Replace predefined policies with its actual setting, e.g. "123":"default" + // to actual values of default section + UnwrapAppPolicies(pt_update->policy_table.app_policies_section.apps); + + std::for_each(pt_update->policy_table.app_policies_section.apps.begin(), + pt_update->policy_table.app_policies_section.apps.end(), + CheckAppPolicy(this, pt_update, snapshot)); +} + +void PolicyManagerImpl::PrepareNotificationData( + const policy_table::FunctionalGroupings& groups, + const policy_table::Strings& group_names, + const std::vector<FunctionalGroupPermission>& group_permission, + Permissions& notification_data) { + LOG4CXX_INFO(logger_, "Preparing data for notification."); + ProcessFunctionalGroup processor(groups, group_permission, notification_data); + std::for_each(group_names.begin(), group_names.end(), processor); +} + +void PolicyManagerImpl::GetUpdateUrls(const std::string& service_type, + EndpointUrls& out_end_points) { + LOG4CXX_AUTO_TRACE(logger_); + cache_->GetUpdateUrls(service_type, out_end_points); +} +void PolicyManagerImpl::GetUpdateUrls(const uint32_t service_type, + EndpointUrls& out_end_points) { + LOG4CXX_AUTO_TRACE(logger_); + cache_->GetUpdateUrls(service_type, out_end_points); +} + +void PolicyManagerImpl::RequestPTUpdate() { + LOG4CXX_AUTO_TRACE(logger_); + utils::SharedPtr<policy_table::Table> policy_table_snapshot = + cache_->GenerateSnapshot(); + if (!policy_table_snapshot) { + LOG4CXX_ERROR(logger_, "Failed to create snapshot of policy table"); + return; + } + + if (IsPTValid(policy_table_snapshot, policy_table::PT_SNAPSHOT)) { + Json::Value value = policy_table_snapshot->ToJsonValue(); + Json::FastWriter writer; + std::string message_string = writer.write(value); + + LOG4CXX_DEBUG(logger_, "Snapshot contents is : " << message_string); + + BinaryMessage update(message_string.begin(), message_string.end()); + + listener_->OnSnapshotCreated( + update, RetrySequenceDelaysSeconds(), TimeoutExchangeMSec()); + } else { + LOG4CXX_ERROR(logger_, "Invalid Policy table snapshot - PTUpdate failed"); + } +} + +void PolicyManagerImpl::StartPTExchange() { + LOG4CXX_AUTO_TRACE(logger_); + + if (ignition_check) { + CheckTriggers(); + ignition_check = false; + } + + if (update_status_manager_.IsAppsSearchInProgress() && + update_status_manager_.IsUpdateRequired()) { + LOG4CXX_INFO(logger_, + "Starting exchange skipped, since applications " + "search is in progress."); + return; + } + + if (update_status_manager_.IsUpdatePending()) { + update_status_manager_.ScheduleUpdate(); + LOG4CXX_INFO(logger_, + "Starting exchange skipped, since another exchange " + "is in progress."); + return; + } + LOG4CXX_INFO(logger_, "Policy want to call RequestPTUpdate"); + if (listener_ && listener_->CanUpdate()) { + LOG4CXX_INFO(logger_, "Listener CanUpdate"); + if (update_status_manager_.IsUpdateRequired()) { + LOG4CXX_INFO(logger_, "IsUpdateRequired"); + RequestPTUpdate(); + } + } +} + +void PolicyManagerImpl::OnAppsSearchStarted() { + LOG4CXX_AUTO_TRACE(logger_); + update_status_manager_.OnAppsSearchStarted(); +} + +void PolicyManagerImpl::OnAppsSearchCompleted() { + LOG4CXX_AUTO_TRACE(logger_); + update_status_manager_.OnAppsSearchCompleted(); + if (update_status_manager_.IsUpdateRequired()) { + StartPTExchange(); + } +} + +const std::vector<std::string> PolicyManagerImpl::GetAppRequestTypes( + const std::string policy_app_id) const { + std::vector<std::string> request_types; + if (kDeviceDisallowed == + cache_->GetDeviceConsent(GetCurrentDeviceId(policy_app_id))) { + cache_->GetAppRequestTypes(kPreDataConsentId, request_types); + } else { + cache_->GetAppRequestTypes(policy_app_id, request_types); + } + return request_types; +} + +const VehicleInfo PolicyManagerImpl::GetVehicleInfo() const { + return cache_->GetVehicleInfo(); +} + +void PolicyManagerImpl::CheckPermissions(const PTString& app_id, + const PTString& hmi_level, + const PTString& rpc, + const RPCParams& rpc_params, + CheckPermissionResult& result) { + LOG4CXX_INFO(logger_, + "CheckPermissions for " << app_id << " and rpc " << rpc + << " for " << hmi_level << " level."); + + const std::string device_id = GetCurrentDeviceId(app_id); + + Permissions rpc_permissions; + + // Check, if there are calculated permission present in cache + if (!cache_->IsPermissionsCalculated(device_id, app_id, rpc_permissions)) { + LOG4CXX_DEBUG(logger_, + "IsPermissionsCalculated for device: " + << device_id << " and app: " << app_id + << " returns false"); + // Get actual application group permission according to user consents + std::vector<FunctionalGroupPermission> app_group_permissions; + GetPermissionsForApp(device_id, app_id, app_group_permissions); + + // Fill struct with known groups RPCs + policy_table::FunctionalGroupings functional_groupings; + cache_->GetFunctionalGroupings(functional_groupings); + + std::vector<FunctionalGroupPermission>::const_iterator it = + app_group_permissions.begin(); + std::vector<FunctionalGroupPermission>::const_iterator it_end = + app_group_permissions.end(); + policy_table::Strings app_groups; + for (; it != it_end; ++it) { + app_groups.push_back((*it).group_name); + } + + // Undefined groups (without user consent) disallowed by default, since + // OnPermissionsChange notification has no "undefined" section + // For RPC permission checking undefinded group will be treated as separate + // type + ProcessFunctionalGroup processor(functional_groupings, + app_group_permissions, + rpc_permissions, + GroupConsent::kGroupUndefined); + std::for_each(app_groups.begin(), app_groups.end(), processor); + + cache_->AddCalculatedPermissions(device_id, app_id, rpc_permissions); + } else { + LOG4CXX_DEBUG(logger_, + "IsPermissionsCalculated for device: " + << device_id << " and app: " << app_id + << " returns true"); + } + + const bool known_rpc = rpc_permissions.end() != rpc_permissions.find(rpc); + LOG4CXX_INFO(logger_, "Is known rpc " << known_rpc); + if (!known_rpc) { + // RPC not found in list == disallowed by backend + result.hmi_level_permitted = kRpcDisallowed; + return; + } + + // Check HMI level + if (rpc_permissions[rpc].hmi_permissions[kAllowedKey].end() != + rpc_permissions[rpc].hmi_permissions[kAllowedKey].find(hmi_level)) { + // RPC found in allowed == allowed by backend and user + result.hmi_level_permitted = kRpcAllowed; + } else if (rpc_permissions[rpc].hmi_permissions[kUndefinedKey].end() != + rpc_permissions[rpc].hmi_permissions[kUndefinedKey].find( + hmi_level)) { + // RPC found in undefined == allowed by backend, but not consented yet by + // user + result.hmi_level_permitted = kRpcDisallowed; + } else if (rpc_permissions[rpc].hmi_permissions[kUserDisallowedKey].end() != + rpc_permissions[rpc].hmi_permissions[kUserDisallowedKey].find( + hmi_level)) { + // RPC found in allowed == allowed by backend, but disallowed by user + result.hmi_level_permitted = kRpcUserDisallowed; + } else { + LOG4CXX_DEBUG(logger_, + "HMI level " << hmi_level << " wasn't found " + << " for rpc " << rpc << " and appID " + << app_id); + return; + } + + if (kRpcAllowed != result.hmi_level_permitted) { + LOG4CXX_DEBUG(logger_, "RPC is not allowed. Stop parameters processing."); + result.list_of_allowed_params = + rpc_permissions[rpc].parameter_permissions[kAllowedKey]; + + result.list_of_disallowed_params = + rpc_permissions[rpc].parameter_permissions[kUserDisallowedKey]; + + result.list_of_undefined_params = + rpc_permissions[rpc].parameter_permissions[kUndefinedKey]; + return; + } + + // Considered that items disallowed by user take priority over system (policy) + // permissions, so that flag is processed first + if (rpc_permissions[rpc] + .parameter_permissions.any_parameter_disallowed_by_user) { + LOG4CXX_DEBUG(logger_, "All parameters are disallowed by user."); + result.list_of_disallowed_params = rpc_params; + result.hmi_level_permitted = kRpcUserDisallowed; + return; + } + + if (rpc_permissions[rpc] + .parameter_permissions.any_parameter_disallowed_by_policy) { + LOG4CXX_DEBUG(logger_, "All parameters are disallowed by policy."); + result.list_of_undefined_params = rpc_params; + result.hmi_level_permitted = kRpcDisallowed; + return; + } + + if (rpc_permissions[rpc].parameter_permissions.any_parameter_allowed) { + LOG4CXX_DEBUG(logger_, "All parameters are allowed."); + result.list_of_allowed_params = rpc_params; + return; + } + + result.list_of_allowed_params = + rpc_permissions[rpc].parameter_permissions[kAllowedKey]; + + result.list_of_disallowed_params = + rpc_permissions[rpc].parameter_permissions[kUserDisallowedKey]; + + result.list_of_undefined_params = + rpc_permissions[rpc].parameter_permissions[kUndefinedKey]; + + // In case of some parameters of RPC are missing in current policy table + // they will be considered as disallowed by policy itself, not by user. + // Undefined parameters contain parameters present in policy table, but which + // have not been allowed or disallowed explicitly by user, so missing params + // are being added to undefined. + RPCParams::const_iterator parameter = rpc_params.begin(); + RPCParams::const_iterator end = rpc_params.end(); + for (; end != parameter; ++parameter) { + if (!result.HasParameter(*parameter)) { + LOG4CXX_DEBUG(logger_, + "Parameter " << *parameter << " is unknown." + " Adding to undefined list."); + result.list_of_undefined_params.insert(*parameter); + } + } + + if (result.DisallowedInclude(rpc_params)) { + LOG4CXX_DEBUG(logger_, "All parameters are disallowed."); + result.hmi_level_permitted = kRpcUserDisallowed; + } else if (!result.IsAnyAllowed(rpc_params)) { + LOG4CXX_DEBUG(logger_, "There are no parameters allowed."); + result.hmi_level_permitted = kRpcDisallowed; + } + + if (cache_->IsApplicationRevoked(app_id)) { + // SDL must be able to notify mobile side with its status after app has + // been revoked by backend + if ("OnHMIStatus" == rpc && "NONE" == hmi_level) { + result.hmi_level_permitted = kRpcAllowed; + } else { + result.hmi_level_permitted = kRpcDisallowed; + } + return; + } +} + +bool PolicyManagerImpl::ResetUserConsent() { + bool result = true; + result = cache_->ResetUserConsent(); + + return result; +} + +void PolicyManagerImpl::SendNotificationOnPermissionsUpdated( + const std::string& application_id) { + LOG4CXX_AUTO_TRACE(logger_); + const std::string device_id = GetCurrentDeviceId(application_id); + if (device_id.empty()) { + LOG4CXX_WARN(logger_, + "Couldn't find device info for application id " + "'" << application_id << "'"); + return; + } + + std::vector<FunctionalGroupPermission> app_group_permissions; + GetPermissionsForApp(device_id, application_id, app_group_permissions); + + policy_table::FunctionalGroupings functional_groupings; + cache_->GetFunctionalGroupings(functional_groupings); + + policy_table::Strings app_groups; + std::vector<FunctionalGroupPermission>::const_iterator it = + app_group_permissions.begin(); + std::vector<FunctionalGroupPermission>::const_iterator it_end = + app_group_permissions.end(); + for (; it != it_end; ++it) { + app_groups.push_back((*it).group_name); + } + + Permissions notification_data; + PrepareNotificationData(functional_groupings, + app_groups, + app_group_permissions, + notification_data); + + LOG4CXX_INFO(logger_, + "Send notification for application_id:" << application_id); + + std::string default_hmi; + GetDefaultHmi(application_id, &default_hmi); + + listener()->OnPermissionsUpdated( + application_id, notification_data, default_hmi); +} + +bool PolicyManagerImpl::CleanupUnpairedDevices() { + LOG4CXX_AUTO_TRACE(logger_); + return cache_->CleanupUnpairedDevices(); +} + +DeviceConsent PolicyManagerImpl::GetUserConsentForDevice( + const std::string& device_id) const { + LOG4CXX_AUTO_TRACE(logger_); + return cache_->GetDeviceConsent(device_id); +} + +void PolicyManagerImpl::SetUserConsentForDevice(const std::string& device_id, + const bool is_allowed) { + LOG4CXX_AUTO_TRACE(logger_); + LOG4CXX_DEBUG(logger_, "Device :" << device_id); + cache_->SetDeviceConsent(device_id, is_allowed); + if (listener_) { + listener_->OnDeviceConsentChanged(device_id, is_allowed); + } else { + LOG4CXX_WARN(logger_, + "Event listener is not initialized. " + "Can't call OnDeviceConsentChanged"); + } + if (is_allowed) { + update_status_manager_.OnDeviceConsented(); + } + StartPTExchange(); +} + +bool PolicyManagerImpl::ReactOnUserDevConsentForApp( + const std::string& app_id, const bool is_device_allowed) { + std::vector<std::string> current_request_types = GetAppRequestTypes(app_id); + std::string current_priority, new_priority; + GetPriority(app_id, ¤t_priority); + + bool result = cache_->ReactOnUserDevConsentForApp(app_id, is_device_allowed); + + std::vector<std::string> new_request_types = GetAppRequestTypes(app_id); + GetPriority(app_id, &new_priority); + std::sort(current_request_types.begin(), current_request_types.end()); + std::sort(new_request_types.begin(), new_request_types.end()); + + std::vector<std::string> diff; + std::set_symmetric_difference(current_request_types.begin(), + current_request_types.end(), + new_request_types.begin(), + new_request_types.end(), + std::back_inserter(diff)); + + AppPermissions permissions(app_id); + + if (!diff.empty()) { + permissions.requestType = new_request_types; + permissions.requestTypeChanged = true; + } + + if ((!current_priority.empty()) && (!new_priority.empty()) && + (current_priority != new_priority)) { + permissions.priority = new_priority; + } + + if (permissions.requestTypeChanged || (!permissions.priority.empty())) { + listener_->SendOnAppPermissionsChanged(permissions, app_id); + } + return result; +} + +bool PolicyManagerImpl::GetInitialAppData(const std::string& application_id, + StringArray* nicknames, + StringArray* app_hmi_types) { + LOG4CXX_AUTO_TRACE(logger_); + const bool result = nicknames && app_hmi_types; + if (result) { + cache_->GetInitialAppData(application_id, *nicknames, *app_hmi_types); + } + return result; +} + +void PolicyManagerImpl::AddDevice(const std::string& device_id, + const std::string& connection_type) { + LOG4CXX_AUTO_TRACE(logger_); + LOG4CXX_DEBUG(logger_, "Device: " << device_id); + if (!cache_->AddDevice(device_id, connection_type)) { + LOG4CXX_WARN(logger_, "Can't add device."); + } +} + +void PolicyManagerImpl::SetDeviceInfo(const std::string& device_id, + const DeviceInfo& device_info) { + LOG4CXX_AUTO_TRACE(logger_); + LOG4CXX_DEBUG(logger_, "Device :" << device_id); + if (!cache_->SetDeviceData(device_id, + device_info.hardware, + device_info.firmware_rev, + device_info.os, + device_info.os_ver, + device_info.carrier, + device_info.max_number_rfcom_ports, + device_info.connection_type)) { + LOG4CXX_WARN(logger_, "Can't set device data."); + } +} + +PermissionConsent PolicyManagerImpl::EnsureCorrectPermissionConsent( + const PermissionConsent& permissions_to_check) { + std::vector<FunctionalGroupPermission> current_user_consents; + GetUserConsentForApp(permissions_to_check.device_id, + permissions_to_check.policy_app_id, + current_user_consents); + + PermissionConsent permissions_to_set; + permissions_to_set.device_id = permissions_to_check.device_id; + permissions_to_set.policy_app_id = permissions_to_check.policy_app_id; + permissions_to_set.consent_source = permissions_to_check.consent_source; + + std::vector<FunctionalGroupPermission>::const_iterator it = + permissions_to_check.group_permissions.begin(); + std::vector<FunctionalGroupPermission>::const_iterator it_end = + permissions_to_check.group_permissions.end(); + + for (; it != it_end; ++it) { + std::vector<FunctionalGroupPermission>::const_iterator it_curr = + current_user_consents.begin(); + std::vector<FunctionalGroupPermission>::const_iterator it_curr_end = + current_user_consents.end(); + + for (; it_curr != it_curr_end; ++it_curr) { + if (it->group_alias == it_curr->group_alias && + it->group_id == it_curr->group_id) { + permissions_to_set.group_permissions.push_back(*it); + } + } + } + + return permissions_to_set; +} + +void PolicyManagerImpl::CheckPendingPermissionsChanges( + const std::string& policy_app_id, + const std::vector<FunctionalGroupPermission>& current_permissions) { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock lock(app_permissions_diff_lock_); + std::map<std::string, AppPermissions>::iterator it_pending = + app_permissions_diff_.find(policy_app_id); + if (app_permissions_diff_.end() == it_pending) { + LOG4CXX_WARN( + logger_, + "No pending permissions had been found for appID: " << policy_app_id); + return; + } + + LOG4CXX_DEBUG( + logger_, + "Pending permissions had been found for appID: " << policy_app_id); + + // Change appPermissionsConsentNeeded depending on unconsented groups + // presence + std::vector<policy::FunctionalGroupPermission>::const_iterator it_groups = + current_permissions.begin(); + std::vector<policy::FunctionalGroupPermission>::const_iterator it_end_groups = + current_permissions.end(); + + for (; it_groups != it_end_groups; ++it_groups) { + if (policy::kGroupUndefined == it_groups->state) { + LOG4CXX_DEBUG( + logger_, + "Unconsented groups still present for appID: " << policy_app_id); + it_pending->second.appPermissionsConsentNeeded = true; + return; + } + } + + LOG4CXX_DEBUG( + logger_, + "Unconsented groups not present anymore for appID: " << policy_app_id); + it_pending->second.appPermissionsConsentNeeded = false; + return; +} + +void PolicyManagerImpl::SetUserConsentForApp( + const PermissionConsent& permissions) { + LOG4CXX_AUTO_TRACE(logger_); + cache_->ResetCalculatedPermissions(); + PermissionConsent verified_permissions = + EnsureCorrectPermissionConsent(permissions); + + if (!cache_->SetUserPermissionsForApp(verified_permissions)) { + LOG4CXX_WARN(logger_, "Can't set user permissions for application."); + } + + // Send OnPermissionChange notification, since consents were changed + std::vector<FunctionalGroupPermission> app_group_permissons; + GetPermissionsForApp(verified_permissions.device_id, + verified_permissions.policy_app_id, + app_group_permissons); + + // Change pending permissions isConsentNeeded state, if no unconsented + // groups left + CheckPendingPermissionsChanges(permissions.policy_app_id, + app_group_permissons); + + // Get current functional groups from DB with RPC permissions + policy_table::FunctionalGroupings functional_groups; + cache_->GetFunctionalGroupings(functional_groups); + + // Get list of groups assigned to application + policy_table::Strings app_groups; + std::vector<FunctionalGroupPermission>::const_iterator it = + app_group_permissons.begin(); + std::vector<FunctionalGroupPermission>::const_iterator it_end = + app_group_permissons.end(); + for (; it != it_end; ++it) { + app_groups.push_back((*it).group_name); + } + + // Fill notification data according to group permissions + Permissions notification_data; + PrepareNotificationData( + functional_groups, app_groups, app_group_permissons, notification_data); + + listener()->OnPermissionsUpdated(verified_permissions.policy_app_id, + notification_data); +} + +bool PolicyManagerImpl::GetDefaultHmi(const std::string& policy_app_id, + std::string* default_hmi) const { + LOG4CXX_AUTO_TRACE(logger_); + const std::string device_id = GetCurrentDeviceId(policy_app_id); + DeviceConsent device_consent = GetUserConsentForDevice(device_id); + const std::string app_id = policy::kDeviceAllowed != device_consent + ? kPreDataConsentId + : policy_app_id; + return cache_->GetDefaultHMI(app_id, *default_hmi); +} + +bool PolicyManagerImpl::GetPriority(const std::string& policy_app_id, + std::string* priority) const { + LOG4CXX_AUTO_TRACE(logger_); + if (!priority) { + LOG4CXX_WARN(logger_, "Input priority parameter is null."); + return false; + } + + return cache_->GetPriority(policy_app_id, *priority); +} + +std::vector<UserFriendlyMessage> PolicyManagerImpl::GetUserFriendlyMessages( + const std::vector<std::string>& message_code, + const std::string& language, + const std::string& active_hmi_language) { + return cache_->GetUserFriendlyMsg( + message_code, language, active_hmi_language); +} + +void PolicyManagerImpl::GetUserConsentForApp( + const std::string& device_id, + const std::string& policy_app_id, + std::vector<FunctionalGroupPermission>& permissions) { + LOG4CXX_AUTO_TRACE(logger_); + + FunctionalIdType group_types; + if (!cache_->GetPermissionsForApp(device_id, policy_app_id, group_types)) { + LOG4CXX_WARN(logger_, + "Can't get user permissions for app " << policy_app_id); + return; + } + + // Functional groups w/o alias ("user_consent_prompt") considered as + // automatically allowed and it could not be changed by user + FunctionalGroupNames group_names; + if (!cache_->GetFunctionalGroupNames(group_names)) { + LOG4CXX_WARN(logger_, "Can't get functional group names"); + return; + } + + FunctionalGroupNames::const_iterator it = group_names.begin(); + FunctionalGroupNames::const_iterator it_end = group_names.end(); + FunctionalGroupIDs auto_allowed_groups; + for (; it != it_end; ++it) { + if (it->second.first.empty()) { + auto_allowed_groups.push_back(it->first); + } + } + + FunctionalGroupIDs all_groups = group_types[kTypeGeneral]; + FunctionalGroupIDs preconsented_groups = group_types[kTypePreconsented]; + FunctionalGroupIDs consent_allowed_groups = group_types[kTypeAllowed]; + FunctionalGroupIDs consent_disallowed_groups = group_types[kTypeDisallowed]; + FunctionalGroupIDs default_groups = group_types[kTypeDefault]; + FunctionalGroupIDs predataconsented_groups = + group_types[kTypePreDataConsented]; + FunctionalGroupIDs device_groups = group_types[kTypeDevice]; + + // Sorting groups by consent + FunctionalGroupIDs preconsented_wo_auto = + ExcludeSame(preconsented_groups, auto_allowed_groups); + + FunctionalGroupIDs preconsented_wo_disallowed_auto = + ExcludeSame(preconsented_wo_auto, consent_disallowed_groups); + + FunctionalGroupIDs allowed_groups = + Merge(consent_allowed_groups, preconsented_wo_disallowed_auto); + + FunctionalGroupIDs merged_stage_1 = + Merge(default_groups, predataconsented_groups); + + FunctionalGroupIDs merged_stage_2 = Merge(merged_stage_1, device_groups); + + FunctionalGroupIDs merged_stage_3 = + Merge(merged_stage_2, auto_allowed_groups); + + FunctionalGroupIDs excluded_stage_1 = ExcludeSame(all_groups, merged_stage_3); + + FunctionalGroupIDs excluded_stage_2 = + ExcludeSame(excluded_stage_1, consent_disallowed_groups); + + FunctionalGroupIDs undefined_consent = + ExcludeSame(excluded_stage_2, allowed_groups); + + // Fill result + FillFunctionalGroupPermissions( + undefined_consent, group_names, kGroupUndefined, permissions); + FillFunctionalGroupPermissions( + allowed_groups, group_names, kGroupAllowed, permissions); + FillFunctionalGroupPermissions( + consent_disallowed_groups, group_names, kGroupDisallowed, permissions); +} + +void PolicyManagerImpl::GetPermissionsForApp( + const std::string& device_id, + const std::string& policy_app_id, + std::vector<FunctionalGroupPermission>& permissions) { + LOG4CXX_AUTO_TRACE(logger_); + std::string app_id_to_check = policy_app_id; + + bool allowed_by_default = false; + if (cache_->IsDefaultPolicy(policy_app_id)) { + app_id_to_check = kDefaultId; + allowed_by_default = true; + } else if (cache_->IsPredataPolicy(policy_app_id) || + policy::kDeviceDisallowed == GetUserConsentForDevice(device_id)) { + app_id_to_check = kPreDataConsentId; + allowed_by_default = true; + } + + FunctionalIdType group_types; + if (!cache_->GetPermissionsForApp(device_id, app_id_to_check, group_types)) { + LOG4CXX_WARN(logger_, + "Can't get user permissions for app " << policy_app_id); + return; + } + + // Functional groups w/o alias ("user_consent_prompt") considered as + // automatically allowed and it could not be changed by user + FunctionalGroupNames group_names; + if (!cache_->GetFunctionalGroupNames(group_names)) { + LOG4CXX_WARN(logger_, "Can't get functional group names"); + return; + } + + // The "default" and "pre_DataConsent" are auto-allowed groups + // So, check if application in the one of these mode. + if (allowed_by_default) { + LOG4CXX_INFO(logger_, "Get auto allowed groups"); + GroupType type = + (kDefaultId == app_id_to_check ? kTypeDefault : kTypePreDataConsented); + + FillFunctionalGroupPermissions( + group_types[type], group_names, kGroupAllowed, permissions); + } else { + // The code bellow allows to process application which + // has specific permissions(not default and pre_DataConsent). + + // All groups for specific application + FunctionalGroupIDs all_groups = group_types[kTypeGeneral]; + + // Groups assigned by the user for specific application + FunctionalGroupIDs allowed_groups = group_types[kTypeAllowed]; + + // Groups disallowed by the user for specific application + FunctionalGroupIDs common_disallowed = group_types[kTypeDisallowed]; + + // Groups that allowed by default but can be changed by the user + FunctionalGroupIDs preconsented_groups = group_types[kTypePreconsented]; + + // Groups which has user consent promt but there is no any consnets now. + FunctionalGroupIDs unconsented_groups = group_types[kTypeUnconsented]; + + // Pull common groups from allowed and preconsented parts. + FunctionalGroupIDs allowed_preconsented = + Merge(allowed_groups, preconsented_groups); + + // Get all groups that we suppose are allowed. + FunctionalGroupIDs all_allowed = Merge(allowed_preconsented, all_groups); + + // In case when same groups exists in disallowed and allowed tables, + // disallowed one have priority over allowed. So we have to remove + // all disallowed groups from allowed table. + FunctionalGroupIDs common_allowed = + ExcludeSame(all_allowed, common_disallowed); + FunctionalGroupIDs consent_disallowed = + ExcludeSame(unconsented_groups, preconsented_groups); + + // Disallowed groups are contain all directly disallowed, + // plus unconsented minus preconsented. + FunctionalGroupIDs all_disallowed = + Merge(common_disallowed, consent_disallowed); + + // Fill result + FillFunctionalGroupPermissions( + consent_disallowed, group_names, kGroupUndefined, permissions); + FillFunctionalGroupPermissions( + common_allowed, group_names, kGroupAllowed, permissions); + FillFunctionalGroupPermissions( + all_disallowed, group_names, kGroupDisallowed, permissions); + } + return; +} + +std::string& PolicyManagerImpl::GetCurrentDeviceId( + const std::string& policy_app_id) const { + LOG4CXX_INFO(logger_, "GetDeviceInfo"); + last_device_id_ = listener()->OnCurrentDeviceIdUpdateRequired(policy_app_id); + return last_device_id_; +} + +void PolicyManagerImpl::SetSystemLanguage(const std::string& language) { + cache_->SetSystemLanguage(language); +} + +void PolicyManagerImpl::SetSystemInfo(const std::string& ccpu_version, + const std::string& wers_country_code, + const std::string& language) { + LOG4CXX_AUTO_TRACE(logger_); + cache_->SetMetaInfo(ccpu_version, wers_country_code, language); +} + +void PolicyManagerImpl::OnSystemReady() { + // Update policy table for the first time with system information + if (!cache_->IsMetaInfoPresent()) { + listener()->OnSystemInfoUpdateRequired(); + } +} + +uint32_t PolicyManagerImpl::GetNotificationsNumber( + const std::string& priority) const { + LOG4CXX_AUTO_TRACE(logger_); + return cache_->GetNotificationsNumber(priority); +} + +bool PolicyManagerImpl::ExceededIgnitionCycles() { + return 0 == cache_->IgnitionCyclesBeforeExchange(); +} + +bool PolicyManagerImpl::IsPTValid( + utils::SharedPtr<policy_table::Table> policy_table, + policy_table::PolicyTableType type) const { + policy_table->SetPolicyTableType(type); + if (!policy_table->is_valid()) { + LOG4CXX_ERROR(logger_, "Policy table is not valid."); + rpc::ValidationReport report("policy_table"); + policy_table->ReportErrors(&report); + LOG4CXX_DEBUG(logger_, "Errors: " << rpc::PrettyFormat(report)); + return false; + } + return true; +} + +const PolicySettings& PolicyManagerImpl::get_settings() const { + DCHECK(settings_); + return *settings_; +} + +bool PolicyManagerImpl::ExceededDays() { + LOG4CXX_AUTO_TRACE(logger_); + + TimevalStruct current_time = date_time::DateTime::getCurrentTime(); + const int kSecondsInDay = 60 * 60 * 24; + const int days = current_time.tv_sec / kSecondsInDay; + + DCHECK(std::numeric_limits<uint16_t>::max() >= days); + + if (std::numeric_limits<uint16_t>::max() <= days) { + LOG4CXX_WARN(logger_, "The days since epoch exceeds maximum value."); + return false; + } + return 0 == cache_->DaysBeforeExchange(static_cast<uint16_t>(days)); +} + +void PolicyManagerImpl::KmsChanged(int kilometers) { + LOG4CXX_AUTO_TRACE(logger_); + if (0 == cache_->KilometersBeforeExchange(kilometers)) { + LOG4CXX_INFO(logger_, "Enough kilometers passed to send for PT update."); + update_status_manager_.ScheduleUpdate(); + StartPTExchange(); + PTUpdatedAt(KILOMETERS, kilometers); + } +} + +void PolicyManagerImpl::IncrementIgnitionCycles() { + cache_->IncrementIgnitionCycles(); +} + +std::string PolicyManagerImpl::ForcePTExchange() { + update_status_manager_.ScheduleUpdate(); + StartPTExchange(); + return update_status_manager_.StringifiedUpdateStatus(); +} + +std::string PolicyManagerImpl::GetPolicyTableStatus() const { + return update_status_manager_.StringifiedUpdateStatus(); +} + +int PolicyManagerImpl::NextRetryTimeout() { + sync_primitives::AutoLock auto_lock(retry_sequence_lock_); + LOG4CXX_DEBUG(logger_, "Index: " << retry_sequence_index_); + int next = 0; + if (!retry_sequence_seconds_.empty() && + retry_sequence_index_ < retry_sequence_seconds_.size()) { + next = retry_sequence_seconds_[retry_sequence_index_]; + ++retry_sequence_index_; + } + return next; +} + +void PolicyManagerImpl::RefreshRetrySequence() { + sync_primitives::AutoLock auto_lock(retry_sequence_lock_); + retry_sequence_timeout_ = cache_->TimeoutResponse(); + retry_sequence_seconds_.clear(); + cache_->SecondsBetweenRetries(retry_sequence_seconds_); +} + +void PolicyManagerImpl::ResetRetrySequence() { + sync_primitives::AutoLock auto_lock(retry_sequence_lock_); + retry_sequence_index_ = 0; + update_status_manager_.OnResetRetrySequence(); +} + +uint32_t PolicyManagerImpl::TimeoutExchangeMSec() { + return retry_sequence_timeout_; +} + +const std::vector<int> PolicyManagerImpl::RetrySequenceDelaysSeconds() { + sync_primitives::AutoLock auto_lock(retry_sequence_lock_); + return retry_sequence_seconds_; +} + +void PolicyManagerImpl::OnExceededTimeout() { + update_status_manager_.OnUpdateTimeoutOccurs(); +} + +void PolicyManagerImpl::OnUpdateStarted() { + uint32_t update_timeout = TimeoutExchangeMSec(); + LOG4CXX_DEBUG(logger_, + "Update timeout will be set to (milisec): " << update_timeout); + update_status_manager_.OnUpdateSentOut(update_timeout); + cache_->SaveUpdateRequired(true); +} + +void PolicyManagerImpl::PTUpdatedAt(Counters counter, int value) { + LOG4CXX_AUTO_TRACE(logger_); + cache_->SetCountersPassedForSuccessfulUpdate(counter, value); + cache_->ResetIgnitionCycles(); +} + +void PolicyManagerImpl::Increment(usage_statistics::GlobalCounterId type) { + LOG4CXX_INFO(logger_, "Increment without app id"); + cache_->Increment(type); +} + +void PolicyManagerImpl::Increment(const std::string& app_id, + usage_statistics::AppCounterId type) { + LOG4CXX_DEBUG(logger_, "Increment " << app_id << " AppCounter: " << type); + cache_->Increment(app_id, type); +} + +void PolicyManagerImpl::Set(const std::string& app_id, + usage_statistics::AppInfoId type, + const std::string& value) { + LOG4CXX_INFO(logger_, "Set " << app_id); + cache_->Set(app_id, type, value); +} + +void PolicyManagerImpl::Add(const std::string& app_id, + usage_statistics::AppStopwatchId type, + int32_t timespan_seconds) { + LOG4CXX_INFO(logger_, "Add " << app_id); + cache_->Add(app_id, type, timespan_seconds); +} + +bool PolicyManagerImpl::IsApplicationRevoked(const std::string& app_id) const { + return cache_->IsApplicationRevoked(app_id); +} + +bool PolicyManagerImpl::IsConsentNeeded(const std::string& app_id) { + LOG4CXX_AUTO_TRACE(logger_); + const std::string device_id = GetCurrentDeviceId(app_id); + int count = cache_->CountUnconsentedGroups(app_id, device_id); + LOG4CXX_DEBUG(logger_, "There are: " << count << " unconsented groups."); + return count != 0; +} + +void PolicyManagerImpl::SetVINValue(const std::string& value) { + cache_->SetVINValue(value); +} + +AppPermissions PolicyManagerImpl::GetAppPermissionsChanges( + const std::string& policy_app_id) { + typedef std::map<std::string, AppPermissions>::iterator PermissionsIt; + PermissionsIt app_id_diff = app_permissions_diff_.find(policy_app_id); + AppPermissions permissions(policy_app_id); + if (app_permissions_diff_.end() != app_id_diff) { + permissions = app_id_diff->second; + } else { + permissions.appPermissionsConsentNeeded = IsConsentNeeded(policy_app_id); + permissions.appRevoked = IsApplicationRevoked(policy_app_id); + GetPriority(permissions.application_id, &permissions.priority); + } + return permissions; +} + +void PolicyManagerImpl::RemovePendingPermissionChanges( + const std::string& app_id) { + app_permissions_diff_.erase(app_id); +} + +bool PolicyManagerImpl::CanAppKeepContext(const std::string& app_id) const { + return cache_->CanAppKeepContext(app_id); +} + +bool PolicyManagerImpl::CanAppStealFocus(const std::string& app_id) const { + return cache_->CanAppStealFocus(app_id); +} + +void PolicyManagerImpl::MarkUnpairedDevice(const std::string& device_id) { + if (!cache_->SetUnpairedDevice(device_id)) { + LOG4CXX_DEBUG(logger_, "Could not set unpaired flag for " << device_id); + return; + } + SetUserConsentForDevice(device_id, false); +} + +void PolicyManagerImpl::OnAppRegisteredOnMobile( + const std::string& application_id) { + StartPTExchange(); + SendNotificationOnPermissionsUpdated(application_id); +} + +const MetaInfo PolicyManagerImpl::GetMetaInfo() const { + LOG4CXX_AUTO_TRACE(logger_); + return cache_->GetMetaInfo(); +} + +std::string PolicyManagerImpl::RetrieveCertificate() const { + LOG4CXX_AUTO_TRACE(logger_); + return cache_->GetCertificate(); +} + +bool PolicyManagerImpl::HasCertificate() const { + return !cache_->GetCertificate().empty(); +} + +void PolicyManagerImpl::SetDecryptedCertificate( + const std::string& certificate) { + LOG4CXX_AUTO_TRACE(logger_); + cache_->SetDecryptedCertificate(certificate); +} + +/** + * @brief The CallStatusChange class notify update manager aboun new application + */ +class CallStatusChange : public utils::Callable { + public: + CallStatusChange(UpdateStatusManager& upd_manager, + const DeviceConsent& device_consent) + : upd_manager_(upd_manager), device_consent_(device_consent) {} + + // Callable interface + void operator()() const { + upd_manager_.OnNewApplicationAdded(device_consent_); + } + + private: + UpdateStatusManager& upd_manager_; + const DeviceConsent device_consent_; +}; + +StatusNotifier PolicyManagerImpl::AddApplication( + const std::string& application_id) { + LOG4CXX_AUTO_TRACE(logger_); + const std::string device_id = GetCurrentDeviceId(application_id); + DeviceConsent device_consent = GetUserConsentForDevice(device_id); + sync_primitives::AutoLock lock(apps_registration_lock_); + + if (IsNewApplication(application_id)) { + AddNewApplication(application_id, device_consent); + return utils::MakeShared<CallStatusChange>(update_status_manager_, + device_consent); + } else { + PromoteExistedApplication(application_id, device_consent); + return utils::MakeShared<utils::CallNothing>(); + } +} + +void PolicyManagerImpl::RemoveAppConsentForGroup( + const std::string& app_id, const std::string& group_name) { + cache_->RemoveAppConsentForGroup(app_id, group_name); +} + +bool PolicyManagerImpl::IsPredataPolicy( + const std::string& policy_app_id) const { + LOG4CXX_INFO(logger_, "IsPredataApp"); + return cache_->IsPredataPolicy(policy_app_id); +} + +void PolicyManagerImpl::AddNewApplication(const std::string& application_id, + DeviceConsent device_consent) { + LOG4CXX_AUTO_TRACE(logger_); + + if (kDeviceHasNoConsent == device_consent || + kDeviceDisallowed == device_consent) { + LOG4CXX_INFO(logger_, + "Setting " + << policy::kPreDataConsentId + << " permissions for application id: " << application_id); + cache_->SetPredataPolicy(application_id); + } else { + LOG4CXX_INFO(logger_, + "Setting " + << policy::kDefaultId + << " permissions for application id: " << application_id); + cache_->SetDefaultPolicy(application_id); + } +} + +void PolicyManagerImpl::PromoteExistedApplication( + const std::string& application_id, DeviceConsent device_consent) { + // If device consent changed to allowed during application being + // disconnected, app permissions should be changed also + if (kDeviceAllowed == device_consent && + cache_->IsPredataPolicy(application_id)) { + cache_->SetDefaultPolicy(application_id); + } + if (HasCertificate()) { + LOG4CXX_DEBUG(logger_, "Certificate exits, no update required."); + return; + } + + if (cache_->AppHasHMIType(application_id, policy_table::AHT_NAVIGATION)) { + update_status_manager_.ScheduleUpdate(); + } +} + +bool PolicyManagerImpl::IsNewApplication( + const std::string& application_id) const { + return false == cache_->IsApplicationRepresented(application_id); +} + +bool PolicyManagerImpl::ResetPT(const std::string& file_name) { + LOG4CXX_AUTO_TRACE(logger_); + cache_->ResetCalculatedPermissions(); + const bool result = cache_->ResetPT(file_name); + if (result) { + RefreshRetrySequence(); + } + return result; +} + +bool PolicyManagerImpl::CheckAppStorageFolder() const { + LOG4CXX_AUTO_TRACE(logger_); + const std::string app_storage_folder = get_settings().app_storage_folder(); + LOG4CXX_DEBUG(logger_, "AppStorageFolder " << app_storage_folder); + if (!file_system::DirectoryExists(app_storage_folder)) { + LOG4CXX_WARN(logger_, + "Storage directory doesn't exist " << app_storage_folder); + return false; + } + if (!(file_system::IsWritingAllowed(app_storage_folder) && + file_system::IsReadingAllowed(app_storage_folder))) { + LOG4CXX_WARN(logger_, + "Storage directory doesn't have read/write permissions " + << app_storage_folder); + return false; + } + return true; +} + +bool PolicyManagerImpl::InitPT(const std::string& file_name, + const PolicySettings* settings) { + LOG4CXX_AUTO_TRACE(logger_); + settings_ = settings; + if (!CheckAppStorageFolder()) { + LOG4CXX_ERROR(logger_, "Can not read/write into AppStorageFolder"); + return false; + } + const bool ret = cache_->Init(file_name, settings); + if (ret) { + RefreshRetrySequence(); + update_status_manager_.OnPolicyInit(cache_->UpdateRequired()); + } + return ret; +} + +uint32_t PolicyManagerImpl::HeartBeatTimeout(const std::string& app_id) const { + return cache_->HeartBeatTimeout(app_id); +} + +void PolicyManagerImpl::SaveUpdateStatusRequired(bool is_update_needed) { + cache_->SaveUpdateRequired(is_update_needed); +} + +void PolicyManagerImpl::set_cache_manager( + CacheManagerInterface* cache_manager) { + cache_ = cache_manager; +} + +} // namespace policy |