1# E类加密数据库的使用
2
3
4## 场景介绍
5
6为了满足数据库的安全特性,存有敏感信息的应用会在[EL5](../reference/apis-ability-kit/js-apis-app-ability-contextConstant.md#areamode)(加密路径切换请参考[获取和修改加密分区](../application-models/application-context-stage.md#获取和修改加密分区)EL1-EL4路径切换)路径下创建了一个E类数据库。在锁屏的情况下,满足一定条件时,会触发密钥的销毁,此时E类数据库不可读写。当锁屏解锁后,密钥会恢复,E类数据库恢复正常读写操作。这样的设计可以有效防止用户数据的泄露。
7
8然而,在锁屏的情况下,应用程序仍然可以继续写入数据,由于此时E类数据库不可读写,可能会导致数据丢失。为了解决这个问题,当前提供了一种方案:在锁屏的情况下,将数据存储在[EL2](../reference/apis-ability-kit/js-apis-app-ability-contextConstant.md#areamode)路径下的C类数据库中。当解锁后,再将数据迁移到E类数据库中。这样可以确保数据在锁屏期间的安全性和完整性。
9
10键值型数据库和关系型数据库均支持E类加密数据库。
11
12## 实现机制
13
14通过封装Mover类、Store类、SecretKeyObserver类和ECStoreManager类实现应用数据库密钥加锁和解锁状态下E类数据库和C类数据库的切换和操作。
15
16Mover类:提供数据库数据迁移接口,在锁屏解锁后,若C类数据库中有数据,使用该接口将数据迁移到E类数据库。
17
18Store类:提供了获取数据库,在数据库中插入数据、删除数据、更新数据和获取当前数据数量的接口。
19
20SecretKeyObserver类:提供了获取当前密钥状态的接口,在密钥销毁后,关闭E类数据库。
21
22ECStoreManager类:用于管理应用的E类数据库和C类数据库。
23
24## 配置权限
25
26使用EL5路径下的数据库,需要配置ohos.permission.PROTECT_SCREEN_LOCK_DATA权限。
27
28```ts
29// module.json5
30"requestPermissions": [
31      {
32        "name": "ohos.permission.PROTECT_SCREEN_LOCK_DATA"
33      }
34    ]
35```
36
37## 键值型数据库E类加密
38
39本章节提供键值型数据库的E类加密数据库使用方式,提供[Mover](#mover)类、[Store](#store)类、[SecretKeyObserver](#secretkeyobserver)类和[ECStoreManager](#ecstoremanager)类的具体实现,并在[EntryAbility](#entryability)和[index按键事件](#index按键事件)中展示这几个类的使用方式。
40
41### Mover
42
43提供数据库数据迁移接口,在锁屏解锁后,若C类数据库中存在数据,使用该接口将数据迁移到E类数据库。
44
45```ts
46// Mover.ts
47import { distributedKVStore } from '@kit.ArkData';
48
49export class Mover {
50  async move(eStore: distributedKVStore.SingleKVStore, cStore: distributedKVStore.SingleKVStore): Promise<void> {
51    if (eStore != null && cStore != null) {
52      let entries: distributedKVStore.Entry[] = await cStore.getEntries('key_test_string');
53      await eStore.putBatch(entries);
54      console.info(`ECDB_Encry move success`);
55    }
56  }
57}
58```
59
60### Store
61
62提供了获取数据库,在数据库中插入数据、删除数据、更新数据和获取当前数据数量的接口。
63
64```ts
65// Store.ts
66import { distributedKVStore } from '@kit.ArkData';
67import { BusinessError } from '@kit.BasicServicesKit';
68
69let kvManager: distributedKVStore.KVManager;
70
71export class StoreInfo {
72  kvManagerConfig: distributedKVStore.KVManagerConfig;
73  storeId: string;
74  option: distributedKVStore.Options;
75}
76
77export class Store {
78  async getECStore(storeInfo: StoreInfo): Promise<distributedKVStore.SingleKVStore> {
79    try {
80      kvManager = distributedKVStore.createKVManager(storeInfo.kvManagerConfig);
81      console.info("Succeeded in creating KVManager");
82    } catch (e) {
83      let error = e as BusinessError;
84      console.error(`Failed to create KVManager.code is ${error.code},message is ${error.message}`);
85    }
86    if (kvManager !== undefined) {
87      kvManager = kvManager as distributedKVStore.KVManager;
88      let kvStore: distributedKVStore.SingleKVStore | null;
89      try {
90        kvStore = await kvManager.getKVStore<distributedKVStore.SingleKVStore>(storeInfo.storeId, storeInfo.option);
91        if (kvStore != undefined) {
92          console.info(`ECDB_Encry succeeded in getting store : ${storeInfo.storeId}`);
93          return kvStore;
94        }
95      } catch (e) {
96        let error = e as BusinessError;
97        console.error(`An unexpected error occurred.code is ${error.code},message is ${error.message}`);
98      }
99    }
100  }
101
102  putOnedata(kvStore: distributedKVStore.SingleKVStore): void {
103    if (kvStore != undefined) {
104      const KEY_TEST_STRING_ELEMENT = 'key_test_string' + String(Date.now());
105      const VALUE_TEST_STRING_ELEMENT = 'value_test_string' + String(Date.now());
106      try {
107        kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => {
108          if (err !== undefined) {
109            console.error(`Failed to put data. Code:${err.code},message:${err.message}`);
110            return;
111          }
112          console.info(`ECDB_Encry Succeeded in putting data.${KEY_TEST_STRING_ELEMENT}`);
113        });
114      } catch (e) {
115        let error = e as BusinessError;
116        console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
117      }
118    }
119  }
120
121  getDataNum(kvStore: distributedKVStore.SingleKVStore): void {
122    if (kvStore != undefined) {
123      let resultSet: distributedKVStore.KVStoreResultSet;
124      kvStore.getResultSet("key_test_string").then((result: distributedKVStore.KVStoreResultSet) => {
125        console.info(`ECDB_Encry Succeeded in getting result set num ${result.getCount()}`);
126        resultSet = result;
127        if (kvStore != null) {
128          kvStore.closeResultSet(resultSet).then(() => {
129            console.info('Succeeded in closing result set');
130          }).catch((err: BusinessError) => {
131            console.error(`Failed to close resultset.code is ${err.code},message is ${err.message}`);
132          });
133        }
134      }).catch((err: BusinessError) => {
135        console.error(`Failed to get resultset.code is ${err.code},message is ${err.message}`);
136      });
137    }
138  }
139
140  deleteOnedata(kvStore: distributedKVStore.SingleKVStore): void {
141    if (kvStore != undefined) {
142      kvStore.getEntries('key_test_string', (err: BusinessError, entries: distributedKVStore.Entry[]) => {
143        if (err != undefined) {
144          console.error(`Failed to get Entries.code is ${err.code},message is ${err.message}`);
145          return;
146        }
147        if (kvStore != null && entries.length != 0) {
148          kvStore.delete(entries[0].key, (err: BusinessError) => {
149            if (err != undefined) {
150              console.error(`Failed to delete.code is ${err.code},message is ${err.message}`);
151              return;
152            }
153            console.info('ECDB_Encry Succeeded in deleting');
154          });
155        }
156      });
157    }
158  }
159
160  updataOnedata(kvStore: distributedKVStore.SingleKVStore): void {
161    if (kvStore != undefined) {
162      kvStore.getEntries('key_test_string', async (err: BusinessError, entries: distributedKVStore.Entry[]) => {
163        if (err != undefined) {
164          console.error(`Failed to get Entries.code is ${err.code},message is ${err.message}`);
165          return;
166        }
167        if (kvStore != null && entries.length != 0) {
168          console.info(`ECDB_Encry old data:${entries[0].key},value :${entries[0].value.value.toString()}`)
169          await kvStore.put(entries[0].key, "new value_test_string" + String(Date.now()) + 'new').then(() => {
170          }).catch((err: BusinessError) => {
171            console.error(`Failed to put.code is ${err.code},message is ${err.message}`);
172          });
173        }
174        console.info(`ECDB_Encry updata success`)
175      });
176    }
177  }
178}
179```
180
181### SecretKeyObserver
182
183该类提供了获取当前密钥状态的接口,在密钥销毁后,关闭E类数据库。
184
185```ts
186// SecretKeyObserver.ts
187import { ECStoreManager } from './ECStoreManager';
188
189export enum SecretStatus {
190  Lock,
191  UnLock
192}
193
194export class SecretKeyObserver {
195  onLock(): void {
196    this.lockStatuas = SecretStatus.Lock;
197    this.storeManager.closeEStore();
198  }
199
200  onUnLock(): void {
201    this.lockStatuas = SecretStatus.UnLock;
202  }
203
204  getCurrentStatus(): number {
205    return this.lockStatuas;
206  }
207
208  initialize(storeManager: ECStoreManager): void {
209    this.storeManager = storeManager;
210  }
211
212  updatalockStatus(code: number) {
213    if (code === SecretStatus.Lock) {
214      this.onLock();
215    } else {
216      this.lockStatuas = code;
217    }
218  }
219
220  // 初始获取锁屏状态
221  private lockStatuas: number = SecretStatus.UnLock;
222  private storeManager: ECStoreManager;
223}
224
225export let lockObserve = new SecretKeyObserver();
226```
227
228### ECStoreManager
229
230ECStoreManager类用于管理应用的E类数据库和C类数据库。支持配置数据库信息、配置迁移函数的信息,可根据密钥状态为应用提供相应的数据库句柄,并提供了关闭E类数据库、数据迁移完成后销毁C类数据库等接口。
231
232```ts
233// ECStoreManager.ts
234import { distributedKVStore } from '@kit.ArkData';
235import { Mover } from './Mover';
236import { BusinessError } from '@kit.BasicServicesKit';
237import { StoreInfo, Store } from './Store';
238import { SecretStatus } from './SecretKeyObserver';
239
240let store = new Store();
241
242export class ECStoreManager {
243  config(cInfo: StoreInfo, other: StoreInfo): void {
244    this.cInfo = cInfo;
245    this.eInfo = other;
246  }
247
248  configDataMover(mover: Mover): void {
249    this.mover = mover;
250  }
251
252  async getCurrentStore(screanStatus: number): Promise<distributedKVStore.SingleKVStore> {
253    console.info(`ECDB_Encry GetCurrentStore start screanStatus: ${screanStatus}`);
254    if (screanStatus === SecretStatus.UnLock) {
255      try {
256        this.eStore = await store.getECStore(this.eInfo);
257      } catch (e) {
258        let error = e as BusinessError;
259        console.error(`Failed to GetECStore.code is ${error.code},message is ${error.message}`);
260      }
261      // 解锁状态 获取e类库
262      if (this.needMove) {
263        if (this.eStore != undefined && this.cStore != undefined) {
264          await this.mover.move(this.eStore, this.cStore);
265        }
266        this.deleteCStore();
267        console.info(`ECDB_Encry Data migration is complete. Destroy cstore`);
268        this.needMove = false;
269      }
270      return this.eStore;
271    } else {
272      // 加锁状态 获取c类库
273      this.needMove = true;
274      try {
275        this.cStore = await store.getECStore(this.cInfo);
276      } catch (e) {
277        let error = e as BusinessError;
278        console.error(`Failed to GetECStore.code is ${error.code},message is ${error.message}`);
279      }
280      return this.cStore;
281    }
282  }
283
284  closeEStore(): void {
285    try {
286      let kvManager = distributedKVStore.createKVManager(this.eInfo.kvManagerConfig);
287      console.info("Succeeded in creating KVManager");
288      if (kvManager != undefined) {
289        kvManager.closeKVStore(this.eInfo.kvManagerConfig.bundleName, this.eInfo.storeId);
290        this.eStore = null;
291        console.info(`ECDB_Encry close EStore success`)
292      }
293    } catch (e) {
294      let error = e as BusinessError;
295      console.error(`Failed to create KVManager.code is ${error.code},message is ${error.message}`);
296    }
297  }
298
299  deleteCStore(): void {
300    try {
301      let kvManager = distributedKVStore.createKVManager(this.cInfo.kvManagerConfig);
302      console.info("Succeeded in creating KVManager");
303      if (kvManager != undefined) {
304        kvManager.deleteKVStore(this.cInfo.kvManagerConfig.bundleName, this.cInfo.storeId);
305        this.cStore = null;
306        console.info("ECDB_Encry delete cStore success");
307      }
308    } catch (e) {
309      let error = e as BusinessError;
310      console.error(`Failed to create KVManager.code is ${error.code},message is ${error.message}`);
311    }
312  }
313
314  private eStore: distributedKVStore.SingleKVStore = null;
315  private cStore: distributedKVStore.SingleKVStore = null;
316  private cInfo: StoreInfo | null = null;
317  private eInfo: StoreInfo | null = null;
318  private needMove: boolean = false;
319  private mover: Mover | null = null;
320}
321```
322
323### EntryAbility
324
325模拟应用启动期间,注册对COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED公共事件的监听,并配置相应的数据库信息、密钥状态信息等。
326
327```ts
328// EntryAbility.ets
329import { AbilityConstant, contextConstant, UIAbility, Want } from '@kit.AbilityKit';
330import { hilog } from '@kit.PerformanceAnalysisKit';
331import { window } from '@kit.ArkUI';
332import { distributedKVStore } from '@kit.ArkData';
333import { ECStoreManager } from './ECStoreManager';
334import { StoreInfo } from './Store';
335import { Mover } from './Mover';
336import { SecretKeyObserver } from './SecretKeyObserver';
337import { commonEventManager } from '@kit.BasicServicesKit';
338import { BusinessError } from '@kit.BasicServicesKit';
339
340
341export let storeManager = new ECStoreManager();
342
343export let e_secretKeyObserver = new SecretKeyObserver();
344
345let mover = new Mover();
346
347let subscriber: commonEventManager.CommonEventSubscriber;
348
349export function createCB(err: BusinessError, commonEventSubscriber: commonEventManager.CommonEventSubscriber) {
350  if (!err) {
351    console.info('ECDB_Encry createSubscriber');
352    subscriber = commonEventSubscriber;
353    try {
354      commonEventManager.subscribe(subscriber, (err: BusinessError, data: commonEventManager.CommonEventData) => {
355        if (err) {
356          console.error(`subscribe failed, code is ${err.code}, message is ${err.message}`);
357        } else {
358          console.info(`ECDB_Encry SubscribeCB ${data.code}`);
359          e_secretKeyObserver.updatalockStatus(data.code);
360        }
361      });
362    } catch (error) {
363      const err: BusinessError = error as BusinessError;
364      console.error(`subscribe failed, code is ${err.code}, message is ${err.message}`);
365    }
366  } else {
367    console.error(`createSubscriber failed, code is ${err.code}, message is ${err.message}`);
368  }
369}
370
371let cInfo: StoreInfo | null = null;
372let eInfo: StoreInfo | null = null;
373
374export default class EntryAbility extends UIAbility {
375  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
376    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
377    let cContext = this.context;
378    cInfo = {
379      "kvManagerConfig": {
380        context: cContext,
381        bundleName: 'com.example.ecstoredemo',
382      },
383      "storeId": "cstore",
384      "option": {
385        createIfMissing: true,
386        encrypt: false,
387        backup: false,
388        autoSync: false,
389        // kvStoreType不填时,默认创建多设备协同数据库
390        kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
391        // 多设备协同数据库:kvStoreType: distributedKVStore.KVStoreType.DEVICE_COLLABORATION,
392        securityLevel: distributedKVStore.SecurityLevel.S3
393      }
394    }
395    let eContext = this.context.createModuleContext("entry");
396    eContext.area = contextConstant.AreaMode.EL5;
397    eInfo = {
398      "kvManagerConfig": {
399        context: eContext,
400        bundleName: 'com.example.ecstoredemo',
401      },
402      "storeId": "estore",
403      "option": {
404        createIfMissing: true,
405        encrypt: false,
406        backup: false,
407        autoSync: false,
408        // kvStoreType不填时,默认创建多设备协同数据库
409        kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
410        // 多设备协同数据库:kvStoreType: distributedKVStore.KVStoreType.DEVICE_COLLABORATION,
411        securityLevel: distributedKVStore.SecurityLevel.S3
412      }
413    }
414    console.info(`ECDB_Encry store area : estore:${eContext.area},cstore${cContext.area}`);
415    // 监听COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED事件 code == 1解锁状态,code==0加锁状态
416    try {
417      commonEventManager.createSubscriber({
418        events: ['COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED']
419      }, createCB);
420      console.info(`ECDB_Encry success subscribe`);
421    } catch (error) {
422      const err: BusinessError = error as BusinessError;
423      console.error(`createSubscriber failed, code is ${err.code}, message is ${err.message}`);
424    }
425    storeManager.config(cInfo, eInfo);
426    storeManager.configDataMover(mover);
427    e_secretKeyObserver.initialize(storeManager);
428  }
429
430  onDestroy(): void {
431    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
432  }
433
434  onWindowStageCreate(windowStage: window.WindowStage): void {
435    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
436
437    windowStage.loadContent('pages/Index', (err) => {
438      if (err.code) {
439        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
440        return;
441      }
442      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
443    });
444  }
445
446  onWindowStageDestroy(): void {
447    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
448  }
449
450  onForeground(): void {
451    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
452  }
453
454  onBackground(): void {
455    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
456  }
457}
458```
459
460### Index按键事件
461
462使用Button按钮,通过点击按钮来模拟应用操作数据库,如插入数据、删除数据、更新数据和获取数据数量的操作等,展示数据库基本的增删改查能力。
463
464```ts
465// Index.ets
466import { storeManager, e_secretKeyObserver } from "../entryability/EntryAbility";
467import { distributedKVStore } from '@kit.ArkData';
468import { Store } from '../entryability/Store';
469
470let storeOption = new Store();
471
472let lockStatus: number = 1;
473
474@Entry
475@Component
476struct Index {
477  @State message: string = 'Hello World';
478
479  build() {
480    Row() {
481      Column() {
482        Button('加锁/解锁').onClick((event: ClickEvent) => {
483          if (lockStatus) {
484            e_secretKeyObserver.onLock();
485            lockStatus = 0;
486          } else {
487            e_secretKeyObserver.onUnLock();
488            lockStatus = 1;
489          }
490          lockStatus ? this.message = "解锁" : this.message = "加锁";
491        }).margin("5");
492        Button('store type').onClick(async (event: ClickEvent) => {
493          e_secretKeyObserver.getCurrentStatus() ? this.message = "estroe" : this.message = "cstore";
494        }).margin("5");
495
496        Button("put").onClick(async (event: ClickEvent) => {
497          let store: distributedKVStore.SingleKVStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
498          storeOption.putOnedata(store);
499        }).margin(5)
500
501        Button("Get").onClick(async (event: ClickEvent) => {
502          let store: distributedKVStore.SingleKVStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
503          storeOption.getDataNum(store);
504        }).margin(5)
505
506        Button("delete").onClick(async (event: ClickEvent) => {
507          let store: distributedKVStore.SingleKVStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
508          storeOption.deleteOnedata(store);
509        }).margin(5)
510
511        Button("updata").onClick(async (event: ClickEvent) => {
512          let store: distributedKVStore.SingleKVStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
513          storeOption.updataOnedata(store);
514        }).margin(5)
515
516        Text(this.message)
517          .fontSize(50)
518          .fontWeight(FontWeight.Bold)
519      }
520      .width('100%')
521    }
522    .height('100%')
523  }
524}
525```
526
527## 关系型数据库E类加密
528
529本章节提供关系型数据库的E类加密数据库使用方式,提供[Mover](#mover-1)类,[Store](#store-1)类,[SecretKeyObserver](#secretkeyobserver-1)类和[ECStoreManager](#ecstoremanager-1)类的具体实现,并在[EntryAbility](#entryability-1)和[index按键事件](#index按键事件-1)中展示这几个类的使用方式。
530
531### Mover
532
533提供数据库数据迁移接口,在锁屏解锁后,若C类数据库中有数据,使用该接口将数据迁移到E类数据库。
534
535```ts
536// Mover.ts
537import { relationalStore } from '@kit.ArkData';
538
539export class Mover {
540  async move(eStore: relationalStore.RdbStore, cStore: relationalStore.RdbStore) {
541    if (eStore != null && cStore != null) {
542      let predicates = new relationalStore.RdbPredicates('employee');
543      let resultSet = await cStore.query(predicates);
544      while (resultSet.goToNextRow()) {
545        let bucket = resultSet.getRow();
546        await eStore.insert('employee', bucket);
547      }
548    }
549  }
550}
551```
552
553### Store
554
555提供了获取数据库,在数据库中插入数据、删除数据、更新数据和获取当前数据数量的接口。其中StoreInfo类用于存储获取数据库相关信息。
556
557```ts
558// Store.ts
559import { relationalStore } from '@kit.ArkData';
560import { BusinessError } from '@kit.BasicServicesKit';
561import { Context } from '@kit.AbilityKit';
562
563export class StoreInfo {
564  context: Context;
565  config: relationalStore.StoreConfig;
566  storeId: string;
567}
568
569let id = 1;
570const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB)';
571
572
573export class Store {
574  async getECStore(storeInfo: StoreInfo): Promise<relationalStore.RdbStore> {
575    let rdbStore: relationalStore.RdbStore | null;
576    try {
577      rdbStore = await relationalStore.getRdbStore(storeInfo.context, storeInfo.config);
578      if (rdbStore.version == 0) {
579        await rdbStore.executeSql(SQL_CREATE_TABLE);
580        console.info(`ECDB_Encry succeeded in getting Store :${storeInfo.storeId}`);
581        rdbStore.version = 1;
582      }
583    } catch (e) {
584      let error = e as BusinessError;
585      console.error(`An unexpected error occurred.code is ${error.code},message is ${error.message}`);
586    }
587    return rdbStore;
588  }
589
590  async putOnedata(rdbStore: relationalStore.RdbStore) {
591    if (rdbStore != undefined) {
592      const valueBucket: relationalStore.ValuesBucket = {
593        ID: id++,
594        NAME: 'Lisa',
595        AGE: 18,
596        SALARY: 100.5,
597        CODES: new Uint8Array([1, 2, 3, 4, 5]),
598      };
599      try {
600        await rdbStore.insert("EMPLOYEE", valueBucket);
601        console.info(`ECDB_Encry insert success`);
602      } catch (e) {
603        let error = e as BusinessError;
604        console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
605      }
606    }
607  }
608
609  async getDataNum(rdbStore: relationalStore.RdbStore) {
610    if (rdbStore != undefined) {
611      try {
612        let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
613        let resultSet = await rdbStore.query(predicates);
614        let count = resultSet.rowCount;
615        console.info(`ECDB_Encry getdatanum success count : ${count}`);
616      } catch (e) {
617        let error = e as BusinessError;
618        console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
619      }
620    }
621  }
622
623  async deleteAlldata(rdbStore: relationalStore.RdbStore) {
624    if (rdbStore != undefined) {
625      try {
626        let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
627        predicates.equalTo('AGE', 18);
628        await rdbStore.delete(predicates);
629        console.info(`ECDB_Encry delete Success`);
630      } catch (e) {
631        let error = e as BusinessError;
632        console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
633      }
634    }
635  }
636
637  async updataOnedata(rdbStore: relationalStore.RdbStore) {
638    if (rdbStore != undefined) {
639      try {
640        let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
641        predicates.equalTo('NAME', 'Lisa');
642        const valueBucket: relationalStore.ValuesBucket = {
643          NAME: 'Anna',
644          SALARY: 100.5,
645          CODES: new Uint8Array([1, 2, 3, 4, 5]),
646        };
647        await rdbStore.update(valueBucket, predicates);
648        console.info(`ECDB_Encry update success`);
649      } catch (e) {
650        let error = e as BusinessError;
651        console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
652      }
653    }
654  }
655}
656```
657
658### SecretKeyObserver
659
660该类提供了获取当前密钥状态的接口,在密钥销毁后,关闭E类数据库。
661
662```ts
663// SecretKeyObserver.ts
664import { ECStoreManager } from './ECStoreManager';
665
666export enum SecretStatus {
667  Lock,
668  UnLock
669}
670
671export class SecretKeyObserver {
672  onLock(): void {
673    this.lockStatuas = SecretStatus.Lock;
674    this.storeManager.closeEStore();
675  }
676
677  onUnLock(): void {
678    this.lockStatuas = SecretStatus.UnLock;
679  }
680
681  getCurrentStatus(): number {
682    return this.lockStatuas;
683  }
684
685  initialize(storeManager: ECStoreManager): void {
686    this.storeManager = storeManager;
687  }
688
689  updatalockStatus(code: number) {
690    if (this.lockStatuas === SecretStatus.Lock) {
691      this.onLock();
692    } else {
693      this.lockStatuas = code;
694    }
695  }
696
697  private lockStatuas: number = SecretStatus.UnLock;
698  private storeManager: ECStoreManager;
699}
700
701export let lockObserve = new SecretKeyObserver();
702```
703
704### ECStoreManager
705
706ECStoreManager类用于管理应用的E类数据库和C类数据库。支持配置数据库信息、配置迁移函数的信息,可根据密钥状态为应用提供相应的数据库句柄,并提供了关闭E类数据库、数据迁移完成后销毁C类数据库等接口。
707
708```ts
709// ECStoreManager.ts
710import { relationalStore } from '@kit.ArkData';
711import { Mover } from './Mover';
712import { BusinessError } from '@kit.BasicServicesKit';
713import { StoreInfo, Store } from './Store';
714import { SecretStatus } from './SecretKeyObserver';
715
716let store = new Store();
717
718export class ECStoreManager {
719  config(cInfo: StoreInfo, other: StoreInfo): void {
720    this.cInfo = cInfo;
721    this.eInfo = other;
722  }
723
724  configDataMover(mover: Mover): void {
725    this.mover = mover;
726  }
727
728  async getCurrentStore(screanStatus: number): Promise<relationalStore.RdbStore> {
729    if (screanStatus === SecretStatus.UnLock) {
730      try {
731        this.eStore = await store.getECStore(this.eInfo);
732      } catch (e) {
733        let error = e as BusinessError;
734        console.error(`Failed to GetECStore.code is ${error.code},message is ${error.message}`);
735      }
736      // 解锁状态 获取e类库
737      if (this.needMove) {
738        if (this.eStore != undefined && this.cStore != undefined) {
739          await this.mover.move(this.eStore, this.cStore);
740          console.info(`ECDB_Encry cstore data move to estore success`);
741        }
742        this.deleteCStore();
743        this.needMove = false;
744      }
745      return this.eStore;
746    } else {
747      // 加锁状态 获取c类库
748      this.needMove = true;
749      try {
750        this.cStore = await store.getECStore(this.cInfo);
751      } catch (e) {
752        let error = e as BusinessError;
753        console.error(`Failed to GetECStore.code is ${error.code},message is ${error.message}`);
754      }
755      return this.cStore;
756    }
757  }
758
759  closeEStore(): void {
760    this.eStore = undefined;
761  }
762
763  async deleteCStore() {
764    try {
765      await relationalStore.deleteRdbStore(this.cInfo.context, this.cInfo.storeId)
766    } catch (e) {
767      let error = e as BusinessError;
768      console.error(`Failed to create KVManager.code is ${error.code},message is ${error.message}`);
769    }
770  }
771
772  private eStore: relationalStore.RdbStore = null;
773  private cStore: relationalStore.RdbStore = null;
774  private cInfo: StoreInfo | null = null;
775  private eInfo: StoreInfo | null = null;
776  private needMove: boolean = false;
777  private mover: Mover | null = null;
778}
779```
780
781### EntryAbility
782
783模拟在应用启动期间,注册对COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED公共事件的监听,并配置相应的数据库信息、密钥状态信息等。
784
785```ts
786// EntryAbility.ets
787import { AbilityConstant, contextConstant, UIAbility, Want } from '@kit.AbilityKit';
788import { hilog } from '@kit.PerformanceAnalysisKit';
789import { window } from '@kit.ArkUI';
790import { relationalStore } from '@kit.ArkData';
791import { ECStoreManager } from './ECStoreManager';
792import { StoreInfo } from './Store';
793import { Mover } from './Mover';
794import { SecretKeyObserver } from './SecretKeyObserver';
795import { commonEventManager } from '@kit.BasicServicesKit';
796import { BusinessError } from '@kit.BasicServicesKit';
797
798
799export let storeManager = new ECStoreManager();
800
801export let e_secretKeyObserver = new SecretKeyObserver();
802
803let mover = new Mover();
804
805let subscriber: commonEventManager.CommonEventSubscriber;
806
807export function createCB(err: BusinessError, commonEventSubscriber: commonEventManager.CommonEventSubscriber) {
808  if (!err) {
809    console.info('ECDB_Encry createSubscriber');
810    subscriber = commonEventSubscriber;
811    try {
812      commonEventManager.subscribe(subscriber, (err: BusinessError, data: commonEventManager.CommonEventData) => {
813        if (err) {
814          console.error(`subscribe failed, code is ${err.code}, message is ${err.message}`);
815        } else {
816          console.info(`ECDB_Encry SubscribeCB ${data.code}`);
817          e_secretKeyObserver.updatalockStatus(data.code);
818        }
819      });
820    } catch (error) {
821      const err: BusinessError = error as BusinessError;
822      console.error(`subscribe failed, code is ${err.code}, message is ${err.message}`);
823    }
824  } else {
825    console.error(`createSubscriber failed, code is ${err.code}, message is ${err.message}`);
826  }
827}
828
829let cInfo: StoreInfo | null = null;
830let eInfo: StoreInfo | null = null;
831
832export default class EntryAbility extends UIAbility {
833  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
834    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
835    let cContext = this.context;
836    cInfo = {
837      context: cContext,
838      config: {
839        name: 'cstore.db',
840        securityLevel: relationalStore.SecurityLevel.S3,
841      },
842      storeId: "cstore.db"
843    }
844    let eContext = this.context.createModuleContext("entry");
845    eContext.area = contextConstant.AreaMode.EL5;
846    eInfo = {
847      context: eContext,
848      config: {
849        name: 'estore.db',
850        securityLevel: relationalStore.SecurityLevel.S3,
851      },
852      storeId: "estore.db",
853    }
854    // 监听COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED事件 code == 1解锁状态,code==0加锁状态
855    console.info(`ECDB_Encry store area : estore:${eContext.area},cstore${cContext.area}`)
856    try {
857      commonEventManager.createSubscriber({
858        events: ['COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED']
859      }, createCB);
860      console.info(`ECDB_Encry success subscribe`);
861    } catch (error) {
862      const err: BusinessError = error as BusinessError;
863      console.error(`createSubscriber failed, code is ${err.code}, message is ${err.message}`);
864    }
865    storeManager.config(cInfo, eInfo);
866    storeManager.configDataMover(mover);
867    e_secretKeyObserver.initialize(storeManager);
868  }
869
870  onDestroy(): void {
871    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
872  }
873
874  onWindowStageCreate(windowStage: window.WindowStage): void {
875    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
876
877    windowStage.loadContent('pages/Index', (err) => {
878      if (err.code) {
879        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
880        return;
881      }
882      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
883    });
884  }
885
886  onWindowStageDestroy(): void {
887    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
888  }
889
890  onForeground(): void {
891    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
892  }
893
894  onBackground(): void {
895    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
896  }
897}
898```
899
900### Index按键事件
901
902使用Button按钮,通过点击按钮来模拟应用操作数据库,如插入数据、删除数据、更新数据和获取数据数量的操作等,展示数据库基本的增删改查能力。
903
904```ts
905// Index.ets
906import { storeManager, e_secretKeyObserver } from "../entryability/EntryAbility";
907import { relationalStore } from '@kit.ArkData';
908import { Store } from '../entryability/Store';
909
910let storeOption = new Store();
911
912let lockStatus: number = 1;
913
914@Entry
915@Component
916struct Index {
917  @State message: string = 'Hello World';
918
919  build() {
920    Row() {
921      Column() {
922        Button('加锁/解锁').onClick((event: ClickEvent) => {
923          if (lockStatus) {
924            e_secretKeyObserver.onLock();
925            lockStatus = 0;
926          } else {
927            e_secretKeyObserver.onUnLock();
928            lockStatus = 1;
929          }
930          lockStatus ? this.message = "解锁" : this.message = "加锁";
931        }).margin("5");
932        Button('store type').onClick(async (event: ClickEvent) => {
933          e_secretKeyObserver.getCurrentStatus() ? this.message = "estroe" : this.message = "cstore";
934          console.info(`ECDB_Encry current store : ${this.message}`);
935        }).margin("5");
936
937        Button("put").onClick(async (event: ClickEvent) => {
938          let store: relationalStore.RdbStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
939          storeOption.putOnedata(store);
940        }).margin(5)
941
942        Button("Get").onClick(async (event: ClickEvent) => {
943          let store: relationalStore.RdbStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
944          storeOption.getDataNum(store);
945        }).margin(5)
946
947        Button("delete").onClick(async (event: ClickEvent) => {
948          let store: relationalStore.RdbStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
949          storeOption.deleteAlldata(store);
950        }).margin(5)
951
952        Button("updata").onClick(async (event: ClickEvent) => {
953          let store: relationalStore.RdbStore = await storeManager.getCurrentStore(e_secretKeyObserver.getCurrentStatus());
954          storeOption.updataOnedata(store);
955        }).margin(5)
956
957        Text(this.message)
958          .fontSize(50)
959          .fontWeight(FontWeight.Bold)
960      }
961      .width('100%')
962    }
963    .height('100%')
964  }
965}
966```
967