1# Using an EL5 Database 2 3 4## When to Use 5 6An [EL5](../reference/apis-ability-kit/js-apis-app-ability-contextConstant.md#contextconstantareamode) database is created in the **el5/** directory to store the application's sensitive information. When the screen is locked and certain conditions are met, the key used to encrypt the sensitive information will be destroyed and the database cannot be operated. After the screen is unlocked, the key is restored and the read and write operations on the database are restored. This mechanism can effectively protect the user data. For details about how to manage the encryption directories, see [Obtaining and Modifying Encrypted Levels](../application-models/application-context-stage.md#obtaining-and-modifying-encryption-levels). 7 8However, the application may write data when the screen is locked. Data loss will be caused if the EL5 database cannot be operated when data is written. A solution is provided to solve this problem. When the screen is locked, incremental data is stored in an [EL2](../reference/apis-ability-kit/js-apis-app-ability-contextConstant.md#contextconstantareamode) database. The data temporarily stored in the EL2 database will be moved to the EL5 database when the EL5 database is unlocked. This ensures data security and consistency when the screen is locked. 9 10Both the KV store and RDB store can be used as an EL5 database. 11 12## Working Principles 13 14The following classes are encapsulated to implement the data operations and transfer between the EL2 and EL5 databases: 15 16- **Mover** class: provides APIs for moving data from an EL2 database to an EL5 database after the screen is unlocked. 17 18- **Store** class: provides APIs for accessing and operating the currently operable database. 19 20- **SecretKeyObserver** class: provides APIs for obtaining the key status. After the key is destroyed, the EL5 database will be closed. 21 22- **ECStoreManager** class: provides APIs for managing the EL2 and EL5 databases. 23 24## Requesting Permissions 25 26To access the database in the **el5/** directory, the application must have the ohos.permission.PROTECT_SCREEN_LOCK_DATA permission. Add this permission in the **module.json5** file. 27 28```ts 29// module.json5 30"requestPermissions": [ 31 { 32 "name": "ohos.permission.PROTECT_SCREEN_LOCK_DATA" 33 } 34 ] 35``` 36 37## Using an EL5 KV Store 38 39The following describes how to use the [Mover](#mover), [Store](#store), [SecretKeyObserver](#secretkeyobserver), and [ECStoreManager](#ecstoremanager) classes to implement the use of a KV store in the **el5/** directory. In the following example, [EntryAbility](#entryability) and [index key event](#index-key-event) are used to present how to use these classes. 40 41### Mover 42 43Use **Mover** to move data from an EL2 database to an EL5 database after the screen is unlocked. 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 62Use the APIs provided by the **Store** class to obtain a database instance, add, delete, and update data, and obtain the data count in the database. 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 183Use the APIs provided by the **SecretKeyObserver** class to obtain the key status. After the key is destroyed, the EL5 database will be closed. 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 // Obtain the screen lock status. 221 private lockStatuas: number = SecretStatus.UnLock; 222 private storeManager: ECStoreManager; 223} 224 225export let lockObserve = new SecretKeyObserver(); 226``` 227 228### ECStoreManager 229 230Use the APIs provided by the **ECStoreManager** class to manage the EL2 and EL5 databases. Specifically, you can use the APIs to configure a database, set the function used to move data, provide the database handle for the application based on the key status, close an EL5 database, and destroy an El2 database after the data is moved. 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 // Obtain an EL5 database when the screen is unlocked. 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 // Obtain an EL2 database when the screen is locked. 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 325Register a listener for the COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED event when the simulated application starts, and configure the database information and key status information. 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 // If kvStoreType is left empty, a device KV store is created by default. 390 kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, 391 // kvStoreType is distributedKVStore.KVStoreType.DEVICE_COLLABORATION for a device KV store. 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 // If kvStoreType is left empty, a device KV store is created by default. 409 kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, 410 // kvStoreType is distributedKVStore.KVStoreType.DEVICE_COLLABORATION for a device KV store. 411 securityLevel: distributedKVStore.SecurityLevel.S3 412 } 413 } 414 console.info(`ECDB_Encry store area : estore:${eContext.area},cstore${cContext.area}`); 415 // Listen for the COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED event. code == 1 indicates the screen is unlocked, and code==0 indicates the screen is locked. 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 Key Event 461 462Use **Button** to simulate application operations on the database, such as inserting, deleting, updating, and obtaining the data count, by clicking the 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 ('Lock/Unlock').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 = "Unlocked": this.message = "Locked"; 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## Using an EL5 RDB Store 528 529The following describes how to use the [Mover](#mover-1), [Store](#store-1), [SecretKeyObserver](#secretkeyobserver-1), and [ECStoreManager](#ecstoremanager-1) classes to implement the use of an RDB store in the **el5/** directory. In the following example, [EntryAbility](#entryability-1) and [index key event](#index-key-event-1) are used to present how to use these classes. 530 531### Mover 532 533Use **Mover** to move data from an EL2 database to an EL5 database after the screen is unlocked. 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 555Use the APIs provided by the **Store** class to obtain a database instance, add, delete, and update data, and obtain the data count in the database. The **StoreInfo** class is used to store and obtain database information. 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 660Use the APIs provided by the **SecretKeyObserver** class to obtain the key status. After the key is destroyed, the EL5 database will be closed. 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 706Use the APIs provided by the **ECStoreManager** class to manage the EL2 and EL5 databases. Specifically, you can use the APIs to configure a database, set the function used to move data, provide the database handle for the application based on the key status, close an EL5 database, and destroy an El2 database after the data is moved. 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 // Obtain an EL5 database when the screen is unlocked. 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 // Obtain an EL2 database when the screen is locked. 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 783Register a listener for the COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED event when the simulated application starts, and configure the database information and key status information. 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 // Listen for the COMMON_EVENT_SCREEN_LOCK_FILE_ACCESS_STATE_CHANGED event. code == 1 indicates the screen is unlocked, and code==0 indicates the screen is locked. 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 Key Event 901 902Use **Button** to simulate application operations on the database, such as inserting, deleting, updating, and obtaining the data count, by clicking the 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 ('Lock/Unlock').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 = "Unlocked": this.message = "Locked"; 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