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