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