1# Using an EL5 Database
2
3
4## When to Use
5
6An [EL5](../reference/apis-ability-kit/js-apis-app-ability-contextConstant.md#areamode) database is created in the **el5/** directory to store the application's sensitive information. When the device screen is locked and certain conditions are met, the key used to encrypt the sensitive information will be destroyed and the database cannot be operated. After the screen is unlocked, the key is restored and the read and write operations on the database are restored. This mechanism can effectively protect the user data. For details about how to manage the encryption directories, see [Obtaining and Modifying Encryption Levels](../application-models/application-context-stage.md#obtaining-and-modifying-encryption-levels).
7
8However, the application may write data when the screen is locked. Data loss will be caused if the EL5 database cannot be operated when data is written. A solution is provided to solve this problem. When the screen is locked, incremental data is stored in an [EL2](../reference/apis-ability-kit/js-apis-app-ability-contextConstant.md#areamode) database. The data temporarily stored in the EL2 database will be moved to the EL5 database when the EL5 database is unlocked. This ensures data security and consistency when the screen is locked.
9
10Both the KV store and RDB store can be used as an EL5 database.
11
12## Working Principles
13
14The following classes are encapsulated to implement the data operations and transfer between EL2 and EL5 databases:
15
16- **Mover** class: provides APIs for moving data from an EL2 database to an EL5 database after the screen is unlocked.
17- **Store** class: provides APIs for accessing and operating the currently operable database.
18- **SecretKeyObserver** class: provides APIs for obtaining the key status. After the key is destroyed, the EL5 database will be closed.
19
20- **ECStoreManager** class: provides APIs for managing the EL2 and EL5 databases.
21
22## Requesting Permissions
23
24To access the database in the **el5/** directory, the application must have the ohos.permission.PROTECT_SCREEN_LOCK_DATA permission. Add this permission in the **module.json5** file.
25
26```ts
27// module.json5
28"requestPermissions": [
29      {
30        "name": "ohos.permission.PROTECT_SCREEN_LOCK_DATA"
31      }
32    ]
33```
34
35## Using an EL5 KV Store
36
37The following describes how to use the [Mover](#mover), [Store](#store), [SecretKeyObserver](#secretkeyobserver), and [ECStoreManager](#ecstoremanager) classes to implement the use of a KV store in the **el5/** directory. In the following example, [EntryAbility](#entryability) and [index key event](#index-key-event) are used to present how to use these classes.
38
39### Mover
40
41Use **Mover** to move data from an EL2 database to an EL5 database after the screen is unlocked.
42
43```ts
44// Mover.ts
45import { distributedKVStore } from '@kit.ArkData';
46
47export class Mover {
48  async move(eStore: distributedKVStore.SingleKVStore, cStore: distributedKVStore.SingleKVStore): Promise<void> {
49    if (eStore != null && cStore != null) {
50      let entries: distributedKVStore.Entry[] = await cStore.getEntries('key_test_string');
51      await eStore.putBatch(entries);
52      console.info(`ECDB_Encry move success`);
53    }
54  }
55}
56```
57
58### Store
59
60Use the APIs provided by the **Store** class to obtain a database instance, add, delete, and update data, and obtain the data count in the database.
61
62```ts
63// Store.ts
64import { distributedKVStore } from '@kit.ArkData';
65import { BusinessError } from '@kit.BasicServicesKit';
66
67let kvManager: distributedKVStore.KVManager;
68
69export class StoreInfo {
70  kvManagerConfig: distributedKVStore.KVManagerConfig;
71  storeId: string;
72  option: distributedKVStore.Options;
73}
74
75export class Store {
76  async getECStore(storeInfo: StoreInfo): Promise<distributedKVStore.SingleKVStore> {
77    try {
78      kvManager = distributedKVStore.createKVManager(storeInfo.kvManagerConfig);
79      console.info("Succeeded in creating KVManager");
80    } catch (e) {
81      let error = e as BusinessError;
82      console.error(`Failed to create KVManager.code is ${error.code},message is ${error.message}`);
83    }
84    if (kvManager !== undefined) {
85      kvManager = kvManager as distributedKVStore.KVManager;
86      let kvStore: distributedKVStore.SingleKVStore | null;
87      try {
88        kvStore = await kvManager.getKVStore<distributedKVStore.SingleKVStore>(storeInfo.storeId, storeInfo.option);
89        if (kvStore != undefined) {
90          console.info(`ECDB_Encry succeeded in getting store : ${storeInfo.storeId}`);
91          return kvStore;
92        }
93      } catch (e) {
94        let error = e as BusinessError;
95        console.error(`An unexpected error occurred.code is ${error.code},message is ${error.message}`);
96      }
97    }
98  }
99
100  putOnedata(kvStore: distributedKVStore.SingleKVStore): void {
101    if (kvStore != undefined) {
102      const KEY_TEST_STRING_ELEMENT = 'key_test_string' + String(Date.now());
103      const VALUE_TEST_STRING_ELEMENT = 'value_test_string' + String(Date.now());
104      try {
105        kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => {
106          if (err !== undefined) {
107            console.error(`Failed to put data. Code:${err.code},message:${err.message}`);
108            return;
109          }
110          console.info(`ECDB_Encry Succeeded in putting data.${KEY_TEST_STRING_ELEMENT}`);
111        });
112      } catch (e) {
113        let error = e as BusinessError;
114        console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
115      }
116    }
117  }
118
119  getDataNum(kvStore: distributedKVStore.SingleKVStore): void {
120    if (kvStore != undefined) {
121      let resultSet: distributedKVStore.KVStoreResultSet;
122      kvStore.getResultSet("key_test_string").then((result: distributedKVStore.KVStoreResultSet) => {
123        console.info(`ECDB_Encry Succeeded in getting result set num ${result.getCount()}`);
124        resultSet = result;
125        if (kvStore != null) {
126          kvStore.closeResultSet(resultSet).then(() => {
127            console.info('Succeeded in closing result set');
128          }).catch((err: BusinessError) => {
129            console.error(`Failed to close resultset.code is ${err.code},message is ${err.message}`);
130          });
131        }
132      }).catch((err: BusinessError) => {
133        console.error(`Failed to get resultset.code is ${err.code},message is ${err.message}`);
134      });
135    }
136  }
137
138  deleteOnedata(kvStore: distributedKVStore.SingleKVStore): void {
139    if (kvStore != undefined) {
140      kvStore.getEntries('key_test_string', (err: BusinessError, entries: distributedKVStore.Entry[]) => {
141        if (err != undefined) {
142          console.error(`Failed to get Entries.code is ${err.code},message is ${err.message}`);
143          return;
144        }
145        if (kvStore != null && entries.length != 0) {
146          kvStore.delete(entries[0].key, (err: BusinessError) => {
147            if (err != undefined) {
148              console.error(`Failed to delete.code is ${err.code},message is ${err.message}`);
149              return;
150            }
151            console.info('ECDB_Encry Succeeded in deleting');
152          });
153        }
154      });
155    }
156  }
157
158  updataOnedata(kvStore: distributedKVStore.SingleKVStore): void {
159    if (kvStore != undefined) {
160      kvStore.getEntries('key_test_string', async (err: BusinessError, entries: distributedKVStore.Entry[]) => {
161        if (err != undefined) {
162          console.error(`Failed to get Entries.code is ${err.code},message is ${err.message}`);
163          return;
164        }
165        if (kvStore != null && entries.length != 0) {
166          console.info(`ECDB_Encry old data:${entries[0].key},value :${entries[0].value.value.toString()}`)
167          await kvStore.put(entries[0].key, "new value_test_string" + String(Date.now()) + 'new').then(() => {
168          }).catch((err: BusinessError) => {
169            console.error(`Failed to put.code is ${err.code},message is ${err.message}`);
170          });
171        }
172        console.info(`ECDB_Encry updata success`)
173      });
174    }
175  }
176}
177```
178
179### SecretKeyObserver
180
181Use the APIs provided by the **SecretKeyObserver** class to obtain the key status. After the key is destroyed, the EL5 database will be closed.
182
183```ts
184// SecretKeyObserver.ts
185import { ECStoreManager } from './ECStoreManager';
186
187export enum SecretStatus {
188  Lock,
189  UnLock
190}
191
192export class SecretKeyObserver {
193  onLock(): void {
194    this.lockStatuas = SecretStatus.Lock;
195    this.storeManager.closeEStore();
196  }
197
198  onUnLock(): void {
199    this.lockStatuas = SecretStatus.UnLock;
200  }
201
202  getCurrentStatus(): number {
203    return this.lockStatuas;
204  }
205
206  initialize(storeManager: ECStoreManager): void {
207    this.storeManager = storeManager;
208  }
209
210  updatalockStatus(code: number) {
211    if (code === SecretStatus.Lock) {
212      this.onLock();
213    } else {
214      this.lockStatuas = code;
215    }
216  }
217
218  // Obtain the screen lock status.
219  private lockStatuas: number = SecretStatus.UnLock;
220  private storeManager: ECStoreManager;
221}
222
223export let lockObserve = new SecretKeyObserver();
224```
225
226### ECStoreManager
227
228Use the APIs provided by the **ECStoreManager** class to manage the EL2 and EL5 databases. Specifically, you can use the APIs to configure a database, set the function used to move data, provide the database handle for the application based on the key status, close an EL5 database, and destroy an El2 database after the data is moved.
229
230```ts
231// ECStoreManager.ts
232import { distributedKVStore } from '@kit.ArkData';
233import { Mover } from './Mover';
234import { BusinessError } from '@kit.BasicServicesKit';
235import { StoreInfo, Store } from './Store';
236import { SecretStatus } from './SecretKeyObserver';
237
238let store = new Store();
239
240export class ECStoreManager {
241  config(cInfo: StoreInfo, other: StoreInfo): void {
242    this.cInfo = cInfo;
243    this.eInfo = other;
244  }
245
246  configDataMover(mover: Mover): void {
247    this.mover = mover;
248  }
249
250  async getCurrentStore(screanStatus: number): Promise<distributedKVStore.SingleKVStore> {
251    console.info(`ECDB_Encry GetCurrentStore start screanStatus: ${screanStatus}`);
252    if (screanStatus === SecretStatus.UnLock) {
253      try {
254        this.eStore = await store.getECStore(this.eInfo);
255      } catch (e) {
256        let error = e as BusinessError;
257        console.error(`Failed to GetECStore.code is ${error.code},message is ${error.message}`);
258      }
259      // Obtain an EL5 database when the screen is unlocked.
260      if (this.needMove) {
261        if (this.eStore != undefined && this.cStore != undefined) {
262          await this.mover.move(this.eStore, this.cStore);
263        }
264        this.deleteCStore();
265        console.info(`ECDB_Encry Data migration is complete. Destroy cstore`);
266        this.needMove = false;
267      }
268      return this.eStore;
269    } else {
270      // Obtain an EL2 database when the screen is locked.
271      this.needMove = true;
272      try {
273        this.cStore = await store.getECStore(this.cInfo);
274      } catch (e) {
275        let error = e as BusinessError;
276        console.error(`Failed to GetECStore.code is ${error.code},message is ${error.message}`);
277      }
278      return this.cStore;
279    }
280  }
281
282  closeEStore(): void {
283    try {
284      let kvManager = distributedKVStore.createKVManager(this.eInfo.kvManagerConfig);
285      console.info("Succeeded in creating KVManager");
286      if (kvManager != undefined) {
287        kvManager.closeKVStore(this.eInfo.kvManagerConfig.bundleName, this.eInfo.storeId);
288        this.eStore = null;
289        console.info(`ECDB_Encry close EStore success`)
290      }
291    } catch (e) {
292      let error = e as BusinessError;
293      console.error(`Failed to create KVManager.code is ${error.code},message is ${error.message}`);
294    }
295  }
296
297  deleteCStore(): void {
298    try {
299      let kvManager = distributedKVStore.createKVManager(this.cInfo.kvManagerConfig);
300      console.info("Succeeded in creating KVManager");
301      if (kvManager != undefined) {
302        kvManager.deleteKVStore(this.cInfo.kvManagerConfig.bundleName, this.cInfo.storeId);
303        this.cStore = null;
304        console.info("ECDB_Encry delete cStore success");
305      }
306    } catch (e) {
307      let error = e as BusinessError;
308      console.error(`Failed to create KVManager.code is ${error.code},message is ${error.message}`);
309    }
310  }
311
312  private eStore: distributedKVStore.SingleKVStore = null;
313  private cStore: distributedKVStore.SingleKVStore = null;
314  private cInfo: StoreInfo | null = null;
315  private eInfo: StoreInfo | null = null;
316  private needMove: boolean = false;
317  private mover: Mover | null = null;
318}
319```
320
321### EntryAbility
322
323Register a listener for the COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED event when the simulated application starts, and configure the database information and key status information.
324
325```ts
326// EntryAbility.ets
327import { AbilityConstant, contextConstant, UIAbility, Want } from '@kit.AbilityKit';
328import { hilog } from '@kit.PerformanceAnalysisKit';
329import { window } from '@kit.ArkUI';
330import { distributedKVStore } from '@kit.ArkData';
331import { ECStoreManager } from './ECStoreManager';
332import { StoreInfo } from './Store';
333import { Mover } from './Mover';
334import { SecretKeyObserver } from './SecretKeyObserver';
335import { commonEventManager } from '@kit.BasicServicesKit';
336import { BusinessError } from '@kit.BasicServicesKit';
337
338
339export let storeManager = new ECStoreManager();
340
341export let e_secretKeyObserver = new SecretKeyObserver();
342
343let mover = new Mover();
344
345let subscriber: commonEventManager.CommonEventSubscriber;
346
347export function createCB(err: BusinessError, commonEventSubscriber: commonEventManager.CommonEventSubscriber) {
348  if (!err) {
349    console.info('ECDB_Encry createSubscriber');
350    subscriber = commonEventSubscriber;
351    try {
352      commonEventManager.subscribe(subscriber, (err: BusinessError, data: commonEventManager.CommonEventData) => {
353        if (err) {
354          console.error(`subscribe failed, code is ${err.code}, message is ${err.message}`);
355        } else {
356          console.info(`ECDB_Encry SubscribeCB ${data.code}`);
357          e_secretKeyObserver.updatalockStatus(data.code);
358        }
359      });
360    } catch (error) {
361      const err: BusinessError = error as BusinessError;
362      console.error(`subscribe failed, code is ${err.code}, message is ${err.message}`);
363    }
364  } else {
365    console.error(`createSubscriber failed, code is ${err.code}, message is ${err.message}`);
366  }
367}
368
369let cInfo: StoreInfo | null = null;
370let eInfo: StoreInfo | null = null;
371
372export default class EntryAbility extends UIAbility {
373  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
374    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
375    let cContext = this.context;
376    cInfo = {
377      "kvManagerConfig": {
378        context: cContext,
379        bundleName: 'com.example.ecstoredemo',
380      },
381      "storeId": "cstore",
382      "option": {
383        createIfMissing: true,
384        encrypt: false,
385        backup: false,
386        autoSync: false,
387        // If kvStoreType is left empty, a device KV store is created by default.
388        kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
389        // kvStoreType is distributedKVStore.KVStoreType.DEVICE_COLLABORATION for a device KV store.
390        securityLevel: distributedKVStore.SecurityLevel.S3
391      }
392    }
393    let eContext = this.context.createModuleContext("entry");
394    eContext.area = contextConstant.AreaMode.EL5;
395    eInfo = {
396      "kvManagerConfig": {
397        context: eContext,
398        bundleName: 'com.example.ecstoredemo',
399      },
400      "storeId": "estore",
401      "option": {
402        createIfMissing: true,
403        encrypt: false,
404        backup: false,
405        autoSync: false,
406        // If kvStoreType is left empty, a device KV store is created by default.
407        kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
408        // kvStoreType is distributedKVStore.KVStoreType.DEVICE_COLLABORATION for a device KV store.
409        securityLevel: distributedKVStore.SecurityLevel.S3
410      }
411    }
412    console.info(`ECDB_Encry store area : estore:${eContext.area},cstore${cContext.area}`);
413    // Listen for the COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED event. code == 1 indicates the screen is unlocked, and code==0 indicates the screen is locked.
414    try {
415      commonEventManager.createSubscriber({
416        events: ['COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED']
417      }, createCB);
418      console.info(`ECDB_Encry success subscribe`);
419    } catch (error) {
420      const err: BusinessError = error as BusinessError;
421      console.error(`createSubscriber failed, code is ${err.code}, message is ${err.message}`);
422    }
423    storeManager.config(cInfo, eInfo);
424    storeManager.configDataMover(mover);
425    e_secretKeyObserver.initialize(storeManager);
426  }
427
428  onDestroy(): void {
429    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
430  }
431
432  onWindowStageCreate(windowStage: window.WindowStage): void {
433    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
434
435    windowStage.loadContent('pages/Index', (err) => {
436      if (err.code) {
437        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
438        return;
439      }
440      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
441    });
442  }
443
444  onWindowStageDestroy(): void {
445    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
446  }
447
448  onForeground(): void {
449    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
450  }
451
452  onBackground(): void {
453    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
454  }
455}
456```
457
458### Index Key Event
459
460Use **Button** to simulate application operations on the database, such as inserting, deleting, updating, and obtaining the data count, by clicking the button.
461
462```ts
463// Index.ets
464import { storeManager, e_secretKeyObserver } from "../entryability/EntryAbility";
465import { distributedKVStore } from '@kit.ArkData';
466import { Store } from '../entryability/Store';
467
468let storeOption = new Store();
469
470let lockStatus: number = 1;
471
472@Entry
473@Component
474struct Index {
475  @State message: string = 'Hello World';
476
477  build() {
478    Row() {
479      Column() {
480        Button ('Lock/Unlock').onClick ((event: ClickEvent) => {
481          if (lockStatus) {
482            e_secretKeyObserver.onLock();
483            lockStatus = 0;
484          } else {
485            e_secretKeyObserver.onUnLock();
486            lockStatus = 1;
487          }
488          lockStatus? this.message = "Unlocked": this.message = "Locked";
489        }).margin("5");
490        Button('store type').onClick(async (event: ClickEvent) => {
491          e_secretKeyObserver.getCurrentStatus() ? this.message = "estroe" : this.message = "cstore";
492        }).margin("5");
493
494        Button("put").onClick(async (event: ClickEvent) => {
495          let store: distributedKVStore.SingleKVStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
496          storeOption.putOnedata(store);
497        }).margin(5)
498
499        Button("Get").onClick(async (event: ClickEvent) => {
500          let store: distributedKVStore.SingleKVStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
501          storeOption.getDataNum(store);
502        }).margin(5)
503
504        Button("delete").onClick(async (event: ClickEvent) => {
505          let store: distributedKVStore.SingleKVStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
506          storeOption.deleteOnedata(store);
507        }).margin(5)
508
509        Button("updata").onClick(async (event: ClickEvent) => {
510          let store: distributedKVStore.SingleKVStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
511          storeOption.updataOnedata(store);
512        }).margin(5)
513
514        Text(this.message)
515          .fontSize(50)
516          .fontWeight(FontWeight.Bold)
517      }
518      .width('100%')
519    }
520    .height('100%')
521  }
522}
523```
524
525## Using an EL5 RDB Store
526
527The following describes how to use the [Mover](#mover-1), [Store](#store-1), [SecretKeyObserver](#secretkeyobserver-1), and [ECStoreManager](#ecstoremanager-1) classes to implement the use of an RDB store in the **el5/** directory. In the following example, [EntryAbility](#entryability-1) and [index key event](#index-key-event-1) are used to present how to use these classes.
528
529### Mover
530
531Use **Mover** to move data from an EL2 database to an EL5 database after the screen is unlocked.
532
533```ts
534// Mover.ts
535import { relationalStore } from '@kit.ArkData';
536
537export class Mover {
538  async move(eStore: relationalStore.RdbStore, cStore: relationalStore.RdbStore) {
539    if (eStore != null && cStore != null) {
540      let predicates = new relationalStore.RdbPredicates('employee');
541      let resultSet = await cStore.query(predicates);
542      while (resultSet.goToNextRow()) {
543        let bucket = resultSet.getRow();
544        await eStore.insert('employee', bucket);
545      }
546    }
547  }
548}
549```
550
551### Store
552
553Use the APIs provided by the **Store** class to obtain a database instance, add, delete, and update data, and obtain the data count in the database. The **StoreInfo** class is used to store and obtain database information.
554
555```ts
556// Store.ts
557import { relationalStore } from '@kit.ArkData';
558import { BusinessError } from '@kit.BasicServicesKit';
559import { Context } from '@kit.AbilityKit';
560
561export class StoreInfo {
562  context: Context;
563  config: relationalStore.StoreConfig;
564  storeId: string;
565}
566
567let id = 1;
568const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB)';
569
570
571export class Store {
572  async getECStore(storeInfo: StoreInfo): Promise<relationalStore.RdbStore> {
573    let rdbStore: relationalStore.RdbStore | null;
574    try {
575      rdbStore = await relationalStore.getRdbStore(storeInfo.context, storeInfo.config);
576      if (rdbStore.version == 0) {
577        await rdbStore.executeSql(SQL_CREATE_TABLE);
578        console.info(`ECDB_Encry succeeded in getting Store : ${storeInfo.storeId}`);
579        rdbStore.version = 1;
580      }
581    } catch (e) {
582      let error = e as BusinessError;
583      console.error(`An unexpected error occurred.code is ${error.code},message is ${error.message}`);
584    }
585    return rdbStore;
586  }
587
588  async putOnedata(rdbStore: relationalStore.RdbStore) {
589    if (rdbStore != undefined) {
590      const valueBucket: relationalStore.ValuesBucket = {
591        ID: id++,
592        NAME: 'Lisa',
593        AGE: 18,
594        SALARY: 100.5,
595        CODES: new Uint8Array([1, 2, 3, 4, 5]),
596      };
597      try {
598        await rdbStore.insert("EMPLOYEE", valueBucket);
599        console.info(`ECDB_Encry insert success`);
600      } catch (e) {
601        let error = e as BusinessError;
602        console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
603      }
604    }
605  }
606
607  async getDataNum(rdbStore: relationalStore.RdbStore) {
608    if (rdbStore != undefined) {
609      try {
610        let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
611        let resultSet = await rdbStore.query(predicates);
612        let count = resultSet.rowCount;
613        console.info(`ECDB_Encry getdatanum success count : ${count}`);
614      } catch (e) {
615        let error = e as BusinessError;
616        console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
617      }
618    }
619  }
620
621  async deleteAlldata(rdbStore: relationalStore.RdbStore) {
622    if (rdbStore != undefined) {
623      try {
624        let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
625        predicates.equalTo('AGE', 18);
626        await rdbStore.delete(predicates);
627        console.info(`ECDB_Encry delete Success`);
628      } catch (e) {
629        let error = e as BusinessError;
630        console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
631      }
632    }
633  }
634
635  async updataOnedata(rdbStore: relationalStore.RdbStore) {
636    if (rdbStore != undefined) {
637      try {
638        let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
639        predicates.equalTo('NAME', 'Lisa');
640        const valueBucket: relationalStore.ValuesBucket = {
641          NAME: 'Anna',
642          SALARY: 100.5,
643          CODES: new Uint8Array([1, 2, 3, 4, 5]),
644        };
645        await rdbStore.update(valueBucket, predicates);
646        console.info(`ECDB_Encry update success`);
647      } catch (e) {
648        let error = e as BusinessError;
649        console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
650      }
651    }
652  }
653}
654```
655
656### SecretKeyObserver
657
658Use the APIs provided by the **SecretKeyObserver** class to obtain the key status. After the key is destroyed, the EL5 database will be closed.
659
660```ts
661// SecretKeyObserver.ts
662import { ECStoreManager } from './ECStoreManager';
663
664export enum SecretStatus {
665  Lock,
666  UnLock
667}
668
669export class SecretKeyObserver {
670  onLock(): void {
671    this.lockStatuas = SecretStatus.Lock;
672    this.storeManager.closeEStore();
673  }
674
675  onUnLock(): void {
676    this.lockStatuas = SecretStatus.UnLock;
677  }
678
679  getCurrentStatus(): number {
680    return this.lockStatuas;
681  }
682
683  initialize(storeManager: ECStoreManager): void {
684    this.storeManager = storeManager;
685  }
686
687  updatalockStatus(code: number) {
688    if (this.lockStatuas === SecretStatus.Lock) {
689      this.onLock();
690    } else {
691      this.lockStatuas = code;
692    }
693  }
694
695  private lockStatuas: number = SecretStatus.UnLock;
696  private storeManager: ECStoreManager;
697}
698
699export let lockObserve = new SecretKeyObserver();
700```
701
702### ECStoreManager
703
704Use the APIs provided by the **ECStoreManager** class to manage the EL2 and EL5 databases. Specifically, you can use the APIs to configure a database, set the function used to move data, provide the database handle for the application based on the key status, close an EL5 database, and destroy an El2 database after the data is moved.
705
706```ts
707// ECStoreManager.ts
708import { relationalStore } from '@kit.ArkData';
709import { Mover } from './Mover';
710import { BusinessError } from '@kit.BasicServicesKit';
711import { StoreInfo, Store } from './Store';
712import { SecretStatus } from './SecretKeyObserver';
713
714let store = new Store();
715
716export class ECStoreManager {
717  config(cInfo: StoreInfo, other: StoreInfo): void {
718    this.cInfo = cInfo;
719    this.eInfo = other;
720  }
721
722  configDataMover(mover: Mover): void {
723    this.mover = mover;
724  }
725
726  async getCurrentStore(screanStatus: number): Promise<relationalStore.RdbStore> {
727    if (screanStatus === SecretStatus.UnLock) {
728      try {
729        this.eStore = await store.getECStore(this.eInfo);
730      } catch (e) {
731        let error = e as BusinessError;
732        console.error(`Failed to GetECStore.code is ${error.code},message is ${error.message}`);
733      }
734      // Obtain an EL5 database when the screen is unlocked.
735      if (this.needMove) {
736        if (this.eStore != undefined && this.cStore != undefined) {
737          await this.mover.move(this.eStore, this.cStore);
738          console.info(`ECDB_Encry cstore data move to estore success`);
739        }
740        this.deleteCStore();
741        this.needMove = false;
742      }
743      return this.eStore;
744    } else {
745      // Obtain an EL2 database when the screen is locked.
746      this.needMove = true;
747      try {
748        this.cStore = await store.getECStore(this.cInfo);
749      } catch (e) {
750        let error = e as BusinessError;
751        console.error(`Failed to GetECStore.code is ${error.code},message is ${error.message}`);
752      }
753      return this.cStore;
754    }
755  }
756
757  closeEStore(): void {
758    this.eStore = undefined;
759  }
760
761  async deleteCStore() {
762    try {
763      await relationalStore.deleteRdbStore(this.cInfo.context, this.cInfo.storeId)
764    } catch (e) {
765      let error = e as BusinessError;
766      console.error(`Failed to create KVManager.code is ${error.code},message is ${error.message}`);
767    }
768  }
769
770  private eStore: relationalStore.RdbStore = null;
771  private cStore: relationalStore.RdbStore = null;
772  private cInfo: StoreInfo | null = null;
773  private eInfo: StoreInfo | null = null;
774  private needMove: boolean = false;
775  private mover: Mover | null = null;
776}
777```
778
779### EntryAbility
780
781Register a listener for the COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED event when the simulated application starts, and configure the database information and key status information.
782
783```ts
784// EntryAbility.ets
785import { AbilityConstant, contextConstant, UIAbility, Want } from '@kit.AbilityKit';
786import { hilog } from '@kit.PerformanceAnalysisKit';
787import { window } from '@kit.ArkUI';
788import { relationalStore } from '@kit.ArkData';
789import { ECStoreManager } from './ECStoreManager';
790import { StoreInfo } from './Store';
791import { Mover } from './Mover';
792import { SecretKeyObserver } from './SecretKeyObserver';
793import { commonEventManager } from '@kit.BasicServicesKit';
794import { BusinessError } from '@kit.BasicServicesKit';
795
796
797export let storeManager = new ECStoreManager();
798
799export let e_secretKeyObserver = new SecretKeyObserver();
800
801let mover = new Mover();
802
803let subscriber: commonEventManager.CommonEventSubscriber;
804
805export function createCB(err: BusinessError, commonEventSubscriber: commonEventManager.CommonEventSubscriber) {
806  if (!err) {
807    console.info('ECDB_Encry createSubscriber');
808    subscriber = commonEventSubscriber;
809    try {
810      commonEventManager.subscribe(subscriber, (err: BusinessError, data: commonEventManager.CommonEventData) => {
811        if (err) {
812          console.error(`subscribe failed, code is ${err.code}, message is ${err.message}`);
813        } else {
814          console.info(`ECDB_Encry SubscribeCB ${data.code}`);
815          e_secretKeyObserver.updatalockStatus(data.code);
816        }
817      });
818    } catch (error) {
819      const err: BusinessError = error as BusinessError;
820      console.error(`subscribe failed, code is ${err.code}, message is ${err.message}`);
821    }
822  } else {
823    console.error(`createSubscriber failed, code is ${err.code}, message is ${err.message}`);
824  }
825}
826
827let cInfo: StoreInfo | null = null;
828let eInfo: StoreInfo | null = null;
829
830export default class EntryAbility extends UIAbility {
831  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
832    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
833    let cContext = this.context;
834    cInfo = {
835      context: cContext,
836      config: {
837        name: 'cstore.db',
838        securityLevel: relationalStore.SecurityLevel.S3,
839      },
840      storeId: "cstore.db"
841    }
842    let eContext = this.context.createModuleContext("entry");
843    eContext.area = contextConstant.AreaMode.EL5;
844    eInfo = {
845      context: eContext,
846      config: {
847        name: 'estore.db',
848        securityLevel: relationalStore.SecurityLevel.S3,
849      },
850      storeId: "estore.db",
851    }
852    // Listen for the COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED event. code == 1 indicates the screen is unlocked, and code==0 indicates the screen is locked.
853    console.info(`ECDB_Encry store area : estore:${eContext.area},cstore${cContext.area}`)
854    try {
855      commonEventManager.createSubscriber({
856        events: ['COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED']
857      }, createCB);
858      console.info(`ECDB_Encry success subscribe`);
859    } catch (error) {
860      const err: BusinessError = error as BusinessError;
861      console.error(`createSubscriber failed, code is ${err.code}, message is ${err.message}`);
862    }
863    storeManager.config(cInfo, eInfo);
864    storeManager.configDataMover(mover);
865    e_secretKeyObserver.initialize(storeManager);
866  }
867
868  onDestroy(): void {
869    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
870  }
871
872  onWindowStageCreate(windowStage: window.WindowStage): void {
873    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
874
875    windowStage.loadContent('pages/Index', (err) => {
876      if (err.code) {
877        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
878        return;
879      }
880      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
881    });
882  }
883
884  onWindowStageDestroy(): void {
885    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
886  }
887
888  onForeground(): void {
889    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
890  }
891
892  onBackground(): void {
893    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
894  }
895}
896```
897
898### Index Key Event
899
900Use **Button** to simulate application operations on the database, such as inserting, deleting, updating, and obtaining the data count, by clicking the button.
901
902```ts
903// Index.ets
904import { storeManager, e_secretKeyObserver } from "../entryability/EntryAbility";
905import { relationalStore } from '@kit.ArkData';
906import { Store } from '../entryability/Store';
907
908let storeOption = new Store();
909
910let lockStatus: number = 1;
911
912@Entry
913@Component
914struct Index {
915  @State message: string = 'Hello World';
916
917  build() {
918    Row() {
919      Column() {
920        Button ('Lock/Unlock').onClick ((event: ClickEvent) => {
921          if (lockStatus) {
922            e_secretKeyObserver.onLock();
923            lockStatus = 0;
924          } else {
925            e_secretKeyObserver.onUnLock();
926            lockStatus = 1;
927          }
928          lockStatus? this.message = "Unlocked": this.message = "Locked";
929        }).margin("5");
930        Button('store type').onClick(async (event: ClickEvent) => {
931          e_secretKeyObserver.getCurrentStatus() ? this.message = "estroe" : this.message = "cstore";
932          console.info(`ECDB_Encry current store : ${this.message}`);
933        }).margin("5");
934
935        Button("put").onClick(async (event: ClickEvent) => {
936          let store: relationalStore.RdbStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
937          storeOption.putOnedata(store);
938        }).margin(5)
939
940        Button("Get").onClick(async (event: ClickEvent) => {
941          let store: relationalStore.RdbStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
942          storeOption.getDataNum(store);
943        }).margin(5)
944
945        Button("delete").onClick(async (event: ClickEvent) => {
946          let store: relationalStore.RdbStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
947          storeOption.deleteAlldata(store);
948        }).margin(5)
949
950        Button("updata").onClick(async (event: ClickEvent) => {
951          let store: relationalStore.RdbStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
952          storeOption.updataOnedata(store);
953        }).margin(5)
954
955        Text(this.message)
956          .fontSize(50)
957          .fontWeight(FontWeight.Bold)
958      }
959      .width('100%')
960    }
961    .height('100%')
962  }
963}
964```
965