1/* 2 * Copyright (c) 2021-2022 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 */ 15import {Log, Trace, WriteFaultLog, FaultID, createOrGet, ScreenLockStatus} from '@ohos/common' 16import ScreenLockModel from './screenLockModel'; 17import AccountModel, {AuthType, AuthSubType, AuthTurstLevel} from './accountsModel' 18import Router from '@system.router'; 19import commonEvent from '@ohos.commonEvent'; 20import hiDebug from '@ohos.hidebug'; 21import systemParameter from '@ohos.systemparameter'; 22import {CommonEventPublishData} from 'commonEvent/commonEventPublishData'; 23import {Callback} from '@ohos.base'; 24import {UIContext} from '@ohos.arkui.UIContext'; 25 26const TAG = 'ScreenLock-ScreenLockService'; 27const URI_DIGITALPASSWORD = 'pages/digitalPassword' 28const URI_MIXEDPASSWORD = 'pages/mixedPassword' 29const URI_CUSTOMPASSWORD = 'pages/customPassword' 30 31//Event type name 32const EVENT_BEGIN_WAKEUP: string = 'beginWakeUp' 33const EVENT_END_WAKEUP: string = 'endWakeUp' 34const EVENT_BEGIN_SCREENON: string = 'beginScreenOn' 35const EVENT_END_SCREEN_ON: string = 'endScreenOn' 36const EVENT_BEGIN_SCREENOFF: string = 'beginScreenOff' 37const EVENT_END_SCREENOFF: string = 'endScreenOff' 38const EVENT_UNLOCK_SCREEN: string = 'unlockScreen' 39const EVENT_LOCK_SCREEN: string = 'lockScreen' 40const EVENT_BEGIN_EXITANIMATION: string = 'beginExitAnimation' 41const EVENT_BEGIN_SLEEP: string = 'beginSleep' 42const EVENT_END_SLEEP: string = 'endSleep' 43const EVENT_CHANGE_USER: string = 'changeUser' 44const EVENT_SCREENLOCK_ENABLE: string = 'screenlockEnabled' 45const EVENT_SYSTEM_READY: string = 'systemReady' 46 47const SERVICE_RESTART: string = 'serviceRestart' 48 49const LOCK_SCREEN_RESULT: string = 'lockScreenResult' 50const UNLOCK_SCREEN_RESULT: string = 'unlockScreenResult' 51const SCREENLOCK_DRAW_DONE: string = 'screenDrawDone' 52 53const ACTIVATING_TYPE = "activating" 54const ACTIVATE_TYPE = "activate" 55const ACTIVATING_EVENT = "activatingEvent" 56const ACTIVATE_EVENT = "activateEvent" 57 58const CHALLENGE_INT = 0 59 60const MAIN_USER = 100 61 62const MEMORY_MONITOR_PERIOD_MS = 600000 63const MEMORY_MONITOR_LIMIT_KB = 120 * 1024 64 65export {AuthType, AuthSubType}; 66 67export enum UnlockResult { 68 Success = 0, 69 Fail = 1, 70 Cancel = 2 71} 72 73export enum LockResult { 74 Success = 0, 75 Fail = 1, 76 Cancel = 2 77} 78 79let mRouterPath: string = "" 80 81let mWillRecognizeFace: boolean = false 82 83let mUnLockBeginAnimation: Callback<Callback<void>> = (callback: Callback<void>) => { 84 callback() 85} 86 87export class ScreenLockService { 88 accountModel: AccountModel = new AccountModel() 89 screenLockModel: ScreenLockModel = new ScreenLockModel() 90 currentLockStatus : ScreenLockStatus; 91 memoryMonitor: number = -1; 92 init() { 93 Log.showDebug(TAG, 'init'); 94 this.startMonitorMemory(); 95 this.accountModel.modelInit(); 96 this.monitorEvents(); 97 this.accountModel.updateAllUsers() 98 this.checkPinAuthProperty(() => { 99 Log.showInfo(TAG, `checkPinAuthProperty back`) 100 this.authUserByFace() 101 }) 102 } 103 104 monitorEvents() { 105 Log.showDebug(TAG, 'registered events start'); 106 this.screenLockModel.eventListener((typeName: String) => { 107 switch (typeName) { 108 // System ready on device boot 109 case EVENT_SYSTEM_READY: 110 Log.showInfo(TAG, `EVENT_SYSTEM_READY event`); 111 this.lockScreen(); 112 break; 113 //Bright screen 114 case EVENT_END_SCREEN_ON: 115 Log.showInfo(TAG, `EVENT_END_SCREEN_ON event`); 116 this.authUserByFace() 117 AppStorage.SetOrCreate('deviceStatus', EVENT_END_SCREEN_ON); 118 break; 119 //The device is going to sleep 120 case EVENT_BEGIN_SLEEP: 121 Trace.start(Trace.CORE_METHOD_SLEEP_TO_LOCK_SCREEN); 122 Log.showInfo(TAG, `EVENT_BEGIN_SLEEP event`); 123 this.lockScreen(); 124 this.accountModel.updateAllUsers() 125 AppStorage.SetOrCreate('deviceStatus', EVENT_BEGIN_SLEEP); 126 break; 127 //unlock request was received 128 case EVENT_UNLOCK_SCREEN: 129 Log.showInfo(TAG, `EVENT_UNLOCK_SCREEN event`); 130 this.unlockScreen(); 131 break; 132 //lock request was received 133 case EVENT_LOCK_SCREEN: 134 Log.showInfo(TAG, `EVENT_LOCK_SCREEN event`); 135 this.lockScreen(); 136 break; 137 case SERVICE_RESTART: 138 setTimeout(() => { 139 this.monitorEvents(); 140 this.lockScreen(); 141 }, 2000); 142 break; 143 default: 144 Log.showError(TAG, `eventListener:typeName ${typeName}`) 145 } 146 }) 147 148 this.accountModel.eventListener(ACTIVATING_TYPE, ACTIVATING_EVENT, () => { 149 Log.showInfo(TAG, `ACTIVATING_TYPE event`); 150 }) 151 152 this.accountModel.eventListener(ACTIVATE_TYPE, ACTIVATE_EVENT, () => { 153 Log.showInfo(TAG, `ACTIVATE_TYPE event`); 154 this.lockScreen(); 155 this.accountModel.updateAllUsers() 156 this.checkPinAuthProperty(() => { 157 Log.showInfo(TAG, `checkPinAuthProperty back`) 158 this.authUserByFace() 159 }) 160 }) 161 162 this.accountModel.commonEventListener(()=>{ 163 Log.showInfo(TAG, `commonEventListener event`); 164 this.accountModel.updateAllUsers(); 165 }) 166 167 Log.showDebug(TAG, 'registered events end'); 168 } 169 170 lockScreen() { 171 Trace.start(Trace.CORE_METHOD_SHOW_LOCK_SCREEN); 172 Log.showDebug(TAG, `lockScreen`); 173 // let length = parseInt(Router.getLength()) 174 // Log.showDebug(TAG, `Router.getLength: ${length}`) 175 // for (let index = 1; index < length; index++) { 176 // Log.showInfo(TAG, `back to index`); 177 // Router.back(); 178 // } 179 180 //lock the screen 181 this.screenLockModel.showScreenLockWindow(() => { 182 Log.showInfo(TAG, `showScreenLockWindow finish`); 183 this.checkPinAuthProperty(() => { 184 }); 185 Log.showInfo(TAG, `screenlock status:${this.currentLockStatus}, userId : ${this.accountModel.getCurrentUserId()}`); 186 if (this.currentLockStatus == ScreenLockStatus.Locking) { 187 Log.showInfo(TAG, `had locked, no need to publish lock_screen`); 188 } else { 189 this.notifyLockScreenResult(LockResult.Success) 190 systemParameter.set('bootevent.lockscreen.ready','true') 191 this.currentLockStatus = ScreenLockStatus.Locking; 192 } 193 }); 194 } 195 196 private checkPinAuthProperty(callback: Callback<void>) { 197 Log.showDebug(TAG, "checkPinAuthProperty") 198 this.accountModel.getAuthProperty(AuthType.PIN, (properties) => { 199 Log.showInfo(TAG, `checkPinAuthProperty: AUTH_SUB_TYPE:${properties.authSubType}`); 200 switch (properties.authSubType) { 201 case AuthSubType.PIN_SIX: 202 AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Locking); 203 mRouterPath = URI_DIGITALPASSWORD; 204 this.checkFaceAuthProperty(() => { 205 callback() 206 }) 207 break; 208 case AuthSubType.PIN_MIXED: 209 AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Locking); 210 mRouterPath = URI_MIXEDPASSWORD; 211 this.checkFaceAuthProperty(() => { 212 callback() 213 }) 214 break; 215 case AuthSubType.PIN_NUMBER: 216 AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Locking); 217 mRouterPath = URI_CUSTOMPASSWORD; 218 this.checkFaceAuthProperty(() => { 219 callback() 220 }) 221 break; 222 default: 223 AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Unlock); 224 mWillRecognizeFace = false 225 } 226 }) 227 } 228 229 private checkFaceAuthProperty(callback: Callback<void>) { 230 Log.showDebug(TAG, "checkFaceAuthProperty") 231 this.accountModel.getAuthProperty(AuthType.FACE, (properties) => { 232 Log.showInfo(TAG, `checkFaceAuthProperty:AUTH_SUB_TYPE:${properties.authSubType}`); 233 switch (properties.authSubType) { 234 case AuthSubType.FACE_2D: 235 case AuthSubType.FACE_3D: 236 mWillRecognizeFace = true 237 callback() 238 break; 239 default: 240 mWillRecognizeFace = false 241 } 242 }) 243 } 244 245 unlockScreen() { 246 Log.showInfo(TAG, `unlockScreen`); 247 this.accountModel.isActivateAccount((isActivate: boolean) => { 248 if (!isActivate) { 249 return 250 } 251 mUnLockBeginAnimation(() => { 252 let status = AppStorage.Link('lockStatus') 253 Log.showDebug(TAG, `unlocking lockStatus:${JSON.stringify(status?.get())}`); 254 if (status?.get() == ScreenLockStatus.Unlock) { 255 Log.showInfo(TAG, `unlock the screen`); 256 this.unlocking(); 257 } else { 258 let slidestatus = AppStorage.Get('slidestatus') 259 if(!slidestatus){ 260 AppStorage.SetOrCreate('slidestatus', true); 261 const UIContext: UIContext = AppStorage.get('UIContext'); 262 Log.showInfo(TAG, `this.UIContext is ${UIContext}`) 263 Log.showInfo(TAG, `unlockScreen Router.push`); 264 UIContext.getRouter().pushUrl({ url: mRouterPath }) 265 } 266 } 267 }) 268 }) 269 } 270 271 unlocking() { 272 Log.showInfo(TAG, `unlocking`); 273 //set the lockStatus to 'Unlock' 274 AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Unlock); 275 this.currentLockStatus = ScreenLockStatus.Unlock; 276 AppStorage.SetOrCreate('slidestatus', false); 277 //unlock the screen 278 this.screenLockModel.hiddenScreenLockWindow(() => { 279 Log.showInfo(TAG, `hiddenScreenLockWindow finish`); 280 //notify the base service that the unlock is completed 281 this.notifyUnlockScreenResult(UnlockResult.Success); 282 }); 283 } 284 285 notifyUnlockScreenResult(result: UnlockResult) { 286 Log.showInfo(TAG, `notifyUnlockScreenResult`); 287 this.screenLockModel.sendScreenLockEvent(UNLOCK_SCREEN_RESULT, result, (error, data) => { 288 Log.showInfo(TAG, `notifyUnlockScreenResult: error:${JSON.stringify(error)} data:${JSON.stringify(data)}`); 289 }); 290 } 291 292 notifyLockScreenResult(result: LockResult) { 293 Log.showInfo(TAG, `notifyLockScreenResult`); 294 this.screenLockModel.sendScreenLockEvent(LOCK_SCREEN_RESULT, result, (error, data) => { 295 Log.showInfo(TAG, `notifyLockScreenResult: error:${JSON.stringify(error)} data:${JSON.stringify(data)}`); 296 }); 297 } 298 299 notifyDrawDone() { 300 Log.showInfo(TAG, `notifyDrawDone`); 301 //notify the base service that the screen is loaded 302 this.screenLockModel.sendScreenLockEvent(SCREENLOCK_DRAW_DONE, 0, (error, result) => { 303 Log.showInfo(TAG, `notifyDrawDone: error:${JSON.stringify(error)} result:${JSON.stringify(result)}`); 304 }); 305 } 306 307 authUser(authSubType: AuthSubType, passwordData: number[] | string, callback): void { 308 Log.showInfo(TAG, `authUser authSubType:${authSubType}`); 309 let password: string = ''; 310 if (typeof passwordData == 'string') { 311 password = passwordData; 312 } else { 313 password = passwordData.join(''); 314 } 315 this.accountModel.registerPWDInputer(password).then(() => { 316 Log.showInfo(TAG, `registerPWDInputer success`); 317 this.accountModel.authUser(CHALLENGE_INT, AuthType.PIN, AuthTurstLevel.ATL4, (result, extraInfo) => { 318 Log.showDebug(TAG, `authUser callback:${result} extraInfo:${JSON.stringify(extraInfo)}`); 319 this.accountModel.unregisterInputer(); 320 callback(result, extraInfo); 321 }) 322 }).catch(() => { 323 Log.showError(TAG, `registerPWDInputer fails`); 324 }) 325 } 326 327 authUserByFace() { 328 if (!mWillRecognizeFace) { 329 Log.showInfo(TAG, "Recognize face is not support") 330 return 331 } 332 Log.showInfo(TAG, `authUserByFace`); 333 this.accountModel.authUser(CHALLENGE_INT, AuthType.FACE, AuthTurstLevel.ATL1, (result, extraInfo) => { 334 Log.showDebug(TAG, `authUserByFace callback:${result} extraInfo:${JSON.stringify(extraInfo)}`); 335 if (result == 0) { 336 AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.Unlock); 337 this.unlockScreen() 338 } else { 339 AppStorage.SetOrCreate('lockStatus', ScreenLockStatus.FaceNotRecognized); 340 this.currentLockStatus = ScreenLockStatus.FaceNotRecognized; 341 } 342 }) 343 } 344 345 onUserSwitch(userId: number) { 346 this.accountModel.onUserSwitch(userId) 347 } 348 349 goBack() { 350 Log.showInfo(TAG, `screen lock service goBack`); 351 Router.back(); 352 this.notifyUnlockScreenResult(UnlockResult.Cancel) 353 this.accountModel.unregisterInputer(); 354 } 355 356 destroy() { 357 this.screenLockModel.eventCancelListener(EVENT_SYSTEM_READY); 358 this.screenLockModel.eventCancelListener(EVENT_END_SCREEN_ON); 359 this.screenLockModel.eventCancelListener(EVENT_BEGIN_SLEEP); 360 this.screenLockModel.eventCancelListener(EVENT_UNLOCK_SCREEN); 361 this.accountModel.eventCancelListener(ACTIVATING_TYPE, ACTIVATING_EVENT); 362 this.accountModel.eventCancelListener(ACTIVATE_TYPE, ACTIVATE_EVENT) 363 this.accountModel.commonEventCancelListener(); 364 this.accountModel.modelFinish() 365 this.stopMonitorMemory() 366 } 367 368 setUnlockAnimation(beginAnimation: Callback<Callback<void>>) { 369 mUnLockBeginAnimation = beginAnimation; 370 } 371 372 getAuthProperty(authType, callback) { 373 Log.showInfo(TAG, `getAuthProperty param: authType ${authType}`); 374 this.accountModel.getAuthProperty(authType, (properties) => { 375 callback(properties); 376 }) 377 } 378 379 private publishByUser(eventName: string, activeUserId: number) { 380 Log.showDebug(TAG, `publishByUser event name: ${eventName}, userId: ${activeUserId}`) 381 let publishData : CommonEventPublishData = { 382 parameters : { 383 userId : activeUserId 384 } 385 }; 386 commonEvent.publish(eventName, publishData, (error, value) => { 387 if (error.code) { 388 Log.showError(TAG, 'Operation failed. Cause: ' + JSON.stringify(error)); 389 } else { 390 Log.showDebug(TAG, 'publish common event success. ' + JSON.stringify(value)); 391 } 392 }); 393 } 394 395 private startMonitorMemory() { 396 this.memoryMonitor = setInterval(() => { 397 const pss = hiDebug.getPss(); 398 Log.showInfo(TAG, `app pss info is: ${pss}`); 399 if (pss > MEMORY_MONITOR_LIMIT_KB) { 400 WriteFaultLog({FAULT_ID: FaultID.MEMORY, MSG: "pss over limit"}) 401 } 402 }, MEMORY_MONITOR_PERIOD_MS) 403 } 404 405 private stopMonitorMemory() { 406 if (this.memoryMonitor !== -1) { 407 clearInterval(this.memoryMonitor); 408 this.memoryMonitor = -1; 409 } 410 } 411} 412 413let screenLockService = createOrGet(ScreenLockService, TAG); 414 415export default screenLockService as ScreenLockService;