1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "miscdevice_service.h"
17
18 #include <string_ex.h>
19
20 #include "sensors_errors.h"
21 #include "system_ability_definition.h"
22 #include "vibration_priority_manager.h"
23 #include "v1_0/light_interface_proxy.h"
24
25 namespace OHOS {
26 namespace Sensors {
27 using namespace OHOS::HiviewDFX;
28
29 namespace {
30 constexpr HiLogLabel LABEL = { LOG_CORE, MISC_LOG_DOMAIN, "MiscdeviceService" };
31 constexpr int32_t MIN_VIBRATOR_TIME = 0;
32 constexpr int32_t MAX_VIBRATOR_TIME = 1800000;
33 } // namespace
34
35 REGISTER_SYSTEM_ABILITY_BY_ID(MiscdeviceService, MISCDEVICE_SERVICE_ABILITY_ID, true);
36
MiscdeviceService(int32_t systemAbilityId,bool runOnCreate)37 MiscdeviceService::MiscdeviceService(int32_t systemAbilityId, bool runOnCreate)
38 : SystemAbility(systemAbilityId, runOnCreate),
39 lightExist_(false),
40 vibratorExist_(false),
41 state_(MiscdeviceServiceState::STATE_STOPPED),
42 vibratorThread_(nullptr)
43 {}
44
~MiscdeviceService()45 MiscdeviceService::~MiscdeviceService()
46 {
47 if (vibratorThread_ != nullptr) {
48 while (vibratorThread_->IsRunning()) {
49 vibratorThread_->NotifyExit();
50 vibratorThread_->NotifyExitSync();
51 }
52 }
53 }
54
OnDump()55 void MiscdeviceService::OnDump()
56 {
57 MISC_HILOGI("ondump is invoked");
58 }
59
OnStart()60 void MiscdeviceService::OnStart()
61 {
62 CALL_LOG_ENTER;
63 if (state_ == MiscdeviceServiceState::STATE_RUNNING) {
64 MISC_HILOGW("state_ already started");
65 return;
66 }
67 if (!InitInterface()) {
68 MISC_HILOGE("Init interface error");
69 return;
70 }
71 if (!InitLightInterface()) {
72 MISC_HILOGE("InitLightInterface failed");
73 return;
74 }
75 if (!SystemAbility::Publish(this)) {
76 MISC_HILOGE("publish MiscdeviceService failed");
77 return;
78 }
79 auto ret = miscDdeviceIdMap_.insert(std::make_pair(MiscdeviceDeviceId::LED, lightExist_));
80 if (!ret.second) {
81 MISC_HILOGI("light exist in miscDdeviceIdMap_");
82 ret.first->second = lightExist_;
83 }
84 ret = miscDdeviceIdMap_.insert(std::make_pair(MiscdeviceDeviceId::VIBRATOR, vibratorExist_));
85 if (!ret.second) {
86 MISC_HILOGI("vibrator exist in miscDdeviceIdMap_");
87 ret.first->second = vibratorExist_;
88 }
89 state_ = MiscdeviceServiceState::STATE_RUNNING;
90 }
91
InitInterface()92 bool MiscdeviceService::InitInterface()
93 {
94 auto ret = vibratorHdiConnection_.ConnectHdi();
95 if (ret != ERR_OK) {
96 MISC_HILOGE("InitVibratorServiceImpl failed");
97 return false;
98 }
99 return true;
100 }
101
InitLightInterface()102 bool MiscdeviceService::InitLightInterface()
103 {
104 auto ret = lightHdiConnection_.ConnectHdi();
105 if (ret != ERR_OK) {
106 MISC_HILOGE("ConnectHdi failed");
107 return false;
108 }
109 return true;
110 }
111
IsValid(int32_t lightId)112 bool MiscdeviceService::IsValid(int32_t lightId)
113 {
114 CALL_LOG_ENTER;
115 for (const auto &item : lightInfos_) {
116 if (lightId == item.lightId) {
117 return true;
118 }
119 }
120 return false;
121 }
122
IsLightAnimationValid(const LightAnimation & animation)123 bool MiscdeviceService::IsLightAnimationValid(const LightAnimation &animation)
124 {
125 if ((animation.mode < 0) || (animation.mode >= LIGHT_MODE_BUTT)) {
126 MISC_HILOGE("animation mode is invalid, mode:%{pubilc}d", animation.mode);
127 return false;
128 }
129 if ((animation.onTime < 0) || (animation.offTime < 0)) {
130 MISC_HILOGE("animation onTime or offTime is invalid, onTime:%{pubilc}d, offTime:%{pubilc}d",
131 animation.onTime, animation.offTime);
132 return false;
133 }
134 return true;
135 }
136
OnStop()137 void MiscdeviceService::OnStop()
138 {
139 CALL_LOG_ENTER;
140 if (state_ == MiscdeviceServiceState::STATE_STOPPED) {
141 MISC_HILOGW("MiscdeviceService stopped already");
142 return;
143 }
144 state_ = MiscdeviceServiceState::STATE_STOPPED;
145 int32_t ret = vibratorHdiConnection_.DestroyHdiConnection();
146 if (ret != ERR_OK) {
147 MISC_HILOGE("destroy hdi connection fail");
148 }
149 }
150
151
ShouldIgnoreVibrate(const VibrateInfo & info)152 bool MiscdeviceService::ShouldIgnoreVibrate(const VibrateInfo &info)
153 {
154 return (PriorityManager->ShouldIgnoreVibrate(info, vibratorThread_) != VIBRATION);
155 }
156
Vibrate(int32_t vibratorId,int32_t timeOut,int32_t usage)157 int32_t MiscdeviceService::Vibrate(int32_t vibratorId, int32_t timeOut, int32_t usage)
158 {
159 if ((timeOut <= MIN_VIBRATOR_TIME) || (timeOut > MAX_VIBRATOR_TIME)
160 || (usage >= USAGE_MAX) || (usage < 0)) {
161 MISC_HILOGE("Invalid parameter");
162 return PARAMETER_ERROR;
163 }
164 VibrateInfo info = {
165 .mode = "time",
166 .packageName = GetPackageName(GetCallingTokenID()),
167 .pid = GetCallingPid(),
168 .uid = GetCallingUid(),
169 .usage = usage,
170 .duration = timeOut
171 };
172 std::lock_guard<std::mutex> lock(vibratorThreadMutex_);
173 if (ShouldIgnoreVibrate(info)) {
174 MISC_HILOGE("Vibration is ignored and high priority is vibrating");
175 return ERROR;
176 }
177 StartVibrateThread(info);
178 return NO_ERROR;
179 }
180
CancelVibrator(int32_t vibratorId)181 int32_t MiscdeviceService::CancelVibrator(int32_t vibratorId)
182 {
183 std::lock_guard<std::mutex> lock(vibratorThreadMutex_);
184 if ((vibratorThread_ == nullptr) || (!vibratorThread_->IsRunning())) {
185 MISC_HILOGE("No vibration, no need to stop");
186 return ERROR;
187 }
188 while (vibratorThread_->IsRunning()) {
189 MISC_HILOGD("Notify the vibratorThread, vibratorId : %{public}d", vibratorId);
190 vibratorThread_->NotifyExit();
191 vibratorThread_->NotifyExitSync();
192 }
193 return NO_ERROR;
194 }
195
PlayVibratorEffect(int32_t vibratorId,const std::string & effect,int32_t count,int32_t usage)196 int32_t MiscdeviceService::PlayVibratorEffect(int32_t vibratorId, const std::string &effect,
197 int32_t count, int32_t usage)
198 {
199 if ((vibratorEffects.find(effect) == vibratorEffects.end()) || (count < 1)
200 || (usage >= USAGE_MAX) || (usage < 0)) {
201 MISC_HILOGE("Invalid parameter");
202 return PARAMETER_ERROR;
203 }
204 VibrateInfo info = {
205 .mode = "preset",
206 .packageName = GetPackageName(GetCallingTokenID()),
207 .pid = GetCallingPid(),
208 .uid = GetCallingUid(),
209 .usage = usage,
210 .duration = vibratorEffects[effect],
211 .effect = effect,
212 .count = count
213 };
214 std::lock_guard<std::mutex> lock(vibratorThreadMutex_);
215 if (ShouldIgnoreVibrate(info)) {
216 MISC_HILOGE("Vibration is ignored and high priority is vibrating");
217 return ERROR;
218 }
219 StartVibrateThread(info);
220 return NO_ERROR;
221 }
222
StartVibrateThread(VibrateInfo info)223 void MiscdeviceService::StartVibrateThread(VibrateInfo info)
224 {
225 if (vibratorThread_ == nullptr) {
226 vibratorThread_ = std::make_shared<VibratorThread>();
227 }
228 while (vibratorThread_->IsRunning()) {
229 vibratorThread_->NotifyExit();
230 vibratorThread_->NotifyExitSync();
231 }
232 vibratorThread_->UpdateVibratorEffect(info);
233 vibratorThread_->Start("VibratorThread");
234 DumpHelper->SaveVibrateRecord(info);
235 }
236
StopVibratorEffect(int32_t vibratorId,const std::string & effect)237 int32_t MiscdeviceService::StopVibratorEffect(int32_t vibratorId, const std::string &effect)
238 {
239 std::lock_guard<std::mutex> lock(vibratorThreadMutex_);
240 if ((vibratorThread_ == nullptr) || (!vibratorThread_->IsRunning())) {
241 MISC_HILOGE("No vibration, no need to stop");
242 return ERROR;
243 }
244 const VibrateInfo info = vibratorThread_->GetCurrentVibrateInfo();
245 if ((info.mode != effect) || (info.pid != GetCallingPid())) {
246 MISC_HILOGE("Stop vibration information mismatch");
247 return ERROR;
248 }
249 while (vibratorThread_->IsRunning()) {
250 MISC_HILOGD("notify the vibratorThread, vibratorId : %{public}d", vibratorId);
251 vibratorThread_->NotifyExit();
252 vibratorThread_->NotifyExitSync();
253 }
254 return NO_ERROR;
255 }
256
GetPackageName(AccessTokenID tokenId)257 std::string MiscdeviceService::GetPackageName(AccessTokenID tokenId)
258 {
259 std::string packageName;
260 int32_t tokenType = AccessTokenKit::GetTokenTypeFlag(tokenId);
261 switch (tokenType) {
262 case ATokenTypeEnum::TOKEN_HAP: {
263 HapTokenInfo hapInfo;
264 if (AccessTokenKit::GetHapTokenInfo(tokenId, hapInfo) != 0) {
265 MISC_HILOGE("get hap token info fail");
266 return {};
267 }
268 packageName = hapInfo.bundleName;
269 break;
270 }
271 case ATokenTypeEnum::TOKEN_NATIVE:
272 case ATokenTypeEnum::TOKEN_SHELL: {
273 NativeTokenInfo tokenInfo;
274 if (AccessTokenKit::GetNativeTokenInfo(tokenId, tokenInfo) != 0) {
275 MISC_HILOGE("get native token info fail");
276 return {};
277 }
278 packageName = tokenInfo.processName;
279 break;
280 }
281 default: {
282 MISC_HILOGW("token type not match");
283 break;
284 }
285 }
286 return packageName;
287 }
288
GetLightList()289 std::vector<LightInfo> MiscdeviceService::GetLightList()
290 {
291 if (!InitLightList()) {
292 MISC_HILOGE("InitLightList init failed");
293 return lightInfos_;
294 }
295 return lightInfos_;
296 }
297
InitLightList()298 bool MiscdeviceService::InitLightList()
299 {
300 int32_t ret = lightHdiConnection_.GetLightList(lightInfos_);
301 if (ret != ERR_OK) {
302 MISC_HILOGE("InitLightList failed, ret:%{public}d", ret);
303 return false;
304 }
305 return true;
306 }
307
TurnOn(int32_t lightId,const LightColor & color,const LightAnimation & animation)308 int32_t MiscdeviceService::TurnOn(int32_t lightId, const LightColor &color, const LightAnimation &animation)
309 {
310 CALL_LOG_ENTER;
311 if (!IsValid(lightId)) {
312 MISC_HILOGE("lightId is invalid, lightId:%{pubilc}d", lightId);
313 return MISCDEVICE_NATIVE_SAM_ERR;
314 }
315 if (!IsLightAnimationValid(animation)) {
316 MISC_HILOGE("animation is invalid");
317 return MISCDEVICE_NATIVE_SAM_ERR;
318 }
319 int32_t ret = lightHdiConnection_.TurnOn(lightId, color, animation);
320 if (ret != ERR_OK) {
321 MISC_HILOGE("TurnOn failed, error:%{public}d", ret);
322 return ERROR;
323 }
324 return ret;
325 }
326
TurnOff(int32_t lightId)327 int32_t MiscdeviceService::TurnOff(int32_t lightId)
328 {
329 CALL_LOG_ENTER;
330 if (!IsValid(lightId)) {
331 MISC_HILOGE("lightId is invalid, lightId:%{pubilc}d", lightId);
332 return MISCDEVICE_NATIVE_SAM_ERR;
333 }
334 int32_t ret = lightHdiConnection_.TurnOff(lightId);
335 if (ret != ERR_OK) {
336 MISC_HILOGE("TurnOff failed, error:%{public}d", ret);
337 return ERROR;
338 }
339 return ret;
340 }
341
Dump(int32_t fd,const std::vector<std::u16string> & args)342 int32_t MiscdeviceService::Dump(int32_t fd, const std::vector<std::u16string> &args)
343 {
344 CALL_LOG_ENTER;
345 if (fd < 0) {
346 MISC_HILOGE("Invalid fd");
347 return DUMP_PARAM_ERR;
348 }
349 if (args.empty()) {
350 MISC_HILOGE("args cannot be empty");
351 dprintf(fd, "args cannot be empty\n");
352 DumpHelper->DumpHelp(fd);
353 return DUMP_PARAM_ERR;
354 }
355 std::vector<std::string> argList = { "" };
356 std::transform(args.begin(), args.end(), std::back_inserter(argList),
357 [](const std::u16string &arg) {
358 return Str16ToStr8(arg);
359 });
360 DumpHelper->ParseCommand(fd, argList);
361 return ERR_OK;
362 }
363 } // namespace Sensors
364 } // namespace OHOS
365