/* * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "miscdevice_service.h" #ifdef OHOS_BUILD_ENABLE_DO_NOT_DISTURB #include "common_event_support.h" #endif // OHOS_BUILD_ENABLE_DO_NOT_DISTURB #include "death_recipient_template.h" #ifdef HIVIEWDFX_HISYSEVENT_ENABLE #include "hisysevent.h" #endif // HIVIEWDFX_HISYSEVENT_ENABLE #ifdef MEMMGR_ENABLE #include "mem_mgr_client.h" #endif // MEMMGR_ENABLE #include "system_ability_definition.h" #include "sensors_errors.h" #include "vibration_priority_manager.h" #include "vibrator_client_proxy.h" #ifdef HDF_DRIVERS_INTERFACE_LIGHT #include "v1_0/light_interface_proxy.h" #endif // HDF_DRIVERS_INTERFACE_LIGHT #ifdef OHOS_BUILD_ENABLE_VIBRATOR_CUSTOM #include "permission_util.h" #include "vibrator_decoder_creator.h" #endif // OHOS_BUILD_ENABLE_VIBRATOR_CUSTOM #undef LOG_TAG #define LOG_TAG "MiscdeviceService" namespace OHOS { namespace Sensors { using namespace OHOS::HiviewDFX; namespace { auto g_miscdeviceService = MiscdeviceDelayedSpSingleton::GetInstance(); const bool G_REGISTER_RESULT = SystemAbility::MakeAndRegisterAbility(g_miscdeviceService.GetRefPtr()); const std::string VIBRATE_PERMISSION = "ohos.permission.VIBRATE"; const std::string LIGHT_PERMISSION = "ohos.permission.SYSTEM_LIGHT_CONTROL"; constexpr int32_t MAX_LIGHT_COUNT = 0XFF; constexpr int32_t MIN_VIBRATOR_TIME = 0; constexpr int32_t MAX_VIBRATOR_TIME = 1800000; constexpr int32_t MIN_VIBRATOR_COUNT = 1; constexpr int32_t MAX_VIBRATOR_COUNT = 1000; constexpr int32_t INTENSITY_MIN = 0; constexpr int32_t INTENSITY_MAX = 100; constexpr int32_t FREQUENCY_MIN = 0; constexpr int32_t FREQUENCY_MAX = 100; constexpr int32_t INTENSITY_ADJUST_MIN = 0; constexpr int32_t INTENSITY_ADJUST_MAX = 100; constexpr int32_t FREQUENCY_ADJUST_MIN = -100; constexpr int32_t FREQUENCY_ADJUST_MAX = 100; constexpr int32_t INVALID_PID = -1; constexpr int32_t BASE_YEAR = 1900; constexpr int32_t BASE_MON = 1; constexpr int32_t CONVERSION_RATE = 1000; #ifdef OHOS_BUILD_ENABLE_VIBRATOR_CUSTOM const std::string PHONE_TYPE = "phone"; #endif // OHOS_BUILD_ENABLE_VIBRATOR_CUSTOM #ifdef OHOS_BUILD_ENABLE_VIBRATOR_PRESET_INFO constexpr int32_t SHORT_VIBRATOR_DURATION = 50; #endif // OHOS_BUILD_ENABLE_VIBRATOR_PRESET_INFO } // namespace bool MiscdeviceService::isVibrationPriorityReady_ = false; std::map MiscdeviceService::devicesManageMap_; std::map, int32_t> MiscdeviceService::clientPidMap_; MiscdeviceService::MiscdeviceService() : SystemAbility(MISCDEVICE_SERVICE_ABILITY_ID, true), lightExist_(false), vibratorExist_(false), state_(MiscdeviceServiceState::STATE_STOPPED) { MISC_HILOGD("Add SystemAbility"); } MiscdeviceService::~MiscdeviceService() { std::lock_guard lock(devicesManageMutex_); auto it = devicesManageMap_.begin(); while (it != devicesManageMap_.end()) { int deviceId = it->first; const VibratorControlInfo& vibratorControlInfo_ = it->second.controlInfo; MISC_HILOGI("Device ID:%d, Motor Count:%d", deviceId, vibratorControlInfo_.motorCount); VibratorIdentifierIPC identifier; identifier.deviceId = deviceId; identifier.vibratorId = -1; StopVibratorService(identifier); it = devicesManageMap_.erase(it); } } void MiscdeviceService::OnDump() { MISC_HILOGI("Ondump is invoked"); } int32_t MiscdeviceService::SubscribeCommonEvent(const std::string &eventName, EventReceiver receiver) __attribute__((no_sanitize("cfi"))) { if (receiver == nullptr) { MISC_HILOGE("receiver is nullptr"); return ERROR; } EventFwk::MatchingSkills matchingSkills; matchingSkills.AddEvent(eventName); EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills); auto subscribePtr = std::make_shared(subscribeInfo, receiver); if (!EventFwk::CommonEventManager::SubscribeCommonEvent(subscribePtr)) { MISC_HILOGE("Subscribe common event fail"); return ERROR; } return ERR_OK; } void MiscdeviceService::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId) { MISC_HILOGI("OnAddSystemAbility systemAbilityId:%{public}d", systemAbilityId); switch (systemAbilityId) { case MEMORY_MANAGER_SA_ID: { MISC_HILOGI("Memory manager service start"); #ifdef MEMMGR_ENABLE Memory::MemMgrClient::GetInstance().NotifyProcessStatus(getpid(), PROCESS_TYPE_SA, PROCESS_STATUS_STARTED, MISCDEVICE_SERVICE_ABILITY_ID); #endif // MEMMGR_ENABLE break; } case COMMON_EVENT_SERVICE_ID: { MISC_HILOGI("Common event service start"); int32_t ret = SubscribeCommonEvent("usual.event.DATA_SHARE_READY", [this](const EventFwk::CommonEventData &data) { this->OnReceiveEvent(data); }); if (ret != ERR_OK) { MISC_HILOGE("Subscribe usual.event.DATA_SHARE_READY fail"); } #ifdef OHOS_BUILD_ENABLE_DO_NOT_DISTURB ret = SubscribeCommonEvent(EventFwk::CommonEventSupport::COMMON_EVENT_USER_SWITCHED, [this](const EventFwk::CommonEventData &data) { this->OnReceiveUserSwitchEvent(data); }); if (ret != ERR_OK) { MISC_HILOGE("Subscribe usual.event.USER_SWITCHED fail"); } #endif // OHOS_BUILD_ENABLE_DO_NOT_DISTURB AddSystemAbilityListener(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID); break; } case DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID: { MISC_HILOGI("Distributed kv data service start"); std::lock_guard lock(isVibrationPriorityReadyMutex_); if (isVibrationPriorityReady_) { /** Datashare will reconnect to the client and register data after alive */ MISC_HILOGI("PriorityManager already init"); break; } if (PriorityManager->Init()) { MISC_HILOGI("PriorityManager init"); isVibrationPriorityReady_ = true; } else { MISC_HILOGE("PriorityManager init fail"); } break; } default: { MISC_HILOGI("Unknown service, systemAbilityId:%{public}d", systemAbilityId); break; } } } void MiscdeviceService::OnReceiveEvent(const EventFwk::CommonEventData &data) { const auto &want = data.GetWant(); std::string action = want.GetAction(); if (action == "usual.event.DATA_SHARE_READY") { MISC_HILOGI("On receive usual.event.DATA_SHARE_READY"); std::lock_guard lock(isVibrationPriorityReadyMutex_); if (isVibrationPriorityReady_) { MISC_HILOGI("PriorityManager already init"); return; } if (PriorityManager->Init()) { MISC_HILOGI("PriorityManager init"); isVibrationPriorityReady_ = true; } else { MISC_HILOGE("PriorityManager init fail"); } } } #ifdef OHOS_BUILD_ENABLE_DO_NOT_DISTURB void MiscdeviceService::OnReceiveUserSwitchEvent(const EventFwk::CommonEventData &data) { const auto &want = data.GetWant(); std::string action = want.GetAction(); if (action == EventFwk::CommonEventSupport::COMMON_EVENT_USER_SWITCHED) { MISC_HILOGI("OnReceiveUserSwitchEvent user switched"); PriorityManager->ReregisterCurrentUserObserver(); #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "USER_SWITCHED_EXCEPTION", HiSysEvent::EventType::FAULT, "PKG_NAME", "OnReceiveUserSwitchEvent", "ERROR_CODE", ERR_OK); #endif // HIVIEWDFX_HISYSEVENT_ENABLE } } #endif // OHOS_BUILD_ENABLE_DO_NOT_DISTURB void MiscdeviceService::OnStart() { CALL_LOG_ENTER; if (state_ == MiscdeviceServiceState::STATE_RUNNING) { MISC_HILOGW("state_ already started"); return; } if (!InitInterface()) { MISC_HILOGE("Init interface error"); } if (!InitLightInterface()) { MISC_HILOGE("InitLightInterface failed"); } if (!SystemAbility::Publish(MiscdeviceDelayedSpSingleton::GetInstance())) { MISC_HILOGE("Publish MiscdeviceService failed"); return; } std::lock_guard lock(miscDeviceIdMapMutex_); auto ret = miscDeviceIdMap_.insert(std::make_pair(MiscdeviceDeviceId::LED, lightExist_)); if (!ret.second) { MISC_HILOGI("Light exist in miscDeviceIdMap_"); ret.first->second = lightExist_; } ret = miscDeviceIdMap_.insert(std::make_pair(MiscdeviceDeviceId::VIBRATOR, vibratorExist_)); if (!ret.second) { MISC_HILOGI("Vibrator exist in miscDeviceIdMap_"); ret.first->second = vibratorExist_; } state_ = MiscdeviceServiceState::STATE_RUNNING; #ifdef MEMMGR_ENABLE AddSystemAbilityListener(MEMORY_MANAGER_SA_ID); #endif // MEMMGR_ENABLE AddSystemAbilityListener(COMMON_EVENT_SERVICE_ID); RegisterVibratorPlugCb(); } int32_t MiscdeviceService::RegisterVibratorPlugCb() { auto ret = vibratorHdiConnection_.RegisterVibratorPlugCallback( std::bind(&MiscdeviceService::SendMsgToClient, this, std::placeholders::_1)); if (ret != ERR_OK) { MISC_HILOGE("RegisterVibratorPlugCallback failed"); return false; } MISC_HILOGI("RegisterVibratorPlugCallback success"); return true; } void MiscdeviceService::OnStartFuzz() { CALL_LOG_ENTER; if (state_ == MiscdeviceServiceState::STATE_RUNNING) { MISC_HILOGW("state_ already started"); return; } if (!InitInterface()) { MISC_HILOGE("Init interface error"); } if (!InitLightInterface()) { MISC_HILOGE("InitLightInterface failed"); } std::lock_guard lock(miscDeviceIdMapMutex_); auto ret = miscDeviceIdMap_.insert(std::make_pair(MiscdeviceDeviceId::LED, lightExist_)); if (!ret.second) { MISC_HILOGI("Light exist in miscDeviceIdMap_"); ret.first->second = lightExist_; } ret = miscDeviceIdMap_.insert(std::make_pair(MiscdeviceDeviceId::VIBRATOR, vibratorExist_)); if (!ret.second) { MISC_HILOGI("Vibrator exist in miscDeviceIdMap_"); ret.first->second = vibratorExist_; } state_ = MiscdeviceServiceState::STATE_RUNNING; } bool MiscdeviceService::InitInterface() { auto ret = vibratorHdiConnection_.ConnectHdi(); if (ret != ERR_OK) { MISC_HILOGE("InitVibratorServiceImpl failed"); return false; } GetOnlineVibratorInfo(); return true; } bool MiscdeviceService::InitLightInterface() { auto ret = lightHdiConnection_.ConnectHdi(); if (ret != ERR_OK) { MISC_HILOGE("ConnectHdi failed"); return false; } return true; } bool MiscdeviceService::IsValid(int32_t lightId) { CALL_LOG_ENTER; std::lock_guard lightInfosLock(lightInfosMutex_); for (const auto &item : lightInfos_) { if (lightId == item.GetLightId()) { return true; } } return false; } bool MiscdeviceService::IsLightAnimationValid(const LightAnimationIPC &animation) { CALL_LOG_ENTER; int32_t mode = animation.GetMode(); int32_t onTime = animation.GetOnTime(); int32_t offTime = animation.GetOffTime(); if ((mode < 0) || (mode >= LIGHT_MODE_BUTT)) { MISC_HILOGE("animation mode is invalid, mode:%{public}d", mode); return false; } if ((onTime < 0) || (offTime < 0)) { MISC_HILOGE("animation onTime or offTime is invalid, onTime:%{public}d, offTime:%{public}d", onTime, offTime); return false; } return true; } void MiscdeviceService::OnStop() { CALL_LOG_ENTER; if (state_ == MiscdeviceServiceState::STATE_STOPPED) { MISC_HILOGW("MiscdeviceService stopped already"); return; } state_ = MiscdeviceServiceState::STATE_STOPPED; int32_t ret = vibratorHdiConnection_.DestroyHdiConnection(); if (ret != ERR_OK) { MISC_HILOGE("Destroy hdi connection fail"); } #ifdef MEMMGR_ENABLE Memory::MemMgrClient::GetInstance().NotifyProcessStatus(getpid(), PROCESS_TYPE_SA, PROCESS_STATUS_DIED, MISCDEVICE_SERVICE_ABILITY_ID); #endif // MEMMGR_ENABLE } bool MiscdeviceService::ShouldIgnoreVibrate(const VibrateInfo &info, const VibratorIdentifierIPC& identifier) { std::lock_guard lock(isVibrationPriorityReadyMutex_); if (!isVibrationPriorityReady_) { MISC_HILOGE("Vibraion priority manager not ready"); return VIBRATION; } std::string curVibrateTime = GetCurrentTime(); auto vibratorThread_ = GetVibratorThread(identifier); int32_t ret = PriorityManager->ShouldIgnoreVibrate(info, vibratorThread_, identifier); if (ret != VIBRATION) { MISC_HILOGE("ShouldIgnoreVibrate currentTime:%{public}s, ret:%{public}d", curVibrateTime.c_str(), ret); } return (ret != VIBRATION); } int32_t MiscdeviceService::Vibrate(const VibratorIdentifierIPC& identifier, int32_t timeOut, int32_t usage, bool systemUsage) { PermissionUtil &permissionUtil = PermissionUtil::GetInstance(); int32_t ret = permissionUtil.CheckVibratePermission(this->GetCallingTokenID(), VIBRATE_PERMISSION); if (ret != PERMISSION_GRANTED) { #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "VIBRATOR_PERMISSIONS_EXCEPTION", HiSysEvent::EventType::SECURITY, "PKG_NAME", "VibrateStub", "ERROR_CODE", ret); #endif // HIVIEWDFX_HISYSEVENT_ENABLE MISC_HILOGE("CheckVibratePermission failed, ret:%{public}d", ret); return PERMISSION_DENIED; } if ((timeOut <= MIN_VIBRATOR_TIME) || (timeOut > MAX_VIBRATOR_TIME) || (usage >= USAGE_MAX) || (usage < 0)) { MISC_HILOGE("Invalid parameter"); return PARAMETER_ERROR; } VibrateInfo info = { .mode = VIBRATE_TIME, .packageName = GetPackageName(GetCallingTokenID()), .pid = GetCallingPid(), .uid = GetCallingUid(), .usage = usage, .systemUsage = systemUsage, .duration = timeOut }; std::string curVibrateTime = GetCurrentTime(); if (StartVibrateThreadControl(identifier, info) != ERR_OK) { MISC_HILOGE("%{public}s:vibration is ignored and high priority is vibrating or no vibration found", curVibrateTime.c_str()); return ERROR; } MISC_HILOGI("Start vibrator, currentTime:%{public}s, package:%{public}s, pid:%{public}d, usage:%{public}d," "deviceId:%{public}d, vibratorId:%{public}d, duration:%{public}d", curVibrateTime.c_str(), info.packageName.c_str(), info.pid, info.usage, identifier.deviceId, identifier.vibratorId, info.duration); return NO_ERROR; } int32_t MiscdeviceService::StopVibrator(const VibratorIdentifierIPC& identifier) { PermissionUtil &permissionUtil = PermissionUtil::GetInstance(); int32_t ret = permissionUtil.CheckVibratePermission(this->GetCallingTokenID(), VIBRATE_PERMISSION); if (ret != PERMISSION_GRANTED) { #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "VIBRATOR_PERMISSIONS_EXCEPTION", HiSysEvent::EventType::SECURITY, "PKG_NAME", "StopVibratorStub", "ERROR_CODE", ret); #endif // HIVIEWDFX_HISYSEVENT_ENABLE MISC_HILOGE("Result:%{public}d", ret); return PERMISSION_DENIED; } std::lock_guard lock(devicesManageMutex_); return StopVibratorService(identifier); } int32_t MiscdeviceService::StopVibratorService(const VibratorIdentifierIPC& identifier) { std::lock_guard lock(vibratorThreadMutex_); std::vector result = CheckDeviceIdIsValid(identifier); size_t ignoreVibrateNum = 0; if (result.empty()) { MISC_HILOGD("result is empty, no need to stop"); return ERROR; } for (const auto& paramIt : result) { auto vibratorThread_ = GetVibratorThread(paramIt); #if defined (OHOS_BUILD_ENABLE_VIBRATOR_CUSTOM) if ((vibratorThread_ == nullptr) || (!vibratorThread_->IsRunning() && !vibratorHdiConnection_.IsVibratorRunning(paramIt))) { MISC_HILOGD("Thread is not running, no need to stop"); ignoreVibrateNum ++; continue; } if (vibratorHdiConnection_.IsVibratorRunning(paramIt)) { vibratorHdiConnection_.Stop(paramIt, HDF_VIBRATOR_MODE_PRESET); vibratorHdiConnection_.Stop(paramIt, HDF_VIBRATOR_MODE_HDHAPTIC); } #else if ((vibratorThread_ == nullptr) || (!vibratorThread_->IsRunning())) { MISC_HILOGD("Thread is not running, no need to stop"); ignoreVibrateNum ++; continue; } #endif // OHOS_BUILD_ENABLE_VIBRATOR_CUSTOM StopVibrateThread(vibratorThread_); } if (ignoreVibrateNum == result.size()) { MISC_HILOGD("No vibration, no need to stop"); return NO_ERROR; } std::string packageName = GetPackageName(GetCallingTokenID()); std::string curVibrateTime = GetCurrentTime(); MISC_HILOGI("Stop vibrator, currentTime:%{public}s, package:%{public}s, pid:%{public}d, deviceId:%{public}d," "vibratorId:%{public}d", curVibrateTime.c_str(), packageName.c_str(), GetCallingPid(), identifier.deviceId, identifier.vibratorId); return NO_ERROR; } int32_t MiscdeviceService::PlayVibratorEffect(const VibratorIdentifierIPC& identifier, const std::string &effect, int32_t count, int32_t usage, bool systemUsage) { int32_t checkResult = PlayVibratorEffectCheckAuthAndParam(count, usage); if (checkResult != ERR_OK) { MISC_HILOGE("CheckAuthAndParam failed, ret:%{public}d", checkResult); return checkResult; } #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR std::optional effectInfo = vibratorHdiConnection_.GetEffectInfo(identifier, effect); if (!effectInfo) { MISC_HILOGE("GetEffectInfo fail"); return ERROR; } if (!(effectInfo->isSupportEffect)) { MISC_HILOGE("Effect not supported"); return PARAMETER_ERROR; } #endif // HDF_DRIVERS_INTERFACE_VIBRATOR VibrateInfo info = { .mode = VIBRATE_PRESET, .packageName = GetPackageName(GetCallingTokenID()), .pid = GetCallingPid(), .uid = GetCallingUid(), .usage = usage, .systemUsage = systemUsage, #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR .duration = effectInfo->duration, #endif // HDF_DRIVERS_INTERFACE_VIBRATOR .effect = effect, .count = count, .intensity = INTENSITY_ADJUST_MAX }; std::string curVibrateTime = GetCurrentTime(); if (StartVibrateThreadControl(identifier, info) != ERR_OK) { MISC_HILOGE("%{public}s:vibration is ignored and high priority is vibrating or no vibration found", curVibrateTime.c_str()); return ERROR; } MISC_HILOGI("Start vibrator, currentTime:%{public}s, package:%{public}s, pid:%{public}d, usage:%{public}d," "deviceId:%{public}d, vibratorId:%{public}d, duration:%{public}d, effect:%{public}s, count:%{public}d", curVibrateTime.c_str(), info.packageName.c_str(), info.pid, info.usage, identifier.deviceId, identifier.vibratorId, info.duration, info.effect.c_str(), info.count); return NO_ERROR; } int32_t MiscdeviceService::PlayVibratorEffectCheckAuthAndParam(int32_t count, int32_t usage) { PermissionUtil &permissionUtil = PermissionUtil::GetInstance(); int32_t ret = permissionUtil.CheckVibratePermission(this->GetCallingTokenID(), VIBRATE_PERMISSION); if (ret != PERMISSION_GRANTED) { #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "VIBRATOR_PERMISSIONS_EXCEPTION", HiSysEvent::EventType::SECURITY, "PKG_NAME", "PlayVibratorEffectStub", "ERROR_CODE", ret); #endif // HIVIEWDFX_HISYSEVENT_ENABLE MISC_HILOGE("CheckVibratePermission failed, ret:%{public}d", ret); return PERMISSION_DENIED; } if ((count < MIN_VIBRATOR_COUNT) || (count > MAX_VIBRATOR_COUNT) || (usage >= USAGE_MAX) || (usage < 0)) { MISC_HILOGE("Invalid parameter"); return PARAMETER_ERROR; } return ERR_OK; } void MiscdeviceService::StartVibrateThread(VibrateInfo info, const VibratorIdentifierIPC& identifier) { auto vibratorThread_ = GetVibratorThread(identifier); if (vibratorThread_ == nullptr) { MISC_HILOGD("No effective vibrator thread"); return; } std::vector waveInfo; if (GetAllWaveInfo(identifier, waveInfo) != ERR_OK) { MISC_HILOGE("GetAllWaveInfo failed"); return; } #ifdef OHOS_BUILD_ENABLE_VIBRATOR_PRESET_INFO VibrateInfo currentVibrateInfo = vibratorThread_->GetCurrentVibrateInfo(); if (info.duration <= SHORT_VIBRATOR_DURATION && currentVibrateInfo.duration <= SHORT_VIBRATOR_DURATION && info.mode == VIBRATE_PRESET && currentVibrateInfo.mode == VIBRATE_PRESET && info.count == 1) { vibratorThread_->UpdateVibratorEffect(info, identifier, waveInfo); FastVibratorEffect(info, identifier); } else { #endif // OHOS_BUILD_ENABLE_VIBRATOR_PRESET_INFO StopVibrateThread(vibratorThread_); #ifdef OHOS_BUILD_ENABLE_VIBRATOR_CUSTOM if (vibratorHdiConnection_.IsVibratorRunning(identifier)) { vibratorHdiConnection_.Stop(identifier, HDF_VIBRATOR_MODE_PRESET); vibratorHdiConnection_.Stop(identifier, HDF_VIBRATOR_MODE_HDHAPTIC); } #endif // OHOS_BUILD_ENABLE_VIBRATOR_CUSTOM vibratorThread_->UpdateVibratorEffect(info, identifier, waveInfo); vibratorThread_->Start("VibratorThread"); #ifdef OHOS_BUILD_ENABLE_VIBRATOR_PRESET_INFO } #endif // OHOS_BUILD_ENABLE_VIBRATOR_PRESET_INFO DumpHelper->SaveVibrateRecord(info); } void MiscdeviceService::StopVibrateThread(std::shared_ptr vibratorThread) { if ((vibratorThread != nullptr) && (vibratorThread->IsRunning())) { vibratorThread->SetExitStatus(true); vibratorThread->WakeUp(); vibratorThread->NotifyExitSync(); vibratorThread->SetExitStatus(false); vibratorThread->ResetVibrateInfo(); } } int32_t MiscdeviceService::StopVibratorByMode(const VibratorIdentifierIPC& identifier, const std::string &mode) { std::lock_guard lock(vibratorThreadMutex_); PermissionUtil &permissionUtil = PermissionUtil::GetInstance(); int32_t ret = permissionUtil.CheckVibratePermission(this->GetCallingTokenID(), VIBRATE_PERMISSION); if (ret != PERMISSION_GRANTED) { #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "VIBRATOR_PERMISSIONS_EXCEPTION", HiSysEvent::EventType::SECURITY, "PKG_NAME", "StopVibratorByModeStub", "ERROR_CODE", ret); #endif // HIVIEWDFX_HISYSEVENT_ENABLE MISC_HILOGE("CheckVibratePermission failed, ret:%{public}d", ret); return PERMISSION_DENIED; } std::vector result = CheckDeviceIdIsValid(identifier); size_t ignoreVibrateNum = 0; if (result.empty()) { MISC_HILOGD("result is empty, no need to stop"); return ERROR; } for (const auto& paramIt : result) { auto vibratorThread_ = GetVibratorThread(paramIt); if ((vibratorThread_ == nullptr) || (!vibratorThread_->IsRunning() && !vibratorHdiConnection_.IsVibratorRunning(paramIt))) { MISC_HILOGD("Thread is not running, no need to stop"); ignoreVibrateNum ++; continue; } const VibrateInfo info = vibratorThread_->GetCurrentVibrateInfo(); if (info.mode != mode) { MISC_HILOGD("Stop vibration information mismatch"); continue; } StopVibrateThread(vibratorThread_); if (vibratorHdiConnection_.IsVibratorRunning(paramIt)) { vibratorHdiConnection_.Stop(paramIt, HDF_VIBRATOR_MODE_PRESET); } } if (ignoreVibrateNum == result.size()) { MISC_HILOGD("No vibration, no need to stop"); return NO_ERROR; } std::string packageName = GetPackageName(GetCallingTokenID()); std::string curVibrateTime = GetCurrentTime(); MISC_HILOGI("Stop vibrator, currentTime:%{public}s, package:%{public}s, pid:%{public}d, deviceId:%{public}d," "vibratorId:%{public}d, mode:%{public}s", curVibrateTime.c_str(), packageName.c_str(), GetCallingPid(), identifier.deviceId, identifier.vibratorId, mode.c_str()); return NO_ERROR; } int32_t MiscdeviceService::IsSupportEffect(const VibratorIdentifierIPC& identifier, const std::string &effect, bool &state) { #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR std::optional effectInfo = vibratorHdiConnection_.GetEffectInfo(identifier, effect); if (!effectInfo) { MISC_HILOGE("GetEffectInfo fail"); return ERROR; } state = effectInfo->isSupportEffect; std::string packageName = GetPackageName(GetCallingTokenID()); std::string curVibrateTime = GetCurrentTime(); MISC_HILOGI("IsSupportEffect, currentTime:%{public}s, package:%{public}s, pid:%{public}d, effect:%{public}s," "state:%{public}d", curVibrateTime.c_str(), packageName.c_str(), GetCallingPid(), effect.c_str(), state); #endif // HDF_DRIVERS_INTERFACE_VIBRATOR return NO_ERROR; } std::string MiscdeviceService::GetCurrentTime() { timespec curTime; clock_gettime(CLOCK_REALTIME, &curTime); struct tm *timeinfo = localtime(&(curTime.tv_sec)); std::string currentTime; if (timeinfo == nullptr) { MISC_HILOGE("timeinfo is null"); return currentTime; } currentTime.append(std::to_string(timeinfo->tm_year + BASE_YEAR)).append("-") .append(std::to_string(timeinfo->tm_mon + BASE_MON)).append("-").append(std::to_string(timeinfo->tm_mday)) .append(" ").append(std::to_string(timeinfo->tm_hour)).append(":").append(std::to_string(timeinfo->tm_min)) .append(":").append(std::to_string(timeinfo->tm_sec)).append(".") .append(std::to_string(curTime.tv_nsec / (CONVERSION_RATE * CONVERSION_RATE))); return currentTime; } #ifdef OHOS_BUILD_ENABLE_VIBRATOR_CUSTOM int32_t MiscdeviceService::PlayVibratorCustom(const VibratorIdentifierIPC& identifier, int32_t fd, int64_t offset, int64_t length, const CustomHapticInfoIPC& customHapticInfoIPC) { int32_t checkResult = CheckAuthAndParam(customHapticInfoIPC.usage, customHapticInfoIPC.parameter, identifier); if (checkResult != ERR_OK) { MISC_HILOGE("CheckAuthAndParam failed, ret:%{public}d", checkResult); close(fd); return checkResult; } RawFileDescriptor rawFd; rawFd.fd = fd; rawFd.offset = offset; rawFd.length = length; JsonParser parser(rawFd); VibratorDecoderCreator creator; std::unique_ptr decoder(creator.CreateDecoder(parser)); CHKPR(decoder, ERROR); VibratePackage package; int32_t ret = decoder->DecodeEffect(rawFd, parser, package); if (ret != SUCCESS || package.patterns.empty()) { MISC_HILOGE("Decode effect error"); return ERROR; } MergeVibratorParmeters(customHapticInfoIPC.parameter, package); package.Dump(); VibrateInfo info = { .packageName = GetPackageName(GetCallingTokenID()), .pid = GetCallingPid(), .uid = GetCallingUid(), .usage = customHapticInfoIPC.usage, .systemUsage = customHapticInfoIPC.systemUsage, .package = package, }; VibratorCapacity capacity; if (GetHapticCapacityInfo(identifier, capacity) != ERR_OK) { MISC_HILOGE("GetVibratorCapacity failed"); return ERROR; } if (capacity.isSupportHdHaptic) { info.mode = VIBRATE_CUSTOM_HD; } else if (capacity.isSupportPresetMapping) { info.mode = VIBRATE_CUSTOM_COMPOSITE_EFFECT; } else if (capacity.isSupportTimeDelay) { info.mode = VIBRATE_CUSTOM_COMPOSITE_TIME; } std::string curVibrateTime = GetCurrentTime(); if (StartVibrateThreadControl(identifier, info) != ERR_OK) { MISC_HILOGE("%{public}s:vibration is ignored and high priority is vibrating or no vibration found", curVibrateTime.c_str()); return ERROR; } MISC_HILOGI("Start vibrator, currentTime:%{public}s, package:%{public}s, pid:%{public}d, usage:%{public}d," "vibratorId:%{public}d, duration:%{public}d", curVibrateTime.c_str(), info.packageName.c_str(), info.pid, info.usage, identifier.vibratorId, package.packageDuration); return NO_ERROR; } #endif // OHOS_BUILD_ENABLE_VIBRATOR_CUSTOM int32_t MiscdeviceService::CheckAuthAndParam(int32_t usage, const VibrateParameter ¶meter, const VibratorIdentifierIPC& identifier) { PermissionUtil &permissionUtil = PermissionUtil::GetInstance(); int32_t ret = permissionUtil.CheckVibratePermission(this->GetCallingTokenID(), VIBRATE_PERMISSION); if (ret != PERMISSION_GRANTED) { #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "VIBRATOR_PERMISSIONS_EXCEPTION", HiSysEvent::EventType::SECURITY, "PKG_NAME", "PlayVibratorCustomStub", "ERROR_CODE", ret); #endif // HIVIEWDFX_HISYSEVENT_ENABLE MISC_HILOGE("CheckVibratePermission failed, ret:%{public}d", ret); return PERMISSION_DENIED; } VibratorCapacity capacity; if (GetHapticCapacityInfo(identifier, capacity) != ERR_OK) { MISC_HILOGE("GetVibratorCapacity failed"); return ERROR; } if (!(capacity.isSupportHdHaptic || capacity.isSupportPresetMapping || capacity.isSupportTimeDelay)) { MISC_HILOGE("The device does not support this operation"); return IS_NOT_SUPPORTED; } if ((usage >= USAGE_MAX) || (usage < 0) || (!CheckVibratorParmeters(parameter))) { MISC_HILOGE("Invalid parameter, usage:%{public}d", usage); return PARAMETER_ERROR; } return ERR_OK; } std::string MiscdeviceService::GetPackageName(AccessTokenID tokenId) { std::string packageName; int32_t tokenType = AccessTokenKit::GetTokenTypeFlag(tokenId); switch (tokenType) { case ATokenTypeEnum::TOKEN_HAP: { HapTokenInfo hapInfo; if (AccessTokenKit::GetHapTokenInfo(tokenId, hapInfo) != 0) { MISC_HILOGE("Get hap token info fail"); return {}; } packageName = hapInfo.bundleName; break; } case ATokenTypeEnum::TOKEN_NATIVE: case ATokenTypeEnum::TOKEN_SHELL: { NativeTokenInfo tokenInfo; if (AccessTokenKit::GetNativeTokenInfo(tokenId, tokenInfo) != 0) { MISC_HILOGE("Get native token info fail"); return {}; } packageName = tokenInfo.processName; break; } default: { MISC_HILOGW("Token type not match"); break; } } return packageName; } int32_t MiscdeviceService::GetLightList(std::vector &lightInfoIpcList) { std::lock_guard lightInfosLock(lightInfosMutex_); std::string packageName = GetPackageName(GetCallingTokenID()); MISC_HILOGI("GetLightList, package:%{public}s", packageName.c_str()); int32_t ret = lightHdiConnection_.GetLightList(lightInfos_); if (ret != ERR_OK) { MISC_HILOGE("GetLightList failed, ret:%{public}d", ret); } size_t lightCount = lightInfos_.size(); MISC_HILOGI("lightCount:%{public}zu", lightCount); if (lightCount > MAX_LIGHT_COUNT) { lightCount = MAX_LIGHT_COUNT; } for (size_t i = 0; i < lightCount; ++i) { lightInfoIpcList.push_back(lightInfos_[i]); } return ERR_OK; } int32_t MiscdeviceService::TurnOn(int32_t lightId, int32_t singleColor, const LightAnimationIPC &animation) { PermissionUtil &permissionUtil = PermissionUtil::GetInstance(); int32_t ret = permissionUtil.CheckVibratePermission(this->GetCallingTokenID(), LIGHT_PERMISSION); if (ret != PERMISSION_GRANTED) { #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "LIGHT_PERMISSIONS_EXCEPTION", HiSysEvent::EventType::SECURITY, "PKG_NAME", "turnOnStub", "ERROR_CODE", ret); #endif // HIVIEWDFX_HISYSEVENT_ENABLE MISC_HILOGE("CheckLightPermission failed, ret:%{public}d", ret); return PERMISSION_DENIED; } LightColor color; color.singleColor = singleColor; std::string packageName = GetPackageName(GetCallingTokenID()); MISC_HILOGI("TurnOn, package:%{public}s", packageName.c_str()); if (!IsValid(lightId)) { MISC_HILOGE("lightId is invalid, lightId:%{public}d", lightId); return MISCDEVICE_NATIVE_SAM_ERR; } if (!IsLightAnimationValid(animation)) { MISC_HILOGE("animation is invalid"); return MISCDEVICE_NATIVE_SAM_ERR; } ret = lightHdiConnection_.TurnOn(lightId, color, animation); if (ret != ERR_OK) { MISC_HILOGE("TurnOn failed, error:%{public}d", ret); return ERROR; } return ret; } int32_t MiscdeviceService::TurnOff(int32_t lightId) { PermissionUtil &permissionUtil = PermissionUtil::GetInstance(); int32_t ret = permissionUtil.CheckVibratePermission(this->GetCallingTokenID(), LIGHT_PERMISSION); if (ret != PERMISSION_GRANTED) { #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "LIGHT_PERMISSIONS_EXCEPTION", HiSysEvent::EventType::SECURITY, "PKG_NAME", "TurnOffStub", "ERROR_CODE", ret); #endif // HIVIEWDFX_HISYSEVENT_ENABLE MISC_HILOGE("CheckLightPermission failed, ret:%{public}d", ret); return PERMISSION_DENIED; } std::string packageName = GetPackageName(GetCallingTokenID()); MISC_HILOGI("TurnOff, package:%{public}s", packageName.c_str()); if (!IsValid(lightId)) { MISC_HILOGE("lightId is invalid, lightId:%{public}d", lightId); return MISCDEVICE_NATIVE_SAM_ERR; } ret = lightHdiConnection_.TurnOff(lightId); if (ret != ERR_OK) { MISC_HILOGE("TurnOff failed, error:%{public}d", ret); return ERROR; } return ret; } int32_t MiscdeviceService::Dump(int32_t fd, const std::vector &args) { CALL_LOG_ENTER; if (fd < 0) { MISC_HILOGE("Invalid fd"); return DUMP_PARAM_ERR; } if (args.empty()) { MISC_HILOGE("args cannot be empty"); dprintf(fd, "args cannot be empty\n"); DumpHelper->DumpHelp(fd); return DUMP_PARAM_ERR; } std::vector argList = { "" }; std::transform(args.begin(), args.end(), std::back_inserter(argList), [](const std::u16string &arg) { return Str16ToStr8(arg); }); DumpHelper->ParseCommand(fd, argList); return ERR_OK; } int32_t MiscdeviceService::PerformVibrationControl(const VibratorIdentifierIPC& identifier, int32_t duration, VibrateInfo& info) { std::string curVibrateTime = GetCurrentTime(); if (StartVibrateThreadControl(identifier, info) != ERR_OK) { MISC_HILOGE("%{public}s:vibration is ignored and high priority is vibrating or no vibration found", curVibrateTime.c_str()); return ERROR; } MISC_HILOGI("Start vibrator, currentTime:%{public}s, package:%{public}s, pid:%{public}d, usage:%{public}d," "duration:%{public}d", curVibrateTime.c_str(), info.packageName.c_str(), info.pid, info.usage, duration); return ERR_OK; } int32_t MiscdeviceService::PlayPattern(const VibratorIdentifierIPC& identifier, const VibratePattern &pattern, const CustomHapticInfoIPC& customHapticInfoIPC) { int32_t checkResult = PlayPatternCheckAuthAndParam(customHapticInfoIPC.usage, customHapticInfoIPC.parameter); if (checkResult != ERR_OK) { MISC_HILOGE("CheckAuthAndParam failed, ret:%{public}d", checkResult); return checkResult; } VibratePattern vibratePattern; uint32_t sessionId = customHapticInfoIPC.parameter.sessionId; vibratePattern.startTime = ((sessionId > 0) ? pattern.startTime : 0); vibratePattern.events = pattern.events; std::vector patterns = {vibratePattern}; VibratePackage package = { .patterns = patterns }; MergeVibratorParmeters(customHapticInfoIPC.parameter, package); package.Dump(); VibrateInfo info = { .mode = VIBRATE_BUTT, .packageName = GetPackageName(GetCallingTokenID()), .pid = GetCallingPid(), .uid = GetCallingUid(), .usage = customHapticInfoIPC.usage, .systemUsage = customHapticInfoIPC.systemUsage, .sessionId = sessionId }; VibratorCapacity capacity; if (GetHapticCapacityInfo(identifier, capacity) != ERR_OK) { MISC_HILOGE("GetVibratorCapacity failed"); return ERROR; } if (capacity.isSupportHdHaptic) { int32_t result = PerformVibrationControl(identifier, pattern.patternDuration, info); if (result != ERR_OK) { MISC_HILOGE("PerformVibrationControl failed"); return result; } if (sessionId > 0) { return vibratorHdiConnection_.PlayPatternBySessionId(identifier, sessionId, package.patterns.front()); } return vibratorHdiConnection_.PlayPattern(identifier, package.patterns.front()); } else if (capacity.isSupportPresetMapping) { info.mode = VIBRATE_CUSTOM_COMPOSITE_EFFECT; } else if (capacity.isSupportTimeDelay) { info.mode = VIBRATE_CUSTOM_COMPOSITE_TIME; } info.package = package; return PerformVibrationControl(identifier, pattern.patternDuration, info); } int32_t MiscdeviceService::PlayPackageBySessionId(const VibratorIdentifierIPC &identifier, const VibratePackageIPC &package, const CustomHapticInfoIPC &customHapticInfoIPC) { CALL_LOG_ENTER; int32_t checkResult = PlayPatternCheckAuthAndParam(customHapticInfoIPC.usage, customHapticInfoIPC.parameter); if (checkResult != ERR_OK) { MISC_HILOGE("CheckAuthAndParam failed, ret:%{public}d", checkResult); return checkResult; } package.Dump(); VibrateInfo info = { .mode = VIBRATE_BUTT, .packageName = GetPackageName(GetCallingTokenID()), .pid = GetCallingPid(), .uid = GetCallingUid(), .usage = customHapticInfoIPC.usage, .systemUsage = customHapticInfoIPC.systemUsage, .sessionId = customHapticInfoIPC.parameter.sessionId }; VibratorCapacity capacity; if (GetHapticCapacityInfo(identifier, capacity) != ERR_OK) { MISC_HILOGE("GetVibratorCapacity failed"); return ERROR; } if (capacity.isSupportHdHaptic) { int32_t result = PerformVibrationControl(identifier, package.packageDuration, info); if (result != ERR_OK) { MISC_HILOGE("PerformVibrationControl failed"); return result; } uint32_t sessionId = customHapticInfoIPC.parameter.sessionId; return vibratorHdiConnection_.PlayPackageBySessionId(identifier, sessionId, package); } else if (capacity.isSupportPresetMapping) { info.mode = VIBRATE_CUSTOM_COMPOSITE_EFFECT; } else if (capacity.isSupportTimeDelay) { info.mode = VIBRATE_CUSTOM_COMPOSITE_TIME; } info.packageIPC = package; return PerformVibrationControl(identifier, package.packageDuration, info); } int32_t MiscdeviceService::StopVibrateBySessionId(const VibratorIdentifierIPC &identifier, uint32_t sessionId) { CALL_LOG_ENTER; PermissionUtil &permissionUtil = PermissionUtil::GetInstance(); int32_t ret = permissionUtil.CheckVibratePermission(this->GetCallingTokenID(), VIBRATE_PERMISSION); if (ret != PERMISSION_GRANTED) { #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "VIBRATOR_PERMISSIONS_EXCEPTION", HiSysEvent::EventType::SECURITY, "PKG_NAME", "StopVibrateBySessionId", "ERROR_CODE", ret); #endif // HIVIEWDFX_HISYSEVENT_ENABLE MISC_HILOGE("CheckVibratePermission failed, ret:%{public}d", ret); return PERMISSION_DENIED; } std::vector result = CheckDeviceIdIsValid(identifier); size_t ignoreVibrateNum = 0; if (result.empty()) { MISC_HILOGE("result is empty, no need to stop"); return ERROR; } for (const auto& paramIt : result) { auto vibratorThread_ = GetVibratorThread(paramIt); if (!vibratorHdiConnection_.IsVibratorRunning(paramIt)) { MISC_HILOGD("Thread is not running, no need to stop"); ignoreVibrateNum++; continue; } if (vibratorHdiConnection_.IsVibratorRunning(paramIt)) { vibratorHdiConnection_.StopVibrateBySessionId(paramIt, sessionId); } } if (ignoreVibrateNum == result.size()) { MISC_HILOGE("No need to stop, ignoreVibrateNum:%{public}zu", ignoreVibrateNum); return NO_ERROR; } std::string packageName = GetPackageName(GetCallingTokenID()); std::string curVibrateTime = GetCurrentTime(); MISC_HILOGI("Stop vibrator, currentTime:%{public}s, package:%{public}s, pid:%{public}d, deviceId:%{public}d," "vibratorId:%{public}d, sessionId:%{public}d", curVibrateTime.c_str(), packageName.c_str(), GetCallingPid(), identifier.deviceId, identifier.vibratorId, sessionId); return NO_ERROR; } int32_t MiscdeviceService::PlayPatternCheckAuthAndParam(int32_t usage, const VibrateParameter ¶meter) { PermissionUtil &permissionUtil = PermissionUtil::GetInstance(); int32_t ret = permissionUtil.CheckVibratePermission(this->GetCallingTokenID(), VIBRATE_PERMISSION); if (ret != PERMISSION_GRANTED) { #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "VIBRATOR_PERMISSIONS_EXCEPTION", HiSysEvent::EventType::SECURITY, "PKG_NAME", "PlayPatternStub", "ERROR_CODE", ret); #endif // HIVIEWDFX_HISYSEVENT_ENABLE MISC_HILOGE("CheckVibratePermission failed, ret:%{public}d", ret); return PERMISSION_DENIED; } if ((usage >= USAGE_MAX) || (usage < 0) || (!CheckVibratorParmeters(parameter))) { MISC_HILOGE("Invalid parameter, usage:%{public}d", usage); return PARAMETER_ERROR; } return ERR_OK; } int32_t MiscdeviceService::GetDelayTime(const VibratorIdentifierIPC& identifier, int32_t &delayTime) { std::string packageName = GetPackageName(GetCallingTokenID()); MISC_HILOGD("GetDelayTime, package:%{public}s", packageName.c_str()); VibratorCapacity capacity; if (GetHapticCapacityInfo(identifier, capacity) != ERR_OK) { MISC_HILOGE("GetVibratorCapacity failed"); return ERROR; } return vibratorHdiConnection_.GetDelayTime(identifier, capacity.GetVibrateMode(), delayTime); } bool MiscdeviceService::CheckVibratorParmeters(const VibrateParameter ¶meter) { if ((parameter.intensity < INTENSITY_ADJUST_MIN) || (parameter.intensity > INTENSITY_ADJUST_MAX) || (parameter.frequency < FREQUENCY_ADJUST_MIN) || (parameter.frequency > FREQUENCY_ADJUST_MAX)) { MISC_HILOGE("Input invalid, intensity parameter is %{public}d, frequency parameter is %{public}d", parameter.intensity, parameter.frequency); return false; } return true; } void MiscdeviceService::MergeVibratorParmeters(const VibrateParameter ¶meter, VibratePackage &package) { if ((parameter.intensity == INTENSITY_ADJUST_MAX) && (parameter.frequency == 0)) { MISC_HILOGD("The adjust parameter is not need to merge"); return; } MISC_HILOGI("intensity:%{public}d, frequency:%{public}d", parameter.intensity, parameter.frequency); for (VibratePattern &pattern : package.patterns) { for (VibrateEvent &event : pattern.events) { float intensityScale = static_cast(parameter.intensity) / INTENSITY_ADJUST_MAX; if ((event.tag == EVENT_TAG_TRANSIENT) || (event.points.empty())) { event.intensity = static_cast(event.intensity * intensityScale); event.intensity = std::max(std::min(event.intensity, INTENSITY_MAX), INTENSITY_MIN); event.frequency = event.frequency + parameter.frequency; event.frequency = std::max(std::min(event.frequency, FREQUENCY_MAX), FREQUENCY_MIN); } else { for (VibrateCurvePoint &point : event.points) { point.intensity = static_cast(point.intensity * intensityScale); point.intensity = std::max(std::min(point.intensity, INTENSITY_ADJUST_MAX), INTENSITY_ADJUST_MIN); point.frequency = point.frequency + parameter.frequency; point.frequency = std::max(std::min(point.frequency, FREQUENCY_ADJUST_MAX), FREQUENCY_ADJUST_MIN); } } } } } void MiscdeviceService::SendMsgToClient(const HdfVibratorPlugInfo &info) { MISC_HILOGI("Device:%{public}d state change, state:%{public}d, deviceName:%{public}s", info.deviceId, info.status, info.deviceName.c_str()); std::lock_guard lockManage(devicesManageMutex_); if (info.status == 0) { auto it = devicesManageMap_.find(info.deviceId); if (it != devicesManageMap_.end()) { VibratorIdentifierIPC identifier; for (auto &value : it->second.baseInfo) { identifier.deviceId = info.deviceId; identifier.vibratorId = value.vibratorId; StopVibratorService(identifier); } devicesManageMap_.erase(it); MISC_HILOGI("Device %{public}d is offline and removed from the map.", info.deviceId); } } else { std::vector vibratorInfo; auto ret = vibratorHdiConnection_.GetVibratorInfo(vibratorInfo); if (ret != NO_ERROR || vibratorInfo.empty()) { MISC_HILOGE("Device not contain the local vibrator"); } if (InsertVibratorInfo(info.deviceId, info.deviceName, vibratorInfo) != NO_ERROR) { MISC_HILOGE("Insert vibrator of device %{public}d fail", info.deviceId); } } std::lock_guard lock(clientPidMapMutex_); MISC_HILOGI("Device:%{public}d state change,state:%{public}d, clientPidMap_.size::%{public}zu", info.deviceId, info.status, clientPidMap_.size()); for (auto it = clientPidMap_.begin(); it != clientPidMap_.end(); ++it) { const sptr& key = it->first; sptr clientProxy = iface_cast(key); if (clientProxy != nullptr) { MISC_HILOGI("Device:%{public}d state change,state:%{public}d, ProcessPlugEvent", info.deviceId, info.status); clientProxy->ProcessPlugEvent(info.status, info.deviceId, info.vibratorCnt); } } } int32_t MiscdeviceService::TransferClientRemoteObject(const sptr &vibratorServiceClient) { auto clientPid = GetCallingPid(); if (clientPid < 0) { MISC_HILOGE("ClientPid is invalid, clientPid:%{public}d", clientPid); return ERROR; } RegisterClientDeathRecipient(vibratorServiceClient, clientPid); return ERR_OK; } void MiscdeviceService::ProcessDeathObserver(const wptr &object) { CALL_LOG_ENTER; sptr client = object.promote(); int32_t clientPid = FindClientPid(client); VibrateInfo info; std::lock_guard lock(devicesManageMutex_); for (const auto& pair : devicesManageMap_) { int deviceId = pair.first; const VibratorControlInfo& vibratorControlInfo_ = pair.second.controlInfo; MISC_HILOGI("Device ID:%{public}d, , Motor Count:%{public}d", deviceId, vibratorControlInfo_.motorCount); for (const auto& motorPair : vibratorControlInfo_.vibratorThreads) { int motorId = motorPair.first; { std::lock_guard lock(vibratorThreadMutex_); auto vibratorThread_ = motorPair.second; if (vibratorThread_ == nullptr) { MISC_HILOGE("MotorId:%{public}d, Vibrate thread no found in devicesManageMap_", motorId); vibratorThread_ = std::make_shared(); } info = vibratorThread_->GetCurrentVibrateInfo(); } int32_t vibratePid = info.pid; MISC_HILOGI("ClientPid:%{public}d, VibratePid:%{public}d", clientPid, vibratePid); if ((clientPid != INVALID_PID) && (clientPid == vibratePid)) { VibratorIdentifierIPC identifier; identifier.deviceId = deviceId; identifier.vibratorId = motorId; StopVibratorService(identifier); } } } UnregisterClientDeathRecipient(client); } void MiscdeviceService::RegisterClientDeathRecipient(sptr vibratorServiceClient, int32_t pid) { if (vibratorServiceClient == nullptr) { MISC_HILOGE("VibratorServiceClient is nullptr"); return; } std::lock_guard lock(clientDeathObserverMutex_); if (clientDeathObserver_ == nullptr) { clientDeathObserver_ = new (std::nothrow) DeathRecipientTemplate(*const_cast(this)); if (clientDeathObserver_ == nullptr) { MISC_HILOGE("ClientDeathObserver_ is nullptr"); return; } } vibratorServiceClient->AddDeathRecipient(clientDeathObserver_); SaveClientPid(vibratorServiceClient, pid); } void MiscdeviceService::UnregisterClientDeathRecipient(sptr vibratorServiceClient) { if (vibratorServiceClient == nullptr) { MISC_HILOGE("vibratorServiceClient is nullptr"); return; } int32_t clientPid = FindClientPid(vibratorServiceClient); if (clientPid == INVALID_PID) { MISC_HILOGE("Pid is invalid"); return; } std::lock_guard lock(clientDeathObserverMutex_); vibratorServiceClient->RemoveDeathRecipient(clientDeathObserver_); DestroyClientPid(vibratorServiceClient); } void MiscdeviceService::SaveClientPid(const sptr &vibratorServiceClient, int32_t pid) { if (vibratorServiceClient == nullptr) { MISC_HILOGE("VibratorServiceClient is nullptr"); return; } std::lock_guard lock(clientPidMapMutex_); clientPidMap_.insert(std::make_pair(vibratorServiceClient, pid)); } int32_t MiscdeviceService::FindClientPid(const sptr &vibratorServiceClient) { if (vibratorServiceClient == nullptr) { MISC_HILOGE("VibratorServiceClient is nullptr"); return INVALID_PID; } std::lock_guard lock(clientPidMapMutex_); auto it = clientPidMap_.find(vibratorServiceClient); if (it == clientPidMap_.end()) { MISC_HILOGE("Cannot find client pid"); return INVALID_PID; } return it->second; } void MiscdeviceService::DestroyClientPid(const sptr &vibratorServiceClient) { if (vibratorServiceClient == nullptr) { MISC_HILOGD("VibratorServiceClient is nullptr"); return; } std::lock_guard lock(clientPidMapMutex_); auto it = clientPidMap_.find(vibratorServiceClient); if (it == clientPidMap_.end()) { MISC_HILOGE("Cannot find client pid"); return; } clientPidMap_.erase(it); } int32_t MiscdeviceService::PlayPrimitiveEffect(const VibratorIdentifierIPC& identifier, const std::string &effect, const PrimitiveEffectIPC& primitiveEffectIPC) { int32_t checkResult = PlayPrimitiveEffectCheckAuthAndParam(primitiveEffectIPC.intensity, primitiveEffectIPC.usage); if (checkResult != ERR_OK) { MISC_HILOGE("CheckAuthAndParam failed, ret:%{public}d", checkResult); return checkResult; } #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR std::optional effectInfo = vibratorHdiConnection_.GetEffectInfo(identifier, effect); if (!effectInfo) { MISC_HILOGE("GetEffectInfo fail"); return ERROR; } if (!(effectInfo->isSupportEffect)) { MISC_HILOGE("Effect not supported"); return PARAMETER_ERROR; } #endif // HDF_DRIVERS_INTERFACE_VIBRATOR VibrateInfo info = { .mode = VIBRATE_PRESET, .packageName = GetPackageName(GetCallingTokenID()), .pid = GetCallingPid(), .uid = GetCallingUid(), .usage = primitiveEffectIPC.usage, .systemUsage = primitiveEffectIPC.systemUsage, #ifdef HDF_DRIVERS_INTERFACE_VIBRATOR .duration = effectInfo->duration, #endif // HDF_DRIVERS_INTERFACE_VIBRATOR .effect = effect, .count = primitiveEffectIPC.count, .intensity = primitiveEffectIPC.intensity }; std::string curVibrateTime = GetCurrentTime(); if (StartVibrateThreadControl(identifier, info) != ERR_OK) { MISC_HILOGE("%{public}s:vibration is ignored and high priority is vibrating or no vibration found", curVibrateTime.c_str()); return ERROR; } MISC_HILOGI("Start vibrator, currentTime:%{public}s, package:%{public}s, pid:%{public}d, usage:%{public}d," "deviceId:%{public}d, vibratorId:%{public}d, duration:%{public}d, effect:%{public}s, intensity:%{public}d", curVibrateTime.c_str(), info.packageName.c_str(), info.pid, info.usage, identifier.deviceId, identifier.vibratorId, info.duration, info.effect.c_str(), info.intensity); return NO_ERROR; } int32_t MiscdeviceService::PlayPrimitiveEffectCheckAuthAndParam(int32_t intensity, int32_t usage) { PermissionUtil &permissionUtil = PermissionUtil::GetInstance(); int32_t ret = permissionUtil.CheckVibratePermission(this->GetCallingTokenID(), VIBRATE_PERMISSION); if (ret != PERMISSION_GRANTED) { #ifdef HIVIEWDFX_HISYSEVENT_ENABLE HiSysEventWrite(HiSysEvent::Domain::MISCDEVICE, "VIBRATOR_PERMISSIONS_EXCEPTION", HiSysEvent::EventType::SECURITY, "PKG_NAME", "PlayPrimitiveEffectStub", "ERROR_CODE", ret); #endif // HIVIEWDFX_HISYSEVENT_ENABLE MISC_HILOGE("CheckVibratePermission failed, ret:%{public}d", ret); return PERMISSION_DENIED; } if ((intensity <= INTENSITY_MIN) || (intensity > INTENSITY_MAX) || (usage >= USAGE_MAX) || (usage < 0)) { MISC_HILOGE("Invalid parameter"); return PARAMETER_ERROR; } return ERR_OK; } int32_t MiscdeviceService::GetLocalDeviceId(int32_t &deviceId) { for (const auto& device : devicesManageMap_) { for (const auto& info : device.second.baseInfo) { if (info.isLocalVibrator) { deviceId = info.deviceId; return NO_ERROR; } } } return ERROR; } int32_t MiscdeviceService::GetOneVibrator(const VibratorIdentifierIPC& actIdentifier, std::vector& vibratorInfoIPC) { if (devicesManageMap_.empty()) { MISC_HILOGE("No vibrator device online"); return ERROR; } auto it = devicesManageMap_.find(actIdentifier.deviceId); if (it == devicesManageMap_.end()) { MISC_HILOGE("Device manager map has no vibrator info"); return ERROR; } for (auto &value : it->second.baseInfo) { if (actIdentifier.vibratorId == value.vibratorId) { vibratorInfoIPC.emplace_back(value); break; } } return NO_ERROR; } int32_t MiscdeviceService::GetVibratorList(const VibratorIdentifierIPC& identifier, std::vector& vibratorInfoIPC) { CALL_LOG_ENTER; identifier.Dump(); if (devicesManageMap_.empty()) { GetOnlineVibratorInfo(); } std::lock_guard lockManage(devicesManageMutex_); if ((identifier.deviceId == -1) && (identifier.vibratorId == -1)) { for (auto &value : devicesManageMap_) { vibratorInfoIPC.insert(vibratorInfoIPC.end(), value.second.baseInfo.begin(), value.second.baseInfo.end()); } } else if ((identifier.deviceId == -1) && (identifier.vibratorId != -1)) { VibratorIdentifierIPC actIdentifier; actIdentifier.vibratorId = identifier.vibratorId; int32_t ret = GetLocalDeviceId(actIdentifier.deviceId); if (ret == NO_ERROR) { ret = GetOneVibrator(actIdentifier, vibratorInfoIPC); if (ret != NO_ERROR) { MISC_HILOGI("Local deviceId %{public}d has no vibratorId %{public}d info", actIdentifier.deviceId, actIdentifier.vibratorId); } } } else if ((identifier.deviceId != -1) && (identifier.vibratorId == -1)) { auto it = devicesManageMap_.find(identifier.deviceId); if (it == devicesManageMap_.end()) { MISC_HILOGD("Device manager map has no vibrator info"); return NO_ERROR; } vibratorInfoIPC = it->second.baseInfo; } else { // ((identifier.deviceId != -1) && (identifier.vibratorId != -1)) if (GetOneVibrator(identifier, vibratorInfoIPC) != NO_ERROR) { MISC_HILOGI("DeviceId %{public}d has no vibratorId %{public}d info", identifier.deviceId, identifier.vibratorId); } } return NO_ERROR; } int32_t MiscdeviceService::GetEffectInfo(const VibratorIdentifierIPC& identifier, const std::string& effectType, EffectInfoIPC& effectInfoIPC) { CALL_LOG_ENTER; identifier.Dump(); if (devicesManageMap_.empty()) { MISC_HILOGI("No vibrator device online"); return NO_ERROR; } VibratorIdentifierIPC localIdentifier; if (identifier.deviceId == -1) { for (const auto& pair : devicesManageMap_) { for (const auto& info : pair.second.baseInfo) { info.isLocalVibrator ? (localIdentifier.deviceId = info.deviceId) : 0; } } } HdfEffectInfo hdfEffectInfo; int32_t ret = vibratorHdiConnection_.GetEffectInfo((identifier.deviceId == -1) ? localIdentifier : identifier, effectType, hdfEffectInfo); if (ret != NO_ERROR) { MISC_HILOGE("HDI::GetEffectInfo return error"); return ERROR; } effectInfoIPC.duration = hdfEffectInfo.duration; effectInfoIPC.isSupportEffect = hdfEffectInfo.isSupportEffect; effectInfoIPC.Dump(); return NO_ERROR; } int32_t MiscdeviceService::SubscribeVibratorPlugInfo(const sptr &vibratorServiceClient) { auto clientPid = GetCallingPid(); if (clientPid < 0) { MISC_HILOGE("ClientPid is invalid, clientPid:%{public}d", clientPid); return ERROR; } if (vibratorServiceClient == nullptr) { MISC_HILOGD("VibratorServiceClient is nullptr"); return ERROR; } return ERR_OK; } int32_t MiscdeviceService::GetVibratorCapacity(const VibratorIdentifierIPC& identifier, VibratorCapacity &vibratorCapacity) { CALL_LOG_ENTER; VibratorCapacity capacity; if (GetHapticCapacityInfo(identifier, capacity) != ERR_OK) { MISC_HILOGE("GetVibratorCapacity failed"); return ERROR; } vibratorCapacity = capacity; return ERR_OK; } // 手表短振快速下发不启动线程 #ifdef OHOS_BUILD_ENABLE_VIBRATOR_PRESET_INFO int32_t MiscdeviceService::FastVibratorEffect(const VibrateInfo &info, const VibratorIdentifierIPC& identifier) { int32_t ret = VibratorDevice.StartByIntensity(identifier, info.effect, info.intensity); if (ret != SUCCESS) { MISC_HILOGE("Vibrate effect %{public}s failed.", info.effect.c_str()); } return NO_ERROR; } #endif // OHOS_BUILD_ENABLE_VIBRATOR_PRESET_INFO std::shared_ptr MiscdeviceService::GetVibratorThread(const VibratorIdentifierIPC& identifier) { CALL_LOG_ENTER; auto deviceIt = devicesManageMap_.find(identifier.deviceId); if (deviceIt != devicesManageMap_.end()) { auto thread = deviceIt->second.controlInfo.GetVibratorThread(identifier.vibratorId); if (thread) { MISC_HILOGI("Success: Vibrate thread found."); return thread; } else { MISC_HILOGE("Failed: Vibrate thread no found."); return nullptr; } } return nullptr; } int32_t MiscdeviceService::GetHapticCapacityInfo(const VibratorIdentifierIPC& identifier, VibratorCapacity& capacityInfo) { CALL_LOG_ENTER; std::lock_guard lock(devicesManageMutex_); if (identifier.deviceId != -1) { auto deviceIt = devicesManageMap_.find(identifier.deviceId); if (deviceIt != devicesManageMap_.end()) { capacityInfo = deviceIt->second.capacityInfo; return ERR_OK; } MISC_HILOGW("No vibrator capacity information found for device ID: %{public}d", identifier.deviceId); return ERR_OK; } for (const auto& pair : devicesManageMap_) { for (const auto& info : pair.second.baseInfo) { if (info.isLocalVibrator) { capacityInfo = pair.second.capacityInfo; return ERR_OK; } } } MISC_HILOGW("No local vibrator capacity information found for device ID: %{public}d", identifier.deviceId); return ERR_OK; } int32_t MiscdeviceService::GetAllWaveInfo(const VibratorIdentifierIPC& identifier, std::vector& waveInfo) { CALL_LOG_ENTER; if (identifier.deviceId != -1) { auto deviceIt = devicesManageMap_.find(identifier.deviceId); if (deviceIt != devicesManageMap_.end()) { waveInfo = deviceIt->second.waveInfo; return ERR_OK; } MISC_HILOGE("Device ID %{public}d not found", identifier.deviceId); return ERR_OK; } for (const auto& [deviceId, deviceInfo] : devicesManageMap_) { for (const auto& baseInfo : deviceInfo.baseInfo) { if (baseInfo.isLocalVibrator) { waveInfo = deviceInfo.waveInfo; return ERR_OK; } } } MISC_HILOGW("No vibrator information found for device ID: %{public}d", identifier.deviceId); return ERR_OK; } int32_t MiscdeviceService::GetHapticStartUpTime(const VibratorIdentifierIPC& identifier, int32_t mode, int32_t &startUpTime) { CALL_LOG_ENTER; auto ret = vibratorHdiConnection_.GetDelayTime(identifier, mode, startUpTime); if (ret != NO_ERROR) { MISC_HILOGE("HDI::GetHapticStartUpTime return error"); return ERROR; } return NO_ERROR; } void MiscdeviceService::ConvertToServerInfos(const std::vector &baseVibratorInfo, const VibratorCapacity &vibratorCapacity, const std::vector &waveInfomation, const HdfVibratorPlugInfo &info, VibratorAllInfos& vibratorAllInfos) { CALL_LOG_ENTER; VibratorInfoIPC vibratorInfo; for (auto infos : baseVibratorInfo) { vibratorInfo.deviceId = infos.deviceId; vibratorInfo.vibratorId = infos.vibratorId; vibratorInfo.deviceName = info.deviceName; vibratorInfo.isSupportHdHaptic = vibratorCapacity.isSupportHdHaptic; vibratorInfo.isLocalVibrator = infos.isLocal; vibratorAllInfos.baseInfo.emplace_back(vibratorInfo); MISC_HILOGI("HDI::HdfVibratorInfo deviceName:%{public}s, deviceId:%{public}d, vibratorId:%{public}d," " isLocalVibrator:%{public}d", info.deviceName.c_str(), vibratorInfo.deviceId, vibratorInfo.vibratorId, vibratorInfo.isLocalVibrator); } vibratorAllInfos.capacityInfo = vibratorCapacity; vibratorAllInfos.waveInfo = waveInfomation; } void MiscdeviceService::GetOnlineVibratorInfo() { CALL_LOG_ENTER; std::vector vibratorInfo; auto ret = vibratorHdiConnection_.GetVibratorInfo(vibratorInfo); if (ret != NO_ERROR || vibratorInfo.empty()) { MISC_HILOGW("Device does not contain any vibrators"); return; } std::lock_guard lockManage(devicesManageMutex_); const std::string deviceName = ""; for (auto &info : vibratorInfo) { const auto it = devicesManageMap_.find(info.deviceId); if (it != devicesManageMap_.end()) { continue; } if (InsertVibratorInfo(info.deviceId, deviceName, vibratorInfo) != NO_ERROR) { MISC_HILOGW("Insert vibrator of device %{public}d fail", info.deviceId); } } } int32_t MiscdeviceService::InsertVibratorInfo(int deviceId, const std::string &deviceName, const std::vector &vibratorInfo) { CALL_LOG_ENTER; std::vector infos; std::vector vibratorIdList; for (auto &info : vibratorInfo) { const auto it = devicesManageMap_.find(info.deviceId); if (it != devicesManageMap_.end()) { MISC_HILOGW("The deviceId already exists in devicesManageMap_, deviceId: %{public}d", info.deviceId); continue; } if (info.deviceId == deviceId) { infos.emplace_back(info); vibratorIdList.push_back(info.vibratorId); } } if (infos.empty()) { MISC_HILOGW("Device %{public}d does not contain any vibrators", deviceId); return NO_ERROR; } VibratorIdentifierIPC param; param.deviceId = infos[0].deviceId; param.vibratorId = infos[0].vibratorId; VibratorCapacity capacity; int32_t ret = vibratorHdiConnection_.GetVibratorCapacity(param, capacity); if (ret != NO_ERROR) { MISC_HILOGW("Get capacity fail from HDI, then use the default capacity, deviceId: %{public}d", param.deviceId); } std::vector waveInfo; ret = vibratorHdiConnection_.GetAllWaveInfo(param, waveInfo); if (ret != NO_ERROR) { MISC_HILOGW("Get waveInfo fail from HDI, deviceId: %{public}d", param.deviceId); } HdfVibratorPlugInfo mockInfo; mockInfo.deviceName = deviceName; VibratorAllInfos localVibratorInfo(vibratorIdList); (void)ConvertToServerInfos(infos, capacity, waveInfo, mockInfo, localVibratorInfo); devicesManageMap_.insert(std::make_pair(param.deviceId, localVibratorInfo)); return NO_ERROR; } int32_t MiscdeviceService::StartVibrateThreadControl(const VibratorIdentifierIPC& identifier, VibrateInfo& info) { std::lock_guard lockManage(devicesManageMutex_); std::string curVibrateTime = GetCurrentTime(); std::vector result = CheckDeviceIdIsValid(identifier); if (result.empty()) { MISC_HILOGE("No vibration found"); return ERROR; } size_t ignoreVibrateNum = 0; const std::vector specialModes = { VIBRATE_CUSTOM_HD, VIBRATE_CUSTOM_COMPOSITE_EFFECT, VIBRATE_CUSTOM_COMPOSITE_TIME, VIBRATE_BUTT }; std::unordered_set uniqueIndices; if (std::find(specialModes.begin(), specialModes.end(), info.mode) != specialModes.end()) { for (const auto& pattern : info.package.patterns) { for (const auto& event : pattern.events) { uniqueIndices.insert(event.index); } } for (const auto& index : uniqueIndices) { MISC_HILOGD("Info mode:%{public}s, vibratorIndex:%{public}d", info.mode.c_str(), index); } } std::lock_guard lock(vibratorThreadMutex_); for (const auto& paramIt : result) { bool shouldProcess = uniqueIndices.empty() || uniqueIndices.find(0) != uniqueIndices.end() || uniqueIndices.find(paramIt.position) != uniqueIndices.end(); if (paramIt.isLocalVibrator && ShouldIgnoreVibrate(info, paramIt)) { if (shouldProcess) { ignoreVibrateNum++; continue; } } if (shouldProcess) { StartVibrateThread(info, paramIt); } } return (ignoreVibrateNum == result.size()) ? ERROR : ERR_OK; } std::vector MiscdeviceService::CheckDeviceIdIsValid(const VibratorIdentifierIPC& identifier) { CALL_LOG_ENTER; std::vector result; auto addToResult = [&](const auto& info) { VibratorIdentifierIPC newIdentifier; newIdentifier.deviceId = info.deviceId; newIdentifier.vibratorId = info.vibratorId; newIdentifier.position = info.position; newIdentifier.isLocalVibrator = info.isLocalVibrator; result.push_back(newIdentifier); MISC_HILOGD("Push result in list,:%{public}d,:%{public}d", newIdentifier.deviceId, newIdentifier.vibratorId); }; auto processDevice = [&](const auto& device) { for (const auto& info : device.second.baseInfo) { bool shouldAdd = false; if (identifier.deviceId == -1 && identifier.vibratorId != -1) { shouldAdd = info.isLocalVibrator && info.vibratorId == identifier.vibratorId; } else if (identifier.deviceId != -1 && identifier.vibratorId != -1) { shouldAdd = info.vibratorId == identifier.vibratorId; } else if (identifier.deviceId == -1 && identifier.vibratorId == -1) { shouldAdd = info.isLocalVibrator; } else { // (identifier.deviceId != -1 && identifier.vibratorId == -1) shouldAdd = true; } if (shouldAdd) { addToResult(info); } } }; if (identifier.deviceId != -1) { auto deviceIt = devicesManageMap_.find(identifier.deviceId); if (deviceIt != devicesManageMap_.end()) { processDevice(*deviceIt); } } else { for (const auto& pair : devicesManageMap_) { processDevice(pair); } } return result; } } // namespace Sensors } // namespace OHOS