• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;