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