From ff86cc1bb518b8a8b1ff8f458d6919a28c8b9a32 Mon Sep 17 00:00:00 2001 From: htt1997 Date: Wed, 5 Jul 2023 10:20:35 +0800 Subject: [PATCH 1/2] fix Signed-off-by: htt1997 --- bin/update/updata.bat | 6 +- data_object/bundle.json | 8 +- ...uteddata_object_store_ipc_interface_code.h | 39 + .../innerkitsimpl/include/iobject_service.h | 6 +- .../innerkitsimpl/include/object_service.h | 9 +- .../src/adaptor/client_adaptor.cpp | 7 +- .../src/object_service_proxy.cpp | 15 +- data_object/interfaces/innerkits/BUILD.gn | 6 +- data_object/interfaces/jskits/BUILD.gn | 32 +- data_share/CODEOWNERS | 17 + data_share/bundle.json | 6 +- .../common/include/napi_callbacks_manager.h | 18 +- .../frameworks/js/napi/dataShare/BUILD.gn | 4 +- .../include/napi_subscriber_manager.h | 4 + .../observer/src/napi_subscriber_manager.cpp | 58 +- .../native/common/include/callbacks_manager.h | 24 +- ...ibuteddata_data_share_ipc_interface_code.h | 99 +++ .../common/include/idata_share_service.h | 23 +- .../native/common/include/idatashare.h | 19 +- .../common/include/ikvstore_data_service.h | 5 +- .../common/include/ishared_result_set.h | 32 +- .../common/include/ishared_result_set_stub.h | 4 +- .../common/src/ikvstore_data_service.cpp | 5 +- .../common/src/ishared_result_set_proxy.cpp | 14 +- .../common/src/ishared_result_set_stub.cpp | 4 +- .../controller/common/general_controller.h | 2 + .../provider/include/ext_special_controller.h | 2 - .../general_controller_porvider_impl.h | 1 + .../provider/src/ext_special_controller.cpp | 15 - .../src/general_controller_provider_impl.cpp | 15 + .../include/general_controller_service_impl.h | 2 + .../src/general_controller_service_impl.cpp | 10 + .../consumer/src/datashare_helper_impl.cpp | 6 +- .../native/consumer/src/datashare_proxy.cpp | 53 +- .../native/provider/src/datashare_stub.cpp | 33 +- .../provider/src/js_datashare_ext_ability.cpp | 5 +- .../proxy/include/data_share_service_proxy.h | 1 + .../published_data_subscriber_manager.h | 3 + .../proxy/include/rdb_subscriber_manager.h | 3 + .../proxy/src/data_share_service_proxy.cpp | 72 +- .../src/published_data_subscriber_manager.cpp | 58 +- .../proxy/src/rdb_subscriber_manager.cpp | 38 +- data_share/interfaces/inner_api/BUILD.gn | 6 +- .../interfaces/inner_api/common/BUILD.gn | 8 +- data_share/test/native/BUILD.gn | 6 +- datamgr_service/BUILD.gn | 3 + datamgr_service/bundle.json | 19 +- datamgr_service/datamgr_service.gni | 8 + .../distributeddataservice/adapter/BUILD.gn | 8 +- .../adapter/account/BUILD.gn | 2 +- .../adapter/account/test/BUILD.gn | 2 +- .../adapter/broadcaster/BUILD.gn | 3 +- .../adapter/communicator/BUILD.gn | 2 +- .../adapter/communicator/test/BUILD.gn | 4 +- .../communicator/test/fuzztest/BUILD.gn | 21 + .../fuzztest/softbusadapter_fuzzer/BUILD.gn | 68 ++ .../softbusadapter_fuzzer/corpus/init | 16 + .../softbusadapter_fuzzer/project.xml | 25 + .../softbusadapter_fuzzer.cpp | 47 + .../softbusadapter_fuzzer.h | 21 + .../adapter/dfx/BUILD.gn | 8 +- .../adapter/dfx/test/BUILD.gn | 12 +- .../adapter/permission/BUILD.gn | 2 +- .../adapter/permission/test/BUILD.gn | 2 +- .../adapter/test/BUILD.gn | 6 + .../adapter/utils/BUILD.gn | 2 +- .../distributeddataservice/app/BUILD.gn | 8 +- .../distributeddataservice/app/CMakeLists.txt | 1 - .../app/src/checker/BUILD.gn | 2 +- .../app/src/uninstaller/BUILD.gn | 6 +- .../distributeddataservice/app/test/BUILD.gn | 12 +- .../app/test/fuzztest/BUILD.gn | 21 + .../fuzztest/dataservicestub_fuzzer/BUILD.gn | 116 +++ .../dataservicestub_fuzzer/corpus/init | 16 + .../dataservicestub_fuzzer.cpp | 57 ++ .../dataservicestub_fuzzer.h | 21 + .../dataservicestub_fuzzer/project.xml | 25 + .../distributeddataservice/framework/BUILD.gn | 2 +- .../framework/cloud/sync_event.cpp | 10 +- .../framework/include/cloud/sync_event.h | 4 +- .../framework/include/store/general_store.h | 8 + .../framework/include/store/general_value.h | 8 +- .../framework/include/store/general_watcher.h | 8 +- .../framework/test/BUILD.gn | 6 +- .../distributeddataservice/service/BUILD.gn | 6 +- .../service/CMakeLists.txt | 3 +- .../service/cloud/cloud_service_impl.cpp | 75 +- .../service/cloud/cloud_service_impl.h | 1 + .../service/cloud/sync_manager.cpp | 165 ++-- .../service/cloud/sync_manager.h | 26 +- .../service/data_share/BUILD.gn | 3 +- .../service/data_share/common/kv_delegate.cpp | 4 +- .../data_share/data/published_data.cpp | 52 +- .../service/data_share/data/published_data.h | 3 + .../data_share/data_share_service_impl.cpp | 61 +- .../data_share/data_share_service_impl.h | 3 + .../data_share/data_share_service_stub.cpp | 11 + .../data_share/data_share_service_stub.h | 4 +- .../service/data_share/gaussdb_rd/BUILD.gn | 6 +- .../src/executor/document/check_common.cpp | 50 +- .../src/executor/document/check_common.h | 2 +- .../src/interface/src/document_store.cpp | 15 +- .../src/interface/src/projection_tree.cpp | 6 +- .../src/interface/src/result_set.cpp | 27 +- .../src/oh_adapter/include/json_object.h | 4 +- .../src/oh_adapter/src/json_object.cpp | 54 +- .../gaussdb_rd/test/unittest/BUILD.gn | 12 +- .../unittest/api/documentdb_find_test.cpp | 38 + .../documentdb_json_common_test.cpp | 19 - .../service/data_share/idata_share_service.h | 2 + .../strategies/rdb_notify_strategy.cpp | 65 ++ .../strategies/rdb_notify_strategy.h | 34 + .../strategies/subscribe_strategy.cpp | 2 +- .../strategies/subscribe_strategy.h | 2 +- .../published_data_subscriber_manager.cpp | 13 + .../published_data_subscriber_manager.h | 2 +- .../rdb_subscriber_manager.cpp | 4 + .../service/kvdb/kvdb_service_stub.cpp | 9 +- .../service/kvdb/kvdb_service_stub.h | 3 +- .../service/object/object_service_stub.cpp | 2 +- .../service/object/object_service_stub.h | 4 +- .../service/rdb/rdb_asset_loader.cpp | 4 +- .../service/rdb/rdb_general_store.cpp | 40 +- .../service/rdb/rdb_general_store.h | 1 + .../service/rdb/rdb_notifier_proxy.cpp | 8 +- .../service/rdb/rdb_service_stub.cpp | 2 +- .../service/rdb/rdb_service_stub.h | 24 +- .../service/rdb/rdb_syncer.cpp | 8 +- .../service/rdb/rdb_watcher.cpp | 1 + .../service/rdb/value_proxy.cpp | 30 +- .../service/rdb/value_proxy.h | 2 +- .../service/test/BUILD.gn | 12 +- .../service/test/config_factory_test.cpp | 2 +- .../service/test/fuzztest/BUILD.gn | 32 + .../fuzztest/cloudservicestub_fuzzer/BUILD.gn | 113 +++ .../cloudservicestub_fuzzer.cpp | 56 ++ .../cloudservicestub_fuzzer.h | 21 + .../cloudservicestub_fuzzer/corpus/init | 16 + .../cloudservicestub_fuzzer/project.xml | 25 + .../datashareservicestub_fuzzer/BUILD.gn | 124 +++ .../datashareservicestub_fuzzer/corpus/init | 16 + .../datashareservicestub_fuzzer.cpp | 56 ++ .../datashareservicestub_fuzzer.h | 21 + .../datashareservicestub_fuzzer/project.xml | 25 + .../fuzztest/kvdbservicestub_fuzzer/BUILD.gn | 110 +++ .../kvdbservicestub_fuzzer/corpus/init | 16 + .../kvdbservicestub_fuzzer.cpp | 56 ++ .../kvdbservicestub_fuzzer.h | 21 + .../kvdbservicestub_fuzzer/project.xml | 25 + .../objectservicestub_fuzzer/BUILD.gn | 110 +++ .../objectservicestub_fuzzer/corpus/init | 16 + .../objectservicestub_fuzzer.cpp | 56 ++ .../objectservicestub_fuzzer.h | 21 + .../objectservicestub_fuzzer/project.xml | 25 + .../fuzztest/rdbresultsetstub_fuzzer/BUILD.gn | 123 +++ .../rdbresultsetstub_fuzzer/corpus/init | 16 + .../rdbresultsetstub_fuzzer/project.xml | 25 + .../rdbresultsetstub_fuzzer.cpp | 58 ++ .../rdbresultsetstub_fuzzer.h | 21 + .../fuzztest/rdbservicestub_fuzzer/BUILD.gn | 111 +++ .../rdbservicestub_fuzzer/corpus/init | 16 + .../rdbservicestub_fuzzer/project.xml | 25 + .../rdbservicestub_fuzzer.cpp | 56 ++ .../rdbservicestub_fuzzer.h | 21 + .../test/fuzztest/udmfservice_fuzzer/BUILD.gn | 71 ++ .../fuzztest/udmfservice_fuzzer/corpus/init | 16 + .../fuzztest/udmfservice_fuzzer/project.xml | 25 + .../udmfservice_fuzzer/udmfservice_fuzzer.cpp | 54 ++ .../udmfservice_fuzzer/udmfservice_fuzzer.h | 21 + .../service/udmf/BUILD.gn | 6 +- .../service/udmf/data_manager.cpp | 22 +- .../service/udmf/data_manager.h | 5 +- .../udmf/lifecycle/lifecycle_policy.cpp | 2 +- .../service/udmf/lifecycle/lifecycle_policy.h | 7 +- .../udmf/preprocess/preprocess_utils.cpp | 16 +- .../udmf/preprocess/preprocess_utils.h | 15 +- .../service/udmf/store/runtime_store.cpp | 10 + .../service/udmf/store/store.h | 19 + .../{store_cache1.cpp => store_cache.cpp} | 33 +- .../store/{store_cache1.h => store_cache.h} | 11 +- .../service/udmf/udmf_service_stub.cpp | 32 +- .../service/udmf/udmf_service_stub.h | 16 +- .../test/fuzztest/schemaquery_fuzzer/BUILD.gn | 2 +- .../test/fuzztest/autolaunch_fuzzer/BUILD.gn | 2 +- .../fuzztest/kvstoredisksize_fuzzer/BUILD.gn | 2 +- kv_store/bundle.json | 14 +- .../common/test/executor_pool_test.cpp | 3 +- .../frameworks/common/test/traits_test.cpp | 4 +- .../distributeddata_ipc_interface_code.h | 29 + .../include/ikvstore_data_service.h | 37 +- .../src/ikvstore_data_service.cpp | 18 +- .../distributeddatafwk/test/BUILD.gn | 22 +- .../distributeddata_kvdb_ipc_interface_code.h | 45 + .../innerkitsimpl/kvdb/include/kvdb_service.h | 23 - .../kvdb/src/kvdb_service_client.cpp | 53 +- .../innerkitsimpl/kvdb/src/store_factory.cpp | 3 + .../innerkitsimpl/kvdb/test/BUILD.gn | 18 +- .../src/js_single_kv_store.cpp | 1 - .../frameworks/libs/distributeddb/BUILD.gn | 7 +- .../common/include/cloud/cloud_db_constant.h | 1 - .../distributeddb/common/include/db_errno.h | 5 + .../src/communicator_aggregator.cpp | 2 + .../relational/relational_store_manager.h | 4 + .../interfaces/include/store_types.h | 5 + .../interfaces/src/kv_store_errno.cpp | 5 + .../relational_store_delegate_impl.cpp | 2 - .../relational/relational_store_manager.cpp | 45 + .../relational/relational_sync_able_storage.h | 2 +- .../include/cloud/cloud_storage_utils.h | 14 +- .../include/icloud_sync_storage_interface.h | 4 +- .../storage/include/isync_interface.h | 2 + .../storage/include/storage_proxy.h | 4 +- .../storage/include/sync_generic_interface.h | 5 + .../storage/src/cloud/cloud_meta_data.cpp | 2 + .../storage/src/cloud/cloud_storage_utils.cpp | 141 ++- .../src/relational_sync_able_storage.cpp | 23 +- .../relational/sqlite_relational_store.cpp | 10 +- .../src/sqlite/sqlite_log_table_manager.cpp | 4 +- .../sqlite_single_ver_natural_store.cpp | 15 +- .../sqlite/sqlite_single_ver_natural_store.h | 2 + ...single_ver_relational_storage_executor.cpp | 135 +-- ...e_single_ver_relational_storage_executor.h | 24 +- ...ver_relational_storage_extend_executor.cpp | 100 ++- .../storage/src/storage_proxy.cpp | 10 +- .../syncer/src/cloud/cloud_db_proxy.cpp | 33 +- .../syncer/src/cloud/cloud_db_proxy.h | 2 + .../src/cloud/cloud_force_pull_strategy.cpp | 9 +- .../src/cloud/cloud_force_pull_strategy.h | 8 +- .../src/cloud/cloud_force_push_strategy.cpp | 11 +- .../src/cloud/cloud_force_push_strategy.h | 8 +- .../syncer/src/cloud/cloud_merge_strategy.cpp | 15 +- .../syncer/src/cloud/cloud_sync_strategy.h | 2 +- .../syncer/src/cloud/cloud_syncer.cpp | 811 ++++++++++------- .../syncer/src/cloud/cloud_syncer.h | 99 ++- .../syncer/src/cloud/strategy_factory.cpp | 2 - .../syncer/src/generic_syncer.cpp | 4 +- .../libs/distributeddb/syncer/src/meta_data.h | 2 +- .../syncer/src/remote_executor.cpp | 4 + .../syncer/src/single_ver_data_sync.cpp | 2 +- .../syncer/src/single_ver_sync_engine.cpp | 5 + .../src/single_ver_sync_state_machine.cpp | 7 +- .../distributeddb/syncer/src/sync_engine.cpp | 8 +- .../syncer/src/sync_task_context.cpp | 1 + .../libs/distributeddb/test/BUILD.gn | 12 +- .../test/fuzztest/delegate_fuzzer/BUILD.gn | 2 +- .../test/fuzztest/fileoper_fuzzer/BUILD.gn | 2 +- .../test/fuzztest/importfile_fuzzer/BUILD.gn | 2 +- .../iprocesscommunicator_fuzzer/BUILD.gn | 2 +- .../kvdelegatemanager_fuzzer/BUILD.gn | 2 +- .../fuzztest/kvstoreresultset_fuzzer/BUILD.gn | 2 +- .../test/fuzztest/nbdelegate_fuzzer/BUILD.gn | 2 +- .../test/fuzztest/parseckeck_fuzzer/BUILD.gn | 2 +- .../test/fuzztest/query_fuzzer/BUILD.gn | 2 +- .../test/fuzztest/rekey_fuzzer/BUILD.gn | 2 +- .../relationalstoredelegate_fuzzer/BUILD.gn | 2 +- .../relationalstoremanager_fuzzer/BUILD.gn | 2 +- .../fuzztest/schemadelegate_fuzzer/BUILD.gn | 2 +- .../test/fuzztest/sync_fuzzer/BUILD.gn | 2 +- .../distributeddb/test/moduletest/BUILD.gn | 50 +- ..._cloud_interfaces_relational_sync_test.cpp | 835 ++++++++++++++---- .../distributeddb_cloud_meta_data_test.cpp | 2 +- ...stributeddb_cloud_save_cloud_data_test.cpp | 250 +++++- ...relational_cloud_syncable_storage_test.cpp | 130 ++- .../common/syncer/cloud/cloud_syncer_test.h | 11 +- ...distributeddb_cloud_asset_compare_test.cpp | 249 +++++- .../distributeddb_cloud_db_proxy_test.cpp | 143 +++ .../distributeddb_cloud_strategy_test.cpp | 53 +- ...stributeddb_cloud_syncer_download_test.cpp | 4 +- ...distributeddb_cloud_syncer_upload_test.cpp | 483 +++++----- .../mock_icloud_sync_storage_interface.h | 2 +- .../common/syncer/cloud/virtual_cloud_db.cpp | 64 +- .../common/syncer/cloud/virtual_cloud_db.h | 14 + .../syncer/cloud/virtual_cloud_syncer.cpp | 6 + .../syncer/cloud/virtual_cloud_syncer.h | 2 + .../distributeddb_mock_sync_module_test.cpp | 109 ++- ...ributeddb_relational_ver_p2p_sync_test.cpp | 20 + ...uteddb_single_ver_p2p_simple_sync_test.cpp | 3 + .../unittest/common/syncer/mock_meta_data.h | 2 + .../common/syncer/mock_single_ver_data_sync.h | 10 + .../common/syncer/mock_single_ver_kv_syncer.h | 7 + .../syncer/mock_single_ver_state_machine.h | 10 + .../innerkits/distributeddata/BUILD.gn | 8 +- .../jskits/distributeddata/BUILD.gn | 2 +- .../jskits/distributedkvstore/BUILD.gn | 2 +- .../single_kvstore_client/BUILD.gn | 16 +- kv_store/test/fuzztest/blob_fuzzer/BUILD.gn | 2 +- .../fuzztest/devicekvstore_fuzzer/BUILD.gn | 2 +- .../distributedkvdatamanager_fuzzer/BUILD.gn | 2 +- .../fuzztest/singlekvstore_fuzzer/BUILD.gn | 2 +- .../test/fuzztest/typesutil_fuzzer/BUILD.gn | 2 +- mock/napi/native_common.h | 2 +- mock/napi/src/js_native_api.h | 3 + mock/src/mock_js_napi.cpp | 1 + relational_store/CMakeLists.txt | 10 +- relational_store/bundle.json | 5 +- .../frameworks/js/napi/cloud_data/BUILD.gn | 5 +- .../js/napi/common/include/js_utils.h | 37 + .../js/napi/common/include/js_uv_queue.h | 63 ++ .../js/napi/common/src/js_uv_queue.cpp | 96 ++ .../frameworks/js/napi/dataability/BUILD.gn | 2 +- .../frameworks/js/napi/rdb/BUILD.gn | 8 +- .../js/napi/rdb/include/napi_rdb_error.h | 2 - .../js/napi/relationalstore/BUILD.gn | 5 +- .../relationalstore/include/napi_async_call.h | 1 + .../relationalstore/include/napi_rdb_error.h | 1 + .../include/napi_rdb_js_utils.h | 6 + .../relationalstore/include/napi_rdb_store.h | 3 + .../relationalstore/src/napi_async_call.cpp | 19 + .../relationalstore/src/napi_rdb_js_utils.cpp | 29 + .../relationalstore/src/napi_rdb_store.cpp | 83 +- .../relationalstore/src/napi_result_set.cpp | 8 + .../native/appdatafwk/src/general_endian.cpp | 39 + .../cloud_data/include/icloud_service.h | 3 +- .../native/cloud_data/src/cloud_manager.cpp | 4 +- .../src/ishared_result_set_proxy.cpp | 12 +- .../src/ishared_result_set_stub.cpp | 4 +- .../dataability/src/ishared_result_set_stub.h | 4 +- .../native/rdb/include/irdb_service.h | 7 +- .../native/rdb/include/rdb_notifier_stub.h | 8 +- .../native/rdb/include/rdb_store_impl.h | 7 + .../native/rdb/include/sqlite_connection.h | 2 + .../native/rdb/include/step_result_set.h | 3 + .../native/rdb/mock/include/rdb_store_impl.h | 1 + .../rdb/mock/include/sqlite_connection.h | 5 +- .../native/rdb/mock/include/step_result_set.h | 3 + .../native/rdb/src/abs_shared_result_set.cpp | 52 +- .../native/rdb/src/rdb_manager_impl.cpp | 7 +- .../native/rdb/src/rdb_notifier_stub.cpp | 2 +- .../native/rdb/src/rdb_service_proxy.cpp | 24 +- .../native/rdb/src/rdb_store_impl.cpp | 107 ++- .../native/rdb/src/rdb_types_util.cpp | 5 +- .../native/rdb/src/sqlite_connection.cpp | 24 +- .../native/rdb/src/step_result_set.cpp | 14 +- .../interfaces/inner_api/appdatafwk/BUILD.gn | 2 +- .../interfaces/inner_api/dataability/BUILD.gn | 2 +- .../dataability/include/ishared_result_set.h | 34 +- .../interfaces/inner_api/rdb/BUILD.gn | 8 +- ...data_relational_store_ipc_interface_code.h | 83 ++ .../inner_api/rdb/include/rdb_errno.h | 5 + .../inner_api/rdb/include/rdb_notifier.h | 6 +- .../inner_api/rdb/include/rdb_service.h | 14 +- .../inner_api/rdb/include/rdb_store.h | 26 + .../inner_api/rdb/include/rdb_types.h | 20 +- .../inner_api/rdb/mock/include/rdb_store.h | 4 +- .../inner_api/rdb_bms_adapter/BUILD.gn | 2 +- .../rdb_bms_adapter/include/data_properties.h | 1 - .../inner_api/rdb_data_share_adapter/BUILD.gn | 2 +- relational_store/interfaces/ndk/BUILD.gn | 14 +- .../unittest/src/CloudSyncConfigCallback.js | 2 +- .../unittest/src/CloudSyncConfigPromise.js | 2 +- .../src/RdbstoreStoreExcuteSqlJsunit.test.js | 2 +- .../src/RdbstoreTransactionJsunit.test.js | 2 +- .../src/RdbStoreAssetResultSetJsunit.test.js | 33 +- .../src/RdbstoreStoreExcuteSqlJsunit.test.js | 2 +- .../src/RdbstoreTransactionJsunit.test.js | 2 +- .../unittest/src/RdbstoreUpdateJsunit.test.js | 2 +- .../test/native/dataability/BUILD.gn | 2 +- relational_store/test/native/rdb/BUILD.gn | 2 +- .../rdb_store_impl_test/BUILD.gn | 4 +- .../rdb/fuzztest/rdbimpl_fuzzer/BUILD.gn | 2 +- .../rdb/fuzztest/rdbstore_fuzzer/BUILD.gn | 2 +- .../native/rdb_data_ability_adapter/BUILD.gn | 2 +- .../native/rdb_data_share_adapter/BUILD.gn | 2 +- relational_store/test/ndk/BUILD.gn | 16 +- test/CMakeLists.txt | 2 +- test/include/CMakeLists.txt | 1 + udmf | 1 - 367 files changed, 7537 insertions(+), 2069 deletions(-) create mode 100644 data_object/frameworks/innerkitsimpl/include/distributeddata_object_store_ipc_interface_code.h create mode 100644 data_share/CODEOWNERS create mode 100644 data_share/frameworks/native/common/include/distributeddata_data_share_ipc_interface_code.h create mode 100644 datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/corpus/init create mode 100644 datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/project.xml create mode 100644 datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/softbusadapter_fuzzer.cpp create mode 100644 datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/softbusadapter_fuzzer.h create mode 100644 datamgr_service/services/distributeddataservice/app/test/fuzztest/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/corpus/init create mode 100644 datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/dataservicestub_fuzzer.cpp create mode 100644 datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/dataservicestub_fuzzer.h create mode 100644 datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/project.xml create mode 100644 datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.cpp create mode 100644 datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.h create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/cloudservicestub_fuzzer.cpp create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/cloudservicestub_fuzzer.h create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/corpus/init create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/project.xml create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/corpus/init create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/datashareservicestub_fuzzer.cpp create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/datashareservicestub_fuzzer.h create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/project.xml create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/corpus/init create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/kvdbservicestub_fuzzer.cpp create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/kvdbservicestub_fuzzer.h create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/project.xml create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/corpus/init create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/objectservicestub_fuzzer.cpp create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/objectservicestub_fuzzer.h create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/project.xml create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/corpus/init create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/project.xml create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/rdbresultsetstub_fuzzer.cpp create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/rdbresultsetstub_fuzzer.h create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/corpus/init create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/project.xml create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/rdbservicestub_fuzzer.cpp create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/rdbservicestub_fuzzer.h create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/BUILD.gn create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/corpus/init create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/project.xml create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/udmfservice_fuzzer.cpp create mode 100644 datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/udmfservice_fuzzer.h rename datamgr_service/services/distributeddataservice/service/udmf/store/{store_cache1.cpp => store_cache.cpp} (55%) rename datamgr_service/services/distributeddataservice/service/udmf/store/{store_cache1.h => store_cache.h} (77%) create mode 100644 kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/distributeddata_ipc_interface_code.h create mode 100644 kv_store/frameworks/innerkitsimpl/kvdb/include/distributeddata_kvdb_ipc_interface_code.h create mode 100644 relational_store/frameworks/js/napi/common/include/js_uv_queue.h create mode 100644 relational_store/frameworks/js/napi/common/src/js_uv_queue.cpp create mode 100644 relational_store/frameworks/native/appdatafwk/src/general_endian.cpp create mode 100644 relational_store/interfaces/inner_api/rdb/include/distributeddata_relational_store_ipc_interface_code.h delete mode 160000 udmf diff --git a/bin/update/updata.bat b/bin/update/updata.bat index 53dc71cf..364878b0 100644 --- a/bin/update/updata.bat +++ b/bin/update/updata.bat @@ -7,9 +7,9 @@ cls @echo %date%-%time% mkdir tmp @echo "clone the datamgr_service" -git clone https://gitee.com/ding_dong_dong/distributeddatamgr_datamgr_service.git ./tmp/datamgr_service +git clone https://gitee.com/openharmony/distributeddatamgr_datamgr_service.git ./tmp/datamgr_service @echo "clone the kv_store" -git clone https://gitee.com/ding_dong_dong/distributeddatamgr_kv_store.git ./tmp/kv_store +git clone https://gitee.com/openharmony/distributeddatamgr_kv_store.git ./tmp/kv_store @echo "clone the relational_store" git clone https://gitee.com/openharmony/distributeddatamgr_relational_store.git ./tmp/relational_store @echo "clone the data_object" @@ -19,7 +19,7 @@ git clone https://gitee.com/openharmony/distributeddatamgr_data_share.git ./tmp/ @echo "clone the preferences" git clone https://gitee.com/openharmony/distributeddatamgr_preferences.git ./tmp/preferences @echo "clone the udmf" -git clone https://gitee.com/ding_dong_dong/distributeddatamgr_udmf.git ./tmp/udmf +git clone https://gitee.com/openharmony/distributeddatamgr_udmf.git ./tmp/udmf xcopy tmp\* ..\..\ /y /e /i /q rd /s /q tmp @echo "FINISHED" diff --git a/data_object/bundle.json b/data_object/bundle.json index 0112f2eb..1c67d441 100644 --- a/data_object/bundle.json +++ b/data_object/bundle.json @@ -44,17 +44,13 @@ "ram": "1024KB", "deps": { "components": [ - "ability_base", "ability_runtime", - "hitrace_native", + "hitrace", "dsoftbus", - "distributeddatamgr", "napi", - "common", "samgr", "ipc", - "hiviewdfx_hilog_native", - "utils_base", + "hilog", "access_token", "c_utils", "device_manager", diff --git a/data_object/frameworks/innerkitsimpl/include/distributeddata_object_store_ipc_interface_code.h b/data_object/frameworks/innerkitsimpl/include/distributeddata_object_store_ipc_interface_code.h new file mode 100644 index 00000000..143334b7 --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/include/distributeddata_object_store_ipc_interface_code.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* SAID:1301 */ +/* FeatureSystem: object_service */ +#ifndef DISTRIBUTEDDATA_OBJECT_STORE_IPC_INTERFACE_H +#define DISTRIBUTEDDATA_OBJECT_STORE_IPC_INTERFACE_H + +namespace OHOS::DistributedObject { +namespace ObjectStoreService { +enum class ObjectServiceInterfaceCode { + OBJECTSTORE_SAVE, + OBJECTSTORE_REVOKE_SAVE, + OBJECTSTORE_RETRIEVE, + OBJECTSTORE_REGISTER_OBSERVER, + OBJECTSTORE_UNREGISTER_OBSERVER, + OBJECTSTORE_SERVICE_CMD_MAX +}; + +enum class KvStoreServiceInterfaceCode { + GET_FEATURE_INTERFACE = 0, + REGISTERCLIENTDEATHOBSERVER, +}; +} +} // namespace OHOS + +#endif // DISTRIBUTEDDATA_OBJECT_STORE_IPC_INTERFACE_H \ No newline at end of file diff --git a/data_object/frameworks/innerkitsimpl/include/iobject_service.h b/data_object/frameworks/innerkitsimpl/include/iobject_service.h index 85195a71..1bc58610 100644 --- a/data_object/frameworks/innerkitsimpl/include/iobject_service.h +++ b/data_object/frameworks/innerkitsimpl/include/iobject_service.h @@ -20,6 +20,7 @@ #include #include "object_service.h" +#include "distributeddata_object_store_ipc_interface_code.h" namespace OHOS::DistributedObject { class IObjectService : public ObjectService, public IRemoteBroker { @@ -29,11 +30,6 @@ public: class IKvStoreDataService : public IRemoteBroker { public: - enum { - GET_FEATURE_INTERFACE = 0, - REGISTERCLIENTDEATHOBSERVER, - }; - DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.DistributedKv.IKvStoreDataService"); virtual sptr GetFeatureInterface(const std::string &name) = 0; diff --git a/data_object/frameworks/innerkitsimpl/include/object_service.h b/data_object/frameworks/innerkitsimpl/include/object_service.h index 6c8dbdb4..2e49a85f 100644 --- a/data_object/frameworks/innerkitsimpl/include/object_service.h +++ b/data_object/frameworks/innerkitsimpl/include/object_service.h @@ -19,18 +19,11 @@ #include #include #include +#include "distributeddata_object_store_ipc_interface_code.h" namespace OHOS::DistributedObject { class ObjectService { public: - enum { - OBJECTSTORE_SAVE, - OBJECTSTORE_REVOKE_SAVE, - OBJECTSTORE_RETRIEVE, - OBJECTSTORE_REGISTER_OBSERVER, - OBJECTSTORE_UNREGISTER_OBSERVER, - OBJECTSTORE_SERVICE_CMD_MAX - }; virtual int32_t ObjectStoreSave(const std::string &bundleName, const std::string &sessionId, const std::string &deviceId, const std::map> &data, sptr callback) = 0; diff --git a/data_object/frameworks/innerkitsimpl/src/adaptor/client_adaptor.cpp b/data_object/frameworks/innerkitsimpl/src/adaptor/client_adaptor.cpp index 1f16cc24..f47e6eda 100644 --- a/data_object/frameworks/innerkitsimpl/src/adaptor/client_adaptor.cpp +++ b/data_object/frameworks/innerkitsimpl/src/adaptor/client_adaptor.cpp @@ -25,6 +25,8 @@ namespace OHOS::ObjectStore { std::shared_ptr ClientAdaptor::distributedDataMgr_ = nullptr; +using KvStoreCode = OHOS::DistributedObject::ObjectStoreService::KvStoreServiceInterfaceCode; + sptr ClientAdaptor::GetObjectService() { if (distributedDataMgr_ == nullptr) { @@ -110,7 +112,7 @@ sptr ObjectStoreDataServiceProxy::GetFeatureInterface(const std:: MessageParcel reply; MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(GET_FEATURE_INTERFACE, data, reply, mo); + int32_t error = Remote()->SendRequest(static_cast(KvStoreCode::GET_FEATURE_INTERFACE), data, reply, mo); if (error != 0) { LOG_ERROR("SendRequest returned %{public}d", error); return nullptr; @@ -142,7 +144,8 @@ uint32_t ObjectStoreDataServiceProxy::RegisterClientDeathObserver( } MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(REGISTERCLIENTDEATHOBSERVER, data, reply, mo); + int32_t error = Remote()->SendRequest( + static_cast(KvStoreCode::REGISTERCLIENTDEATHOBSERVER), data, reply, mo); if (error != 0) { LOG_WARN("failed during IPC. errCode %d", error); return ERR_IPC; diff --git a/data_object/frameworks/innerkitsimpl/src/object_service_proxy.cpp b/data_object/frameworks/innerkitsimpl/src/object_service_proxy.cpp index 42bff35a..8d23a238 100644 --- a/data_object/frameworks/innerkitsimpl/src/object_service_proxy.cpp +++ b/data_object/frameworks/innerkitsimpl/src/object_service_proxy.cpp @@ -23,6 +23,9 @@ namespace OHOS::DistributedObject { using namespace ObjectStore; + +using ObjectCode = ObjectStoreService::ObjectServiceInterfaceCode; + ObjectServiceProxy::ObjectServiceProxy(const sptr &impl) : IRemoteProxy(impl) { ZLOGI("init service proxy."); @@ -43,7 +46,7 @@ int32_t ObjectServiceProxy::ObjectStoreSave(const std::string &bundleName, const } MessageParcel reply; MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(OBJECTSTORE_SAVE, data, reply, mo); + int32_t error = Remote()->SendRequest(static_cast(ObjectCode::OBJECTSTORE_SAVE), data, reply, mo); if (error != 0) { ZLOGE("SendRequest returned %d", error); return ERR_IPC; @@ -67,7 +70,7 @@ int32_t ObjectServiceProxy::ObjectStoreRevokeSave( MessageParcel reply; MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(OBJECTSTORE_REVOKE_SAVE, data, reply, mo); + int32_t error = Remote()->SendRequest(static_cast(ObjectCode::OBJECTSTORE_REVOKE_SAVE), data, reply, mo); if (error != 0) { ZLOGE("SendRequest returned %d", error); return ERR_IPC; @@ -91,7 +94,7 @@ int32_t ObjectServiceProxy::ObjectStoreRetrieve( MessageParcel reply; MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(OBJECTSTORE_RETRIEVE, data, reply, mo); + int32_t error = Remote()->SendRequest(static_cast(ObjectCode::OBJECTSTORE_RETRIEVE), data, reply, mo); if (error != 0) { ZLOGE("SendRequest returned %d", error); return ERR_IPC; @@ -115,7 +118,8 @@ int32_t ObjectServiceProxy::RegisterDataObserver(const std::string &bundleName, MessageParcel reply; MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(OBJECTSTORE_REGISTER_OBSERVER, data, reply, mo); + int32_t error = Remote()->SendRequest( + static_cast(ObjectCode::OBJECTSTORE_REGISTER_OBSERVER), data, reply, mo); if (error != 0) { ZLOGE("SendRequest returned %d", error); return ERR_IPC; @@ -138,7 +142,8 @@ int32_t ObjectServiceProxy::UnregisterDataChangeObserver(const std::string &bund MessageParcel reply; MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(OBJECTSTORE_UNREGISTER_OBSERVER, data, reply, mo); + int32_t error = Remote()->SendRequest( + static_cast(ObjectCode::OBJECTSTORE_UNREGISTER_OBSERVER), data, reply, mo); if (error != 0) { ZLOGE("SendRequest returned %d", error); return ERR_IPC; diff --git a/data_object/interfaces/innerkits/BUILD.gn b/data_object/interfaces/innerkits/BUILD.gn index 25a47e34..fbe4aeb7 100644 --- a/data_object/interfaces/innerkits/BUILD.gn +++ b/data_object/interfaces/innerkits/BUILD.gn @@ -63,9 +63,9 @@ object_external_deps_config = [ "c_utils:utils", "device_manager:devicemanagersdk", "dsoftbus:softbus_client", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", + "hilog:libhilog", "ipc:ipc_core", "kv_store:distributeddata_inner", "samgr:samgr_proxy", diff --git a/data_object/interfaces/jskits/BUILD.gn b/data_object/interfaces/jskits/BUILD.gn index ce5ff55b..b2b70587 100644 --- a/data_object/interfaces/jskits/BUILD.gn +++ b/data_object/interfaces/jskits/BUILD.gn @@ -10,7 +10,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import("//arkcompiler/ets_frontend/ts2panda/ts2abc_config.gni") + +import("//arkcompiler/ets_frontend/es2panda/es2abc_config.gni") import("//build/ohos.gni") import("//build/ohos/ace/ace.gni") import("//foundation/arkui/ace_engine/ace_config.gni") @@ -20,26 +21,13 @@ group("build_module") { } # compile .js to .abc. -action("gen_distributed_data_object_abc") { - visibility = [ ":*" ] - script = "//arkcompiler/ets_frontend/ts2panda/scripts/generate_js_bytecode.py" - - args = [ - "--src-js", - rebase_path("distributed_data_object.js"), - "--dst-file", - rebase_path(target_out_dir + "/distributed_data_object.abc"), - "--node", - rebase_path("${node_path}"), - "--frontend-tool-path", - rebase_path("${ts2abc_build_path}"), - "--node-modules", - rebase_path("${node_modules}"), - "--module", - ] - deps = [ "//arkcompiler/ets_frontend/ts2panda:ark_ts2abc_build" ] - inputs = [ "distributed_data_object.js" ] - outputs = [ target_out_dir + "/distributed_data_object.abc" ] +es2abc_gen_abc("gen_distributed_data_object_abc") { + extra_visibility = [ ":*" ] + src_js = rebase_path("distributed_data_object.js") + dst_file = rebase_path(target_out_dir + "/distributed_data_object.abc") + in_puts = [ "distributed_data_object.js" ] + out_puts = [ target_out_dir + "/distributed_data_object.abc" ] + extra_args = [ "--module" ] } config("objectstore_config") { @@ -118,7 +106,7 @@ ohos_shared_library("distributeddataobject") { "ability_runtime:napi_base_context", "access_token:libaccesstoken_sdk", "common_event_service:cesfwk_innerkits", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "napi:ace_napi", ] diff --git a/data_share/CODEOWNERS b/data_share/CODEOWNERS new file mode 100644 index 00000000..f59cc39e --- /dev/null +++ b/data_share/CODEOWNERS @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# any change to +# frameworks/native/common/include/distributeddata_data_share_ipc_interface_code.h +# needs to be reviewed by @leonchan5 +frameworks/native/common/include/distributeddata_data_share_ipc_interface_code.h @leonchan5 \ No newline at end of file diff --git a/data_share/bundle.json b/data_share/bundle.json index d1378671..1f23b4c2 100644 --- a/data_share/bundle.json +++ b/data_share/bundle.json @@ -55,9 +55,9 @@ "access_token", "common_event_service", "c_utils", - "hisysevent_native", - "hitrace_native", - "hiviewdfx_hilog_native", + "hisysevent", + "hitrace", + "hilog", "ipc", "ipc_js", "libuv", diff --git a/data_share/frameworks/js/napi/common/include/napi_callbacks_manager.h b/data_share/frameworks/js/napi/common/include/napi_callbacks_manager.h index c8936fd5..1cf38af5 100644 --- a/data_share/frameworks/js/napi/common/include/napi_callbacks_manager.h +++ b/data_share/frameworks/js/napi/common/include/napi_callbacks_manager.h @@ -27,6 +27,7 @@ template class NapiCallbacksManager { public: std::vector AddObservers(const std::vector &keys, const std::shared_ptr observer, + std::function &, const std::shared_ptr &observer)>, std::function &, const std::shared_ptr &observer, std::vector &)>); @@ -58,12 +59,15 @@ private: }; template -std::vector NapiCallbacksManager::AddObservers(const std::vector &keys, - const std::shared_ptr observer, std::function &, - const std::shared_ptr &observer, std::vector &)> processOnFirstAdd) +std::vector NapiCallbacksManager::AddObservers( + const std::vector &keys, const std::shared_ptr observer, + std::function &, const std::shared_ptr &observer)> processOnLocalAdd, + std::function &, const std::shared_ptr &observer, + std::vector &)> processOnFirstAdd) { std::vector result; std::vector firstRegisterKey; + std::vector localRegisterKey; { std::lock_guard lck(mutex_); for (auto &key : keys) { @@ -77,10 +81,14 @@ std::vector NapiCallbacksManager::AddObservers(c result.emplace_back(static_cast(key), E_REGISTERED_REPEATED); continue; } + localRegisterKey.emplace_back(key); callbacks_[key].emplace_back(observer); result.emplace_back(key, E_OK); } } + if (!localRegisterKey.empty()) { + processOnLocalAdd(localRegisterKey, observer); + } processOnFirstAdd(firstRegisterKey, observer, result); return result; } @@ -98,8 +106,8 @@ bool NapiCallbacksManager::IsRegistered(const Observer &observer, } template -std::vector NapiCallbacksManager::DelObservers(const std::vector &keys, - const std::shared_ptr observer, +std::vector NapiCallbacksManager::DelObservers( + const std::vector &keys, const std::shared_ptr observer, std::function &, const std::shared_ptr &, std::vector &)> processOnLastDel) { diff --git a/data_share/frameworks/js/napi/dataShare/BUILD.gn b/data_share/frameworks/js/napi/dataShare/BUILD.gn index 0f58291d..14e12a8c 100644 --- a/data_share/frameworks/js/napi/dataShare/BUILD.gn +++ b/data_share/frameworks/js/napi/dataShare/BUILD.gn @@ -48,7 +48,7 @@ ohos_shared_library("datashare") { "ability_runtime:napi_common", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "napi:ace_napi", ] @@ -77,7 +77,7 @@ ohos_shared_library("datasharepredicates") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "napi:ace_napi", ] diff --git a/data_share/frameworks/js/napi/observer/include/napi_subscriber_manager.h b/data_share/frameworks/js/napi/observer/include/napi_subscriber_manager.h index 0a472814..16068300 100644 --- a/data_share/frameworks/js/napi/observer/include/napi_subscriber_manager.h +++ b/data_share/frameworks/js/napi/observer/include/napi_subscriber_manager.h @@ -67,7 +67,9 @@ public: void Emit(const RdbChangeNode &changeNode); private: + void Emit(const std::vector &keys, const std::shared_ptr &observer); std::weak_ptr dataShareHelper_; + std::map lastChangeNodeMap_; }; struct NapiPublishedObserverMapKey { @@ -110,7 +112,9 @@ public: void Emit(const PublishedDataChangeNode &changeNode); private: + void Emit(const std::vector &keys, const std::shared_ptr &observer); std::weak_ptr dataShareHelper_; + std::map lastChangeNodeMap_; }; } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/js/napi/observer/src/napi_subscriber_manager.cpp b/data_share/frameworks/js/napi/observer/src/napi_subscriber_manager.cpp index f686ff91..2745d003 100644 --- a/data_share/frameworks/js/napi/observer/src/napi_subscriber_manager.cpp +++ b/data_share/frameworks/js/napi/observer/src/napi_subscriber_manager.cpp @@ -32,7 +32,11 @@ std::vector NapiRdbSubscriberManager::AddObservers(napi_env env std::for_each(uris.begin(), uris.end(), [&keys, &templateId](auto &uri) { keys.emplace_back(uri, templateId); }); - return BaseCallbacks::AddObservers(keys, std::make_shared(env, callback), + return BaseCallbacks::AddObservers( + keys, std::make_shared(env, callback), + [this](const std::vector &localRegisterKeys, const std::shared_ptr observer) { + Emit(localRegisterKeys, observer); + }, [&datashareHelper, &templateId, this](const std::vector &firstAddKeys, const std::shared_ptr observer, std::vector &opResult) { std::vector firstAddUris; @@ -73,10 +77,11 @@ std::vector NapiRdbSubscriberManager::DelObservers(napi_env env keys.emplace_back(uri, templateId); }); return BaseCallbacks::DelObservers(keys, callback == nullptr ? nullptr : std::make_shared(env, callback), - [&dataShareHelper, &templateId](const std::vector &lastDelKeys, const std::shared_ptr &observer, - std::vector &opResult) { + [&dataShareHelper, &templateId, this](const std::vector &lastDelKeys, + const std::shared_ptr &observer, std::vector &opResult) { std::vector lastDelUris; - std::for_each(lastDelKeys.begin(), lastDelKeys.end(), [&lastDelUris](auto &result) { + std::for_each(lastDelKeys.begin(), lastDelKeys.end(), [&lastDelUris, this](auto &result) { + lastChangeNodeMap_.erase(result); lastDelUris.emplace_back(result); }); if (lastDelUris.empty()) { @@ -90,6 +95,7 @@ std::vector NapiRdbSubscriberManager::DelObservers(napi_env env void NapiRdbSubscriberManager::Emit(const RdbChangeNode &changeNode) { Key key(changeNode.uri_, changeNode.templateId_); + lastChangeNodeMap_[key] = changeNode; auto callbacks = BaseCallbacks::GetEnabledObservers(key); for (auto &obs : callbacks) { if (obs != nullptr) { @@ -98,6 +104,16 @@ void NapiRdbSubscriberManager::Emit(const RdbChangeNode &changeNode) } } +void NapiRdbSubscriberManager::Emit(const std::vector &keys, const std::shared_ptr &observer) +{ + for (auto const &key : keys) { + auto it = lastChangeNodeMap_.find(key); + if (it != lastChangeNodeMap_.end()) { + observer->OnChange(it->second); + } + } +} + std::vector NapiPublishedSubscriberManager::AddObservers(napi_env env, napi_value callback, const std::vector &uris, int64_t subscriberId) { @@ -111,7 +127,11 @@ std::vector NapiPublishedSubscriberManager::AddObservers(napi_e std::for_each(uris.begin(), uris.end(), [&keys, &subscriberId](auto &uri) { keys.emplace_back(uri, subscriberId); }); - return BaseCallbacks::AddObservers(keys, std::make_shared(env, callback), + return BaseCallbacks::AddObservers( + keys, std::make_shared(env, callback), + [this](const std::vector &localRegisterKeys, const std::shared_ptr observer) { + Emit(localRegisterKeys, observer); + }, [&dataShareHelper, &subscriberId, this](const std::vector &firstAddKeys, const std::shared_ptr observer, std::vector &opResult) { std::vector firstAddUris; @@ -152,10 +172,11 @@ std::vector NapiPublishedSubscriberManager::DelObservers(napi_e keys.emplace_back(uri, subscriberId); }); return BaseCallbacks::DelObservers(keys, callback == nullptr ? nullptr : std::make_shared(env, callback), - [&dataShareHelper, &subscriberId, &callback, &uris](const std::vector &lastDelKeys, + [&dataShareHelper, &subscriberId, &callback, &uris, this](const std::vector &lastDelKeys, const std::shared_ptr &observer, std::vector &opResult) { std::vector lastDelUris; - std::for_each(lastDelKeys.begin(), lastDelKeys.end(), [&lastDelUris](auto &result) { + std::for_each(lastDelKeys.begin(), lastDelKeys.end(), [&lastDelUris, this](auto &result) { + lastChangeNodeMap_.erase(result); lastDelUris.emplace_back(result); }); if (lastDelUris.empty()) { @@ -168,13 +189,20 @@ std::vector NapiPublishedSubscriberManager::DelObservers(napi_e void NapiPublishedSubscriberManager::Emit(const PublishedDataChangeNode &changeNode) { + for (auto &data : changeNode.datas_) { + Key key(data.key_, data.subscriberId_); + lastChangeNodeMap_[key].datas_.clear(); + } std::map, PublishedDataChangeNode> results; for (auto &data : changeNode.datas_) { Key key(data.key_, data.subscriberId_); auto callbacks = BaseCallbacks::GetEnabledObservers(key); if (callbacks.empty()) { LOG_WARN("%{private}s nobody subscribe, but still notify", data.key_.c_str()); + continue; } + lastChangeNodeMap_[key].datas_.emplace_back(data.key_, data.subscriberId_, data.GetData()); + lastChangeNodeMap_[key].ownerBundleName_ = changeNode.ownerBundleName_; for (auto const &obs : callbacks) { results[obs].datas_.emplace_back(data.key_, data.subscriberId_, data.GetData()); } @@ -184,5 +212,21 @@ void NapiPublishedSubscriberManager::Emit(const PublishedDataChangeNode &changeN callback->OnChange(node); } } + +void NapiPublishedSubscriberManager::Emit(const std::vector &keys, const std::shared_ptr &observer) +{ + PublishedDataChangeNode node; + for (auto &key : keys) { + auto it = lastChangeNodeMap_.find(key); + if (it == lastChangeNodeMap_.end()) { + continue; + } + for (auto &data : it->second.datas_) { + node.datas_.emplace_back(data.key_, data.subscriberId_, data.GetData()); + } + node.ownerBundleName_ = it->second.ownerBundleName_; + } + observer->OnChange(node); +} } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/common/include/callbacks_manager.h b/data_share/frameworks/native/common/include/callbacks_manager.h index 43ddf0a9..7dd33229 100644 --- a/data_share/frameworks/native/common/include/callbacks_manager.h +++ b/data_share/frameworks/native/common/include/callbacks_manager.h @@ -28,6 +28,7 @@ class CallbacksManager { public: std::vector AddObservers(const std::vector &keys, void *subscriber, const std::shared_ptr observer, + std::function &, const std::shared_ptr &observer)>, std::function &, const std::shared_ptr &observer, std::vector &)>); @@ -40,6 +41,7 @@ public: CallbacksManager::DefaultProcess); std::vector EnableObservers(const std::vector &keys, void *subscriber, + std::function>> &)> processOnLocalEnabled, std::function &, std::vector &)>); std::vector DisableObservers(const std::vector &keys, void *subscriber, @@ -73,11 +75,14 @@ private: template std::vector CallbacksManager::AddObservers(const std::vector &keys, - void *subscriber, const std::shared_ptr observer, std::function &, - const std::shared_ptr &observer, std::vector &)> processOnFirstAdd) + void *subscriber, const std::shared_ptr observer, + std::function &, const std::shared_ptr &observer)> processOnLocalAdd, + std::function &, + const std::shared_ptr &observer, std::vector &)> processOnFirstAdd) { std::vector result; std::vector firstRegisterKey; + std::vector localRegisterKey; { std::lock_guard lck(mutex_); for (auto &key : keys) { @@ -87,10 +92,14 @@ std::vector CallbacksManager::AddObservers(const firstRegisterKey.emplace_back(key); continue; } + localRegisterKey.emplace_back(key); callbacks_[key].emplace_back(observer, subscriber); result.emplace_back(key, E_OK); } } + if (!localRegisterKey.empty()) { + processOnLocalAdd(localRegisterKey, observer); + } processOnFirstAdd(firstRegisterKey, observer, result); return result; } @@ -207,10 +216,12 @@ std::vector> CallbacksManager::GetEnabl template std::vector CallbacksManager::EnableObservers( const std::vector &keys, void *subscriber, + std::function>> &)> processOnLocalEnabled, std::function &, std::vector &)> processOnFirstEnabled) { std::vector result; std::vector firstRegisterKey; + std::map>> localEnabledObservers; { std::lock_guard lck(mutex_); for (auto &key : keys) { @@ -223,6 +234,7 @@ std::vector CallbacksManager::EnableObservers( bool hasEnabled = false; for (auto &item : callbacks_[key]) { if (item.subscriber_ == subscriber) { + localEnabledObservers[key].emplace_back(item.observer_); item.enabled_ = true; hasEnabled = true; } @@ -235,16 +247,20 @@ std::vector CallbacksManager::EnableObservers( result.emplace_back(key, E_OK); continue; } + localEnabledObservers.erase(key); firstRegisterKey.emplace_back(key); } } + if (!localEnabledObservers.empty()) { + processOnLocalEnabled(localEnabledObservers); + } processOnFirstEnabled(firstRegisterKey, result); return result; } template -std::vector CallbacksManager::DisableObservers( - const std::vector &keys, void *subscriber, +std::vector CallbacksManager::DisableObservers(const std::vector &keys, + void *subscriber, std::function &, std::vector &)> processOnLastDisable) { std::vector result; diff --git a/data_share/frameworks/native/common/include/distributeddata_data_share_ipc_interface_code.h b/data_share/frameworks/native/common/include/distributeddata_data_share_ipc_interface_code.h new file mode 100644 index 00000000..4000bafb --- /dev/null +++ b/data_share/frameworks/native/common/include/distributeddata_data_share_ipc_interface_code.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* SAID:1301 */ +/* FeatureSystem: data_share_service */ +#ifndef DISTRIBUTEDDATA_DATA_SHARE_IPC_INTERFACE_H +#define DISTRIBUTEDDATA_DATA_SHARE_IPC_INTERFACE_H + +namespace OHOS::DistributedShare { +namespace DataShare { +enum class IDataShareInterfaceCode { + CMD_GET_FILE_TYPES = 1, + CMD_OPEN_FILE, + CMD_OPEN_RAW_FILE, + CMD_INSERT, + CMD_UPDATE, + CMD_DELETE, + CMD_QUERY, + CMD_GET_TYPE, + CMD_BATCH_INSERT, + CMD_REGISTER_OBSERVER, + CMD_UNREGISTER_OBSERVER, + CMD_NOTIFY_CHANGE, + CMD_NORMALIZE_URI, + CMD_DENORMALIZE_URI, + CMD_EXECUTE_BATCH, +}; + +enum class ISharedResultInterfaceCode { + FUNC_GET_ROW_COUNT, + FUNC_GET_ALL_COLUMN_NAMES, + FUNC_ON_GO, + FUNC_CLOSE, + FUNC_GET_BLOB, + FUNC_GET_STRING, + FUNC_GET_INT, + FUNC_GET_LONG, + FUNC_GET_DOUBLE, + FUNC_IS_COLUMN_NULL, + FUNC_GO_TO, + FUNC_GO_TO_ROW, + FUNC_GO_TO_FISTR_ROW, + FUNC_GO_TO_LAST_ROW, + FUNC_GO_TO_NEXT_ROW, + FUNC_GO_TO_PREV_ROW, + FUNC_IS_AT_FIRST_ROW, + FUNC_IS_AT_LAST_ROW, + FUNC_IS_STARTED_ROW, + FUNC_IS_ENDED_ROW, + FUNC_IS_CLOSED, + FUNC_GET_COLUMN_COUNT, + FUNC_GET_COLUMN_INDEX, + FUNC_GET_COLUMN_NAME, + FUNC_GET_COLUMN_TYPE, + FUNC_GET_ROW_INDEX, + FUNC_BUTT, +}; + +enum class DataShareServiceInterfaceCode { + DATA_SHARE_SERVICE_CMD_INSERT, + DATA_SHARE_SERVICE_CMD_DELETE, + DATA_SHARE_SERVICE_CMD_UPDATE, + DATA_SHARE_SERVICE_CMD_QUERY, + DATA_SHARE_SERVICE_CMD_ADD_TEMPLATE, + DATA_SHARE_SERVICE_CMD_DEL_TEMPLATE, + DATA_SHARE_SERVICE_CMD_PUBLISH, + DATA_SHARE_SERVICE_CMD_GET_DATA, + DATA_SHARE_SERVICE_CMD_SUBSCRIBE_RDB, + DATA_SHARE_SERVICE_CMD_UNSUBSCRIBE_RDB, + DATA_SHARE_SERVICE_CMD_ENABLE_SUBSCRIBE_RDB, + DATA_SHARE_SERVICE_CMD_DISABLE_SUBSCRIBE_RDB, + DATA_SHARE_SERVICE_CMD_SUBSCRIBE_PUBLISHED, + DATA_SHARE_SERVICE_CMD_UNSUBSCRIBE_PUBLISHED, + DATA_SHARE_SERVICE_CMD_ENABLE_SUBSCRIBE_PUBLISHED, + DATA_SHARE_SERVICE_CMD_DISABLE_SUBSCRIBE_PUBLISHED, + DATA_SHARE_SERVICE_CMD_NOTIFY, + DATA_SHARE_SERVICE_CMD_NOTIFY_OBSERVERS, + DATA_SHARE_SERVICE_CMD_MAX +}; + +enum class IKvStoreDataInterfaceCode { + GET_FEATURE_INTERFACE = 0 +}; +} +} // namespace OHOS + +#endif // DISTRIBUTEDDATA_DATA_SHARE_IPC_INTERFACE_H \ No newline at end of file diff --git a/data_share/frameworks/native/common/include/idata_share_service.h b/data_share/frameworks/native/common/include/idata_share_service.h index 06f84e6a..0f9a5b9e 100644 --- a/data_share/frameworks/native/common/include/idata_share_service.h +++ b/data_share/frameworks/native/common/include/idata_share_service.h @@ -26,32 +26,13 @@ #include "datashare_result_set.h" #include "datashare_template.h" #include "datashare_values_bucket.h" +#include "distributeddata_data_share_ipc_interface_code.h" #include "uri.h" namespace OHOS::DataShare { class IDataShareService : public IRemoteBroker { public: DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.DataShare.IDataShareService"); - enum { - DATA_SHARE_SERVICE_CMD_INSERT, - DATA_SHARE_SERVICE_CMD_DELETE, - DATA_SHARE_SERVICE_CMD_UPDATE, - DATA_SHARE_SERVICE_CMD_QUERY, - DATA_SHARE_SERVICE_CMD_ADD_TEMPLATE, - DATA_SHARE_SERVICE_CMD_DEL_TEMPLATE, - DATA_SHARE_SERVICE_CMD_PUBLISH, - DATA_SHARE_SERVICE_CMD_GET_DATA, - DATA_SHARE_SERVICE_CMD_SUBSCRIBE_RDB, - DATA_SHARE_SERVICE_CMD_UNSUBSCRIBE_RDB, - DATA_SHARE_SERVICE_CMD_ENABLE_SUBSCRIBE_RDB, - DATA_SHARE_SERVICE_CMD_DISABLE_SUBSCRIBE_RDB, - DATA_SHARE_SERVICE_CMD_SUBSCRIBE_PUBLISHED, - DATA_SHARE_SERVICE_CMD_UNSUBSCRIBE_PUBLISHED, - DATA_SHARE_SERVICE_CMD_ENABLE_SUBSCRIBE_PUBLISHED, - DATA_SHARE_SERVICE_CMD_DISABLE_SUBSCRIBE_PUBLISHED, - DATA_SHARE_SERVICE_CMD_NOTIFY, - DATA_SHARE_SERVICE_CMD_MAX - }; enum { DATA_SHARE_ERROR = -1, @@ -98,6 +79,8 @@ public: virtual std::vector DisableSubscribePublishedData(const std::vector &uris, int64_t subscriberId) = 0; + + virtual void Notify(const std::string &uri) = 0; }; } // namespace OHOS::DataShare #endif diff --git a/data_share/frameworks/native/common/include/idatashare.h b/data_share/frameworks/native/common/include/idatashare.h index 0e28597a..11bd40f9 100644 --- a/data_share/frameworks/native/common/include/idatashare.h +++ b/data_share/frameworks/native/common/include/idatashare.h @@ -22,6 +22,7 @@ #include "datashare_predicates.h" #include "datashare_result_set.h" #include "datashare_values_bucket.h" +#include "distributeddata_data_share_ipc_interface_code.h" #include "uri.h" namespace OHOS { @@ -34,24 +35,6 @@ class IDataShare : public IRemoteBroker { public: DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.DataShare.IDataShare"); - enum { - CMD_GET_FILE_TYPES = 1, - CMD_OPEN_FILE, - CMD_OPEN_RAW_FILE, - CMD_INSERT, - CMD_UPDATE, - CMD_DELETE, - CMD_QUERY, - CMD_GET_TYPE, - CMD_BATCH_INSERT, - CMD_REGISTER_OBSERVER, - CMD_UNREGISTER_OBSERVER, - CMD_NOTIFY_CHANGE, - CMD_NORMALIZE_URI, - CMD_DENORMALIZE_URI, - CMD_EXECUTE_BATCH, - }; - virtual int OpenFile(const Uri &uri, const std::string &mode) = 0; virtual int OpenRawFile(const Uri &uri, const std::string &mode) = 0; diff --git a/data_share/frameworks/native/common/include/ikvstore_data_service.h b/data_share/frameworks/native/common/include/ikvstore_data_service.h index 55b33a92..4dcfc497 100644 --- a/data_share/frameworks/native/common/include/ikvstore_data_service.h +++ b/data_share/frameworks/native/common/include/ikvstore_data_service.h @@ -19,15 +19,12 @@ #include "iremote_broker.h" #include "iremote_proxy.h" +#include "distributeddata_data_share_ipc_interface_code.h" namespace OHOS { namespace DataShare { class IKvStoreDataService : public IRemoteBroker { public: - enum { - GET_FEATURE_INTERFACE = 0 - }; - enum { DATA_SHARE_ERROR = -1, DATA_SHARE_OK = 0, diff --git a/data_share/frameworks/native/common/include/ishared_result_set.h b/data_share/frameworks/native/common/include/ishared_result_set.h index f8d7d1d1..ffb5c33f 100644 --- a/data_share/frameworks/native/common/include/ishared_result_set.h +++ b/data_share/frameworks/native/common/include/ishared_result_set.h @@ -18,6 +18,7 @@ #include #include "iremote_broker.h" #include "datashare_result_set.h" +#include "distributeddata_data_share_ipc_interface_code.h" namespace OHOS::DataShare { class ISharedResultSet : public DataShareResultSet, public IRemoteBroker { public: @@ -26,37 +27,6 @@ public: static sptr WriteToParcel(std::shared_ptr resultSet, MessageParcel &parcel); -protected: - enum { - FUNC_GET_ROW_COUNT, - FUNC_GET_ALL_COLUMN_NAMES, - FUNC_ON_GO, - FUNC_CLOSE, - FUNC_GET_BLOB, - FUNC_GET_STRING, - FUNC_GET_INT, - FUNC_GET_LONG, - FUNC_GET_DOUBLE, - FUNC_IS_COLUMN_NULL, - FUNC_GO_TO, - FUNC_GO_TO_ROW, - FUNC_GO_TO_FISTR_ROW, - FUNC_GO_TO_LAST_ROW, - FUNC_GO_TO_NEXT_ROW, - FUNC_GO_TO_PREV_ROW, - FUNC_IS_AT_FIRST_ROW, - FUNC_IS_AT_LAST_ROW, - FUNC_IS_STARTED_ROW, - FUNC_IS_ENDED_ROW, - FUNC_IS_CLOSED, - FUNC_GET_COLUMN_COUNT, - FUNC_GET_COLUMN_INDEX, - FUNC_GET_COLUMN_NAME, - FUNC_GET_COLUMN_TYPE, - FUNC_GET_ROW_INDEX, - FUNC_BUTT - }; - private: static std::function(MessageParcel &parcel)> consumerCreator_; static std::function(std::shared_ptr, diff --git a/data_share/frameworks/native/common/include/ishared_result_set_stub.h b/data_share/frameworks/native/common/include/ishared_result_set_stub.h index 46252492..70993a93 100644 --- a/data_share/frameworks/native/common/include/ishared_result_set_stub.h +++ b/data_share/frameworks/native/common/include/ishared_result_set_stub.h @@ -23,6 +23,8 @@ #include "iremote_stub.h" namespace OHOS::DataShare { +using ResultCode = OHOS::DistributedShare::DataShare::ISharedResultInterfaceCode; + class ISharedResultSetStub : public IRemoteStub { public: explicit ISharedResultSetStub(std::shared_ptr resultSet); @@ -40,7 +42,7 @@ protected: private: using Handler = int(ISharedResultSetStub::*)(MessageParcel &request, MessageParcel &reply); std::shared_ptr resultSet_; - static constexpr Handler handlers[FUNC_BUTT] { + static constexpr Handler handlers[static_cast(ResultCode::FUNC_BUTT)] { &ISharedResultSetStub::HandleGetRowCountRequest, &ISharedResultSetStub::HandleGetAllColumnNamesRequest, &ISharedResultSetStub::HandleOnGoRequest, diff --git a/data_share/frameworks/native/common/src/ikvstore_data_service.cpp b/data_share/frameworks/native/common/src/ikvstore_data_service.cpp index 341a1f22..29f746ce 100644 --- a/data_share/frameworks/native/common/src/ikvstore_data_service.cpp +++ b/data_share/frameworks/native/common/src/ikvstore_data_service.cpp @@ -16,6 +16,8 @@ #include "ikvstore_data_service.h" #include "datashare_log.h" +using namespace OHOS::DistributedShare::DataShare; + namespace OHOS { namespace DataShare { DataShareKvServiceProxy::DataShareKvServiceProxy(const sptr &impl) @@ -39,7 +41,8 @@ sptr DataShareKvServiceProxy::GetFeatureInterface(const std::stri MessageParcel reply; MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(GET_FEATURE_INTERFACE, data, reply, mo); + int32_t error = Remote()->SendRequest( + static_cast(IKvStoreDataInterfaceCode::GET_FEATURE_INTERFACE), data, reply, mo); if (error != 0) { LOG_ERROR("SendRequest returned %{public}d", error); return nullptr; diff --git a/data_share/frameworks/native/common/src/ishared_result_set_proxy.cpp b/data_share/frameworks/native/common/src/ishared_result_set_proxy.cpp index 2df45f5e..cedc768a 100644 --- a/data_share/frameworks/native/common/src/ishared_result_set_proxy.cpp +++ b/data_share/frameworks/native/common/src/ishared_result_set_proxy.cpp @@ -19,6 +19,8 @@ #include "datashare_log.h" #include "iremote_proxy.h" +using namespace OHOS::DistributedShare::DataShare; + namespace OHOS::DataShare { std::function(MessageParcel &parcel)> ISharedResultSet::consumerCreator_ = ISharedResultSetProxy::CreateProxy; @@ -54,7 +56,8 @@ int ISharedResultSetProxy::GetAllColumnNames(std::vector &columnNam request.WriteInterfaceToken(GetDescriptor()); MessageParcel reply; MessageOption msgOption; - int errCode = Remote()->SendRequest(FUNC_GET_ALL_COLUMN_NAMES, request, reply, msgOption); + int errCode = Remote()->SendRequest( + static_cast(ISharedResultInterfaceCode::FUNC_GET_ALL_COLUMN_NAMES), request, reply, msgOption); if (errCode != 0) { LOG_ERROR("IPC Error %{public}x", errCode); return -errCode; @@ -81,7 +84,8 @@ int ISharedResultSetProxy::GetRowCount(int &count) request.WriteInterfaceToken(GetDescriptor()); MessageParcel reply; MessageOption msgOption; - int errCode = Remote()->SendRequest(FUNC_GET_ROW_COUNT, request, reply, msgOption); + int errCode = Remote()->SendRequest( + static_cast(ISharedResultInterfaceCode::FUNC_GET_ROW_COUNT), request, reply, msgOption); if (errCode != 0) { LOG_ERROR("IPC Error %{public}x", errCode); return -errCode; @@ -105,7 +109,8 @@ bool ISharedResultSetProxy::OnGo(int oldRowIndex, int newRowIndex, int *cachedIn request.WriteInt32(newRowIndex); MessageParcel reply; MessageOption msgOption; - int errCode = Remote()->SendRequest(FUNC_ON_GO, request, reply, msgOption); + int errCode = Remote()->SendRequest( + static_cast(ISharedResultInterfaceCode::FUNC_ON_GO), request, reply, msgOption); if (errCode != 0) { LOG_ERROR("IPC Error %{public}x", errCode); return false; @@ -127,7 +132,8 @@ int ISharedResultSetProxy::Close() request.WriteInterfaceToken(GetDescriptor()); MessageParcel reply; MessageOption msgOption; - int errCode = Remote()->SendRequest(FUNC_CLOSE, request, reply, msgOption); + int errCode = Remote()->SendRequest( + static_cast(ISharedResultInterfaceCode::FUNC_CLOSE), request, reply, msgOption); if (errCode != 0) { LOG_ERROR("IPC Error %{public}x", errCode); return -errCode; diff --git a/data_share/frameworks/native/common/src/ishared_result_set_stub.cpp b/data_share/frameworks/native/common/src/ishared_result_set_stub.cpp index 722daae4..6fd0020b 100644 --- a/data_share/frameworks/native/common/src/ishared_result_set_stub.cpp +++ b/data_share/frameworks/native/common/src/ishared_result_set_stub.cpp @@ -20,7 +20,7 @@ namespace OHOS::DataShare { std::function(std::shared_ptr, MessageParcel &)> ISharedResultSet::providerCreator_ = ISharedResultSetStub::CreateStub; -constexpr ISharedResultSetStub::Handler ISharedResultSetStub::handlers[ISharedResultSet::FUNC_BUTT]; +constexpr ISharedResultSetStub::Handler ISharedResultSetStub::handlers[static_cast(ResultCode::FUNC_BUTT)]; sptr ISharedResultSetStub::CreateStub(std::shared_ptr result, OHOS::MessageParcel &parcel) @@ -56,7 +56,7 @@ int ISharedResultSetStub::OnRemoteRequest(uint32_t code, OHOS::MessageParcel &da return INVALID_FD; } - if (code >= FUNC_BUTT) { + if (code >= static_cast(ResultCode::FUNC_BUTT)) { LOG_ERROR("method code(%{public}d) out of range", code); return IPCObjectStub::OnRemoteRequest(code, data, reply, option); } diff --git a/data_share/frameworks/native/consumer/controller/common/general_controller.h b/data_share/frameworks/native/consumer/controller/common/general_controller.h index 10a8d4ee..3fac63bd 100644 --- a/data_share/frameworks/native/consumer/controller/common/general_controller.h +++ b/data_share/frameworks/native/consumer/controller/common/general_controller.h @@ -46,6 +46,8 @@ public: virtual void RegisterObserver(const Uri &uri, const sptr &dataObserver) = 0; virtual void UnregisterObserver(const Uri &uri, const sptr &dataObserver) = 0; + + virtual void NotifyChange(const Uri &uri) = 0; }; } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/consumer/controller/provider/include/ext_special_controller.h b/data_share/frameworks/native/consumer/controller/provider/include/ext_special_controller.h index 32a5ba99..4c3d7a69 100644 --- a/data_share/frameworks/native/consumer/controller/provider/include/ext_special_controller.h +++ b/data_share/frameworks/native/consumer/controller/provider/include/ext_special_controller.h @@ -41,8 +41,6 @@ public: Uri DenormalizeUri(const Uri &uri); std::vector GetFileTypes(const Uri &uri, const std::string &mimeTypeFilter); - - void NotifyChange(const Uri &uri); private: std::shared_ptr connection_ = nullptr; diff --git a/data_share/frameworks/native/consumer/controller/provider/include/general_controller_porvider_impl.h b/data_share/frameworks/native/consumer/controller/provider/include/general_controller_porvider_impl.h index 37c12b0f..1f75d74c 100644 --- a/data_share/frameworks/native/consumer/controller/provider/include/general_controller_porvider_impl.h +++ b/data_share/frameworks/native/consumer/controller/provider/include/general_controller_porvider_impl.h @@ -45,6 +45,7 @@ public: void UnregisterObserver(const Uri &uri, const sptr &dataObserver) override; + void NotifyChange(const Uri &uri) override; private: std::shared_ptr connection_ = nullptr; sptr token_ = {}; diff --git a/data_share/frameworks/native/consumer/controller/provider/src/ext_special_controller.cpp b/data_share/frameworks/native/consumer/controller/provider/src/ext_special_controller.cpp index b931115b..3da33f95 100644 --- a/data_share/frameworks/native/consumer/controller/provider/src/ext_special_controller.cpp +++ b/data_share/frameworks/native/consumer/controller/provider/src/ext_special_controller.cpp @@ -124,21 +124,6 @@ std::vector ExtSpecialController::GetFileTypes(const Uri &uri, cons return proxy->GetFileTypes(uri, mimeTypeFilter); } -void ExtSpecialController::NotifyChange(const Uri &uri) -{ - auto connection = connection_; - if (connection == nullptr) { - LOG_ERROR("connection is nullptr"); - return; - } - auto proxy = connection->GetDataShareProxy(uri_, token_); - if (proxy == nullptr) { - LOG_ERROR("proxy is nullptr"); - return; - } - proxy->NotifyChange(uri); -} - ExtSpecialController::ExtSpecialController(std::shared_ptr connection, const Uri &uri, const sptr &token) : connection_(connection), token_(token), uri_(uri) diff --git a/data_share/frameworks/native/consumer/controller/provider/src/general_controller_provider_impl.cpp b/data_share/frameworks/native/consumer/controller/provider/src/general_controller_provider_impl.cpp index ea310623..ccc8fc47 100644 --- a/data_share/frameworks/native/consumer/controller/provider/src/general_controller_provider_impl.cpp +++ b/data_share/frameworks/native/consumer/controller/provider/src/general_controller_provider_impl.cpp @@ -114,6 +114,21 @@ void GeneralControllerProviderImpl::UnregisterObserver(const Uri &uri, proxy->UnregisterObserver(uri, dataObserver); } +void GeneralControllerProviderImpl::NotifyChange(const Uri &uri) +{ + auto connection = connection_; + if (connection == nullptr) { + LOG_ERROR("connection is nullptr"); + return; + } + auto proxy = connection->GetDataShareProxy(uri_, token_); + if (proxy == nullptr) { + LOG_ERROR("proxy is nullptr"); + return; + } + proxy->NotifyChange(uri); +} + GeneralControllerProviderImpl::GeneralControllerProviderImpl(std::shared_ptr connection, const Uri &uri, const sptr &token) : connection_(connection), token_(token), uri_(uri) { diff --git a/data_share/frameworks/native/consumer/controller/service/include/general_controller_service_impl.h b/data_share/frameworks/native/consumer/controller/service/include/general_controller_service_impl.h index bed139b8..c1b65efb 100644 --- a/data_share/frameworks/native/consumer/controller/service/include/general_controller_service_impl.h +++ b/data_share/frameworks/native/consumer/controller/service/include/general_controller_service_impl.h @@ -43,6 +43,8 @@ public: void RegisterObserver(const Uri &uri, const sptr &dataObserver) override; void UnregisterObserver(const Uri &uri, const sptr &dataObserver) override; + + void NotifyChange(const Uri &uri) override; }; } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/consumer/controller/service/src/general_controller_service_impl.cpp b/data_share/frameworks/native/consumer/controller/service/src/general_controller_service_impl.cpp index 1163df66..7acb6999 100644 --- a/data_share/frameworks/native/consumer/controller/service/src/general_controller_service_impl.cpp +++ b/data_share/frameworks/native/consumer/controller/service/src/general_controller_service_impl.cpp @@ -90,5 +90,15 @@ void GeneralControllerServiceImpl::UnregisterObserver(const Uri &uri, LOG_ERROR("UnregisterObserver failed"); } } + +void GeneralControllerServiceImpl::NotifyChange(const Uri &uri) +{ + auto proxy = DataShareManagerImpl::GetInstance().GetServiceProxy(); + if (proxy == nullptr) { + LOG_ERROR("proxy is nullptr"); + return; + } + proxy->Notify(uri.ToString()); +} } // namespace DataShare } // namespace OHOS \ No newline at end of file diff --git a/data_share/frameworks/native/consumer/src/datashare_helper_impl.cpp b/data_share/frameworks/native/consumer/src/datashare_helper_impl.cpp index f845c627..5f7a8696 100644 --- a/data_share/frameworks/native/consumer/src/datashare_helper_impl.cpp +++ b/data_share/frameworks/native/consumer/src/datashare_helper_impl.cpp @@ -185,12 +185,12 @@ void DataShareHelperImpl::UnregisterObserver(const Uri &uri, const sptrNotifyChange(uri); + return generalCtl->NotifyChange(uri); } Uri DataShareHelperImpl::NormalizeUri(Uri &uri) diff --git a/data_share/frameworks/native/consumer/src/datashare_proxy.cpp b/data_share/frameworks/native/consumer/src/datashare_proxy.cpp index 157f6119..b0819336 100644 --- a/data_share/frameworks/native/consumer/src/datashare_proxy.cpp +++ b/data_share/frameworks/native/consumer/src/datashare_proxy.cpp @@ -25,6 +25,8 @@ #include "ishared_result_set.h" #include "pac_map.h" +using namespace OHOS::DistributedShare::DataShare; + namespace OHOS { namespace DataShare { constexpr int32_t PERMISSION_ERR = 1; @@ -52,7 +54,8 @@ std::vector DataShareProxy::GetFileTypes(const Uri &uri, const std: return types; } - int32_t err = Remote()->SendRequest(CMD_GET_FILE_TYPES, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_GET_FILE_TYPES), data, reply, option); if (err != DATA_SHARE_NO_ERROR) { LOG_ERROR("GetFileTypes fail to SendRequest. err: %{public}d", err); } @@ -85,7 +88,8 @@ int DataShareProxy::OpenFile(const Uri &uri, const std::string &mode) MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(CMD_OPEN_FILE, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_OPEN_FILE), data, reply, option); if (err != DATA_SHARE_NO_ERROR) { LOG_ERROR("OpenFile fail to SendRequest. err: %{public}d", err); return fd; @@ -121,7 +125,8 @@ int DataShareProxy::OpenRawFile(const Uri &uri, const std::string &mode) MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(CMD_OPEN_RAW_FILE, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_OPEN_RAW_FILE), data, reply, option); if (err != DATA_SHARE_NO_ERROR) { LOG_ERROR("OpenRawFile fail to SendRequest. err: %{public}d", err); return fd; @@ -149,7 +154,8 @@ int DataShareProxy::Insert(const Uri &uri, const DataShareValuesBucket &value) } MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(CMD_INSERT, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_INSERT), data, reply, option); if (err != DATA_SHARE_NO_ERROR) { LOG_ERROR("Insert fail to SendRequest. err: %{public}d", err); return err == PERMISSION_ERR ? PERMISSION_ERR_CODE : index; @@ -162,8 +168,7 @@ int DataShareProxy::Insert(const Uri &uri, const DataShareValuesBucket &value) return index; } -int DataShareProxy::Update(const Uri &uri, const DataSharePredicates &predicates, - const DataShareValuesBucket &value) +int DataShareProxy::Update(const Uri &uri, const DataSharePredicates &predicates, const DataShareValuesBucket &value) { int index = -1; MessageParcel data; @@ -177,7 +182,8 @@ int DataShareProxy::Update(const Uri &uri, const DataSharePredicates &predicates } MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(CMD_UPDATE, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_UPDATE), data, reply, option); if (err != DATA_SHARE_NO_ERROR) { LOG_ERROR("Update fail to SendRequest. err: %{public}d", err); return err == PERMISSION_ERR ? PERMISSION_ERR_CODE : index; @@ -204,7 +210,8 @@ int DataShareProxy::Delete(const Uri &uri, const DataSharePredicates &predicates MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(CMD_DELETE, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_DELETE), data, reply, option); if (err != DATA_SHARE_NO_ERROR) { LOG_ERROR("Delete fail to SendRequest. err: %{public}d", err); return err == PERMISSION_ERR ? PERMISSION_ERR_CODE : index; @@ -216,8 +223,8 @@ int DataShareProxy::Delete(const Uri &uri, const DataSharePredicates &predicates return index; } -std::shared_ptr DataShareProxy::Query(const Uri &uri, - const DataSharePredicates &predicates, std::vector &columns, DatashareBusinessError &businessError) +std::shared_ptr DataShareProxy::Query(const Uri &uri, const DataSharePredicates &predicates, + std::vector &columns, DatashareBusinessError &businessError) { MessageParcel data; if (!data.WriteInterfaceToken(DataShareProxy::GetDescriptor())) { @@ -230,7 +237,8 @@ std::shared_ptr DataShareProxy::Query(const Uri &uri, } MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(CMD_QUERY, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_QUERY), data, reply, option); auto result = ISharedResultSet::ReadFromParcel(reply); businessError.SetCode(reply.ReadInt32()); businessError.SetMessage(reply.ReadString()); @@ -258,7 +266,8 @@ std::string DataShareProxy::GetType(const Uri &uri) MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(CMD_GET_TYPE, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_GET_TYPE), data, reply, option); if (err != DATA_SHARE_NO_ERROR) { LOG_ERROR("GetFileTypes fail to SendRequest. err: %{public}d", err); return type; @@ -292,7 +301,8 @@ int DataShareProxy::BatchInsert(const Uri &uri, const std::vectorSendRequest(CMD_BATCH_INSERT, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_BATCH_INSERT), data, reply, option); if (err != DATA_SHARE_NO_ERROR) { LOG_ERROR("fail to SendRequest. err: %{public}d", err); return err == PERMISSION_ERR ? PERMISSION_ERR_CODE : ret; @@ -321,7 +331,8 @@ bool DataShareProxy::RegisterObserver(const Uri &uri, const sptrSendRequest(CMD_REGISTER_OBSERVER, data, reply, option); + int32_t result = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_REGISTER_OBSERVER), data, reply, option); if (result == ERR_NONE) { LOG_INFO("SendRequest ok, retval is %{public}d", reply.ReadInt32()); } else { @@ -347,7 +358,8 @@ bool DataShareProxy::UnregisterObserver(const Uri &uri, const sptrSendRequest(CMD_UNREGISTER_OBSERVER, data, reply, option); + int32_t result = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_UNREGISTER_OBSERVER), data, reply, option); if (result == ERR_NONE) { LOG_INFO("SendRequest ok, retval is %{public}d", reply.ReadInt32()); } else { @@ -373,7 +385,8 @@ bool DataShareProxy::NotifyChange(const Uri &uri) MessageParcel reply; MessageOption option; - int32_t result = Remote()->SendRequest(CMD_NOTIFY_CHANGE, data, reply, option); + int32_t result = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_NOTIFY_CHANGE), data, reply, option); if (result == ERR_NONE) { LOG_INFO("SendRequest ok, retval is %{public}d", reply.ReadInt32()); } else { @@ -399,7 +412,8 @@ Uri DataShareProxy::NormalizeUri(const Uri &uri) MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(CMD_NORMALIZE_URI, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_NORMALIZE_URI), data, reply, option); if (err != DATA_SHARE_NO_ERROR) { LOG_ERROR("NormalizeUri fail to SendRequest. err: %{public}d", err); return Uri(""); @@ -429,7 +443,8 @@ Uri DataShareProxy::DenormalizeUri(const Uri &uri) MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(CMD_DENORMALIZE_URI, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_DENORMALIZE_URI), data, reply, option); if (err != DATA_SHARE_NO_ERROR) { LOG_ERROR("DenormalizeUri fail to SendRequest. err: %{public}d", err); return Uri(""); @@ -444,4 +459,4 @@ Uri DataShareProxy::DenormalizeUri(const Uri &uri) return info; } } // namespace DataShare -} // namespace OHOS \ No newline at end of file +} // namespace OHOS diff --git a/data_share/frameworks/native/provider/src/datashare_stub.cpp b/data_share/frameworks/native/provider/src/datashare_stub.cpp index 03ff16b1..019359dc 100644 --- a/data_share/frameworks/native/provider/src/datashare_stub.cpp +++ b/data_share/frameworks/native/provider/src/datashare_stub.cpp @@ -22,26 +22,31 @@ #include "ishared_result_set.h" #include "unistd.h" +using namespace OHOS::DistributedShare::DataShare; + namespace OHOS { namespace DataShare { constexpr int DEFAULT_NUMBER = -1; constexpr int PERMISSION_ERROR_NUMBER = -2; DataShareStub::DataShareStub() { - stubFuncMap_[CMD_GET_FILE_TYPES] = &DataShareStub::CmdGetFileTypes; - stubFuncMap_[CMD_OPEN_FILE] = &DataShareStub::CmdOpenFile; - stubFuncMap_[CMD_OPEN_RAW_FILE] = &DataShareStub::CmdOpenRawFile; - stubFuncMap_[CMD_INSERT] = &DataShareStub::CmdInsert; - stubFuncMap_[CMD_UPDATE] = &DataShareStub::CmdUpdate; - stubFuncMap_[CMD_DELETE] = &DataShareStub::CmdDelete; - stubFuncMap_[CMD_QUERY] = &DataShareStub::CmdQuery; - stubFuncMap_[CMD_GET_TYPE] = &DataShareStub::CmdGetType; - stubFuncMap_[CMD_BATCH_INSERT] = &DataShareStub::CmdBatchInsert; - stubFuncMap_[CMD_REGISTER_OBSERVER] = &DataShareStub::CmdRegisterObserver; - stubFuncMap_[CMD_UNREGISTER_OBSERVER] = &DataShareStub::CmdUnregisterObserver; - stubFuncMap_[CMD_NOTIFY_CHANGE] = &DataShareStub::CmdNotifyChange; - stubFuncMap_[CMD_NORMALIZE_URI] = &DataShareStub::CmdNormalizeUri; - stubFuncMap_[CMD_DENORMALIZE_URI] = &DataShareStub::CmdDenormalizeUri; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_GET_FILE_TYPES)] = &DataShareStub::CmdGetFileTypes; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_OPEN_FILE)] = &DataShareStub::CmdOpenFile; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_OPEN_RAW_FILE)] = &DataShareStub::CmdOpenRawFile; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_INSERT)] = &DataShareStub::CmdInsert; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_UPDATE)] = &DataShareStub::CmdUpdate; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_DELETE)] = &DataShareStub::CmdDelete; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_QUERY)] = &DataShareStub::CmdQuery; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_GET_TYPE)] = &DataShareStub::CmdGetType; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_BATCH_INSERT)] = &DataShareStub::CmdBatchInsert; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_REGISTER_OBSERVER)] = + &DataShareStub::CmdRegisterObserver; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_UNREGISTER_OBSERVER)] = + &DataShareStub::CmdUnregisterObserver; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_NOTIFY_CHANGE)] = &DataShareStub::CmdNotifyChange; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_NORMALIZE_URI)] = &DataShareStub::CmdNormalizeUri; + stubFuncMap_[static_cast(IDataShareInterfaceCode::CMD_DENORMALIZE_URI)] = + &DataShareStub::CmdDenormalizeUri; } DataShareStub::~DataShareStub() diff --git a/data_share/frameworks/native/provider/src/js_datashare_ext_ability.cpp b/data_share/frameworks/native/provider/src/js_datashare_ext_ability.cpp index 7e95f706..de48819b 100644 --- a/data_share/frameworks/native/provider/src/js_datashare_ext_ability.cpp +++ b/data_share/frameworks/native/provider/src/js_datashare_ext_ability.cpp @@ -32,6 +32,8 @@ #include "napi_remote_object.h" #include "system_ability_definition.h" +using namespace OHOS::DistributedShare::DataShare; + namespace OHOS { namespace DataShare { using namespace AbilityRuntime; @@ -882,7 +884,8 @@ void JsDataShareExtAbility::NotifyToDataShareService() LOG_ERROR("Write descriptor failed!"); return; } - remote->SendRequest(IDataShareService::DATA_SHARE_SERVICE_CMD_NOTIFY, data, reply, option); + remote->SendRequest( + static_cast(DataShareServiceInterfaceCode::DATA_SHARE_SERVICE_CMD_NOTIFY), data, reply, option); } bool MakeNapiColumn(napi_env env, napi_value &napiColumns, const std::vector &columns) diff --git a/data_share/frameworks/native/proxy/include/data_share_service_proxy.h b/data_share/frameworks/native/proxy/include/data_share_service_proxy.h index 41340503..23690e91 100644 --- a/data_share/frameworks/native/proxy/include/data_share_service_proxy.h +++ b/data_share/frameworks/native/proxy/include/data_share_service_proxy.h @@ -67,6 +67,7 @@ public: std::vector DisableSubscribePublishedData( const std::vector &uris, int64_t subscriberId) override; + void Notify(const std::string &uri) override; private: static inline BrokerDelegator delegator_; diff --git a/data_share/frameworks/native/proxy/include/published_data_subscriber_manager.h b/data_share/frameworks/native/proxy/include/published_data_subscriber_manager.h index d24f11f7..a5db17c4 100644 --- a/data_share/frameworks/native/proxy/include/published_data_subscriber_manager.h +++ b/data_share/frameworks/native/proxy/include/published_data_subscriber_manager.h @@ -92,10 +92,13 @@ public: void Emit(PublishedDataChangeNode &changeNode); private: + void Emit(const std::vector &keys, const std::shared_ptr &observer); + void Emit(std::map>> &obsMap); PublishedDataSubscriberManager(); bool Init(); void Destroy(); sptr serviceCallback_; + std::map lastChangeNodeMap_; }; } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/proxy/include/rdb_subscriber_manager.h b/data_share/frameworks/native/proxy/include/rdb_subscriber_manager.h index 47462d09..45e296c5 100644 --- a/data_share/frameworks/native/proxy/include/rdb_subscriber_manager.h +++ b/data_share/frameworks/native/proxy/include/rdb_subscriber_manager.h @@ -93,10 +93,13 @@ public: void Emit(const RdbChangeNode &changeNode); private: + void Emit(const std::vector &keys, const std::shared_ptr &observer); + void Emit(std::map>> &obsMap); RdbSubscriberManager(); bool Init(); void Destroy(); sptr serviceCallback_; + std::map lastChangeNodeMap_; }; } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/proxy/src/data_share_service_proxy.cpp b/data_share/frameworks/native/proxy/src/data_share_service_proxy.cpp index 2f874640..ef0ddd8a 100644 --- a/data_share/frameworks/native/proxy/src/data_share_service_proxy.cpp +++ b/data_share/frameworks/native/proxy/src/data_share_service_proxy.cpp @@ -21,6 +21,8 @@ namespace OHOS { namespace DataShare { +using InterfaceCode = OHOS::DistributedShare::DataShare::DataShareServiceInterfaceCode; + DataShareServiceProxy::DataShareServiceProxy(const sptr &object) : IRemoteProxy(object) { @@ -42,7 +44,8 @@ int32_t DataShareServiceProxy::Insert(const Uri &uri, const DataShareValuesBucke MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_INSERT, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_INSERT), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("Insert fail to SendRequest. uri: %{public}s, err: %{public}d", uriStr.c_str(), err); return DATA_SHARE_ERROR; @@ -66,7 +69,8 @@ int32_t DataShareServiceProxy::Update(const Uri &uri, MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_UPDATE, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_UPDATE), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("Update fail to SendRequest. uri: %{public}s, err: %{public}d", uriStr.c_str(), err); return DATA_SHARE_ERROR; @@ -89,7 +93,8 @@ int32_t DataShareServiceProxy::Delete(const Uri &uri, const DataSharePredicates MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_DELETE, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_DELETE), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("Delete fail to SendRequest. uri: %{public}s, err: %{public}d", uriStr.c_str(), err); return DATA_SHARE_ERROR; @@ -114,7 +119,8 @@ std::shared_ptr DataShareServiceProxy::Query(const Uri &uri, MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_QUERY, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_QUERY), data, reply, option); auto result = ISharedResultSet::ReadFromParcel(reply); businessError.SetCode(reply.ReadInt32()); @@ -139,7 +145,8 @@ int DataShareServiceProxy::AddQueryTemplate(const std::string &uri, int64_t subs MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_ADD_TEMPLATE, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_ADD_TEMPLATE), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("AddTemplate fail to SendRequest. uri: %{public}s, err: %{public}d", uri.c_str(), err); return DATA_SHARE_ERROR; @@ -161,7 +168,8 @@ int DataShareServiceProxy::DelQueryTemplate(const std::string &uri, int64_t subs MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_DEL_TEMPLATE, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_DEL_TEMPLATE), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("AddTemplate fail to SendRequest. uri: %{public}s, err: %{public}d", uri.c_str(), err); return DATA_SHARE_ERROR; @@ -184,7 +192,8 @@ std::vector DataShareServiceProxy::Publish(const Data &data, co MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_PUBLISH, parcel, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_PUBLISH), parcel, reply, option); if (err != NO_ERROR) { LOG_ERROR("Publish fail to SendRequest. err: %{public}d", err); return results; @@ -209,7 +218,8 @@ Data DataShareServiceProxy::GetPublishedData(const std::string &bundleName, int MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_GET_DATA, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_GET_DATA), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("AddTemplate fail to SendRequest, err: %{public}d", err); return results; @@ -239,7 +249,8 @@ std::vector DataShareServiceProxy::SubscribeRdbData(const std:: MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_SUBSCRIBE_RDB, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_SUBSCRIBE_RDB), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("SubscribeRdbData fail to SendRequest. err: %{public}d", err); return results; @@ -265,7 +276,8 @@ std::vector DataShareServiceProxy::UnSubscribeRdbData( MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_UNSUBSCRIBE_RDB, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_UNSUBSCRIBE_RDB), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("fail to SendRequest. err: %{public}d", err); return results; @@ -291,7 +303,8 @@ std::vector DataShareServiceProxy::EnableSubscribeRdbData( MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_ENABLE_SUBSCRIBE_RDB, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_ENABLE_SUBSCRIBE_RDB), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("fail to SendRequest. err: %{public}d", err); return results; @@ -317,7 +330,8 @@ std::vector DataShareServiceProxy::DisableSubscribeRdbData( MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_DISABLE_SUBSCRIBE_RDB, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_DISABLE_SUBSCRIBE_RDB), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("AddTemplate fail to SendRequest. err: %{public}d", err); return results; @@ -346,7 +360,8 @@ std::vector DataShareServiceProxy::SubscribePublishedData( MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_SUBSCRIBE_PUBLISHED, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_SUBSCRIBE_PUBLISHED), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("AddTemplate fail to SendRequest. err: %{public}d", err); return results; @@ -371,7 +386,8 @@ std::vector DataShareServiceProxy::UnSubscribePublishedData( MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_UNSUBSCRIBE_PUBLISHED, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_UNSUBSCRIBE_PUBLISHED), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("AddTemplate fail to SendRequest. err: %{public}d", err); return results; @@ -396,7 +412,8 @@ std::vector DataShareServiceProxy::EnableSubscribePublishedData MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_ENABLE_SUBSCRIBE_PUBLISHED, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_ENABLE_SUBSCRIBE_PUBLISHED), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("AddTemplate fail to SendRequest. err: %{public}d", err); return results; @@ -421,7 +438,8 @@ std::vector DataShareServiceProxy::DisableSubscribePublishedDat MessageParcel reply; MessageOption option; - int32_t err = Remote()->SendRequest(DATA_SHARE_SERVICE_CMD_DISABLE_SUBSCRIBE_PUBLISHED, data, reply, option); + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_DISABLE_SUBSCRIBE_PUBLISHED), data, reply, option); if (err != NO_ERROR) { LOG_ERROR("AddTemplate fail to SendRequest. err: %{public}d", err); return results; @@ -429,5 +447,27 @@ std::vector DataShareServiceProxy::DisableSubscribePublishedDat ITypesUtil::Unmarshal(reply, results); return results; } + +void DataShareServiceProxy::Notify(const std::string &uri) +{ + MessageParcel data; + if (!data.WriteInterfaceToken(IDataShareService::GetDescriptor())) { + LOG_ERROR("Write descriptor failed!"); + return; + } + if (!ITypesUtil::Marshal(data, uri)) { + LOG_ERROR("Write to message parcel failed!"); + return; + } + + MessageParcel reply; + MessageOption option; + int32_t err = Remote()->SendRequest( + static_cast(InterfaceCode::DATA_SHARE_SERVICE_CMD_NOTIFY_OBSERVERS), data, reply, option); + if (err != NO_ERROR) { + LOG_ERROR("Notify fail to SendRequest. err: %{public}d", err); + return; + } +} } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/proxy/src/published_data_subscriber_manager.cpp b/data_share/frameworks/native/proxy/src/published_data_subscriber_manager.cpp index 59f75d18..01a49f2e 100644 --- a/data_share/frameworks/native/proxy/src/published_data_subscriber_manager.cpp +++ b/data_share/frameworks/native/proxy/src/published_data_subscriber_manager.cpp @@ -32,7 +32,11 @@ std::vector PublishedDataSubscriberManager::AddObservers(void * std::for_each(uris.begin(), uris.end(), [&keys, &subscriberId](auto &uri) { keys.emplace_back(uri, subscriberId); }); - return BaseCallbacks::AddObservers(keys, subscriber, std::make_shared(callback), + return BaseCallbacks::AddObservers( + keys, subscriber, std::make_shared(callback), + [this](const std::vector &localRegisterKeys, const std::shared_ptr observer) { + Emit(localRegisterKeys, observer); + }, [&proxy, subscriber, &subscriberId, this](const std::vector &firstAddKeys, const std::shared_ptr observer, std::vector &opResult) { std::vector firstAddUris; @@ -72,6 +76,7 @@ std::vector PublishedDataSubscriberManager::DelObservers(void * // delete all obs by subscriber std::map> keysMap; for (auto const &key : lastDelKeys) { + lastChangeNodeMap_.erase(key); keysMap[key.subscriberId_].emplace_back(key.uri_); } for (auto const &[subscriberId, uris] : keysMap) { @@ -100,7 +105,8 @@ std::vector PublishedDataSubscriberManager::DelObservers(void * return BaseCallbacks::DelObservers(keys, subscriber, [&proxy, &subscriberId, this](const std::vector &lastDelKeys, std::vector &opResult) { std::vector lastDelUris; - std::for_each(lastDelKeys.begin(), lastDelKeys.end(), [&lastDelUris](auto &result) { + std::for_each(lastDelKeys.begin(), lastDelKeys.end(), [&lastDelUris, this](auto &result) { + lastChangeNodeMap_.erase(result); lastDelUris.emplace_back(result); }); if (lastDelUris.empty()) { @@ -127,7 +133,10 @@ std::vector PublishedDataSubscriberManager::EnableObservers(voi std::for_each(uris.begin(), uris.end(), [&keys, &subscriberId](auto &uri) { keys.emplace_back(uri, subscriberId); }); - return BaseCallbacks::EnableObservers(keys, subscriber, + return BaseCallbacks::EnableObservers( + keys, subscriber, [this](std::map>> &obsMap) { + Emit(obsMap); + }, [&proxy, &subscriberId, subscriber, this](const std::vector &firstAddKeys, std::vector &opResult) { std::vector firstAddUris; @@ -204,6 +213,10 @@ void PublishedDataSubscriberManager::RecoverObservers(std::shared_ptr, PublishedDataChangeNode> results; for (auto &data : changeNode.datas_) { PublishedObserverMapKey key(data.key_, data.subscriberId_); @@ -212,6 +225,8 @@ void PublishedDataSubscriberManager::Emit(PublishedDataChangeNode &changeNode) LOG_WARN("%{private}s nobody subscribe, but still notify", data.key_.c_str()); continue; } + lastChangeNodeMap_[key].datas_.emplace_back(data.key_, data.subscriberId_, data.GetData()); + lastChangeNodeMap_[key].ownerBundleName_ = changeNode.ownerBundleName_; for (auto const &obs : callbacks) { results[obs].datas_.emplace_back(data.key_, data.subscriberId_, data.GetData()); } @@ -222,6 +237,43 @@ void PublishedDataSubscriberManager::Emit(PublishedDataChangeNode &changeNode) } } +void PublishedDataSubscriberManager::Emit(const std::vector &keys, const std::shared_ptr &observer) +{ + PublishedDataChangeNode node; + for (auto &key : keys) { + auto it = lastChangeNodeMap_.find(key); + if (it == lastChangeNodeMap_.end()) { + continue; + } + for (auto &data : it->second.datas_) { + node.datas_.emplace_back(data.key_, data.subscriberId_, data.GetData()); + } + node.ownerBundleName_ = it->second.ownerBundleName_; + } + observer->OnChange(node); +} + +void PublishedDataSubscriberManager::Emit(std::map>> &obsMap) +{ + std::map, PublishedDataChangeNode> results; + for (auto &[key, obsVector] : obsMap) { + auto it = lastChangeNodeMap_.find(key); + if (it == lastChangeNodeMap_.end()) { + continue; + } + for (auto &data : it->second.datas_) { + PublishedObserverMapKey mapKey(data.key_, data.subscriberId_); + for (auto &obs : obsVector) { + results[obs].datas_.emplace_back(data.key_, data.subscriberId_, data.GetData()); + results[obs].ownerBundleName_ = it->second.ownerBundleName_; + } + } + } + for (auto &[callback, node] : results) { + callback->OnChange(node); + } +} + bool PublishedDataSubscriberManager::Init() { if (serviceCallback_ == nullptr) { diff --git a/data_share/frameworks/native/proxy/src/rdb_subscriber_manager.cpp b/data_share/frameworks/native/proxy/src/rdb_subscriber_manager.cpp index 6ffb4208..88692dc0 100644 --- a/data_share/frameworks/native/proxy/src/rdb_subscriber_manager.cpp +++ b/data_share/frameworks/native/proxy/src/rdb_subscriber_manager.cpp @@ -43,7 +43,11 @@ std::vector RdbSubscriberManager::AddObservers(void *subscriber std::for_each(uris.begin(), uris.end(), [&keys, &templateId](auto &uri) { keys.emplace_back(uri, templateId); }); - return BaseCallbacks::AddObservers(keys, subscriber, std::make_shared(callback), + return BaseCallbacks::AddObservers( + keys, subscriber, std::make_shared(callback), + [this](const std::vector &localRegisterKeys, const std::shared_ptr observer) { + Emit(localRegisterKeys, observer); + }, [&proxy, subscriber, &templateId, this](const std::vector &firstAddKeys, const std::shared_ptr observer, std::vector &opResult) { std::vector firstAddUris; @@ -89,8 +93,9 @@ std::vector RdbSubscriberManager::DelObservers(void *subscriber return BaseCallbacks::DelObservers(keys, subscriber, [&proxy, &templateId, this](const std::vector &lastDelKeys, std::vector &opResult) { std::vector lastDelUris; - std::for_each(lastDelKeys.begin(), lastDelKeys.end(), [&lastDelUris](auto &result) { + std::for_each(lastDelKeys.begin(), lastDelKeys.end(), [&lastDelUris, this](auto &result) { lastDelUris.emplace_back(result); + lastChangeNodeMap_.erase(result); }); if (lastDelUris.empty()) { return; @@ -116,6 +121,7 @@ std::vector RdbSubscriberManager::DelObservers(void *subscriber [&proxy, this](const std::vector &lastDelKeys, std::vector &opResult) { // delete all obs by subscriber for (const auto &key : lastDelKeys) { + lastChangeNodeMap_.erase(key); auto unsubResult = proxy->UnSubscribeRdbData(std::vector(1, key.uri_), key.templateId_); opResult.insert(opResult.end(), unsubResult.begin(), unsubResult.end()); } @@ -135,6 +141,9 @@ std::vector RdbSubscriberManager::EnableObservers(void *subscri keys.emplace_back(uri, templateId); }); return BaseCallbacks::EnableObservers(keys, subscriber, + [this](std::map>> &obsMap) { + Emit(obsMap); + }, [&proxy, subscriber, &templateId, this](const std::vector &firstAddKeys, std::vector &opResult) { std::vector firstAddUris; @@ -182,7 +191,6 @@ std::vector RdbSubscriberManager::DisableObservers(void *subscr auto results = proxy->DisableSubscribeRdbData(lastDisabledUris, templateId); opResult.insert(opResult.end(), results.begin(), results.end()); - Destroy(); }); } @@ -212,6 +220,7 @@ void RdbSubscriberManager::RecoverObservers(std::shared_ptr &keys, const std::shared_ptr &observer) +{ + for (auto const &key : keys) { + auto it = lastChangeNodeMap_.find(key); + if (it != lastChangeNodeMap_.end()) { + observer->OnChange(it->second); + } + } +} + +void RdbSubscriberManager::Emit(std::map>> &obsMap) +{ + for (auto &[key, obsVector] : obsMap) { + auto it = lastChangeNodeMap_.find(key); + if (it == lastChangeNodeMap_.end()) { + continue; + } + for (auto &obs : obsVector) { + obs->OnChange(it->second); + } + } +} + bool RdbSubscriberManager::Init() { if (serviceCallback_ == nullptr) { diff --git a/data_share/interfaces/inner_api/BUILD.gn b/data_share/interfaces/inner_api/BUILD.gn index bb6d232c..5ac401be 100644 --- a/data_share/interfaces/inner_api/BUILD.gn +++ b/data_share/interfaces/inner_api/BUILD.gn @@ -86,7 +86,7 @@ ohos_shared_library("datashare_consumer") { "ability_runtime:dataobs_manager", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "ipc_js:rpc", "napi:ace_napi", @@ -127,7 +127,7 @@ ohos_shared_library("datashare_provider") { "access_token:libaccesstoken_sdk", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "ipc_js:rpc", "napi:ace_napi", @@ -154,7 +154,7 @@ ohos_shared_library("datashare_ext_ability_module") { "ability_runtime:runtime", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] relative_install_dir = "extensionability/" diff --git a/data_share/interfaces/inner_api/common/BUILD.gn b/data_share/interfaces/inner_api/common/BUILD.gn index 14d97ae0..878748b1 100644 --- a/data_share/interfaces/inner_api/common/BUILD.gn +++ b/data_share/interfaces/inner_api/common/BUILD.gn @@ -73,10 +73,10 @@ ohos_shared_library("datashare_common") { "ability_base:zuri", "ability_runtime:abilitykit_native", "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", "ipc:ipc_napi_common", "ipc:ipc_single", "napi:ace_napi", diff --git a/data_share/test/native/BUILD.gn b/data_share/test/native/BUILD.gn index dbb1d37d..00e5a302 100644 --- a/data_share/test/native/BUILD.gn +++ b/data_share/test/native/BUILD.gn @@ -68,8 +68,8 @@ ohos_unittest("NativeDataShareTest") { "access_token:libtoken_setproc", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hilog_native:libhilog", - "hitrace_native:hitrace_meter", + "hilog:libhilog", + "hitrace:hitrace_meter", "ipc:ipc_single", "media_library:media_library", "relational_store:rdb_data_ability_adapter", @@ -107,7 +107,7 @@ ohos_unittest("SlientAccessTest") { "access_token:libtoken_setproc", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "safwk:system_ability_fwk", "samgr:samgr_proxy", diff --git a/datamgr_service/BUILD.gn b/datamgr_service/BUILD.gn index f2510207..e759bcf1 100644 --- a/datamgr_service/BUILD.gn +++ b/datamgr_service/BUILD.gn @@ -29,6 +29,9 @@ group("fuzztest") { testonly = true deps = [] deps += [ + "services/distributeddataservice/adapter/test:fuzztest", + "services/distributeddataservice/app/test/fuzztest:fuzztest", + "services/distributeddataservice/service/test/fuzztest:fuzztest", "test/fuzztest/autolaunch_fuzzer:fuzztest", "test/fuzztest/kvstoredisksize_fuzzer:fuzztest", ] diff --git a/datamgr_service/bundle.json b/datamgr_service/bundle.json index 683a81f1..3b5839ad 100644 --- a/datamgr_service/bundle.json +++ b/datamgr_service/bundle.json @@ -39,7 +39,8 @@ "subsystem": "distributeddatamgr", "syscap": [], "features": [ - "datamgr_service_config" + "datamgr_service_config", + "datamgr_service_udmf" ], "adapted_system_type": [ "standard" @@ -55,7 +56,6 @@ "ability_runtime", "access_token", "bundle_framework", - "common", "common_event_service", "c_utils", "dataclassification", @@ -63,26 +63,25 @@ "device_auth", "device_manager", "dsoftbus", - "hisysevent_native", - "hitrace_native", - "hiviewdfx_hilog_native", + "hilog", + "hisysevent", + "hitrace", "huks", - "init", "kv_store", "ipc", "napi", "os_account", "relational_store", "safwk", - "samgr" + "samgr", + "udmf" ], "third_party": [ "cjson", + "jsoncpp", + "libuv", "openssl", "sqlite", - "libuv", - "libz", - "jsoncpp", "zlib" ] }, diff --git a/datamgr_service/datamgr_service.gni b/datamgr_service/datamgr_service.gni index 3a7b7e96..ac2f5ccb 100644 --- a/datamgr_service/datamgr_service.gni +++ b/datamgr_service/datamgr_service.gni @@ -32,6 +32,12 @@ ipc_core_path = "//foundation/communication/ipc/interfaces/innerkits/ipc_core" device_manager_path = "//foundation/distributedhardware/device_manager" +data_service_path = "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice" + +udmf_path = "//foundation/distributeddatamgr/udmf" + +dataobject_path = "//foundation/distributeddatamgr/data_object" + declare_args() { datamgr_service_power = true if (!defined(global_parts_info.power_manager_native_powermgr_client) || @@ -47,4 +53,6 @@ declare_args() { } datamgr_service_config = true + + datamgr_service_udmf = false } diff --git a/datamgr_service/services/distributeddataservice/adapter/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/BUILD.gn index 515866a6..7c5cebe1 100644 --- a/datamgr_service/services/distributeddataservice/adapter/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/BUILD.gn @@ -52,10 +52,10 @@ ohos_shared_library("distributeddata_adapter") { external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", ] public_configs = [ ":distributeddata_adapter_public_config" ] diff --git a/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn index d2a449b8..e9428651 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn @@ -42,7 +42,7 @@ ohos_static_library("distributeddata_account_static") { "ability_base:want", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] if (os_account_part_is_enabled) { diff --git a/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn index fa8c3d6e..34a2846e 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn @@ -38,7 +38,7 @@ ohos_unittest("AccountDelegateTest") { "ability_base:want", "bundle_framework:appexecfwk_base", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] diff --git a/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn index fe0fc348..472bef0c 100644 --- a/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn @@ -30,13 +30,12 @@ ohos_static_library("distributeddata_broadcaster_static") { cflags_cc = [ "-fvisibility=hidden" ] external_deps = [ - # "ces:libcommonevent", "ability_base:base", "ability_base:want", "bundle_framework:appexecfwk_base", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] subsystem_name = "distributeddatamgr" diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn index be70a5dd..451b8de6 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn @@ -58,7 +58,7 @@ ohos_static_library("distributeddata_communicator_static") { "c_utils:utils", "device_manager:devicemanagersdk", "dsoftbus:softbus_client", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] subsystem_name = "distributeddatamgr" diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn index a3fa43ac..b3dbad12 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn @@ -30,7 +30,7 @@ ohos_unittest("CommunicationProviderTest") { ] external_deps = [ "dsoftbus:softbus_client", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] deps = [ @@ -55,7 +55,7 @@ ohos_unittest("DeviceManagerAdapterTest") { ] external_deps = [ "dsoftbus:softbus_client", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] deps = [ diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/BUILD.gn new file mode 100644 index 00000000..dacf421d --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/BUILD.gn @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +######################################################################################### +group("fuzztest") { + testonly = true + + deps = [ "softbusadapter_fuzzer:fuzztest" ] +} diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/BUILD.gn new file mode 100644 index 00000000..25df6bdb --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/BUILD.gn @@ -0,0 +1,68 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +##############################hydra-fuzz######################################## +import("//build/config/features.gni") +import("//build/test.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +##############################fuzztest########################################## +ohos_fuzztest("SoftBusAdapterFuzzTest") { + module_out_path = "datamgr_service/adapter" + + include_dirs = [ + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", + "${data_service_path}/adapter/include/log", + "${data_service_path}/adapter/include/autils", + "${data_service_path}/adapter/include/utils", + "${data_service_path}/adapter/communicator/src", + "${dsoftbus_core_path}", + "${kv_store_common_path}", + "${kv_store_distributeddb_path}/interfaces/include", + "${kv_store_distributeddb_path}/include", + "${kv_store_distributeddb_path}/interfaces/include/relational", + "${kv_store_path}/interfaces/innerkits/distributeddata/include", + ] + + fuzz_config_file = "${data_service_path}/adapter/communicator/test/fuzztest/softbusadapter_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ "softbusadapter_fuzzer.cpp" ] + + deps = [ + "${data_service_path}/adapter/communicator:distributeddata_communicator_static", + "${data_service_path}/adapter/dfx:distributeddata_dfx_static", + "${data_service_path}/adapter/utils:distributeddata_utils_static", + ] + + external_deps = [ + "c_utils:utils", + "device_manager:devicemanagersdk", + "dsoftbus:softbus_client", + "hilog:libhilog", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + + deps = [ ":SoftBusAdapterFuzzTest" ] +} +############################################################################### diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/corpus/init b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/corpus/init new file mode 100644 index 00000000..2b595da0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/project.xml b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/project.xml new file mode 100644 index 00000000..3fdba3e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/softbusadapter_fuzzer.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/softbusadapter_fuzzer.cpp new file mode 100644 index 00000000..cc972106 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/softbusadapter_fuzzer.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "softbusadapter_fuzzer.h" + +#include +#include + +#include "softbus_adapter_standard.cpp" +#include "message_parcel.h" +#include "securec.h" + +using namespace OHOS::AppDistributedKv; + +namespace OHOS { +bool OnBytesReceivedFuzz(const uint8_t *data, size_t size) +{ + int connId = static_cast(*data); + unsigned int dataLen = static_cast(size); + AppDataListenerWrap::OnBytesReceived(connId, data, dataLen); + return true; +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return 0; + } + + OHOS::OnBytesReceivedFuzz(data, size); + + return 0; +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/softbusadapter_fuzzer.h b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/softbusadapter_fuzzer.h new file mode 100644 index 00000000..d77e3037 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/softbusadapter_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SOFTBUSADAPTER_FUZZER_H +#define SOFTBUSADAPTER_FUZZER_H + +#define FUZZ_PROJECT_NAME "softbusadapter_fuzzer" + +#endif // SOFTBUSADAPTER_FUZZER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn index 2818cae4..9d23ea69 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn @@ -44,10 +44,10 @@ ohos_static_library("distributeddata_dfx_static") { deps = [ "//third_party/openssl:libcrypto_shared" ] external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn index 4b4df71f..fe26d017 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn @@ -41,9 +41,9 @@ ohos_unittest("DistributeddataDfxMSTTest") { external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", ] ldflags = [ "-Wl,--exclude-libs,ALL" ] deps = [ @@ -99,9 +99,9 @@ ohos_unittest("DistributeddataDfxUTTest") { external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", ] ldflags = [ "-Wl,--exclude-libs,ALL" ] deps = [ diff --git a/datamgr_service/services/distributeddataservice/adapter/permission/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/permission/BUILD.gn index 48e77927..2c478746 100644 --- a/datamgr_service/services/distributeddataservice/adapter/permission/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/permission/BUILD.gn @@ -35,7 +35,7 @@ ohos_static_library("distributeddata_permission_static") { external_deps = [ "access_token:libaccesstoken_sdk", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" diff --git a/datamgr_service/services/distributeddataservice/adapter/permission/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/permission/test/BUILD.gn index a19f4c30..509f49b3 100644 --- a/datamgr_service/services/distributeddataservice/adapter/permission/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/permission/test/BUILD.gn @@ -42,7 +42,7 @@ ohos_unittest("PermissionValidatorTest") { "//third_party/googletest:gtest_main", ] - external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + external_deps = [ "hilog:libhilog" ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/test/BUILD.gn index 206f581e..f85ada83 100644 --- a/datamgr_service/services/distributeddataservice/adapter/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/test/BUILD.gn @@ -24,3 +24,9 @@ group("unittest") { "../permission/test:unittest", ] } + +group("fuzztest") { + testonly = true + + deps = [ "../communicator/test/fuzztest:fuzztest" ] +} diff --git a/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn index b57d430b..6442a139 100644 --- a/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn @@ -35,7 +35,7 @@ ohos_static_library("distributeddata_utils_static") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" diff --git a/datamgr_service/services/distributeddataservice/app/BUILD.gn b/datamgr_service/services/distributeddataservice/app/BUILD.gn index 5df04bdd..607c6732 100644 --- a/datamgr_service/services/distributeddataservice/app/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/BUILD.gn @@ -118,10 +118,10 @@ ohos_shared_library("distributeddataservice") { "bundle_framework:appexecfwk_core", "c_utils:utils", "dataclassification:data_transit_mgr", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", "ipc:ipc_core", "kv_store:distributeddata_inner", "safwk:system_ability_fwk", diff --git a/datamgr_service/services/distributeddataservice/app/CMakeLists.txt b/datamgr_service/services/distributeddataservice/app/CMakeLists.txt index 017b7ac7..262fa5da 100644 --- a/datamgr_service/services/distributeddataservice/app/CMakeLists.txt +++ b/datamgr_service/services/distributeddataservice/app/CMakeLists.txt @@ -38,7 +38,6 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../adapter/include/utils) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../service/bootstrap/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../service/config/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../service/crypto/include) -include_directories(../framework/directory/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../service/permission/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../service/rdb) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../service/kvdb) diff --git a/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn b/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn index 1f59492c..0cb0a4f8 100644 --- a/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn @@ -40,7 +40,7 @@ ohos_static_library("distributeddata_checker_static") { "bundle_framework:appexecfwk_base", "bundle_framework:appexecfwk_core", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", "samgr:samgr_proxy", ] diff --git a/datamgr_service/services/distributeddataservice/app/src/uninstaller/BUILD.gn b/datamgr_service/services/distributeddataservice/app/src/uninstaller/BUILD.gn index 04daeef7..54196c83 100644 --- a/datamgr_service/services/distributeddataservice/app/src/uninstaller/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/src/uninstaller/BUILD.gn @@ -42,14 +42,12 @@ ohos_static_library("distributeddata_uninstaller_static") { ] external_deps = [ + "ability_base:want", "bundle_framework:appexecfwk_base", "c_utils:utils", - - # "ces:libcommonevent", - "ability_base:want", "common_event_service:cesfwk_innerkits", "dataclassification:data_transit_mgr", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", "safwk:system_ability_fwk", "samgr:samgr_proxy", diff --git a/datamgr_service/services/distributeddataservice/app/test/BUILD.gn b/datamgr_service/services/distributeddataservice/app/test/BUILD.gn index 3ce6b41d..f471e188 100644 --- a/datamgr_service/services/distributeddataservice/app/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/test/BUILD.gn @@ -87,10 +87,10 @@ ohos_unittest("KvStoreDataServiceTest") { "c_utils:utils", "dataclassification:data_transit_mgr", "device_auth:deviceauth_sdk", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", "ipc:ipc_core", "safwk:system_ability_fwk", "samgr:samgr_proxy", @@ -138,7 +138,7 @@ ohos_unittest("SessionManagerTest") { "c_utils:utils", "dataclassification:data_transit_mgr", "device_auth:deviceauth_sdk", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", "safwk:system_ability_fwk", "samgr:samgr_proxy", @@ -177,7 +177,7 @@ ohos_unittest("KvStoreFlowCtrlManagerTest") { "c_utils:utils", "dataclassification:data_transit_mgr", "device_auth:deviceauth_sdk", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", "safwk:system_ability_fwk", "samgr:samgr_proxy", diff --git a/datamgr_service/services/distributeddataservice/app/test/fuzztest/BUILD.gn b/datamgr_service/services/distributeddataservice/app/test/fuzztest/BUILD.gn new file mode 100644 index 00000000..d7c29a7a --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/test/fuzztest/BUILD.gn @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +######################################################################################### +group("fuzztest") { + testonly = true + + deps = [ "dataservicestub_fuzzer:fuzztest" ] +} diff --git a/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/BUILD.gn new file mode 100644 index 00000000..3e594bee --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/BUILD.gn @@ -0,0 +1,116 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +##############################hydra-fuzz######################################## +import("//build/config/features.gni") +import("//build/test.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +##############################fuzztest########################################## +ohos_fuzztest("DataServiceStubFuzzTest") { + module_out_path = "datamgr_service/app" + + include_dirs = [ + "${kv_store_common_path}", + "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/service/config/include", + "${data_service_path}/service/crypto/include", + "${data_service_path}/service/directory/include", + "${data_service_path}/service/permission/include", + "${data_service_path}/service/matrix/include", + "${data_service_path}/app/src", + "${data_service_path}/app/src/backup_rule/include", + "${data_service_path}/app/src/checker", + "${data_service_path}/app/src/flowctrl_manager", + "${data_service_path}/app/src/security", + "${data_service_path}/app/src/session_manager", + "${data_service_path}/app/src/uninstaller", + "${data_service_path}/framework/include", + "${data_service_path}/service/backup/include", + "${data_service_path}/service/kvdb", + "${data_service_path}/adapter/include/account", + "${data_service_path}/adapter/include/permission", + "${data_service_path}/adapter/include/uninstaller", + "${data_service_path}/adapter/include/broadcaster", + "${data_service_path}/adapter/include/utils", + "${data_service_path}/adapter/include/dfx", + "${data_service_path}/adapter/include", + "${device_manager_path}/interfaces/inner_kits/native_cpp/include", + "${distributedfilejs_path}/interfaces/kits/js/src/mod_securitylabel", + "//third_party/json/single_include", + ] + + fuzz_config_file = + "${data_service_path}/app/test/fuzztest/dataservicestub_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ + "${data_service_path}/app/src/dump_helper.cpp", + "${data_service_path}/app/src/feature_stub_impl.cpp", + "${data_service_path}/app/src/kvstore_account_observer.cpp", + "${data_service_path}/app/src/kvstore_data_service.cpp", + "${data_service_path}/app/src/kvstore_device_listener.cpp", + "${data_service_path}/app/src/kvstore_meta_manager.cpp", + "${data_service_path}/app/src/security/security.cpp", + "${data_service_path}/app/src/security/sensitive.cpp", + "${data_service_path}/app/src/session_manager/route_head_handler_impl.cpp", + "${data_service_path}/app/src/session_manager/session_manager.cpp", + "${data_service_path}/app/src/session_manager/upgrade_manager.cpp", + "${data_service_path}/app/src/task_manager.cpp", + "dataservicestub_fuzzer.cpp", + ] + + deps = [ + "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster_static", + "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/app/src/checker:distributeddata_checker_static", + "${data_service_path}/app/src/flowctrl_manager:distributeddata_flowctrl_static", + "${data_service_path}/app/src/uninstaller:distributeddata_uninstaller_static", + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service:distributeddatasvc", + "${kv_store_distributeddb_path}:distributeddb", + ] + + external_deps = [ + "ability_base:base", + "ability_base:want", + "access_token:libaccesstoken_sdk", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "dataclassification:data_transit_mgr", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + + deps = [ ":DataServiceStubFuzzTest" ] +} +############################################################################### diff --git a/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/corpus/init b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/corpus/init new file mode 100644 index 00000000..2b595da0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/dataservicestub_fuzzer.cpp b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/dataservicestub_fuzzer.cpp new file mode 100644 index 00000000..e5164c94 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/dataservicestub_fuzzer.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dataservicestub_fuzzer.h" + +#include +#include + +#include "kvstore_data_service.h" +#include "message_parcel.h" +#include "securec.h" + +using namespace OHOS::DistributedKv; + +namespace OHOS { +const std::u16string INTERFACE_TOKEN = u"OHOS.DistributedKv.IKvStoreDataService"; +const uint32_t CODE_MIN = 0; +const uint32_t CODE_MAX = 10; + +bool OnRemoteRequestFuzz(const uint8_t *data, size_t size) +{ + uint32_t code = static_cast(*data) % (CODE_MAX - CODE_MIN + 1) + CODE_MIN; + MessageParcel request; + request.WriteInterfaceToken(INTERFACE_TOKEN); + request.WriteBuffer(data, size); + request.RewindRead(0); + MessageParcel reply; + MessageOption option; + std::shared_ptr kvStoreDataServiceStub = std::make_shared(); + kvStoreDataServiceStub->OnRemoteRequest(code, request, reply, option); + return true; +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return 0; + } + + OHOS::OnRemoteRequestFuzz(data, size); + + return 0; +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/dataservicestub_fuzzer.h b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/dataservicestub_fuzzer.h new file mode 100644 index 00000000..02e3b8df --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/dataservicestub_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DATAMGR_SERVICE_DATA_SERVICE_STUB_FUZZER_H +#define DATAMGR_SERVICE_DATA_SERVICE_STUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "dataservicestub_fuzzer" + +#endif // DATAMGR_SERVICE_DATA_SERVICE_STUB_FUZZER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/project.xml b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/project.xml new file mode 100644 index 00000000..3fdba3e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/BUILD.gn b/datamgr_service/services/distributeddataservice/framework/BUILD.gn index b09c9c74..b13f8c45 100644 --- a/datamgr_service/services/distributeddataservice/framework/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/framework/BUILD.gn @@ -90,7 +90,7 @@ ohos_shared_library("distributeddatasvcfwk") { external_deps = [ "access_token:libaccesstoken_sdk", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] subsystem_name = "distributeddatamgr" diff --git a/datamgr_service/services/distributeddataservice/framework/cloud/sync_event.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/sync_event.cpp index 7c2d3d93..f165e4f7 100644 --- a/datamgr_service/services/distributeddataservice/framework/cloud/sync_event.cpp +++ b/datamgr_service/services/distributeddataservice/framework/cloud/sync_event.cpp @@ -16,8 +16,8 @@ #include "cloud/sync_event.h" namespace OHOS::DistributedData { -SyncEvent::EventInfo::EventInfo(int32_t mode, int32_t wait, std::shared_ptr query, GenAsync async) - : mode_(mode), wait_(wait), query_(std::move(query)), asyncDetail_(std::move(async)) +SyncEvent::EventInfo::EventInfo(int32_t mode, int32_t wait, bool retry, std::shared_ptr query, GenAsync async) + : retry_(retry), mode_(mode), wait_(wait), query_(std::move(query)), asyncDetail_(std::move(async)) { } @@ -31,6 +31,7 @@ SyncEvent::EventInfo &SyncEvent::EventInfo::operator=(SyncEvent::EventInfo &&inf if (this == &info) { return *this; } + retry_ = info.retry_; mode_ = info.mode_; wait_ = info.wait_; query_ = std::move(info.query_); @@ -58,6 +59,11 @@ int32_t SyncEvent::GetWait() const return info_.wait_; } +bool SyncEvent::AutoRetry() const +{ + return info_.retry_; +} + std::shared_ptr SyncEvent::GetQuery() const { return info_.query_; diff --git a/datamgr_service/services/distributeddataservice/framework/include/cloud/sync_event.h b/datamgr_service/services/distributeddataservice/framework/include/cloud/sync_event.h index 351a919a..fb25f1a3 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/cloud/sync_event.h +++ b/datamgr_service/services/distributeddataservice/framework/include/cloud/sync_event.h @@ -23,13 +23,14 @@ class API_EXPORT SyncEvent : public CloudEvent { public: class EventInfo { public: - API_EXPORT EventInfo(int32_t mode, int32_t wait, std::shared_ptr query, GenAsync async); + API_EXPORT EventInfo(int32_t mode, int32_t wait, bool retry, std::shared_ptr query, GenAsync async); API_EXPORT EventInfo(EventInfo &&info) noexcept; EventInfo(const EventInfo &info) = default; API_EXPORT EventInfo &operator=(EventInfo &&info) noexcept; EventInfo &operator=(const EventInfo &info) = default; private: friend SyncEvent; + bool retry_ = false; int32_t mode_ = -1; int32_t wait_ = 0; std::shared_ptr query_; @@ -39,6 +40,7 @@ public: ~SyncEvent() override = default; int32_t GetMode() const; int32_t GetWait() const; + bool AutoRetry() const; std::shared_ptr GetQuery() const; GenAsync GetAsyncDetail() const; diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h b/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h index 0ee2012a..0da33a6e 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h +++ b/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h @@ -43,6 +43,12 @@ public: CLOUD_END, MODE_BUTT = CLOUD_END, }; + enum CleanMode { + NEARBY_DATA = 0, + CLOUD_DATA, + CLOUD_INFO, + LOCAL_DATA, + }; struct BindInfo { BindInfo(std::shared_ptr db = nullptr, std::shared_ptr loader = nullptr) @@ -72,6 +78,8 @@ public: virtual int32_t Sync(const Devices &devices, int32_t mode, GenQuery &query, DetailAsync async, int32_t wait) = 0; + virtual int32_t Clean(const std::vector &devices, int32_t mode, const std::string &tableName) = 0; + virtual int32_t Watch(int32_t origin, Watcher &watcher) = 0; virtual int32_t Unwatch(int32_t origin, Watcher &watcher) = 0; diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h b/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h index c482b940..4bf696fe 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h +++ b/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h @@ -32,10 +32,10 @@ enum GenProgress { }; struct GenStatistic { - int32_t total; - int32_t success; - int32_t failed; - int32_t untreated; + uint32_t total; + uint32_t success; + uint32_t failed; + uint32_t untreated; }; struct GenTableDetail { diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/general_watcher.h b/datamgr_service/services/distributeddataservice/framework/include/store/general_watcher.h index 4583aa9d..bcf226d6 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/store/general_watcher.h +++ b/datamgr_service/services/distributeddataservice/framework/include/store/general_watcher.h @@ -29,7 +29,13 @@ public: ORIGIN_ALL, ORIGIN_BUTT, }; + enum DataType : int32_t { + BASIC_DATA, + ASSET_DATA, + TYPE_BUTT, + }; int32_t origin = ORIGIN_BUTT; + int32_t dataType = BASIC_DATA; // origin is ORIGIN_LOCAL, the id is empty // origin is ORIGIN_NEARBY, the id is networkId; // origin is ORIGIN_CLOUD, the id is the cloud account id @@ -43,7 +49,7 @@ public: OP_BUTT, }; // PK primary key - using PRIValue = std::variant; + using PRIValue = std::variant; using PRIFields = std::map; using ChangeInfo = std::map[OP_BUTT]>; virtual ~GeneralWatcher() = default; diff --git a/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn b/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn index 1e2ccfa5..ba131185 100644 --- a/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn @@ -37,7 +37,7 @@ ohos_unittest("CheckerManagerTest") { "access_token:libaccesstoken_sdk", "access_token:libnativetoken", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] @@ -60,7 +60,7 @@ ohos_unittest("EventCenterTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] @@ -83,7 +83,7 @@ ohos_unittest("SerializableTest") { "ability_base:base", "ability_base:want", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] diff --git a/datamgr_service/services/distributeddataservice/service/BUILD.gn b/datamgr_service/services/distributeddataservice/service/BUILD.gn index 4fbe91e3..42b0e4b6 100644 --- a/datamgr_service/services/distributeddataservice/service/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/BUILD.gn @@ -16,6 +16,10 @@ import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") group("build_module") { deps = [ ":distributeddatasvc" ] + + if (datamgr_service_udmf) { + deps += [ "${data_service_path}/service/udmf:udmf_server" ] + } } config("module_public_config") { visibility = [ ":*" ] @@ -124,7 +128,7 @@ ohos_shared_library("distributeddatasvc") { "c_utils:utils", "device_auth:deviceauth_sdk", "device_manager:devicemanagersdk", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "huks:libhukssdk", "ipc:ipc_core", "kv_store:distributeddata_inner", diff --git a/datamgr_service/services/distributeddataservice/service/CMakeLists.txt b/datamgr_service/services/distributeddataservice/service/CMakeLists.txt index b872f11b..c04eacd4 100644 --- a/datamgr_service/services/distributeddataservice/service/CMakeLists.txt +++ b/datamgr_service/services/distributeddataservice/service/CMakeLists.txt @@ -14,7 +14,6 @@ aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/backup/src serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/bootstrap/src serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/config/src serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/config/src/model serviceSrc) -aux_source_directory(../framework/directory/src serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/crypto/src serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/rdb serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/kvdb serviceSrc) @@ -40,7 +39,6 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/backup/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/config/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/crypto/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/bootstrap/include) -include_directories(../framework/directory/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/permission/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/matrix/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/data_share/common) @@ -73,6 +71,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../adapter/include/security) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../adapter/include/utils) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../app/src) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../relational_store/interfaces/inner_api/appdatafwk/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../relational_store/interfaces/inner_api/cloud_data/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../relational_store/interfaces/inner_api/rdb/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../relational_store/interfaces/inner_api/rdb_data_share_adapter/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../relational_store/interfaces/inner_api/rdb_bms_adapter/include) diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp index 547ed074..844f2ed3 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "CloudServiceImpl" #include "cloud_service_impl.h" - +#include "accesstoken_kit.h" #include "account/account_delegate.h" #include "checker/checker_manager.h" #include "cloud/cloud_server.h" @@ -29,10 +29,13 @@ #include "runtime_config.h" #include "store/auto_cache.h" #include "utils/anonymous.h" +#include "sync_manager.h" namespace OHOS::CloudData { using namespace DistributedData; +using namespace std::chrono; using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter; using Account = OHOS::DistributedKv::AccountDelegate; +using AccessTokenKit = Security::AccessToken::AccessTokenKit; __attribute__((used)) CloudServiceImpl::Factory CloudServiceImpl::factory_; const CloudServiceImpl::Work CloudServiceImpl::HANDLERS[WORK_BUTT] = { &CloudServiceImpl::DoSubscribe, @@ -122,14 +125,8 @@ int32_t CloudServiceImpl::ChangeAppSwitch(const std::string &id, const std::stri return SUCCESS; } -int32_t CloudServiceImpl::Clean(const std::string &id, const std::map &actions) +int32_t CloudServiceImpl::DoClean(CloudInfo &cloudInfo, const std::map &actions) { - CloudInfo cloudInfo; - auto tokenId = IPCSkeleton::GetCallingTokenID(); - cloudInfo.user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(tokenId); - if (GetCloudInfoFromMeta(cloudInfo) != SUCCESS) { - return ERROR; - } syncManager_.StopCloudSync(cloudInfo.user); auto keys = cloudInfo.GetSchemaKey(); for (const auto &[bundle, action] : actions) { @@ -137,13 +134,56 @@ int32_t CloudServiceImpl::Clean(const std::string &id, const std::mapClean({}, action, ""); + if (status != E_OK) { + ZLOGW("remove device data status:%{public}d, user:%{pubilc}d, bundleName:%{public}s, " + "storeId:%{public}s", + status, static_cast(cloudInfo.user), meta.bundleName.c_str(), meta.GetStoreAlias().c_str()); + continue; + } } } return SUCCESS; } +int32_t CloudServiceImpl::Clean(const std::string &id, const std::map &actions) +{ + CloudInfo cloudInfo; + auto tokenId = IPCSkeleton::GetCallingTokenID(); + cloudInfo.user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(tokenId); + if (GetCloudInfoFromMeta(cloudInfo) != SUCCESS) { + ZLOGE("get cloud meta failed user:%{public}d", static_cast(cloudInfo.user)); + return ERROR; + } + if (id != cloudInfo.id) { + ZLOGE("different id, [server] id:%{public}s, [meta] id:%{public}s", Anonymous::Change(cloudInfo.id).c_str(), + Anonymous::Change(id).c_str()); + } + return DoClean(cloudInfo, actions); +} + int32_t CloudServiceImpl::NotifyDataChange(const std::string &id, const std::string &bundleName) { CloudInfo cloudInfo; @@ -254,14 +294,21 @@ bool CloudServiceImpl::UpdateCloudInfo(int32_t user) return true; } if (oldInfo.id != cloudInfo.id) { - ZLOGE("different id, [server] id:%{public}s, [meta] id:%{public}s", - Anonymous::Change(cloudInfo.id).c_str(), Anonymous::Change(oldInfo.id).c_str()); + ZLOGE("different id, [server] id:%{public}s, [meta] id:%{public}s", Anonymous::Change(cloudInfo.id).c_str(), + Anonymous::Change(oldInfo.id).c_str()); std::map actions; for (auto &[bundle, app] : cloudInfo.apps) { actions[bundle] = CLEAR_CLOUD_INFO; } + DoClean(oldInfo, actions); + } + if (cloudInfo.enableCloud) { + for (auto &[bundle, app] : cloudInfo.apps) { + if (app.cloudSwitch && !oldInfo.apps[bundle].cloudSwitch) { + syncManager_.DoCloudSync({ cloudInfo.user, bundle }); + } + } } - MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true); return true; } @@ -426,8 +473,8 @@ bool CloudServiceImpl::DoSubscribe(int32_t user) ZLOGD("begin cloud:%{public}d user:%{public}d apps:%{public}zu", cloudInfo.enableCloud, sub.userId, cloudInfo.apps.size()); - auto onThreshold = (std::chrono::system_clock::now() + std::chrono::hours(EXPIRE_INTERVAL)).time_since_epoch(); - auto offThreshold = std::chrono::system_clock::now().time_since_epoch(); + auto onThreshold = duration_cast((system_clock::now() + hours(EXPIRE_INTERVAL)).time_since_epoch()); + auto offThreshold = duration_cast(system_clock::now().time_since_epoch()); std::map> subDbs; std::map> unsubDbs; for (auto &[bundle, app] : cloudInfo.apps) { diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h index 554d8301..31599142 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h @@ -80,6 +80,7 @@ private: ExecutorPool::Task GenTask(int32_t retry, int32_t user, AsyncWork work); void Execute(Tasks tasks); bool DoSubscribe(int32_t user); + int32_t DoClean(CloudInfo &cloudInfo, const std::map &actions); std::shared_ptr executor_; SyncManager syncManager_; static const Work HANDLERS[WORK_BUTT]; diff --git a/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.cpp b/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.cpp index 20eb8637..8bc0025d 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.cpp @@ -28,12 +28,15 @@ namespace OHOS::CloudData { using namespace DistributedData; using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter; +using Defer = EventCenter::Defer; +std::atomic SyncManager::genId_ = 0; SyncManager::SyncInfo::SyncInfo(int32_t user, const std::string &bundleName, const Store &store, const Tables &tables) : user_(user), bundleName_(bundleName) { if (!store.empty()) { tables_[store] = tables; } + syncId_ = SyncManager::GenerateId(user); } SyncManager::SyncInfo::SyncInfo(int32_t user, const std::string &bundleName, const Stores &stores) @@ -42,11 +45,14 @@ SyncManager::SyncInfo::SyncInfo(int32_t user, const std::string &bundleName, con for (auto &store : stores) { tables_[store] = {}; } + syncId_ = SyncManager::GenerateId(user); } SyncManager::SyncInfo::SyncInfo(int32_t user, const std::string &bundleName, const MutliStoreTables &tables) : user_(user), bundleName_(bundleName), tables_(tables) { + tables_ = tables; + syncId_ = SyncManager::GenerateId(user); } void SyncManager::SyncInfo::SetMode(int32_t mode) @@ -69,7 +75,7 @@ void SyncManager::SyncInfo::SetQuery(std::shared_ptr query) query_ = query; } -void SyncManager::SyncInfo::SetError(int32_t code) +void SyncManager::SyncInfo::SetError(int32_t code) const { if (async_) { GenDetails details; @@ -136,8 +142,8 @@ int32_t SyncManager::DoCloudSync(SyncInfo syncInfo) return E_NOT_INIT; } - actives_.Compute(GenSyncId(syncInfo.user_), [this, &syncInfo](const uint64_t &key, TaskId &taskId) mutable { - taskId = executor_->Execute(GetSyncTask(0, GenSyncRef(key), std::move(syncInfo))); + actives_.Compute(GenerateId(syncInfo.user_), [this, &syncInfo](const uint64_t &key, TaskId &taskId) mutable { + taskId = executor_->Execute(GetSyncTask(0, true, GenSyncRef(key), std::move(syncInfo))); return true; }); @@ -158,11 +164,11 @@ int32_t SyncManager::StopCloudSync(int32_t user) return E_OK; } -ExecutorPool::Task SyncManager::GetSyncTask(int32_t retry, RefCount ref, SyncInfo &&syncInfo) +ExecutorPool::Task SyncManager::GetSyncTask(int32_t times, bool retry, RefCount ref, SyncInfo &&syncInfo) { - retry++; - return [this, retry, ref = std::move(ref), info = std::move(syncInfo)]() mutable { - EventCenter::Defer defer(GetSyncHandler(), CloudEvent::CLOUD_SYNC); + times++; + return [this, times, retry, ref = std::move(ref), info = std::move(syncInfo)]() mutable { + activeInfos_.Erase(info.syncId_); CloudInfo cloud; cloud.user = info.user_; if (!MetaDataManager::GetInstance().LoadMeta(cloud.GetKey(), cloud, true)) { @@ -179,11 +185,14 @@ ExecutorPool::Task SyncManager::GetSyncTask(int32_t retry, RefCount ref, SyncInf std::vector schemas; auto key = cloud.GetSchemaPrefix(info.bundleName_); + auto retryer = GetRetryer(times, info); if (!MetaDataManager::GetInstance().LoadMeta(key, schemas, true)) { - DoRetry(retry, std::move(info)); + UpdateSchema(info); + retryer(RETRY_INTERVAL, E_RETRY_TIMEOUT); return; } + Defer defer(GetSyncHandler(std::move(retryer)), CloudEvent::CLOUD_SYNC); for (auto &schema : schemas) { if (!cloud.IsOn(schema.bundleName)) { continue; @@ -197,24 +206,18 @@ ExecutorPool::Task SyncManager::GetSyncTask(int32_t retry, RefCount ref, SyncInf storeInfo.instanceId = cloud.apps[schema.bundleName].instanceId; auto query = info.GenerateQuery(database.name, database.GetTableNames()); auto evt = std::make_unique(std::move(storeInfo), - SyncEvent::EventInfo { info.mode_, info.wait_, std::move(query), info.async_ }); + SyncEvent::EventInfo { info.mode_, info.wait_, retry, std::move(query), info.async_ }); EventCenter::GetInstance().PostEvent(std::move(evt)); } } }; } -std::function SyncManager::GetSyncHandler() +std::function SyncManager::GetSyncHandler(Retryer retryer) { - return [](const Event &event) { + return [retryer](const Event &event) { auto &evt = static_cast(event); auto &storeInfo = evt.GetStoreInfo(); - auto instance = CloudServer::GetInstance(); - if (instance == nullptr) { - ZLOGD("not support cloud sync"); - return; - } - StoreMetaData meta; meta.storeId = storeInfo.storeName; meta.bundleName = storeInfo.bundleName; @@ -226,35 +229,32 @@ std::function SyncManager::GetSyncHandler() meta.GetStoreAlias().c_str()); return; } - auto store = AutoCache::GetInstance().GetStore(meta, {}); + auto store = GetStore(meta, storeInfo.user); if (store == nullptr) { ZLOGE("store null, storeId:%{public}s", meta.GetStoreAlias().c_str()); return; } - if (!store->IsBound()) { - CloudInfo info; - info.user = storeInfo.user; - SchemaMeta schemaMeta; - std::string schemaKey = info.GetSchemaKey(storeInfo.bundleName, storeInfo.instanceId); - if (!MetaDataManager::GetInstance().LoadMeta(std::move(schemaKey), schemaMeta, true)) { - ZLOGE("failed, no schema bundleName:%{public}s, storeId:%{public}s", storeInfo.bundleName.c_str(), - Anonymous::Change(storeInfo.storeName).c_str()); - return; - } - auto dbMeta = schemaMeta.GetDataBase(storeInfo.storeName); - auto cloudDB = instance->ConnectCloudDB(meta.tokenId, dbMeta); - auto assetLoader = instance->ConnectAssetLoader(meta.tokenId, dbMeta); - if (cloudDB == nullptr || assetLoader == nullptr) { - ZLOGE("failed, no cloud DB or no assetLoader <0x%{public}x %{public}s<->%{public}s>", storeInfo.tokenId, - dbMeta.name.c_str(), dbMeta.alias.c_str()); - return; + ZLOGD("database:<%{public}d:%{public}s:%{public}s> sync start", storeInfo.user, storeInfo.bundleName.c_str(), + meta.GetStoreAlias().c_str()); + auto status = store->Sync({ SyncInfo::DEFAULT_ID }, evt.GetMode(), *(evt.GetQuery()), evt.AutoRetry() + ? [retryer](const GenDetails &details) { + if (details.empty()) { + ZLOGE("retry, details empty"); + return; + } + int32_t code = details.begin()->second.code; + retryer(code == E_ALREADY_LOCKED ? LOCKED_INTERVAL : RETRY_INTERVAL, code); } - store->Bind(dbMeta, {cloudDB, assetLoader}); + : evt.GetAsyncDetail(), evt.GetWait()); + GenAsync async = evt.GetAsyncDetail(); + if (status != E_OK && async) { + GenDetails details; + auto &detail = details[SyncInfo::DEFAULT_ID]; + detail.progress = SYNC_FINISH; + detail.code = status; + async(std::move(details)); } - ZLOGD("database:<%{public}d:%{public}s:%{public}s> sync start", storeInfo.user, storeInfo.bundleName.c_str(), - Anonymous::Change(storeInfo.storeName).c_str()); - store->Sync({ SyncInfo::DEFAULT_ID }, evt.GetMode(), *(evt.GetQuery()), evt.GetAsyncDetail(), evt.GetWait()); }; } @@ -268,15 +268,44 @@ std::function SyncManager::GetClientChangeHandler() syncInfo.SetWait(evt.GetWait()); syncInfo.SetAsyncDetail(evt.GetAsyncDetail()); syncInfo.SetQuery(evt.GetQuery()); - auto task = GetSyncTask(RETRY_TIMES, RefCount(), std::move(syncInfo)); + auto times = evt.AutoRetry() ? RETRY_TIMES - CLIENT_RETRY_TIMES : RETRY_TIMES; + auto task = GetSyncTask(times, evt.AutoRetry(), RefCount(), std::move(syncInfo)); task(); }; } -uint64_t SyncManager::GenSyncId(int32_t user) +SyncManager::Retryer SyncManager::GetRetryer(int32_t times, const SyncInfo &syncInfo) +{ + if (times >= RETRY_TIMES) { + return [info = SyncInfo(syncInfo)](Duration, int32_t code) mutable { + if (code == E_OK) { + return true; + } + info.SetError(code); + return true; + }; + } + return [this, times, info = SyncInfo(syncInfo)](Duration interval, int32_t code) mutable { + if (code == E_OK) { + return true; + } + + activeInfos_.ComputeIfAbsent(info.syncId_, [this, times, interval, &info](uint64_t key) mutable { + auto syncId = GenerateId(info.user_); + actives_.Compute(syncId, [this, times, interval, &info](const uint64_t &key, TaskId &value) mutable { + value = executor_->Schedule(interval, GetSyncTask(times, true, GenSyncRef(key), std::move(info))); + return true; + }); + return syncId; + }); + return true; + }; +} + +uint64_t SyncManager::GenerateId(int32_t user) { uint64_t syncId = static_cast(user) & 0xFFFFFFFF; - return (syncId << MV_BIT) | (++syncId_); + return (syncId << MV_BIT) | (++genId_); } RefCount SyncManager::GenSyncRef(uint64_t syncId) @@ -292,19 +321,51 @@ int32_t SyncManager::Compare(uint64_t syncId, int32_t user) return (syncId & USER_MARK) == (inner << MV_BIT); } -void SyncManager::DoRetry(int32_t retry, SyncInfo &&info) +void SyncManager::UpdateSchema(const SyncManager::SyncInfo &syncInfo) { CloudEvent::StoreInfo storeInfo; - storeInfo.user = info.user_; - storeInfo.bundleName = info.bundleName_; + storeInfo.user = syncInfo.user_; + storeInfo.bundleName = syncInfo.bundleName_; EventCenter::GetInstance().PostEvent(std::make_unique(CloudEvent::GET_SCHEMA, storeInfo)); - if (retry > RETRY_TIMES) { - info.SetError(E_RETRY_TIMEOUT); - return; +} + +AutoCache::Store SyncManager::GetStore(const StoreMetaData &meta, int32_t user, bool mustBind) +{ + auto instance = CloudServer::GetInstance(); + if (instance == nullptr) { + ZLOGD("not support cloud sync"); + return nullptr; } - actives_.Compute(GenSyncId(info.user_), [this, retry, &info](const uint64_t &key, TaskId &value) mutable { - value = executor_->Schedule(RETRY_INTERVAL, GetSyncTask(retry, GenSyncRef(key), std::move(info))); - return true; - }); + + auto store = AutoCache::GetInstance().GetStore(meta, {}); + if (store == nullptr) { + ZLOGE("store null, storeId:%{public}s", meta.GetStoreAlias().c_str()); + return nullptr; + } + + if (!store->IsBound()) { + CloudInfo info; + info.user = user; + SchemaMeta schemaMeta; + std::string schemaKey = info.GetSchemaKey(meta.bundleName, meta.instanceId); + if (!MetaDataManager::GetInstance().LoadMeta(std::move(schemaKey), schemaMeta, true)) { + ZLOGE("failed, no schema bundleName:%{public}s, storeId:%{public}s", meta.bundleName.c_str(), + meta.GetStoreAlias().c_str()); + return nullptr; + } + auto dbMeta = schemaMeta.GetDataBase(meta.storeId); + auto cloudDB = instance->ConnectCloudDB(meta.tokenId, dbMeta); + auto assetLoader = instance->ConnectAssetLoader(meta.tokenId, dbMeta); + if (mustBind && (cloudDB == nullptr || assetLoader == nullptr)) { + ZLOGE("failed, no cloud DB <0x%{public}x %{public}s<->%{public}s>", meta.tokenId, dbMeta.name.c_str(), + dbMeta.alias.c_str()); + return nullptr; + } + + if (cloudDB != nullptr || assetLoader != nullptr) { + store->Bind(dbMeta, { std::move(cloudDB), std::move(assetLoader) }); + } + } + return store; } } // namespace OHOS::CloudData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.h b/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.h index b08fcf4a..5f19611d 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.h +++ b/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.h @@ -17,6 +17,7 @@ #define OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_SYNC_MANAGER_H #include "eventcenter/event.h" #include "executor_pool.h" +#include "store/auto_cache.h" #include "store/general_store.h" #include "store/general_value.h" #include "utils/ref_count.h" @@ -28,6 +29,9 @@ public: using GenStore = DistributedData::GeneralStore; using GenQuery = DistributedData::GenQuery; using RefCount = DistributedData::RefCount; + using AutoCache = DistributedData::AutoCache; + using StoreMetaData = DistributedData::StoreMetaData; + static AutoCache::Store GetStore(const StoreMetaData &meta, int32_t user, bool mustBind = true); class SyncInfo final { public: using Store = std::string; @@ -41,12 +45,13 @@ public: void SetWait(int32_t wait); void SetAsyncDetail(GenAsync asyncDetail); void SetQuery(std::shared_ptr query); - void SetError(int32_t code); + void SetError(int32_t code) const; std::shared_ptr GenerateQuery(const std::string &store, const Tables &tables); inline static constexpr const char *DEFAULT_ID = "default"; private: friend SyncManager; + uint64_t syncId_ = 0; int32_t mode_ = GenStore::CLOUD_TIME_FIRST; int32_t user_ = 0; int32_t wait_ = 0; @@ -66,22 +71,29 @@ private: using Event = DistributedData::Event; using Task = ExecutorPool::Task; using TaskId = ExecutorPool::TaskId; + using Duration = ExecutorPool::Duration; + using Retryer = std::function; + static constexpr ExecutorPool::Duration RETRY_INTERVAL = std::chrono::seconds(10); // second - static constexpr int32_t RETRY_TIMES = 6; // second + static constexpr ExecutorPool::Duration LOCKED_INTERVAL = std::chrono::seconds(30); // second + static constexpr int32_t RETRY_TIMES = 6; // normal retry + static constexpr int32_t CLIENT_RETRY_TIMES = 3; // normal retry static constexpr uint64_t USER_MARK = 0xFFFFFFFF00000000; // high 32 bit static constexpr int32_t MV_BIT = 32; - Task GetSyncTask(int32_t retry, RefCount ref, SyncInfo &&syncInfo); - void DoRetry(int32_t retry, SyncInfo &&info); - std::function GetSyncHandler(); + Task GetSyncTask(int32_t times, bool retry, RefCount ref, SyncInfo &&syncInfo); + void UpdateSchema(const SyncInfo &syncInfo); + std::function GetSyncHandler(Retryer retryer); std::function GetClientChangeHandler(); - uint64_t GenSyncId(int32_t user); + Retryer GetRetryer(int32_t times, const SyncInfo &syncInfo); + static uint64_t GenerateId(int32_t user); RefCount GenSyncRef(uint64_t syncId); int32_t Compare(uint64_t syncId, int32_t user); - std::atomic syncId_ = 0; + static std::atomic genId_; std::shared_ptr executor_; ConcurrentMap actives_; + ConcurrentMap activeInfos_; }; } // namespace OHOS::CloudData #endif // OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_SYNC_MANAGER_H diff --git a/datamgr_service/services/distributeddataservice/service/data_share/BUILD.gn b/datamgr_service/services/distributeddataservice/service/data_share/BUILD.gn index 2d8ffad4..8cb08cb8 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/data_share/BUILD.gn @@ -68,6 +68,7 @@ ohos_shared_library("data_share_service") { "strategies/insert_strategy.cpp", "strategies/publish_strategy.cpp", "strategies/query_strategy.cpp", + "strategies/rdb_notify_strategy.cpp", "strategies/subscribe_strategy.cpp", "strategies/template_strategy.cpp", "strategies/update_strategy.cpp", @@ -99,7 +100,7 @@ ohos_shared_library("data_share_service") { "c_utils:utils", "data_share:datashare_common", "device_manager:devicemanagersdk", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", "relational_store:native_rdb", "relational_store:rdb_bms_adapter", diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/kv_delegate.cpp b/datamgr_service/services/distributeddataservice/service/data_share/common/kv_delegate.cpp index d0736685..9e36164a 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/kv_delegate.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/kv_delegate.cpp @@ -138,9 +138,9 @@ int32_t KvDelegate::Get(const std::string &collectionName, const Id &id, std::st std::string filter = DistributedData::Serializable::Marshall(id); if (Get(collectionName, filter, "{}", value) != E_OK) { ZLOGE("Get failed, %{public}s %{public}s", collectionName.c_str(), filter.c_str()); - return false; + return E_ERROR; } - return true; + return E_OK; } bool KvDelegate::GetVersion(const std::string &collectionName, const std::string &filter, int &version) diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.cpp index a3cb46ed..416b27c9 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.cpp @@ -16,6 +16,7 @@ #include "published_data.h" #include "log_print.h" +#include "subscriber_managers/published_data_subscriber_manager.h" namespace OHOS::DataShare { bool PublishedData::HasVersion() const @@ -33,8 +34,7 @@ std::string PublishedData::GetValue() const return DistributedData::Serializable::Marshall(value); } -PublishedData::PublishedData(const PublishedDataNode &node, const int version) - : PublishedData(node) +PublishedData::PublishedData(const PublishedDataNode &node, const int version) : PublishedData(node) { value.SetVersion(version); } @@ -84,10 +84,13 @@ bool PublishedDataNode::Unmarshal(const DistributedData::Serializable::json &nod bool ret = GetValue(node, GET_NAME(key), key); ret = ret && GetValue(node, GET_NAME(bundleName), bundleName); ret = ret && GetValue(node, GET_NAME(subscriberId), subscriberId); - ret = ret && GetValue(node, GET_NAME(value), value); + if (ret) { + GetValue(node, GET_NAME(value), value); + VersionData::Unmarshal(node); + } ret = ret && GetValue(node, GET_NAME(timestamp), timestamp); ret = ret && GetValue(node, GET_NAME(userId), userId); - return ret && VersionData::Unmarshal(node); + return ret; } PublishedDataNode::PublishedDataNode(const std::string &key, const std::string &bundleName, int64_t subscriberId, @@ -159,7 +162,10 @@ void PublishedData::ClearAging() return; } std::vector queryResults; - int32_t status = delegate->GetBatch(KvDBDelegate::DATA_TABLE, "{}", "{}", queryResults); + int32_t status = delegate->GetBatch(KvDBDelegate::DATA_TABLE, "{}", + "{\"id_\": true, \"timestamp\": true, \"key\": true, \"bundleName\": true, \"subscriberId\": true, " + "\"userId\": true}", + queryResults); if (status != E_OK) { ZLOGE("db GetBatch failed %{public}d", status); return; @@ -171,8 +177,8 @@ void PublishedData::ClearAging() ZLOGE("Unmarshall %{public}s failed", result.c_str()); continue; } - - if (data.timestamp < lastValidTime) { + if (data.timestamp < lastValidTime && PublishedDataSubscriberManager::GetInstance() + .GetCount(PublishedDataKey(data.key, data.bundleName, data.subscriberId)) == 0) { status = delegate->Delete(KvDBDelegate::DATA_TABLE, Id(PublishedData::GenId(data.key, data.bundleName, data.subscriberId), data.userId)); if (status != E_OK) { @@ -186,4 +192,36 @@ void PublishedData::ClearAging() } return; } + +void PublishedData::UpdateTimestamp( + const std::string &key, const std::string &bundleName, int64_t subscriberId, const int32_t userId) +{ + auto delegate = KvDBDelegate::GetInstance(); + if (delegate == nullptr) { + ZLOGE("db open failed"); + return; + } + std::string queryResult; + int32_t status = + delegate->Get(KvDBDelegate::DATA_TABLE, Id(GenId(key, bundleName, subscriberId), userId), queryResult); + if (status != E_OK) { + ZLOGE("db Get failed, %{private}s %{public}d", queryResult.c_str(), status); + return; + } + PublishedDataNode data; + if (!PublishedDataNode::Unmarshall(queryResult, data)) { + ZLOGE("Unmarshall failed, %{private}s", queryResult.c_str()); + return; + } + auto now = time(nullptr); + if (now <= 0) { + ZLOGE("time failed"); + return; + } + data.timestamp = now; + status = delegate->Upsert(KvDBDelegate::DATA_TABLE, PublishedData(data)); + if (status == E_OK) { + ZLOGI("update timestamp %{private}s", data.key.c_str()); + } +} } // namespace OHOS::DataShare \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.h b/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.h index aba9ee9f..cff038a3 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.h @@ -42,6 +42,8 @@ public: explicit PublishedData(const PublishedDataNode &node); static std::vector Query(const std::string &bundleName, int32_t userId); static void Delete(const std::string &bundleName, const int32_t userId); + static void UpdateTimestamp( + const std::string &key, const std::string &bundleName, int64_t subscriberId, const int32_t userId); static void ClearAging(); static int32_t Query(const std::string &filter, PublishedDataNode::Data &publishedData); static std::string GenId(const std::string &key, const std::string &bundleName, int64_t subscriberId); @@ -51,6 +53,7 @@ public: int GetVersion() const override; std::string GetValue() const override; friend class GetDataStrategy; + private: PublishedDataNode value; }; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp index 48f23f91..568c1046 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp @@ -214,7 +214,7 @@ std::vector DataShareServiceImpl::SubscribeRdbData( std::vector results; for (const auto &uri : uris) { auto context = std::make_shared(uri); - results.emplace_back(uri, subscribeStrategy_.Execute(context, [&id, &observer, &context, this]() -> bool { + results.emplace_back(uri, subscribeStrategy_.Execute(context, [&id, &observer, &context, this]() { return RdbSubscriberManager::GetInstance().Add( Key(context->uri, id.subscriberId_, id.bundleName_), observer, context, binderInfo_.executors); })); @@ -228,7 +228,7 @@ std::vector DataShareServiceImpl::UnsubscribeRdbData( std::vector results; for (const auto &uri : uris) { auto context = std::make_shared(uri); - results.emplace_back(uri, subscribeStrategy_.Execute(context, [&id, &context]() -> bool { + results.emplace_back(uri, subscribeStrategy_.Execute(context, [&id, &context]() { return RdbSubscriberManager::GetInstance().Delete( Key(context->uri, id.subscriberId_, id.bundleName_), context->callerTokenId); })); @@ -242,7 +242,7 @@ std::vector DataShareServiceImpl::EnableRdbSubs( std::vector results; for (const auto &uri : uris) { auto context = std::make_shared(uri); - results.emplace_back(uri, subscribeStrategy_.Execute(context, [&id, &context]() -> bool { + results.emplace_back(uri, subscribeStrategy_.Execute(context, [&id, &context]() { return RdbSubscriberManager::GetInstance().Enable( Key(context->uri, id.subscriberId_, id.bundleName_), context); })); @@ -256,7 +256,7 @@ std::vector DataShareServiceImpl::DisableRdbSubs( std::vector results; for (const auto &uri : uris) { auto context = std::make_shared(uri); - results.emplace_back(uri, subscribeStrategy_.Execute(context, [&id, &context]() -> bool { + results.emplace_back(uri, subscribeStrategy_.Execute(context, [&id, &context]() { return RdbSubscriberManager::GetInstance().Disable( Key(context->uri, id.subscriberId_, id.bundleName_), context->callerTokenId); })); @@ -281,7 +281,7 @@ std::vector DataShareServiceImpl::SubscribePublishedData(const PublishedDataKey key(uri, callerBundleName, subscriberId); context->callerBundleName = callerBundleName; context->calledBundleName = key.bundleName; - result = subscribeStrategy_.Execute(context, [&subscriberId, &observer, &context]() -> bool { + result = subscribeStrategy_.Execute(context, [&subscriberId, &observer, &context]() { return PublishedDataSubscriberManager::GetInstance().Add( PublishedDataKey(context->uri, context->callerBundleName, subscriberId), observer, context->callerTokenId); @@ -289,6 +289,12 @@ std::vector DataShareServiceImpl::SubscribePublishedData(const results.emplace_back(uri, result); if (result == E_OK) { publishedKeys.emplace_back(context->uri, context->callerBundleName, subscriberId); + if (binderInfo_.executors != nullptr) { + binderInfo_.executors->Execute([context, subscriberId]() { + PublishedData::UpdateTimestamp( + context->uri, context->calledBundleName, subscriberId, context->currentUserId); + }); + } userId = context->currentUserId; } } @@ -312,9 +318,16 @@ std::vector DataShareServiceImpl::UnsubscribePublishedData(cons PublishedDataKey key(uri, callerBundleName, subscriberId); context->callerBundleName = callerBundleName; context->calledBundleName = key.bundleName; - results.emplace_back(uri, subscribeStrategy_.Execute(context, [&subscriberId, &context]() -> bool { - return PublishedDataSubscriberManager::GetInstance().Delete( + results.emplace_back(uri, subscribeStrategy_.Execute(context, [&subscriberId, &context, this]() { + auto result = PublishedDataSubscriberManager::GetInstance().Delete( PublishedDataKey(context->uri, context->callerBundleName, subscriberId), context->callerTokenId); + if (result == E_OK && binderInfo_.executors != nullptr) { + binderInfo_.executors->Execute([context, subscriberId]() { + PublishedData::UpdateTimestamp( + context->uri, context->calledBundleName, subscriberId, context->currentUserId); + }); + } + return result; })); } return results; @@ -337,10 +350,16 @@ std::vector DataShareServiceImpl::EnablePubSubs(const std::vect PublishedDataKey key(uri, callerBundleName, subscriberId); context->callerBundleName = callerBundleName; context->calledBundleName = key.bundleName; - result = subscribeStrategy_.Execute(context, [&subscriberId, &context]() -> bool { + result = subscribeStrategy_.Execute(context, [&subscriberId, &context]() { return PublishedDataSubscriberManager::GetInstance().Enable( PublishedDataKey(context->uri, context->callerBundleName, subscriberId), context->callerTokenId); }); + if (result == E_OK && binderInfo_.executors != nullptr) { + binderInfo_.executors->Execute([context, subscriberId]() { + PublishedData::UpdateTimestamp( + context->uri, context->calledBundleName, subscriberId, context->currentUserId); + }); + } results.emplace_back(uri, result); if (result == E_OK) { publishedKeys.emplace_back(context->uri, context->callerBundleName, subscriberId); @@ -367,9 +386,16 @@ std::vector DataShareServiceImpl::DisablePubSubs(const std::vec PublishedDataKey key(uri, callerBundleName, subscriberId); context->callerBundleName = callerBundleName; context->calledBundleName = key.bundleName; - results.emplace_back(uri, subscribeStrategy_.Execute(context, [&subscriberId, &context]() -> bool { - return PublishedDataSubscriberManager::GetInstance().Disable( + results.emplace_back(uri, subscribeStrategy_.Execute(context, [&subscriberId, &context, this]() { + auto result = PublishedDataSubscriberManager::GetInstance().Disable( PublishedDataKey(context->uri, context->callerBundleName, subscriberId), context->callerTokenId); + if (result == E_OK && binderInfo_.executors != nullptr) { + binderInfo_.executors->Execute([context, subscriberId]() { + PublishedData::UpdateTimestamp( + context->uri, context->calledBundleName, subscriberId, context->currentUserId); + }); + } + return result; })); } return results; @@ -434,4 +460,19 @@ int32_t DataShareServiceImpl::OnAppUninstall( RdbHelper::ClearCache(); return EOK; } + +void DataShareServiceImpl::NotifyObserver(const std::string &uri) +{ + ZLOGD("%{private}s try notified", uri.c_str()); + auto context = std::make_shared(uri); + if (!GetCallerBundleName(context->callerBundleName)) { + ZLOGE("get bundleName error, %{private}s", uri.c_str()); + return; + } + auto ret = rdbNotifyStrategy_.Execute(context); + if (ret) { + ZLOGI("%{private}s start notified", uri.c_str()); + RdbSubscriberManager::GetInstance().Emit(uri, context); + } +} } // namespace OHOS::DataShare diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.h b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.h index 493882da..72d102ca 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.h @@ -27,6 +27,7 @@ #include "insert_strategy.h" #include "publish_strategy.h" #include "query_strategy.h" +#include "rdb_notify_strategy.h" #include "subscribe_strategy.h" #include "template_strategy.h" #include "update_strategy.h" @@ -67,6 +68,7 @@ public: int32_t OnBind(const BindInfo &binderInfo) override; int32_t OnUserChange(uint32_t code, const std::string &user, const std::string &account) override; int32_t OnAppUninstall(const std::string &bundleName, int32_t user, int32_t index, uint32_t tokenId) override; + void NotifyObserver(const std::string &uri) override; private: class Factory { @@ -87,6 +89,7 @@ private: QueryStrategy queryStrategy_; UpdateStrategy updateStrategy_; TemplateStrategy templateStrategy_; + RdbNotifyStrategy rdbNotifyStrategy_; BindInfo binderInfo_; }; } // namespace OHOS::DataShare diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp index 852b874b..99383d08 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp @@ -329,5 +329,16 @@ int DataShareServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, Me } return -1; } + +int32_t DataShareServiceStub::OnRemoteNotifyObserver(MessageParcel &data, MessageParcel &reply) +{ + std::string uri; + if (!ITypesUtil::Unmarshal(data, uri)) { + ZLOGE("read device list failed."); + return -1; + } + NotifyObserver(uri); + return 0; +} } // namespace DataShare } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.h b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.h index d7e1dc27..17ac116a 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.h @@ -44,6 +44,7 @@ private: int32_t OnRemoteEnablePubSubs(MessageParcel& data, MessageParcel& reply); int32_t OnRemoteDisablePubSubs(MessageParcel& data, MessageParcel& reply); int32_t OnRemoteNotifyConnectDone(MessageParcel& data, MessageParcel& reply); + int32_t OnRemoteNotifyObserver(MessageParcel& data, MessageParcel& reply); using RequestHandle = int (DataShareServiceStub::*)(MessageParcel &, MessageParcel &); static constexpr RequestHandle HANDLERS[DATA_SHARE_SERVICE_CMD_MAX] = { &DataShareServiceStub::OnRemoteInsert, @@ -62,7 +63,8 @@ private: &DataShareServiceStub::OnRemoteUnsubscribePublishedData, &DataShareServiceStub::OnRemoteEnablePubSubs, &DataShareServiceStub::OnRemoteDisablePubSubs, - &DataShareServiceStub::OnRemoteNotifyConnectDone }; + &DataShareServiceStub::OnRemoteNotifyConnectDone, + &DataShareServiceStub::OnRemoteNotifyObserver }; }; } // namespace DataShare } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/BUILD.gn b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/BUILD.gn index 47128f8c..293099f3 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/BUILD.gn @@ -82,9 +82,9 @@ ohos_shared_library("gaussdb_rd") { external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", ] subsystem_name = "distributeddatamgr" diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/executor/document/check_common.cpp b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/executor/document/check_common.cpp index 01513f9f..52891fe1 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/executor/document/check_common.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/executor/document/check_common.cpp @@ -155,34 +155,50 @@ int CheckCommon::CheckDocument(JsonObject &documentObj) return E_OK; } -int CheckCommon::CheckUpdata(JsonObject &updataObj, std::vector> &path) +int SplitFieldName(const std::string &fieldName, std::vector &allFieldsName) { - if (updataObj.GetDeep() > JSON_DEEP_MAX) { - GLOGE("projectionObj's json deep is deeper than JSON_DEEP_MAX"); - return -E_INVALID_ARGS; - } - for (size_t i = 0; i < path.size(); i++) { - if (path[i].empty()) { - return -E_INVALID_JSON_FORMAT; + std::string tempParseName; + std::string priFieldName = fieldName; + for (size_t j = 0; j < priFieldName.size(); j++) { + if (priFieldName[j] != '.') { + tempParseName += priFieldName[j]; } - for (size_t j = 0; j < path[i].size(); j++) { - if (path[i][j].empty()) { + if (priFieldName[j] == '.' || j == priFieldName.size() - 1) { + if ((j > 0 && priFieldName[j] == '.' && priFieldName[j - 1] == '.') || + (priFieldName[j] == '.' && j == priFieldName.size() - 1)) { return -E_INVALID_ARGS; } - for (auto oneChar : path[i][j]) { + allFieldsName.emplace_back(tempParseName); + tempParseName.clear(); + } + } + return E_OK; +} + +int CheckCommon::CheckUpdata(JsonObject &updataObj) +{ + JsonObject jsonTemp = updataObj.GetChild(); + size_t maxDeep = 0; + while (!jsonTemp.IsNull()) { + std::vector allFieldsName; + int errCode = SplitFieldName(jsonTemp.GetItemField(), allFieldsName); + if (errCode != E_OK) { + return errCode; + } + for (auto fieldName : allFieldsName) { + for (auto oneChar : fieldName) { if (!((isalpha(oneChar)) || (isdigit(oneChar)) || (oneChar == '_'))) { + GLOGE("updata fieldName is illegal"); return -E_INVALID_ARGS; } } } - if (!path[i].empty() && !path[i][0].empty() && isdigit(path[i][0][0])) { - return -E_INVALID_ARGS; - } - } - for (const auto &singlePath : path) { - if (singlePath.size() > JSON_DEEP_MAX) { + maxDeep = std::max(allFieldsName.size() + jsonTemp.GetDeep(), maxDeep); + if (maxDeep > JSON_DEEP_MAX) { + GLOGE("document's json deep is deeper than JSON_DEEP_MAX"); return -E_INVALID_ARGS; } + jsonTemp = jsonTemp.GetNext(); } bool isIdExist = true; CheckIdFormat(updataObj, isIdExist); diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/executor/document/check_common.h b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/executor/document/check_common.h index 2985bd67..e9ae1180 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/executor/document/check_common.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/executor/document/check_common.h @@ -32,7 +32,7 @@ public: static int CheckFilter(JsonObject &filterObj, bool &isOnlyId, std::vector> &filterPath); static int CheckIdFormat(JsonObject &filterJson, bool &isIdExisit); static int CheckDocument(JsonObject &documentObj); - static int CheckUpdata(JsonObject &updataObj, std::vector> &path); + static int CheckUpdata(JsonObject &updata); static int CheckProjection(JsonObject &projectionObj, std::vector> &path); }; using Key = std::vector; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/document_store.cpp b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/document_store.cpp index 1b50f92a..caa230c1 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/document_store.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/document_store.cpp @@ -157,13 +157,7 @@ int UpdateArgsCheck(const std::string &collection, const std::string &filter, co return errCode; } if (update != "{}") { - std::vector> allPath; - allPath = JsonCommon::ParsePath(updateObj, errCode); - if (errCode != E_OK) { - GLOGE("updateObj ParsePath failed"); - return errCode; - } - errCode = CheckCommon::CheckUpdata(updateObj, allPath); + errCode = CheckCommon::CheckUpdata(updateObj); if (errCode != E_OK) { GLOGE("Updata format is illegal"); return errCode; @@ -343,12 +337,7 @@ int UpsertDocumentFormatCheck(const std::string &document, JsonObject &documentO { int errCode = E_OK; if (document != "{}") { - std::vector> allPath; - allPath = JsonCommon::ParsePath(documentObj, errCode); - if (errCode != E_OK) { - return errCode; - } - errCode = CheckCommon::CheckUpdata(documentObj, allPath); + errCode = CheckCommon::CheckUpdata(documentObj); if (errCode != E_OK) { GLOGE("UpsertDocument document format is illegal"); return errCode; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/projection_tree.cpp b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/projection_tree.cpp index 5c37b84b..4ab699c3 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/projection_tree.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/projection_tree.cpp @@ -58,11 +58,11 @@ bool ProjectionTree::SearchTree(std::vector &singlePath, size_t &in { ProjectionNode *node = &node_; for (size_t i = 0; i < singlePath.size(); i++) { - if (node->isDeepest) { - index = i; - } if (node->sonNode[singlePath[i]] != nullptr) { node = node->sonNode[singlePath[i]]; + if (node->isDeepest) { + index = i + 1; + } } else { return false; } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/result_set.cpp b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/result_set.cpp index 6c221daa..225a8bc8 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/result_set.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/interface/src/result_set.cpp @@ -190,22 +190,25 @@ int ResultSet::CheckCutNode(JsonObject *node, std::vector singlePat GLOGE("No node to cut"); return -E_NO_DATA; } - singlePath.emplace_back(node->GetItemField()); - size_t index = 0; - if (!context_->projectionTree.SearchTree(singlePath, index) && index == 0) { - allCutPath.emplace_back(singlePath); - } - if (!node->GetChild().IsNull()) { - JsonObject nodeNew = node->GetChild(); - CheckCutNode(&nodeNew, singlePath, allCutPath); - } - if (!node->GetNext().IsNull()) { + JsonObject nodeInstance = *node; + while (!nodeInstance.IsNull()) { + singlePath.emplace_back(nodeInstance.GetItemField()); + size_t index = 0; + bool isMatch = context_->projectionTree.SearchTree(singlePath, index); + if ((nodeInstance.GetType() == JsonObject::Type::JSON_ARRAY && isMatch && index == 0) || + (!isMatch && index == 0)) { + allCutPath.emplace_back(singlePath); + } + if (nodeInstance.GetType() != JsonObject::Type::JSON_ARRAY && !nodeInstance.GetChild().IsNull()) { + JsonObject nodeChiled = nodeInstance.GetChild(); + CheckCutNode(&nodeChiled, singlePath, allCutPath); + } singlePath.pop_back(); - JsonObject nodeNew = node->GetNext(); - CheckCutNode(&nodeNew, singlePath, allCutPath); + nodeInstance = nodeInstance.GetNext(); } return E_OK; } + int ResultSet::CutJsonBranch(std::string &jsonData) { int errCode; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/oh_adapter/include/json_object.h b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/oh_adapter/include/json_object.h index afd0489d..9680c82c 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/oh_adapter/include/json_object.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/oh_adapter/include/json_object.h @@ -106,8 +106,8 @@ public: private: JsonObject(); int Init(const std::string &str, bool isFilter = false); - int CheckJsonRepeatField(cJSON *object); - int CheckSubObj(std::set &fieldSet, cJSON *subObj, int parentType); + int CheckJsonRepeatField(cJSON *object, bool isFirstFloor); + int CheckSubObj(std::set &fieldSet, cJSON *subObj, int parentType, bool isFirstFloor); int GetDeep(cJSON *cjson); int CheckNumber(cJSON *cjson, int &errCode); cJSON *cjson_ = nullptr; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/oh_adapter/src/json_object.cpp b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/oh_adapter/src/json_object.cpp index 7ac3a08c..86357c71 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/oh_adapter/src/json_object.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/src/oh_adapter/src/json_object.cpp @@ -14,9 +14,9 @@ */ #include "json_object.h" - #include #include +#include #include "doc_errno.h" #include "log_print.h" @@ -152,17 +152,23 @@ int JsonObject::GetDeep(cJSON *cjson) int JsonObject::CheckNumber(cJSON *item, int &errCode) { - if (item != NULL && cJSON_IsNumber(item)) { - double value = cJSON_GetNumberValue(item); - if (value > __DBL_MAX__ || value < -__DBL_MAX__) { - errCode = -E_INVALID_ARGS; + std::queue cjsonQueue; + cjsonQueue.push(item); + while (!cjsonQueue.empty()) { + cJSON *node = cjsonQueue.front(); + cjsonQueue.pop(); + if (node != NULL && cJSON_IsNumber(node)) { + double value = cJSON_GetNumberValue(node); + if (value > __DBL_MAX__ || value < -__DBL_MAX__) { + errCode = -E_INVALID_ARGS; + } + } + if (node->child != nullptr) { + cjsonQueue.push(node->child); + } + if (node->next != nullptr) { + cjsonQueue.push(node->next); } - } - if (item->child != nullptr) { - return CheckNumber(item->child, errCode); - } - if (item->next != nullptr) { - return CheckNumber(item->next, errCode); } return E_OK; } @@ -189,7 +195,8 @@ int JsonObject::Init(const std::string &str, bool isFilter) return -E_INVALID_ARGS; } if (!isFilter) { - ret = CheckJsonRepeatField(cjson_); + bool isFirstFloor = true; + ret = CheckJsonRepeatField(cjson_, isFirstFloor); if (ret != E_OK) { return ret; } @@ -197,7 +204,7 @@ int JsonObject::Init(const std::string &str, bool isFilter) return E_OK; } -int JsonObject::CheckJsonRepeatField(cJSON *object) +int JsonObject::CheckJsonRepeatField(cJSON *object, bool isFirstFloor) { if (object == nullptr) { return -E_INVALID_ARGS; @@ -210,7 +217,7 @@ int JsonObject::CheckJsonRepeatField(cJSON *object) std::set fieldSet; cJSON *subObj = object->child; while (subObj != nullptr) { - ret = CheckSubObj(fieldSet, subObj, type); + ret = CheckSubObj(fieldSet, subObj, type, isFirstFloor); if (ret != E_OK) { break; } @@ -219,7 +226,7 @@ int JsonObject::CheckJsonRepeatField(cJSON *object) return ret; } -int JsonObject::CheckSubObj(std::set &fieldSet, cJSON *subObj, int parentType) +int JsonObject::CheckSubObj(std::set &fieldSet, cJSON *subObj, int parentType, bool isFirstFloor) { if (subObj == nullptr) { return -E_INVALID_ARGS; @@ -227,9 +234,20 @@ int JsonObject::CheckSubObj(std::set &fieldSet, cJSON *subObj, int std::string fieldName; if (subObj->string != nullptr) { fieldName = subObj->string; + if (!isFirstFloor) { + for (auto oneChar : fieldName) { + if (!((isalpha(oneChar)) || (isdigit(oneChar)) || (oneChar == '_'))) { + return -E_INVALID_ARGS; + } + } + } + if (!fieldName.empty() && isdigit(fieldName[0])) { + return -E_INVALID_ARGS; + } } + isFirstFloor = false; if (parentType == cJSON_Array) { - return CheckJsonRepeatField(subObj); + return CheckJsonRepeatField(subObj, isFirstFloor); } if (fieldName.empty()) { return -E_INVALID_JSON_FORMAT; @@ -239,7 +257,7 @@ int JsonObject::CheckSubObj(std::set &fieldSet, cJSON *subObj, int } else { return -E_INVALID_JSON_FORMAT; } - return CheckJsonRepeatField(subObj); + return CheckJsonRepeatField(subObj, isFirstFloor); } std::string JsonObject::Print() const @@ -657,7 +675,6 @@ int JsonObject::DeleteItemOnTarget(const JsonFieldPath &path) cJSON *nodeFather = MoveToPath(cjson_, patherPath, caseSensitive_); if (nodeFather == nullptr) { - GLOGE("Delete item failed, json field path not found."); return -E_JSON_PATH_NOT_EXISTS; } @@ -690,7 +707,6 @@ int JsonObject::DeleteItemDeeplyOnTarget(const JsonFieldPath &path) cJSON *nodeFather = MoveToPath(cjson_, patherPath, caseSensitive_); if (nodeFather == nullptr) { - GLOGE("Delete item failed, json field path not found."); return -E_JSON_PATH_NOT_EXISTS; } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/BUILD.gn b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/BUILD.gn index b4cc59a3..81eb4698 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/BUILD.gn @@ -81,9 +81,9 @@ ohos_source_set("src_file") { deps += [ "//third_party/cJSON:cjson" ] external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", ] subsystem_name = "distributeddatamgr" @@ -115,9 +115,9 @@ template("gaussdb_rd_unittest") { ] external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", ] } } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/api/documentdb_find_test.cpp b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/api/documentdb_find_test.cpp index f77761d8..654294a3 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/api/documentdb_find_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/api/documentdb_find_test.cpp @@ -35,6 +35,7 @@ namespace { std::string g_path = "./document.db"; GRD_DB *g_db = nullptr; constexpr const char *COLLECTION_NAME = "student"; +constexpr const char *colName = "data_"; const int MAX_COLLECTION_NAME = 511; const int MAX_ID_LENS = 899; @@ -1464,4 +1465,41 @@ HWTEST_F(DocumentDBFindTest, DocumentDBFindTest062, TestSize.Level1) Query query = { filter, projection }; EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_INVALID_ARGS); } + +HWTEST_F(DocumentDBFindTest, DocumentDBFindTest063, TestSize.Level1) +{ + GRD_DB *test_db = nullptr; + std::string path = "./dataShare.db"; + int status = GRD_DBOpen(path.c_str(), nullptr, GRD_DB_OPEN_CREATE, &test_db); + EXPECT_EQ(status, GRD_OK); + EXPECT_EQ(GRD_CreateCollection(test_db, colName, "", 0), GRD_OK); + string document1 = "{\"_id\":\"key2_11_com.acts.ohos.data.datasharetestclient_100\",\ + \"bundleName\":\"com.acts.ohos.data.datasharetestclient\",\"key\":\"key2\",\ + \"subscriberId\":11,\"timestamp\":1509100700,""\"userId\":100,\"value\":{\"type\":0,"; + string document2 = "\"value\":["; + string document3 = "5,"; + string document4 = document3; + for (int i = 0; i < 100000; i++) { + document4 += document3; + } + document4.push_back('5'); + string document5 = "]}}"; + string document0635 = document1 + document2 + document4 + document5; + EXPECT_EQ(GRD_InsertDoc(test_db, colName, document0635.c_str(), 0), GRD_OK); + EXPECT_EQ(status, GRD_OK); + const char *filter = "{}"; + GRD_ResultSet *resultSet = nullptr; + const char *projection = "{\"id_\":true, \"timestamp\":true, \"key\":true, \"bundleName\": true, " + "\"subscriberId\": true}"; + Query query = { filter, projection }; + EXPECT_EQ(GRD_FindDoc(test_db, colName, query, 1, &resultSet), GRD_OK); + char *value; + while (GRD_Next(resultSet) == GRD_OK) { + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + GRD_FreeValue(value); + } + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + EXPECT_EQ(GRD_DBClose(test_db, 0), GRD_OK); + DocumentDBTestUtils::RemoveTestDbFiles(path.c_str()); +} } // namespace diff --git a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/oh_adapter/documentdb_json_common_test.cpp b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/oh_adapter/documentdb_json_common_test.cpp index bec7c70a..3e92ba17 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/oh_adapter/documentdb_json_common_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/gaussdb_rd/test/unittest/oh_adapter/documentdb_json_common_test.cpp @@ -147,25 +147,6 @@ HWTEST_F(DocumentDBJsonCommonTest, JsonObjectAppendTest005, TestSize.Level0) EXPECT_EQ(itemCase.GetItemValue().GetStringValue(), "GG"); } -HWTEST_F(DocumentDBJsonCommonTest, JsonObjectAppendTest006, TestSize.Level0) -{ - std::string document = R""({"name":{"first":"Tno", "last":"moray"}})""; - std::string updateDoc = R""({"name":{"midle.AA":"GG"}})""; - - int errCode = E_OK; - JsonObject src = JsonObject::Parse(document, errCode); - EXPECT_EQ(errCode, E_OK); - JsonObject add = JsonObject::Parse(updateDoc, errCode); - EXPECT_EQ(errCode, E_OK); - - EXPECT_EQ(JsonCommon::Append(src, add, false), E_OK); - GLOGD("result: %s", src.Print().c_str()); - - JsonObject itemCase = src.FindItem({ "name", "midle.AA" }, errCode); - EXPECT_EQ(errCode, E_OK); - EXPECT_EQ(itemCase.GetItemValue().GetStringValue(), "GG"); -} - HWTEST_F(DocumentDBJsonCommonTest, JsonObjectAppendTest007, TestSize.Level0) { std::string document = R""({"name":{"first":["XX", "CC"], "last":"moray"}})""; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/idata_share_service.h b/datamgr_service/services/distributeddataservice/service/data_share/idata_share_service.h index 1ae6824f..ce2ff44b 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/idata_share_service.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/idata_share_service.h @@ -46,6 +46,7 @@ public: DATA_SHARE_SERVICE_CMD_ENABLE_SUBSCRIBE_PUBLISHED, DATA_SHARE_SERVICE_CMD_DISABLE_SUBSCRIBE_PUBLISHED, DATA_SHARE_SERVICE_CMD_NOTIFY, + DATA_SHARE_SERVICE_CMD_NOTIFY_OBSERVERS, DATA_SHARE_SERVICE_CMD_MAX }; @@ -79,6 +80,7 @@ public: virtual std::vector DisablePubSubs(const std::vector &uris, const int64_t subscriberId) = 0; virtual void OnConnectDone() = 0; + virtual void NotifyObserver(const std::string &uri) = 0; }; } // namespace OHOS::DataShare #endif diff --git a/datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.cpp b/datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.cpp new file mode 100644 index 00000000..52cb9816 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define LOG_TAG "RdbNotifyStrategy" + +#include "rdb_notify_strategy.h" + +#include "general/load_config_common_strategy.h" +#include "general/load_config_data_info_strategy.h" +#include "general/load_config_from_bundle_info_strategy.h" +#include "log_print.h" +#include "utils/anonymous.h" + +namespace OHOS::DataShare { +bool RdbNotifyStrategy::Execute(std::shared_ptr context) +{ + auto &preProcess = GetStrategy(); + if (preProcess.IsEmpty()) { + ZLOGE("get strategy fail, maybe memory not enough"); + return false; + } + if (!preProcess(context)) { + ZLOGE("pre process fail, uri: %{public}s", DistributedData::Anonymous::Change(context->uri).c_str()); + return false; + } + if (context->callerBundleName != context->calledBundleName) { + ZLOGE("not your data, cannot notify, callerBundleName: %{public}s, calledBundleName: %{public}s", + context->callerBundleName.c_str(), context->calledBundleName.c_str()); + return false; + } + return true; +} + +SeqStrategy &RdbNotifyStrategy::GetStrategy() +{ + std::lock_guard lock(mutex_); + if (!strategies_.IsEmpty()) { + return strategies_; + } + std::initializer_list list = { + new (std::nothrow)LoadConfigCommonStrategy(), + new (std::nothrow)LoadConfigFromBundleInfoStrategy(), + new (std::nothrow)LoadConfigDataInfoStrategy() + }; + auto ret = strategies_.Init(list); + if (!ret) { + std::for_each(list.begin(), list.end(), [](Strategy *item) { + delete item; + }); + return strategies_; + } + return strategies_; +} +} // namespace OHOS::DataShare \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.h b/datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.h new file mode 100644 index 00000000..22eae10d --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef DATASHARESERVICE_RDB_NOTIFY_STRAGETY_H +#define DATASHARESERVICE_RDB_NOTIFY_STRAGETY_H + +#include + +#include "datashare_values_bucket.h" +#include "seq_strategy.h" + +namespace OHOS::DataShare { +class RdbNotifyStrategy final { +public: + bool Execute(std::shared_ptr context); + +private: + SeqStrategy &GetStrategy(); + std::mutex mutex_; + SeqStrategy strategies_; +}; +} // namespace OHOS::DataShare +#endif diff --git a/datamgr_service/services/distributeddataservice/service/data_share/strategies/subscribe_strategy.cpp b/datamgr_service/services/distributeddataservice/service/data_share/strategies/subscribe_strategy.cpp index 067c8cda..4b7314c8 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/strategies/subscribe_strategy.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/strategies/subscribe_strategy.cpp @@ -24,7 +24,7 @@ #include "utils/anonymous.h" namespace OHOS::DataShare { -int32_t SubscribeStrategy::Execute(std::shared_ptr context, std::function process) +int32_t SubscribeStrategy::Execute(std::shared_ptr context, std::function process) { auto &preProcess = GetStrategy(); if (preProcess.IsEmpty()) { diff --git a/datamgr_service/services/distributeddataservice/service/data_share/strategies/subscribe_strategy.h b/datamgr_service/services/distributeddataservice/service/data_share/strategies/subscribe_strategy.h index 7395b90f..3456b66c 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/strategies/subscribe_strategy.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/strategies/subscribe_strategy.h @@ -23,7 +23,7 @@ namespace OHOS::DataShare { class SubscribeStrategy final { public: - int32_t Execute(std::shared_ptr context, std::function process); + int32_t Execute(std::shared_ptr context, std::function process); private: SeqStrategy &GetStrategy(); diff --git a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.cpp b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.cpp index 6aea095b..af1570d4 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.cpp @@ -80,6 +80,8 @@ int PublishedDataSubscriberManager::Delete(const PublishedDataKey &key, const ui publishedDataCache.ComputeIfPresent(key, [&callerTokenId](const auto &key, std::vector &value) { for (auto it = value.begin(); it != value.end();) { if (it->callerTokenId == callerTokenId) { + ZLOGI("delete publish subscriber, uri %{private}s tokenId %{public}d", key.key.c_str(), + callerTokenId); it = value.erase(it); } else { it++; @@ -175,11 +177,22 @@ void PublishedDataSubscriberManager::PutInto( } } } + void PublishedDataSubscriberManager::Clear() { publishedDataCache.Clear(); } +int PublishedDataSubscriberManager::GetCount(const PublishedDataKey &key) +{ + int count = 0; + publishedDataCache.ComputeIfPresent(key, [&count](const auto &key, std::vector &value) { + count = value.size(); + return true; + }); + return count; +} + PublishedDataKey::PublishedDataKey(const std::string &key, const std::string &bundle, const int64_t subscriberId) : key(key), bundleName(bundle), subscriberId(subscriberId) { diff --git a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.h b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.h index 221fd7ee..de3149d2 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.h @@ -49,7 +49,7 @@ public: void Emit(const std::vector &keys, const int32_t userId, const std::string &ownerBundleName, const sptr observer = nullptr); void Clear(); - + int GetCount(const PublishedDataKey &key); private: struct ObserverNode { ObserverNode(const sptr &observer, uint32_t callerTokenId); diff --git a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.cpp b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.cpp index ed602307..faf0cb57 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.cpp @@ -232,6 +232,10 @@ void RdbSubscriberManager::Emit(const std::string &uri, std::shared_ptr if (!URIUtils::IsDataProxyURI(uri)) { return; } + if (context->calledSourceDir.empty()) { + LoadConfigDataInfoStrategy loadDataInfo; + loadDataInfo(context); + } rdbCache_.ForEach([&uri, &context, this](const Key &key, std::vector &val) { if (key.uri != uri) { return false; diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp index 8894c4ad..1da51ce4 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp @@ -23,7 +23,8 @@ #include "utils/anonymous.h" namespace OHOS::DistributedKv { using namespace OHOS::DistributedData; -const KVDBServiceStub::Handler KVDBServiceStub::HANDLERS[TRANS_BUTT] = { +const KVDBServiceStub::Handler + KVDBServiceStub::HANDLERS[static_cast(KVDBServiceInterfaceCode::TRANS_BUTT)] = { &KVDBServiceStub::OnGetStoreIds, &KVDBServiceStub::OnBeforeCreate, &KVDBServiceStub::OnAfterCreate, @@ -53,8 +54,10 @@ int KVDBServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, Message return -1; } - if (TRANS_HEAD > code || code >= TRANS_BUTT || HANDLERS[code] == nullptr) { - ZLOGE("not support code:%{public}u, BUTT:%{public}d", code, TRANS_BUTT); + if (static_cast(KVDBServiceInterfaceCode::TRANS_HEAD) > code || + code >= static_cast(KVDBServiceInterfaceCode::TRANS_BUTT) || HANDLERS[code] == nullptr) { + ZLOGE("not support code:%{public}u, BUTT:%{public}d", code, + static_cast(KVDBServiceInterfaceCode::TRANS_BUTT)); return -1; } diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.h b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.h index ab0bacc4..00b1763d 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.h +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.h @@ -15,6 +15,7 @@ #ifndef OHOS_DISTRIBUTED_DATA_SERVICE_KVDB_SERVICE_STUB_H #define OHOS_DISTRIBUTED_DATA_SERVICE_KVDB_SERVICE_STUB_H +#include "distributeddata_kvdb_ipc_interface_code.h" #include "iremote_stub.h" #include "kvdb_service.h" #include "feature/feature_system.h" @@ -43,7 +44,7 @@ private: int32_t OnSubscribe(const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply); int32_t OnUnsubscribe(const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply); int32_t OnGetBackupPassword(const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply); - static const Handler HANDLERS[TRANS_BUTT]; + static const Handler HANDLERS[static_cast(KVDBServiceInterfaceCode::TRANS_BUTT)]; }; } // namespace OHOS::DistributedKv #endif // OHOS_DISTRIBUTED_DATA_SERVICE_KVDB_SERVICE_STUB_H diff --git a/datamgr_service/services/distributeddataservice/service/object/object_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/object/object_service_stub.cpp index 9a5281bf..a97dd72d 100644 --- a/datamgr_service/services/distributeddataservice/service/object/object_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/object/object_service_stub.cpp @@ -150,7 +150,7 @@ int ObjectServiceStub::OnRemoteRequest(uint32_t code, MessageParcel& data, Messa if (!CheckInterfaceToken(data)) { return -1; } - if (code >= 0 && code < OBJECTSTORE_SERVICE_CMD_MAX) { + if (code >= 0 && code < static_cast(ObjectCode::OBJECTSTORE_SERVICE_CMD_MAX)) { return (this->*HANDLERS[code])(data, reply); } return -1; diff --git a/datamgr_service/services/distributeddataservice/service/object/object_service_stub.h b/datamgr_service/services/distributeddataservice/service/object/object_service_stub.h index c3e319fa..6acd6c75 100644 --- a/datamgr_service/services/distributeddataservice/service/object/object_service_stub.h +++ b/datamgr_service/services/distributeddataservice/service/object/object_service_stub.h @@ -20,6 +20,8 @@ #include "iobject_service.h" #include "feature/feature_system.h" namespace OHOS::DistributedObject { +using ObjectCode = ObjectStoreService::ObjectServiceInterfaceCode; + class ObjectServiceStub : public ObjectService, public DistributedData::FeatureSystem::Feature { public: int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply) override; @@ -33,7 +35,7 @@ private: int32_t OnUnsubscribeRequest(MessageParcel &data, MessageParcel &reply); using RequestHandle = int (ObjectServiceStub::*)(MessageParcel &, MessageParcel &); - static constexpr RequestHandle HANDLERS[OBJECTSTORE_SERVICE_CMD_MAX] = { + static constexpr RequestHandle HANDLERS[static_cast(ObjectCode::OBJECTSTORE_SERVICE_CMD_MAX)] = { &ObjectServiceStub::ObjectStoreSaveOnRemote, &ObjectServiceStub::ObjectStoreRevokeSaveOnRemote, &ObjectServiceStub::ObjectStoreRetrieveOnRemote, diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.cpp index b7d4d938..a0d9f538 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.cpp @@ -31,8 +31,8 @@ DBStatus RdbAssetLoader::Download(const std::string &tableName, const std::strin std::map &assets) { DistributedData::VBucket downLoadAssets = ValueProxy::Convert(assets); - - auto error = assetLoader_->Download(tableName, gid, (const DistributedData::Value &)prefix, downLoadAssets); + DistributedDB::Type prefixTemp = prefix; + auto error = assetLoader_->Download(tableName, gid, ValueProxy::Convert(std::move(prefixTemp)), downLoadAssets); if (error == DistributedData::GeneralError::E_OK) { assets = ValueProxy::Convert(std::move(downLoadAssets)); } diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp index 03d90430..88a5e0eb 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp @@ -14,7 +14,7 @@ */ #define LOG_TAG "RdbGeneralStore" #include "rdb_general_store.h" - +#include "cloud_service.h" #include "cloud/asset_loader.h" #include "cloud/cloud_db.h" #include "cloud/schema_meta.h" @@ -32,9 +32,12 @@ namespace OHOS::DistributedRdb { using namespace DistributedData; using namespace DistributedDB; using namespace NativeRdb; +using namespace CloudData; using DBField = DistributedDB::Field; using DBTable = DistributedDB::TableSchema; using DBSchema = DistributedDB::DataBaseSchema; +using ClearMode = DistributedDB::ClearMode; +using DBStatus = DistributedDB::DBStatus; class RdbOpenCallbackImpl : public RdbOpenCallback { public: int OnCreate(RdbStore &rdbStore) override @@ -103,10 +106,6 @@ int32_t RdbGeneralStore::Bind(const Database &database, BindInfo bindInfo) rdbCloud_ = std::make_shared(bindInfo_.db_); delegate_->SetCloudDB(rdbCloud_); rdbLoader_ = std::make_shared(bindInfo_.loader_); - if (rdbLoader_ == nullptr) { - ZLOGE("rdb_AssetLoader is null"); - return GeneralError::E_ERROR; - } delegate_->SetIAssetLoader(rdbLoader_); DBSchema schema; schema.tables.resize(database.tables.size()); @@ -197,6 +196,36 @@ int32_t RdbGeneralStore::Sync(const Devices &devices, int32_t mode, GenQuery &qu return status == DistributedDB::OK ? GeneralError::E_OK : GeneralError::E_ERROR; } +int32_t RdbGeneralStore::Clean(const std::vector &devices, int32_t mode, const std::string &tableName) +{ + if (mode < 0 || mode > CloudService::CLEAR_CLOUD_BUTT) { + return GeneralError::E_INVALID_ARGS; + } + int32_t dbMode; + DBStatus status; + switch (mode) { + case CloudService::CLEAR_CLOUD_INFO: + dbMode = CleanMode::CLOUD_INFO; + status = delegate_->RemoveDeviceData("", static_cast(dbMode)); + break; + case CloudService::CLEAR_CLOUD_DATA_AND_INFO: + dbMode = CleanMode::CLOUD_DATA; + status = delegate_->RemoveDeviceData("", static_cast(dbMode)); + break; + default: + if (devices.empty()) { + status = delegate_->RemoveDeviceData(); + break; + } + + for (auto device : devices) { + status = delegate_->RemoveDeviceData(device, tableName); + } + break; + } + return status == DistributedDB::OK ? GeneralError::E_OK : GeneralError::E_ERROR; +} + int32_t RdbGeneralStore::Watch(int32_t origin, Watcher &watcher) { if (origin != Watcher::Origin::ORIGIN_ALL || observer_.watcher_ != nullptr) { @@ -284,6 +313,7 @@ void RdbGeneralStore::ObserverProxy::OnChange(DBOrigin origin, const std::string genOrigin.origin = (origin == DBOrigin::ORIGIN_LOCAL) ? GenOrigin::ORIGIN_LOCAL : (origin == DBOrigin::ORIGIN_CLOUD) ? GenOrigin::ORIGIN_CLOUD : GenOrigin::ORIGIN_NEARBY; + genOrigin.dataType = data.type == DistributedDB::ASSET ? GenOrigin::ASSET_DATA : GenOrigin::BASIC_DATA; genOrigin.id.push_back(originalId); genOrigin.store = storeId_; Watcher::PRIFields fields; diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h index 2a27c83a..3213be87 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h @@ -49,6 +49,7 @@ public: std::shared_ptr Query(const std::string &table, const std::string &sql, Values &&args) override; std::shared_ptr Query(const std::string &table, GenQuery &query) override; int32_t Sync(const Devices &devices, int32_t mode, GenQuery &query, DetailAsync async, int32_t wait) override; + int32_t Clean(const std::vector &devices, int32_t mode, const std::string &tableName) override; int32_t Watch(int32_t origin, Watcher &watcher) override; int32_t Unwatch(int32_t origin, Watcher &watcher) override; int32_t Close() override; diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_notifier_proxy.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_notifier_proxy.cpp index 92aee4fa..1d9d7401 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_notifier_proxy.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_notifier_proxy.cpp @@ -17,6 +17,8 @@ #include "itypes_util.h" #include "log_print.h" namespace OHOS::DistributedRdb { +using NotifierIFCode = RelationalStore::IRdbNotifierInterfaceCode; + RdbNotifierProxy::RdbNotifierProxy(const sptr &object) : IRemoteProxy(object) { ZLOGI("construct"); @@ -40,7 +42,8 @@ int32_t RdbNotifierProxy::OnComplete(uint32_t seqNum, Details &&result) MessageParcel reply; MessageOption option(MessageOption::TF_ASYNC); - if (Remote()->SendRequest(RDB_NOTIFIER_CMD_SYNC_COMPLETE, data, reply, option) != 0) { + if (Remote()->SendRequest( + static_cast(NotifierIFCode::RDB_NOTIFIER_CMD_SYNC_COMPLETE), data, reply, option) != 0) { ZLOGE("send request failed"); return RDB_ERROR; } @@ -61,7 +64,8 @@ int32_t RdbNotifierProxy::OnChange(const Origin &origin, const PrimaryFields &pr MessageParcel reply; MessageOption option; - if (Remote()->SendRequest(RDB_NOTIFIER_CMD_DATA_CHANGE, data, reply, option) != 0) { + if (Remote()->SendRequest( + static_cast(NotifierIFCode::RDB_NOTIFIER_CMD_DATA_CHANGE), data, reply, option) != 0) { ZLOGE("send request failed"); return RDB_ERROR; } diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp index bf493d2c..8e602e5c 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp @@ -207,7 +207,7 @@ int RdbServiceStub::OnRemoteRequest(uint32_t code, MessageParcel& data, MessageP if (!CheckInterfaceToken(data)) { return RDB_ERROR; } - if (code >= 0 && code < RDB_SERVICE_CMD_MAX) { + if (code >= 0 && code < static_cast(RdbServiceCode::RDB_SERVICE_CMD_MAX)) { return (this->*HANDLERS[code])(data, reply); } return RDB_ERROR; diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.h index b67c3e5b..fbd2173a 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.h @@ -22,6 +22,8 @@ #include "feature/feature_system.h" namespace OHOS::DistributedRdb { +using RdbServiceCode = OHOS::DistributedRdb::RelationalStore::RdbServiceInterfaceCode; + class RdbServiceStub : public RdbService, public DistributedData::FeatureSystem::Feature { public: DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.DistributedRdb.IRdbService"); @@ -49,16 +51,18 @@ private: int32_t OnRemoteDoRemoteQuery(MessageParcel& data, MessageParcel& reply); using RequestHandle = int (RdbServiceStub::*)(MessageParcel &, MessageParcel &); - static constexpr RequestHandle HANDLERS[RDB_SERVICE_CMD_MAX] = { - [RDB_SERVICE_CMD_OBTAIN_TABLE] = &RdbServiceStub::OnRemoteObtainDistributedTableName, - [RDB_SERVICE_CMD_INIT_NOTIFIER] = &RdbServiceStub::OnRemoteInitNotifier, - [RDB_SERVICE_CMD_SET_DIST_TABLE] = &RdbServiceStub::OnRemoteSetDistributedTables, - [RDB_SERVICE_CMD_SYNC] = &RdbServiceStub::OnRemoteDoSync, - [RDB_SERVICE_CMD_ASYNC] = &RdbServiceStub::OnRemoteDoAsync, - [RDB_SERVICE_CMD_SUBSCRIBE] = &RdbServiceStub::OnRemoteDoSubscribe, - [RDB_SERVICE_CMD_UNSUBSCRIBE] = &RdbServiceStub::OnRemoteDoUnSubscribe, - [RDB_SERVICE_CMD_REMOTE_QUERY] = &RdbServiceStub::OnRemoteDoRemoteQuery, - [RDB_SERVICE_CMD_GET_SCHEMA] = &RdbServiceStub::OnGetSchema + static constexpr RequestHandle HANDLERS[static_cast(RdbServiceCode::RDB_SERVICE_CMD_MAX)] = { + [static_cast(RdbServiceCode::RDB_SERVICE_CMD_OBTAIN_TABLE)] = + &RdbServiceStub::OnRemoteObtainDistributedTableName, + [static_cast(RdbServiceCode::RDB_SERVICE_CMD_INIT_NOTIFIER)] = &RdbServiceStub::OnRemoteInitNotifier, + [static_cast(RdbServiceCode::RDB_SERVICE_CMD_SET_DIST_TABLE)] = + &RdbServiceStub::OnRemoteSetDistributedTables, + [static_cast(RdbServiceCode::RDB_SERVICE_CMD_SYNC)] = &RdbServiceStub::OnRemoteDoSync, + [static_cast(RdbServiceCode::RDB_SERVICE_CMD_ASYNC)] = &RdbServiceStub::OnRemoteDoAsync, + [static_cast(RdbServiceCode::RDB_SERVICE_CMD_SUBSCRIBE)] = &RdbServiceStub::OnRemoteDoSubscribe, + [static_cast(RdbServiceCode::RDB_SERVICE_CMD_UNSUBSCRIBE)] = &RdbServiceStub::OnRemoteDoUnSubscribe, + [static_cast(RdbServiceCode::RDB_SERVICE_CMD_REMOTE_QUERY)] = &RdbServiceStub::OnRemoteDoRemoteQuery, + [static_cast(RdbServiceCode::RDB_SERVICE_CMD_GET_SCHEMA)] = &RdbServiceStub::OnGetSchema }; }; } // namespace OHOS::DistributedRdb diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.cpp index 1f65915f..9fbd7642 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.cpp @@ -167,11 +167,11 @@ int32_t RdbSyncer::InitDBDelegate(const StoreMetaData &meta) } option.observer = observer_; std::string fileName = meta.dataDir; - ZLOGI("path=%{public}s storeId=%{public}s", fileName.c_str(), meta.GetStoreAlias().c_str()); + ZLOGI("path=%{public}s storeId=%{public}s", Anonymous::Change(fileName).c_str(), meta.GetStoreAlias().c_str()); auto status = manager_->OpenStore(fileName, meta.storeId, option, delegate_); if (status != DistributedDB::DBStatus::OK) { ZLOGE("open store failed, path=%{public}s storeId=%{public}s status=%{public}d", - fileName.c_str(), meta.GetStoreAlias().c_str(), status); + Anonymous::Change(fileName).c_str(), meta.GetStoreAlias().c_str(), status); return RDB_ERROR; } ZLOGI("open store success"); @@ -385,8 +385,8 @@ int32_t RdbSyncer::DoSync(const Option &option, const PredicatesMemo &predicates query->query_.FromTable(predicates.tables_); } - auto info = ChangeEvent::EventInfo(option.mode, (option.isAsync ? 0 : WAIT_TIME), query, - [async](const GenDetails &details) { + auto info = ChangeEvent::EventInfo(option.mode, (option.isAsync ? 0 : WAIT_TIME), + (option.isAsync && option.seqNum == 0), query, [async](const GenDetails &details) { async(HandleGenDetails(details)); }); auto evt = std::make_unique(std::move(storeInfo), std::move(info)); diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_watcher.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_watcher.cpp index c929a769..a0d4d0ed 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_watcher.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_watcher.cpp @@ -35,6 +35,7 @@ int32_t RdbWatcher::OnChange(const Origin &origin, const PRIFields &primaryField } DistributedRdb::Origin rdbOrigin; rdbOrigin.origin = origin.origin; + rdbOrigin.dataType = origin.dataType; rdbOrigin.id = origin.id; rdbOrigin.store = origin.store; notifier->OnChange(rdbOrigin, primaryFields, std::move(values)); diff --git a/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.cpp b/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.cpp index db4ef2fe..23bac1a7 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.cpp @@ -125,7 +125,7 @@ ValueProxy::Asset::Asset(NativeRdb::AssetValue asset) asset_ = DistributedData::Asset { .version = asset.version, .status = asset.status, .expiresTime = asset.expiresTime, - .id = asset.id, + .id = std::move(asset.id), .name = std::move(asset.name), .uri = std::move(asset.uri), .createTime = std::move(asset.createTime), @@ -199,8 +199,7 @@ ValueProxy::Asset::operator DistributedDB::Asset() .createTime = std::move(asset_.createTime), .size = std::move(asset_.size), .hash = std::move(asset_.hash), - .flag = ConvertToDBStatus(asset_).second, - .status = ConvertToDBStatus(asset_).first }; + .status = ConvertToDBStatus(asset_) }; } uint32_t ValueProxy::Asset::ConvertToDataStatus(const DistributedDB::Asset &asset) @@ -209,7 +208,7 @@ uint32_t ValueProxy::Asset::ConvertToDataStatus(const DistributedDB::Asset &asse return DistributedData::Asset::STATUS_DOWNLOADING; } else if (asset.status == DistributedDB::AssetStatus::ABNORMAL) { return DistributedData::Asset::STATUS_ABNORMAL; - } else if (asset.status == DistributedDB::AssetStatus::NORMAL) { + } else { switch (asset.flag) { case static_cast(DistributedDB::AssetOpType::INSERT): return DistributedData::Asset::STATUS_INSERT; @@ -224,30 +223,23 @@ uint32_t ValueProxy::Asset::ConvertToDataStatus(const DistributedDB::Asset &asse return DistributedData::Asset::STATUS_UNKNOWN; } -std::pair ValueProxy::Asset::ConvertToDBStatus(const DistributedData::Asset &asset) +uint32_t ValueProxy::Asset::ConvertToDBStatus(const DistributedData::Asset &asset) { switch (asset.status) { case DistributedData::Asset::STATUS_NORMAL: - return { static_cast(DistributedDB::AssetStatus::NORMAL), - static_cast(DistributedDB::AssetOpType::NO_CHANGE) }; + return static_cast(DistributedDB::AssetStatus::NORMAL); case DistributedData::Asset::STATUS_ABNORMAL: - return { static_cast(DistributedDB::AssetStatus::ABNORMAL), - static_cast(DistributedDB::AssetOpType::NO_CHANGE) }; + return static_cast(DistributedDB::AssetStatus::ABNORMAL); case DistributedData::Asset::STATUS_INSERT: - return { static_cast(DistributedDB::AssetStatus::NORMAL), - static_cast(DistributedDB::AssetOpType::INSERT) }; + return static_cast(DistributedDB::AssetStatus::INSERT); case DistributedData::Asset::STATUS_UPDATE: - return { static_cast(DistributedDB::AssetStatus::NORMAL), - static_cast(DistributedDB::AssetOpType::UPDATE) }; + return static_cast(DistributedDB::AssetStatus::UPDATE); case DistributedData::Asset::STATUS_DELETE: - return { static_cast(DistributedDB::AssetStatus::NORMAL), - static_cast(DistributedDB::AssetOpType::DELETE) }; + return static_cast(DistributedDB::AssetStatus::DELETE); case DistributedData::Asset::STATUS_DOWNLOADING: - return { static_cast(DistributedDB::AssetStatus::DOWNLOADING), - static_cast(DistributedDB::AssetOpType::NO_CHANGE) }; + return static_cast(DistributedDB::AssetStatus::DOWNLOADING); default: - return { static_cast(DistributedDB::AssetStatus::NORMAL), - static_cast(DistributedDB::AssetOpType::NO_CHANGE) }; + return static_cast(DistributedDB::AssetStatus::NORMAL); } } diff --git a/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.h b/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.h index 83790b76..3c351ee5 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/value_proxy.h @@ -61,7 +61,7 @@ public: operator DistributedData::Asset(); operator DistributedDB::Asset(); static uint32_t ConvertToDataStatus(const DistributedDB::Asset &asset); - static std::pair ConvertToDBStatus(const DistributedData::Asset &asset); + static uint32_t ConvertToDBStatus(const DistributedData::Asset &asset); private: DistributedData::Asset asset_; diff --git a/datamgr_service/services/distributeddataservice/service/test/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/BUILD.gn index c28c697a..a951e052 100644 --- a/datamgr_service/services/distributeddataservice/service/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/BUILD.gn @@ -54,7 +54,7 @@ ohos_unittest("CloudDataTest") { "ability_base:base", "ability_base:want", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", "kv_store:distributeddata_inner", ] @@ -84,7 +84,7 @@ ohos_unittest("ValueProxyTest") { "ability_base:base", "ability_base:want", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", "kv_store:distributeddata_inner", ] @@ -109,7 +109,7 @@ ohos_unittest("ConfigFactoryTest") { "ability_base:base", "ability_base:want", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] @@ -135,7 +135,7 @@ ohos_unittest("DirectoryManagerTest") { "access_token:libaccesstoken_sdk", "access_token:libnativetoken", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] @@ -160,7 +160,7 @@ ohos_unittest("CryptoManagerTest") { "access_token:libaccesstoken_sdk", "access_token:libnativetoken", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] @@ -189,7 +189,7 @@ ohos_unittest("DeviceMatrixTest") { "access_token:libaccesstoken_sdk", "access_token:libnativetoken", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] diff --git a/datamgr_service/services/distributeddataservice/service/test/config_factory_test.cpp b/datamgr_service/services/distributeddataservice/service/test/config_factory_test.cpp index 02106109..70a6a5ad 100644 --- a/datamgr_service/services/distributeddataservice/service/test/config_factory_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/config_factory_test.cpp @@ -61,7 +61,7 @@ HWTEST_F(ConfigFactoryTest, ComponentConfig, TestSize.Level0) { auto *components = ConfigFactory::GetInstance().GetComponentConfig(); ASSERT_NE(components, nullptr); - ASSERT_EQ(components->size(), 4); + ASSERT_EQ(components->size(), 3); const ComponentConfig &config = (*components)[0]; ASSERT_EQ(config.description, "3rd party adapter"); ASSERT_EQ(config.lib, "libconfigdemo.z.so"); diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/BUILD.gn new file mode 100644 index 00000000..59ad2cd8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/BUILD.gn @@ -0,0 +1,32 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +######################################################################################### +group("fuzztest") { + testonly = true + + deps = [ + "cloudservicestub_fuzzer:fuzztest", + "datashareservicestub_fuzzer:fuzztest", + "kvdbservicestub_fuzzer:fuzztest", + "objectservicestub_fuzzer:fuzztest", + "rdbresultsetstub_fuzzer:fuzztest", + "rdbservicestub_fuzzer:fuzztest", + ] + if (datamgr_service_udmf) { + deps += [ "udmfservice_fuzzer:fuzztest" ] + } +} diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/BUILD.gn new file mode 100644 index 00000000..d39a5b82 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/BUILD.gn @@ -0,0 +1,113 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +##############################hydra-fuzz######################################## +import("//build/config/features.gni") +import("//build/test.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +##############################fuzztest########################################## +ohos_fuzztest("CloudServiceStubFuzzTest") { + module_out_path = "datamgr_service/service" + + include_dirs = [ + "${data_service_path}/adapter/include", + "${data_service_path}/app/src", + "${data_service_path}/framework/include", + "${data_service_path}/service/backup/include", + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/service/cloud", + "${data_service_path}/service/config/include", + "${data_service_path}/service/crypto/include", + "${data_service_path}/service/kvdb", + "${data_service_path}/service/matrix/include", + "${data_service_path}/service/object", + "${data_service_path}/service/permission/include", + "${data_service_path}/service/rdb", + "${kv_store_common_path}", + "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", + "${kv_store_path}/frameworks/innerkitsimpl/kvdb/include", + "${kv_store_distributeddb_path}", + "${kv_store_distributeddb_path}/include/", + "${kv_store_distributeddb_path}/interfaces/include/", + "${kv_store_distributeddb_path}/interfaces/include/relational", + "${dataobject_path}/frameworks/innerkitsimpl/include", + "${relational_store_path}/interfaces/inner_api/cloud_data/include", + "${relational_store_path}/interfaces/inner_api/rdb/include", + "//third_party/json/single_include", + ] + + fuzz_config_file = + "${data_service_path}/service/test/fuzztest/cloudservicestub_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ + "${data_service_path}/service/cloud/cloud_service_impl.cpp", + "${data_service_path}/service/cloud/cloud_service_stub.cpp", + "${data_service_path}/service/cloud/sync_manager.cpp", + "${data_service_path}/service/rdb/rdb_asset_loader.cpp", + "${data_service_path}/service/rdb/rdb_cloud.cpp", + "${data_service_path}/service/rdb/rdb_cloud_data_translate.cpp", + "${data_service_path}/service/rdb/rdb_cursor.cpp", + "${data_service_path}/service/rdb/rdb_general_store.cpp", + "${data_service_path}/service/rdb/rdb_notifier_proxy.cpp", + "${data_service_path}/service/rdb/rdb_query.cpp", + "${data_service_path}/service/rdb/rdb_result_set_impl.cpp", + "${data_service_path}/service/rdb/rdb_result_set_stub.cpp", + "${data_service_path}/service/rdb/rdb_service_impl.cpp", + "${data_service_path}/service/rdb/rdb_service_stub.cpp", + "${data_service_path}/service/rdb/rdb_store_observer_impl.cpp", + "${data_service_path}/service/rdb/rdb_syncer.cpp", + "${data_service_path}/service/rdb/rdb_watcher.cpp", + "${data_service_path}/service/rdb/value_proxy.cpp", + "cloudservicestub_fuzzer.cpp", + ] + + deps = [ + "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service:distributeddatasvc", + "${kv_store_distributeddb_path}:distributeddb", + ] + + external_deps = [ + "ability_base:want", + "ability_base:zuri", + "ability_runtime:ability_manager", + "ability_runtime:dataobs_manager", + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "c_utils:utils", + "device_auth:deviceauth_sdk", + "device_manager:devicemanagersdk", + "hilog:libhilog", + "huks:libhukssdk", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "relational_store:native_rdb", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + + deps = [ ":CloudServiceStubFuzzTest" ] +} +############################################################################### diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/cloudservicestub_fuzzer.cpp b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/cloudservicestub_fuzzer.cpp new file mode 100644 index 00000000..1dada5ad --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/cloudservicestub_fuzzer.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cloudservicestub_fuzzer.h" + +#include +#include + +#include "cloud_service_impl.h" +#include "message_parcel.h" +#include "securec.h" + +using namespace OHOS::CloudData; + +namespace OHOS { +const std::u16string INTERFACE_TOKEN = u"OHOS.CloudData.CloudServer"; +const uint32_t CODE_MIN = 0; +const uint32_t CODE_MAX = 4; + +bool OnRemoteRequestFuzz(const uint8_t *data, size_t size) +{ + uint32_t code = static_cast(*data) % (CODE_MAX - CODE_MIN + 1) + CODE_MIN; + MessageParcel request; + request.WriteInterfaceToken(INTERFACE_TOKEN); + request.WriteBuffer(data, size); + request.RewindRead(0); + MessageParcel reply; + std::shared_ptr cloudServiceStub = std::make_shared(); + cloudServiceStub->OnRemoteRequest(code, request, reply); + return true; +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return 0; + } + + OHOS::OnRemoteRequestFuzz(data, size); + + return 0; +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/cloudservicestub_fuzzer.h b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/cloudservicestub_fuzzer.h new file mode 100644 index 00000000..c007ebba --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/cloudservicestub_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DATAMGR_SERVICE_CLOUD_SERVICE_STUB_FUZZER_H +#define DATAMGR_SERVICE_CLOUD_SERVICE_STUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "cloudservicestub_fuzzer" + +#endif // DATAMGR_SERVICE_CLOUD_SERVICE_STUB_FUZZER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/corpus/init b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/corpus/init new file mode 100644 index 00000000..2b595da0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/project.xml b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/project.xml new file mode 100644 index 00000000..3fdba3e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/BUILD.gn new file mode 100644 index 00000000..e2cbf7fe --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/BUILD.gn @@ -0,0 +1,124 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +##############################hydra-fuzz######################################## +import("//build/config/features.gni") +import("//build/test.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +##############################fuzztest########################################## +ohos_fuzztest("DataShareServiceStubFuzzTest") { + module_out_path = "datamgr_service/service" + + include_dirs = [ + "${data_service_path}/adapter/include", + "${data_service_path}/app/src", + "${data_service_path}/framework/include", + "${data_service_path}/service/data_share/common", + "${data_service_path}/service/data_share/data", + "${data_service_path}/service/data_share/strategies", + "${data_service_path}/service/data_share/subscriber_managers", + "${data_service_path}/service/data_share", + "${datashare_path}/frameworks/native/common/include", + "${datashare_path}/interfaces/inner_api/common/include", + "${datashare_path}/interfaces/inner_api/consumer/include", + "//third_party/json/single_include", + ] + + fuzz_config_file = + "${data_service_path}/service/test/fuzztest/datashareservicestub_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ + "${data_service_path}/service/data_share/common/app_connect_manager.cpp", + "${data_service_path}/service/data_share/common/bundle_mgr_proxy.cpp", + "${data_service_path}/service/data_share/common/db_delegate.cpp", + "${data_service_path}/service/data_share/common/div_strategy.cpp", + "${data_service_path}/service/data_share/common/extension_connect_adaptor.cpp", + "${data_service_path}/service/data_share/common/kv_delegate.cpp", + "${data_service_path}/service/data_share/common/rdb_delegate.cpp", + "${data_service_path}/service/data_share/common/scheduler_manager.cpp", + "${data_service_path}/service/data_share/common/seq_strategy.cpp", + "${data_service_path}/service/data_share/common/uri_utils.cpp", + "${data_service_path}/service/data_share/data/published_data.cpp", + "${data_service_path}/service/data_share/data/resultset_json_formatter.cpp", + "${data_service_path}/service/data_share/data/template_data.cpp", + "${data_service_path}/service/data_share/data_share_obs_proxy.cpp", + "${data_service_path}/service/data_share/data_share_service_impl.cpp", + "${data_service_path}/service/data_share/data_share_service_stub.cpp", + "${data_service_path}/service/data_share/data_share_types_util.cpp", + "${data_service_path}/service/data_share/strategies/data_proxy/load_config_from_data_proxy_node_strategy.cpp", + "${data_service_path}/service/data_share/strategies/data_share/load_config_from_data_share_bundle_info_strategy.cpp", + "${data_service_path}/service/data_share/strategies/delete_strategy.cpp", + "${data_service_path}/service/data_share/strategies/general/check_is_data_proxy_strategy.cpp", + "${data_service_path}/service/data_share/strategies/general/check_is_single_app_strategy.cpp", + "${data_service_path}/service/data_share/strategies/general/cross_permission_strategy.cpp", + "${data_service_path}/service/data_share/strategies/general/empty_strategy.cpp", + "${data_service_path}/service/data_share/strategies/general/load_config_common_strategy.cpp", + "${data_service_path}/service/data_share/strategies/general/load_config_data_info_strategy.cpp", + "${data_service_path}/service/data_share/strategies/general/load_config_from_bundle_info_strategy.cpp", + "${data_service_path}/service/data_share/strategies/general/permission_strategy.cpp", + "${data_service_path}/service/data_share/strategies/general/process_single_app_user_cross_strategy.cpp", + "${data_service_path}/service/data_share/strategies/get_data_strategy.cpp", + "${data_service_path}/service/data_share/strategies/insert_strategy.cpp", + "${data_service_path}/service/data_share/strategies/publish_strategy.cpp", + "${data_service_path}/service/data_share/strategies/query_strategy.cpp", + "${data_service_path}/service/data_share/strategies/rdb_notify_strategy.cpp", + "${data_service_path}/service/data_share/strategies/subscribe_strategy.cpp", + "${data_service_path}/service/data_share/strategies/template_strategy.cpp", + "${data_service_path}/service/data_share/strategies/update_strategy.cpp", + "${data_service_path}/service/data_share/subscriber_managers/published_data_subscriber_manager.cpp", + "${data_service_path}/service/data_share/subscriber_managers/rdb_subscriber_manager.cpp", + "datashareservicestub_fuzzer.cpp", + ] + + deps = [ + "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service/data_share:data_share_service", + "${data_service_path}/service/data_share/gaussdb_rd:gaussdb_rd", + ] + + external_deps = [ + "ability_base:want", + "ability_base:zuri", + "ability_runtime:ability_manager", + "ability_runtime:dataobs_manager", + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "data_share:datashare_common", + "device_manager:devicemanagersdk", + "hilog:libhilog", + "ipc:ipc_core", + "relational_store:native_rdb", + "relational_store:rdb_bms_adapter", + "relational_store:rdb_data_share_adapter", + "samgr:samgr_proxy", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + + deps = [ ":DataShareServiceStubFuzzTest" ] +} +############################################################################### diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/corpus/init b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/corpus/init new file mode 100644 index 00000000..2b595da0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/datashareservicestub_fuzzer.cpp b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/datashareservicestub_fuzzer.cpp new file mode 100644 index 00000000..7fb0269f --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/datashareservicestub_fuzzer.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "datashareservicestub_fuzzer.h" + +#include +#include + +#include "data_share_service_impl.h" +#include "message_parcel.h" +#include "securec.h" + +using namespace OHOS::DataShare; + +namespace OHOS { +const std::u16string INTERFACE_TOKEN = u"OHOS.DataShare.IDataShare"; +const uint32_t CODE_MIN = 0; +const uint32_t CODE_MAX = 16; + +bool OnRemoteRequestFuzz(const uint8_t *data, size_t size) +{ + uint32_t code = static_cast(*data) % (CODE_MAX - CODE_MIN + 1) + CODE_MIN; + MessageParcel request; + request.WriteInterfaceToken(INTERFACE_TOKEN); + request.WriteBuffer(data, size); + request.RewindRead(0); + MessageParcel reply; + std::shared_ptr dataShareServiceStub = std::make_shared(); + dataShareServiceStub->OnRemoteRequest(code, request, reply); + return true; +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return 0; + } + + OHOS::OnRemoteRequestFuzz(data, size); + + return 0; +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/datashareservicestub_fuzzer.h b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/datashareservicestub_fuzzer.h new file mode 100644 index 00000000..28399e52 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/datashareservicestub_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DATAMGR_SERVICE_DATA_SHARE_SERVICE_STUB_FUZZER_H +#define DATAMGR_SERVICE_DATA_SHARE_SERVICE_STUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "datashareservicestub_fuzzer" + +#endif // DATAMGR_SERVICE_DATA_SHARE_SERVICE_STUB_FUZZER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/project.xml b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/project.xml new file mode 100644 index 00000000..3fdba3e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/BUILD.gn new file mode 100644 index 00000000..8998072c --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/BUILD.gn @@ -0,0 +1,110 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +##############################hydra-fuzz######################################## +import("//build/config/features.gni") +import("//build/test.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +##############################fuzztest########################################## +ohos_fuzztest("KvdbServiceStubFuzzTest") { + module_out_path = "datamgr_service/service" + + include_dirs = [ + "${data_service_path}/adapter/include", + "${data_service_path}/app/src", + "${data_service_path}/framework/include", + "${data_service_path}/service/backup/include", + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/service/config/include", + "${data_service_path}/service/crypto/include", + "${data_service_path}/service/kvdb", + "${data_service_path}/service/matrix/include", + "${data_service_path}/service/permission/include", + "${kv_store_common_path}", + "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", + "${kv_store_path}/frameworks/innerkitsimpl/kvdb/include", + "${kv_store_distributeddb_path}", + "${kv_store_distributeddb_path}/include/", + "${kv_store_distributeddb_path}/interfaces/include/", + "${kv_store_distributeddb_path}/interfaces/include/relational", + "//third_party/json/single_include", + ] + + fuzz_config_file = + "${data_service_path}/service/test/fuzztest/kvdbservicestub_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ + "${data_service_path}/service/backup/src/backup_manager.cpp", + "${data_service_path}/service/bootstrap/src/bootstrap.cpp", + "${data_service_path}/service/config/src/config_factory.cpp", + "${data_service_path}/service/config/src/model/backup_config.cpp", + "${data_service_path}/service/config/src/model/checker_config.cpp", + "${data_service_path}/service/config/src/model/component_config.cpp", + "${data_service_path}/service/config/src/model/directory_config.cpp", + "${data_service_path}/service/config/src/model/global_config.cpp", + "${data_service_path}/service/config/src/model/network_config.cpp", + "${data_service_path}/service/config/src/model/protocol_config.cpp", + "${data_service_path}/service/crypto/src/crypto_manager.cpp", + "${data_service_path}/service/kvdb/auth_delegate.cpp", + "${data_service_path}/service/kvdb/kvdb_exporter.cpp", + "${data_service_path}/service/kvdb/kvdb_service_impl.cpp", + "${data_service_path}/service/kvdb/kvdb_service_stub.cpp", + "${data_service_path}/service/kvdb/kvstore_sync_manager.cpp", + "${data_service_path}/service/kvdb/query_helper.cpp", + "${data_service_path}/service/kvdb/store_cache.cpp", + "${data_service_path}/service/kvdb/upgrade.cpp", + "${data_service_path}/service/kvdb/user_delegate.cpp", + "${data_service_path}/service/matrix/src/device_matrix.cpp", + "${data_service_path}/service/matrix/src/matrix_event.cpp", + "${data_service_path}/service/permission/src/permit_delegate.cpp", + "kvdbservicestub_fuzzer.cpp", + ] + + deps = [ + "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/framework:distributeddatasvcfwk", + "${kv_store_distributeddb_path}:distributeddb", + ] + + external_deps = [ + "ability_base:want", + "ability_base:zuri", + "ability_runtime:ability_manager", + "ability_runtime:dataobs_manager", + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "c_utils:utils", + "device_auth:deviceauth_sdk", + "device_manager:devicemanagersdk", + "hilog:libhilog", + "huks:libhukssdk", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + + deps = [ ":KvdbServiceStubFuzzTest" ] +} +############################################################################### diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/corpus/init b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/corpus/init new file mode 100644 index 00000000..2b595da0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/kvdbservicestub_fuzzer.cpp b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/kvdbservicestub_fuzzer.cpp new file mode 100644 index 00000000..b01aa999 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/kvdbservicestub_fuzzer.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kvdbservicestub_fuzzer.h" + +#include +#include + +#include "kvdb_service_impl.h" +#include "message_parcel.h" +#include "securec.h" + +using namespace OHOS::DistributedKv; + +namespace OHOS { +const std::u16string INTERFACE_TOKEN = u"OHOS.DistributedKv.KVFeature"; +const uint32_t CODE_MIN = 0; +const uint32_t CODE_MAX = 16; + +bool OnRemoteRequestFuzz(const uint8_t *data, size_t size) +{ + uint32_t code = static_cast(*data) % (CODE_MAX - CODE_MIN + 1) + CODE_MIN; + MessageParcel request; + request.WriteInterfaceToken(INTERFACE_TOKEN); + request.WriteBuffer(data, size); + request.RewindRead(0); + MessageParcel reply; + std::shared_ptr kvdbServiceStub = std::make_shared(); + kvdbServiceStub->OnRemoteRequest(code, request, reply); + return true; +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return 0; + } + + OHOS::OnRemoteRequestFuzz(data, size); + + return 0; +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/kvdbservicestub_fuzzer.h b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/kvdbservicestub_fuzzer.h new file mode 100644 index 00000000..9fba238a --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/kvdbservicestub_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DATAMGR_SERVICE_KVDB_SERVICE_STUB_FUZZER_H +#define DATAMGR_SERVICE_KVDB_SERVICE_STUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "kvdbservicestub_fuzzer" + +#endif // DATAMGR_SERVICE_KVDB_SERVICE_STUB_FUZZER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/project.xml b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/project.xml new file mode 100644 index 00000000..3fdba3e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/BUILD.gn new file mode 100644 index 00000000..2db37d6e --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/BUILD.gn @@ -0,0 +1,110 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +##############################hydra-fuzz######################################## +import("//build/config/features.gni") +import("//build/test.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +##############################fuzztest########################################## +ohos_fuzztest("ObjectServiceStubFuzzTest") { + module_out_path = "datamgr_service/service" + + include_dirs = [ + "${data_service_path}/adapter/include", + "${data_service_path}/app/src", + "${data_service_path}/framework/include", + "${data_service_path}/service/backup/include", + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/service/cloud", + "${data_service_path}/service/config/include", + "${data_service_path}/service/crypto/include", + "${data_service_path}/service/data_share", + "${data_service_path}/service/kvdb", + "${data_service_path}/service/matrix/include", + "${data_service_path}/service/object", + "${data_service_path}/service/permission/include", + "${data_service_path}/service/rdb", + "${kv_store_common_path}", + "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", + "${kv_store_path}/frameworks/innerkitsimpl/kvdb/include", + "${kv_store_distributeddb_path}", + "${kv_store_distributeddb_path}/include/", + "${kv_store_distributeddb_path}/interfaces/include/", + "${kv_store_distributeddb_path}/interfaces/include/relational", + "${dataobject_path}/frameworks/innerkitsimpl/include", + "//third_party/json/single_include", + ] + + fuzz_config_file = + "${data_service_path}/service/test/fuzztest/objectservicestub_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ + "${data_service_path}/service/bootstrap/src/bootstrap.cpp", + "${data_service_path}/service/config/src/config_factory.cpp", + "${data_service_path}/service/config/src/model/backup_config.cpp", + "${data_service_path}/service/config/src/model/checker_config.cpp", + "${data_service_path}/service/config/src/model/component_config.cpp", + "${data_service_path}/service/config/src/model/directory_config.cpp", + "${data_service_path}/service/config/src/model/global_config.cpp", + "${data_service_path}/service/config/src/model/network_config.cpp", + "${data_service_path}/service/config/src/model/protocol_config.cpp", + "${data_service_path}/service/crypto/src/crypto_manager.cpp", + "${data_service_path}/service/matrix/src/device_matrix.cpp", + "${data_service_path}/service/matrix/src/matrix_event.cpp", + "${data_service_path}/service/object/object_callback_proxy.cpp", + "${data_service_path}/service/object/object_data_listener.cpp", + "${data_service_path}/service/object/object_manager.cpp", + "${data_service_path}/service/object/object_service_impl.cpp", + "${data_service_path}/service/object/object_service_stub.cpp", + "${data_service_path}/service/permission/src/permit_delegate.cpp", + "objectservicestub_fuzzer.cpp", + ] + + deps = [ + "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/framework:distributeddatasvcfwk", + "${kv_store_distributeddb_path}:distributeddb", + ] + + external_deps = [ + "ability_base:want", + "ability_base:zuri", + "ability_runtime:ability_manager", + "ability_runtime:dataobs_manager", + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "c_utils:utils", + "device_auth:deviceauth_sdk", + "device_manager:devicemanagersdk", + "hilog:libhilog", + "huks:libhukssdk", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + + deps = [ ":ObjectServiceStubFuzzTest" ] +} +############################################################################### diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/corpus/init b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/corpus/init new file mode 100644 index 00000000..2b595da0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/objectservicestub_fuzzer.cpp b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/objectservicestub_fuzzer.cpp new file mode 100644 index 00000000..410f53b1 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/objectservicestub_fuzzer.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "objectservicestub_fuzzer.h" + +#include +#include + +#include "object_service_impl.h" +#include "message_parcel.h" +#include "securec.h" + +using namespace OHOS::DistributedObject; + +namespace OHOS { +const std::u16string INTERFACE_TOKEN = u"OHOS.DistributedObject.IObjectService"; +const uint32_t CODE_MIN = 0; +const uint32_t CODE_MAX = 4; + +bool OnRemoteRequestFuzz(const uint8_t *data, size_t size) +{ + uint32_t code = static_cast(*data) % (CODE_MAX - CODE_MIN + 1) + CODE_MIN; + MessageParcel request; + request.WriteInterfaceToken(INTERFACE_TOKEN); + request.WriteBuffer(data, size); + request.RewindRead(0); + MessageParcel reply; + std::shared_ptr objectServiceStub = std::make_shared(); + objectServiceStub->OnRemoteRequest(code, request, reply); + return true; +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return 0; + } + + OHOS::OnRemoteRequestFuzz(data, size); + + return 0; +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/objectservicestub_fuzzer.h b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/objectservicestub_fuzzer.h new file mode 100644 index 00000000..019e06f5 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/objectservicestub_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DATAMGR_SERVICE_OBJECT_SERVICE_STUB_FUZZER_H +#define DATAMGR_SERVICE_OBJECT_SERVICE_STUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "objectservicestub_fuzzer" + +#endif // DATAMGR_SERVICE_OBJECT_SERVICE_STUB_FUZZER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/project.xml b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/project.xml new file mode 100644 index 00000000..3fdba3e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/BUILD.gn new file mode 100644 index 00000000..494fd1c0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/BUILD.gn @@ -0,0 +1,123 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +##############################hydra-fuzz######################################## +import("//build/config/features.gni") +import("//build/test.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +##############################fuzztest########################################## +ohos_fuzztest("RdbResultSetStubFuzzTest") { + module_out_path = "datamgr_service/service" + + include_dirs = [ + "${data_service_path}/adapter/include", + "${data_service_path}/app/src", + "${data_service_path}/framework/include", + "${data_service_path}/service/backup/include", + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/service/cloud", + "${data_service_path}/service/config/include", + "${data_service_path}/service/crypto/include", + "${data_service_path}/service/data_share", + "${data_service_path}/service/kvdb", + "${data_service_path}/service/matrix/include", + "${data_service_path}/service/object", + "${data_service_path}/service/permission/include", + "${data_service_path}/service/rdb", + "${kv_store_common_path}", + "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", + "${kv_store_path}/frameworks/innerkitsimpl/kvdb/include", + "${kv_store_distributeddb_path}", + "${kv_store_distributeddb_path}/include/", + "${kv_store_distributeddb_path}/interfaces/include/", + "${kv_store_distributeddb_path}/interfaces/include/relational", + "${dataobject_path}/frameworks/innerkitsimpl/include", + "${relational_store_path}/interfaces/inner_api/cloud_data/include", + "${relational_store_path}/interfaces/inner_api/rdb/include", + "//third_party/json/single_include", + ] + + fuzz_config_file = + "${data_service_path}/service/test/fuzztest/rdbresultsetstub_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ + "${data_service_path}/service/bootstrap/src/bootstrap.cpp", + "${data_service_path}/service/config/src/config_factory.cpp", + "${data_service_path}/service/config/src/model/backup_config.cpp", + "${data_service_path}/service/config/src/model/checker_config.cpp", + "${data_service_path}/service/config/src/model/component_config.cpp", + "${data_service_path}/service/config/src/model/directory_config.cpp", + "${data_service_path}/service/config/src/model/global_config.cpp", + "${data_service_path}/service/config/src/model/network_config.cpp", + "${data_service_path}/service/config/src/model/protocol_config.cpp", + "${data_service_path}/service/crypto/src/crypto_manager.cpp", + "${data_service_path}/service/matrix/src/device_matrix.cpp", + "${data_service_path}/service/matrix/src/matrix_event.cpp", + "${data_service_path}/service/permission/src/permit_delegate.cpp", + "${data_service_path}/service/rdb/rdb_asset_loader.cpp", + "${data_service_path}/service/rdb/rdb_cloud.cpp", + "${data_service_path}/service/rdb/rdb_cloud_data_translate.cpp", + "${data_service_path}/service/rdb/rdb_cursor.cpp", + "${data_service_path}/service/rdb/rdb_general_store.cpp", + "${data_service_path}/service/rdb/rdb_notifier_proxy.cpp", + "${data_service_path}/service/rdb/rdb_query.cpp", + "${data_service_path}/service/rdb/rdb_result_set_impl.cpp", + "${data_service_path}/service/rdb/rdb_result_set_stub.cpp", + "${data_service_path}/service/rdb/rdb_service_impl.cpp", + "${data_service_path}/service/rdb/rdb_service_stub.cpp", + "${data_service_path}/service/rdb/rdb_store_observer_impl.cpp", + "${data_service_path}/service/rdb/rdb_syncer.cpp", + "${data_service_path}/service/rdb/rdb_watcher.cpp", + "${data_service_path}/service/rdb/value_proxy.cpp", + "rdbresultsetstub_fuzzer.cpp", + ] + + deps = [ + "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/framework:distributeddatasvcfwk", + "${kv_store_distributeddb_path}:distributeddb", + ] + + external_deps = [ + "ability_base:want", + "ability_base:zuri", + "ability_runtime:ability_manager", + "ability_runtime:dataobs_manager", + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "c_utils:utils", + "device_auth:deviceauth_sdk", + "device_manager:devicemanagersdk", + "hilog:libhilog", + "huks:libhukssdk", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "relational_store:native_rdb", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + + deps = [ ":RdbResultSetStubFuzzTest" ] +} +############################################################################### diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/corpus/init b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/corpus/init new file mode 100644 index 00000000..2b595da0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/project.xml b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/project.xml new file mode 100644 index 00000000..3fdba3e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/rdbresultsetstub_fuzzer.cpp b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/rdbresultsetstub_fuzzer.cpp new file mode 100644 index 00000000..a1542122 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/rdbresultsetstub_fuzzer.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rdbresultsetstub_fuzzer.h" + +#include +#include + +#include "rdb_result_set_impl.h" +#include "message_parcel.h" +#include "securec.h" + +using namespace OHOS::DistributedRdb; + +namespace OHOS { +const std::u16string INTERFACE_TOKEN = u"OHOS::NativeRdb.IResultSet"; +const uint32_t CODE_MIN = 0; +const uint32_t CODE_MAX = 24; + +bool OnRemoteRequestFuzz(const uint8_t *data, size_t size) +{ + uint32_t code = static_cast(*data) % (CODE_MAX - CODE_MIN + 1) + CODE_MIN; + MessageParcel request; + request.WriteInterfaceToken(INTERFACE_TOKEN); + request.WriteBuffer(data, size); + request.RewindRead(0); + MessageParcel reply; + MessageOption option; + std::shared_ptr dbResultSet; + std::shared_ptr rdbResultSetStub = std::make_shared(dbResultSet); + rdbResultSetStub->OnRemoteRequest(code, request, reply, option); + return true; +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return 0; + } + + OHOS::OnRemoteRequestFuzz(data, size); + + return 0; +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/rdbresultsetstub_fuzzer.h b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/rdbresultsetstub_fuzzer.h new file mode 100644 index 00000000..b8f8cc37 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/rdbresultsetstub_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DATAMGR_SERVICE_RDB_RESULT_SET_STUB_FUZZER_H +#define DATAMGR_SERVICE_RDB_RESULT_SET_STUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "rdbresultsetstub_fuzzer" + +#endif // DATAMGR_SERVICE_RDB_RESULT_SET_STUB_FUZZER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/BUILD.gn new file mode 100644 index 00000000..9fef0947 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/BUILD.gn @@ -0,0 +1,111 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +##############################hydra-fuzz######################################## +import("//build/config/features.gni") +import("//build/test.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +##############################fuzztest########################################## +ohos_fuzztest("RdbServiceStubFuzzTest") { + module_out_path = "datamgr_service/service" + + include_dirs = [ + "${data_service_path}/adapter/include", + "${data_service_path}/app/src", + "${data_service_path}/framework/include", + "${data_service_path}/service/backup/include", + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/service/cloud", + "${data_service_path}/service/config/include", + "${data_service_path}/service/crypto/include", + "${data_service_path}/service/data_share", + "${data_service_path}/service/kvdb", + "${data_service_path}/service/matrix/include", + "${data_service_path}/service/object", + "${data_service_path}/service/permission/include", + "${data_service_path}/service/rdb", + "${kv_store_common_path}", + "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", + "${kv_store_path}/frameworks/innerkitsimpl/kvdb/include", + "${kv_store_distributeddb_path}", + "${kv_store_distributeddb_path}/include/", + "${kv_store_distributeddb_path}/interfaces/include/", + "${kv_store_distributeddb_path}/interfaces/include/relational", + "${dataobject_path}/frameworks/innerkitsimpl/include", + "${relational_store_path}/interfaces/inner_api/cloud_data/include", + "${relational_store_path}/interfaces/inner_api/rdb/include", + "//third_party/json/single_include", + ] + + fuzz_config_file = + "${data_service_path}/service/test/fuzztest/rdbservicestub_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ + "${data_service_path}/service/rdb/rdb_asset_loader.cpp", + "${data_service_path}/service/rdb/rdb_cloud.cpp", + "${data_service_path}/service/rdb/rdb_cloud_data_translate.cpp", + "${data_service_path}/service/rdb/rdb_cursor.cpp", + "${data_service_path}/service/rdb/rdb_general_store.cpp", + "${data_service_path}/service/rdb/rdb_notifier_proxy.cpp", + "${data_service_path}/service/rdb/rdb_query.cpp", + "${data_service_path}/service/rdb/rdb_result_set_impl.cpp", + "${data_service_path}/service/rdb/rdb_result_set_stub.cpp", + "${data_service_path}/service/rdb/rdb_service_impl.cpp", + "${data_service_path}/service/rdb/rdb_service_stub.cpp", + "${data_service_path}/service/rdb/rdb_store_observer_impl.cpp", + "${data_service_path}/service/rdb/rdb_syncer.cpp", + "${data_service_path}/service/rdb/rdb_watcher.cpp", + "${data_service_path}/service/rdb/value_proxy.cpp", + "rdbservicestub_fuzzer.cpp", + ] + + deps = [ + "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service:distributeddatasvc", + "${kv_store_distributeddb_path}:distributeddb", + ] + + external_deps = [ + "ability_base:want", + "ability_base:zuri", + "ability_runtime:ability_manager", + "ability_runtime:dataobs_manager", + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "c_utils:utils", + "device_auth:deviceauth_sdk", + "device_manager:devicemanagersdk", + "hilog:libhilog", + "huks:libhukssdk", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "relational_store:native_rdb", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + + deps = [ ":RdbServiceStubFuzzTest" ] +} +############################################################################### diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/corpus/init b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/corpus/init new file mode 100644 index 00000000..2b595da0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/project.xml b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/project.xml new file mode 100644 index 00000000..3fdba3e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/rdbservicestub_fuzzer.cpp b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/rdbservicestub_fuzzer.cpp new file mode 100644 index 00000000..aa7737e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/rdbservicestub_fuzzer.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rdbservicestub_fuzzer.h" + +#include +#include + +#include "rdb_service_impl.h" +#include "message_parcel.h" +#include "securec.h" + +using namespace OHOS::DistributedRdb; + +namespace OHOS { +const std::u16string INTERFACE_TOKEN = u"OHOS.DistributedRdb.IRdbService"; +const uint32_t CODE_MIN = 0; +const uint32_t CODE_MAX = 10; + +bool OnRemoteRequestFuzz(const uint8_t *data, size_t size) +{ + uint32_t code = static_cast(*data) % (CODE_MAX - CODE_MIN + 1) + CODE_MIN; + MessageParcel request; + request.WriteInterfaceToken(INTERFACE_TOKEN); + request.WriteBuffer(data, size); + request.RewindRead(0); + MessageParcel reply; + std::shared_ptr rdbServiceStub = std::make_shared(); + rdbServiceStub->OnRemoteRequest(code, request, reply); + return true; +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return 0; + } + + OHOS::OnRemoteRequestFuzz(data, size); + + return 0; +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/rdbservicestub_fuzzer.h b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/rdbservicestub_fuzzer.h new file mode 100644 index 00000000..582118e9 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/rdbservicestub_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DATAMGR_SERVICE_RDB_SERVICE_STUB_FUZZER_H +#define DATAMGR_SERVICE_RDB_SERVICE_STUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "rdbservicestub_fuzzer" + +#endif // DATAMGR_SERVICE_RDB_SERVICE_STUB_FUZZER_HH \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/BUILD.gn new file mode 100644 index 00000000..4656e9aa --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/BUILD.gn @@ -0,0 +1,71 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +##############################hydra-fuzz######################################## +import("//build/config/features.gni") +import("//build/test.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +##############################fuzztest########################################## +ohos_fuzztest("UdmfServiceFuzzTest") { + module_out_path = "datamgr_service/service" + + include_dirs = [ + "${udmf_path}/framework/common", + "${udmf_path}/interfaces/innerkits/common", + "${udmf_path}/interfaces/innerkits/data", + "${data_service_path}/framework/include", + "${data_service_path}/service/udmf/lifecycle", + "${data_service_path}/service/udmf/permission", + "${data_service_path}/service/udmf/preprocess", + "${data_service_path}/service/udmf/store", + "${data_service_path}/service/udmf", + "${kv_store_path}/frameworks/common", + ] + + fuzz_config_file = + "${data_service_path}/service/test/fuzztest/udmfservice_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ "udmfservice_fuzzer.cpp" ] + + deps = [ + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service/udmf:udmf_server", + ] + + external_deps = [ + "ability_base:zuri", + "ability_runtime:uri_permission_mgr", + "access_token:libaccesstoken_sdk", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "udmf:udmf_client", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + + deps = [ ":UdmfServiceFuzzTest" ] +} +############################################################################### diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/corpus/init b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/corpus/init new file mode 100644 index 00000000..2b595da0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/project.xml b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/project.xml new file mode 100644 index 00000000..3fdba3e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/udmfservice_fuzzer.cpp b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/udmfservice_fuzzer.cpp new file mode 100644 index 00000000..010f5bda --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/udmfservice_fuzzer.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "udmfservice_fuzzer.h" + +#include +#include + +#include "udmf_service_impl.h" +#include "message_parcel.h" +#include "securec.h" + +using namespace OHOS::UDMF; + +namespace OHOS { +const std::u16string INTERFACE_TOKEN = u"OHOS.UDMF.UdmfService"; + +bool OnRemoteRequestFuzz(const uint8_t* data, size_t size) +{ + uint32_t code = static_cast(*data); + MessageParcel request; + request.WriteInterfaceToken(INTERFACE_TOKEN); + request.WriteBuffer(data, size); + request.RewindRead(0); + MessageParcel reply; + std::shared_ptr udmfServiceStub = std::make_shared(); + udmfServiceStub->OnRemoteRequest(code, request, reply); + return true; +} +} + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + if (data == nullptr) { + return 0; + } + + OHOS::OnRemoteRequestFuzz(data, size); + + return 0; +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/udmfservice_fuzzer.h b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/udmfservice_fuzzer.h new file mode 100644 index 00000000..d86d273e --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/udmfservice_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SERVICE_FUZZER_H +#define UDMF_SERVICE_FUZZER_H + +#define FUZZ_PROJECT_NAME "udmfservice_fuzzer" + +#endif // UDMF_SERVICE_FUZZER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/udmf/BUILD.gn b/datamgr_service/services/distributeddataservice/service/udmf/BUILD.gn index 64077d45..9997263e 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/udmf/BUILD.gn @@ -13,10 +13,6 @@ import("//build/ohos.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") -group("build_module") { - deps = [ ":udmf_server" ] -} - config("module_public_config") { visibility = [ ":*" ] @@ -62,7 +58,7 @@ ohos_shared_library("udmf_server") { "access_token:libaccesstoken_sdk", "bundle_framework:appexecfwk_core", "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", "kv_store:distributeddata_inner", "udmf:udmf_client", diff --git a/datamgr_service/services/distributeddataservice/service/udmf/data_manager.cpp b/datamgr_service/services/distributeddataservice/service/udmf/data_manager.cpp index c2d3b94f..7b4bc0a3 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/data_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/data_manager.cpp @@ -56,13 +56,13 @@ int32_t DataManager::SaveData(CustomOption &option, UnifiedData &unifiedData, st } // imput runtime info before put it into store and save one privilege - PreProcessUtils utils = PreProcessUtils::GetInstance(); - if (!utils.RuntimeDataImputation(unifiedData, option)) { - ZLOGE("Imputation failed, %{public}s", utils.errorStr.c_str()); + if (PreProcessUtils::RuntimeDataImputation(unifiedData, option) != E_OK) { + ZLOGE("Imputation failed"); return E_UNKNOWN; } - for (const auto &record : unifiedData.GetRecords()) { - record->SetUid(PreProcessUtils::GetInstance().IdGenerator()); + for (auto &record : unifiedData.GetRecords()) { + std::string uid = PreProcessUtils::IdGenerator(); + record->SetUid(uid); } std::string intention = unifiedData.GetRuntime()->key.intention; @@ -113,7 +113,7 @@ int32_t DataManager::RetrieveData(const QueryOption &query, UnifiedData &unified return E_NO_PERMISSION; } std::string bundleName; - if (!PreProcessUtils::GetInstance().GetHapBundleNameByToken(query.tokenId, bundleName)) { + if (!PreProcessUtils::GetHapBundleNameByToken(query.tokenId, bundleName)) { return E_ERROR; } if (runtime->createPackage != bundleName) { @@ -185,10 +185,10 @@ int32_t DataManager::UpdateData(const QueryOption &query, UnifiedData &unifiedDa return E_INVALID_PARAMETERS; } std::shared_ptr runtime = data.GetRuntime(); - runtime->lastModifiedTime = PreProcessUtils::GetInstance().GetTimeStamp(); + runtime->lastModifiedTime = PreProcessUtils::GetTimeStamp(); unifiedData.SetRuntime(*runtime); - for (const auto &record : unifiedData.GetRecords()) { - record->SetUid(PreProcessUtils::GetInstance().IdGenerator()); + for (auto &record : unifiedData.GetRecords()) { + record->SetUid(PreProcessUtils::IdGenerator()); } if (store->Update(unifiedData) != E_OK) { ZLOGE("Update unified data failed, intention: %{public}s.", key.intention.c_str()); @@ -253,9 +253,7 @@ int32_t DataManager::AddPrivilege(const QueryOption &query, const Privilege &pri } std::string processName; - PreProcessUtils utils = PreProcessUtils::GetInstance(); - if (!utils.GetNativeProcessNameByToken(query.tokenId, processName)) { - ZLOGE("%{public}s", utils.errorStr.c_str()); + if (!PreProcessUtils::GetNativeProcessNameByToken(query.tokenId, processName)) { return E_UNKNOWN; } diff --git a/datamgr_service/services/distributeddataservice/service/udmf/data_manager.h b/datamgr_service/services/distributeddataservice/service/udmf/data_manager.h index 518e288d..aab40398 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/data_manager.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/data_manager.h @@ -22,9 +22,10 @@ #include #include "error_code.h" -#include "store_cache1.h" +#include "store/store_cache.h" #include "unified_data.h" #include "unified_types.h" +#include "store.h" namespace OHOS { namespace UDMF { @@ -46,7 +47,7 @@ public: private: DataManager(); int32_t QueryDataCommon(const QueryOption &query, std::vector &dataSet, std::shared_ptr &store); - StoreCache1 storeCache_; + StoreCache storeCache_; std::map authorizationMap_; }; } // namespace UDMF diff --git a/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.cpp b/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.cpp index 280866e6..7e790fb9 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.cpp @@ -88,7 +88,7 @@ Status LifeCyclePolicy::GetTimeoutKeys( ZLOGD("entries is empty."); return E_OK; } - auto curTime = PreProcessUtils::GetInstance().GetTimeStamp(); + auto curTime = PreProcessUtils::GetTimeStamp(); for (const auto &data : datas) { if (curTime > data.GetRuntime()->createTime + duration_cast(interval).count() || curTime < data.GetRuntime()->createTime) { diff --git a/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.h b/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.h index 175c997c..c3f45d8d 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.h @@ -18,9 +18,10 @@ #include #include -#include "store.h" -#include "store_cache1.h" +#include "store/store_cache.h" #include "unified_key.h" +#include "error_code.h" +#include "store.h" namespace OHOS { namespace UDMF { @@ -37,7 +38,7 @@ public: private: static const std::string DATA_PREFIX; - StoreCache1 storeCache_; + StoreCache storeCache_; }; } // namespace UDMF } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.cpp b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.cpp index 6962c69b..130ffa20 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.cpp @@ -17,6 +17,7 @@ #include +#include "error_code.h" #include "accesstoken_kit.h" #include "bundlemgr/bundle_mgr_client_impl.h" #include "ipc_skeleton.h" @@ -25,18 +26,11 @@ namespace OHOS { namespace UDMF { static constexpr int ID_LEN = 32; const char SPECIAL = '^'; -PreProcessUtils &PreProcessUtils::GetInstance() -{ - static auto instance = new PreProcessUtils(); - return *instance; -} - -bool PreProcessUtils::RuntimeDataImputation(UnifiedData &data, CustomOption &option) +int32_t PreProcessUtils::RuntimeDataImputation(UnifiedData &data, CustomOption &option) { auto it = UD_INTENTION_MAP.find(option.intention); if (it == UD_INTENTION_MAP.end()) { - errorStr = "invalid intention"; - return false; + return E_UNKNOWN; } std::string bundleName; GetHapBundleNameByToken(option.tokenId, bundleName); @@ -51,7 +45,7 @@ bool PreProcessUtils::RuntimeDataImputation(UnifiedData &data, CustomOption &opt runtime.sourcePackage = bundleName; runtime.createPackage = bundleName; data.SetRuntime(runtime); - return true; + return E_OK; } std::string PreProcessUtils::IdGenerator() @@ -82,7 +76,6 @@ bool PreProcessUtils::GetHapBundleNameByToken(int tokenId, std::string &bundleNa Security::AccessToken::HapTokenInfo hapInfo; if (Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, hapInfo) != Security::AccessToken::AccessTokenKitRet::RET_SUCCESS) { - errorStr = "get bundle info error"; return false; } bundleName = hapInfo.bundleName; @@ -94,7 +87,6 @@ bool PreProcessUtils::GetNativeProcessNameByToken(int tokenId, std::string &proc Security::AccessToken::NativeTokenInfo nativeInfo; if (Security::AccessToken::AccessTokenKit::GetNativeTokenInfo(tokenId, nativeInfo) != Security::AccessToken::AccessTokenKitRet::RET_SUCCESS) { - errorStr = "get native info error"; return false; } processName = nativeInfo.processName; diff --git a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.h b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.h index 2ab12d0f..175027ea 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.h @@ -27,16 +27,11 @@ namespace OHOS { namespace UDMF { class PreProcessUtils { public: - static PreProcessUtils &GetInstance(); - /* - * Data Imputation - */ - bool RuntimeDataImputation(UnifiedData &data, CustomOption &option); - std::string IdGenerator(); - time_t GetTimeStamp(); - bool GetHapBundleNameByToken(int tokenId, std::string &bundleName); - bool GetNativeProcessNameByToken(int tokenId, std::string &processName); - std::string errorStr; + static int32_t RuntimeDataImputation(UnifiedData &data, CustomOption &option); + static std::string IdGenerator(); + static time_t GetTimeStamp(); + static bool GetHapBundleNameByToken(int tokenId, std::string &bundleName); + static bool GetNativeProcessNameByToken(int tokenId, std::string &processName); }; } // namespace UDMF } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.cpp b/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.cpp index 3a2dc11b..cb957545 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.cpp @@ -32,6 +32,7 @@ const std::string RuntimeStore::BASE_DIR = "/data/service/el1/public/database/di RuntimeStore::RuntimeStore(const std::string &storeId) : storeId_({ storeId }) { + UpdateTime(); ZLOGI("Construct runtimeStore: %{public}s.", storeId_.storeId.c_str()); } @@ -43,6 +44,7 @@ RuntimeStore::~RuntimeStore() Status RuntimeStore::Put(const UnifiedData &unifiedData) { + UpdateTime(); std::vector entries; std::string unifiedKey = unifiedData.GetRuntime()->key.GetUnifiedKey(); // add unified record @@ -77,6 +79,7 @@ Status RuntimeStore::Put(const UnifiedData &unifiedData) Status RuntimeStore::Get(const std::string &key, UnifiedData &unifiedData) { + UpdateTime(); std::vector entries; if (GetEntries(key, entries) != E_OK) { ZLOGI("GetEntries failed, dataPrefix: %{public}s.", key.c_str()); @@ -91,6 +94,7 @@ Status RuntimeStore::Get(const std::string &key, UnifiedData &unifiedData) Status RuntimeStore::GetSummary(const std::string &key, Summary &summary) { + UpdateTime(); UnifiedData unifiedData; if (Get(key, unifiedData) != E_OK) { ZLOGE("Get unified data failed."); @@ -112,6 +116,7 @@ Status RuntimeStore::GetSummary(const std::string &key, Summary &summary) Status RuntimeStore::Update(const UnifiedData &unifiedData) { + UpdateTime(); std::string key = unifiedData.GetRuntime()->key.key; if (Delete(key) != E_OK) { ZLOGE("Delete unified data failed."); @@ -126,6 +131,7 @@ Status RuntimeStore::Update(const UnifiedData &unifiedData) Status RuntimeStore::Delete(const std::string &key) { + UpdateTime(); std::vector entries; if (GetEntries(key, entries) != E_OK) { ZLOGE("GetEntries failed, dataPrefix: %{public}s.", key.c_str()); @@ -144,6 +150,7 @@ Status RuntimeStore::Delete(const std::string &key) Status RuntimeStore::DeleteBatch(const std::vector &unifiedKeys) { + UpdateTime(); ZLOGD("called!"); if (unifiedKeys.empty()) { ZLOGD("No need to delete!"); @@ -160,6 +167,7 @@ Status RuntimeStore::DeleteBatch(const std::vector &unifiedKeys) Status RuntimeStore::Sync(const std::vector &devices) { + UpdateTime(); SameProcessIpcGuard ipcGuard; DistributedKv::Status status = kvStore_->Sync(devices, SyncMode::PULL); if (status != DistributedKv::Status::SUCCESS) { @@ -171,11 +179,13 @@ Status RuntimeStore::Sync(const std::vector &devices) Status RuntimeStore::Clear() { + UpdateTime(); return Delete(DATA_PREFIX); } Status RuntimeStore::GetBatchData(const std::string &dataPrefix, std::vector &unifiedDataSet) { + UpdateTime(); std::vector entries; auto status = GetEntries(dataPrefix, entries); if (status != E_OK) { diff --git a/datamgr_service/services/distributeddataservice/service/udmf/store/store.h b/datamgr_service/services/distributeddataservice/service/udmf/store/store.h index ccd1c41b..ab5de3eb 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/store/store.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/store/store.h @@ -16,7 +16,9 @@ #ifndef UDMF_STORE_H #define UDMF_STORE_H +#include #include +#include #include "error_code.h" #include "unified_data.h" @@ -27,6 +29,7 @@ namespace OHOS { namespace UDMF { class Store { public: + using Time = std::chrono::steady_clock::time_point; virtual Status Put(const UnifiedData &unifiedData) = 0; virtual Status Get(const std::string &key, UnifiedData &unifiedData) = 0; virtual Status GetSummary(const std::string &key, Summary &summary) = 0; @@ -38,6 +41,22 @@ public: virtual bool Init() = 0; virtual void Close() = 0; virtual Status GetBatchData(const std::string &dataPrefix, std::vector &unifiedDataSet) = 0; + + bool operator<(const Time &time) const + { + std::shared_lock lock(timeMutex_); + return time_ < time; + } + + void UpdateTime() + { + std::unique_lock lock(timeMutex_); + time_ = std::chrono::steady_clock::now() + std::chrono::minutes(INTERVAL); + } +private: + static constexpr int64_t INTERVAL = 1; // 1 min + mutable Time time_; + mutable std::shared_mutex timeMutex_; }; } // namespace UDMF } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache1.cpp b/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache.cpp similarity index 55% rename from datamgr_service/services/distributeddataservice/service/udmf/store/store_cache1.cpp rename to datamgr_service/services/distributeddataservice/service/udmf/store/store_cache.cpp index ce5a3da9..ba0c258c 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache1.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache.cpp @@ -12,9 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "StoreCache1" +#define LOG_TAG "StoreCache" -#include "store_cache1.h" +#include "store_cache.h" +#include #include "log_print.h" #include "runtime_store.h" @@ -22,7 +23,9 @@ namespace OHOS { namespace UDMF { -std::shared_ptr StoreCache1::GetStore(std::string intention) +std::shared_ptr StoreCache::executorPool_ = std::make_shared(2, 1); + +std::shared_ptr StoreCache::GetStore(std::string intention) { std::shared_ptr store; stores_.Compute(intention, [&store](const auto &intention, std::shared_ptr &storePtr) -> bool { @@ -43,7 +46,31 @@ std::shared_ptr StoreCache1::GetStore(std::string intention) } return false; }); + + std::unique_lock lock(taskMutex_); + if (taskId_ == ExecutorPool::INVALID_TASK_ID) { + taskId_ = executorPool_->Schedule(std::chrono::minutes(INTERVAL), std::bind(&StoreCache::GarbageCollect, this)); + } return store; } + +void StoreCache::GarbageCollect() +{ + auto current = std::chrono::steady_clock::now(); + stores_.EraseIf([¤t](auto &key, std::shared_ptr &storePtr) { + if (*storePtr < current) { + ZLOGD("GarbageCollect, stores:%{public}s time limit, will be close.", key.c_str()); + return true; + } + return false; + }); + std::unique_lock lock(taskMutex_); + if (!stores_.Empty()) { + ZLOGE("GarbageCollect, stores size:%{public}zu", stores_.Size()); + taskId_ = executorPool_->Schedule(std::chrono::minutes(INTERVAL), std::bind(&StoreCache::GarbageCollect, this)); + } else { + taskId_ = ExecutorPool::INVALID_TASK_ID; + } +} } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache1.h b/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache.h similarity index 77% rename from datamgr_service/services/distributeddataservice/service/udmf/store/store_cache1.h rename to datamgr_service/services/distributeddataservice/service/udmf/store/store_cache.h index 4d90dac3..a66e4c65 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache1.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache.h @@ -17,19 +17,28 @@ #define UDMF_STORE_CACHE_H #include +#include #include "concurrent_map.h" +#include "executor_pool.h" #include "store.h" #include "unified_meta.h" namespace OHOS { namespace UDMF { -class StoreCache1 { +class StoreCache { public: std::shared_ptr GetStore(std::string intention); private: + void GarbageCollect(); + ConcurrentMap> stores_; + std::mutex taskMutex_; + ExecutorPool::TaskId taskId_ = ExecutorPool::INVALID_TASK_ID; + + static constexpr int64_t INTERVAL = 1; // 1 min + static std::shared_ptr executorPool_; }; } // namespace UDMF } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.cpp index febb3a3d..ca92a0fb 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.cpp @@ -27,23 +27,8 @@ namespace OHOS { namespace UDMF { -UdmfServiceStub::UdmfServiceStub() -{ - memberFuncMap_[static_cast(SET_DATA)] = &UdmfServiceStub::OnSetData; - memberFuncMap_[static_cast(GET_DATA)] = &UdmfServiceStub::OnGetData; - memberFuncMap_[static_cast(GET_BATCH_DATA)] = &UdmfServiceStub::OnGetBatchData; - memberFuncMap_[static_cast(UPDATE_DATA)] = &UdmfServiceStub::OnUpdateData; - memberFuncMap_[static_cast(DELETE_DATA)] = &UdmfServiceStub::OnDeleteData; - memberFuncMap_[static_cast(GET_SUMMARY)] = &UdmfServiceStub::OnGetSummary; - memberFuncMap_[static_cast(ADD_PRIVILEGE)] = &UdmfServiceStub::OnAddPrivilege; - memberFuncMap_[static_cast(SYNC)] = &UdmfServiceStub::OnSync; -} - -UdmfServiceStub::~UdmfServiceStub() -{ - memberFuncMap_.clear(); -} - +constexpr UdmfServiceStub::Handler + UdmfServiceStub::HANDLERS[static_cast(UdmfServiceInterfaceCode::CODE_BUTT)]; int UdmfServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply) { ZLOGI("start##code = %{public}u", code); @@ -53,18 +38,11 @@ int UdmfServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, Message ZLOGE("end##descriptor checked fail"); return -1; } - if (CODE_HEAD > code || code >= CODE_BUTT) { + if (static_cast(UdmfServiceInterfaceCode::CODE_HEAD) > code || + code >= static_cast(UdmfServiceInterfaceCode::CODE_BUTT)) { return -1; } - auto itFunc = memberFuncMap_.find(code); - if (itFunc != memberFuncMap_.end()) { - auto memberFunc = itFunc->second; - if (memberFunc != nullptr) { - return (this->*memberFunc)(data, reply); - } - } - ZLOGI("end##ret = -1"); - return -1; + return (this->*HANDLERS[code])(data, reply); } int32_t UdmfServiceStub::OnSetData(MessageParcel &data, MessageParcel &reply) diff --git a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.h b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.h index 9684d2ec..d3a73999 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.h @@ -22,6 +22,7 @@ #include "feature/feature_system.h" #include "message_parcel.h" +#include "distributeddata_udmf_ipc_interface_code.h" #include "error_code.h" #include "udmf_service.h" @@ -32,8 +33,6 @@ namespace UDMF { */ class UdmfServiceStub : public UdmfService, public DistributedData::FeatureSystem::Feature { public: - UdmfServiceStub(); - virtual ~UdmfServiceStub() override; int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply) override; private: @@ -52,8 +51,17 @@ private: const std::string WRITE_PERMISSION = "ohos.permission.WRITE_UDMF_DATA"; const std::string SYNC_PERMISSION = "ohos.permission.SYNC_UDMF_DATA"; - using UdmfServiceFunc = int32_t (UdmfServiceStub::*)(MessageParcel &data, MessageParcel &reply); - std::map memberFuncMap_; + using Handler = int32_t (UdmfServiceStub::*)(MessageParcel &data, MessageParcel &reply); + static constexpr Handler HANDLERS[static_cast(UdmfServiceInterfaceCode::CODE_BUTT)] = { + &UdmfServiceStub::OnSetData, + &UdmfServiceStub::OnGetData, + &UdmfServiceStub::OnGetBatchData, + &UdmfServiceStub::OnUpdateData, + &UdmfServiceStub::OnDeleteData, + &UdmfServiceStub::OnGetSummary, + &UdmfServiceStub::OnAddPrivilege, + &UdmfServiceStub::OnSync + }; }; } // namespace UDMF } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/test/fuzztest/schemaquery_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/test/fuzztest/schemaquery_fuzzer/BUILD.gn index d2236940..2cc4e277 100644 --- a/datamgr_service/services/distributeddataservice/test/fuzztest/schemaquery_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/test/fuzztest/schemaquery_fuzzer/BUILD.gn @@ -69,7 +69,7 @@ ohos_fuzztest("SchemaQueryFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] } diff --git a/datamgr_service/test/fuzztest/autolaunch_fuzzer/BUILD.gn b/datamgr_service/test/fuzztest/autolaunch_fuzzer/BUILD.gn index fb3e4402..92344ab4 100644 --- a/datamgr_service/test/fuzztest/autolaunch_fuzzer/BUILD.gn +++ b/datamgr_service/test/fuzztest/autolaunch_fuzzer/BUILD.gn @@ -89,7 +89,7 @@ ohos_fuzztest("AutoLaunchFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/datamgr_service/test/fuzztest/kvstoredisksize_fuzzer/BUILD.gn b/datamgr_service/test/fuzztest/kvstoredisksize_fuzzer/BUILD.gn index 9ee8840f..d6de3de8 100644 --- a/datamgr_service/test/fuzztest/kvstoredisksize_fuzzer/BUILD.gn +++ b/datamgr_service/test/fuzztest/kvstoredisksize_fuzzer/BUILD.gn @@ -90,7 +90,7 @@ ohos_fuzztest("KvStoreDiskSizeFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/bundle.json b/kv_store/bundle.json index df1ee903..63a0761f 100644 --- a/kv_store/bundle.json +++ b/kv_store/bundle.json @@ -50,7 +50,6 @@ "third_party": [ "jsoncpp", "libuv", - "libz", "openssl", "sqlite", "zlib" @@ -60,23 +59,16 @@ "components": [ "ability_base", "ability_runtime", - "access_token", "bundle_framework", - "common", "common_event_service", "c_utils", - "dataclassification", - "device_auth", "device_manager", - "dsoftbus", - "hisysevent_native", - "hitrace_native", - "hiviewdfx_hilog_native", + "hilog", + "hisysevent", + "hitrace", "huks", - "init", "ipc", "napi", - "os_account", "safwk", "samgr" ] diff --git a/kv_store/frameworks/common/test/executor_pool_test.cpp b/kv_store/frameworks/common/test/executor_pool_test.cpp index 77dc4841..66eccd34 100644 --- a/kv_store/frameworks/common/test/executor_pool_test.cpp +++ b/kv_store/frameworks/common/test/executor_pool_test.cpp @@ -89,7 +89,7 @@ HWTEST_F(ExecutorPoolTest, Schedule, TestSize.Level0) expiredTime); ASSERT_NE(taskId, ExecutorPool::INVALID_TASK_ID); std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_INTERVAL * 10)); - ASSERT_EQ(testData, 10); + ASSERT_EQ(testData->data, 10); executorPool_->Remove(taskId); } @@ -114,6 +114,7 @@ HWTEST_F(ExecutorPoolTest, MultiSchedule, TestSize.Level0) } std::this_thread::sleep_for(std::chrono::milliseconds(LONG_INTERVAL * 10)); ASSERT_EQ(data->data, 100); + auto it = ids.begin(); while (it != ids.end()) { executorPool_->Remove(*it); it++; diff --git a/kv_store/frameworks/common/test/traits_test.cpp b/kv_store/frameworks/common/test/traits_test.cpp index 939fcd20..c0d9844f 100644 --- a/kv_store/frameworks/common/test/traits_test.cpp +++ b/kv_store/frameworks/common/test/traits_test.cpp @@ -29,8 +29,8 @@ public: class Convertible { public: // Convertible is auto convert type, do not add explicit to stop the type convert. - Convertible(const From &){}; - Convertible(){} + Convertible(const From &) {}; + Convertible() {} Convertible(Convertible &&) noexcept {}; Convertible &operator=(Convertible &&) noexcept { diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/distributeddata_ipc_interface_code.h b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/distributeddata_ipc_interface_code.h new file mode 100644 index 00000000..ea279de2 --- /dev/null +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/distributeddata_ipc_interface_code.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DISTRIBUTEDDATA_IPC_INTERFACE_CODE_H +#define DISTRIBUTEDDATA_IPC_INTERFACE_CODE_H + +#include + +/* SAID:1301 */ +namespace OHOS::DistributedKv { +enum class KvStoreDataServiceInterfaceCode : uint32_t { + GET_FEATURE_INTERFACE = 0, + REGISTERCLIENTDEATHOBSERVER, + SERVICE_CMD_LAST +}; +} // namespace OHOS::DistributedKv +#endif // DISTRIBUTEDDATA_IPC_INTERFACE_CODE_H \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/ikvstore_data_service.h b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/ikvstore_data_service.h index b67e248d..408fbc75 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/ikvstore_data_service.h +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/ikvstore_data_service.h @@ -16,6 +16,7 @@ #ifndef I_KV_STORE_DATA_SERVICE_H #define I_KV_STORE_DATA_SERVICE_H +#include "distributeddata_ipc_interface_code.h" #include "iremote_broker.h" #include "ikvstore_client_death_observer.h" #include "ikvstore_observer.h" @@ -27,21 +28,6 @@ namespace OHOS::DistributedKv { class IKvStoreDataService : public IRemoteBroker { public: - enum { - GET_FEATURE_INTERFACE, - REGISTERCLIENTDEATHOBSERVER, - CLOSEKVSTORE, - CLOSEALLKVSTORE, - DELETEKVSTORE, - DELETEALLKVSTORE, - GETSINGLEKVSTORE, - GETLOCALDEVICE, - GETREMOTEDEVICES, - STARTWATCHDEVICECHANGE, - STOPWATCHDEVICECHANGE, - SERVICE_CMD_LAST, - }; - DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.DistributedKv.IKvStoreDataService"); virtual sptr GetFeatureInterface(const std::string &name) = 0; @@ -55,26 +41,17 @@ protected: class KvStoreDataServiceStub : public IRemoteStub { public: int API_EXPORT OnRemoteRequest(uint32_t code, MessageParcel &data, - MessageParcel &reply, MessageOption &option) override; + MessageParcel &reply, MessageOption &option) override; private: - int32_t NoSupport(MessageParcel &data, MessageParcel &reply); int32_t GetFeatureInterfaceOnRemote(MessageParcel &data, MessageParcel &reply); int32_t RegisterClientDeathObserverOnRemote(MessageParcel &data, MessageParcel &reply); using RequestHandler = int32_t(KvStoreDataServiceStub::*)(MessageParcel&, MessageParcel&); - static constexpr RequestHandler HANDLERS[SERVICE_CMD_LAST] = { - [GET_FEATURE_INTERFACE] = &KvStoreDataServiceStub::GetFeatureInterfaceOnRemote, - [REGISTERCLIENTDEATHOBSERVER] = &KvStoreDataServiceStub::RegisterClientDeathObserverOnRemote, - [CLOSEKVSTORE] = &KvStoreDataServiceStub::NoSupport, - [CLOSEALLKVSTORE] = &KvStoreDataServiceStub::NoSupport, - [DELETEKVSTORE] = &KvStoreDataServiceStub::NoSupport, - [DELETEALLKVSTORE] = &KvStoreDataServiceStub::NoSupport, - [GETSINGLEKVSTORE] = &KvStoreDataServiceStub::NoSupport, - [GETLOCALDEVICE] = &KvStoreDataServiceStub::NoSupport, - [GETREMOTEDEVICES] = &KvStoreDataServiceStub::NoSupport, - [STARTWATCHDEVICECHANGE] = &KvStoreDataServiceStub::NoSupport, - [STOPWATCHDEVICECHANGE] = &KvStoreDataServiceStub::NoSupport, + static constexpr RequestHandler + HANDLERS[static_cast(KvStoreDataServiceInterfaceCode::SERVICE_CMD_LAST)] = { + &KvStoreDataServiceStub::GetFeatureInterfaceOnRemote, + &KvStoreDataServiceStub::RegisterClientDeathObserverOnRemote, }; }; @@ -91,4 +68,4 @@ private: }; } // namespace OHOS::DistributedKv -#endif // I_KV_STORE_DATA_SERVICE_H +#endif // I_KV_STORE_DATA_SERVICE_H \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/ikvstore_data_service.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/ikvstore_data_service.cpp index 5e9f0ec5..72130884 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/ikvstore_data_service.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/ikvstore_data_service.cpp @@ -24,7 +24,8 @@ namespace OHOS { namespace DistributedKv { -constexpr KvStoreDataServiceStub::RequestHandler KvStoreDataServiceStub::HANDLERS[SERVICE_CMD_LAST]; +constexpr KvStoreDataServiceStub::RequestHandler + KvStoreDataServiceStub::HANDLERS[static_cast(KvStoreDataServiceInterfaceCode::SERVICE_CMD_LAST)]; KvStoreDataServiceProxy::KvStoreDataServiceProxy(const sptr &impl) : IRemoteProxy(impl) { @@ -47,7 +48,8 @@ sptr KvStoreDataServiceProxy::GetFeatureInterface(const std::stri MessageParcel reply; MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(GET_FEATURE_INTERFACE, data, reply, mo); + int32_t error = Remote()->SendRequest( + static_cast(KvStoreDataServiceInterfaceCode::GET_FEATURE_INTERFACE), data, reply, mo); if (error != 0) { ZLOGE("SendRequest returned %{public}d", error); return nullptr; @@ -83,7 +85,8 @@ Status KvStoreDataServiceProxy::RegisterClientDeathObserver(const AppId &appId, } MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(REGISTERCLIENTDEATHOBSERVER, data, reply, mo); + int32_t error = Remote()->SendRequest( + static_cast(KvStoreDataServiceInterfaceCode::REGISTERCLIENTDEATHOBSERVER), data, reply, mo); if (error != 0) { ZLOGW("failed during IPC. errCode %d", error); return Status::IPC_ERROR; @@ -91,13 +94,6 @@ Status KvStoreDataServiceProxy::RegisterClientDeathObserver(const AppId &appId, return static_cast(reply.ReadInt32()); } -int32_t KvStoreDataServiceStub::NoSupport(MessageParcel &data, MessageParcel &reply) -{ - (void)data; - (void)reply; - return NOT_SUPPORT; -} - int32_t KvStoreDataServiceStub::RegisterClientDeathObserverOnRemote(MessageParcel &data, MessageParcel &reply) { AppId appId = { data.ReadString() }; @@ -135,7 +131,7 @@ int32_t KvStoreDataServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &da ZLOGE("local descriptor is not equal to remote"); return -1; } - if (code >= 0 && code < SERVICE_CMD_LAST) { + if (code >= 0 && code < static_cast(KvStoreDataServiceInterfaceCode::SERVICE_CMD_LAST)) { return (this->*HANDLERS[code])(data, reply); } else { MessageOption mo { MessageOption::TF_SYNC }; diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/BUILD.gn b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/BUILD.gn index 14bb5e17..feca27a0 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/BUILD.gn +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/BUILD.gn @@ -88,10 +88,10 @@ ohos_source_set("distributeddatafwk_src_file") { ] external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", "huks:libhukssdk", "ipc:ipc_single", "samgr:samgr_proxy", @@ -109,7 +109,7 @@ ohos_unittest("DistributedKvDataManagerTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "samgr:samgr_proxy", ] @@ -129,7 +129,7 @@ ohos_unittest("DistributedKvDataManagerEncryptTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "samgr:samgr_proxy", ] @@ -150,7 +150,7 @@ ohos_unittest("LocalSubscribeStoreTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "samgr:samgr_proxy", ] @@ -171,7 +171,7 @@ ohos_unittest("LocalSubscribeDeviceStoreTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "samgr:samgr_proxy", ] @@ -192,7 +192,7 @@ ohos_unittest("SingleKvStoreClientQueryTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "samgr:samgr_proxy", ] @@ -213,7 +213,7 @@ ohos_unittest("SingleKvStoreClientTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "samgr:samgr_proxy", ] @@ -234,7 +234,7 @@ ohos_unittest("DeviceKvStoreTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "samgr:samgr_proxy", ] diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/distributeddata_kvdb_ipc_interface_code.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/distributeddata_kvdb_ipc_interface_code.h new file mode 100644 index 00000000..0b071cf2 --- /dev/null +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/distributeddata_kvdb_ipc_interface_code.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DISTRIBUTEDDATA_KVDB_IPC_INTERFACE_CODE_H +#define DISTRIBUTEDDATA_KVDB_IPC_INTERFACE_CODE_H + +#include + +/* SAID:1301 FeatureSystem:kvdb_service */ +namespace OHOS::DistributedKv { +enum class KVDBServiceInterfaceCode : uint32_t { + TRANS_HEAD = 0, + TRANS_GET_STORE_IDS = TRANS_HEAD, + TRANS_BEFORE_CREATE, + TRANS_AFTER_CREATE, + TRANS_DELETE, + TRANS_SYNC, + TRANS_REGISTER_CALLBACK, + TRANS_UNREGISTER_CALLBACK, + TRANS_SET_SYNC_PARAM, + TRANS_GET_SYNC_PARAM, + TRANS_ENABLE_CAP, + TRANS_DISABLE_CAP, + TRANS_SET_CAP, + TRANS_ADD_SUB, + TRANS_RMV_SUB, + TRANS_SUB, + TRANS_UNSUB, + TRANS_GET_PASSWORD, + TRANS_BUTT +}; +} // namespace OHOS::DistributedKv +#endif // DISTRIBUTEDDATA_KVDB_IPC_INTERFACE_CODE_H \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h index c343d06a..c536a468 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h @@ -63,29 +63,6 @@ public: virtual Status Unsubscribe(const AppId &appId, const StoreId &storeId, sptr observer) = 0; virtual Status GetBackupPassword( const AppId &appId, const StoreId &storeId, std::vector &password) = 0; - -protected: - enum TransId : int32_t { - TRANS_HEAD, - TRANS_GET_STORE_IDS = TRANS_HEAD, - TRANS_BEFORE_CREATE, - TRANS_AFTER_CREATE, - TRANS_DELETE, - TRANS_SYNC, - TRANS_REGISTER_CALLBACK, - TRANS_UNREGISTER_CALLBACK, - TRANS_SET_SYNC_PARAM, - TRANS_GET_SYNC_PARAM, - TRANS_ENABLE_CAP, - TRANS_DISABLE_CAP, - TRANS_SET_CAP, - TRANS_ADD_SUB, - TRANS_RMV_SUB, - TRANS_SUB, - TRANS_UNSUB, - TRANS_GET_PASSWORD, - TRANS_BUTT, - }; }; } // namespace OHOS::DistributedKv #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_KVDB_SERVICE_H diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp index 765dbac3..37e468ea 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp @@ -15,6 +15,7 @@ #define LOG_TAG "KVDBServiceClient" #include "kvdb_service_client.h" #include +#include "distributeddata_kvdb_ipc_interface_code.h" #include "itypes_util.h" #include "kvstore_observer_client.h" #include "kvstore_service_death_notifier.h" @@ -105,7 +106,8 @@ KVDBServiceClient::KVDBServiceClient(const sptr &handle) : IRemot Status KVDBServiceClient::GetStoreIds(const AppId &appId, std::vector &storeIds) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_GET_STORE_IDS, reply, appId, StoreId(), storeIds); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_GET_STORE_IDS), + reply, appId, StoreId(), storeIds); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s", status, appId.appId.c_str()); } @@ -116,7 +118,8 @@ Status KVDBServiceClient::GetStoreIds(const AppId &appId, std::vector & Status KVDBServiceClient::BeforeCreate(const AppId &appId, const StoreId &storeId, const Options &options) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_BEFORE_CREATE, reply, appId, storeId, options); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_BEFORE_CREATE), + reply, appId, storeId, options); if (status != SUCCESS) { ZLOGE("status:0x%{public}x appId:%{public}s, storeId:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); @@ -128,7 +131,8 @@ Status KVDBServiceClient::AfterCreate( const AppId &appId, const StoreId &storeId, const Options &options, const std::vector &password) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_AFTER_CREATE, reply, appId, storeId, options, password); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_AFTER_CREATE), + reply, appId, storeId, options, password); if (status != SUCCESS) { ZLOGE("status:0x%{public}x appId:%{public}s, storeId:%{public}s, encrypt:%{public}d", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str(), options.encrypt); @@ -139,7 +143,8 @@ Status KVDBServiceClient::AfterCreate( Status KVDBServiceClient::Delete(const AppId &appId, const StoreId &storeId) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_DELETE, reply, appId, storeId); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_DELETE), + reply, appId, storeId); if (status != SUCCESS) { ZLOGE("status:0x%{public}x appId:%{public}s, storeId:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); @@ -150,8 +155,8 @@ Status KVDBServiceClient::Delete(const AppId &appId, const StoreId &storeId) Status KVDBServiceClient::Sync(const AppId &appId, const StoreId &storeId, const SyncInfo &syncInfo) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_SYNC, reply, appId, storeId, syncInfo.seqId, syncInfo.mode, syncInfo.devices, - syncInfo.delay, syncInfo.query); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_SYNC), reply, appId, storeId, + syncInfo.seqId, syncInfo.mode, syncInfo.devices, syncInfo.delay, syncInfo.query); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, storeId:%{public}s, sequenceId:%{public}" PRIu64, status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str(), syncInfo.seqId); @@ -162,7 +167,8 @@ Status KVDBServiceClient::Sync(const AppId &appId, const StoreId &storeId, const Status KVDBServiceClient::RegisterSyncCallback(const AppId &appId, sptr callback) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_REGISTER_CALLBACK, reply, appId, StoreId(), callback->AsObject().GetRefPtr()); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_REGISTER_CALLBACK), reply, + appId, StoreId(), callback->AsObject().GetRefPtr()); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, callback:0x%{public}x", status, appId.appId.c_str(), StoreUtil::Anonymous(callback.GetRefPtr())); @@ -173,7 +179,8 @@ Status KVDBServiceClient::RegisterSyncCallback(const AppId &appId, sptr(KVDBServiceInterfaceCode::TRANS_UNREGISTER_CALLBACK), + reply, appId, StoreId()); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s", status, appId.appId.c_str()); } @@ -183,7 +190,8 @@ Status KVDBServiceClient::UnregisterSyncCallback(const AppId &appId) Status KVDBServiceClient::SetSyncParam(const AppId &appId, const StoreId &storeId, const KvSyncParam &syncParam) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_SET_SYNC_PARAM, reply, appId, storeId, syncParam.allowedDelayMs); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_SET_SYNC_PARAM), reply, + appId, storeId, syncParam.allowedDelayMs); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, storeId:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); @@ -194,7 +202,8 @@ Status KVDBServiceClient::SetSyncParam(const AppId &appId, const StoreId &storeI Status KVDBServiceClient::GetSyncParam(const AppId &appId, const StoreId &storeId, KvSyncParam &syncParam) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_GET_SYNC_PARAM, reply, appId, storeId); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_GET_SYNC_PARAM), + reply, appId, storeId); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, storeId:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); @@ -207,7 +216,8 @@ Status KVDBServiceClient::GetSyncParam(const AppId &appId, const StoreId &storeI Status KVDBServiceClient::EnableCapability(const AppId &appId, const StoreId &storeId) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_ENABLE_CAP, reply, appId, storeId); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_ENABLE_CAP), + reply, appId, storeId); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, storeId:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); @@ -218,7 +228,8 @@ Status KVDBServiceClient::EnableCapability(const AppId &appId, const StoreId &st Status KVDBServiceClient::DisableCapability(const AppId &appId, const StoreId &storeId) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_DISABLE_CAP, reply, appId, storeId); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_DISABLE_CAP), + reply, appId, storeId); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, storeId:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); @@ -230,7 +241,8 @@ Status KVDBServiceClient::SetCapability(const AppId &appId, const StoreId &store const std::vector &local, const std::vector &remote) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_SET_CAP, reply, appId, storeId, local, remote); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_SET_CAP), + reply, appId, storeId, local, remote); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, storeId:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); @@ -241,7 +253,8 @@ Status KVDBServiceClient::SetCapability(const AppId &appId, const StoreId &store Status KVDBServiceClient::AddSubscribeInfo(const AppId &appId, const StoreId &storeId, const SyncInfo &syncInfo) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_ADD_SUB, reply, appId, storeId, syncInfo.seqId, syncInfo.devices, syncInfo.query); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_ADD_SUB), + reply, appId, storeId, syncInfo.seqId, syncInfo.devices, syncInfo.query); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, storeId:%{public}s, query:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str(), @@ -253,7 +266,8 @@ Status KVDBServiceClient::AddSubscribeInfo(const AppId &appId, const StoreId &st Status KVDBServiceClient::RmvSubscribeInfo(const AppId &appId, const StoreId &storeId, const SyncInfo &syncInfo) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_RMV_SUB, reply, appId, storeId, syncInfo.seqId, syncInfo.devices, syncInfo.query); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_RMV_SUB), + reply, appId, storeId, syncInfo.seqId, syncInfo.devices, syncInfo.query); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, storeId:%{public}s, query:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str(), @@ -265,7 +279,8 @@ Status KVDBServiceClient::RmvSubscribeInfo(const AppId &appId, const StoreId &st Status KVDBServiceClient::Subscribe(const AppId &appId, const StoreId &storeId, sptr observer) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_SUB, reply, appId, storeId, observer->AsObject()); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_SUB), + reply, appId, storeId, observer->AsObject()); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, storeId:%{public}s, observer:0x%{public}x", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str(), @@ -277,7 +292,8 @@ Status KVDBServiceClient::Subscribe(const AppId &appId, const StoreId &storeId, Status KVDBServiceClient::Unsubscribe(const AppId &appId, const StoreId &storeId, sptr observer) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_UNSUB, reply, appId, storeId, observer->AsObject().GetRefPtr()); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_UNSUB), + reply, appId, storeId, observer->AsObject().GetRefPtr()); if (status != SUCCESS) { ZLOGE("status:0x%{public}x, appId:%{public}s, storeId:%{public}s, observer:0x%{public}x", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str(), @@ -290,7 +306,8 @@ Status KVDBServiceClient::GetBackupPassword( const AppId &appId, const StoreId &storeId, std::vector &password) { MessageParcel reply; - int32_t status = IPC_SEND(TRANS_GET_PASSWORD, reply, appId, storeId); + int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_GET_PASSWORD), + reply, appId, storeId); if (status != SUCCESS) { ZLOGE("status:0x%{public}x appId:%{public}s, storeId:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp index fda4ce86..394b27a4 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp @@ -40,6 +40,9 @@ StoreFactory::StoreFactory() convertors_[SINGLE_VERSION] = new Convertor(); convertors_[MULTI_VERSION] = new Convertor(); DistributedDB::RuntimeConfig::SetThreadPool(std::make_shared()); + DistributedDB::RuntimeConfig::SetSyncActivationCheckCallback([](const ActivationCheckParam ¶m) -> bool { + return false; + }); if (DBManager::IsProcessSystemApiAdapterValid()) { return; } diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/BUILD.gn b/kv_store/frameworks/innerkitsimpl/kvdb/test/BUILD.gn index dfe1a375..c5a7c29d 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/test/BUILD.gn +++ b/kv_store/frameworks/innerkitsimpl/kvdb/test/BUILD.gn @@ -91,10 +91,10 @@ ohos_source_set("kvdb_src_file") { ] external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", "huks:libhukssdk", "ipc:ipc_single", "samgr:samgr_proxy", @@ -112,7 +112,7 @@ ohos_unittest("SingleStoreImplTest") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "safwk:system_ability_fwk", "samgr:samgr_proxy", @@ -179,7 +179,7 @@ ohos_unittest("AutoSyncTimerTest") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "safwk:system_ability_fwk", "samgr:samgr_proxy", @@ -202,7 +202,7 @@ ohos_unittest("DevManagerTest") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "safwk:system_ability_fwk", "samgr:samgr_proxy", @@ -225,7 +225,7 @@ ohos_unittest("SingleStoreImplGetTopTest") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "safwk:system_ability_fwk", "samgr:samgr_proxy", @@ -248,7 +248,7 @@ ohos_unittest("StoreFactoryTest") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "safwk:system_ability_fwk", "samgr:samgr_proxy", diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_single_kv_store.cpp b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_single_kv_store.cpp index 444f9947..9cd6bc9c 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_single_kv_store.cpp +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_single_kv_store.cpp @@ -397,7 +397,6 @@ napi_value JsSingleKVStore::StartTransaction(napi_env env, napi_callback_info in { auto ctxt = std::make_shared(); ctxt->GetCbInfo(env, info); - auto execute = [ctxt]() { auto& kvStore = reinterpret_cast(ctxt->native)->kvStore_; Status status = kvStore->StartTransaction(); diff --git a/kv_store/frameworks/libs/distributeddb/BUILD.gn b/kv_store/frameworks/libs/distributeddb/BUILD.gn index 92460ee4..ae33396b 100644 --- a/kv_store/frameworks/libs/distributeddb/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/BUILD.gn @@ -56,6 +56,7 @@ config("distrdb_config") { "USE_DFX_ABILITY", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "MAX_UPLOAD_COUNT=30", ] if (is_debug) { defines += [ "TRACE_SQLITE_EXECUTE" ] @@ -96,9 +97,9 @@ ohos_shared_library("distributeddb") { external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", ] subsystem_name = "distributeddatamgr" diff --git a/kv_store/frameworks/libs/distributeddb/common/include/cloud/cloud_db_constant.h b/kv_store/frameworks/libs/distributeddb/common/include/cloud/cloud_db_constant.h index 902aaf18..af35f7a4 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/cloud/cloud_db_constant.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/cloud/cloud_db_constant.h @@ -30,7 +30,6 @@ public: static constexpr const char *CURSOR_FIELD = "#_cursor"; static constexpr const char *ROW_ID_FIELD_NAME = "rowid"; static constexpr uint32_t MAX_UPLOAD_SIZE = 1024 * 512 * 3; // 1.5M - static constexpr uint32_t MAX_DOWNLOAD_RETRY_TIME = 50; // cloud data timestamp is utc ms precision // used for 100ns to ms when handle cloud data timestamp static constexpr uint32_t TEN_THOUSAND = 10000; diff --git a/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h b/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h index bf4f441c..8a34bde8 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h @@ -129,6 +129,11 @@ constexpr int E_CONSTRAINT = (E_BASE + 107); // sql failed with constraint constexpr int E_CLOUD_ERROR = (E_BASE + 108); // cloud error constexpr int E_QUERY_END = (E_BASE + 110); // Indicates that query function has queried last data from cloud constexpr int E_DB_CLOSED = (E_BASE + 111); // db is closed +constexpr int E_NOT_SET = (E_BASE + 112); // asset loader is not set +constexpr int E_CLOUD_NETWORK_ERROR = (E_BASE + 113); // network error in cloud +constexpr int E_CLOUD_SYNC_UNSET = (E_BASE + 114); // not set sync option in cloud +constexpr int E_CLOUD_FULL_RECORDS = (E_BASE + 115); // cloud's record is full +constexpr int E_CLOUD_LOCK_ERROR = (E_BASE + 116); // cloud failed to get sync lock // Num 150+ is reserved for schema related errno, since it may be added regularly constexpr int E_JSON_PARSE_FAIL = (E_BASE + 150); // Parse json fail in grammatical level constexpr int E_JSON_INSERT_PATH_EXIST = (E_BASE + 151); // Path already exist before insert diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp b/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp index b8c738eb..0fe52b83 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp @@ -401,6 +401,8 @@ void CommunicatorAggregator::SendPacketsAndDisposeTask(const SendTask &inTask, u } if (taskNeedFinalize) { TaskFinalizer(inTask, errCode); + std::lock_guard autoLock(sendRecordMutex_); + sendRecord_.erase(inTask.frameId); } } diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_manager.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_manager.h index a4303151..4e683a77 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_manager.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_manager.h @@ -29,6 +29,10 @@ public: // Only calculate the table name with device hash, no guarantee for the table exists DB_API static std::string GetDistributedTableName(const std::string &device, const std::string &tableName); + DB_API static std::string GetDistributedLogTableName(const std::string &tableName); + // key:colName value:real value + DB_API static std::vector CalcPrimaryKeyHash(const std::map primaryKey); + DB_API RelationalStoreManager(const std::string &appId, const std::string &userId, int32_t instanceId = 0); DB_API ~RelationalStoreManager() = default; diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h index 77d8fdd6..6ab481aa 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h @@ -71,6 +71,11 @@ enum DBStatus { CLOUD_ERROR, // cloud error QUERY_END, // Indicates that query function has queried last data from cloud DB_CLOSED, // db is closed + UNSET_ERROR, // something should be set not be set + CLOUD_NETWORK_ERROR, // network error in cloud + CLOUD_SYNC_UNSET, // not set sync option in cloud + CLOUD_FULL_RECORDS, // cloud's record is full + CLOUD_LOCK_ERROR, // cloud failed to get sync lock }; struct KvStoreConfig { diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp index 35fa55e2..cb217cad 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp @@ -69,6 +69,11 @@ namespace { { -E_CONSTRAINT, CONSTRAINT }, { -E_CLOUD_ERROR, CLOUD_ERROR }, { -E_DB_CLOSED, DB_CLOSED }, + { -E_NOT_SET, UNSET_ERROR }, + { -E_CLOUD_NETWORK_ERROR, CLOUD_NETWORK_ERROR }, + { -E_CLOUD_SYNC_UNSET, CLOUD_SYNC_UNSET }, + { -E_CLOUD_FULL_RECORDS, CLOUD_FULL_RECORDS }, + { -E_CLOUD_LOCK_ERROR, CLOUD_LOCK_ERROR }, }; } diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp index 03805dfc..f7bac8f5 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp @@ -43,7 +43,6 @@ RelationalStoreDelegateImpl::~RelationalStoreDelegateImpl() DBStatus RelationalStoreDelegateImpl::RemoveDeviceDataInner(const std::string &device, ClearMode mode) { -#ifdef MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA if (mode >= BUTT) { LOGE("Invalid mode for Remove device data, %d.", INVALID_ARGS); return INVALID_ARGS; @@ -61,7 +60,6 @@ DBStatus RelationalStoreDelegateImpl::RemoveDeviceDataInner(const std::string &d } return OK; } -#endif // MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA return RemoveDeviceData(device, ""); } diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp index aed8a2a9..7f27c6ba 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp @@ -19,6 +19,7 @@ #include "auto_launch.h" #include "cloud/cloud_db_constant.h" +#include "cloud/cloud_storage_utils.h" #include "relational_store_instance.h" #include "db_common.h" #include "db_dfx_adapter.h" @@ -141,6 +142,50 @@ std::string RelationalStoreManager::GetDistributedTableName(const std::string &d return DBCommon::GetDistributedTableName(device, tableName); } +DB_API std::string RelationalStoreManager::GetDistributedLogTableName(const std::string &tableName) +{ + return DBCommon::GetLogTableName(tableName); +} + +DB_API std::vector RelationalStoreManager::CalcPrimaryKeyHash(const std::map primaryKey) +{ + std::vector result; + if (primaryKey.empty()) { + LOGW("primaryKey is empty"); + return result; + } + int errCode = E_OK; + if (primaryKey.size() == 1) { + auto iter = primaryKey.begin(); + Field field = { iter->first, static_cast(iter->second.index()), true, false}; + errCode = CloudStorageUtils::CalculateHashKeyForOneField(field, primaryKey, false, result); + if (errCode != E_OK) { + // never happen + LOGE("calc hash fail when there is one primary key errCode = %d", errCode); + return result; + } + } else { + std::vector tempRes; + for (const auto &item: primaryKey) { + std::vector temp; + Field field = { item.first, static_cast(item.second.index()), true, false}; + errCode = CloudStorageUtils::CalculateHashKeyForOneField(field, primaryKey, false, temp); + if (errCode != E_OK) { + // never happen + LOGE("calc hash fail when there is more than one primary key errCode = %d", errCode); + return result; + } + tempRes.insert(tempRes.end(), temp.begin(), temp.end()); + } + errCode = DBCommon::CalcValueHash(tempRes, result); + if (errCode != E_OK) { + LOGE("calc hash fail when calc the composite primary key errCode = %d", errCode); + return result; + } + } + return result; +} + void RelationalStoreManager::SetAutoLaunchRequestCallback(const AutoLaunchRequestCallback &callback) { RuntimeContext::GetInstance()->SetAutoLaunchRequestCallback(callback, DBTypeInner::DB_RELATION); diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h index 387e8c32..b6ce9ac8 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h @@ -162,7 +162,7 @@ public: int FillCloudAssetForDownload(const std::string &tableName, VBucket &asset, bool isFullReplace) override; - int FillCloudAssetForUpload(const CloudSyncData &data) override; + int FillCloudGidAndAsset(const OpType &opType, const CloudSyncData &data) override; void SetSyncAbleEngine(std::shared_ptr syncAbleEngine); diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h b/kv_store/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h index 1fc38c1b..539a139b 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h @@ -54,11 +54,16 @@ public: static void FillAssetsForDownload(Assets &assets); static int FillAssetForUpload(Asset &asset); static void FillAssetsForUpload(Assets &assets); - static void FillAssetFromVBucketBeforeDownload(VBucket &vBucket); - static void FillAssetFromVBucketDownloadFinish(VBucket &vBucket); - static void FillAssetFromVBucketAfterUpload(VBucket &vBucket); + static void PrepareToFillAssetFromVBucket(VBucket &vBucket); + static void FillAssetFromVBucketFinish(VBucket &vBucket, std::function fillAsset, + std::function fillAssets); static bool IsAsset(const Type &type); static bool IsAssets(const Type &type); + static bool IsAssetsContainDuplicateAsset(Assets &assets); + static void EraseNoChangeAsset(std::map &assetsMap); + static void MergeDownloadAsset(std::map &downloadAssets, + std::map &mergeAssets); + static std::map GenAssetsIndexMap(Assets &assets); template static int GetValueFromOneField(Type &cloudValue, T &outVal) @@ -93,6 +98,9 @@ public: outVal = *value; return E_OK; } + + static int CalculateHashKeyForOneField(const Field &field, const VBucket &vBucket, bool allowEmpty, + std::vector &hashValue); }; } #endif // CLOUD_STORAGE_UTILS_H diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h b/kv_store/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h index e7cc3b43..da18258b 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h @@ -31,6 +31,8 @@ enum class OpType : uint8_t { // used in Cloud Force Push strategy, when SET_CLOUD_FORCE_PUSH_FLAG_ONE, upload process won't process this record SET_CLOUD_FORCE_PUSH_FLAG_ONE, SET_CLOUD_FORCE_PUSH_FLAG_ZERO, + UPDATE_TIMESTAMP, + CLEAR_GID, NOT_HANDLE }; @@ -87,7 +89,7 @@ public: virtual int FillCloudAssetForDownload(const std::string &tableName, VBucket &asset, bool isFullReplace) = 0; - virtual int FillCloudAssetForUpload(const CloudSyncData &data) = 0; + virtual int FillCloudGidAndAsset(const OpType &opType, const CloudSyncData &data) = 0; }; } diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/isync_interface.h b/kv_store/frameworks/libs/distributeddb/storage/include/isync_interface.h index 893305b1..9bf95083 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/isync_interface.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/isync_interface.h @@ -69,6 +69,8 @@ public: virtual const DBProperties &GetDbProperties() const = 0; virtual int GetSecurityOption(SecurityOption &option) const = 0; + + virtual int IsSupportSubscribe() const = 0; }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/storage_proxy.h b/kv_store/frameworks/libs/distributeddb/storage/include/storage_proxy.h index b87bf3ee..f82fb91b 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/storage_proxy.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/storage_proxy.h @@ -43,7 +43,7 @@ public: int GetCloudWaterMark(const std::string &tableName, CloudWaterMark &cloudMark); - int PutCloudWaterMark(const std::string &tableName, CloudWaterMark &cloudMark); + int SetCloudWaterMark(const std::string &tableName, CloudWaterMark &cloudMark); int StartTransaction(TransactType type = TransactType::DEFERRED); @@ -81,7 +81,7 @@ public: int FillCloudAssetForDownload(const std::string &tableName, VBucket &asset, bool isFullReplace); - int FillCloudAssetForUpload(const CloudSyncData &data); + int FillCloudGidAndAsset(const OpType &opType, const CloudSyncData &data); protected: void Init(); diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/sync_generic_interface.h b/kv_store/frameworks/libs/distributeddb/storage/include/sync_generic_interface.h index 1e3e2d52..da94c92f 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/sync_generic_interface.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/sync_generic_interface.h @@ -144,6 +144,11 @@ public: { return {}; } + + int IsSupportSubscribe() const override + { + return -E_NOT_SUPPORT; + } }; } #endif // SYNC_GENERIC_INTERFACE_H diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_meta_data.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_meta_data.cpp index d8c6c720..e7db3f79 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_meta_data.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_meta_data.cpp @@ -55,6 +55,7 @@ int CloudMetaData::GetCloudWaterMark(TableName tableName, CloudWaterMark &cloudM } } cloudMark = cloudMetaVals_[tableName].cloudMark; + LOGD("[Meta] get cloud water mark=%s", cloudMark.c_str()); return E_OK; } @@ -97,6 +98,7 @@ int CloudMetaData::SetCloudWaterMark(TableName tableName, CloudWaterMark &cloudM } else { iter->second.cloudMark = cloudMark; } + LOGD("[Meta] set cloud water mark=%s", cloudMark.c_str()); return E_OK; } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp index bf84c6fa..49863758 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include "cloud/cloud_db_types.h" #include "db_common.h" @@ -164,7 +165,7 @@ int CloudStorageUtils::BindAsset(int index, const VBucket &vBucket, const Field LOGE("can not get asset from vBucket when bind, %d", errCode); return errCode; } - RuntimeContext::GetInstance()->AssetToBlob(asset, val); + errCode = RuntimeContext::GetInstance()->AssetToBlob(asset, val); } else if (field.type == TYPE_INDEX) { Assets assets; errCode = GetValueFromOneField(type, assets); @@ -172,22 +173,21 @@ int CloudStorageUtils::BindAsset(int index, const VBucket &vBucket, const Field LOGE("can not get assets from vBucket when bind, %d", errCode); return errCode; } - if (assets.empty()) { - errCode = -E_NOT_FOUND; - } else { - RuntimeContext::GetInstance()->AssetsToBlob(assets, val); + if (!assets.empty()) { + errCode = RuntimeContext::GetInstance()->AssetsToBlob(assets, val); } } else { LOGE("field type is not asset or assets, %d", -E_CLOUD_ERROR); return -E_CLOUD_ERROR; } - if (errCode == E_OK) { - errCode = SQLiteUtils::BindBlobToStatement(upsertStmt, index, val); - } else { - errCode = SQLiteUtils::MapSQLiteErrno(sqlite3_bind_null(upsertStmt, index)); - } if (errCode != E_OK) { - LOGE("Bind blob to asset failed, %d", errCode); + LOGE("assets or asset to blob fail, %d", -E_CLOUD_ERROR); + return -E_CLOUD_ERROR; + } + if (val.empty()) { + errCode = SQLiteUtils::MapSQLiteErrno(sqlite3_bind_null(upsertStmt, index)); + } else { + errCode = SQLiteUtils::BindBlobToStatement(upsertStmt, index, val); } return errCode; } @@ -448,7 +448,7 @@ void CloudStorageUtils::FillAssetsForUpload(Assets &assets) } } -void CloudStorageUtils::FillAssetFromVBucketBeforeDownload(VBucket &vBucket) +void CloudStorageUtils::PrepareToFillAssetFromVBucket(VBucket &vBucket) { for (auto &item: vBucket) { if (IsAsset(item.second)) { @@ -467,40 +467,14 @@ void CloudStorageUtils::FillAssetFromVBucketBeforeDownload(VBucket &vBucket) } } -void CloudStorageUtils::FillAssetFromVBucketDownloadFinish(VBucket &vBucket) -{ - for (auto &item: vBucket) { - if (IsAsset(item.second)) { - Asset asset; - GetValueFromType(item.second, asset); - int errCode = FillAssetForDownload(asset); - if (errCode != E_OK) { - vBucket[item.first] = Nil(); - } else { - vBucket[item.first] = asset; - } - continue; - } - if (IsAssets(item.second)) { - Assets assets; - GetValueFromType(item.second, assets); - FillAssetsForDownload(assets); - if (assets.empty()) { - vBucket[item.first] = Nil(); - } else { - vBucket[item.first] = assets; - } - } - } -} - -void CloudStorageUtils::FillAssetFromVBucketAfterUpload(VBucket &vBucket) +void CloudStorageUtils::FillAssetFromVBucketFinish(VBucket &vBucket, std::function fillAsset, + std::function fillAssets) { for (auto &item: vBucket) { if (IsAsset(item.second)) { Asset asset; GetValueFromType(item.second, asset); - int errCode = FillAssetForUpload(asset); + int errCode = fillAsset(asset); if (errCode != E_OK) { vBucket[item.first] = Nil(); } else { @@ -511,7 +485,7 @@ void CloudStorageUtils::FillAssetFromVBucketAfterUpload(VBucket &vBucket) if (IsAssets(item.second)) { Assets assets; GetValueFromType(item.second, assets); - FillAssetsForUpload(assets); + fillAssets(assets); if (assets.empty()) { vBucket[item.first] = Nil(); } else { @@ -536,4 +510,87 @@ bool CloudStorageUtils::IsAssets(const Type &type) } return false; } + +int CloudStorageUtils::CalculateHashKeyForOneField(const Field &field, const VBucket &vBucket, bool allowEmpty, + std::vector &hashValue) +{ + if (allowEmpty && vBucket.find(field.colName) == vBucket.end()) { + return E_OK; // if vBucket from cloud doesn't contain primary key and allowEmpty, no need to calculate hash + } + static std::map &)>> toVecFunc = { + {TYPE_INDEX, &CloudStorageUtils::Int64ToVector}, + {TYPE_INDEX, &CloudStorageUtils::BoolToVector}, + {TYPE_INDEX, &CloudStorageUtils::DoubleToVector}, + {TYPE_INDEX, &CloudStorageUtils::TextToVector}, + {TYPE_INDEX, &CloudStorageUtils::BlobToVector}, + {TYPE_INDEX, &CloudStorageUtils::BlobToVector}, + {TYPE_INDEX, &CloudStorageUtils::BlobToVector}, + }; + auto it = toVecFunc.find(field.type); + if (it == toVecFunc.end()) { + LOGE("unknown cloud type when convert field to vector."); + return -E_CLOUD_ERROR; + } + std::vector value; + int errCode = it->second(vBucket, field, value); + if (errCode != E_OK) { + LOGE("convert cloud field fail, %d", errCode); + return errCode; + } + return DBCommon::CalcValueHash(value, hashValue); +} + +bool CloudStorageUtils::IsAssetsContainDuplicateAsset(Assets &assets) +{ + std::set set; + for (const auto &asset : assets) { + if (set.find(asset.name) != set.end()) { + return true; + } + set.insert(asset.name); + } + return false; +} + +void CloudStorageUtils::EraseNoChangeAsset(std::map &assetsMap) +{ + for (auto &items: assetsMap) { + for (auto item = items.second.begin(); item != items.second.end();) { + if (static_cast((*item).status) == AssetOpType::NO_CHANGE) { + item = items.second.erase(item); + } else { + item++; + } + } + } +} + +void CloudStorageUtils::MergeDownloadAsset(std::map &downloadAssets, + std::map &mergeAssets) +{ + for (auto &items: mergeAssets) { + auto downloadItem = downloadAssets.find(items.first); + if (downloadItem == downloadAssets.end()) { + continue; + } + std::map beCoveredAssetsMap = GenAssetsIndexMap(items.second); + for (const Asset &asset: downloadItem->second) { + auto it = beCoveredAssetsMap.find(asset.name); + if (it == beCoveredAssetsMap.end()) { + continue; + } + items.second[it->second] = asset; + } + } +} + +std::map CloudStorageUtils::GenAssetsIndexMap(Assets &assets) +{ + // key of assetsIndexMap is name of asset, the value of it is index. + std::map assetsIndexMap; + for (size_t i = 0; i < assets.size(); i++) { + assetsIndexMap[assets[i].name] = i; + } + return assetsIndexMap; +} } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_able_storage.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_able_storage.cpp index 7612f523..42bc3f4a 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_able_storage.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_able_storage.cpp @@ -866,7 +866,7 @@ int RelationalSyncAbleStorage::GetRemoteDeviceSchema(const std::string &deviceId LOGE("Get remote device schema from meta failed. err=%d", errCode); return errCode; } - std::string remoteSchema(remoteSchemaBuff.begin(), remoteSchemaBuff.end()); + remoteSchema = std::string(remoteSchemaBuff.begin(), remoteSchemaBuff.end()); errCode = remoteDeviceSchema_.Put(deviceId, remoteSchema); } @@ -1160,11 +1160,14 @@ int RelationalSyncAbleStorage::FillCloudAssetForDownload(const std::string &tabl return errCode; } -int RelationalSyncAbleStorage::FillCloudAssetForUpload(const CloudSyncData &data) +int RelationalSyncAbleStorage::FillCloudGidAndAsset(const OpType &opType, const CloudSyncData &data) { if (storageEngine_ == nullptr) { return -E_INVALID_DB; } + if (opType == OpType::UPDATE && data.updData.assets.empty()) { + return E_OK; + } int errCode = E_OK; auto writeHandle = static_cast( storageEngine_->FindExecutor(true, OperatePerm::NORMAL_PERM, errCode, 0)); @@ -1176,8 +1179,22 @@ int RelationalSyncAbleStorage::FillCloudAssetForUpload(const CloudSyncData &data ReleaseHandle(writeHandle); return errCode; } - errCode = writeHandle->FillCloudAssetForUpload(data); + if (opType == OpType::INSERT) { + errCode = writeHandle->UpdateCloudLogGid(data); + if (errCode != E_OK) { + LOGE("Failed to fill cloud log gid, %d.", errCode); + writeHandle->Rollback(); + ReleaseHandle(writeHandle); + return errCode; + } + if (!data.insData.assets.empty()) { + errCode = writeHandle->FillCloudAssetForUpload(data.tableName, data.insData); + } + } else { + errCode = writeHandle->FillCloudAssetForUpload(data.tableName, data.updData); + } if (errCode != E_OK) { + LOGE("Failed to fill cloud asset, %d.", errCode); writeHandle->Rollback(); ReleaseHandle(writeHandle); return errCode; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp index 0340b123..069a4176 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp @@ -945,8 +945,16 @@ int SQLiteRelationalStore::Sync(const std::vector &devices, SyncMod LOGE("[RelationalStore] sync with empty table"); return -E_INVALID_ARGS; } + SecurityOption option; + int errCode = storageEngine_->GetSecurityOption(option); + if (errCode != E_OK && errCode != -E_NOT_SUPPORT) { + return -E_SECURITY_OPTION_CHECK_ERROR; + } + if (errCode == E_OK && option.securityLabel == S4) { + return -E_SECURITY_OPTION_CHECK_ERROR; + } for (const auto &table: tableNames) { - int errCode = ChkSchema(table); + errCode = ChkSchema(table); if (errCode != E_OK) { LOGE("[RelationalStore] schema check failed when sync"); return errCode; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.cpp index 053ed430..6a449a78 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.cpp @@ -45,8 +45,8 @@ int SqliteLogTableManager::CreateRelationalLogTable(sqlite3 *db, const TableInfo "wtimestamp INT NOT NULL," \ "flag INT NOT NULL," \ "hash_key BLOB NOT NULL," \ - "cloud_gid TEXT," \ - + primaryKey + ");"; + "cloud_gid TEXT," + + primaryKey + ");"; std::vector logTableSchema; logTableSchema.emplace_back(createTableSql); GetIndexSql(table, logTableSchema); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp index bf820309..5b874ca0 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp @@ -2251,11 +2251,10 @@ int SQLiteSingleVerNaturalStore::InterceptData(std::vector & int SQLiteSingleVerNaturalStore::AddSubscribe(const std::string &subscribeId, const QueryObject &query, bool needCacheSubscribe) { - const SchemaObject &localSchema = MyProp().GetSchemaConstRef(); - if (localSchema.GetSchemaType() != SchemaType::NONE && localSchema.GetSchemaType() != SchemaType::JSON) { - // Flatbuffer schema is not support subscribe + if (IsSupportSubscribe() != E_OK) { return -E_NOT_SUPPORT; } + const SchemaObject &localSchema = MyProp().GetSchemaConstRef(); QueryObject queryInner = query; queryInner.SetSchema(localSchema); if (IsExtendedCacheDBMode() && needCacheSubscribe) { // cache auto subscribe when engine state is in CACHEDB mode @@ -2390,6 +2389,16 @@ void SQLiteSingleVerNaturalStore::Dump(int fd) SyncAbleKvDB::Dump(fd); } +int SQLiteSingleVerNaturalStore::IsSupportSubscribe() const +{ + const SchemaObject &localSchema = MyProp().GetSchemaConstRef(); + if (localSchema.GetSchemaType() != SchemaType::NONE && localSchema.GetSchemaType() != SchemaType::JSON) { + // Flatbuffer schema is not support subscribe + return -E_NOT_SUPPORT; + } + return E_OK; +} + int SQLiteSingleVerNaturalStore::RemoveDeviceDataInner(const std::string &hashDev, bool isNeedNotify) { int errCode = E_OK; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h index 0bb1a832..077afff2 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h @@ -192,6 +192,8 @@ public: void Dump(int fd) override; + int IsSupportSubscribe() const override; + private: struct TransPair { int index; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.cpp index 45422138..65bfe058 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.cpp @@ -42,6 +42,7 @@ static constexpr const char* FLAG_IS_CLOUD = "FLAG & 0x02 = 0"; // see if 1th bi static constexpr const char* SET_FLAG_LOCAL = "FLAG | 0x02"; // set 1th bit of flag to one which is local static constexpr const int SET_FLAG_ZERO_MASK = 0x03; // clear 2th bit of flag static constexpr const int SET_FLAG_ONE_MASK = 0x04; // set 2th bit of flag +static constexpr const int SET_CLOUD_FLAG = 0x05; // set 1th bit of flag to 0 int PermitSelect(void *a, int b, const char *c, const char *d, const char *e, const char *f) { @@ -62,14 +63,6 @@ SQLiteSingleVerRelationalStorageExecutor::SQLiteSingleVerRelationalStorageExecut bindCloudFieldFuncMap_[TYPE_INDEX] = &CloudStorageUtils::BindBlob; bindCloudFieldFuncMap_[TYPE_INDEX] = &CloudStorageUtils::BindAsset; bindCloudFieldFuncMap_[TYPE_INDEX] = &CloudStorageUtils::BindAsset; - - toVectorFuncMap_[TYPE_INDEX] = &CloudStorageUtils::Int64ToVector; - toVectorFuncMap_[TYPE_INDEX] = &CloudStorageUtils::BoolToVector; - toVectorFuncMap_[TYPE_INDEX] = &CloudStorageUtils::DoubleToVector; - toVectorFuncMap_[TYPE_INDEX] = &CloudStorageUtils::TextToVector; - toVectorFuncMap_[TYPE_INDEX] = &CloudStorageUtils::BlobToVector; - toVectorFuncMap_[TYPE_INDEX] = &CloudStorageUtils::BlobToVector; - toVectorFuncMap_[TYPE_INDEX] = &CloudStorageUtils::BlobToVector; } @@ -538,6 +531,12 @@ int IdentifyCloudType(CloudSyncData &cloudSyncData, VBucket &data, VBucket &log, if (!data.empty()) { cloudSyncData.insData.record.push_back(data); cloudSyncData.insData.rowid.push_back(*rowid); + VBucket asset; + CloudStorageUtils::ObtainAssetFromVBucket(data, asset); + if (!asset.empty()) { + cloudSyncData.insData.timestamp.push_back(*timeStamp); + cloudSyncData.insData.assets.push_back(asset); + } } cloudSyncData.insData.extend.push_back(log); } else { @@ -930,10 +929,8 @@ int SQLiteSingleVerRelationalStorageExecutor::SaveSyncDataItems(RelationalSyncDa return saveStmt.ResetStatements(false); }); - if (errCode == -E_NOT_FOUND) { - errCode = E_OK; - } - return saveStmt.ResetStatements(true); + int ret = saveStmt.ResetStatements(true); + return errCode != E_OK ? errCode : ret; } int SQLiteSingleVerRelationalStorageExecutor::SaveSyncItems(RelationalSyncDataInserter &inserter, bool useTrans) @@ -1553,6 +1550,7 @@ int SQLiteSingleVerRelationalStorageExecutor::GetSyncCloudData(CloudSyncData &cl } Timestamp queryTime = 0; uint32_t totalSize = 0; + uint32_t stepNum = 0; do { if (isStepNext) { errCode = StepNext(isMemDb_, queryStmt, queryTime); @@ -1561,7 +1559,7 @@ int SQLiteSingleVerRelationalStorageExecutor::GetSyncCloudData(CloudSyncData &cl } } isStepNext = true; - errCode = GetCloudDataForSync(queryStmt, cloudDataResult, totalSize, maxSize); + errCode = GetCloudDataForSync(queryStmt, cloudDataResult, stepNum++, totalSize, maxSize); } while (errCode == E_OK); if (errCode != -E_UNFINISHED) { (void)token.ReleaseCloudStatement(); @@ -1570,7 +1568,7 @@ int SQLiteSingleVerRelationalStorageExecutor::GetSyncCloudData(CloudSyncData &cl } int SQLiteSingleVerRelationalStorageExecutor::GetCloudDataForSync(sqlite3_stmt *statement, - CloudSyncData &cloudDataResult, uint32_t &totalSize, const uint32_t &maxSize) + CloudSyncData &cloudDataResult, uint32_t stepNum, uint32_t &totalSize, const uint32_t &maxSize) { VBucket log; VBucket extraLog; @@ -1599,7 +1597,7 @@ int SQLiteSingleVerRelationalStorageExecutor::GetCloudDataForSync(sqlite3_stmt * } } - if (totalSize < maxSize) { + if (IsGetCloudDataContinue(stepNum, totalSize, maxSize)) { errCode = IdentifyCloudType(cloudDataResult, data, log, extraLog); } else { errCode = -E_UNFINISHED; @@ -1622,6 +1620,10 @@ int SQLiteSingleVerRelationalStorageExecutor::PutVBucketByType(VBucket &vBucket, if (errCode != E_OK) { return errCode; } + if (CloudStorageUtils::IsAssetsContainDuplicateAsset(assets)) { + LOGE("assets is contain duplicate Asset"); + return -E_CLOUD_ERROR; + } vBucket.insert_or_assign(field.colName, assets); } else { vBucket.insert_or_assign(field.colName, cloudValue); @@ -1749,7 +1751,7 @@ std::string SQLiteSingleVerRelationalStorageExecutor::GetInsertSqlForCloudSync(c } int SQLiteSingleVerRelationalStorageExecutor::GetPrimaryKeyHashValue(const VBucket &vBucket, - const TableSchema &tableSchema, std::vector &hashValue) + const TableSchema &tableSchema, std::vector &hashValue, bool allowEmpty) { int errCode = E_OK; std::map pkMap = CloudStorageUtils::GetCloudPrimaryKeyFieldMap(tableSchema); @@ -1760,12 +1762,12 @@ int SQLiteSingleVerRelationalStorageExecutor::GetPrimaryKeyHashValue(const VBuck errCode = DBCommon::CalcValueHash(value, hashValue); } else if (pkMap.size() == 1) { std::vector pkVec = CloudStorageUtils::GetCloudPrimaryKeyField(tableSchema); - errCode = CalculateHashKeyForOneField(pkVec.at(0), vBucket, hashValue); + errCode = CloudStorageUtils::CalculateHashKeyForOneField(pkVec.at(0), vBucket, allowEmpty, hashValue); } else { std::vector tempRes; for (const auto &item: pkMap) { std::vector temp; - errCode = CalculateHashKeyForOneField(item.second, vBucket, temp); + errCode = CloudStorageUtils::CalculateHashKeyForOneField(item.second, vBucket, allowEmpty, temp); if (errCode != E_OK) { LOGE("calc hash fail when there is more than one primary key. errCode = %d", errCode); return errCode; @@ -1806,7 +1808,7 @@ int SQLiteSingleVerRelationalStorageExecutor::GetQueryLogStatement(const TableSc std::vector hashValue; if (pkSet.size() > 0) { - errCode = GetPrimaryKeyHashValue(vBucket, tableSchema, hashValue); + errCode = GetPrimaryKeyHashValue(vBucket, tableSchema, hashValue, true); } if (errCode != E_OK) { LOGE("calc hash fail when get query log statement, errCode = %d", errCode); @@ -1824,23 +1826,6 @@ int SQLiteSingleVerRelationalStorageExecutor::GetQueryLogStatement(const TableSc return errCode != E_OK ? errCode : ret; } -int SQLiteSingleVerRelationalStorageExecutor::CalculateHashKeyForOneField(const Field &field, const VBucket &vBucket, - std::vector &hashValue) -{ - auto it = toVectorFuncMap_.find(field.type); - if (it == toVectorFuncMap_.end()) { - LOGE("unknown cloud type when convert field to vector."); - return -E_CLOUD_ERROR; - } - std::vector value; - int errCode = it->second(vBucket, field, value); - if (errCode != E_OK) { - LOGE("convert cloud field fail, %d", errCode); - return errCode; - } - return DBCommon::CalcValueHash(value, hashValue); -} - int SQLiteSingleVerRelationalStorageExecutor::GetQueryLogSql(const std::string &tableName, const VBucket &vBucket, std::set &pkSet, std::string &querySql) { @@ -1886,7 +1871,9 @@ int SQLiteSingleVerRelationalStorageExecutor::ExecutePutCloudData(const std::str case OpType::ONLY_UPDATE_GID: case OpType::SET_CLOUD_FORCE_PUSH_FLAG_ZERO: case OpType::SET_CLOUD_FORCE_PUSH_FLAG_ONE: - errCode = UpdateCloudGidOrFlag(vBucket, tableSchema, op); + case OpType::UPDATE_TIMESTAMP: + case OpType::CLEAR_GID: + errCode = OnlyUpdateLogTable(vBucket, tableSchema, op); break; case OpType::NOT_HANDLE: break; @@ -2166,12 +2153,14 @@ int SQLiteSingleVerRelationalStorageExecutor::PutCloudSyncData(const std::string if (ret != E_OK) { LOGE("Fail to set log trigger on, %d", ret); } - LOGD("save cloud data ok, insert count = %d, update count = %d, delete count = %d, only update gid count = %d, " - "set LCC flag zero count = %d, set LCC flag one count = %d, not handle count = %d", - statisticMap[static_cast(OpType::INSERT)], statisticMap[static_cast(OpType::UPDATE)], + LOGD("save cloud data: %d, insert cnt = %d, update cnt = %d, delete cnt = %d, only update gid cnt = %d, " + "set LCC flag zero cnt = %d, set LCC flag one cnt = %d, update timestamp cnt = %d, clear gid count = %d," + " not handle cnt = %d", + errCode, statisticMap[static_cast(OpType::INSERT)], statisticMap[static_cast(OpType::UPDATE)], statisticMap[static_cast(OpType::DELETE)], statisticMap[static_cast(OpType::ONLY_UPDATE_GID)], statisticMap[static_cast(OpType::SET_CLOUD_FORCE_PUSH_FLAG_ZERO)], statisticMap[static_cast(OpType::SET_CLOUD_FORCE_PUSH_FLAG_ONE)], + statisticMap[static_cast(OpType::UPDATE_TIMESTAMP)], statisticMap[static_cast(OpType::CLEAR_GID)], statisticMap[static_cast(OpType::NOT_HANDLE)]); return errCode == E_OK ? ret : errCode; } @@ -2186,7 +2175,7 @@ int SQLiteSingleVerRelationalStorageExecutor::InsertCloudData(const std::string LOGE("Get insert statement failed when save cloud data, %d", errCode); return errCode; } - CloudStorageUtils::FillAssetFromVBucketBeforeDownload(vBucket); + CloudStorageUtils::PrepareToFillAssetFromVBucket(vBucket); errCode = BindValueToUpsertStatement(vBucket, tableSchema.fields, insertStmt); if (errCode != E_OK) { SQLiteUtils::ResetStatement(insertStmt, true, errCode); @@ -2369,14 +2358,14 @@ int SQLiteSingleVerRelationalStorageExecutor::BindValueToInsertLogStatement(VBuc } std::string SQLiteSingleVerRelationalStorageExecutor::GetWhereConditionForDataTable(const std::string &gidStr, - const std::set &pkSet, const std::string &tableName) + const std::set &pkSet, const std::string &tableName, bool queryByPk) { std::string where = " where"; if (!gidStr.empty()) { // gid has higher priority, because primary key may be modified where += " rowid = (select data_key from " + DBCommon::GetLogTableName(tableName) + " where cloud_gid = '" + gidStr + "')"; } - if (!pkSet.empty()) { + if (!pkSet.empty() && queryByPk) { if (!gidStr.empty()) { where += " or"; } @@ -2450,7 +2439,7 @@ int SQLiteSingleVerRelationalStorageExecutor::GetUpdateDataTableStatement(const int SQLiteSingleVerRelationalStorageExecutor::UpdateCloudData(const std::string &tableName, VBucket &vBucket, const TableSchema &tableSchema) { - CloudStorageUtils::FillAssetFromVBucketBeforeDownload(vBucket); + CloudStorageUtils::PrepareToFillAssetFromVBucket(vBucket); sqlite3_stmt *updateStmt = nullptr; int errCode = GetUpdateDataTableStatement(vBucket, tableSchema, updateStmt); if (errCode != E_OK) { @@ -2488,15 +2477,21 @@ int SQLiteSingleVerRelationalStorageExecutor::GetUpdateLogRecordStatement(const updateLogSql += "flag = flag & " + std::to_string(SET_FLAG_ZERO_MASK); // clear 2th bit of flag } else if (opType == OpType::SET_CLOUD_FORCE_PUSH_FLAG_ONE) { updateLogSql += "flag = flag | " + std::to_string(SET_FLAG_ONE_MASK); // set 2th bit of flag + } else if (opType == OpType::UPDATE_TIMESTAMP) { + updateLogSql += "device = 'cloud', flag = flag & " + std::to_string(SET_CLOUD_FLAG) + + ", timestamp = ?, cloud_gid = ''"; + updateColName.push_back(CloudDbConstant::MODIFY_FIELD); + } else if (opType == OpType::CLEAR_GID) { + updateLogSql += "cloud_gid = '', flag = flag & " + std::to_string(SET_FLAG_ZERO_MASK); } else { if (opType == OpType::DELETE) { - updateLogSql += "data_key = -1, flag = 1, "; + updateLogSql += "data_key = -1, flag = 1, cloud_gid = '', "; } else { - updateLogSql += "flag = 0, "; + updateLogSql += "flag = 0, cloud_gid = ?, "; + updateColName.push_back(CloudDbConstant::GID_FIELD); } - updateLogSql += "device = 'cloud', timestamp = ?, cloud_gid = ?"; + updateLogSql += "device = 'cloud', timestamp = ?"; updateColName.push_back(CloudDbConstant::MODIFY_FIELD); - updateColName.push_back(CloudDbConstant::GID_FIELD); } std::string gidStr; @@ -2525,6 +2520,12 @@ int SQLiteSingleVerRelationalStorageExecutor::GetUpdateLogRecordStatement(const return errCode; } +static inline bool IsAllowWithPrimaryKey(OpType opType) +{ + return (opType == OpType::DELETE || opType == OpType::UPDATE_TIMESTAMP || opType == OpType::CLEAR_GID || + opType == OpType::ONLY_UPDATE_GID); +} + int SQLiteSingleVerRelationalStorageExecutor::UpdateLogRecord(const VBucket &vBucket, const TableSchema &tableSchema, OpType opType) { @@ -2536,8 +2537,8 @@ int SQLiteSingleVerRelationalStorageExecutor::UpdateLogRecord(const VBucket &vBu return errCode; } - std::map pkMap = CloudStorageUtils::GetCloudPrimaryKeyFieldMap(tableSchema); - errCode = BindValueToUpdateLogStatement(vBucket, tableSchema, updateColName, pkMap, updateLogStmt); + errCode = BindValueToUpdateLogStatement(vBucket, tableSchema, updateColName, IsAllowWithPrimaryKey(opType), + updateLogStmt); int ret = E_OK; if (errCode != E_OK) { LOGE("bind value to update log statement failed when update cloud data, %d", errCode); @@ -2556,7 +2557,7 @@ int SQLiteSingleVerRelationalStorageExecutor::UpdateLogRecord(const VBucket &vBu } int SQLiteSingleVerRelationalStorageExecutor::BindValueToUpdateLogStatement(const VBucket &vBucket, - const TableSchema &tableSchema, std::vector &colNames, std::map &pkMap, + const TableSchema &tableSchema, const std::vector &colNames, bool allowPrimaryKeyEmpty, sqlite3_stmt *updateLogStmt) { int index = 0; @@ -2564,9 +2565,17 @@ int SQLiteSingleVerRelationalStorageExecutor::BindValueToUpdateLogStatement(cons for (const auto &colName : colNames) { index++; if (colName == CloudDbConstant::GID_FIELD) { + if (vBucket.find(colName) == vBucket.end()) { + LOGE("cloud data doesn't contain gid field when bind update log stmt."); + return -E_CLOUD_ERROR; + } errCode = SQLiteUtils::BindTextToStatement(updateLogStmt, index, std::get(vBucket.at(colName))); } else if (colName == CloudDbConstant::MODIFY_FIELD) { + if (vBucket.find(colName) == vBucket.end()) { + LOGE("cloud data doesn't contain modify field when bind update log stmt."); + return -E_CLOUD_ERROR; + } errCode = SQLiteUtils::BindInt64ToStatement(updateLogStmt, index, std::get(vBucket.at(colName))); } else { LOGE("invalid col name when bind value to update log statement."); @@ -2577,12 +2586,13 @@ int SQLiteSingleVerRelationalStorageExecutor::BindValueToUpdateLogStatement(cons return errCode; } } + std::map pkMap = CloudStorageUtils::GetCloudPrimaryKeyFieldMap(tableSchema); if (pkMap.empty()) { return E_OK; } std::vector hashKey; - errCode = GetPrimaryKeyHashValue(vBucket, tableSchema, hashKey); + errCode = GetPrimaryKeyHashValue(vBucket, tableSchema, hashKey, allowPrimaryKeyEmpty); if (errCode != E_OK) { return errCode; } @@ -2598,27 +2608,18 @@ int SQLiteSingleVerRelationalStorageExecutor::GetDeleteStatementForCloudSync(con LOGE("Get gid from cloud data fail when construct delete sql, errCode = %d", errCode); return errCode; } - if (!gidStr.empty() && gidStr.find("'") != std::string::npos) { - LOGE("invalid char in cloud gid"); + if (gidStr.empty() || gidStr.find("'") != std::string::npos) { + LOGE("empty or invalid char in cloud gid"); return -E_CLOUD_ERROR; } std::string deleteSql = "delete from " + tableSchema.name; - deleteSql += GetWhereConditionForDataTable(gidStr, pkSet, tableSchema.name); + deleteSql += GetWhereConditionForDataTable(gidStr, pkSet, tableSchema.name, false); errCode = SQLiteUtils::GetStatement(dbHandle_, deleteSql, deleteStmt); if (errCode != E_OK) { - LOGE("Get delete statement failed when delete data, %d", errCode); - return errCode; + LOGE("Get delete statement failed when delete data, %d, deleteSql = %s", errCode, deleteSql.c_str()); } - - std::vector pkFields = CloudStorageUtils::GetCloudPrimaryKeyField(tableSchema); - errCode = BindValueToUpsertStatement(vBucket, pkFields, deleteStmt); - int ret = E_OK; - if (errCode != E_OK) { - LOGE("bind value to delete statement failed when delete data, %d", errCode); - SQLiteUtils::ResetStatement(deleteStmt, true, ret); - } - return errCode != E_OK ? errCode : ret; + return errCode; } int SQLiteSingleVerRelationalStorageExecutor::DeleteCloudData(const std::string &tableName, const VBucket &vBucket, @@ -2651,7 +2652,7 @@ int SQLiteSingleVerRelationalStorageExecutor::DeleteCloudData(const std::string return errCode; } -int SQLiteSingleVerRelationalStorageExecutor::UpdateCloudGidOrFlag(const VBucket &vBucket, +int SQLiteSingleVerRelationalStorageExecutor::OnlyUpdateLogTable(const VBucket &vBucket, const TableSchema &tableSchema, OpType opType) { return UpdateLogRecord(vBucket, tableSchema, opType); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.h index b91d0e41..cba0db78 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.h @@ -109,7 +109,7 @@ public: int DoCleanInner(ClearMode mode, const std::vector &tableNameList, const std::vector &tableSchemaList, std::vector &assets); - int FillCloudAssetForUpload(const CloudSyncData &data); + int FillCloudAssetForUpload(const std::string &tableName, const CloudSyncBatch &data); private: int DoCleanLogs(const std::vector &tableNameList); @@ -166,8 +166,8 @@ private: int GeneLogInfoForExistedData(sqlite3 *db, const std::string &tableName, const TableInfo &table, const std::string &calPrimaryKeyHash); - int GetCloudDataForSync(sqlite3_stmt *statement, CloudSyncData &cloudDataResult, uint32_t &totalSize, - const uint32_t &maxSize); + int GetCloudDataForSync(sqlite3_stmt *statement, CloudSyncData &cloudDataResult, uint32_t stepNum, + uint32_t &totalSize, const uint32_t &maxSize); int PutVBucketByType(VBucket &vBucket, const Field &field, Type &cloudValue); @@ -176,7 +176,8 @@ private: std::string GetInsertSqlForCloudSync(const TableSchema &tableSchema); - int GetPrimaryKeyHashValue(const VBucket &vBucket, const TableSchema &tableSchema, std::vector &hashValue); + int GetPrimaryKeyHashValue(const VBucket &vBucket, const TableSchema &tableSchema, std::vector &hashValue, + bool allowEmpty = false); int GetQueryLogStatement(const TableSchema &tableSchema, const VBucket &vBucket, const std::string &querySql, std::set &pkSet, sqlite3_stmt *&selectStmt); @@ -190,11 +191,10 @@ private: int GetQueryLogRowid(const std::string &tableName, const VBucket &vBucket, int64_t &rowId); int GetFillDownloadAssetStatement(const std::string &tableName, const VBucket &vBucket, - const std::vector &fields, bool isFullReplace, sqlite3_stmt *&statement); + const std::vector &fields, sqlite3_stmt *&statement); - int GetFillUploadAssetStatement(const std::string &tableName, const VBucket &vBucket, sqlite3_stmt *&statement); - - int CalculateHashKeyForOneField(const Field &field, const VBucket &vBucket, std::vector &hashValue); + int InitFillUploadAssetStatement(const std::string &tableName, const CloudSyncBatch &data, + const int &index, sqlite3_stmt *&statement); void GetLogInfoByStatement(sqlite3_stmt *statement, LogInfo &logInfo); @@ -215,7 +215,7 @@ private: int BindValueToInsertLogStatement(VBucket &vBucket, const TableSchema &tableSchema, sqlite3_stmt *insertLogStmt); std::string GetWhereConditionForDataTable(const std::string &gidStr, const std::set &pkSet, - const std::string &tableName); + const std::string &tableName, bool queryByPk = true); int GetUpdateSqlForCloudSync(const TableSchema &tableSchema, const VBucket &vBucket, const std::string &gidStr, const std::set &pkSet, std::string &updateSql); @@ -230,14 +230,16 @@ private: int UpdateLogRecord(const VBucket &vBucket, const TableSchema &tableSchema, OpType opType); int BindValueToUpdateLogStatement(const VBucket &vBucket, const TableSchema &tableSchema, - std::vector &colNames, std::map &pkMap, sqlite3_stmt *updateLogStmt); + const std::vector &colNames, bool allowPrimaryKeyEmpty, sqlite3_stmt *updateLogStmt); int GetDeleteStatementForCloudSync(const TableSchema &tableSchema, const std::set &pkSet, const VBucket &vBucket, sqlite3_stmt *&deleteStmt); int DeleteCloudData(const std::string &tableName, const VBucket &vBucket, const TableSchema &tableSchema); - int UpdateCloudGidOrFlag(const VBucket &vBucket, const TableSchema &tableSchema, OpType opType); + int OnlyUpdateLogTable(const VBucket &vBucket, const TableSchema &tableSchema, OpType opType); + + bool IsGetCloudDataContinue(uint32_t curNum, uint32_t curSize, uint32_t maxSize); std::string baseTblName_; TableInfo table_; // Always operating table, user table when get, device table when put. diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_extend_executor.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_extend_executor.cpp index e3924d87..db88d3d8 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_extend_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_extend_executor.cpp @@ -26,14 +26,14 @@ int SQLiteSingleVerRelationalStorageExecutor::GetQueryInfoSql(const std::string if (assetFields.empty() && pkSet.empty()) { return GetQueryLogSql(tableName, vBucket, pkSet, querySql); } - std::string cloudGid; - int errCode = CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, vBucket, cloudGid); + std::string gid; + int errCode = CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, vBucket, gid); if (errCode != E_OK) { LOGE("Get cloud gid fail when query log table."); return errCode; } - if (pkSet.empty() && cloudGid.empty()) { + if (pkSet.empty() && gid.empty()) { LOGE("query log table failed because of both primary key and gid are empty."); return -E_CLOUD_ERROR; } @@ -47,7 +47,7 @@ int SQLiteSingleVerRelationalStorageExecutor::GetQueryInfoSql(const std::string } sql += " from '" + DBCommon::GetLogTableName(tableName) + "' AS a LEFT JOIN '" + tableName + "' AS b "; sql += " ON (a.data_key = b.rowid) WHERE "; - if (!cloudGid.empty()) { + if (!gid.empty()) { sql += " a.cloud_gid = ? or "; } sql += "a.hash_key = ?"; @@ -92,7 +92,7 @@ int SQLiteSingleVerRelationalStorageExecutor::GetQueryLogRowid(const std::string } int SQLiteSingleVerRelationalStorageExecutor::GetFillDownloadAssetStatement(const std::string &tableName, - const VBucket &vBucket, const std::vector &fields, bool isFullReplace, sqlite3_stmt *&statement) + const VBucket &vBucket, const std::vector &fields, sqlite3_stmt *&statement) { std::string sql = "UPDATE " + tableName + " SET "; for (const auto &field: fields) { @@ -138,11 +138,12 @@ int SQLiteSingleVerRelationalStorageExecutor::FillCloudAssetForDownload(const Ta goto END; } if (isFullReplace) { - CloudStorageUtils::FillAssetFromVBucketDownloadFinish(vBucket); + CloudStorageUtils::FillAssetFromVBucketFinish(vBucket, CloudStorageUtils::FillAssetForDownload, + CloudStorageUtils::FillAssetsForDownload); } else { - CloudStorageUtils::FillAssetFromVBucketBeforeDownload(vBucket); + CloudStorageUtils::PrepareToFillAssetFromVBucket(vBucket); } - errCode = GetFillDownloadAssetStatement(tableSchema.name, vBucket, assetsField, isFullReplace, stmt); + errCode = GetFillDownloadAssetStatement(tableSchema.name, vBucket, assetsField, stmt); if (errCode != E_OK) { goto END; } @@ -167,13 +168,13 @@ END: return errCode; } -int SQLiteSingleVerRelationalStorageExecutor::FillCloudAssetForUpload(const CloudSyncData &data) +int SQLiteSingleVerRelationalStorageExecutor::FillCloudAssetForUpload(const std::string &tableName, + const CloudSyncBatch &data) { - if (data.updData.assets.empty() || data.updData.rowid.empty() || data.updData.timestamp.empty()) { + if (data.assets.empty() || data.rowid.empty() || data.timestamp.empty()) { return -E_INVALID_ARGS; } - if (data.updData.assets.size() != data.updData.rowid.size() || - data.updData.assets.size() != data.updData.timestamp.size()) { + if (data.assets.size() != data.rowid.size() || data.assets.size() != data.timestamp.size()) { return -E_INVALID_ARGS; } int errCode = SetLogTriggerStatus(false); @@ -182,66 +183,85 @@ int SQLiteSingleVerRelationalStorageExecutor::FillCloudAssetForUpload(const Clou return errCode; } sqlite3_stmt *stmt = nullptr; - for (size_t i = 0; i < data.updData.assets.size(); ++i) { - VBucket assetData = data.updData.assets.at(i); - CloudStorageUtils::FillAssetFromVBucketAfterUpload(assetData); - errCode = GetFillUploadAssetStatement(data.tableName, assetData, stmt); - if (errCode != E_OK) { - goto END; - } - int64_t rowid = data.updData.rowid[i]; - errCode = SQLiteUtils::BindInt64ToStatement(stmt, assetData.size() + 1, rowid); - if (errCode != E_OK) { - break; - } - int64_t timeStamp = data.updData.timestamp[i]; - errCode = SQLiteUtils::BindInt64ToStatement(stmt, assetData.size() + 2, timeStamp); // 2 is index + for (size_t i = 0; i < data.assets.size(); ++i) { + errCode = InitFillUploadAssetStatement(tableName, data, i, stmt); if (errCode != E_OK) { break; } errCode = SQLiteUtils::StepWithRetry(stmt, false); - if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { - errCode = E_OK; - SQLiteUtils::ResetStatement(stmt, false, errCode); - } else { + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { LOGE("Fill upload asset failed:%d", errCode); break; } + errCode = E_OK; + SQLiteUtils::ResetStatement(stmt, true, errCode); + stmt = nullptr; + if (errCode != E_OK) { + break; + } } - SQLiteUtils::ResetStatement(stmt, true, errCode); -END: + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, true, ret); int endCode = SetLogTriggerStatus(true); if (endCode != E_OK) { LOGE("Fail to set log trigger off, %d", endCode); + return endCode; } - return errCode; + return errCode != E_OK ? errCode : ret; } -int SQLiteSingleVerRelationalStorageExecutor::GetFillUploadAssetStatement(const std::string &tableName, - const VBucket &vBucket, sqlite3_stmt *&statement) +int SQLiteSingleVerRelationalStorageExecutor::InitFillUploadAssetStatement(const std::string &tableName, + const CloudSyncBatch &data, const int &index, sqlite3_stmt *&statement) { + VBucket vBucket = data.assets.at(index); + CloudStorageUtils::FillAssetFromVBucketFinish(vBucket, CloudStorageUtils::FillAssetForUpload, + CloudStorageUtils::FillAssetsForUpload); std::string sql = "UPDATE " + tableName + " SET "; for (const auto &item: vBucket) { sql += item.first + " = ?,"; } sql.pop_back(); - sql += " WHERE rowid = ? and (select 1 from " + DBCommon::GetLogTableName(tableName) + " WHERE timestamp = ?);"; + sql += " WHERE rowid = ? and (select 1 from " + DBCommon::GetLogTableName(tableName) + + " WHERE timestamp = ?);"; int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, statement); if (errCode != E_OK) { return errCode; } - int index = 1; + int batchIndex = 1; for (const auto &item: vBucket) { Field field = { .colName = item.first, .type = static_cast(item.second.index()) }; - errCode = bindCloudFieldFuncMap_[TYPE_INDEX](index++, vBucket, field, statement); + errCode = bindCloudFieldFuncMap_[TYPE_INDEX](batchIndex++, vBucket, field, statement); if (errCode != E_OK) { - SQLiteUtils::ResetStatement(statement, true, errCode); return errCode; } } - return errCode; + int64_t rowid = data.rowid[index]; + errCode = SQLiteUtils::BindInt64ToStatement(statement, vBucket.size() + 1, rowid); + if (errCode != E_OK) { + return errCode; + } + int64_t timeStamp = data.timestamp[index]; + return SQLiteUtils::BindInt64ToStatement(statement, vBucket.size() + 2, timeStamp); // 2 is index; +} + +bool SQLiteSingleVerRelationalStorageExecutor::IsGetCloudDataContinue(uint32_t curNum, uint32_t curSize, + uint32_t maxSize) +{ + if (curNum == 0) { + return true; + } +#ifdef MAX_UPLOAD_COUNT + if (curSize < maxSize && curNum < MAX_UPLOAD_COUNT) { + return true; + } +#else + if (curSize < maxSize) { + return true; + } +#endif + return false; } } // namespace DistributedDB #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp index 4e5d7e4b..c8d711c1 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp @@ -85,7 +85,7 @@ int StorageProxy::GetCloudWaterMark(const std::string &tableName, CloudWaterMark return cloudMetaData_->GetCloudWaterMark(tableName, cloudMark); } -int StorageProxy::PutCloudWaterMark(const std::string &tableName, CloudWaterMark &cloudMark) +int StorageProxy::SetCloudWaterMark(const std::string &tableName, CloudWaterMark &cloudMark) { std::shared_lock readLock(storeMutex_); if (cloudMetaData_ == nullptr) { @@ -320,12 +320,16 @@ int StorageProxy::FillCloudAssetForDownload(const std::string &tableName, VBucke return store_->FillCloudAssetForDownload(tableName, asset, isFullReplace); } -int StorageProxy::FillCloudAssetForUpload(const CloudSyncData &data) +int StorageProxy::FillCloudGidAndAsset(const OpType &opType, const CloudSyncData &data) { std::shared_lock readLock(storeMutex_); if (store_ == nullptr) { return -E_INVALID_DB; } - return store_->FillCloudAssetForUpload(data); + if (!transactionExeFlag_.load()) { + LOGE("the transaction has not been started"); + return -E_TRANSACT_STATE; + } + return store_->FillCloudGidAndAsset(opType, data); } } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.cpp index fbafb439..7bc80f9e 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.cpp @@ -27,7 +27,9 @@ CloudDBProxy::CloudDBProxy() int CloudDBProxy::SetCloudDB(const std::shared_ptr &cloudDB) { std::unique_lock writeLock(cloudMutex_); - iCloudDb_ = cloudDB; + if (!iCloudDb_) { + iCloudDb_ = cloudDB; + } return E_OK; } @@ -98,9 +100,6 @@ int CloudDBProxy::Query(const std::string &tableName, VBucket &extend, std::vect context->SetTableName(tableName); int errCode = InnerAction(context, cloudDb, QUERY); context->MoveOutQueryExtendAndData(extend, data); - if (errCode != E_OK && errCode != -E_QUERY_END) { - return -E_CLOUD_ERROR; - } return errCode; } @@ -178,10 +177,10 @@ int CloudDBProxy::Download(const std::string &tableName, const std::string &gid, { std::shared_lock readLock(assetLoaderMutex_); if (iAssetLoader_ == nullptr) { - LOGE("Asset loader has not been set %d", -E_INVALID_DB); - return -E_INVALID_DB; + LOGE("Asset loader has not been set %d", -E_NOT_SET); + return -E_NOT_SET; } - return iAssetLoader_->Download(tableName, gid, prefix, assets); + return iAssetLoader_->Download(tableName, gid, prefix, assets) == OK ? E_OK : -E_CLOUD_ERROR; } int CloudDBProxy::RemoveLocalAssets(const std::vector &assets) @@ -306,7 +305,7 @@ void CloudDBProxy::InnerActionTask(const std::shared_ptr &co LOGD("[CloudDBProxy] action %" PRIu8 " end res:%d", static_cast(action), static_cast(status)); if (!setResAlready) { - context->SetActionRes(status == OK ? E_OK : -E_CLOUD_ERROR); + context->SetActionRes(GetInnerErrorCode(status)); } context->FinishAndNotify(); @@ -317,6 +316,24 @@ void CloudDBProxy::InnerActionTask(const std::shared_ptr &co asyncTaskCv_.notify_all(); } +int CloudDBProxy::GetInnerErrorCode(DBStatus status) +{ + switch (status) { + case OK: + return E_OK; + case CLOUD_NETWORK_ERROR: + return -E_CLOUD_NETWORK_ERROR; + case CLOUD_SYNC_UNSET: + return -E_CLOUD_SYNC_UNSET; + case CLOUD_FULL_RECORDS: + return -E_CLOUD_FULL_RECORDS; + case CLOUD_LOCK_ERROR: + return -E_CLOUD_LOCK_ERROR; + default: + return -E_CLOUD_ERROR; + } +} + CloudDBProxy::CloudActionContext::CloudActionContext() : actionFinished_(false), actionRes_(OK), diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.h index 4173ba10..957648cd 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.h @@ -129,6 +129,8 @@ protected: void InnerActionTask(const std::shared_ptr &context, const std::shared_ptr &cloudDb, InnerActionCode action); + static int GetInnerErrorCode(DBStatus status); + mutable std::shared_mutex cloudMutex_; mutable std::shared_mutex assetLoaderMutex_; std::shared_ptr iCloudDb_; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_pull_strategy.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_pull_strategy.cpp index 70ed70cd..2af8c11e 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_pull_strategy.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_pull_strategy.cpp @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifdef MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA #include "cloud_force_pull_strategy.h" #include "db_common.h" #include "db_errno.h" @@ -25,9 +24,10 @@ OpType CloudForcePullStrategy::TagSyncDataStatus(bool existInLocal, LogInfo &loc if (existInLocal) { if (!IsDelete(localInfo) && IsDelete(cloudInfo)) { return OpType::DELETE; + } else if (IsDelete(cloudInfo)) { + return OpType::UPDATE_TIMESTAMP; } else { - // When gid doestn't exist in local, it will fill gid on local also. - return OpType::UPDATE; + return IsDelete(localInfo) ? OpType::INSERT : OpType::UPDATE; } } else { if (IsDelete(cloudInfo)) { @@ -47,5 +47,4 @@ bool CloudForcePullStrategy::JudgeUpload() { return false; } -} -#endif // MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA \ No newline at end of file +} \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_pull_strategy.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_pull_strategy.h index 34dd0997..79db2efd 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_pull_strategy.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_pull_strategy.h @@ -12,9 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifdef MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA -#ifndef CLOUD_COVER_LOCAL_H -#define CLOUD_COVER_LOCAL_H +#ifndef CLOUD_FORCE_PULL_STRATEGY_H +#define CLOUD_FORCE_PULL_STRATEGY_H #include "cloud_sync_strategy.h" namespace DistributedDB { @@ -27,5 +26,4 @@ public: bool JudgeUpload() override; }; } -#endif // CLOUD_COVER_LOCAL_H -#endif // MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA \ No newline at end of file +#endif // CLOUD_FORCE_PULL_STRATEGY_H \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_push_strategy.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_push_strategy.cpp index 40f0029e..1fbac2f6 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_push_strategy.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_push_strategy.cpp @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifdef MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA #include "cloud_force_push_strategy.h" #include "db_common.h" #include "db_errno.h" @@ -21,10 +20,15 @@ namespace DistributedDB { const std::string cloud_device_name = "cloud"; OpType CloudForcePushStrategy::TagSyncDataStatus(bool existInLocal, LogInfo &localInfo, LogInfo &cloudInfo) { + bool isCloudDelete = IsDelete(cloudInfo); if (existInLocal) { if (localInfo.cloudGid.empty()) { - return OpType::ONLY_UPDATE_GID; + // when cloud data is deleted, we think it is different data + return isCloudDelete ? OpType::NOT_HANDLE : OpType::ONLY_UPDATE_GID; } else { + if (isCloudDelete) { + return OpType::CLEAR_GID; + } if (localInfo.device == cloud_device_name && localInfo.timestamp == cloudInfo.timestamp) { return OpType::SET_CLOUD_FORCE_PUSH_FLAG_ONE; } @@ -47,5 +51,4 @@ bool CloudForcePushStrategy::JudgeUpload() { return true; } -} -#endif // MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA \ No newline at end of file +} \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_push_strategy.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_push_strategy.h index 94eb9ba4..b7616e67 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_push_strategy.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_force_push_strategy.h @@ -12,9 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifdef MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA -#ifndef LOCAL_COVER_CLOUD_H -#define LOCAL_COVER_CLOUD_H +#ifndef CLOUD_FORCE_PUSH_STRATEGY_H +#define CLOUD_FORCE_PUSH_STRATEGY_H #include "cloud_sync_strategy.h" namespace DistributedDB { @@ -27,5 +26,4 @@ public: bool JudgeUpload() override; }; } -#endif // LOCAL_COVER_CLOUD_H -#endif // MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA \ No newline at end of file +#endif // CLOUD_FORCE_PUSH_STRATEGY_H \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.cpp index 15df052a..9b8755fd 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.cpp @@ -18,8 +18,11 @@ namespace DistributedDB { OpType CloudMergeStrategy::TagSyncDataStatus(bool existInLocal, LogInfo &localInfo, LogInfo &cloudInfo) { + bool isCloudDelete = IsDelete(cloudInfo); + bool isLocalDelete = IsDelete(localInfo); if (!existInLocal) { - if ((cloudInfo.flag & 0x1) == 1) { + // when cloud data is deleted, we think it is different data + if (isCloudDelete) { return OpType::NOT_HANDLE; } return OpType::INSERT; @@ -27,14 +30,16 @@ OpType CloudMergeStrategy::TagSyncDataStatus(bool existInLocal, LogInfo &localIn OpType type = OpType::NOT_HANDLE; if (localInfo.timestamp > cloudInfo.timestamp) { if (localInfo.cloudGid.empty()) { - type = OpType::ONLY_UPDATE_GID; + type = isCloudDelete ? OpType::NOT_HANDLE : OpType::ONLY_UPDATE_GID; + } else { + type = isCloudDelete ? OpType::CLEAR_GID : type; } return type; } - if ((cloudInfo.flag & 0x1) == 1) { - type = IsDelete(localInfo) ? OpType::NOT_HANDLE : OpType::DELETE; + if (isCloudDelete) { + type = isLocalDelete ? OpType::UPDATE_TIMESTAMP : OpType::DELETE; } else { - type = IsDelete(localInfo) ? OpType::INSERT : OpType::UPDATE; + type = isLocalDelete ? OpType::INSERT : OpType::UPDATE; } return type; } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_strategy.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_strategy.h index 3b4f0bcb..2d0fd48b 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_strategy.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_strategy.h @@ -45,7 +45,7 @@ public: return false; } - bool IsDelete(const LogInfo &info) + static bool IsDelete(const LogInfo &info) { return (info.flag & 0x1) == 1; } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp index 87ed5afd..69da43a3 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp @@ -16,7 +16,6 @@ #include #include -#include #include "cloud/cloud_db_constant.h" #include "cloud/cloud_storage_utils.h" @@ -43,7 +42,8 @@ CloudSyncer::CloudSyncer(std::shared_ptr storageProxy) closed_(false), timerId_(0u), heartBeatCount_(0), - failedHeartBeatCount_(0) + failedHeartBeatCount_(0), + syncCallbackCount_(0) { } @@ -114,12 +114,24 @@ void CloudSyncer::Close() for (auto &info: infoList) { info.status = ProcessStatus::FINISHED; info.errCode = -E_DB_CLOSED; - ProcessNotifier notifier; + ProcessNotifier notifier(this); notifier.Init(info.table, info.devices); notifier.NotifyProcess(info, {}, true); LOGI("[CloudSyncer] finished taskId %" PRIu64 " errCode %d", info.taskId, info.errCode); } storageProxy_->Close(); + WaitAllSyncCallbackTaskFinish(); +} + +CloudSyncer::ProcessNotifier::ProcessNotifier(CloudSyncer *syncer) + : syncer_(syncer) +{ + RefObject::IncObjRef(syncer_); +} + +CloudSyncer::ProcessNotifier::~ProcessNotifier() +{ + RefObject::DecObjRef(syncer_); } void CloudSyncer::ProcessNotifier::Init(const std::vector &tableName, @@ -182,8 +194,16 @@ void CloudSyncer::ProcessNotifier::NotifyProcess(const CloudTaskInfo &taskInfo, if (!callback) { return; } - int errCode = RuntimeContext::GetInstance()->ScheduleTask([callback, currentProcess]() { + CloudSyncer *syncer = syncer_; + if (syncer == nullptr) { + return; // should not happen + } + RefObject::IncObjRef(syncer); + syncer->IncSyncCallbackTaskCount(); + int errCode = RuntimeContext::GetInstance()->ScheduleTask([callback, currentProcess, syncer]() { callback(currentProcess); + syncer->DecSyncCallbackTaskCount(); + RefObject::DecObjRef(syncer); LOGD("[ProcessNotifier] notify process finish"); }); if (errCode != E_OK) { @@ -218,7 +238,6 @@ void CloudSyncer::DoSyncIfNeed() if (closed_) { return; } - std::lock_guard lock(syncMutex_); // get taskId from queue TaskId triggerTaskId; { @@ -242,6 +261,7 @@ void CloudSyncer::DoSyncIfNeed() int CloudSyncer::DoSync(TaskId taskId) { + std::lock_guard lock(syncMutex_); CloudTaskInfo taskInfo; { std::lock_guard autoLock(queueLock_); @@ -264,27 +284,9 @@ int CloudSyncer::DoSync(TaskId taskId) return errCode; } -int CloudSyncer::DoSyncInner(const CloudTaskInfo &taskInfo, const bool &needUpload) +int CloudSyncer::DoUploadInNeed(const CloudTaskInfo &taskInfo, const bool needUpload) { int errCode = E_OK; - for (size_t i = 0; i < taskInfo.table.size(); ++i) { - LOGD("[CloudSyncer] try download table, index: %zu", i + 1); - errCode = CheckTaskIdValid(taskInfo.taskId); - if (errCode != E_OK) { - LOGE("[CloudSyncer] task is invalid, abort sync"); - return errCode; - } - { - std::lock_guard autoLock(contextLock_); - currentContext_.tableName = taskInfo.table[i]; - } - errCode = DoDownload(taskInfo.taskId); - if (errCode != E_OK) { - LOGE("[CloudSyncer] download failed %d", errCode); - return errCode; - } - } - if (needUpload) { errCode = storageProxy_->StartTransaction(); if (errCode != E_OK) { @@ -307,6 +309,11 @@ int CloudSyncer::DoSyncInner(const CloudTaskInfo &taskInfo, const bool &needUplo LOGE("[CloudSyncer] upload failed %d", errCode); break; } + errCode = SaveCloudWaterMark(taskInfo.table[i]); + if (errCode != E_OK) { + LOGE("[CloudSyncer] Can not save cloud water mark after uploading %d", errCode); + return errCode; + } } if (errCode == E_OK) { storageProxy_->Commit(); @@ -317,8 +324,43 @@ int CloudSyncer::DoSyncInner(const CloudTaskInfo &taskInfo, const bool &needUplo return errCode; } +int CloudSyncer::DoSyncInner(const CloudTaskInfo &taskInfo, const bool needUpload) +{ + int errCode = E_OK; + for (size_t i = 0; i < taskInfo.table.size(); ++i) { + LOGD("[CloudSyncer] try download table, index: %zu", i + 1); + errCode = CheckTaskIdValid(taskInfo.taskId); + if (errCode != E_OK) { + LOGE("[CloudSyncer] task is invalid, abort sync"); + return errCode; + } + { + std::lock_guard autoLock(contextLock_); + currentContext_.tableName = taskInfo.table[i]; + } + errCode = DoDownload(taskInfo.taskId); + if (errCode != E_OK) { + LOGE("[CloudSyncer] download failed %d", errCode); + return errCode; + } + if (!needUpload) { + errCode = SaveCloudWaterMark(taskInfo.table[i]); + if (errCode != E_OK) { + LOGE("[CloudSyncer] Can not save cloud water mark after downloading %d", errCode); + return errCode; + } + } + } + + return DoUploadInNeed(taskInfo, needUpload); +} + void CloudSyncer::DoFinished(TaskId taskId, int errCode, const InnerProcessInfo &processInfo) { + { + std::lock_guard autoLock(queueLock_); + taskQueue_.remove(taskId); + } std::shared_ptr notifier = nullptr; { // check current task is running or not @@ -364,26 +406,26 @@ static int GetCloudPkVals(VBucket &datum, const std::vector &pkColN std::vector &cloudPkVals) { if (!cloudPkVals.empty()) { - LOGE("Output paramater should be empty"); + LOGE("[CloudSyncer] Output paramater should be empty"); return -E_INVALID_ARGS; } if (pkColNames.size() == 1 && pkColNames[0] == CloudDbConstant::ROW_ID_FIELD_NAME) { // if data don't have primary key, then use rowID as value - cloudPkVals.emplace_back(std::move(dataKey)); + cloudPkVals.push_back(dataKey); return E_OK; } for (const auto &pkColName : pkColNames) { auto iter = datum.find(pkColName); if (iter == datum.end()) { - LOGE("Cloud data do not contain expected primary field value"); + LOGE("[CloudSyncer] Cloud data do not contain expected primary field value"); return -E_CLOUD_ERROR; } - cloudPkVals.push_back(datum[pkColName]); + cloudPkVals.push_back(iter->second); } return E_OK; } -static int SaveChangedtData(VBucket &datum, ChangedData &changedData, DataInfoWithLog &localInfo, ChangeType type) +static int SaveChangedDataByType(VBucket &datum, ChangedData &changedData, DataInfoWithLog &localInfo, ChangeType type) { int ret = E_OK; std::vector cloudPkVals; @@ -399,43 +441,41 @@ static int SaveChangedtData(VBucket &datum, ChangedData &changedData, DataInfoWi return E_OK; } -static bool shouldSaveData(const LogInfo &localLogInfo, const LogInfo &cloudLogInfo) +static bool NeedSaveData(const LogInfo &localLogInfo, const LogInfo &cloudLogInfo) { // if timeStamp, write timestamp, cloudGid are all the same, // we thought that the datum is mostly be the same between cloud and local // However, there are still slightly possibility that it may be created from different device, // So, during the strategy policy [i.e. TagSyncDataStatus], the datum was tagged as UPDATE // But we won't notify the datum - if (localLogInfo.timestamp == cloudLogInfo.timestamp && + bool isSame = localLogInfo.timestamp == cloudLogInfo.timestamp && localLogInfo.wTimestamp == cloudLogInfo.wTimestamp && - localLogInfo.cloudGid == cloudLogInfo.cloudGid) { - return false; - } - return true; + localLogInfo.cloudGid == cloudLogInfo.cloudGid; + return !isSame; } -int CloudSyncer::SaveChangedData(DownloadData &downloadData, int dataIndex, DataInfoWithLog &localInfo, - LogInfo &cloudLogInfo, ChangedData &changedData, std::vector &InsertDataNoPrimaryKeys) +int CloudSyncer::SaveChangedData(SyncParam ¶m, int dataIndex, DataInfo &dataInfo, + std::vector &InsertDataNoPrimaryKeys) { // For no primary key situation, - if (downloadData.opType[dataIndex] == OpType::INSERT && changedData.field.size() == 1 && - changedData.field[0] == CloudDbConstant::ROW_ID_FIELD_NAME) { + if (param.downloadData.opType[dataIndex] == OpType::INSERT && param.changedData.field.size() == 1 && + param.changedData.field[0] == CloudDbConstant::ROW_ID_FIELD_NAME) { InsertDataNoPrimaryKeys.push_back(dataIndex); return E_OK; } - switch (downloadData.opType[dataIndex]) { + switch (param.downloadData.opType[dataIndex]) { case OpType::INSERT: - return SaveChangedtData( - downloadData.data[dataIndex], changedData, localInfo, ChangeType::OP_INSERT); + return SaveChangedDataByType( + param.downloadData.data[dataIndex], param.changedData, dataInfo.localInfo, ChangeType::OP_INSERT); case OpType::UPDATE: - if (shouldSaveData(localInfo.logInfo, cloudLogInfo)) { - return SaveChangedtData( - downloadData.data[dataIndex], changedData, localInfo, ChangeType::OP_UPDATE); + if (NeedSaveData(dataInfo.localInfo.logInfo, dataInfo.cloudLogInfo)) { + return SaveChangedDataByType( + param.downloadData.data[dataIndex], param.changedData, dataInfo.localInfo, ChangeType::OP_UPDATE); } break; case OpType::DELETE: - return SaveChangedtData( - downloadData.data[dataIndex], changedData, localInfo, ChangeType::OP_DELETE); + return SaveChangedDataByType( + param.downloadData.data[dataIndex], param.changedData, dataInfo.localInfo, ChangeType::OP_DELETE); default: break; } @@ -458,7 +498,9 @@ static LogInfo GetCloudLogInfo(VBucket &datum) cloudLogInfo.cloudGid = std::get(datum[CloudDbConstant::GID_FIELD]); return cloudLogInfo; } - +/** + * UpdateChangedData will be used for Insert case, which we can only get rowid after we saved data in db. +*/ static void UpdateChangedData( DownloadData &downloadData, const std::vector &InsertDataNoPrimaryKeys, ChangedData &changedData) { @@ -473,28 +515,42 @@ static void UpdateChangedData( static void TagAsset(AssetOpType flag, AssetStatus status, Asset &asset, Assets &res) { - asset.flag = static_cast(flag); + if (asset.status == static_cast(AssetStatus::DELETE)) { + asset.flag = static_cast(AssetOpType::DELETE); + } else { + asset.flag = static_cast(flag); + } asset.status = static_cast(status); Timestamp timestamp; OS::GetCurrentSysTimeInMicrosecond(timestamp); - asset.timestamp = timestamp / CloudDbConstant::TEN_THOUSAND; + asset.timestamp = static_cast(timestamp / CloudDbConstant::TEN_THOUSAND); res.push_back(asset); } -static void TagAssets(AssetOpType flag, AssetStatus status, Assets &assets, Assets &res) +static void TagAssetWithNormalStatus(const bool isNormalStatus, AssetOpType flag, Asset &asset, Assets &res) +{ + if (isNormalStatus) { + TagAsset(flag, AssetStatus::NORMAL, asset, res); + return; + } + TagAsset(flag, AssetStatus::DOWNLOADING, asset, res); +} + +static void TagAssetsWithNormalStatus(const bool isNormalStatus, AssetOpType flag, Assets &assets, Assets &res) { for (Asset &asset : assets) { - TagAsset(flag, status, asset, res); + TagAssetWithNormalStatus(isNormalStatus, flag, asset, res); } } template -static bool IsDataContainField(const std::string &assetFieldName, VBucket &data) +static bool IsDataContainField(const std::string &assetFieldName, const VBucket &data) { auto assetIter = data.find(assetFieldName); if (assetIter == data.end()) { return false; } + // When type of Assets is not Nil but a vector which size is 0, we think data is not contain this field. if (assetIter->second.index() == TYPE_INDEX) { if (std::get(assetIter->second).empty()) { return false; @@ -506,8 +562,9 @@ static bool IsDataContainField(const std::string &assetFieldName, VBucket &data) return true; } -// AssetOpType and AssetStatus will be tagged, assets to be changed will be returned -static Assets TagAsset(const std::string &assetFieldName, VBucket &coveredData, VBucket &beCoveredData) +// AssetOpType and AssetStatus will be tagged, assets to be changed will be returned +static Assets TagAsset(const std::string &assetFieldName, VBucket &coveredData, VBucket &beCoveredData, + bool setNormalStatus) { Assets res = {}; bool beCoveredHasAsset = IsDataContainField(assetFieldName, beCoveredData) || @@ -515,15 +572,22 @@ static Assets TagAsset(const std::string &assetFieldName, VBucket &coveredData, bool coveredHasAsset = IsDataContainField(assetFieldName, coveredData); if (!beCoveredHasAsset) { if (!coveredHasAsset) { - LOGD("Both data do not contain certain asset field"); + LOGD("[CloudSyncer] Both data do not contain certain asset field"); return res; } - LOGD("coveredData will be regarded as insert"); - TagAsset(AssetOpType::INSERT, AssetStatus::DOWNLOADING, std::get(coveredData[assetFieldName]), res); + TagAssetWithNormalStatus( + setNormalStatus, AssetOpType::INSERT, std::get(coveredData[assetFieldName]), res); return res; } if (!coveredHasAsset) { - TagAsset(AssetOpType::DELETE, AssetStatus::DOWNLOADING, std::get(beCoveredData[assetFieldName]), res); + if (beCoveredData[assetFieldName].index() == TYPE_INDEX) { + TagAssetWithNormalStatus(setNormalStatus, AssetOpType::DELETE, + std::get(beCoveredData[assetFieldName]), res); + } + if (beCoveredData[assetFieldName].index() == TYPE_INDEX) { + TagAssetsWithNormalStatus(setNormalStatus, AssetOpType::DELETE, + std::get(beCoveredData[assetFieldName]), res); + } return res; } Asset &covered = std::get(coveredData[assetFieldName]); @@ -539,29 +603,20 @@ static Assets TagAsset(const std::string &assetFieldName, VBucket &coveredData, beCovered = beCoveredDataInAssets[0]; } if (covered.name != beCovered.name) { - TagAsset(AssetOpType::INSERT, AssetStatus::DOWNLOADING, covered, res); - TagAsset(AssetOpType::DELETE, AssetStatus::DOWNLOADING, beCovered, res); + TagAssetWithNormalStatus(setNormalStatus, AssetOpType::INSERT, covered, res); + TagAssetWithNormalStatus(setNormalStatus, AssetOpType::DELETE, beCovered, res); return res; } if (covered.hash != beCovered.hash) { - TagAsset(AssetOpType::UPDATE, AssetStatus::DOWNLOADING, covered, res); + TagAssetWithNormalStatus(setNormalStatus, AssetOpType::UPDATE, covered, res); } return res; } -static std::unordered_map GenAssetsMap(Assets &assets) -{ - std::unordered_map assetsMap; - for (size_t i = 0; i < assets.size(); i++) { - assetsMap[assets[i].name] = i; - } - return assetsMap; -} - // AssetOpType and AssetStatus will be tagged, assets to be changed will be returned // use VBucket rather than Type because we need to check whether it is empty static Assets TagAssets(const std::string &assetFieldName, VBucket &coveredData, VBucket &beCoveredData, - bool WriteToCoveredData) + bool setNormalStatus) { Assets res = {}; bool beCoveredHasAssets = IsDataContainField(assetFieldName, beCoveredData); @@ -571,57 +626,97 @@ static Assets TagAssets(const std::string &assetFieldName, VBucket &coveredData, return res; } // all the element in assets will be set to INSERT - TagAssets(AssetOpType::INSERT, AssetStatus::DOWNLOADING, std::get(coveredData[assetFieldName]), res); + TagAssetsWithNormalStatus(setNormalStatus, + AssetOpType::INSERT, std::get(coveredData[assetFieldName]), res); return res; } if (!coveredHasAssets) { // all the element in assets will be set to DELETE - TagAssets(AssetOpType::DELETE, AssetStatus::DOWNLOADING, std::get(beCoveredData[assetFieldName]), res); - if (WriteToCoveredData) { - LOGD("Write assets to be deleted from beCoveredData to CoveredData"); - coveredData[assetFieldName] = res; - } + TagAssetsWithNormalStatus(setNormalStatus, + AssetOpType::DELETE, std::get(beCoveredData[assetFieldName]), res); + coveredData[assetFieldName] = res; return res; } Assets &covered = std::get(coveredData[assetFieldName]); Assets &beCovered = std::get(beCoveredData[assetFieldName]); - std::unordered_map CoveredAssetsMap = GenAssetsMap(covered); + std::map coveredAssetsIndexMap = CloudStorageUtils::GenAssetsIndexMap(covered); for (Asset &beCoveredAsset : beCovered) { - auto it = CoveredAssetsMap.find(beCoveredAsset.name); - if (it == CoveredAssetsMap.end()) { - TagAsset(AssetOpType::DELETE, AssetStatus::DOWNLOADING, beCoveredAsset, res); - if (WriteToCoveredData) { - std::get(coveredData[assetFieldName]).push_back(beCoveredAsset); - } + auto it = coveredAssetsIndexMap.find(beCoveredAsset.name); + if (it == coveredAssetsIndexMap.end()) { + TagAssetWithNormalStatus(setNormalStatus, AssetOpType::DELETE, beCoveredAsset, res); + std::get(coveredData[assetFieldName]).push_back(beCoveredAsset); continue; } Asset &coveredAsset = covered[it->second]; if (beCoveredAsset.hash != coveredAsset.hash) { - TagAsset(AssetOpType::UPDATE, AssetStatus::DOWNLOADING, coveredAsset, res); + TagAssetWithNormalStatus(setNormalStatus, AssetOpType::UPDATE, coveredAsset, res); + } else { + res.push_back(coveredAsset); } // Erase element which has been handled, remaining element will be set to Insert - CoveredAssetsMap.erase(it); - // flag in Asset is defaultly set to NoChange, so we just continue - continue; + coveredAssetsIndexMap.erase(it); + // flag in Asset is defaultly set to NoChange, so we just go to next iteration } - for (auto &noHandledAssetKvPair : CoveredAssetsMap) { - TagAsset(AssetOpType::INSERT, AssetStatus::DOWNLOADING, covered[noHandledAssetKvPair.second], res); + for (const auto &noHandledAssetKvPair : coveredAssetsIndexMap) { + TagAssetWithNormalStatus(setNormalStatus, AssetOpType::INSERT, covered[noHandledAssetKvPair.second], res); } return res; } -bool CloudSyncer::ShouldProcessAssets() +bool CloudSyncer::IsDataContainDuplicateAsset(const std::vector &assetFields, VBucket &data) +{ + for (auto &assetField : assetFields) { + if (assetField.type == TYPE_INDEX && data[assetField.colName].index() == TYPE_INDEX) { + if (CloudStorageUtils::IsAssetsContainDuplicateAsset(std::get(data[assetField.colName]))) { + return true; + } + } + } + return false; +} + +bool CloudSyncer::IsDataContainAssets() { std::lock_guard autoLock(contextLock_); - if (currentContext_.assetFields[currentContext_.tableName].empty()) { - LOGI("Current table do not contain assets, thereby we needn't download assets"); + bool hasTable = (currentContext_.assetFields.find(currentContext_.tableName) != currentContext_.assetFields.end()); + if (!hasTable) { + LOGE("[CloudSyncer] failed to get assetFields, because tablename doesn't exit in currentContext, %d.", + -E_INTERNAL_ERROR); + } + if (hasTable && currentContext_.assetFields[currentContext_.tableName].empty()) { + LOGI("[CloudSyncer] Current table do not contain assets, thereby we needn't download assets"); return false; } return true; } -std::map CloudSyncer::TagAssetsInSingleRecord(VBucket &CoveredData, VBucket &BeCoveredData, - bool WriteToCoveredData) +void CloudSyncer::IncSyncCallbackTaskCount() +{ + std::lock_guard autoLock(syncCallbackMutex_); + syncCallbackCount_++; +} + +void CloudSyncer::DecSyncCallbackTaskCount() +{ + { + std::lock_guard autoLock(syncCallbackMutex_); + syncCallbackCount_--; + } + syncCallbackCv_.notify_all(); +} + +void CloudSyncer::WaitAllSyncCallbackTaskFinish() +{ + std::unique_lock uniqueLock(syncCallbackMutex_); + LOGD("[CloudSyncer] Begin wait all callback task finish"); + syncCallbackCv_.wait(uniqueLock, [this]() { + return syncCallbackCount_ <= 0; + }); + LOGD("[CloudSyncer] End wait all callback task finish"); +} + +std::map CloudSyncer::TagAssetsInSingleRecord(VBucket &coveredData, VBucket &beCoveredData, + bool setNormalStatus) { // Define a map to store the result std::map res = {}; @@ -632,27 +727,30 @@ std::map CloudSyncer::TagAssetsInSingleRecord(VBucket &Cove } // For every column contain asset or assets, assetFields are in context for (const Field &assetField : assetFields) { - res[assetField.colName] = TagAssetsInSingleCol(CoveredData, BeCoveredData, assetField, WriteToCoveredData); + Assets assets = TagAssetsInSingleCol(coveredData, beCoveredData, assetField, setNormalStatus); + if (!assets.empty()) { + res[assetField.colName] = assets; + } } return res; } Assets CloudSyncer::TagAssetsInSingleCol( - VBucket &CoveredData, VBucket &BeCoveredData, const Field &assetField, bool WriteToCoveredData) -{ + VBucket &coveredData, VBucket &beCoveredData, const Field &assetField, bool setNormalStatus) +{ // Define a list to store the tagged result Assets assets = {}; switch (assetField.type) { case TYPE_INDEX: { - assets = TagAssets(assetField.colName, CoveredData, BeCoveredData, WriteToCoveredData); + assets = TagAssets(assetField.colName, coveredData, beCoveredData, setNormalStatus); break; } case TYPE_INDEX: { - assets = TagAsset(assetField.colName, CoveredData, BeCoveredData); + assets = TagAsset(assetField.colName, coveredData, beCoveredData, setNormalStatus); break; } default: - LOGW("Meet an unexpected type %d", assetField.type); + LOGW("[CloudSyncer] Meet an unexpected type %d", assetField.type); break; } return assets; @@ -677,7 +775,7 @@ int CloudSyncer::FillCloudAssets( return E_OK; } -int CloudSyncer::HandleDownloadResult(const std::string &tableName, std::string gid, +int CloudSyncer::HandleDownloadResult(const std::string &tableName, const std::string &gid, std::map &DownloadResult, bool setAllNormal) { VBucket normalAssets; @@ -699,7 +797,7 @@ int CloudSyncer::HandleDownloadResult(const std::string &tableName, std::string failedAssetsList.push_back(asset); } if (static_cast(asset.status) == AssetStatus::DOWNLOADING) { - LOGW("Asset status should not be DOWNLOADING after download operation"); + LOGW("[CloudSyncer] Asset status should not be DOWNLOADING after download operation"); } } if (!normalAssetsList.empty()) { @@ -729,42 +827,58 @@ static ChangeType OpTypeToChangeType(OpType strategy) int CloudSyncer::CloudDbDownloadAssets(InnerProcessInfo &info, DownloadList &downloadList, bool willHandleResult, ChangedData &changedAssets) { - for (auto &assetsDownloadInfo : downloadList) { - std::string gid = std::get<0>(assetsDownloadInfo); - Type primaryKey = std::get<1>(assetsDownloadInfo); - OpType strategy = std::get<2>(assetsDownloadInfo); - std::map assets = std::get<3>(assetsDownloadInfo); + int downloadStatus = E_OK; + for (size_t i = 0; i < downloadList.size(); i++) { + std::string gid = std::get<0>(downloadList[i]); // 0 means gid is the first element in assetsInfo + Type primaryKey = std::get<1>(downloadList[i]); // 1 means primaryKey is the second element in assetsInfo + OpType strategy = std::get<2>(downloadList[i]); // 2 means strategy is the third element in assetsInfo + // 3 means assets info [colName, assets] is the forth element in downloadList[i] + std::map assets = std::get<3>(downloadList[i]); + std::map downloadAssets(assets); + CloudStorageUtils::EraseNoChangeAsset(downloadAssets); // Download data (include deleting) - int errorCode = cloudDB_.Download(info.tableName, gid, primaryKey, assets); - if (!willHandleResult || assets.empty()) { + if (downloadAssets.empty()) { continue; } + int errorCode = cloudDB_.Download(info.tableName, gid, primaryKey, downloadAssets); + if (errorCode == -E_NOT_SET) { + info.downLoadInfo.failCount += (downloadList.size() - i); + info.downLoadInfo.successCount -= (downloadList.size() - i); + return -E_NOT_SET; + } + changedAssets.primaryData[OpTypeToChangeType(strategy)].push_back({primaryKey}); + if (!willHandleResult) { + continue; + } + CloudStorageUtils::MergeDownloadAsset(downloadAssets, assets); // Process result of each asset if (errorCode != E_OK) { // if not OK, update process info and handle download result seperately - info.downLoadInfo.failCount++; - info.downLoadInfo.successCount--; int ret = HandleDownloadResult(info.tableName, gid, assets, false); if (ret != E_OK) { + info.downLoadInfo.failCount += (downloadList.size() - i); + info.downLoadInfo.successCount -= (downloadList.size() - i); return ret; } + downloadStatus = downloadStatus == E_OK ? errorCode : downloadStatus; + info.downLoadInfo.failCount++; + info.downLoadInfo.successCount--; continue; } - // if success, update ChangedData && Write every attribute of asset into database - // All status will be set to NORMAL(0) - changedAssets.primaryData[OpTypeToChangeType(strategy)].push_back({primaryKey}); int ret = HandleDownloadResult(info.tableName, gid, assets, true); if (ret != E_OK) { + info.downLoadInfo.failCount += (downloadList.size() - i); + info.downLoadInfo.successCount -= (downloadList.size() - i); return ret; } } - return E_OK; + return downloadStatus; } -int CloudSyncer::DownloadNotifyAssets(InnerProcessInfo &info, std::vector &pKColNames, +int CloudSyncer::DownloadAssets(InnerProcessInfo &info, const std::vector &pKColNames, ChangedData &changedAssets) { - if (!ShouldProcessAssets()) { + if (!IsDataContainAssets()) { return E_OK; } // update changed data info @@ -786,16 +900,13 @@ int CloudSyncer::DownloadNotifyAssets(InnerProcessInfo &info, std::vector CloudSyncer::GetAssetsFromVBucket(VBucket &data) return assets; } -static bool IsCompositeKey(std::vector &pKColNames) +static bool IsCompositeKey(const std::vector &pKColNames) { - if (pKColNames.empty()) { - return false; - } - if (pKColNames.size() > 1) { - return true; - } - return false; + return (pKColNames.size() > 1); } -static bool IsNoPrimaryKey(std::vector &pKColNames) +static bool IsNoPrimaryKey(const std::vector &pKColNames) { if (pKColNames.empty()) { return true; @@ -846,7 +951,7 @@ static bool IsNoPrimaryKey(std::vector &pKColNames) return false; } -static bool IsSinglePrimaryKey(std::vector &pKColNames) +static bool IsSinglePrimaryKey(const std::vector &pKColNames) { if (IsCompositeKey(pKColNames) || IsNoPrimaryKey(pKColNames)) { return false; @@ -854,133 +959,166 @@ static bool IsSinglePrimaryKey(std::vector &pKColNames) return true; } -void CloudSyncer::TagStatus(bool isExist, const TableName &tableName, size_t idx, DownloadData &downloadData, - std::vector &pKColNames, DataInfoWithLog &localInfo, LogInfo &cloudLogInfo, VBucket &localAssetInfo, - AssetDownloadList &assetsDownloadList) +static int GetSinglePk(VBucket &datum, const std::vector &pkColNames, int64_t dataKey, Type &pkVal) { - OpType strategy = - currentContext_.strategy->TagSyncDataStatus(isExist, localInfo.logInfo, cloudLogInfo); - downloadData.opType[idx] = strategy; - if (!ShouldProcessAssets()) { - return; - } - std::map assetsMap; - Type prefix; - std::vector pKVals; + std::vector pkVals; int ret = E_OK; - if (IsSinglePrimaryKey(pKColNames)) { - if (strategy == OpType::DELETE) { - ret = GetCloudPkVals(localInfo.primaryKeys, pKColNames, localInfo.logInfo.dataKey, pKVals); - } else { - ret = GetCloudPkVals(downloadData.data[idx], pKColNames, localInfo.logInfo.dataKey, pKVals); + if (IsSinglePrimaryKey(pkColNames)) { + ret = GetCloudPkVals(datum, pkColNames, dataKey, pkVals); + if (ret != E_OK) { + LOGE("[CloudSyncer] Cannot get single primary key for the datum %d", ret); + return ret; + } + pkVal = pkVals[0]; + if (pkVal.index() == TYPE_INDEX) { + LOGE("[CloudSyncer] Invalid primary key type in TagStatus, it's Nil."); + return -E_INTERNAL_ERROR; } - prefix = pKVals[0]; } - switch (strategy) + return E_OK; +} + +int CloudSyncer::TagStatus(bool isExist, SyncParam ¶m, size_t idx, DataInfo &dataInfo, VBucket &localAssetInfo) +{ + OpType strategyOpResult = OpType::NOT_HANDLE; { + std::lock_guard autoLock(contextLock_); + if (!currentContext_.strategy) { + LOGE("[CloudSyncer] strategy has not been set when tag status, %d.", -E_INTERNAL_ERROR); + return -E_INTERNAL_ERROR; + } + strategyOpResult = + currentContext_.strategy->TagSyncDataStatus(isExist, dataInfo.localInfo.logInfo, dataInfo.cloudLogInfo); + } + param.downloadData.opType[idx] = strategyOpResult; + if (!IsDataContainAssets()) { + return E_OK; + } + return TagDownloadAssets(idx, param, dataInfo, localAssetInfo); +} + +int CloudSyncer::TagDownloadAssets(size_t idx, SyncParam ¶m, DataInfo &dataInfo, VBucket &localAssetInfo) +{ + Type prefix; + int ret = E_OK; + OpType strategy = param.downloadData.opType[idx]; + std::map assetsMap; + switch (strategy) { case OpType::INSERT: case OpType::UPDATE: - assetsMap = TagAssetsInSingleRecord(downloadData.data[idx], localAssetInfo, false); - assetsDownloadList.downloadList.push_back( - std::make_tuple(cloudLogInfo.cloudGid, prefix, strategy, assetsMap)); + assetsMap = TagAssetsInSingleRecord(param.downloadData.data[idx], localAssetInfo, false); + ret = GetSinglePk(param.downloadData.data[idx], param.pkColNames, + dataInfo.localInfo.logInfo.dataKey, prefix); + if (ret != E_OK) { + LOGE("Can not get single primary key while strategy is UPDATE/INSERT in TagDownloadAssets %d", ret); + return ret; + } + param.assetsDownloadList.downloadList.push_back( + std::make_tuple(dataInfo.cloudLogInfo.cloudGid, prefix, strategy, assetsMap)); break; case OpType::DELETE: - assetsMap = TagAssetsInSingleRecord(downloadData.data[idx], localAssetInfo, false); - assetsDownloadList.completeDownloadList.push_back( - std::make_tuple(cloudLogInfo.cloudGid, prefix, strategy, assetsMap)); + assetsMap = TagAssetsInSingleRecord(param.downloadData.data[idx], localAssetInfo, false); + ret = GetSinglePk(dataInfo.localInfo.primaryKeys, param.pkColNames, + dataInfo.localInfo.logInfo.dataKey, prefix); + if (ret != E_OK) { + LOGE("Can not get single primary key while strategy is DELETE in TagDownloadAssets %d", ret); + return ret; + } + param.assetsDownloadList.completeDownloadList.push_back( + std::make_tuple(dataInfo.cloudLogInfo.cloudGid, prefix, strategy, assetsMap)); break; case OpType::NOT_HANDLE: case OpType::ONLY_UPDATE_GID: - case OpType::SET_CLOUD_FORCE_PUSH_FLAG_ZERO: {// means upload need this data + case OpType::SET_CLOUD_FORCE_PUSH_FLAG_ZERO: { // means upload need this data // Save the asset info into context - assetsMap = GetAssetsFromVBucket(downloadData.data[idx]); - if (!assetsMap.empty()) { - { - std::lock_guard autoLock(contextLock_); - if (currentContext_.assetsInfo.find(tableName) == currentContext_.assetsInfo.end()) { - currentContext_.assetsInfo[tableName] = {}; - } - currentContext_.assetsInfo[tableName][cloudLogInfo.cloudGid] = assetsMap; + assetsMap = GetAssetsFromVBucket(param.downloadData.data[idx]); + { + std::lock_guard autoLock(contextLock_); + if (currentContext_.assetsInfo.find(param.tableName) == currentContext_.assetsInfo.end()) { + currentContext_.assetsInfo[param.tableName] = {}; } + currentContext_.assetsInfo[param.tableName][dataInfo.cloudLogInfo.cloudGid] = assetsMap; } break; } default: break; } - return; + return E_OK; } -int CloudSyncer::SaveDatum(const std::string &tableName, size_t idx, DownloadData &downloadData, - AssetDownloadList &assetsDownloadList, ChangedData &changedData, std::vector &InsertDataNoPrimaryKeys) +int CloudSyncer::SaveDatum(SyncParam ¶m, size_t idx, std::vector &InsertDataNoPrimaryKeys) { - int ret = CheckDownloadDatum(downloadData.data[idx]); + int ret = CheckDownloadDatum(param.downloadData.data[idx]); if (ret != E_OK) { LOGE("[CloudSyncer] Invalid download data:%d", ret); return ret; } - ModifyCloudDataTime(downloadData.data[idx]); - DataInfoWithLog localInfo; + ModifyCloudDataTime(param.downloadData.data[idx]); + DataInfo dataInfo; VBucket localAssetInfo; bool isExist = true; - ret = storageProxy_->GetInfoByPrimaryKeyOrGid(tableName, downloadData.data[idx], localInfo, localAssetInfo); + ret = storageProxy_->GetInfoByPrimaryKeyOrGid(param.tableName, param.downloadData.data[idx], dataInfo.localInfo, + localAssetInfo); if (ret == -E_NOT_FOUND) { isExist = false; } else if (ret != E_OK) { - LOGE("[CloudSyncer] Cannot get cloud water level from cloud meta data: %d.", ret); + LOGE("[CloudSyncer] Cannot get info by primary key or gid: %d.", ret); return ret; } // Get cloudLogInfo from cloud data - LogInfo cloudLogInfo = GetCloudLogInfo(downloadData.data[idx]); + dataInfo.cloudLogInfo = GetCloudLogInfo(param.downloadData.data[idx]); // Tag datum to get opType - TagStatus(isExist, tableName, idx, downloadData, changedData.field, localInfo, cloudLogInfo, localAssetInfo, - assetsDownloadList); - ret = SaveChangedData(downloadData, idx, localInfo, cloudLogInfo, changedData, InsertDataNoPrimaryKeys); + ret = TagStatus(isExist, param, idx, dataInfo, localAssetInfo); if (ret != E_OK) { - LOGE("[CloudSyncer] Cannot save changed data: %d.", ret); + LOGE("[CloudSyncer] Cannot tag status: %d.", ret); return ret; } - return E_OK; + ret = SaveChangedData(param, idx, dataInfo, InsertDataNoPrimaryKeys); + if (ret != E_OK) { + LOGE("[CloudSyncer] Cannot save changed data: %d.", ret); + } + return ret; } -int CloudSyncer::SaveData(const TableName &tableName, DownloadData &downloadData, - Info &downloadInfo, CloudWaterMark &latestCloudWaterMark, ChangedData &changedData) +int CloudSyncer::SaveData(SyncParam ¶m) { - if (!IsChngDataEmpty(changedData)) { - // changedData.primaryData should have no member inside + if (!IsChngDataEmpty(param.changedData)) { + LOGE("[CloudSyncer] changedData.primaryData should have no member inside."); return -E_INVALID_ARGS; } // Update download btach Info - downloadInfo.batchIndex += 1; - downloadInfo.total += downloadData.data.size(); + param.info.downLoadInfo.batchIndex += 1; + param.info.downLoadInfo.total += param.downloadData.data.size(); int ret = E_OK; std::vector InsertDataNoPrimaryKeys; AssetDownloadList assetsDownloadList; - for (size_t i = 0; i < downloadData.data.size(); i++) { - ret = SaveDatum(tableName, i, downloadData, assetsDownloadList, changedData, InsertDataNoPrimaryKeys); + param.assetsDownloadList = assetsDownloadList; + for (size_t i = 0; i < param.downloadData.data.size(); i++) { + ret = SaveDatum(param, i, InsertDataNoPrimaryKeys); if (ret != E_OK) { - LOGE("Cannot save datum due to error code %d", ret); + LOGE("[CloudSyncer] Cannot save datum due to error code %d", ret); return ret; } } // Save assetsMap into current context { std::lock_guard autoLock(contextLock_); - currentContext_.assetDownloadList = assetsDownloadList; + currentContext_.assetDownloadList = param.assetsDownloadList; } // save the data to the database by batch - ret = storageProxy_->PutCloudSyncData(tableName, downloadData); + ret = storageProxy_->PutCloudSyncData(param.tableName, param.downloadData); if (ret != E_OK) { - downloadInfo.failCount += downloadData.data.size(); + param.info.downLoadInfo.failCount += param.downloadData.data.size(); LOGE("[CloudSyncer] Cannot save the data to databse with error code: %d.", ret); return ret; } - UpdateChangedData(downloadData, InsertDataNoPrimaryKeys, changedData); + UpdateChangedData(param.downloadData, InsertDataNoPrimaryKeys, param.changedData); // Update downloadInfo - downloadInfo.successCount += downloadData.data.size(); + param.info.downLoadInfo.successCount += param.downloadData.data.size(); // Get latest cloudWaterMark - VBucket &lastData = downloadData.data.back(); - latestCloudWaterMark = std::get(lastData[CloudDbConstant::CURSOR_FIELD]); + VBucket &lastData = param.downloadData.data.back(); + param.cloudWaterMark = std::get(lastData[CloudDbConstant::CURSOR_FIELD]); return E_OK; } @@ -999,12 +1137,12 @@ int CloudSyncer::PreCheck(CloudSyncer::TaskId &taskId, const TableName &tableNam } } if (currentContext_.strategy == nullptr) { - LOGE("Strategy has not been initialized"); + LOGE("[CloudSyncer] Strategy has not been initialized"); return -E_INVALID_ARGS; } ret = storageProxy_->CheckSchema(tableName); if (ret != E_OK) { - LOGE("A schema error occurred on the table to be synced, %d", ret); + LOGE("[CloudSyncer] A schema error occurred on the table to be synced, %d", ret); return ret; } return E_OK; @@ -1051,9 +1189,30 @@ int CloudSyncer::NotifyChangedData(ChangedData &&changedData) return ret; } -int CloudSyncer::SaveDataInTransaction(CloudSyncer::TaskId taskId, DownloadData &downloadData, - std::vector &pkColNames, InnerProcessInfo &info, CloudWaterMark &newCloudWaterMark, - ChangedData &changedData) +void CloudSyncer::NotifyInDownload(CloudSyncer::TaskId taskId, SyncParam ¶m) +{ + CloudTaskInfo taskInfo; + { + std::lock_guard autoLock(queueLock_); + taskInfo = cloudTaskInfos_[taskId]; + } + std::lock_guard autoLock(contextLock_); + + if (currentContext_.strategy->JudgeUpload()) { + currentContext_.notifier->NotifyProcess(taskInfo, param.info); + } else { + if (param.isLastBatch) { + param.info.tableStatus = ProcessStatus::FINISHED; + } + if (taskInfo.table.back() == param.tableName && param.isLastBatch) { + currentContext_.notifier->UpdateProcess(param.info); + } else { + currentContext_.notifier->NotifyProcess(taskInfo, param.info); + } + } +} + +int CloudSyncer::SaveDataInTransaction(CloudSyncer::TaskId taskId, SyncParam ¶m) { int ret = storageProxy_->StartTransaction(TransactType::IMMEDIATE); if (ret != E_OK) { @@ -1061,16 +1220,16 @@ int CloudSyncer::SaveDataInTransaction(CloudSyncer::TaskId taskId, DownloadData return ret; } if (!IsModeForcePush(taskId)) { - changedData.tableName = info.tableName; - changedData.field = pkColNames; - changedData.type = ChangedDataType::DATA; + param.changedData.tableName = param.info.tableName; + param.changedData.field = param.pkColNames; + param.changedData.type = ChangedDataType::DATA; } - ret = SaveData(info.tableName, downloadData, info.downLoadInfo, newCloudWaterMark, changedData); + ret = SaveData(param); if (ret != E_OK) { LOGE("[CloudSyncer] cannot save data: %d.", ret); { std::lock_guard autoLock(contextLock_); - currentContext_.notifier->UpdateProcess(info); + currentContext_.notifier->UpdateProcess(param.info); } int rollBackErrorCode = storageProxy_->Rollback(); if (rollBackErrorCode != E_OK) { @@ -1088,38 +1247,29 @@ int CloudSyncer::SaveDataInTransaction(CloudSyncer::TaskId taskId, DownloadData return E_OK; } -int CloudSyncer::SaveDataNotifyProcess(CloudSyncer::TaskId taskId, DownloadData &downloadData, - std::vector &pkColNames, InnerProcessInfo &info, CloudWaterMark &newCloudWaterMark) +int CloudSyncer::SaveDataNotifyProcess(CloudSyncer::TaskId taskId, SyncParam ¶m) { ChangedData changedData; - int ret = SaveDataInTransaction(taskId, downloadData, pkColNames, info, newCloudWaterMark, changedData); + param.changedData = changedData; + int ret = SaveDataInTransaction(taskId, param); if (ret != E_OK) { return ret; } // call OnChange to notify changedData object first time (without Assets) - ret = NotifyChangedData(std::move(changedData)); + ret = NotifyChangedData(std::move(param.changedData)); if (ret != E_OK) { - LOGE("Cannot notify changed data due to error %d", ret); + LOGE("[CloudSyncer] Cannot notify changed data due to error %d", ret); return ret; } // Begin dowloading assets ChangedData changedAssets; - ret = DownloadNotifyAssets(info, pkColNames, changedAssets); + ret = DownloadAssets(param.info, param.pkColNames, changedAssets); + (void)NotifyChangedData(std::move(changedAssets)); if (ret != E_OK) { - LOGE("Someting wrong happened during assets downloading due to error %d", ret); + LOGE("[CloudSyncer] Someting wrong happened during assets downloading due to error %d", ret); return ret; } - bool isUpdateCloudCursor = true; - { - std::lock_guard autoLock(queueLock_); - currentContext_.notifier->NotifyProcess(cloudTaskInfos_[taskId], info); - isUpdateCloudCursor = currentContext_.strategy->JudgeUpdateCursor(); - } - // use the cursor of the last datum in data set to update cloud water mark - if (isUpdateCloudCursor) { - std::lock_guard autoLock(contextLock_); - currentContext_.cloudWaterMarks[info.tableName] = newCloudWaterMark; - } + UpdateCloudWaterMark(param); return E_OK; } @@ -1141,18 +1291,15 @@ void CloudSyncer::NotifyInBatchUpload(const UploadParam &uploadParam, const Inne int CloudSyncer::DoDownload(CloudSyncer::TaskId taskId) { - TableName tableName; - int ret = GetCurrentTableName(tableName); + SyncParam param; + int ret = GetCurrentTableName(param.tableName); if (ret != E_OK) { LOGE("[CloudSyncer] Invalid table name for syncing: %d", ret); return ret; } - InnerProcessInfo info; - info.tableName = tableName; - - std::vector colNames; + param.info.tableName = param.tableName; std::vector assetFields; - ret = storageProxy_->GetPrimaryColNamesWithAssetsFields(tableName, colNames, assetFields); + ret = storageProxy_->GetPrimaryColNamesWithAssetsFields(param.tableName, param.pkColNames, assetFields); if (ret != E_OK) { LOGE("[CloudSyncer] Cannot get primary column names: %d", ret); return ret; @@ -1162,57 +1309,52 @@ int CloudSyncer::DoDownload(CloudSyncer::TaskId taskId) currentContext_.assetFields[currentContext_.tableName] = assetFields; } - CloudWaterMark cloudWaterMark; - ret = storageProxy_->GetCloudWaterMark(tableName, cloudWaterMark); + ret = storageProxy_->GetCloudWaterMark(param.tableName, param.cloudWaterMark); if (ret != E_OK) { LOGE("[CloudSyncer] Cannot get cloud water level from cloud meta data: %d.", ret); return ret; } - return DoDownloadInner(taskId, colNames, info, cloudWaterMark); + return DoDownloadInner(taskId, param); } -int CloudSyncer::DoDownloadInner(CloudSyncer::TaskId taskId, std::vector &colNames, - InnerProcessInfo &info, CloudWaterMark &cloudWaterMark) +int CloudSyncer::DoDownloadInner(CloudSyncer::TaskId taskId, SyncParam ¶m) { // Query data by batch until reaching end and not more data need to be download bool queryEnd = false; - uint32_t retryCnt = 0; - int ret = E_OK; + int ret = PreCheck(taskId, param.info.tableName); + if (ret != E_OK) { + return ret; + } while (!queryEnd) { - ret = PreCheck(taskId, info.tableName); - if (ret != E_OK) { - return ret; - } // Get cloud data after cloud water mark - info.tableStatus = ProcessStatus::PROCESSING; + param.info.tableStatus = ProcessStatus::PROCESSING; DownloadData downloadData; - ret = QueryCloudData(info.tableName, cloudWaterMark, downloadData); + param.downloadData = downloadData; + param.isLastBatch = false; + ret = QueryCloudData(param.info.tableName, param.cloudWaterMark, param.downloadData); if (ret == -E_QUERY_END) { // Won't break here since downloadData may not be null queryEnd = true; + param.isLastBatch = true; } else if (ret != E_OK) { return ret; } - if (downloadData.data.empty()) { - if (ret == E_OK && retryCnt >= CloudDbConstant::MAX_DOWNLOAD_RETRY_TIME) { - LOGE("Cloud Db send empty data but didn't return QUERY_END for too much time"); - return -E_CLOUD_ERROR; - } - if (ret == E_OK && retryCnt < CloudDbConstant::MAX_DOWNLOAD_RETRY_TIME) { - LOGW("Cloud Db return E_OK but send empty data, it should return QUERY_END, retry"); - retryCnt++; + if (param.downloadData.data.empty()) { + if (ret == E_OK) { + LOGD("[CloudSyncer] try to query cloud data use increment water mark"); + UpdateCloudWaterMark(param); continue; } - NotifyInEmptyDownload(taskId, info); + NotifyInEmptyDownload(taskId, param.info); break; } // Save data in transaction, update cloud water mark, notify process and changed data - ret = SaveDataNotifyProcess(taskId, downloadData, colNames, info, cloudWaterMark); + ret = SaveDataNotifyProcess(taskId, param); + (void)NotifyInDownload(taskId, param); if (ret != E_OK) { return ret; } - retryCnt = 0; } return E_OK; } @@ -1291,9 +1433,9 @@ int CloudSyncer::DoBatchUpload(CloudSyncData &uploadData, UploadParam &uploadPar return errCode; } // we need to fill back gid after insert data to cloud. - int ret = storageProxy_->FillCloudGid(uploadData); + int ret = storageProxy_->FillCloudGidAndAsset(OpType::INSERT, uploadData); if (ret != E_OK) { - LOGE("[CloudSyncer] Failed to fill back gid when doing upload, %d.", ret); + LOGE("[CloudSyncer] Failed to fill back when doing upload insData, %d.", ret); return ret; } innerProcessInfo.upLoadInfo.successCount += insertInfo.successCount; @@ -1305,9 +1447,9 @@ int CloudSyncer::DoBatchUpload(CloudSyncData &uploadData, UploadParam &uploadPar if (errCode != E_OK) { return errCode; } - errCode = storageProxy_->FillCloudAssetForUpload(uploadData); + errCode = storageProxy_->FillCloudGidAndAsset(OpType::UPDATE, uploadData); if (errCode != E_OK) { - LOGE("Cannot fill cloud asset during upload procedure"); + LOGE("[CloudSyncer] Failed to fill back when doing upload updData, %d.", errCode); return errCode; } innerProcessInfo.upLoadInfo.successCount += updateInfo.successCount; @@ -1340,21 +1482,7 @@ int CloudSyncer::PutWaterMarkAfterBatchUpload(const std::string &tableName, Uplo LOGE("[CloudSyncer] Cannot set local water mark while Uploading, %d.", errCode); return errCode; } - CloudWaterMark cloudWaterMark; - { - std::lock_guard autoLock(contextLock_); - auto it = currentContext_.cloudWaterMarks.find(tableName); - if (it == currentContext_.cloudWaterMarks.end()) { - LOGD("[CloudSyncer] Not found water mark just return"); - return E_OK; - } - cloudWaterMark = currentContext_.cloudWaterMarks[tableName]; - } - errCode = storageProxy_->PutCloudWaterMark(tableName, cloudWaterMark); - if (errCode != E_OK) { - LOGE("[CloudSyncer] Cannot set cloud water mark while Uploading, %d.", errCode); - } - return errCode; + return E_OK; } int CloudSyncer::DoUpload(CloudSyncer::TaskId taskId, bool lastTable) @@ -1416,7 +1544,8 @@ static AssetOpType StatusToFlag(AssetStatus status) { case AssetStatus::NORMAL: return AssetOpType::NO_CHANGE; default: - LOGW("Unexpected Situation and won't be handled, Caller should ensure that current situation won't occur"); + LOGW("[CloudSyncer] Unexpected Situation and won't be handled" + ", Caller should ensure that current situation won't occur"); return AssetOpType::NO_CHANGE; } } @@ -1424,6 +1553,7 @@ static AssetOpType StatusToFlag(AssetStatus status) { static void StatusToFlagForAsset(Asset &asset) { asset.flag = static_cast(StatusToFlag(static_cast(asset.status))); + asset.status = static_cast(AssetStatus::NORMAL); } static void StatusToFlagForAssets(Assets &assets) @@ -1447,7 +1577,7 @@ static void StatusToFlagForAssetsInRecord(const std::vector &fields, VBuc void CloudSyncer::TagUploadAssets(CloudSyncData &uploadData) { - if (!ShouldProcessAssets()) { + if (!IsDataContainAssets()) { return; } std::map> cloudAssets; @@ -1468,7 +1598,7 @@ void CloudSyncer::TagUploadAssets(CloudSyncData &uploadData) // But we need to check for safety auto gidIter = uploadData.updData.extend[i].find(CloudDbConstant::GID_FIELD); if (gidIter == uploadData.updData.extend[i].end()) { - LOGE("Datum to be upload must contain gid"); + LOGE("[CloudSyncer] Datum to be upload must contain gid"); return; } // update data must contain gid, however, we could only pull data after water mark @@ -1484,15 +1614,15 @@ void CloudSyncer::TagUploadAssets(CloudSyncData &uploadData) StatusToFlagForAssetsInRecord(assetFields, uploadData.updData.record[i]); continue; } - for (auto &it : cloudAssets[gid]) { + for (const auto &it : cloudAssets[gid]) { cloudAsset[it.first] = it.second; } (void)TagAssetsInSingleRecord(uploadData.updData.record[i], cloudAsset, true); } } -int CloudSyncer::PreProcessBatchUpload(TaskId taskId, CloudSyncData &uploadData, InnerProcessInfo &innerProcessInfo, - LocalWaterMark &localMark) +int CloudSyncer::PreProcessBatchUpload(TaskId taskId, const InnerProcessInfo &innerProcessInfo, + CloudSyncData &uploadData, LocalWaterMark &localMark) { // Precheck and calculate local water mark which would be updated if batch upload successed. int ret = CheckTaskIdValid(taskId); @@ -1515,6 +1645,24 @@ int CloudSyncer::PreProcessBatchUpload(TaskId taskId, CloudSyncData &uploadData, return ret; } +int CloudSyncer::SaveCloudWaterMark(const TableName &tableName) +{ + CloudWaterMark cloudWaterMark; + { + std::lock_guard autoLock(contextLock_); + if (currentContext_.cloudWaterMarks.find(tableName) == currentContext_.cloudWaterMarks.end()) { + LOGD("[CloudSyncer] Not found water mark just return"); + return E_OK; + } + cloudWaterMark = currentContext_.cloudWaterMarks[tableName]; + } + int errCode = storageProxy_->SetCloudWaterMark(tableName, cloudWaterMark); + if (errCode != E_OK) { + LOGE("[CloudSyncer] Cannot set cloud water mark while Uploading, %d.", errCode); + } + return errCode; +} + void CloudSyncer::SetUploadDataFlag(const TaskId taskId, CloudSyncData& uploadData) { std::lock_guard autoLock(queueLock_); @@ -1543,12 +1691,12 @@ int CloudSyncer::DoUploadInner(const std::string &tableName, UploadParam &upload InnerProcessInfo info; info.tableName = tableName; info.tableStatus = ProcessStatus::PROCESSING; - info.upLoadInfo.total = uploadParam.count; + info.upLoadInfo.total = static_cast(uploadParam.count); uint32_t batchIndex = 0; while (!CheckCloudSyncDataEmpty(uploadData)) { getDataUnfinished = (ret == -E_UNFINISHED); - ret = PreProcessBatchUpload(uploadParam.taskId, uploadData, info, uploadParam.localMark); + ret = PreProcessBatchUpload(uploadParam.taskId, info, uploadData, uploadParam.localMark); if (ret != E_OK) { goto RELEASE_EXIT; } @@ -1565,7 +1713,7 @@ int CloudSyncer::DoUploadInner(const std::string &tableName, UploadParam &upload goto RELEASE_EXIT; } - ClearCloudSyncData(uploadData); + uploadData = CloudSyncData(tableName); if (continueStmtToken == nullptr) { break; @@ -1588,26 +1736,34 @@ RELEASE_EXIT: int CloudSyncer::CheckDownloadDatum(VBucket &datum) { - if (datum.find(CloudDbConstant::GID_FIELD) == datum.end() || - datum.find(CloudDbConstant::CREATE_FIELD) == datum.end() || - datum.find(CloudDbConstant::MODIFY_FIELD) == datum.end() || - datum.find(CloudDbConstant::DELETE_FIELD) == datum.end() || - datum.find(CloudDbConstant::CURSOR_FIELD) == datum.end()) { - LOGE("Cloud data do not contain expected field"); + // type index of field in fields + std::vector> filedAndIndex = { + std::pair(CloudDbConstant::GID_FIELD, TYPE_INDEX), + std::pair(CloudDbConstant::CREATE_FIELD, TYPE_INDEX), + std::pair(CloudDbConstant::MODIFY_FIELD, TYPE_INDEX), + std::pair(CloudDbConstant::DELETE_FIELD, TYPE_INDEX), + std::pair(CloudDbConstant::CURSOR_FIELD, TYPE_INDEX) + }; + + for (size_t i = 0; i < filedAndIndex.size(); i++) { + if (datum.find(filedAndIndex[i].first) == datum.end()) { + LOGE("[CloudSyncer] Cloud data do not contain expected field: %s.", filedAndIndex[i].first.c_str()); return -E_CLOUD_ERROR; } - if (datum[CloudDbConstant::GID_FIELD].index() != TYPE_INDEX || - datum[CloudDbConstant::CREATE_FIELD].index() != TYPE_INDEX || - datum[CloudDbConstant::MODIFY_FIELD].index() != TYPE_INDEX || - datum[CloudDbConstant::DELETE_FIELD].index() != TYPE_INDEX || - datum[CloudDbConstant::CURSOR_FIELD].index() != TYPE_INDEX) { - LOGE("Cloud data do not contain expected type"); + if (datum[filedAndIndex[i].first].index() != static_cast(filedAndIndex[i].second)) { + LOGE("[CloudSyncer] Cloud data's field: %s, doesn't has expected type.", filedAndIndex[i].first.c_str()); return -E_CLOUD_ERROR; } + } + + std::lock_guard autoLock(contextLock_); + if (IsDataContainDuplicateAsset(currentContext_.assetFields[currentContext_.tableName], datum)) { + return -E_CLOUD_ERROR; + } return E_OK; } -int CloudSyncer::QueryCloudData(const std::string &tableName, const CloudWaterMark &cloudWaterMark, +int CloudSyncer::QueryCloudData(const std::string &tableName, CloudWaterMark &cloudWaterMark, DownloadData &downloadData) { VBucket extend = { @@ -1616,15 +1772,22 @@ int CloudSyncer::QueryCloudData(const std::string &tableName, const CloudWaterMa int ret = cloudDB_.Query(tableName, extend, downloadData.data); downloadData.opType.resize(downloadData.data.size()); if (ret == -E_QUERY_END) { - LOGI("[CloudSyncer] Download data from cloud database success and no more data need to be downloaded"); + LOGD("[CloudSyncer] Download data from cloud database success and no more data need to be downloaded"); return -E_QUERY_END; } - if (ret == E_OK) { - LOGI("[CloudSyncer] Download data from cloud database success but still has data to download"); - return E_OK; + if (ret == E_OK && downloadData.data.empty()) { + if (extend[CloudDbConstant::CURSOR_FIELD].index() != TYPE_INDEX) { + LOGE("[CloudSyncer] cursor type is not valid=%d", extend[CloudDbConstant::CURSOR_FIELD].index()); + return -E_CLOUD_ERROR; + } + cloudWaterMark = std::get(extend[CloudDbConstant::CURSOR_FIELD]); + LOGD("[CloudSyncer] Download data is empty, try to use other cursor=%s", cloudWaterMark.c_str()); + return ret; } - LOGE("[CloudSyncer] Download data from cloud database unsuccess %d", ret); - return -E_CLOUD_ERROR; + if (ret != E_OK) { + LOGE("[CloudSyncer] Download data from cloud database unsuccess %d", ret); + } + return ret; } int CloudSyncer::CheckParamValid(const std::vector &devices, SyncMode mode) @@ -1738,16 +1901,12 @@ int CloudSyncer::PrepareSync(TaskId taskId) return -E_DB_CLOSED; } currentContext_.currentTaskId = taskId; - currentContext_.notifier = std::make_shared(); + currentContext_.notifier = std::make_shared(this); currentContext_.strategy = StrategyFactory::BuildSyncStrategy(mode); currentContext_.notifier->Init(tableNames, devices); LOGI("[CloudSyncer] exec taskId %" PRIu64, taskId); } - // remove task id from queue std::lock_guard autoLock(queueLock_); - if (!taskQueue_.empty()) { - taskQueue_.pop_front(); - } cloudTaskInfos_[taskId].status = ProcessStatus::PROCESSING; return E_OK; } @@ -1891,14 +2050,14 @@ int CloudSyncer::CheckCloudSyncDataValid(CloudSyncData uploadData, const std::st (updRecordLen > 0 && updExtendLen > 0 && updRecordLen == updExtendLen) || (delRecordLen > 0 && delExtendLen > 0 && delRecordLen == delExtendLen)); if (!syncDataValid) { - LOGE("upload data is empty but upload count is not zero or upload table name" + LOGE("[CloudSyncer] upload data is empty but upload count is not zero or upload table name" " is not the same as table name of sync data."); return -E_INTERNAL_ERROR; } int64_t syncDataCount = static_cast(insRecordLen) + static_cast(updRecordLen) + static_cast(delRecordLen); if (syncDataCount > count) { - LOGE("Size of a batch of sync data is greater than upload data size."); + LOGE("[CloudSyncer] Size of a batch of sync data is greater than upload data size."); return -E_INTERNAL_ERROR; } @@ -1998,7 +2157,7 @@ int CloudSyncer::CleanCloudData(ClearMode mode, const std::vector & int index = 1; for (const auto &tableName: tableNameList) { LOGD("[CloudSyncer] Start clean cloud water mark. table index: %d.", index); - int ret = storageProxy_->PutCloudWaterMark(tableName, emptyString); + int ret = storageProxy_->SetCloudWaterMark(tableName, emptyString); if (ret != E_OK) { LOGE("[CloudSyncer] failed to put cloud water mark after clean cloud data, %d.", ret); return ret; @@ -2018,13 +2177,15 @@ int CloudSyncer::CleanCloudData(ClearMode mode, const std::vector & storageProxy_->Rollback(); return errCode; } - - errCode = cloudDB_.RemoveLocalAssets(assets); - if (errCode != E_OK) { - LOGE("[Storage Executor] failed to remove local assets, %d.", errCode); - storageProxy_->Rollback(); - return errCode; + if (!assets.empty() && mode == FLAG_AND_DATA) { + errCode = cloudDB_.RemoveLocalAssets(assets); + if (errCode != E_OK) { + LOGE("[Storage Executor] failed to remove local assets, %d.", errCode); + storageProxy_->Rollback(); + return errCode; + } } + storageProxy_->Commit(); return errCode; @@ -2039,4 +2200,18 @@ void CloudSyncer::ModifyCloudDataTime(VBucket &data) data[CloudDbConstant::MODIFY_FIELD] = modifyTime; data[CloudDbConstant::CREATE_FIELD] = createTime; } + +void CloudSyncer::UpdateCloudWaterMark(const SyncParam ¶m) +{ + bool isUpdateCloudCursor = true; + { + std::lock_guard autoLock(queueLock_); + isUpdateCloudCursor = currentContext_.strategy->JudgeUpdateCursor(); + } + // use the cursor of the last datum in data set to update cloud water mark + if (isUpdateCloudCursor) { + std::lock_guard autoLock(contextLock_); + currentContext_.cloudWaterMarks[param.info.tableName] = param.cloudWaterMark; + } +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h index fc614307..aaf558c5 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h @@ -61,14 +61,37 @@ protected: int64_t timeout; std::vector devices; }; + struct DataInfo { + DataInfoWithLog localInfo; + LogInfo cloudLogInfo; + }; struct InnerProcessInfo { std::string tableName; ProcessStatus tableStatus = ProcessStatus::PREPARED; Info downLoadInfo; Info upLoadInfo; }; + struct AssetDownloadList { + // assets in following list will fill STATUS and timestamp after calling downloading + DownloadList downloadList; + // assets in following list won't fill STATUS and timestamp after calling downloading + DownloadList completeDownloadList; + }; + struct SyncParam { + DownloadData downloadData; + ChangedData changedData; + InnerProcessInfo info; + AssetDownloadList assetsDownloadList; + CloudWaterMark cloudWaterMark; + std::vector pkColNames; + std::string tableName; + bool isLastBatch = false; + }; class ProcessNotifier { public: + explicit ProcessNotifier(CloudSyncer *syncer); + ~ProcessNotifier(); + void Init(const std::vector &tableName, const std::vector &devices); void UpdateProcess(const InnerProcessInfo &process); @@ -81,12 +104,7 @@ protected: std::mutex processMutex_; SyncProcess syncProcess_; std::vector devices_; - }; - struct AssetDownloadList { - // assets in following list will fill STATUS and timestamp after calling downloading - DownloadList downloadList; - // assets in following list won't fill STATUS and timestamp after calling downloading - DownloadList completeDownloadList; + CloudSyncer *syncer_; }; struct TaskContext { TaskId currentTaskId = 0u; @@ -113,14 +131,15 @@ protected: int DoSync(TaskId taskId); - int DoSyncInner(const CloudTaskInfo &taskInfo, const bool &needUpload); + int DoSyncInner(const CloudTaskInfo &taskInfo, const bool needUpload); + + int DoUploadInNeed(const CloudTaskInfo &taskInfo, const bool needUpload); void DoFinished(TaskId taskId, int errCode, const InnerProcessInfo &processInfo); virtual int DoDownload(TaskId taskId); - int DoDownloadInner(CloudSyncer::TaskId taskId, std::vector &colNames, - InnerProcessInfo &info, CloudWaterMark &cloudWaterMark); + int DoDownloadInner(CloudSyncer::TaskId taskId, SyncParam ¶m); void NotifyInEmptyDownload(CloudSyncer::TaskId taskId, InnerProcessInfo &info); @@ -142,8 +161,8 @@ protected: void ClearCloudSyncData(CloudSyncData &uploadData); - int PreProcessBatchUpload(TaskId taskId, CloudSyncData &uploadData, InnerProcessInfo &innerProcessInfo, - LocalWaterMark &localMark); + int PreProcessBatchUpload(TaskId taskId, const InnerProcessInfo &innerProcessInfo, + CloudSyncData &uploadData, LocalWaterMark &localMark); int PutWaterMarkAfterBatchUpload(const std::string &tableName, UploadParam &uploadParam); @@ -157,7 +176,7 @@ protected: int CheckDownloadDatum(VBucket &datum); - int QueryCloudData(const std::string &tableName, const CloudWaterMark &cloudWaterMark, DownloadData &downloadData); + int QueryCloudData(const std::string &tableName, CloudWaterMark &cloudWaterMark, DownloadData &downloadData); int CheckTaskIdValid(TaskId taskId); @@ -185,21 +204,18 @@ protected: void SetTaskFailed(TaskId taskId, int errCode); - int SaveDatum(const std::string &tableName, size_t idx, DownloadData &downloadData, - AssetDownloadList &assetsDownloadList, ChangedData &changedData, std::vector &InsertDataNoPrimaryKeys); + int SaveDatum(SyncParam ¶m, size_t idx, std::vector &InsertDataNoPrimaryKeys); - int SaveData(const TableName &tablename, DownloadData &downloadData, - Info &downloadInfo, CloudWaterMark &latestCloudWaterMark, ChangedData &changedData); + int SaveData(SyncParam ¶m); - int SaveDataInTransaction(CloudSyncer::TaskId taskId, DownloadData &downloadData, - std::vector &pkColNames, InnerProcessInfo &info, CloudWaterMark &newCloudWaterMark, - ChangedData &changedData); + void NotifyInDownload(CloudSyncer::TaskId taskId, SyncParam ¶m); - int SaveChangedData(DownloadData &downloadData, int dataIndex, DataInfoWithLog &localLogInfo, - LogInfo &cloudLogInfo, ChangedData &changedData, std::vector &InsertDataNoPrimaryKeys); + int SaveDataInTransaction(CloudSyncer::TaskId taskId, SyncParam ¶m); - int SaveDataNotifyProcess(CloudSyncer::TaskId taskId, DownloadData &downloadData, - std::vector &pkColNames, InnerProcessInfo &info, CloudWaterMark &newCloudWaterMark); + int SaveChangedData(SyncParam ¶m, int dataIndex, DataInfo &dataInfo, + std::vector &InsertDataNoPrimaryKeys); + + int SaveDataNotifyProcess(CloudSyncer::TaskId taskId, SyncParam ¶m); void NotifyInBatchUpload(const UploadParam &uploadParam, const InnerProcessInfo &innerProcessInfo, bool lastBatch); @@ -209,35 +225,48 @@ protected: std::map GetAssetsFromVBucket(VBucket &data); - std::map TagAssetsInSingleRecord(VBucket &CoveredData, VBucket &BeCoveredData, - bool WriteToCoveredData); + std::map TagAssetsInSingleRecord(VBucket &coveredData, VBucket &beCoveredData, + bool setNormalStatus); + + Assets TagAssetsInSingleCol(VBucket &coveredData, VBucket &beCoveredData, const Field &assetField, + bool setNormalStatus); - Assets TagAssetsInSingleCol(VBucket &CoveredData, VBucket &BeCoveredData, const Field &assetField, - bool WriteToCoveredData); + int TagStatus(bool isExist, SyncParam ¶m, size_t idx, DataInfo &dataInfo, VBucket &localAssetInfo); - void TagStatus(bool isExist, const TableName &tableName, size_t idx, DownloadData &downloadData, - std::vector &pKColNames, DataInfoWithLog &localInfo, LogInfo &cloudLogInfo, - VBucket &localAssetInfo, AssetDownloadList &assetsDownloadList); + int TagDownloadAssets(size_t idx, SyncParam ¶m, DataInfo &dataInfo, + VBucket &localAssetInfo); void TagUploadAssets(CloudSyncData &uploadData); int FillCloudAssets(const std::string &tableName, VBucket &normalAssets, VBucket &failedAssets); - int HandleDownloadResult(const std::string &tableName, std::string gid, + int HandleDownloadResult(const std::string &tableName, const std::string &gid, std::map &DownloadResult, bool setAllNormal); - int DownloadNotifyAssets(InnerProcessInfo &info, std::vector &pKColNames, + int DownloadAssets(InnerProcessInfo &info, const std::vector &pKColNames, ChangedData &changedAssets); int CloudDbDownloadAssets(InnerProcessInfo &info, DownloadList &downloadList, bool willHandleResult, ChangedData &changedAssets); - bool ShouldProcessAssets(); + bool IsDataContainAssets(); + + bool IsDataContainDuplicateAsset(const std::vector &assetFields, VBucket &data); + + void IncSyncCallbackTaskCount(); + + void DecSyncCallbackTaskCount(); + + void WaitAllSyncCallbackTaskFinish(); static int CheckParamValid(const std::vector &devices, SyncMode mode); void ModifyCloudDataTime(VBucket &data); + int SaveCloudWaterMark(const TableName &tableName); + + void UpdateCloudWaterMark(const SyncParam ¶m); + std::mutex queueLock_; TaskId currentTaskId_; std::list taskQueue_; @@ -261,6 +290,10 @@ protected: std::condition_variable heartbeatCv_; int32_t heartBeatCount_; std::atomic failedHeartBeatCount_; + + std::mutex syncCallbackMutex_; + std::condition_variable syncCallbackCv_; + int32_t syncCallbackCount_; }; } #endif // CLOUD_SYNCER_H diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/strategy_factory.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/strategy_factory.cpp index e0bcd545..39ef7b6f 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/strategy_factory.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/strategy_factory.cpp @@ -24,12 +24,10 @@ std::shared_ptr StrategyFactory::BuildSyncStrategy(SyncMode m switch (mode) { case SyncMode::SYNC_MODE_CLOUD_MERGE: return std::make_shared(); -#ifdef MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA case SyncMode::SYNC_MODE_CLOUD_FORCE_PULL: return std::make_shared(); case SyncMode::SYNC_MODE_CLOUD_FORCE_PUSH: return std::make_shared(); -#endif // MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA default: LOGW("[StrategyFactory] Not support mode %d", static_cast(mode)); return std::make_shared(); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.cpp index 6ed92a08..f9215f1c 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.cpp @@ -1024,6 +1024,7 @@ int GenericSyncer::CloseInner(bool isClosedOperation) int GenericSyncer::GetSyncDataSize(const std::string &device, size_t &size) const { uint64_t localWaterMark = 0; + std::shared_ptr metadata = nullptr; { std::lock_guard lock(syncerLock_); if (metadata_ == nullptr || syncInterface_ == nullptr) { @@ -1034,8 +1035,9 @@ int GenericSyncer::GetSyncDataSize(const std::string &device, size_t &size) cons return -E_BUSY; } syncInterface_->IncRefCount(); - metadata_->GetLocalWaterMark(device, localWaterMark); + metadata = metadata_; } + metadata->GetLocalWaterMark(device, localWaterMark); uint32_t expectedMtuSize = 1024u * 1024u; // 1M DataSizeSpecInfo syncDataSizeInfo = {expectedMtuSize, static_cast(MAX_TIMESTAMP)}; std::vector outData; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.h b/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.h index 19ec075e..f3d4a7cb 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.h @@ -55,7 +55,7 @@ public: void GetTimeOffset(const DeviceID &deviceId, TimeOffset &outValue); - void GetLocalWaterMark(const DeviceID &deviceId, uint64_t &outValue); + virtual void GetLocalWaterMark(const DeviceID &deviceId, uint64_t &outValue); int SaveLocalWaterMark(const DeviceID &deviceId, uint64_t inValue); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.cpp index 96a2420a..1d5753d3 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.cpp @@ -310,6 +310,10 @@ bool RemoteExecutor::CheckParamValid(const std::string &device, uint64_t timeout LOGD("[RemoteExecutor][CheckParamValid] device is empty"); return false; } + if (device.length() > DBConstant::MAX_DEV_LENGTH) { + LOGE("[RemoteExecutor] dev is too long len=%zu", device.length()); + return false; + } ICommunicator *communicator = GetAndIncCommunicator(); if (communicator == nullptr) { return false; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_data_sync.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_data_sync.cpp index 5301e977..0954b3b9 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_data_sync.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_data_sync.cpp @@ -933,7 +933,7 @@ int SingleVerDataSync::DoAbilitySyncIfNeed(SingleVerSyncTaskContext *context, co } else { SendDataAck(context, message, -E_NEED_ABILITY_SYNC, 0); } - return -E_WAIT_NEXT_MESSAGE; + return -E_NEED_ABILITY_SYNC; } } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_engine.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_engine.cpp index 764553de..28f013cd 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_engine.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_engine.cpp @@ -62,6 +62,11 @@ void SingleVerSyncEngine::EnableClearRemoteStaleData(bool enable) int SingleVerSyncEngine::StartAutoSubscribeTimer() { + if (syncInterface_->IsSupportSubscribe() == -E_NOT_SUPPORT) { + LOGI("[StartAutoSubscribeTimer] no need to start subscribe timer"); + return E_OK; + } + std::lock_guard lockGuard(timerLock_); if (subscribeTimerId_ > 0) { LOGI("[SingleSyncEngine] subscribeTimerId is already set"); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_state_machine.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_state_machine.cpp index efc27dd0..50e3b429 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_state_machine.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_state_machine.cpp @@ -276,10 +276,14 @@ const std::vector &SingleVerSyncStateMachine::GetStateSwitchTa int SingleVerSyncStateMachine::PrepareNextSyncTask() { int errCode = StartWatchDog(); - if (errCode != E_OK) { + if (errCode != E_OK && errCode != -E_UNEXPECTED_DATA) { LOGE("[StateMachine][PrepareNextSyncTask] WatchDog start failed,err=%d", errCode); return errCode; } + if (errCode == -E_UNEXPECTED_DATA) { + LOGI("[PrepareNextSyncTask] timer already exists, reset the timer."); + (void)ResetWatchDog(); + } if (currentState_ != State::IDLE && currentState_ != State::SYNC_TASK_FINISHED) { LOGW("[StateMachine][PrepareNextSyncTask] PreSync may get an err, state=%" PRIu8 ",dev=%s", @@ -615,6 +619,7 @@ int SingleVerSyncStateMachine::AbilitySyncRecv(const Message *inMsg) // while recv last notify means ability sync finished,it is better to reset watchDog to avoid timeout. LOGI("[StateMachine][AbilitySyncRecv] ability sync finished,label=%s,dev=%s", dataSync_->GetLabel().c_str(), STR_MASK(context_->GetDeviceId())); + context_->SetRemoteSoftwareVersion(packet->GetSoftwareVersion()); currentRemoteVersionId_ = context_->GetRemoteSoftwareVersionId(); std::lock_guard lock(stateMachineLock_); (void)ResetWatchDog(); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_engine.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_engine.cpp index f0fd3de9..ee1c4aaa 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_engine.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_engine.cpp @@ -72,11 +72,13 @@ int SyncEngine::Initialize(ISyncInterface *syncInterface, const std::shared_ptr< if ((syncInterface == nullptr) || (metadata == nullptr)) { return -E_INVALID_ARGS; } + syncInterface_ = syncInterface; int errCode = StartAutoSubscribeTimer(); if (errCode != OK) { + syncInterface_ = nullptr; return errCode; } - syncInterface_ = syncInterface; + errCode = InitComunicator(syncInterface); if (errCode != E_OK) { LOGE("[SyncEngine] Init Communicator failed"); @@ -1142,6 +1144,10 @@ bool SyncEngine::CheckDeviceIdValid(const std::string &checkDeviceId, const std: if (checkDeviceId.empty()) { return false; } + if (checkDeviceId.length() > DBConstant::MAX_DEV_LENGTH) { + LOGE("[SyncEngine] dev is too long len=%zu", checkDeviceId.length()); + return false; + } return localDeviceId != checkDeviceId; } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.cpp index 6909b163..b8fedaaa 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.cpp @@ -556,6 +556,7 @@ int SyncTaskContext::TimeOut(TimerId id) void SyncTaskContext::CopyTargetData(const ISyncTarget *target, const TaskParam &taskParam) { + retryTime_ = 0; mode_ = target->GetMode(); status_ = SyncOperation::OP_SYNCING; isNeedRetry_ = SyncTaskContext::NO_NEED_RETRY; diff --git a/kv_store/frameworks/libs/distributeddb/test/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/BUILD.gn index ebed30ee..617a6a04 100644 --- a/kv_store/frameworks/libs/distributeddb/test/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/BUILD.gn @@ -326,9 +326,9 @@ ohos_source_set("src_file") { ] external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", ] part_name = "kv_store" } @@ -359,9 +359,9 @@ template("distributeddb_unittest") { ] external_deps = [ "c_utils:utils", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", ] } } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn index 6faa07da..5f815d05 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn @@ -101,7 +101,7 @@ ohos_fuzztest("DelegateFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn index b1312290..52aee242 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn @@ -102,7 +102,7 @@ ohos_fuzztest("FileOperFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn index 4c9a9639..eef7a91d 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn @@ -102,7 +102,7 @@ ohos_fuzztest("ImportFileFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn index 0493b443..c946920f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn @@ -101,7 +101,7 @@ ohos_fuzztest("IProcessCommunicatorFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn index 11d3cf89..c7fb8f27 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn @@ -102,7 +102,7 @@ ohos_fuzztest("KvDelegateManagerFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn index 66fd0b78..20a78fd9 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn @@ -102,7 +102,7 @@ ohos_fuzztest("KvStoreResultSetFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn index 00b33766..474a1d5a 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn @@ -101,7 +101,7 @@ ohos_fuzztest("NbDelegateFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn index a240626a..9727e3b5 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn @@ -102,7 +102,7 @@ ohos_fuzztest("ParseCkeckFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn index 3a4fbc8b..2824f50c 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn @@ -101,7 +101,7 @@ ohos_fuzztest("QueryFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn index 7c967d84..52458c01 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn @@ -102,7 +102,7 @@ ohos_fuzztest("ReKeyFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn index c261228e..632298e4 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn @@ -106,7 +106,7 @@ ohos_fuzztest("RelationalstoredelegateFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn index d4b65a80..56af80ab 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn @@ -106,7 +106,7 @@ ohos_fuzztest("RelationalstoremanagerFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn index 8c192846..c4a58b88 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn @@ -101,7 +101,7 @@ ohos_fuzztest("SchemaDelegateFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn index 522c4797..7ca919b4 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn @@ -107,7 +107,7 @@ ohos_fuzztest("SyncFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/moduletest/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/moduletest/BUILD.gn index d16cccf7..94500597 100644 --- a/kv_store/frameworks/libs/distributeddb/test/moduletest/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/moduletest/BUILD.gn @@ -85,7 +85,7 @@ ohos_moduletest("DistributeddbKvTransactionTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -110,7 +110,7 @@ ohos_moduletest("DistributeddbKvTransactionPerfTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -133,7 +133,7 @@ ohos_moduletest("DistributeddbKvConcurrencyCrudTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -156,7 +156,7 @@ ohos_moduletest("DistributeddbKvBatchCrudTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -179,7 +179,7 @@ ohos_moduletest("DistributeddbKvCreateTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -202,7 +202,7 @@ ohos_moduletest("DistributeddbKvCrudTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -225,7 +225,7 @@ ohos_moduletest("DistributeddbKvObserverTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -248,7 +248,7 @@ ohos_moduletest("DistributeddbKvObserverSnapTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -270,7 +270,7 @@ ohos_moduletest("DistributeddbKvBackupTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -293,7 +293,7 @@ ohos_moduletest("DistributeddbKvRealdelTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -318,7 +318,7 @@ ohos_moduletest("DistributeddbNbCreateTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -342,7 +342,7 @@ ohos_moduletest("DistributeddbNbCrudTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -366,7 +366,7 @@ ohos_moduletest("DistributeddbNbObserverTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -392,7 +392,7 @@ ohos_moduletest("DistributeddbNbCursorTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -418,7 +418,7 @@ ohos_moduletest("DistributeddbNbBackupTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -443,7 +443,7 @@ ohos_moduletest("DistributeddbNbBatchCrudTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -468,7 +468,7 @@ ohos_moduletest("DistributeddbNbLocalBatchCrudTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -492,7 +492,7 @@ ohos_moduletest("DistributeddbNbSchemaDbTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -517,7 +517,7 @@ ohos_moduletest("DistributeddbNbPredicateQueryTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -542,7 +542,7 @@ ohos_moduletest("DistributeddbNbPredicateQueryExpandTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -567,7 +567,7 @@ ohos_moduletest("DistributeddbNbAutolaunchTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -592,7 +592,7 @@ ohos_moduletest("DistributedbNbDbDamageTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -617,7 +617,7 @@ ohos_moduletest("DistributeddbNbCrudPowerTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -642,7 +642,7 @@ ohos_moduletest("DistributeddbNbSchemaTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } @@ -667,7 +667,7 @@ ohos_moduletest("DistributeddbNbSchemaUpgradeTest") { ] external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] part_name = "datamgr_service" } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_interfaces_relational_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_interfaces_relational_sync_test.cpp index cb5caf22..1deab896 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_interfaces_relational_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_interfaces_relational_sync_test.cpp @@ -15,20 +15,21 @@ #ifdef RELATIONAL_STORE #include #include -#include "distributeddb_tools_unit_test.h" #include "cloud/cloud_storage_utils.h" -#include "relational_store_manager.h" +#include "cloud_db_constant.h" #include "distributeddb_data_generate_unit_test.h" +#include "distributeddb_tools_unit_test.h" +#include "process_system_api_adapter_impl.h" #include "relational_store_instance.h" +#include "relational_store_manager.h" +#include "runtime_config.h" #include "sqlite_relational_store.h" #include "sqlite_relational_utils.h" #include "store_observer.h" -#include "cloud_db_constant.h" -#include "virtual_cloud_db.h" #include "time_helper.h" -#include "runtime_config.h" -#include "virtual_cloud_data_translate.h" #include "virtual_asset_loader.h" +#include "virtual_cloud_data_translate.h" +#include "virtual_cloud_db.h" using namespace testing::ext; using namespace DistributedDB; @@ -53,6 +54,8 @@ namespace { std::shared_ptr g_virtualAssetLoader; DistributedDB::RelationalStoreManager g_mgr(APP_ID, USER_ID); RelationalStoreObserverUnitTest *g_observer = nullptr; + RelationalStoreDelegate *g_delegate = nullptr; + SyncProcess g_syncProcess; using CloudSyncStatusCallback = std::function &onProcess)>; const std::string CREATE_LOCAL_TABLE_SQL = "CREATE TABLE IF NOT EXISTS " + g_tableName1 + "(" \ @@ -161,8 +164,8 @@ namespace { EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)); SQLiteUtils::ResetStatement(stmt, true, errCode); } - LOGD("insert user record worker1[primary key]:[local%d - cloud%d) , worker2[primary key]:[%d - %d)", - begin, count, begin, count); + LOGD("insert user record worker1[primary key]:[local%" PRId64 " - cloud%" PRId64 + ") , worker2[primary key]:[%" PRId64 "- %" PRId64")", begin, count, begin, count); } void UpdateUserTableRecord(sqlite3 *&db, int64_t begin, int64_t count) @@ -176,8 +179,8 @@ namespace { updateAge += ");"; ASSERT_EQ(RelationalTestUtils::ExecSql(db, updateAge), SQLITE_OK); } - LOGD("update local record worker1[primary key]:[local%d - local%d) , worker2[primary key]:[%d - %d)", - begin, count, begin, count); + LOGD("update local record worker1[primary key]:[local%" PRId64 " - local%" PRId64 + ") , worker2[primary key]:[%" PRId64 "- %" PRId64")", begin, count, begin, count); } void DeleteUserTableRecord(sqlite3 *&db, int64_t begin, int64_t count) @@ -191,8 +194,8 @@ namespace { updateAge += ");"; ASSERT_EQ(RelationalTestUtils::ExecSql(db, updateAge), SQLITE_OK); } - LOGD("delete local record worker1[primary key]:[local%d - local%d) , worker2[primary key]:[%d - %d)", - begin, count, begin, count); + LOGD("delete local record worker1[primary key]:[local%" PRId64 " - local%" PRId64 + ") , worker2[primary key]:[%" PRId64 "- %" PRId64")", begin, count, begin, count); } void InsertRecordWithoutPk2LocalAndCloud(sqlite3 *&db, int64_t begin, int64_t count, int photoSize) @@ -237,6 +240,8 @@ namespace { std::vector photo(photoSize, 'v'); std::vector record1; std::vector extend1; + std::vector record2; + std::vector extend2; Timestamp now = TimeHelper::GetSysCurrentTime(); for (int64_t i = begin; i < begin + count; ++i) { VBucket data; @@ -244,45 +249,35 @@ namespace { data.insert_or_assign("height", 166.0); // 166.0 is random double value data.insert_or_assign("married", false); data.insert_or_assign("photo", photo); + data.insert_or_assign("age", 13L); Asset asset = g_cloudAsset; asset.name = asset.name + std::to_string(i); assetIsNull ? data.insert_or_assign("assert", Nil()) : data.insert_or_assign("assert", asset); - data.insert_or_assign("age", 13L); record1.push_back(data); VBucket log; log.insert_or_assign(CloudDbConstant::CREATE_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND + i); log.insert_or_assign(CloudDbConstant::MODIFY_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND + i); log.insert_or_assign(CloudDbConstant::DELETE_FIELD, false); extend1.push_back(log); - } - ASSERT_EQ(g_virtualCloudDb->BatchInsert(g_tableName1, std::move(record1), extend1), DBStatus::OK); - std::vector record2, extend2; - now = TimeHelper::GetSysCurrentTime(); - for (int64_t i = begin; i < begin + count; ++i) { - VBucket data; + std::vector assets; data.insert_or_assign("id", i); - data.insert_or_assign("name", "Cloud" + std::to_string(i)); data.insert_or_assign("height", 180.3); // 180.3 is random double value - data.insert_or_assign("photo", photo); - std::vector assets; - Asset asset = g_cloudAsset; - for (int64_t j = i; j <= i + 1; j++) { + for (int64_t j = i; j <= i + 2; j++) { // 2 extra num asset.name = g_cloudAsset.name + std::to_string(j); assets.push_back(asset); } + data.erase("assert"); + data.erase("married"); assetIsNull ? data.insert_or_assign("asserts", Nil()) : data.insert_or_assign("asserts", assets); - data.insert_or_assign("age", 28L); record2.push_back(data); - VBucket log; - log.insert_or_assign(CloudDbConstant::CREATE_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND + i); - log.insert_or_assign(CloudDbConstant::MODIFY_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND + i); - log.insert_or_assign(CloudDbConstant::DELETE_FIELD, false); extend2.push_back(log); } + ASSERT_EQ(g_virtualCloudDb->BatchInsert(g_tableName1, std::move(record1), extend1), DBStatus::OK); ASSERT_EQ(g_virtualCloudDb->BatchInsert(g_tableName2, std::move(record2), extend2), DBStatus::OK); - LOGD("insert cloud record worker1[primary key]:[cloud%d - cloud%d) , worker2[primary key]:[%d - %d)", - begin, count, begin, count); + LOGD("insert cloud record worker1[primary key]:[cloud%" PRId64 " - cloud%" PRId64 + ") , worker2[primary key]:[%" PRId64 "- %" PRId64")", begin, count, begin, count); + std::this_thread::sleep_for(std::chrono::milliseconds(count)); } void UpdateAssetForTest(sqlite3 *&db, AssetOpType opType, int64_t cloudCount, int64_t rowid) @@ -348,6 +343,83 @@ namespace { SQLiteUtils::ResetStatement(stmt, true, errCode); } + void UpdateLocalAssetsToRepeat(sqlite3 *&db, int64_t rowid) + { + string sql = "UPDATE " + g_tables[1] + " SET asserts = ? where rowid = '" + std::to_string(rowid) + "';"; + std::vector assetsBlob; + int errCode; + Assets assets; + assets.push_back(g_localAsset); + assets.push_back(g_localAsset); + RuntimeContext::GetInstance()->AssetsToBlob(assets, assetsBlob); + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + if (SQLiteUtils::BindBlobToStatement(stmt, 1, assetsBlob, false) == E_OK) { + EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)); + } + SQLiteUtils::ResetStatement(stmt, true, errCode); + } + + void UpdateDiffType(int64_t begin) + { + std::vector hash = {"DEC", "update_", "insert_"}; + std::vector name = { + g_cloudAsset.name + std::to_string(0), + g_cloudAsset.name + std::to_string(1), + g_cloudAsset.name + std::to_string(3) // 3 is insert id + }; + std::vector record; + std::vector extend; + Assets assets; + for (int i = 0; i < 3; i ++) { // 3 is type num + Asset asset = g_cloudAsset; + asset.name = name[i]; + asset.hash = hash[i]; + assets.push_back(asset); + } + VBucket data; + data.insert_or_assign("name", "Cloud" + std::to_string(0)); + data.insert_or_assign("id", 0L); + data.insert_or_assign("asserts", assets); + Timestamp now = TimeHelper::GetSysCurrentTime(); + VBucket log; + log.insert_or_assign(CloudDbConstant::DELETE_FIELD, false); + log.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(begin)); + log.insert_or_assign(CloudDbConstant::CREATE_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND); + log.insert_or_assign(CloudDbConstant::MODIFY_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND); + record.push_back(data); + extend.push_back(log); + ASSERT_EQ(g_virtualCloudDb->BatchUpdate(g_tableName2, std::move(record), extend), DBStatus::OK); + } + + void CheckDiffTypeAsset(sqlite3 *&db) + { + std::vector names = { + g_cloudAsset.name + std::to_string(0), + g_cloudAsset.name + std::to_string(1), + g_cloudAsset.name + std::to_string(3) // 3 is insert id + }; + std::string sql = "SELECT asserts from " + g_tables[1] + " WHERE rowid = 0;"; + sqlite3_stmt *stmt = nullptr; + int index = 0; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + while (SQLiteUtils::StepWithRetry(stmt) == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + ASSERT_EQ(sqlite3_column_type(stmt, 0), SQLITE_BLOB); + Type cloudValue; + ASSERT_EQ(SQLiteRelationalUtils::GetCloudValueByType(stmt, TYPE_INDEX, 0, cloudValue), E_OK); + std::vector assetsBlob; + Assets assets; + ASSERT_EQ(CloudStorageUtils::GetValueFromOneField(cloudValue, assetsBlob), E_OK); + ASSERT_EQ(RuntimeContext::GetInstance()->BlobToAssets(assetsBlob, assets), E_OK); + for (const Asset &asset: assets) { + ASSERT_EQ(asset.status, static_cast(AssetStatus::NORMAL)); + ASSERT_EQ(asset.name, names[index++]); + } + } + int errCode; + SQLiteUtils::ResetStatement(stmt, true, errCode); + } + void CheckFillAssetForTest10(sqlite3 *&db) { std::string sql = "SELECT assert from " + g_tables[0] + " WHERE rowid in ('27','28','29','30');"; @@ -451,6 +523,16 @@ namespace { } } + // void CheckLocalTotalNum(sqlite3 *&db, std::vector tableList, std::vector countList) + // { + // int i = 0; + // for (const auto &tableName: tableList) { + // std::string sql = "select count(*) from " + tableName + ";"; + // EXPECT_EQ(sqlite3_exec(db, sql.c_str(), QueryCountCallback, + // reinterpret_cast(countList[i]), nullptr), SQLITE_OK); + // i++; + // } + // } void CheckCleanLogNum(sqlite3 *&db, const std::vector tableList, int count) { for (const auto &tableName: tableList) { @@ -589,6 +671,7 @@ namespace { expectProcess.push_back(syncProcess); } } + void InitProcessForMannualSync1(std::vector &expectProcess) { expectProcess.clear(); @@ -626,38 +709,26 @@ namespace { expectProcess.push_back(syncProcess); } } + void InitProcessForCleanCloudData1(const uint32_t &cloudCount, const uint32_t &localCount, std::vector &expectProcess) { + // cloudCount also means data count in one batch expectProcess.clear(); std::vector infos; uint32_t index = 1; infos.push_back(TableProcessInfo{ - PROCESSING, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0} + FINISHED, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0} }); infos.push_back(TableProcessInfo{ PREPARED, {0, 0, 0, 0}, {0, 0, 0, 0} }); infos.push_back(TableProcessInfo{ - PROCESSING, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0} - }); - infos.push_back(TableProcessInfo{ - PROCESSING, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0} - }); - - infos.push_back(TableProcessInfo{ - PROCESSING, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0} - }); - infos.push_back(TableProcessInfo{ - PROCESSING, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0} - }); - - infos.push_back(TableProcessInfo{ - PROCESSING, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0} + FINISHED, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0} }); infos.push_back(TableProcessInfo{ - PROCESSING, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0} + FINISHED, {index, cloudCount, cloudCount, 0}, {0, 0, 0, 0} }); for (size_t i = 0; i < infos.size() / g_arrayHalfSub; ++i) { @@ -670,7 +741,6 @@ namespace { } } - void InitProcessForTest2(const uint32_t &cloudCount, const uint32_t &localCount, std::vector &expectProcess) { @@ -758,7 +828,6 @@ namespace { expectProcess.push_back(syncProcess); } } - void GetCallback(SyncProcess &syncProcess, CloudSyncStatusCallback &callback, std::vector &expectProcess) { @@ -932,6 +1001,16 @@ namespace { LOGD("-------------------sync end--------------"); } + void CloseDb() + { + delete g_observer; + g_virtualCloudDb = nullptr; + if (g_delegate != nullptr) { + EXPECT_EQ(g_mgr.CloseStore(g_delegate), DBStatus::OK); + g_delegate = nullptr; + } + } + class DistributedDBCloudInterfacesRelationalSyncTest : public testing::Test { public: static void SetUpTestCase(void); @@ -940,7 +1019,6 @@ namespace { void TearDown(); protected: sqlite3 *db = nullptr; - RelationalStoreDelegate *delegate = nullptr; }; @@ -968,33 +1046,28 @@ namespace { g_observer = new (std::nothrow) RelationalStoreObserverUnitTest(); ASSERT_NE(g_observer, nullptr); ASSERT_EQ(g_mgr.OpenStore(g_storePath, g_storeID, RelationalStoreDelegate::Option { .observer = g_observer }, - delegate), DBStatus::OK); - ASSERT_NE(delegate, nullptr); - ASSERT_EQ(delegate->CreateDistributedTable(g_tableName1, CLOUD_COOPERATION), DBStatus::OK); - ASSERT_EQ(delegate->CreateDistributedTable(g_tableName2, CLOUD_COOPERATION), DBStatus::OK); - ASSERT_EQ(delegate->CreateDistributedTable(g_tableName3, CLOUD_COOPERATION), DBStatus::OK); + g_delegate), DBStatus::OK); + ASSERT_NE(g_delegate, nullptr); + ASSERT_EQ(g_delegate->CreateDistributedTable(g_tableName1, CLOUD_COOPERATION), DBStatus::OK); + ASSERT_EQ(g_delegate->CreateDistributedTable(g_tableName2, CLOUD_COOPERATION), DBStatus::OK); + ASSERT_EQ(g_delegate->CreateDistributedTable(g_tableName3, CLOUD_COOPERATION), DBStatus::OK); g_virtualCloudDb = make_shared(); g_virtualAssetLoader = make_shared(); - ASSERT_EQ(delegate->SetCloudDB(g_virtualCloudDb), DBStatus::OK); - ASSERT_EQ(delegate->SetIAssetLoader(g_virtualAssetLoader), DBStatus::OK); + g_syncProcess = {}; + ASSERT_EQ(g_delegate->SetCloudDB(g_virtualCloudDb), DBStatus::OK); + ASSERT_EQ(g_delegate->SetIAssetLoader(g_virtualAssetLoader), DBStatus::OK); // sync before setting cloud db schema,it should return SCHEMA_MISMATCH Query query = Query::Select().FromTable(g_tables); CloudSyncStatusCallback callback; - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::SCHEMA_MISMATCH); DataBaseSchema dataBaseSchema; GetCloudDbSchema(dataBaseSchema); - ASSERT_EQ(delegate->SetCloudDbSchema(dataBaseSchema), DBStatus::OK); + ASSERT_EQ(g_delegate->SetCloudDbSchema(dataBaseSchema), DBStatus::OK); } void DistributedDBCloudInterfacesRelationalSyncTest::TearDown(void) { - delete g_observer; - g_virtualCloudDb = nullptr; - if (delegate != nullptr) { - EXPECT_EQ(g_mgr.CloseStore(delegate), DBStatus::OK); - delegate = nullptr; - } EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) { LOGE("rm test db files error."); @@ -1030,17 +1103,17 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest001, TestS Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; InitProcessForTest1(cloudCount, localCount, expectProcess); - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); EXPECT_TRUE(g_observer->IsAllChangedDataEq()); g_observer->ClearChangedData(); LOGD("expect download:worker1[primary key]:[cloud0 - cloud20), worker2[primary key]:[10 - 20)"); CheckDownloadResult(db, {20L, 10L}); // 20 and 10 means the num of downloads from cloud db by worker1 and worker2 LOGD("expect upload:worker1[primary key]:[local0 - local10), worker2[primary key]:[0 - 10)"); CheckCloudTotalCount({30L, 20L}); // 30 and 20 means the total num of worker1 and worker2 from the cloud db + CloseDb(); } /** @@ -1060,15 +1133,15 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest002, TestS Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; InitProcessForTest2(cloudCount, localCount, expectProcess); - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); LOGD("expect download:worker1[primary key]:[cloud0 - cloud10), worker2[primary key]:[0 - 10)"); CheckDownloadResult(db, {10L, 10L}); // 10 and 10 means the num of downloads from cloud db by worker1 and worker2 LOGD("expect upload:worker1[primary key]:[local0 - local20), worker2[primary key]:[10 - 20)"); CheckCloudTotalCount({30L, 20L}); // 30 and 20 means the total num of worker1 and worker2 from the cloud db + CloseDb(); } /** @@ -1087,22 +1160,21 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest003, TestS Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; InitProcessForTest1(cloudCount, cloudCount, expectProcess); - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); CheckDownloadResult(db, {20L, 0L}); // 20 and 0 means the num of downloads from cloud db by worker1 and worker2 CheckCloudTotalCount({40L, 20L}); // 40 and 20 means the total num of worker1 and worker2 from the cloud db int updateCount = 10; UpdateUserTableRecord(db, 5, updateCount); // 5 is start id to be updated - syncProcess = {}; + g_syncProcess = {}; InitProcessForTest1(cloudCount, updateCount, expectProcess); - GetCallback(syncProcess, callback, expectProcess); + GetCallback(g_syncProcess, callback, expectProcess); LOGD("-------------------sync after update--------------"); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); VBucket extend; extend[CloudDbConstant::CURSOR_FIELD] = std::to_string(0); @@ -1120,13 +1192,14 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest003, TestS int deleteCount = 3; DeleteUserTableRecord(db, 0, deleteCount); - syncProcess = {}; + g_syncProcess = {}; InitProcessForTest1(updateCount, deleteCount, expectProcess); - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); CheckCloudTotalCount({37L, 17L}); // 37 and 17 means the total num of worker1 and worker2 from the cloud db + CloseDb(); } /** @@ -1148,11 +1221,11 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest004, TestS } Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, 20); // 20 is wait time + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, 20); // 20 is wait time + CloseDb(); } /** @@ -1165,13 +1238,13 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest004, TestS HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest005, TestSize.Level0) { Query query = Query::Select().FromTable(g_tables).OrderBy("123", true); - SyncProcess syncProcess; - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, nullptr, g_syncWaitTime), + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, nullptr, g_syncWaitTime), DBStatus::NOT_SUPPORT); query = Query::Select(); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, nullptr, g_syncWaitTime), + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, nullptr, g_syncWaitTime), DBStatus::INVALID_ARGS); + CloseDb(); } /** @@ -1201,15 +1274,14 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest006, TestS InsertUserTableRecord(db, 0, cloudCount / g_arrayHalfSub, paddingSize, false); Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); + GetCallback(g_syncProcess, callback, expectProcess); // Set correct cloudDbSchema (correct version) DataBaseSchema correctSchema; GetCloudDbSchema(correctSchema); - ASSERT_EQ(delegate->SetCloudDbSchema(correctSchema), DBStatus::OK); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + ASSERT_EQ(g_delegate->SetCloudDbSchema(correctSchema), DBStatus::OK); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); EXPECT_TRUE(g_observer->IsAllChangedDataEq()); g_observer->ClearChangedData(); LOGD("expect download:worker1[primary key]:[cloud0 - cloud20), worker2[primary key]:[10 - 20)"); @@ -1219,16 +1291,17 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest006, TestS // Reset cloudDbSchema (invalid version - null) DataBaseSchema nullSchema; - ASSERT_EQ(delegate->SetCloudDbSchema(nullSchema), DBStatus::OK); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), + ASSERT_EQ(g_delegate->SetCloudDbSchema(nullSchema), DBStatus::OK); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::SCHEMA_MISMATCH); // Reset cloudDbSchema (invalid version - field mismatch) DataBaseSchema invalidSchema; GetInvalidCloudDbSchema(invalidSchema); - ASSERT_EQ(delegate->SetCloudDbSchema(invalidSchema), DBStatus::OK); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), + ASSERT_EQ(g_delegate->SetCloudDbSchema(invalidSchema), DBStatus::OK); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::SCHEMA_MISMATCH); + CloseDb(); } /** @@ -1246,15 +1319,15 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest007, TestS InsertCloudTableRecord(0, localCount / g_arrayHalfSub, paddingSize, false); Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); CheckAssetAfterDownload(db, localCount); CheckAllAssetAfterUpload(localCount); CheckAssetsAfterDownload(db, localCount); + CloseDb(); } /* @@ -1266,9 +1339,11 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest007, TestS */ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest008, TestSize.Level0) { - ASSERT_EQ(delegate->SetCloudDB(nullptr), OK); + ASSERT_EQ(g_delegate->SetCloudDB(nullptr), OK); // it will not happen because cloudb has been set in SetUp() Query query = Query::Select().FromTable({g_tableName3}); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, nullptr, g_syncWaitTime), CLOUD_ERROR); + // clouddb has been set in SetUp() and it's not null + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, nullptr, g_syncWaitTime), OK); + CloseDb(); } /** @@ -1287,22 +1362,22 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest009, TestS Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; InitProcessForTest1(cloudCount, cloudCount, expectProcess); - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); LOGD("expect download:worker1[primary key]:[cloud0 - cloud20), worker2[primary key]:none"); CheckDownloadResult(db, {20L, 0L}); // 20 and 0 means the num of downloads from cloud db by worker1 and worker2 LOGD("expect upload:worker1[primary key]:[local0 - local20), worker2[primary key]:[0 - 20)"); CheckCloudTotalCount({40L, 20L}); // 40 and 20 means the total num of worker1 and worker2 from the cloud db - syncProcess = {}; + g_syncProcess = {}; InitProcessForTest9(cloudCount, 0, expectProcess); - GetCallback(syncProcess, callback, expectProcess); + GetCallback(g_syncProcess, callback, expectProcess); LOGD("--------------the second sync-------------"); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); + CloseDb(); } HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest0010, TestSize.Level0) @@ -1314,11 +1389,10 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest0010, Test InsertUserTableRecord(db, 0, localCount, paddingSize, false); Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); int rowid = 27; UpdateAssetForTest(db, AssetOpType::NO_CHANGE, cloudCount, rowid++); @@ -1332,14 +1406,15 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest0010, Test UpdateAssetsForTest(db, AssetOpType::DELETE, id++); UpdateAssetsForTest(db, AssetOpType::UPDATE, id++); - syncProcess = {}; - GetCallback(syncProcess, callback, expectProcess); + g_syncProcess = {}; + GetCallback(g_syncProcess, callback, expectProcess); LOGD("--------------the second sync-------------"); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); CheckFillAssetForTest10(db); CheckFillAssetsForTest10(db); + CloseDb(); } /** @@ -1367,13 +1442,14 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest011, TestS } cv.notify_all(); }; - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); std::unique_lock uniqueLock(syncMutex); cv.wait(uniqueLock, [&syncFinish]() { return syncFinish; }); RuntimeContext::GetInstance()->StopTaskPool(); EXPECT_EQ(callCount, 2); // 2 is onProcess count + CloseDb(); } HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest012, TestSize.Level0) @@ -1385,33 +1461,199 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest012, TestS InsertUserTableRecord(db, 0, localCount, paddingSize, true); Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); InsertCloudTableRecord(localCount + cloudCount, cloudCount, paddingSize, false); InsertUserTableRecord(db, localCount + cloudCount, localCount, paddingSize, true); - syncProcess = {}; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + g_syncProcess = {}; + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); InsertCloudTableRecord(2 * (localCount + cloudCount), cloudCount, paddingSize, false); // 2 is offset InsertUserTableRecord(db, 2 * (localCount + cloudCount), localCount, paddingSize, false); // 2 is offset - syncProcess = {}; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + g_syncProcess = {}; + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); InsertCloudTableRecord(3 * (localCount + cloudCount), cloudCount, paddingSize, true); // 3 is offset InsertUserTableRecord(db, 3 * (localCount + cloudCount), localCount, paddingSize, true); // 3 is offset - syncProcess = {}; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + g_syncProcess = {}; + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); + CloseDb(); +} + +/* + * @tc.name: CloudSyncTest013 + * @tc.desc: test increment watermark when cloud db query data size is 0 + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhuwentao + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest013, TestSize.Level0) +{ + /** + * @tc.steps: insert some data into cloud db + * @tc.expected: return ok. + */ + int64_t paddingSize = 10; + int64_t cloudCount = 10; + SyncProcess syncProcess; + InsertCloudTableRecord(0, cloudCount, paddingSize, true); + /** + * @tc.steps: try to cloud sync + * @tc.expected: return ok. + */ + Query query = Query::Select().FromTable(g_tables); + CloudSyncStatusCallback callback = [&syncProcess](const std::map &process) { + LOGI("devices size = %d", process.size()); + ASSERT_EQ(process.size(), 1u); + syncProcess = std::move(process.begin()->second); + if (syncProcess.process == FINISHED) { + g_processCondition.notify_one(); + } + }; + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); WaitForSyncFinish(syncProcess, g_syncWaitTime); + uint32_t queryTimes = g_virtualCloudDb->GetQueryTimes(g_tableName1); + /** + * @tc.steps: insert some increment data into cloud db + * @tc.expected: return ok. + */ + VBucket data; + Timestamp now = TimeHelper::GetSysCurrentTime(); + data.insert_or_assign("name", "Cloud" + std::to_string(0)); + data.insert_or_assign("height", 166.0); // 166.0 is random double value + data.insert_or_assign("married", false); + data.insert_or_assign("age", 13L); + VBucket log; + log.insert_or_assign(CloudDbConstant::CREATE_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND); + log.insert_or_assign(CloudDbConstant::MODIFY_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND); + log.insert_or_assign(CloudDbConstant::DELETE_FIELD, false); + log.insert_or_assign(CloudDbConstant::CREATE_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND); + log.insert_or_assign(CloudDbConstant::CURSOR_FIELD, "0123"); + g_virtualCloudDb->SetIncrementData(g_tableName1, data, log); + syncProcess.process = PREPARED; + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(syncProcess, g_syncWaitTime); + uint32_t lastQueryTimes = g_virtualCloudDb->GetQueryTimes(g_tableName1); + ASSERT_EQ(lastQueryTimes - queryTimes, 2u); + CloseDb(); +} + +void TestSyncForStatus(RelationalStoreDelegate *delegate, DBStatus expectStatus) +{ + std::mutex dataMutex; + std::condition_variable cv; + bool finish = false; + DBStatus res = OK; + CloudSyncStatusCallback callback = [&dataMutex, &cv, &finish, &res]( + const std::map &process) { + std::map syncProcess; + { + std::lock_guard autoLock(dataMutex); + syncProcess = process; + if (syncProcess[DEVICE_CLOUD].process == FINISHED) { + finish = true; + } + res = syncProcess[DEVICE_CLOUD].errCode; + } + cv.notify_one(); + }; + Query query = Query::Select().FromTable({g_tableName3}); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + { + std::unique_lock uniqueLock(dataMutex); + cv.wait(uniqueLock, [&finish] { + return finish; + }); + } + EXPECT_EQ(res, expectStatus); + RuntimeContext::GetInstance()->StopTaskPool(); +} + +/* + * @tc.name: CloudSyncTest015 + * @tc.desc: Test sync with cloud error + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest015, TestSize.Level0) +{ + g_virtualCloudDb->SetActionStatus(CLOUD_NETWORK_ERROR); + TestSyncForStatus(g_delegate, CLOUD_NETWORK_ERROR); + + g_virtualCloudDb->SetActionStatus(CLOUD_SYNC_UNSET); + TestSyncForStatus(g_delegate, CLOUD_SYNC_UNSET); + + g_virtualCloudDb->SetActionStatus(CLOUD_FULL_RECORDS); + TestSyncForStatus(g_delegate, CLOUD_FULL_RECORDS); + + g_virtualCloudDb->SetActionStatus(CLOUD_LOCK_ERROR); + TestSyncForStatus(g_delegate, CLOUD_LOCK_ERROR); + + g_virtualCloudDb->SetActionStatus(DB_ERROR); + TestSyncForStatus(g_delegate, CLOUD_ERROR); + + g_virtualCloudDb->SetActionStatus(OK); + CloseDb(); +} + +/* + * @tc.name: CloudSyncTest014 + * @tc.desc: Test sync with s4 + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncTest014, TestSize.Level0) +{ + auto adapter = std::make_shared(); + RuntimeConfig::SetProcessSystemAPIAdapter(adapter); + + // sync failed because get security option failed + adapter->ForkGetSecurityOption([](const std::string&, SecurityOption &option) { + option.securityLabel = S0; + return DB_ERROR; + }); + Query query = Query::Select().FromTable({g_tableName3}); + EXPECT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, nullptr, g_syncWaitTime), + SECURITY_OPTION_CHECK_ERROR); + + // sync failed because get S4 + adapter->ForkGetSecurityOption([](const std::string&, SecurityOption &option) { + option.securityLabel = S4; + return NOT_SUPPORT; + }); + Query invalidQuery = Query::Select().FromTable({g_tableName3}).PrefixKey({'k'}); + EXPECT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, invalidQuery, nullptr, g_syncWaitTime), + NOT_SUPPORT); + + // sync failed because get S4 + adapter->ForkGetSecurityOption([](const std::string&, SecurityOption &option) { + option.securityLabel = S4; + return OK; + }); + EXPECT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, nullptr, g_syncWaitTime), + SECURITY_OPTION_CHECK_ERROR); + + // sync failed because S4 has been cached + adapter->ForkGetSecurityOption([](const std::string&, SecurityOption &option) { + option.securityLabel = S0; + return OK; + }); + EXPECT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, nullptr, g_syncWaitTime), + SECURITY_OPTION_CHECK_ERROR); + RuntimeConfig::SetProcessSystemAPIAdapter(nullptr); + CloseDb(); } /* @@ -1428,11 +1670,11 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, DataNotifier001, TestSi InsertRecordWithoutPk2LocalAndCloud(db, 0, localCount, paddingSize); Query query = Query::Select().FromTable({g_tableName3}); std::vector expectProcess; - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); + CloseDb(); } /** @@ -1450,17 +1692,16 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncAssetTest001, InsertCloudTableRecord(0, localCount / g_arrayHalfSub, paddingSize, false); Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); CheckAssetAfterDownload(db, localCount); CheckAllAssetAfterUpload(localCount); + CloseDb(); } -#ifdef MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA /* * @tc.name: MannualNotify001 * @tc.desc: Test FLAG_ONLY mode of RemoveDeviceData @@ -1476,14 +1717,14 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, MannualNotify001, TestS Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; InitProcessForMannualSync1(expectProcess); - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback, g_syncWaitTime), + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); - + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); + CloseDb(); } + /* * @tc.name: CleanCloudDataTest001 * @tc.desc: Test FLAG_ONLY mode of RemoveDeviceData @@ -1501,16 +1742,16 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CleanCloudDataTest001, Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; InitProcessForCleanCloudData1(cloudCount, localCount, expectProcess); - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback, g_syncWaitTime), + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); std::string device = ""; CheckCloudRecordNum(db, g_tables, {20, 20}); - ASSERT_EQ(delegate->RemoveDeviceData(device, FLAG_ONLY), DBStatus::OK); + ASSERT_EQ(g_delegate->RemoveDeviceData(device, FLAG_ONLY), DBStatus::OK); CheckCleanLogNum(db, g_tables, 0); + CloseDb(); } /* @@ -1530,17 +1771,281 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CleanCloudDataTest002, Query query = Query::Select().FromTable(g_tables); std::vector expectProcess; InitProcessForCleanCloudData1(cloudCount, localCount, expectProcess); - SyncProcess syncProcess; CloudSyncStatusCallback callback; - GetCallback(syncProcess, callback, expectProcess); - ASSERT_EQ(delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback, g_syncWaitTime), + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback, g_syncWaitTime), DBStatus::OK); - WaitForSyncFinish(syncProcess, g_syncWaitTime); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); std::string device = ""; CheckCloudRecordNum(db, g_tables, {20, 20}); // 20 means cloud data num - ASSERT_EQ(delegate->RemoveDeviceData(device, FLAG_AND_DATA), DBStatus::OK); + ASSERT_EQ(g_delegate->RemoveDeviceData(device, FLAG_AND_DATA), DBStatus::OK); CheckCleanDataAndLogNum(db, g_tables, 0, {localCount, 0}); + CloseDb(); +} + +/* + * @tc.name: CleanCloudDataTest003 + * @tc.desc: Test FLAG_ONLY mode of RemoveDeviceData concurrently with Sync + * @tc.type: FUNC + * @tc.require: + * @tc.author: huangboxin + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CleanCloudDataTest003, TestSize.Level0) +{ + /** + * @tc.steps: step1. make data: 10 records on local and 20 records on cloud + */ + int64_t paddingSize = 10; + int localCount = 10; + int cloudCount = 20; + InsertCloudTableRecord(0, cloudCount, paddingSize, false); + InsertUserTableRecord(db, 0, localCount, paddingSize, false); + /** + * @tc.steps: step2. call Sync with cloud force pull strategy, and after that, local will has 20 records. + */ + Query query = Query::Select().FromTable(g_tables); + std::vector expectProcess; + InitProcessForCleanCloudData1(cloudCount, localCount, expectProcess); + CloudSyncStatusCallback callback; + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback, g_syncWaitTime), + DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); + CheckCloudRecordNum(db, g_tables, {20, 20}); // 20 means cloud data num + + /** + * @tc.steps: step3. insert 10 records into local, so local will has 20 local records and 20 cloud records. + */ + InsertUserTableRecord(db, 0, localCount, paddingSize, false); + /** + * @tc.steps: step4. call RemoveDeviceData synchronize with Sync with cloud force push strategy. + */ + g_syncProcess = {}; + std::vector expectProcess2; + InitProcessForCleanCloudData1(cloudCount, localCount, expectProcess2); + CloudSyncStatusCallback callback2; + GetCallback(g_syncProcess, callback2, expectProcess2); + std::string device = ""; + + std::thread thread1([&]() { + ASSERT_EQ(g_delegate->RemoveDeviceData(device, FLAG_AND_DATA), DBStatus::OK); + }); + std::condition_variable cv; + std::thread thread2([&]() { + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PULL, query, callback2, g_syncWaitTime), + DBStatus::OK); + LOGD("-------------------sync end--------------"); + }); + thread1.join(); + thread2.join(); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); + RuntimeContext::GetInstance()->StopTaskPool(); + CheckCleanLogNum(db, g_tables, 20); + LOGD("================================== test clean cloud data 003 end ==================================="); + CloseDb(); +} + +/* + * @tc.name: CalPrimaryKeyHash001 + * @tc.desc: Test CalcPrimaryKeyHash interface when primary key is string + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhuwentao + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CalPrimaryKeyHash001, TestSize.Level0) +{ + /** + * @tc.steps: step1. local insert one data, primary key is string + * @tc.expected: OK. + */ + std::string photo(1u, 'v'); + std::string name = "Local0"; + std::map primaryKey = {{"name", name}}; + string sql = "INSERT OR REPLACE INTO " + g_tableName1 + + " (name, height, married, photo, age) VALUES ('Local" + std::to_string(0) + + "', '175.8', '0', '" + photo + "', '18');"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); + std::vector result = RelationalStoreManager::CalcPrimaryKeyHash(primaryKey); + EXPECT_NE(result.size(), 0u); + std::string logTableName = RelationalStoreManager::GetDistributedLogTableName(g_tableName1); + /** + * @tc.steps: step1. query timestamp use hashKey + * @tc.expected: OK. + */ + std::string querysql = "select timestamp/10000 from " + logTableName + " where hash_key=?"; + sqlite3_stmt *statement = nullptr; + int errCode = SQLiteUtils::GetStatement(db, querysql, statement); + EXPECT_EQ(errCode, E_OK); + errCode = SQLiteUtils::BindBlobToStatement(statement, 1, result); // 1 means hashkey index + if (errCode != E_OK) { + SQLiteUtils::ResetStatement(statement, true, errCode); + return; + } + errCode = SQLiteUtils::StepWithRetry(statement, false); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + Timestamp timestamp = static_cast(sqlite3_column_int64(statement, 0)); + LOGD("get timestamp = %" PRIu64, timestamp); + errCode = E_OK; + } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + errCode = -E_NOT_FOUND; + } + EXPECT_EQ(errCode, E_OK); + SQLiteUtils::ResetStatement(statement, true, errCode); + CloseDb(); +} + +/* + * @tc.name: CalPrimaryKeyHash002 + * @tc.desc: Test CalcPrimaryKeyHash interface when primary key is int + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhuwentao + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CalPrimaryKeyHash002, TestSize.Level0) +{ + /** + * @tc.steps: step1. local insert one data, primary key is int + * @tc.expected: OK. + */ + int64_t id = 1; + std::map primaryKey = {{"id", id}}; + std::string sql = "INSERT OR REPLACE INTO " + g_tableName2 + + " (id, name, height) VALUES ('" + '1' + "', 'Local" + + std::to_string(0) + "', '155.10');"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); + std::vector result = RelationalStoreManager::CalcPrimaryKeyHash(primaryKey); + EXPECT_NE(result.size(), 0u); + std::string logTableName = RelationalStoreManager::GetDistributedLogTableName(g_tableName2); + /** + * @tc.steps: step1. query timestamp use hashKey + * @tc.expected: OK. + */ + std::string querysql = "select timestamp/10000 from " + logTableName + " where hash_key=?"; + sqlite3_stmt *statement = nullptr; + int errCode = SQLiteUtils::GetStatement(db, querysql, statement); + EXPECT_EQ(errCode, E_OK); + errCode = SQLiteUtils::BindBlobToStatement(statement, 1, result); // 1 means hashkey index + if (errCode != E_OK) { + SQLiteUtils::ResetStatement(statement, true, errCode); + return; + } + errCode = SQLiteUtils::StepWithRetry(statement, false); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + Timestamp timestamp = static_cast(sqlite3_column_int64(statement, 0)); + LOGD("get timestamp = %" PRIu64, timestamp); + errCode = E_OK; + } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + errCode = -E_NOT_FOUND; + } + EXPECT_EQ(errCode, E_OK); + SQLiteUtils::ResetStatement(statement, true, errCode); + CloseDb(); +} + +/* + * @tc.name: CloudSyncAssetTest002 + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: huangboxin + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncAssetTest002, TestSize.Level0) +{ + int64_t paddingSize = 10; + int localCount = 3; + int cloudCount = 3; + InsertCloudTableRecord(0, cloudCount, paddingSize, true); + InsertUserTableRecord(db, 0, localCount, paddingSize, false); + Query query = Query::Select().FromTable(g_tables); + std::vector expectProcess; + CloudSyncStatusCallback callback; + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_FORCE_PUSH, query, callback, g_syncWaitTime), + DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); + CloseDb(); +} + +/* + * @tc.name: CloudSyncAssetTest003 + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncAssetTest003, TestSize.Level0) +{ + int64_t paddingSize = 10; + int localCount = 3; + int cloudCount = 3; + InsertCloudTableRecord(0, cloudCount, paddingSize, true); + InsertUserTableRecord(db, 0, localCount, paddingSize, false); + UpdateLocalAssetsToRepeat(db, 1); + Query query = Query::Select().FromTable(g_tables); + std::vector expectProcess; + CloudSyncStatusCallback callback = [](const std::map &process) { + ASSERT_EQ(process.size(), 1u); + g_syncProcess = std::move(process.begin()->second); + + if (g_syncProcess.process == FINISHED) { + g_processCondition.notify_one(); + } + }; + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), + DBStatus::OK); + { + std::unique_lock lock(g_processMutex); + g_processCondition.wait(lock, []() { + return g_syncProcess.process == FINISHED; + }); + ASSERT_EQ(g_syncProcess.errCode, DBStatus::CLOUD_ERROR); + } + CloseDb(); +} + +/* + * @tc.name: CloudSyncAssetTest004 + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalSyncTest, CloudSyncAssetTest004, TestSize.Level0) +{ + int64_t paddingSize = 10; + int localCount = 3; + int cloudCount = 3; + InsertUserTableRecord(db, 0, localCount, paddingSize, false); + InsertCloudTableRecord(0, cloudCount, paddingSize, false); + Query query = Query::Select().FromTable(g_tables); + std::vector expectProcess; + CloudSyncStatusCallback callback; + GetCallback(g_syncProcess, callback, expectProcess); + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback, g_syncWaitTime), + DBStatus::OK); + WaitForSyncFinish(g_syncProcess, g_syncWaitTime); + + UpdateDiffType(localCount); + g_syncProcess = {}; + CloudSyncStatusCallback callback1 = [](const std::map &process) { + ASSERT_EQ(process.size(), 1u); + g_syncProcess = std::move(process.begin()->second); + if (g_syncProcess.process == FINISHED) { + g_processCondition.notify_one(); + } + }; + + ASSERT_EQ(g_delegate->Sync({DEVICE_CLOUD}, SYNC_MODE_CLOUD_MERGE, query, callback1, g_syncWaitTime), + DBStatus::OK); + { + std::unique_lock lock(g_processMutex); + g_processCondition.wait(lock, []() { + return g_syncProcess.process == FINISHED; + }); + ASSERT_EQ(g_syncProcess.errCode, DBStatus::OK); + } + CheckDiffTypeAsset(db); + CloseDb(); } -#endif // MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA } #endif // RELATIONAL_STORE diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_meta_data_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_meta_data_test.cpp index cf37722e..8d34a059 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_meta_data_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_meta_data_test.cpp @@ -99,7 +99,7 @@ namespace { void SetAndGetWaterMark(TableName tableName, CloudWaterMark mark) { CloudWaterMark retMark; - EXPECT_EQ(g_storageProxy->PutCloudWaterMark(tableName, mark), E_OK); + EXPECT_EQ(g_storageProxy->SetCloudWaterMark(tableName, mark), E_OK); EXPECT_EQ(g_storageProxy->GetCloudWaterMark(tableName, retMark), E_OK); EXPECT_EQ(retMark, mark); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_save_cloud_data_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_save_cloud_data_test.cpp index 05ff36f7..0f383bec 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_save_cloud_data_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_save_cloud_data_test.cpp @@ -47,6 +47,8 @@ namespace { IRelationalStore *g_store = nullptr; RelationalStoreDelegate *g_delegate = nullptr; ICloudSyncStorageInterface *g_cloudStore = nullptr; + constexpr const int64_t BASE_MODIFY_TIME = 12345678L; + constexpr const int64_t BASE_CREATE_TIME = 12345679L; enum class PrimaryKeyType { NO_PRIMARY_KEY, @@ -80,8 +82,8 @@ namespace { void SetCloudSchema(PrimaryKeyType pkType, bool nullable) { TableSchema tableSchema; - Field field1 = { "id", TYPE_INDEX, - pkType == PrimaryKeyType::SINGLE_PRIMARY_KEY || pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY, true }; + bool isIdPk = pkType == PrimaryKeyType::SINGLE_PRIMARY_KEY || pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY; + Field field1 = { "id", TYPE_INDEX, isIdPk, !isIdPk }; Field field2 = { "name", TYPE_INDEX, pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY, true }; Field field3 = { "age", TYPE_INDEX, pkType == PrimaryKeyType::COMPOSITE_PRIMARY_KEY, true }; Field field4 = { "sex", TYPE_INDEX, false, nullable }; @@ -395,7 +397,6 @@ namespace { * @tc.name: GetInfoByPrimaryKeyOrGidTest011 * @tc.desc: Test GetInfoByPrimaryKeyOrGid when table has composite primary key and gid match, * primary key mismatch - * primary key mismatch; * @tc.type: FUNC * @tc.require: * @tc.author: zhangshijie @@ -405,6 +406,53 @@ namespace { GetInfoByPrimaryKeyOrGidTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, "abcd0", 11L, E_OK, false); } + void VbucketWithoutPrimaryDataTest(PrimaryKeyType pkType) + { + /** + * @tc.steps:step1. create db, create table. + * @tc.expected: step1. return ok. + */ + PrepareDataBase(g_tableName, pkType); + + /** + * @tc.steps:step2. call GetInfoByPrimaryKeyOrGid. + * @tc.expected: step2. return E_OK. + */ + std::shared_ptr storageProxy = GetStorageProxy(g_cloudStore); + ASSERT_NE(storageProxy, nullptr); + EXPECT_EQ(storageProxy->StartTransaction(), E_OK); + VBucket vBucket; + std::string gid = g_gid + std::to_string(0); + vBucket[CloudDbConstant::GID_FIELD] = gid; + DataInfoWithLog dataInfoWithLog; + VBucket assetInfo; + EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfoWithLog, assetInfo), E_OK); + } + + /** + * @tc.name: GetInfoByPrimaryKeyOrGidTest012 + * @tc.desc: Test GetInfoByPrimaryKeyOrGid when vbucket doesn't contain pk data and gid match, + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangshijie + */ + HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest012, TestSize.Level0) + { + VbucketWithoutPrimaryDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY); + } + + /** + * @tc.name: GetInfoByPrimaryKeyOrGidTest013 + * @tc.desc: Test GetInfoByPrimaryKeyOrGid when vbucket doesn't contain pk(composite pk) data and gid match, + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangshijie + */ + HWTEST_F(DistributedDBCloudSaveCloudDataTest, GetInfoByPrimaryKeyOrGidTest013, TestSize.Level0) + { + VbucketWithoutPrimaryDataTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY); + } + void ConstructDownloadData(DownloadData &downloadData, GidType gidType, bool nullable, bool vBucketContains) { for (int i = 0; i < 7; i++) { // 7 is record counts @@ -559,7 +607,7 @@ namespace { */ HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest006, TestSize.Level0) { - SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_EMPTY); + SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_EMPTY, true, true, -E_CLOUD_ERROR); } /** @@ -572,7 +620,7 @@ namespace { */ HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest007, TestSize.Level0) { - SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_EMPTY, true, false); + SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_MATCH, true, false); } /** @@ -614,35 +662,23 @@ namespace { /** * @tc.name: PutCloudSyncDataTest011 - * @tc.desc: Test save cloud data into table with SINGLE_PRIMARY_KEY primary key, gid is empty, primary key mismatch - * @tc.type: FUNC - * @tc.require: - * @tc.author: zhangshijie - */ - HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest011, TestSize.Level0) - { - SaveCloudDataTest(PrimaryKeyType::SINGLE_PRIMARY_KEY, GidType::GID_EMPTY); - } - - /** - * @tc.name: PutCloudSyncDataTest012 * @tc.desc: Test save cloud data into table with composite primary key, invalid gid * @tc.type: FUNC * @tc.require: * @tc.author: zhangshijie */ - HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest012, TestSize.Level0) + HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest011, TestSize.Level0) { SaveCloudDataTest(PrimaryKeyType::COMPOSITE_PRIMARY_KEY, GidType::GID_INVALID, true, true, -E_CLOUD_ERROR); } void ConstructMultiDownloadData(DownloadData &downloadData, GidType gidType) { - for (int i = 0; i < 5; i++) { // 5 is record counts + for (int i = 0; i < 6; i++) { // 6 is record counts VBucket vBucket; - if (i == 0) { + if (i < 1) { // UPDATE_TIMESTAMP doesn't contain pk vBucket["id"] = 1L + i; - } else { + } else if (i > 1) { vBucket["id"] = 10L + i; // 10 is id offset for cloud data } @@ -654,7 +690,11 @@ namespace { vBucket["image"] = std::vector(1, i); std::string gid; if (gidType == GidType::GID_MATCH) { - gid = g_gid + std::to_string(i); + if (i <= 1) { // first 2 exists in local + gid = g_gid + std::to_string(i); + } else { + gid = g_gid + std::to_string(10 + i); // 10 is id offset for cloud data + } } else if (gidType == GidType::GID_EMPTY) { std::string emptyGid = ""; gid = emptyGid; @@ -663,25 +703,25 @@ namespace { } vBucket[CloudDbConstant::GID_FIELD] = gid; - int64_t cTime = 12345678L + i; + int64_t cTime = BASE_CREATE_TIME + i; vBucket[CloudDbConstant::CREATE_FIELD] = cTime; - int64_t mTime = 12345679L + i; + int64_t mTime = BASE_MODIFY_TIME + i; vBucket[CloudDbConstant::MODIFY_FIELD] = mTime; downloadData.data.push_back(vBucket); } - downloadData.opType = { OpType::UPDATE, OpType::INSERT, OpType::INSERT, + downloadData.opType = { OpType::UPDATE, OpType::UPDATE_TIMESTAMP, OpType::INSERT, OpType::INSERT, OpType::INSERT, OpType::NOT_HANDLE }; } /** - * @tc.name: PutCloudSyncDataTest013 + * @tc.name: PutCloudSyncDataTest012 * @tc.desc: Test save cloud data into table with no primary key, multi cloud data * @tc.type: FUNC * @tc.require: * @tc.author: zhangshijie */ - HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest013, TestSize.Level0) + HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest012, TestSize.Level0) { /** * @tc.steps:step1. create db, create table. @@ -702,4 +742,160 @@ namespace { EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK); EXPECT_EQ(storageProxy->Commit(), E_OK); } + + /** + * @tc.name: PutCloudSyncDataTest013 + * @tc.desc: Test save cloud data with type = update_timestamp + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangshijie + */ + HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest013, TestSize.Level0) + { + /** + * @tc.steps:step1. create db, create table. + * @tc.expected: step1. return ok. + */ + PrepareDataBase(g_tableName, PrimaryKeyType::SINGLE_PRIMARY_KEY, true); + + std::string sql = "delete from " + g_tableName + " where id = 2"; + sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX); + EXPECT_NE(db, nullptr); + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK); + /** + * @tc.steps:step2. call PutCloudSyncData + * @tc.expected: step2. return ok. + */ + std::shared_ptr storageProxy = GetStorageProxy(g_cloudStore); + ASSERT_NE(storageProxy, nullptr); + EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK); + + DownloadData downloadData; + ConstructMultiDownloadData(downloadData, GidType::GID_MATCH); + EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK); + EXPECT_EQ(storageProxy->Commit(), E_OK); + + /** + * @tc.steps:step3. verify data + * @tc.expected: step3. verify data ok. + */ + sql = "select device, timestamp, flag from " + DBCommon::GetLogTableName(g_tableName) + + " where data_key = -1 and cloud_gid = ''"; + int count = 0; + int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) { + std::string device = "cloud"; + std::vector deviceVec; + (void)SQLiteUtils::GetColumnBlobValue(stmt, 0, deviceVec); // 0 is device + std::string getDevice; + DBCommon::VectorToString(deviceVec, getDevice); + EXPECT_EQ(device, getDevice); + EXPECT_EQ(sqlite3_column_int64(stmt, 1), BASE_MODIFY_TIME + 1); + EXPECT_EQ(sqlite3_column_int(stmt, 2), 1); // 2 is flag + count++; + return OK; + }); + EXPECT_EQ(errCode, E_OK); + EXPECT_EQ(count, 1); + EXPECT_EQ(sqlite3_close_v2(db), E_OK); + } + + /** + * @tc.name: PutCloudSyncDataTest014 + * @tc.desc: Test PutCloudSyncData when vbucket doesn't contain pk data and gid match, + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangshijie + */ + HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest014, TestSize.Level0) + { + /** + * @tc.steps:step1. create db, create table. + * @tc.expected: step1. return ok. + */ + PrepareDataBase(g_tableName, PrimaryKeyType::SINGLE_PRIMARY_KEY); + + /** + * @tc.steps:step2. construct data without primary key value, call PutCloudSyncData. + * @tc.expected: step2. return E_OK. + */ + std::shared_ptr storageProxy = GetStorageProxy(g_cloudStore); + ASSERT_NE(storageProxy, nullptr); + EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK); + + DownloadData downloadData; + VBucket vBucket; + std::string gid = g_gid + std::to_string(0); + vBucket[CloudDbConstant::GID_FIELD] = gid; + vBucket[CloudDbConstant::MODIFY_FIELD] = BASE_MODIFY_TIME; + downloadData.data.push_back(vBucket); + downloadData.opType = { OpType::DELETE }; + EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK); + EXPECT_EQ(storageProxy->Commit(), E_OK); + } + + /** + * @tc.name: PutCloudSyncDataTest015 + * @tc.desc: Test clear gid and ONLY_UPDATE_GID + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangshijie + */ + HWTEST_F(DistributedDBCloudSaveCloudDataTest, PutCloudSyncDataTest015, TestSize.Level0) + { + /** + * @tc.steps:step1. create db, create table. + * @tc.expected: step1. return ok. + */ + PrepareDataBase(g_tableName, PrimaryKeyType::SINGLE_PRIMARY_KEY); + + /** + * @tc.steps:step2. construct data type = clear_gid, call PutCloudSyncData. + * @tc.expected: step2. return E_OK. + */ + std::shared_ptr storageProxy = GetStorageProxy(g_cloudStore); + ASSERT_NE(storageProxy, nullptr); + EXPECT_EQ(storageProxy->StartTransaction(TransactType::IMMEDIATE), E_OK); + + DownloadData downloadData; + for (int i = 0; i < 2; i++) { // 2 is record count + VBucket vBucket; + std::string gid = g_gid + std::to_string(i * 4); // 4 is data index + vBucket[CloudDbConstant::GID_FIELD] = gid; + vBucket[CloudDbConstant::MODIFY_FIELD] = BASE_MODIFY_TIME; + downloadData.data.push_back(vBucket); + } + downloadData.opType = { OpType::ONLY_UPDATE_GID, OpType::CLEAR_GID }; + EXPECT_EQ(storageProxy->PutCloudSyncData(g_tableName, downloadData), E_OK); + EXPECT_EQ(storageProxy->Commit(), E_OK); + + /** + * @tc.steps:step3. verify data + * @tc.expected: step3. verify data ok. + */ + std::string sql = "select cloud_gid, flag from " + DBCommon::GetLogTableName(g_tableName) + + " where data_key = 1 or data_key = 5"; + int count = 0; + sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX); + EXPECT_NE(db, nullptr); + int errCode = RelationalTestUtils::ExecSql(db, sql, nullptr, [&count] (sqlite3_stmt *stmt) { + std::string gid = ""; + if (count == 0) { + gid = g_gid + "0"; + } + const unsigned char *val = sqlite3_column_text(stmt, 0); + EXPECT_TRUE(val != nullptr); + std::string getGid = reinterpret_cast(val); + LOGD("GET GID = %s", getGid.c_str()); + EXPECT_EQ(getGid, gid); + if (count == 1) { + int flag = sqlite3_column_int(stmt, 1); + EXPECT_EQ(flag & 0x04, 0); // 0x04 is binay num of b100, clear gid will clear 2th bit of flag + } + count++; + return OK; + }); + EXPECT_EQ(errCode, E_OK); + EXPECT_EQ(count, 2); // 2 is result count + EXPECT_EQ(sqlite3_close_v2(db), E_OK); + } } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_cloud_syncable_storage_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_cloud_syncable_storage_test.cpp index 7044a483..b41bc2c5 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_cloud_syncable_storage_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_cloud_syncable_storage_test.cpp @@ -105,9 +105,13 @@ void CreateAndInitUserTable(int64_t count, int64_t photoSize) std::string photo(photoSize, 'v'); std::vector assetBlob; std::vector assetsBlob; + Asset asset = g_localAsset; + int id = 0; Assets assets; - assets.push_back(g_localAsset); - assets.push_back(g_localAsset); + asset.name = g_localAsset.name + std::to_string(id++); + assets.push_back(asset); + asset.name = g_localAsset.name + std::to_string(id++); + assets.push_back(asset); int errCode; ASSERT_EQ(RuntimeContext::GetInstance()->AssetToBlob(g_localAsset, assetBlob), E_OK); ASSERT_EQ(RuntimeContext::GetInstance()->AssetsToBlob(assets, assetsBlob), E_OK); @@ -158,7 +162,7 @@ void InitLogData(int64_t insCount, int64_t updCount, int64_t delCount, int64_t e sqlite3_close(db); } -void UpdateLogGid(int64_t count) +void InitLogGid(int64_t count) { sqlite3 *db = nullptr; ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK); @@ -212,7 +216,7 @@ void SetDbSchema(const TableSchema &tableSchema) EXPECT_EQ(g_cloudStore->SetCloudDbSchema(dataBaseSchema), E_OK); } -void InitUserAndLogForAsset(int64_t insCount, int64_t photoSize) +void InitUserDataForAssetTest(int64_t insCount, int64_t photoSize) { sqlite3 *db = nullptr; ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK); @@ -220,7 +224,6 @@ void InitUserAndLogForAsset(int64_t insCount, int64_t photoSize) sqlite3_close(db); EXPECT_EQ(g_delegate->CreateDistributedTable(g_tableName, DistributedDB::CLOUD_COOPERATION), OK); CreateAndInitUserTable(insCount, photoSize); - UpdateLogGid(insCount); SetDbSchema(g_tableSchema); } @@ -990,7 +993,8 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetInfoByPrimaryKeyOrG { int64_t insCount = 100; int64_t photoSize = 10; - InitUserAndLogForAsset(insCount, photoSize); + InitUserDataForAssetTest(insCount, photoSize); + InitLogGid(insCount); EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK); for (int i = 1; i <= insCount; i++) { @@ -1007,8 +1011,9 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetInfoByPrimaryKeyOrG Asset asset = std::get(entry1->second); EXPECT_EQ(asset.name, "Phone"); Assets assets = std::get(entry2->second); + int id = 0; for (const auto &item: assets) { - EXPECT_EQ(item.name, "Phone"); + EXPECT_EQ(item.name, "Phone" + std::to_string(id++)); } } EXPECT_EQ(g_storageProxy->Commit(), E_OK); @@ -1018,7 +1023,8 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, PutCloudSyncData001, T { int64_t insCount = 10; int64_t photoSize = 10; - InitUserAndLogForAsset(insCount, photoSize); + InitUserDataForAssetTest(insCount, photoSize); + InitLogGid(insCount); DownloadData downloadData; ConstructMultiDownloadData(insCount, downloadData); @@ -1034,7 +1040,8 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset001, Tes { int64_t insCount = 10; int64_t photoSize = 10; - InitUserAndLogForAsset(insCount, photoSize); + InitUserDataForAssetTest(insCount, photoSize); + InitLogGid(insCount); fillCloudAssetTest(insCount, AssetStatus::NORMAL, false); fillCloudAssetTest(insCount, AssetStatus::DOWNLOADING, false); fillCloudAssetTest(insCount, AssetStatus::ABNORMAL, false); @@ -1047,7 +1054,8 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset002, Tes { int64_t insCount = 10; int64_t photoSize = 10; - InitUserAndLogForAsset(insCount, photoSize); + InitUserDataForAssetTest(insCount, photoSize); + InitLogGid(insCount); sqlite3 *db = nullptr; ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK); @@ -1060,6 +1068,8 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset002, Tes SQLiteUtils::ResetStatement(stmt, true, errCode); CloudSyncData syncData(g_tableName); + EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK); + ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::UPDATE, syncData), E_OK); syncData.updData.rowid.push_back(1L); VBucket bucket1; Asset asset = g_localAsset; @@ -1073,7 +1083,8 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset002, Tes bucket1.insert_or_assign("asserts", assets); syncData.updData.assets.push_back(bucket1); syncData.updData.timestamp.push_back(timeStamp); - ASSERT_EQ(g_storageProxy->FillCloudAssetForUpload(syncData), E_OK); + ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::UPDATE, syncData), E_OK); + EXPECT_EQ(g_storageProxy->Commit(), E_OK); ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT assert, asserts FROM " + g_tableName + " WHERE rowid = 1;", stmt), E_OK); @@ -1083,5 +1094,102 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset002, Tes SQLiteUtils::ResetStatement(stmt, true, errCode); sqlite3_close(db); } + +/** + * @tc.name: FillCloudAsset003 + * @tc.desc: The twice fill have different assert columns + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset003, TestSize.Level0) +{ + int64_t insCount = 2; + int64_t photoSize = 10; + InitUserDataForAssetTest(insCount, photoSize); + InitLogGid(insCount); + + sqlite3 *db = nullptr; + ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK); + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName) + + " WHERE data_key in ('1', '2');", stmt), E_OK); + ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)); + int64_t timeStamp1 = static_cast(sqlite3_column_int64(stmt, 0)); + int64_t timeStamp2 = static_cast(sqlite3_column_int64(stmt, 1)); + int errCode; + SQLiteUtils::ResetStatement(stmt, true, errCode); + sqlite3_close(db); + + CloudSyncData syncData(g_tableName); + syncData.updData.rowid.push_back(1L); + syncData.updData.rowid.push_back(2L); + VBucket bucket1, bucket2; + Asset asset = g_localAsset; + asset.size = "888"; + asset.status = static_cast(AssetStatus::UPDATE); + Assets assets; + assets.push_back(asset); + assets.push_back(asset); + bucket1.insert_or_assign("assert", asset); + bucket2.insert_or_assign("assert", asset); + bucket2.insert_or_assign("asserts", assets); + syncData.updData.assets.push_back(bucket1); + syncData.updData.assets.push_back(bucket2); + syncData.updData.timestamp.push_back(timeStamp1); + syncData.updData.timestamp.push_back(timeStamp2); + EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK); + ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::UPDATE, syncData), E_OK); + EXPECT_EQ(g_storageProxy->Commit(), E_OK); +} + +/** + * @tc.name: FillCloudAsset004 + * @tc.desc: Test fill asset for insert type + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudAsset004, TestSize.Level0) +{ + int64_t insCount = 2; + int64_t photoSize = 10; + InitUserDataForAssetTest(insCount, photoSize); + + sqlite3 *db = nullptr; + ASSERT_EQ(sqlite3_open(g_storePath.c_str(), &db), SQLITE_OK); + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, "SELECT timestamp FROM " + DBCommon::GetLogTableName(g_tableName) + + " WHERE data_key in ('1', '2');", stmt), E_OK); + ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)); + std::vector timeVector; + timeVector.push_back(static_cast(sqlite3_column_int64(stmt, 0))); + timeVector.push_back(static_cast(sqlite3_column_int64(stmt, 1))); + int errCode; + SQLiteUtils::ResetStatement(stmt, true, errCode); + sqlite3_close(db); + + CloudSyncData syncData(g_tableName); + for (int64_t i = 1; i <= insCount; ++i) { + syncData.insData.rowid.push_back(i); + VBucket bucket1; + bucket1.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(i)); + syncData.insData.extend.push_back(bucket1); + + VBucket bucket2; + Asset asset = g_localAsset; + asset.size = "888"; + Assets assets; + assets.push_back(asset); + assets.push_back(asset); + bucket2.insert_or_assign("assert", asset); + bucket2.insert_or_assign("asserts", assets); + syncData.insData.assets.push_back(bucket2); + syncData.insData.timestamp.push_back(timeVector[i - 1]); + } + EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK); + ASSERT_EQ(g_storageProxy->FillCloudGidAndAsset(OpType::INSERT, syncData), E_OK); + EXPECT_EQ(g_storageProxy->Commit(), E_OK); +} } #endif // RELATIONAL_STORE \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/cloud_syncer_test.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/cloud_syncer_test.h index 54400fce..9175fdb4 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/cloud_syncer_test.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/cloud_syncer_test.h @@ -45,7 +45,7 @@ public: cloudTaskInfos_[taskId].taskId = taskId; currentContext_.currentTaskId = taskId; currentContext_.tableName = "TestTable" + std::to_string(taskId); - currentContext_.notifier = std::make_shared(); + currentContext_.notifier = std::make_shared(this); currentContext_.notifier->Init({currentContext_.tableName}, { "cloud" }); currentContext_.strategy = std::make_shared(); closed_ = false; @@ -224,9 +224,14 @@ public: } std::map TestTagAssetsInSingleRecord( - VBucket &CoveredData, VBucket &BeCoveredData, bool WriteToCoveredData = false) + VBucket &coveredData, VBucket &beCoveredData, bool WriteToCoveredData = false) { - return TagAssetsInSingleRecord(CoveredData, BeCoveredData, WriteToCoveredData); + return TagAssetsInSingleRecord(coveredData, beCoveredData, WriteToCoveredData); + } + + bool TestIsDataContainDuplicateAsset(std::vector &assetFields, VBucket &data) + { + return IsDataContainDuplicateAsset(assetFields, data); } void SetCloudWaterMarks(const TableName &tableName, const CloudWaterMark &mark) diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_asset_compare_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_asset_compare_test.cpp index 921b4917..a07dfc00 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_asset_compare_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_asset_compare_test.cpp @@ -73,6 +73,10 @@ namespace { VBucket DATA_NULL_ASSET; VBucket DATA_ASSET_IN_ASSETS; VBucket DATA_NULL_ASSETS; + VBucket DATA_ALL_NULL_ASSETS; + VBucket DATA_EMPTY_ASSETS; + VBucket DATA_UPDATE_DELTE_NOCHANGE_INSERT; + VBucket DATA_SAME_NAME_ASSETS; Asset GenAsset(std::string name, std::string hash) { @@ -102,8 +106,9 @@ namespace { a3Changed = GenAsset("truck", "truck1Changed"); a4 = GenAsset("sedan", "sedan1"); a4Changed = GenAsset("sedan", "sedan1Changed"); - a5 = GenAsset("truck", "truck1"); - a5Changed = GenAsset("truck", "truck1Changed"); + a5 = GenAsset("trucker", "truck1"); + a5Changed = GenAsset("trucker", "truck1Changed"); + DATA_EMPTY.clear(); DATA_BASELINE = GenDatum(1, "Jack", a1, Assets({a2, a3, a4})); // id is 1 DATA_EMPTY_ASSET = GenDatum(2, "PoorGuy", a1, Assets({})); // id is 2 DATA_EMPTY_ASSET.erase(FIELD_HOUSE); @@ -119,7 +124,12 @@ namespace { std::monostate nil; DATA_NULL_ASSET = GenDatum(11, "Lob3", nil, Assets({a1, a2, a3})); // id is 11 DATA_ASSET_IN_ASSETS = GenDatum(12, "Lob4", Assets({a1}), Assets({a2, a3, a4})); // id is 12 - DATA_NULL_ASSETS = GenDatum(13, "Lob5", Assets({a1}), nil); // id is 12 + DATA_NULL_ASSETS = GenDatum(13, "Lob5", Assets({a1}), nil); // id is 13 + DATA_ALL_NULL_ASSETS = GenDatum(14, "Nico", nil, nil); // id is 14 + DATA_EMPTY_ASSETS = GenDatum(15, "Lob6", a1, Assets({})); // id is 15 + DATA_EMPTY_ASSETS.erase(FIELD_CARS); + DATA_UPDATE_DELTE_NOCHANGE_INSERT = GenDatum(16, "Nico321", nil, Assets({a2Changed, a4, a5})); // id is 16 + DATA_SAME_NAME_ASSETS = GenDatum(16, "Nico156", nil, Assets({a1, a1Changed})); // id is 16 } void CreateDB() @@ -292,7 +302,7 @@ namespace { std::map expectedList; TagAsset(AssetOpType::UPDATE, AssetStatus::DOWNLOADING, a1); expectedList[FIELD_HOUSE] = { a1 }; - expectedList[FIELD_CARS] = {}; + expectedList[FIELD_CARS] = { a2, a3, a4 }; ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); } @@ -311,7 +321,7 @@ namespace { std::map expectedList; TagAsset(AssetOpType::UPDATE, AssetStatus::DOWNLOADING, a3); expectedList[FIELD_HOUSE] = {}; - expectedList[FIELD_CARS] = { a3 }; + expectedList[FIELD_CARS] = { a2, a3, a4 }; ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); } @@ -329,7 +339,7 @@ namespace { DATA_BASELINE, DATA_ALL_SAME); std::map expectedList; expectedList[FIELD_HOUSE] = {}; - expectedList[FIELD_CARS] = {}; + expectedList[FIELD_CARS] = { a2, a3, a4 }; ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); } @@ -348,7 +358,7 @@ namespace { std::map expectedList; TagAsset(AssetOpType::DELETE, AssetStatus::DOWNLOADING, a5); expectedList[FIELD_HOUSE] = {}; - expectedList[FIELD_CARS] = { a5 }; + expectedList[FIELD_CARS] = { a2, a3, a4, a5 }; ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); } @@ -368,7 +378,7 @@ namespace { TagAsset(AssetOpType::DELETE, AssetStatus::DOWNLOADING, a5); TagAsset(AssetOpType::INSERT, AssetStatus::DOWNLOADING, a4); expectedList[FIELD_HOUSE] = {}; - expectedList[FIELD_CARS] = { a5, a4 }; + expectedList[FIELD_CARS] = { a2, a3, a5, a4 }; ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); } @@ -389,7 +399,7 @@ namespace { TagAsset(AssetOpType::DELETE, AssetStatus::DOWNLOADING, a5); TagAsset(AssetOpType::INSERT, AssetStatus::DOWNLOADING, a4); expectedList[FIELD_HOUSE] = {}; - expectedList[FIELD_CARS] = { a3, a5, a4 }; + expectedList[FIELD_CARS] = { a2, a3, a5, a4 }; ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); } @@ -496,8 +506,10 @@ namespace { TagAsset(AssetOpType::NO_CHANGE, AssetStatus::DOWNLOADING, a2); TagAsset(AssetOpType::NO_CHANGE, AssetStatus::DOWNLOADING, a3); TagAsset(AssetOpType::NO_CHANGE, AssetStatus::DOWNLOADING, a4); - expectedList[FIELD_HOUSE] = {}; - expectedList[FIELD_CARS] = {}; + a2.status = static_cast(AssetStatus::NORMAL); + a3.status = static_cast(AssetStatus::NORMAL); + a4.status = static_cast(AssetStatus::NORMAL); + expectedList[FIELD_CARS] = {a2, a3, a4}; ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); } @@ -538,7 +550,7 @@ namespace { std::map expectedList; TagAsset(AssetOpType::UPDATE, AssetStatus::DOWNLOADING, a1Changed); expectedList[FIELD_HOUSE] = { a1Changed }; - expectedList[FIELD_CARS] = {}; + expectedList[FIELD_CARS] = {a2, a3, a4}; ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); } @@ -604,4 +616,217 @@ namespace { EXPECT_EQ(std::get(DATA_EMPTY[FIELD_CARS])[1].flag, static_cast(AssetOpType::DELETE)); EXPECT_EQ(std::get(DATA_EMPTY[FIELD_CARS])[2].flag, static_cast(AssetOpType::DELETE)); } + + /** + * @tc.name: AssetCmpTest020 + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: wanyi + */ + HWTEST_F(DistributedDBCloudAssetCompareTest, AssetCmpTest020, TestSize.Level0) + { + auto assetList = g_cloudSyncer->TestTagAssetsInSingleRecord( + DATA_ALL_NULL_ASSETS, DATA_BASELINE, true); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_HOUSE]).flag, static_cast(AssetOpType::DELETE)); + EXPECT_EQ(std::get(DATA_ALL_NULL_ASSETS[FIELD_CARS])[0].flag, + static_cast(AssetOpType::DELETE)); + EXPECT_EQ(std::get(DATA_ALL_NULL_ASSETS[FIELD_CARS])[1].flag, + static_cast(AssetOpType::DELETE)); + EXPECT_EQ(std::get(DATA_ALL_NULL_ASSETS[FIELD_CARS])[2].flag, + static_cast(AssetOpType::DELETE)); + + std::map expectedList; + TagAsset(AssetOpType::DELETE, AssetStatus::NORMAL, a1); + TagAsset(AssetOpType::DELETE, AssetStatus::NORMAL, a2); + TagAsset(AssetOpType::DELETE, AssetStatus::NORMAL, a3); + TagAsset(AssetOpType::DELETE, AssetStatus::NORMAL, a4); + expectedList[FIELD_HOUSE] = { a1 }; + expectedList[FIELD_CARS] = { a2, a3, a4 }; + ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); + ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); + } + + /** + * @tc.name: AssetCmpTest021 + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: wanyi + */ + HWTEST_F(DistributedDBCloudAssetCompareTest, AssetCmpTest021, TestSize.Level0) + { + auto assetList = g_cloudSyncer->TestTagAssetsInSingleRecord( + DATA_ALL_NULL_ASSETS, DATA_ALL_NULL_ASSETS, true); + ASSERT_TRUE(DATA_ALL_NULL_ASSETS[FIELD_HOUSE].index() == TYPE_INDEX); + ASSERT_TRUE(DATA_ALL_NULL_ASSETS[FIELD_CARS].index() == TYPE_INDEX); + + std::map expectedList; + expectedList[FIELD_HOUSE] = {}; + expectedList[FIELD_CARS] = {}; + ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); + ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); + } + + /** + * @tc.name: AssetCmpTest022 + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: wanyi + */ + HWTEST_F(DistributedDBCloudAssetCompareTest, AssetCmpTest022, TestSize.Level0) + { + auto assetList = g_cloudSyncer->TestTagAssetsInSingleRecord( + DATA_BASELINE, DATA_ALL_NULL_ASSETS, true); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_HOUSE]).flag, static_cast(AssetOpType::INSERT)); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_CARS])[0].flag, static_cast(AssetOpType::INSERT)); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_CARS])[1].flag, static_cast(AssetOpType::INSERT)); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_CARS])[2].flag, static_cast(AssetOpType::INSERT)); + + std::map expectedList; + TagAsset(AssetOpType::INSERT, AssetStatus::NORMAL, a1); + TagAsset(AssetOpType::INSERT, AssetStatus::NORMAL, a2); + TagAsset(AssetOpType::INSERT, AssetStatus::NORMAL, a3); + TagAsset(AssetOpType::INSERT, AssetStatus::NORMAL, a4); + expectedList[FIELD_HOUSE] = { a1 }; + expectedList[FIELD_CARS] = { a2, a3, a4 }; + ASSERT_TRUE(CheckAssetDownloadList(FIELD_HOUSE, assetList, expectedList)); + ASSERT_TRUE(CheckAssetDownloadList(FIELD_CARS, assetList, expectedList)); + } + + /** + * @tc.name: AssetCmpTest023 + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: wanyi + */ + HWTEST_F(DistributedDBCloudAssetCompareTest, AssetCmpTest023, TestSize.Level0) + { + auto assetList = g_cloudSyncer->TestTagAssetsInSingleRecord( + DATA_ASSET_SAME_NAME_BUT_CHANGE, DATA_BASELINE, true); + EXPECT_EQ(std::get(DATA_ASSET_SAME_NAME_BUT_CHANGE[FIELD_HOUSE]).flag, + static_cast(AssetOpType::UPDATE)); + EXPECT_EQ(std::get(DATA_ASSET_SAME_NAME_BUT_CHANGE[FIELD_CARS])[0].flag, + static_cast(AssetOpType::NO_CHANGE)); + EXPECT_EQ(std::get(DATA_ASSET_SAME_NAME_BUT_CHANGE[FIELD_CARS])[1].flag, + static_cast(AssetOpType::NO_CHANGE)); + EXPECT_EQ(std::get(DATA_ASSET_SAME_NAME_BUT_CHANGE[FIELD_CARS])[2].flag, + static_cast(AssetOpType::NO_CHANGE)); + } + + /** + * @tc.name: AssetCmpTest024 + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: wanyi + */ + HWTEST_F(DistributedDBCloudAssetCompareTest, AssetCmpTest024, TestSize.Level0) + { + auto assetList = g_cloudSyncer->TestTagAssetsInSingleRecord( + DATA_ASSETS_DIFFERENT_CHANGED_FIELD, DATA_BASELINE, true); + EXPECT_EQ(std::get(DATA_ASSETS_DIFFERENT_CHANGED_FIELD[FIELD_HOUSE]).flag, + static_cast(AssetOpType::NO_CHANGE)); + EXPECT_EQ(std::get(DATA_ASSETS_DIFFERENT_CHANGED_FIELD[FIELD_CARS])[0].flag, + static_cast(AssetOpType::NO_CHANGE)); + EXPECT_EQ(std::get(DATA_ASSETS_DIFFERENT_CHANGED_FIELD[FIELD_CARS])[1].flag, + static_cast(AssetOpType::UPDATE)); + EXPECT_EQ(std::get(DATA_ASSETS_DIFFERENT_CHANGED_FIELD[FIELD_CARS])[2].flag, + static_cast(AssetOpType::INSERT)); + EXPECT_EQ(std::get(DATA_ASSETS_DIFFERENT_CHANGED_FIELD[FIELD_CARS])[3].flag, + static_cast(AssetOpType::DELETE)); + } + + /** + * @tc.name: AssetCmpTest025 + * @tc.desc: Cloud device contain a record without assets, local device insert an assets and begin to sync. + * CloudAsset will be a record without assets. Local data will be a record with assets. + * @tc.type: FUNC + * @tc.require: + * @tc.author: wanyi + */ + HWTEST_F(DistributedDBCloudAssetCompareTest, AssetCmpTest025, TestSize.Level0) + { + auto assetList = g_cloudSyncer->TestTagAssetsInSingleRecord(DATA_BASELINE, DATA_NULL_ASSETS, true); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_HOUSE]).flag, static_cast(AssetOpType::NO_CHANGE)); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_CARS])[0].flag, static_cast(AssetOpType::INSERT)); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_CARS])[1].flag, static_cast(AssetOpType::INSERT)); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_CARS])[2].flag, static_cast(AssetOpType::INSERT)); + } + + /** + * @tc.name: AssetCmpTest026 + * @tc.desc: Cloud device contain a record without assets, local device insert an assets and begin to sync. + * CloudAsset will be a record without assets. Local data will be a record with assets. + * In this case, record do not contain certain asset column + * @tc.type: FUNC + * @tc.require: + * @tc.author: wanyi + */ + HWTEST_F(DistributedDBCloudAssetCompareTest, AssetCmpTest026, TestSize.Level0) + { + auto assetList = g_cloudSyncer->TestTagAssetsInSingleRecord(DATA_BASELINE, DATA_EMPTY_ASSETS, true); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_HOUSE]).flag, static_cast(AssetOpType::NO_CHANGE)); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_CARS])[0].flag, static_cast(AssetOpType::INSERT)); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_CARS])[1].flag, static_cast(AssetOpType::INSERT)); + EXPECT_EQ(std::get(DATA_BASELINE[FIELD_CARS])[2].flag, static_cast(AssetOpType::INSERT)); + } + + /** + * @tc.name: AssetCmpTest027 + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: wanyi + */ + HWTEST_F(DistributedDBCloudAssetCompareTest, AssetCmpTest027, TestSize.Level0) + { + auto assetList = g_cloudSyncer->TestTagAssetsInSingleRecord( + DATA_UPDATE_DELTE_NOCHANGE_INSERT, DATA_BASELINE, false); + EXPECT_EQ(std::get(DATA_UPDATE_DELTE_NOCHANGE_INSERT[FIELD_CARS])[0].flag, + static_cast(AssetOpType::UPDATE)); + EXPECT_EQ(std::get(DATA_UPDATE_DELTE_NOCHANGE_INSERT[FIELD_CARS])[1].flag, + static_cast(AssetOpType::NO_CHANGE)); + EXPECT_EQ(std::get(DATA_UPDATE_DELTE_NOCHANGE_INSERT[FIELD_CARS])[2].flag, + static_cast(AssetOpType::INSERT)); + EXPECT_EQ(std::get(DATA_UPDATE_DELTE_NOCHANGE_INSERT[FIELD_CARS])[3].flag, + static_cast(AssetOpType::DELETE)); + } + + /** + * @tc.name: AssetCmpTest028 + * @tc.desc: Two same name asset appears in the assets field, this situation is not allowed + * @tc.type: FUNC + * @tc.require: + * @tc.author: wanyi + */ + HWTEST_F(DistributedDBCloudAssetCompareTest, AssetCmpTest028, TestSize.Level0) + { + auto assetList = g_cloudSyncer->TestTagAssetsInSingleRecord( + DATA_ALL_NULL_ASSETS, DATA_BASELINE, true); + EXPECT_EQ(std::get(DATA_ALL_NULL_ASSETS[FIELD_CARS])[0].flag, + static_cast(AssetOpType::DELETE)); + EXPECT_EQ(std::get(DATA_ALL_NULL_ASSETS[FIELD_CARS])[1].flag, + static_cast(AssetOpType::DELETE)); + EXPECT_EQ(std::get(DATA_ALL_NULL_ASSETS[FIELD_CARS])[2].flag, + static_cast(AssetOpType::DELETE)); + } + + /** + * @tc.name: AssetCmpTest029 + * @tc.desc: Two same name asset appears in the assets field, this situation is not allowed + * @tc.type: FUNC + * @tc.require: + * @tc.author: wanyi + */ + HWTEST_F(DistributedDBCloudAssetCompareTest, AssetCmpTest029, TestSize.Level0) + { + Field field1 = { FIELD_HOUSE, TYPE_INDEX }; + Field field2 = { FIELD_CARS, TYPE_INDEX }; + std::vector assetFields = { field1, field2 }; + ASSERT_TRUE(g_cloudSyncer->TestIsDataContainDuplicateAsset(assetFields, DATA_SAME_NAME_ASSETS)); + ASSERT_TRUE(g_cloudSyncer->TestIsDataContainDuplicateAsset(assetFields, DATA_BASELINE) == false); + } } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_db_proxy_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_db_proxy_test.cpp index 02e98239..80458c5b 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_db_proxy_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_db_proxy_test.cpp @@ -20,6 +20,7 @@ #include "cloud_db_types.h" #include "cloud_db_proxy.h" #include "distributeddb_tools_unit_test.h" +#include "kv_store_errno.h" #include "mock_icloud_sync_storage_interface.h" #include "virtual_cloud_db.h" #include "virtual_cloud_syncer.h" @@ -423,4 +424,146 @@ HWTEST_F(DistributedDBCloudDBProxyTest, CloudDBProxyTest006, TestSize.Level3) cloudSyncer->Close(); RefObject::KillAndDecObjRef(cloudSyncer); } + +/** + * @tc.name: CloudDBProxyTest007 + * @tc.desc: Verify syncer close after notify finish. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBCloudDBProxyTest, CloudDBProxyTest007, TestSize.Level4) +{ + /** + * @tc.steps: step1. set cloud db to proxy + * @tc.expected: step1. E_OK + */ + auto iCloud = std::make_shared(); + auto cloudSyncer = new(std::nothrow) VirtualCloudSyncer(StorageProxy::GetCloudDb(iCloud.get())); + EXPECT_CALL(*iCloud, StartTransaction).WillRepeatedly(testing::Return(E_OK)); + EXPECT_CALL(*iCloud, Commit).WillRepeatedly(testing::Return(E_OK)); + ASSERT_NE(cloudSyncer, nullptr); + ASSERT_EQ(cloudSyncer->SetCloudDB(virtualCloudDb_), E_OK); + cloudSyncer->SetSyncAction(false, false); + /** + * @tc.steps: step2. call sync and wait sync finish + * @tc.expected: step2. notify before close finished + */ + std::atomic close = false; + int callCount = 0; + std::mutex callMutex; + std::condition_variable cv; + const auto callback = [&close, &callCount, &callMutex, &cv]( + const std::map &) { + std::this_thread::sleep_for(std::chrono::seconds(5)); // block notify 5s + { + std::lock_guard autoLock(callMutex); + callCount++; + } + cv.notify_all(); + EXPECT_EQ(close, false); + }; + EXPECT_EQ(cloudSyncer->Sync({ "cloud" }, SyncMode::SYNC_MODE_CLOUD_MERGE, { TABLE_NAME }, callback, 0), E_OK); + /** + * @tc.steps: step3. wait notify finished + */ + std::this_thread::sleep_for(std::chrono::seconds(2)); // block 2s + cloudSyncer->Close(); + close = true; + { + LOGI("begin to wait sync"); + std::unique_lock uniqueLock(callMutex); + cv.wait(uniqueLock, [&callCount]() { + return callCount > 0; + }); + LOGI("end to wait sync"); + } + RefObject::KillAndDecObjRef(cloudSyncer); +} + +/** + * @tc.name: CloudDBProxyTest008 + * @tc.desc: Verify cloud db heartbeat with diff status. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBCloudDBProxyTest, CloudDBProxyTest008, TestSize.Level0) +{ + /** + * @tc.steps: step1. set cloud db to proxy + * @tc.expected: step1. E_OK + */ + CloudDBProxy proxy; + EXPECT_EQ(proxy.SetCloudDB(virtualCloudDb_), E_OK); + /** + * @tc.steps: step2. proxy heartbeat with diff status + */ + virtualCloudDb_->SetActionStatus(CLOUD_NETWORK_ERROR); + int errCode = proxy.HeartBeat(); + EXPECT_EQ(errCode, -E_CLOUD_NETWORK_ERROR); + EXPECT_EQ(TransferDBErrno(errCode), CLOUD_NETWORK_ERROR); + + virtualCloudDb_->SetActionStatus(CLOUD_SYNC_UNSET); + errCode = proxy.HeartBeat(); + EXPECT_EQ(errCode, -E_CLOUD_SYNC_UNSET); + EXPECT_EQ(TransferDBErrno(errCode), CLOUD_SYNC_UNSET); + + virtualCloudDb_->SetActionStatus(CLOUD_FULL_RECORDS); + errCode = proxy.HeartBeat(); + EXPECT_EQ(errCode, -E_CLOUD_FULL_RECORDS); + EXPECT_EQ(TransferDBErrno(errCode), CLOUD_FULL_RECORDS); + + virtualCloudDb_->SetActionStatus(CLOUD_LOCK_ERROR); + errCode = proxy.HeartBeat(); + EXPECT_EQ(errCode, -E_CLOUD_LOCK_ERROR); + EXPECT_EQ(TransferDBErrno(errCode), CLOUD_LOCK_ERROR); + + virtualCloudDb_->SetActionStatus(DB_ERROR); + errCode = proxy.HeartBeat(); + EXPECT_EQ(errCode, -E_CLOUD_ERROR); + EXPECT_EQ(TransferDBErrno(errCode), CLOUD_ERROR); + + /** + * @tc.steps: step3. proxy close cloud db + * @tc.expected: step3. E_OK + */ + EXPECT_EQ(proxy.Close(), E_OK); +} + +/** + * @tc.name: CloudSyncQueue001 + * @tc.desc: Verify sync task count decrease after sync finished. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBCloudDBProxyTest, CloudSyncQueue001, TestSize.Level2) +{ + /** + * @tc.steps: step1. set cloud db to proxy and sleep 5s when download + * @tc.expected: step1. E_OK + */ + auto iCloud = std::make_shared(); + ASSERT_NE(iCloud, nullptr); + auto cloudSyncer = new(std::nothrow) VirtualCloudSyncer(StorageProxy::GetCloudDb(iCloud.get())); + ASSERT_NE(cloudSyncer, nullptr); + EXPECT_CALL(*iCloud, Rollback).WillRepeatedly(testing::Return(E_OK)); + EXPECT_CALL(*iCloud, Commit).WillRepeatedly(testing::Return(E_OK)); + EXPECT_CALL(*iCloud, StartTransaction).WillRepeatedly(testing::Return(E_OK)); + ASSERT_EQ(cloudSyncer->SetCloudDB(virtualCloudDb_), E_OK); + cloudSyncer->SetSyncAction(true, false); + cloudSyncer->SetDownloadFunc([cloudSyncer]() { + EXPECT_EQ(cloudSyncer->GetQueueCount(), 1u); + std::this_thread::sleep_for(std::chrono::seconds(2)); // sleep 2s + return E_OK; + }); + /** + * @tc.steps: step2. call sync and wait sync finish + */ + int callCount = 0; + EXPECT_EQ(Sync(cloudSyncer, callCount), OK); + RuntimeContext::GetInstance()->StopTaskPool(); + EXPECT_EQ(callCount, 1); +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_strategy_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_strategy_test.cpp index ee15854e..33328422 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_strategy_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_strategy_test.cpp @@ -140,10 +140,26 @@ HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest001, TestSize.Level0) * @tc.expected: step8 not handle cloud record */ cloudInfo.flag = 0x01; // it means delete + EXPECT_EQ(strategy->TagSyncDataStatus(true, localInfo, cloudInfo), OpType::UPDATE_TIMESTAMP); + /** + * @tc.steps: step9. cloud is delete and local not exist + * @tc.expected: step9 not handle cloud record + */ + EXPECT_EQ(strategy->TagSyncDataStatus(false, localInfo, cloudInfo), OpType::NOT_HANDLE); + /** + * @tc.steps: step10. cloud is old and delete, local has gid + * @tc.expected: step10 clear gid + */ + localInfo.timestamp = 3u; // mark 3 means local is new + EXPECT_EQ(strategy->TagSyncDataStatus(true, localInfo, cloudInfo), OpType::CLEAR_GID); + /** + * @tc.steps: step10. cloud is old and delete, local has not gid + * @tc.expected: step10 not handle cloud record + */ + localInfo.cloudGid = ""; EXPECT_EQ(strategy->TagSyncDataStatus(true, localInfo, cloudInfo), OpType::NOT_HANDLE); } -#ifdef MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA /** * @tc.name: TagOpTyeTest002 * @tc.desc: Verify local cover cloud strategy tag operation type function. @@ -185,7 +201,13 @@ HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest002, TestSize.Level0) * @tc.expected: step5. ONLY UPDATE GID */ cloudInfo.flag = 0x01; // it means delete - EXPECT_EQ(strategy->TagSyncDataStatus(true, localInfo, cloudInfo), OpType::ONLY_UPDATE_GID); + EXPECT_EQ(strategy->TagSyncDataStatus(true, localInfo, cloudInfo), OpType::NOT_HANDLE); + /** + * @tc.steps: step6. local has cloud record(with gid) but cloud flag is delete + * @tc.expected: step6. CLEAR_GID + */ + localInfo.cloudGid = "gid"; + EXPECT_EQ(strategy->TagSyncDataStatus(true, localInfo, cloudInfo), OpType::CLEAR_GID); } /** @@ -243,5 +265,30 @@ HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest003, TestSize.Level0) localInfo.cloudGid = "gid"; EXPECT_EQ(strategy->TagSyncDataStatus(true, localInfo, cloudInfo), OpType::UPDATE); } -#endif // MANNUAL_SYNC_AND_CLEAN_CLOUD_DATA +/** + * @tc.name: TagOpTyeTest004 + * @tc.desc: Verify cloud cover local strategy tag operation type function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: huangboxin + */ +HWTEST_F(DistributedDBCloudStrategyTest, TagOpTyeTest004, TestSize.Level0) +{ + /** + * @tc.steps: step1. cloud cover local strategy + */ + auto strategy = StrategyFactory::BuildSyncStrategy(SyncMode::SYNC_MODE_CLOUD_FORCE_PULL); + ASSERT_NE(strategy, nullptr); + LogInfo localInfo; + LogInfo cloudInfo; + + cloudInfo.flag = 0x01; + localInfo.flag = 0x01; + localInfo.cloudGid = ""; + EXPECT_EQ(strategy->TagSyncDataStatus(true, localInfo, cloudInfo), OpType::UPDATE_TIMESTAMP); + + cloudInfo.flag = 0x00; + localInfo.flag = 0x01; + EXPECT_EQ(strategy->TagSyncDataStatus(true, localInfo, cloudInfo), OpType::INSERT); +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_test.cpp index ae15727a..8fb260e2 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_test.cpp @@ -543,10 +543,10 @@ HWTEST_F(DistributedDBCloudSyncerDownloadTest, DownloadMockQueryTest005, TestSiz EXPECT_CALL(*g_idb, Query(_, _, _)) .WillRepeatedly([](const std::string &, VBucket &, std::vector &data) { data = GetRetCloudData(0); // Gen 0 data - return OK; + return QUERY_END; }); int errCode = g_cloudSyncer->CallDoDownload(taskId); - EXPECT_EQ(errCode, -E_CLOUD_ERROR); + EXPECT_EQ(errCode, E_OK); } /** diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_upload_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_upload_test.cpp index 7e29a761..dafc63b7 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_upload_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_upload_test.cpp @@ -45,6 +45,11 @@ static void CommonExpectCall(MockICloudSyncStorageInterface *iCloud) EXPECT_CALL(*iCloud, GetCloudDataNext(_, _)).WillRepeatedly(Return(E_OK)); EXPECT_CALL(*iCloud, GetCloudDbSchema(_)).WillRepeatedly(Return(E_OK)); } +static void BatchExpectCall(MockICloudSyncStorageInterface *iCloud) +{ + EXPECT_CALL(*iCloud, PutMetaData(_, _)).WillRepeatedly(Return(E_OK)); + EXPECT_CALL(*iCloud, FillCloudGid(_)).WillRepeatedly(Return(E_OK)); +} class DistributedDBCloudSyncerUploadTest : public testing::Test { public: static void SetUpTestCase(void); @@ -81,9 +86,9 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck001, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); TaskId taskId = 1; EXPECT_CALL(*iCloud, GetMetaData(_, _)).WillRepeatedly(Return(E_OK)); @@ -95,32 +100,34 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck001, TestSize.Level1 EXPECT_CALL(*iCloud, GetCloudTableSchema(_, _)).WillRepeatedly(Return(E_OK)); EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)).WillRepeatedly(Return(E_OK)); - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_PUSH_ONLY); - int errCode = cloudSyncer.CallDoUpload(taskId); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_PUSH_ONLY); + int errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_INVALID_ARGS); - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_PULL_ONLY); - errCode = cloudSyncer.CallDoUpload(taskId); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_PULL_ONLY); + errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_INVALID_ARGS); - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_PUSH_PULL); - errCode = cloudSyncer.CallDoUpload(taskId); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_PUSH_PULL); + errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_INVALID_ARGS); - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); - errCode = cloudSyncer.CallDoUpload(taskId); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); + errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, E_OK); - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); - errCode = cloudSyncer.CallDoUpload(taskId); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, E_OK); - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PULL); - errCode = cloudSyncer.CallDoUpload(taskId); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PULL); + errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_INVALID_ARGS); - errCode = cloudSyncer.CallDoUpload(taskId); + errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_INVALID_ARGS); + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; @@ -138,9 +145,9 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck002, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); TaskId taskId = 2u; EXPECT_CALL(*iCloud, StartTransaction(_)).WillRepeatedly(Return(E_OK)); @@ -151,12 +158,14 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck002, TestSize.Level1 EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)).WillRepeatedly(Return(E_OK)); // 1. The water level was read successfully - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); EXPECT_CALL(*iCloud, GetMetaData(_, _)).WillOnce(Return(E_OK)); EXPECT_CALL(*iCloud, ChkSchema(_)).WillRepeatedly(Return(E_OK)); - int errCode = cloudSyncer.CallDoUpload(taskId); + int errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, E_OK); + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; @@ -173,9 +182,9 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck003, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); EXPECT_CALL(*iCloud, StartTransaction(_)).WillRepeatedly(Return(E_OK)); EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)).WillRepeatedly(Return(E_OK)); @@ -187,43 +196,13 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck003, TestSize.Level1 // 2. Failed to read water level TaskId taskId = 3u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); EXPECT_CALL(*iCloud, GetMetaData(_, _)).WillOnce(Return(-E_INVALID_DB)); - int errCode = cloudSyncer.CallDoUpload(taskId); + int errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_INVALID_DB); - taskId = 4u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); - EXPECT_CALL(*iCloud, GetMetaData(_, _)).WillOnce(Return(-E_SECUREC_ERROR)); - errCode = cloudSyncer.CallDoUpload(taskId); - EXPECT_EQ(errCode, -E_SECUREC_ERROR); - - taskId = 5u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); - EXPECT_CALL(*iCloud, GetMetaData(_, _)).WillOnce(Return(-E_INVALID_ARGS)); - errCode = cloudSyncer.CallDoUpload(taskId); - EXPECT_EQ(errCode, -E_INVALID_ARGS); - - taskId = 6u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); - EXPECT_CALL(*iCloud, GetMetaData(_, _)).WillOnce(Return(-E_BUSY)); - errCode = cloudSyncer.CallDoUpload(taskId); - EXPECT_EQ(errCode, -E_BUSY); - - taskId = 7u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); - EXPECT_CALL(*iCloud, GetMetaData(_, _)).WillOnce(Return(-E_NOT_FOUND)); - errCode = cloudSyncer.CallDoUpload(taskId); - // when we coudln't find key in get meta data, read local water mark will return default value and E_OK - EXPECT_EQ(errCode, E_OK); - - // Other sqlite error, like SQLITE_ERROR - taskId = 8u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_MERGE); - EXPECT_CALL(*iCloud, GetMetaData(_, _)).WillOnce(Return(SQLITE_ERROR)); - errCode = cloudSyncer.CallDoUpload(taskId); - EXPECT_EQ(errCode, SQLITE_ERROR); - + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -240,10 +219,10 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck004, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); - cloudSyncer.InitCloudSyncer(3u, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->SetMockICloudDB(idb); + cloudSyncer->InitCloudSyncer(3u, SYNC_MODE_CLOUD_FORCE_PUSH); EXPECT_CALL(*iCloud, StartTransaction(_)).WillRepeatedly(Return(E_OK)); EXPECT_CALL(*iCloud, ChkSchema(_)).WillRepeatedly(Return(E_OK)); @@ -253,36 +232,12 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck004, TestSize.Level1 // 1. Failed to get total data count EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)).WillOnce(Return(-E_INVALID_DB)); - int errCode = cloudSyncer.CallDoUpload(3u); + int errCode = cloudSyncer->CallDoUpload(3u); EXPECT_EQ(errCode, -E_INVALID_DB); - cloudSyncer.InitCloudSyncer(4u, SYNC_MODE_CLOUD_FORCE_PUSH); - EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)).WillOnce(Return(-E_BUSY)); - errCode = cloudSyncer.CallDoUpload(4u); - EXPECT_EQ(errCode, -E_BUSY); - - cloudSyncer.InitCloudSyncer(5u, SYNC_MODE_CLOUD_FORCE_PUSH); - - EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)).WillOnce(Return(-E_OUT_OF_MEMORY)); - errCode = cloudSyncer.CallDoUpload(5u); - EXPECT_EQ(errCode, -E_OUT_OF_MEMORY); - - cloudSyncer.InitCloudSyncer(6u, SYNC_MODE_CLOUD_FORCE_PUSH); - EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)).WillOnce(Return(-E_INTERNAL_ERROR)); - errCode = cloudSyncer.CallDoUpload(6u); - EXPECT_EQ(errCode, -E_INTERNAL_ERROR); - - cloudSyncer.InitCloudSyncer(7u, SYNC_MODE_CLOUD_FORCE_PUSH); - EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)).WillOnce(Return(-E_INVALID_QUERY_FORMAT)); - errCode = cloudSyncer.CallDoUpload(7u); - EXPECT_EQ(errCode, -E_INVALID_QUERY_FORMAT); - - cloudSyncer.InitCloudSyncer(9u, SYNC_MODE_CLOUD_FORCE_PUSH); - EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)).WillOnce(Return(SQLITE_ERROR)); - errCode = cloudSyncer.CallDoUpload(9u); - EXPECT_EQ(errCode, SQLITE_ERROR); - RuntimeContext::GetInstance()->StopTaskPool(); + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -299,10 +254,10 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck005, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); - cloudSyncer.InitCloudSyncer(3u, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->SetMockICloudDB(idb); + cloudSyncer->InitCloudSyncer(3u, SYNC_MODE_CLOUD_FORCE_PUSH); EXPECT_CALL(*iCloud, StartTransaction(_)).WillRepeatedly(Return(E_OK)); EXPECT_CALL(*iCloud, ChkSchema(_)).WillRepeatedly(Return(E_OK)); @@ -313,23 +268,25 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck005, TestSize.Level1 EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)).WillRepeatedly(Return(E_OK)); // 2. get total upload count ok - cloudSyncer.InitCloudSyncer(10u, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(10u, SYNC_MODE_CLOUD_FORCE_PUSH); EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)).WillOnce(Return(E_OK)); - int errCode = cloudSyncer.CallDoUpload(10u); + int errCode = cloudSyncer->CallDoUpload(10u); EXPECT_EQ(errCode, E_OK); // 3. get total upload count ok, which is 0 - cloudSyncer.InitCloudSyncer(11u, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(11u, SYNC_MODE_CLOUD_FORCE_PUSH); EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)) .WillOnce([](const std::string &, const Timestamp &, const bool, int64_t & count) { count = 0; return E_OK; }); - errCode = cloudSyncer.CallDoUpload(11u); + errCode = cloudSyncer->CallDoUpload(11u); EXPECT_EQ(errCode, E_OK); RuntimeContext::GetInstance()->StopTaskPool(); + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -346,11 +303,11 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck006, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); TaskId taskId = 4u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); EXPECT_CALL(*idb, BatchInsert(_, _, _)).WillRepeatedly(Return(OK)); @@ -370,7 +327,7 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck006, TestSize.Level1 EXPECT_CALL(*iCloud, PutMetaData(_, _)).WillRepeatedly(Return(E_OK)); VBucket tmp = {pair(CloudDbConstant::MODIFY_FIELD, 1)}; - CloudSyncData uploadData(cloudSyncer.GetCurrentContextTableName()); + CloudSyncData uploadData(cloudSyncer->GetCurrentContextTableName()); // batch_1 CloudSyncData quantity > total count uploadData.insData.record = std::vector(1001, tmp); @@ -380,11 +337,12 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck006, TestSize.Level1 cloudDataResult = uploadData; return E_OK; }); - int errCode = cloudSyncer.CallDoUpload(taskId); + int errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_INTERNAL_ERROR); RuntimeContext::GetInstance()->StopTaskPool(); - + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -401,15 +359,14 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck007, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); - cloudSyncer.InitCloudSyncer(4u, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->SetMockICloudDB(idb); + cloudSyncer->InitCloudSyncer(4u, SYNC_MODE_CLOUD_FORCE_PUSH); CommonExpectCall(iCloud); + BatchExpectCall(iCloud); EXPECT_CALL(*idb, BatchInsert(_, _, _)).WillRepeatedly(Return(OK)); - EXPECT_CALL(*iCloud, PutMetaData(_, _)).WillRepeatedly(Return(E_OK)); - EXPECT_CALL(*iCloud, FillCloudGid(_)).WillRepeatedly(Return(E_OK)); EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)) .WillRepeatedly([](const std::string &, const Timestamp &, const bool, int64_t & count) { count = 1000; @@ -417,16 +374,15 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck007, TestSize.Level1 }); // Batch_n CloudSyncData quantity > total count - cloudSyncer.InitCloudSyncer(5u, SYNC_MODE_CLOUD_FORCE_PUSH); - CloudSyncData uploadData2(cloudSyncer.GetCurrentContextTableName()); + cloudSyncer->InitCloudSyncer(5u, SYNC_MODE_CLOUD_FORCE_PUSH); + CloudSyncData uploadData2(cloudSyncer->GetCurrentContextTableName()); VBucket tmp = {pair(CloudDbConstant::MODIFY_FIELD, 1)}; uploadData2.insData.record = std::vector(1000, tmp); uploadData2.insData.extend = std::vector(1000, tmp); SyncTimeRange syncTimeRange = { .beginTime = 1u }; - Query query1 = Query::Select(); - QueryObject queryObject(query1); - queryObject.SetTableName(cloudSyncer.GetCurrentContextTableName()); + QueryObject queryObject(Query::Select()); + queryObject.SetTableName(cloudSyncer->GetCurrentContextTableName()); auto token = new (std::nothrow) SQLiteSingleVerRelationalContinueToken(syncTimeRange, queryObject); ContinueToken conStmtToken = static_cast(token); delete token; @@ -438,7 +394,7 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck007, TestSize.Level1 return -E_UNFINISHED; }); - CloudSyncData uploadData3(cloudSyncer.GetCurrentContextTableName()); + CloudSyncData uploadData3(cloudSyncer->GetCurrentContextTableName()); uploadData3.insData.record = std::vector(1001, tmp); uploadData3.insData.extend = std::vector(1001, tmp); EXPECT_CALL(*iCloud, GetCloudDataNext(_, _)).WillOnce( @@ -446,11 +402,12 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck007, TestSize.Level1 cloudDataResult = uploadData3; return E_OK; }); - int errCode = cloudSyncer.CallDoUpload(5u); + int errCode = cloudSyncer->CallDoUpload(5u); EXPECT_EQ(errCode, -E_INTERNAL_ERROR); RuntimeContext::GetInstance()->StopTaskPool(); - + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -467,11 +424,11 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck008, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); TaskId taskId = 4u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); EXPECT_CALL(*idb, BatchInsert(_, _, _)).WillRepeatedly(Return(OK)); @@ -493,8 +450,8 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck008, TestSize.Level1 // empty CloudSyncData taskId = 6u; - CloudSyncData uploadData2(cloudSyncer.GetCurrentContextTableName()); - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + CloudSyncData uploadData2(cloudSyncer->GetCurrentContextTableName()); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); uploadData2.insData.record = std::vector(100); uploadData2.insData.extend = std::vector(100); EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)) @@ -504,11 +461,12 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck008, TestSize.Level1 return -E_UNFINISHED; }); - int errCode = cloudSyncer.CallDoUpload(taskId); + int errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_INTERNAL_ERROR); RuntimeContext::GetInstance()->StopTaskPool(); - + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -526,12 +484,12 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck009, TestSize.Level1 // ClouSyncData format is ok MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); TaskId taskId = 5u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); VBucket tmp = {pair(CloudDbConstant::MODIFY_FIELD, 1)}; CommonExpectCall(iCloud); EXPECT_CALL(*iCloud, PutMetaData(_, _)).WillRepeatedly(Return(E_OK)); @@ -545,7 +503,7 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck009, TestSize.Level1 return E_OK; }); - CloudSyncData uploadData(cloudSyncer.GetCurrentContextTableName()); + CloudSyncData uploadData(cloudSyncer->GetCurrentContextTableName()); uploadData.insData.record = std::vector(1000, tmp); uploadData.insData.extend = std::vector(1000, tmp); EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)) @@ -554,11 +512,11 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck009, TestSize.Level1 cloudDataResult = uploadData; return E_OK; }); - int errCode = cloudSyncer.CallDoUpload(taskId); + int errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, E_OK); // CloudSyncData format error: record does not match extend length - cloudSyncer.CallClearCloudSyncData(uploadData); + cloudSyncer->CallClearCloudSyncData(uploadData); uploadData.insData.record = std::vector(1000, tmp); uploadData.insData.extend = std::vector(999, tmp); EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)) @@ -567,11 +525,12 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck009, TestSize.Level1 cloudDataResult = uploadData; return E_OK; }); - errCode = cloudSyncer.CallDoUpload(taskId); + errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_INTERNAL_ERROR); RuntimeContext::GetInstance()->StopTaskPool(); - + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -589,12 +548,12 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck017, TestSize.Level1 // ClouSyncData format is ok MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); TaskId taskId = 5u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); VBucket tmp = {pair(CloudDbConstant::MODIFY_FIELD, 1)}; CommonExpectCall(iCloud); EXPECT_CALL(*iCloud, PutMetaData(_, _)).WillRepeatedly(Return(E_OK)); @@ -609,7 +568,7 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck017, TestSize.Level1 }); // CloudSyncData format error: tableName is different from the table name corresponding to Task - CloudSyncData uploadData2(cloudSyncer.GetCurrentContextTableName() + "abc"); + CloudSyncData uploadData2(cloudSyncer->GetCurrentContextTableName() + "abc"); uploadData2.insData.record = std::vector(1000, tmp); uploadData2.insData.extend = std::vector(1000, tmp); EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)) @@ -618,11 +577,12 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck017, TestSize.Level1 cloudDataResult = uploadData2; return E_OK; }); - int errCode = cloudSyncer.CallDoUpload(taskId); + int errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_INTERNAL_ERROR); RuntimeContext::GetInstance()->StopTaskPool(); - + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -639,14 +599,14 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck010, TestSize.Level1 // insert has data, update has data, delete has data (check whether it is running normally and info count) MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); TaskId taskId = 6u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); - CloudSyncData uploadData(cloudSyncer.GetCurrentContextTableName()); - cloudSyncer.initFullCloudSyncData(uploadData, 1000); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + CloudSyncData uploadData(cloudSyncer->GetCurrentContextTableName()); + cloudSyncer->initFullCloudSyncData(uploadData, 1000); EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)) .WillOnce([&uploadData](const TableSchema &, const Timestamp &, @@ -673,13 +633,15 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck010, TestSize.Level1 EXPECT_CALL(*iCloud, GetCloudTableSchema(_, _)).WillRepeatedly(Return(E_OK)); EXPECT_CALL(*iCloud, FillCloudGid(_)).WillRepeatedly(Return(E_OK)); - int errCode = cloudSyncer.CallDoUpload(taskId); + int errCode = cloudSyncer->CallDoUpload(taskId); EXPECT_EQ(errCode, E_OK); std::this_thread::sleep_for(std::chrono::seconds(1)); - EXPECT_EQ(cloudSyncer.GetUploadSuccessCount(taskId), 3000); - EXPECT_EQ(cloudSyncer.GetUploadFailCount(taskId), 0); + EXPECT_EQ(cloudSyncer->GetUploadSuccessCount(taskId), 3000); + EXPECT_EQ(cloudSyncer->GetUploadFailCount(taskId), 0); RuntimeContext::GetInstance()->StopTaskPool(); + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -696,11 +658,11 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck011, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); VBucket tmp = {pair(CloudDbConstant::MODIFY_FIELD, 1)}; - cloudSyncer.InitCloudSyncer(6u, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(6u, SYNC_MODE_CLOUD_FORCE_PUSH); EXPECT_CALL(*iCloud, StartTransaction(_)).WillRepeatedly(Return(E_OK)); EXPECT_CALL(*iCloud, ChkSchema(_)).WillRepeatedly(Return(E_OK)); @@ -722,7 +684,7 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck011, TestSize.Level1 EXPECT_CALL(*iCloud, FillCloudGid(_)).WillRepeatedly(Return(E_OK)); // insert has no data, update and delete have data - CloudSyncData uploadData2(cloudSyncer.GetCurrentContextTableName()); + CloudSyncData uploadData2(cloudSyncer->GetCurrentContextTableName()); uploadData2.updData.record = std::vector(1000, tmp); uploadData2.updData.extend = std::vector(1000, tmp); uploadData2.delData.record = std::vector(1000, tmp); @@ -733,14 +695,15 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck011, TestSize.Level1 cloudDataResult = uploadData2; return E_OK; }); - int errCode = cloudSyncer.CallDoUpload(6u); + int errCode = cloudSyncer->CallDoUpload(6u); std::this_thread::sleep_for(std::chrono::seconds(1)); EXPECT_EQ(errCode, E_OK); - EXPECT_EQ(cloudSyncer.GetUploadSuccessCount(6u), 2000); - EXPECT_EQ(cloudSyncer.GetUploadFailCount(6u), 0); + EXPECT_EQ(cloudSyncer->GetUploadSuccessCount(6u), 2000); + EXPECT_EQ(cloudSyncer->GetUploadFailCount(6u), 0); RuntimeContext::GetInstance()->StopTaskPool(); - + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -757,11 +720,11 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck012, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); VBucket tmp = {pair(CloudDbConstant::MODIFY_FIELD, 1)}; - cloudSyncer.InitCloudSyncer(6u, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(6u, SYNC_MODE_CLOUD_FORCE_PUSH); EXPECT_CALL(*iCloud, StartTransaction(_)).WillRepeatedly(Return(E_OK)); EXPECT_CALL(*iCloud, ChkSchema(_)).WillRepeatedly(Return(E_OK)); @@ -783,7 +746,7 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck012, TestSize.Level1 EXPECT_CALL(*iCloud, FillCloudGid(_)).WillRepeatedly(Return(E_OK)); // insert has data, update has no data, delete has data - CloudSyncData uploadData3(cloudSyncer.GetCurrentContextTableName()); + CloudSyncData uploadData3(cloudSyncer->GetCurrentContextTableName()); uploadData3.insData.record = std::vector(1000, tmp); uploadData3.insData.extend = std::vector(1000, tmp); uploadData3.delData.record = std::vector(1000, tmp); @@ -794,14 +757,15 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck012, TestSize.Level1 cloudDataResult = uploadData3; return E_OK; }); - int errCode = cloudSyncer.CallDoUpload(6u); + int errCode = cloudSyncer->CallDoUpload(6u); std::this_thread::sleep_for(std::chrono::seconds(1)); EXPECT_EQ(errCode, E_OK); - EXPECT_EQ(cloudSyncer.GetUploadSuccessCount(6u), 2000); - EXPECT_EQ(cloudSyncer.GetUploadFailCount(6u), 0); + EXPECT_EQ(cloudSyncer->GetUploadSuccessCount(6u), 2000); + EXPECT_EQ(cloudSyncer->GetUploadFailCount(6u), 0); RuntimeContext::GetInstance()->StopTaskPool(); - + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -819,18 +783,16 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck013, TestSize.Level1 // batch api all success. MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); - TaskId taskId = 7u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->SetMockICloudDB(idb); + cloudSyncer->InitCloudSyncer(7u, SYNC_MODE_CLOUD_FORCE_PUSH); // taskId is 7u CommonExpectCall(iCloud); - EXPECT_CALL(*iCloud, PutMetaData(_, _)).WillRepeatedly(Return(E_OK)); - EXPECT_CALL(*iCloud, FillCloudGid(_)).WillRepeatedly(Return(E_OK)); + BatchExpectCall(iCloud); - CloudSyncData uploadData(cloudSyncer.GetCurrentContextTableName()); - cloudSyncer.initFullCloudSyncData(uploadData, 1000); + CloudSyncData uploadData(cloudSyncer->GetCurrentContextTableName()); + cloudSyncer->initFullCloudSyncData(uploadData, 1000); EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)) .WillRepeatedly([&uploadData](const TableSchema &, const Timestamp &, ContinueToken &continueStmtToken, CloudSyncData &cloudDataResult) { @@ -858,14 +820,15 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck013, TestSize.Level1 extend = uploadData.delData.extend; return OK; }); - int errCode = cloudSyncer.CallDoUpload(taskId); + int errCode = cloudSyncer->CallDoUpload(7u); // taskId is 7u EXPECT_EQ(errCode, E_OK); - cloudSyncer.CallNotify(); + cloudSyncer->CallNotify(); std::this_thread::sleep_for(std::chrono::seconds(1)); - EXPECT_EQ(cloudSyncer.GetUploadSuccessCount(taskId), 3000); - EXPECT_EQ(cloudSyncer.GetUploadFailCount(taskId), 0); - + EXPECT_EQ(cloudSyncer->GetUploadSuccessCount(7u), 3000); // taskId is 7u + EXPECT_EQ(cloudSyncer->GetUploadFailCount(7u), 0); // taskId is 7u + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); RuntimeContext::GetInstance()->StopTaskPool(); storageProxy.reset(); delete iCloud; @@ -882,9 +845,9 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck014, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer2(storageProxy); + TestCloudSyncer *cloudSyncer2 = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb2 = std::make_shared(); - cloudSyncer2.SetMockICloudDB(idb2); + cloudSyncer2->SetMockICloudDB(idb2); TaskId taskId = 8u; CommonExpectCall(iCloud); @@ -892,9 +855,9 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck014, TestSize.Level1 EXPECT_CALL(*iCloud, FillCloudGid(_)).WillRepeatedly(Return(E_OK)); // batch api partially success - cloudSyncer2.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); - CloudSyncData uploadData2(cloudSyncer2.GetCurrentContextTableName()); - cloudSyncer2.initFullCloudSyncData(uploadData2, 1000); + cloudSyncer2->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + CloudSyncData uploadData2(cloudSyncer2->GetCurrentContextTableName()); + cloudSyncer2->initFullCloudSyncData(uploadData2, 1000); EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)).WillRepeatedly( [&uploadData2](const TableSchema &, const Timestamp &, ContinueToken &, CloudSyncData &cloudDataResult) { cloudDataResult = uploadData2; return E_OK; @@ -915,14 +878,16 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck014, TestSize.Level1 extend = uploadData2.updData.extend; return DB_ERROR; }); - int errCode = cloudSyncer2.CallDoUpload(taskId); + int errCode = cloudSyncer2->CallDoUpload(taskId); EXPECT_EQ(errCode, -E_CLOUD_ERROR); - cloudSyncer2.CallNotify(); + cloudSyncer2->CallNotify(); std::this_thread::sleep_for(std::chrono::seconds(1)); - EXPECT_EQ(cloudSyncer2.GetUploadSuccessCount(taskId), 1000); - EXPECT_EQ(cloudSyncer2.GetUploadFailCount(taskId), 2000); + EXPECT_EQ(cloudSyncer2->GetUploadSuccessCount(taskId), 1000); + EXPECT_EQ(cloudSyncer2->GetUploadFailCount(taskId), 2000); RuntimeContext::GetInstance()->StopTaskPool(); + cloudSyncer2->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer2); storageProxy.reset(); delete iCloud; idb2 = nullptr; @@ -939,20 +904,19 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck015, TestSize.Level1 { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer3(storageProxy); + TestCloudSyncer *cloudSyncer3 = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb3 = std::make_shared(); - cloudSyncer3.SetMockICloudDB(idb3); + cloudSyncer3->SetMockICloudDB(idb3); CommonExpectCall(iCloud); - EXPECT_CALL(*iCloud, PutMetaData(_, _)).WillRepeatedly(Return(E_OK)); - EXPECT_CALL(*iCloud, FillCloudGid(_)).WillRepeatedly(Return(E_OK)); + BatchExpectCall(iCloud); // BatchInsert failed, BatchUpdate ok, BatchDelete ok - cloudSyncer3.InitCloudSyncer(9u, SYNC_MODE_CLOUD_FORCE_PUSH); - CloudSyncData uploadData3(cloudSyncer3.GetCurrentContextTableName()); - cloudSyncer3.initFullCloudSyncData(uploadData3, 1000); + cloudSyncer3->InitCloudSyncer(9u, SYNC_MODE_CLOUD_FORCE_PUSH); + CloudSyncData uploadData3(cloudSyncer3->GetCurrentContextTableName()); + cloudSyncer3->initFullCloudSyncData(uploadData3, 1000); EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)) - .WillRepeatedly([&uploadData3](const TableSchema &, const Timestamp &, ContinueToken &, + .WillRepeatedly([&uploadData3](const TableSchema &, const Timestamp &, ContinueToken &, CloudSyncData &cloudDataResult) { cloudDataResult = uploadData3; return E_OK; @@ -977,16 +941,17 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck015, TestSize.Level1 std::vector &&record, std::vector &extend) { record = uploadData3.updData.record; extend = uploadData3.delData.extend; - return OK; + return OK; }); - int errCode = cloudSyncer3.CallDoUpload(9u); - cloudSyncer3.CallNotify(); + EXPECT_EQ(cloudSyncer3->CallDoUpload(9u), -E_CLOUD_ERROR); + cloudSyncer3->CallNotify(); RuntimeContext::GetInstance()->StopTaskPool(); - EXPECT_EQ(errCode, -E_CLOUD_ERROR); - EXPECT_EQ(cloudSyncer3.GetUploadSuccessCount(9u), 0); - EXPECT_EQ(cloudSyncer3.GetUploadFailCount(9u), 3000); + EXPECT_EQ(cloudSyncer3->GetUploadSuccessCount(9u), 0); + EXPECT_EQ(cloudSyncer3->GetUploadFailCount(9u), 3000); + cloudSyncer3->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer3); storageProxy.reset(); delete iCloud; idb3 = nullptr; @@ -1025,11 +990,11 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck016, TestSize.Level1 // update water level successful MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); - cloudSyncer.InitCloudSyncer(8u, SYNC_MODE_CLOUD_MERGE); - cloudSyncer.SetCloudWaterMarks(TABLE_NAME_1, CLOUD_WATER_MARK); + cloudSyncer->SetMockICloudDB(idb); + cloudSyncer->InitCloudSyncer(8u, SYNC_MODE_CLOUD_MERGE); + cloudSyncer->SetCloudWaterMarks(TABLE_NAME_1, CLOUD_WATER_MARK); CommonExpectCall(iCloud); // CheckSchema @@ -1039,8 +1004,8 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck016, TestSize.Level1 return E_OK; }); VBucket tmp = {pair(CloudDbConstant::MODIFY_FIELD, 1)}; - CloudSyncData uploadData(cloudSyncer.GetCurrentContextTableName()); - cloudSyncer.initFullCloudSyncData(uploadData, 1000); + CloudSyncData uploadData(cloudSyncer->GetCurrentContextTableName()); + cloudSyncer->initFullCloudSyncData(uploadData, 1000); EXPECT_CALL(*iCloud, FillCloudGid(_)).WillRepeatedly(Return(E_OK)); EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)) @@ -1050,14 +1015,15 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck016, TestSize.Level1 return E_OK; }); ExpectCallForTestCase016(idb, uploadData); - EXPECT_EQ(cloudSyncer.CallDoUpload(8u), E_OK); + EXPECT_EQ(cloudSyncer->CallDoUpload(8u), E_OK); EXPECT_CALL(*iCloud, PutMetaData(_, _)).WillOnce(Return(-E_INVALID_DB)); - EXPECT_EQ(cloudSyncer.CallDoUpload(8u), -E_INVALID_DB); + EXPECT_EQ(cloudSyncer->CallDoUpload(8u), -E_INVALID_DB); EXPECT_CALL(*iCloud, PutMetaData(_, _)).WillOnce(Return(-E_INVALID_ARGS)); - EXPECT_EQ(cloudSyncer.CallDoUpload(8u), -E_INVALID_ARGS); + EXPECT_EQ(cloudSyncer->CallDoUpload(8u), -E_INVALID_ARGS); RuntimeContext::GetInstance()->StopTaskPool(); - + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -1087,24 +1053,24 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck018, TestSize.Level1 auto *iCloud = new(std::nothrow) MockICloudSyncStorageInterface(); ASSERT_NE(iCloud, nullptr); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); auto idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); - cloudSyncer.InitCloudSyncer(5u, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->SetMockICloudDB(idb); + cloudSyncer->InitCloudSyncer(5u, SYNC_MODE_CLOUD_FORCE_PUSH); CommonExpectCall(iCloud); MockCall(iCloud, idb); // Batch_n CloudSyncData quantity > total count VBucket tmp = {pair(CloudDbConstant::MODIFY_FIELD, 1)}; - cloudSyncer.InitCloudSyncer(5u, SYNC_MODE_CLOUD_FORCE_PUSH); - CloudSyncData uploadData2(cloudSyncer.GetCurrentContextTableName()); + cloudSyncer->InitCloudSyncer(5u, SYNC_MODE_CLOUD_FORCE_PUSH); + CloudSyncData uploadData2(cloudSyncer->GetCurrentContextTableName()); uploadData2.insData.record = std::vector(1000, tmp); uploadData2.insData.extend = std::vector(1000, tmp); SyncTimeRange syncTimeRange = { .beginTime = 1u }; QueryObject queryObject(Query::Select()); - queryObject.SetTableName(cloudSyncer.GetCurrentContextTableName()); + queryObject.SetTableName(cloudSyncer->GetCurrentContextTableName()); auto token = new (std::nothrow) SQLiteSingleVerRelationalContinueToken(syncTimeRange, queryObject); auto conStmtToken = static_cast(token); delete token; @@ -1116,7 +1082,7 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck018, TestSize.Level1 return -E_UNFINISHED; }); - CloudSyncData uploadData3(cloudSyncer.GetCurrentContextTableName()); + CloudSyncData uploadData3(cloudSyncer->GetCurrentContextTableName()); uploadData3.insData.extend = std::vector(2001, tmp); uploadData3.insData.record = std::vector(2001, tmp); EXPECT_CALL(*iCloud, GetCloudDataNext(_, _)).WillOnce( @@ -1125,15 +1091,16 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadModeCheck018, TestSize.Level1 return E_OK; }); std::atomic callCount = 0; - cloudSyncer.SetCurrentCloudTaskInfos({"TABLE"}, [&callCount](const std::map &) { + cloudSyncer->SetCurrentCloudTaskInfos({"TABLE"}, [&callCount](const std::map &) { callCount++; }); - int errCode = cloudSyncer.CallDoUpload(5u, true); + int errCode = cloudSyncer->CallDoUpload(5u, true); EXPECT_EQ(errCode, -E_INTERNAL_ERROR); RuntimeContext::GetInstance()->StopTaskPool(); EXPECT_EQ(callCount, 1); - + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -1163,27 +1130,32 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadNotifyCheck001, TestSize.Leve { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); TaskId taskId = 17u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); std::string tableName2 = "TestTable2" + std::to_string(taskId); - std::vector tables = {cloudSyncer.GetCurrentContextTableName(), tableName2}; + std::vector tables = {cloudSyncer->GetCurrentContextTableName(), tableName2}; SyncProcess res; TableProcessInfo tbProcessInfo; - res.tableProcess[cloudSyncer.GetCurrentContextTableName()] = tbProcessInfo; + res.tableProcess[cloudSyncer->GetCurrentContextTableName()] = tbProcessInfo; res.tableProcess[tableName2] = tbProcessInfo; - cloudSyncer.SetCurrentCloudTaskInfos(tables, [&res]( + std::mutex mutex; + cloudSyncer->SetCurrentCloudTaskInfos(tables, [&res, &mutex]( const std::map &process) { + std::lock_guard autoLock(mutex); + if (process.empty()) { + return; + } res = process.begin()->second; }); CommonExpectCall(iCloud); MockMethod(idb, iCloud); - CloudSyncData uploadData(cloudSyncer.GetCurrentContextTableName()); - cloudSyncer.initFullCloudSyncData(uploadData, 1000); // each size 1000 + CloudSyncData uploadData(cloudSyncer->GetCurrentContextTableName()); + cloudSyncer->initFullCloudSyncData(uploadData, 1000); // each size 1000 CloudSyncData uploadData2(tableName2); - cloudSyncer.initFullCloudSyncData(uploadData2, 1000); // each size 1000 + cloudSyncer->initFullCloudSyncData(uploadData2, 1000); // each size 1000 EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)) .WillOnce([&uploadData](const TableSchema &, const Timestamp &, @@ -1195,12 +1167,14 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadNotifyCheck001, TestSize.Leve cloudDataResult = uploadData2; return E_OK;}); - EXPECT_EQ(cloudSyncer.CallDoSyncInner(cloudSyncer.GetCurrentCloudTaskInfos(), true), E_OK); - EXPECT_EQ(res.tableProcess[cloudSyncer.GetCurrentContextTableName()].process, PROCESSING); - cloudSyncer.CallNotify(); + EXPECT_EQ(cloudSyncer->CallDoSyncInner(cloudSyncer->GetCurrentCloudTaskInfos(), true), E_OK); + EXPECT_EQ(res.tableProcess[cloudSyncer->GetCurrentContextTableName()].process, PROCESSING); + cloudSyncer->CallNotify(); RuntimeContext::GetInstance()->StopTaskPool(); - EXPECT_EQ(res.tableProcess[cloudSyncer.GetCurrentContextTableName()].process, FINISHED); + EXPECT_EQ(res.tableProcess[cloudSyncer->GetCurrentContextTableName()].process, FINISHED); EXPECT_EQ(res.tableProcess[tableName2].process, FINISHED); + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -1217,22 +1191,25 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadNotifyCheck002, TestSize.Leve { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); TaskId taskId = 17u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); std::string tableName2 = "TestTable2" + std::to_string(taskId); - std::vector tables = { - cloudSyncer.GetCurrentContextTableName(), tableName2 - }; + std::vector tables = {cloudSyncer->GetCurrentContextTableName(), tableName2}; SyncProcess res; TableProcessInfo tbProcessInfo; - res.tableProcess[cloudSyncer.GetCurrentContextTableName()] = tbProcessInfo; + res.tableProcess[cloudSyncer->GetCurrentContextTableName()] = tbProcessInfo; res.tableProcess[tableName2] = tbProcessInfo; - cloudSyncer.SetCurrentCloudTaskInfos(tables, [&res]( + std::mutex mutex; + cloudSyncer->SetCurrentCloudTaskInfos(tables, [&res, &mutex]( const std::map &process) { + std::lock_guard autoLock(mutex); + if (process.empty()) { + return; + } res = process.begin()->second; }); CommonExpectCall(iCloud); @@ -1244,10 +1221,9 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadNotifyCheck002, TestSize.Leve EXPECT_CALL(*iCloud, GetUploadCount(_, _, _, _)) .WillRepeatedly([](const std::string &, const Timestamp &, const bool, int64_t & count) { count = 3000; // total count is 3000 - return E_OK; - }); - CloudSyncData uploadData(cloudSyncer.GetCurrentContextTableName()); - cloudSyncer.initFullCloudSyncData(uploadData, 1000); // each size 1000 + return E_OK;}); + CloudSyncData uploadData(cloudSyncer->GetCurrentContextTableName()); + cloudSyncer->initFullCloudSyncData(uploadData, 1000); // each size 1000 EXPECT_CALL(*iCloud, GetCloudData(_, _, _, _)) .WillOnce([&uploadData](const TableSchema &, const Timestamp &, @@ -1255,11 +1231,13 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadNotifyCheck002, TestSize.Leve cloudDataResult = uploadData; return E_OK;}); - EXPECT_EQ(cloudSyncer.CallDoSyncInner(cloudSyncer.GetCurrentCloudTaskInfos(), true), -E_CLOUD_ERROR); - cloudSyncer.CallNotify(); + EXPECT_EQ(cloudSyncer->CallDoSyncInner(cloudSyncer->GetCurrentCloudTaskInfos(), true), -E_CLOUD_ERROR); + cloudSyncer->CallNotify(); RuntimeContext::GetInstance()->StopTaskPool(); - EXPECT_EQ(res.tableProcess[cloudSyncer.GetCurrentContextTableName()].process, PROCESSING); + EXPECT_EQ(res.tableProcess[cloudSyncer->GetCurrentContextTableName()].process, PROCESSING); EXPECT_EQ(res.tableProcess[tableName2].process, PROCESSING); + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; @@ -1276,22 +1254,27 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadNotifyCheck003, TestSize.Leve { MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); std::shared_ptr storageProxy = std::make_shared(iCloud); - TestCloudSyncer cloudSyncer(storageProxy); + TestCloudSyncer *cloudSyncer = new(std::nothrow) TestCloudSyncer(storageProxy); std::shared_ptr idb = std::make_shared(); - cloudSyncer.SetMockICloudDB(idb); + cloudSyncer->SetMockICloudDB(idb); TaskId taskId = 19u; - cloudSyncer.InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); + cloudSyncer->InitCloudSyncer(taskId, SYNC_MODE_CLOUD_FORCE_PUSH); std::string tableName2 = "TestTable2" + std::to_string(taskId); std::vector tables = { - cloudSyncer.GetCurrentContextTableName(), tableName2 + cloudSyncer->GetCurrentContextTableName(), tableName2 }; SyncProcess res; TableProcessInfo tbProcessInfo; - res.tableProcess[cloudSyncer.GetCurrentContextTableName()] = tbProcessInfo; + res.tableProcess[cloudSyncer->GetCurrentContextTableName()] = tbProcessInfo; res.tableProcess[tableName2] = tbProcessInfo; - cloudSyncer.SetCurrentCloudTaskInfos(tables, [&res]( + std::mutex mutex; + cloudSyncer->SetCurrentCloudTaskInfos(tables, [&res, &mutex]( const std::map &process) { + std::lock_guard autoLock(mutex); + if (process.empty()) { + return; + } res = process.begin()->second; }); CommonExpectCall(iCloud); @@ -1306,11 +1289,13 @@ HWTEST_F(DistributedDBCloudSyncerUploadTest, UploadNotifyCheck003, TestSize.Leve return E_OK; }); // test when count == 0 - EXPECT_EQ(cloudSyncer.CallDoSyncInner(cloudSyncer.GetCurrentCloudTaskInfos(), true), E_OK); - cloudSyncer.CallNotify(); + EXPECT_EQ(cloudSyncer->CallDoSyncInner(cloudSyncer->GetCurrentCloudTaskInfos(), true), E_OK); + cloudSyncer->CallNotify(); RuntimeContext::GetInstance()->StopTaskPool(); - EXPECT_EQ(res.tableProcess[cloudSyncer.GetCurrentContextTableName()].process, FINISHED); + EXPECT_EQ(res.tableProcess[cloudSyncer->GetCurrentContextTableName()].process, FINISHED); EXPECT_EQ(res.tableProcess[tableName2].process, FINISHED); + cloudSyncer->CallClose(); + RefObject::KillAndDecObjRef(cloudSyncer); storageProxy.reset(); delete iCloud; idb = nullptr; diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h index aed113e8..2c182d39 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h @@ -41,7 +41,7 @@ public: MOCK_METHOD3(CleanCloudData, int(ClearMode mode, const std::vector &tableNameList, std::vector &assets)); MOCK_METHOD3(FillCloudAssetForDownload, int(const std::string &, VBucket &, bool)); - MOCK_METHOD1(FillCloudAssetForUpload, int(const CloudSyncData &)); + MOCK_METHOD2(FillCloudGidAndAsset, int(const OpType &, const CloudSyncData &)); }; } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp index f7166ab8..5afb7d11 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp @@ -87,6 +87,9 @@ DBStatus VirtualCloudDb::BatchDelete(const std::string &tableName, std::vector &data) { + if (actionStatus_ != OK) { + return actionStatus_; + } if (cloudError_) { return DB_ERROR; } if (blockTimeMs_ != 0) { std::this_thread::sleep_for(std::chrono::milliseconds(blockTimeMs_)); } + if (queryTimes_.find(tableName) == queryTimes_.end()) { + queryTimes_.try_emplace(tableName, 0); + } + queryTimes_[tableName]++; std::lock_guard autoLock(cloudDataMutex_); if (cloudData_.find(tableName) == cloudData_.end()) { return QUERY_END; } - LOGD("extend size: %zu type: %zu expect: %zu", extend.size(), extend[g_cursorField].index(), - TYPE_INDEX); std::string cursor = std::get(extend[g_cursorField]); - cursor = cursor.empty() ? "0" : cursor; - for (auto &tableData : cloudData_[tableName]) { + bool isIncreCursor = (cursor.substr(0, increPrefix_.size()) == increPrefix_); + LOGD("extend size: %zu type: %zu expect: %zu, cursor: %s", extend.size(), extend[g_cursorField].index(), + TYPE_INDEX, cursor.c_str()); + if (isIncreCursor) { + GetCloudData(cursor, isIncreCursor, incrementCloudData_[tableName], data); + } else { + cursor = cursor.empty() ? "0" : cursor; + GetCloudData(cursor, isIncreCursor, cloudData_[tableName], data); + } + if (!isIncreCursor && data.empty() && isSetCrementCloudData_) { + extend[g_cursorField] = increPrefix_; + return OK; + } + return (data.empty() || data.size() < static_cast(queryLimit_)) ? QUERY_END : OK; +} + +void VirtualCloudDb::GetCloudData(const std::string &cursor, bool isIncreCursor, std::vector allData, + std::vector &data) +{ + for (auto &tableData : allData) { std::string srcCursor = std::get(tableData.extend[g_cursorField]); - if (std::stol(srcCursor) > std::stol(cursor)) { + if ((!isIncreCursor && std::stol(srcCursor) > std::stol(cursor)) || isIncreCursor) { VBucket bucket = tableData.record; for (const auto &ex: tableData.extend) { bucket.insert(ex); @@ -158,10 +184,9 @@ DBStatus VirtualCloudDb::Query(const std::string &tableName, VBucket &extend, st data.push_back(std::move(bucket)); } if (data.size() >= static_cast(queryLimit_)) { - return OK; + return; } } - return (data.empty() || data.size() < static_cast(queryLimit_)) ? QUERY_END : OK; } DBStatus VirtualCloudDb::InnerUpdate(const std::string &tableName, std::vector &&record, @@ -250,4 +275,29 @@ void VirtualCloudDb::SetHeartbeatError(bool heartbeatError) { heartbeatError_ = heartbeatError; } + +void VirtualCloudDb::SetIncrementData(const std::string &tableName, const VBucket &record, const VBucket &extend) +{ + std::lock_guard autoLock(cloudDataMutex_); + isSetCrementCloudData_ = true; + auto iter = incrementCloudData_.find(tableName); + if (iter == incrementCloudData_.end()) { + return; + } + CloudData data = {record, extend}; + iter->second.push_back(data); +} + +uint32_t VirtualCloudDb::GetQueryTimes(const std::string &tableName) +{ + if (queryTimes_.find(tableName) == queryTimes_.end()) { + return 0; + } + return queryTimes_[tableName]; +} + +void VirtualCloudDb::SetActionStatus(DBStatus status) +{ + actionStatus_ = status; +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h index e536e7f2..4b7054c5 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h @@ -53,6 +53,12 @@ public: bool GetLockStatus(); void SetHeartbeatError(bool heartbeatError); + + void SetIncrementData(const std::string &tableName, const VBucket &record, const VBucket &extend); + + uint32_t GetQueryTimes(const std::string &tableName); + + void SetActionStatus(DBStatus status); private: struct CloudData { VBucket record; @@ -64,6 +70,9 @@ private: DBStatus UpdateCloudData(const std::string &tableName, CloudData &&cloudData); + void GetCloudData(const std::string &cursor, bool isIncreCursor, std::vector allData, + std::vector &data); + std::atomic cloudError_ = false; std::atomic heartbeatError_ = false; std::atomic lockStatus_ = false; @@ -74,6 +83,11 @@ private: std::atomic heartbeatCount_ = 0; std::mutex cloudDataMutex_; std::map> cloudData_; + std::map> incrementCloudData_; + bool isSetCrementCloudData_ = false; + std::string increPrefix_ = "increPrefix_"; + std::map queryTimes_; + DBStatus actionStatus_ = OK; }; } #endif // VIRTUAL_CLOUD_DB_H diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.cpp index 0aa8627d..15afa3aa 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.cpp @@ -68,4 +68,10 @@ void VirtualCloudSyncer::Notify(bool notifyIfError) std::lock_guard autoLock(contextLock_); currentContext_.notifier->NotifyProcess(taskInfo, {}, notifyIfError); } + +size_t VirtualCloudSyncer::GetQueueCount() +{ + std::lock_guard autoLock(queueLock_); + return taskQueue_.size(); +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.h index 73df6a86..ad35668a 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.h @@ -31,6 +31,8 @@ public: void SetDownloadFunc(const std::function &); void Notify(bool notifyIfError = false); + + size_t GetQueueCount(); private: std::function downloadFunc_; std::atomic doDownload_; diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp index 86c18e51..c35cd16e 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp @@ -380,7 +380,6 @@ void TimeSync001() delete storage; delete communicator; } -} class DistributedDBMockSyncModuleTest : public testing::Test { public: @@ -796,6 +795,31 @@ HWTEST_F(DistributedDBMockSyncModuleTest, DataSyncCheck003, TestSize.Level1) } #endif +/** + * @tc.name: DataSyncCheck004 + * @tc.desc: Test dataSync do ability sync. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBMockSyncModuleTest, DataSyncCheck004, TestSize.Level1) +{ + MockSingleVerDataSync dataSync; + auto *message = new (std::nothrow) DistributedDB::Message(); + ASSERT_TRUE(message != nullptr); + message->SetMessageType(TYPE_NOTIFY); + auto *context = new (std::nothrow) SingleVerKvSyncTaskContext(); + ASSERT_NE(context, nullptr); + auto *communicator = new (std::nothrow) VirtualCommunicator("DEVICE", nullptr); + ASSERT_NE(communicator, nullptr); + dataSync.SetCommunicatorHandle(communicator); + EXPECT_EQ(dataSync.CallDoAbilitySyncIfNeed(context, message, false), -E_NEED_ABILITY_SYNC); + delete message; + RefObject::KillAndDecObjRef(context); + dataSync.SetCommunicatorHandle(nullptr); + RefObject::KillAndDecObjRef(communicator); +} + /** * @tc.name: AutoLaunchCheck001 * @tc.desc: Test autoLaunch close connection. @@ -1741,6 +1765,45 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncTaskContextCheck005, TestSize.Leve EXPECT_EQ(context->GetQuerySyncId(), ""); RefObject::KillAndDecObjRef(context); } + +/** + * @tc.name: SyncTaskContextCheck006 + * @tc.desc: test context call get query id async. + * @tc.type: FUNC + * @tc.require: AR000CCPOM + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBMockSyncModuleTest, SyncTaskContextCheck006, TestSize.Level1) +{ + /** + * @tc.steps: step1. prepare context + */ + auto context = new (std::nothrow) SingleVerRelationalSyncTaskContext(); + ASSERT_NE(context, nullptr); + VirtualCommunicator communicator("device", nullptr); + VirtualSingleVerSyncDBInterface dbSyncInterface; + SingleVerSyncStateMachine stateMachine; + std::shared_ptr metadata = std::make_shared(); + ASSERT_EQ(metadata->Initialize(&dbSyncInterface), E_OK); + (void)stateMachine.Initialize(context, &dbSyncInterface, metadata, &communicator); + (void)context->Initialize("device", &dbSyncInterface, metadata, &communicator); + /** + * @tc.steps: step2. add sync target into context + */ + auto target = new (std::nothrow) SingleVerSyncTarget(); + ASSERT_NE(target, nullptr); + target->SetTaskType(ISyncTarget::RESPONSE); + EXPECT_EQ(context->AddSyncTarget(target), E_OK); + /** + * @tc.steps: step3. move to next target + * @tc.expected: retry time will be reset to zero + */ + context->SetRetryTime(AUTO_RETRY_TIMES); + context->MoveToNextTarget(); + EXPECT_EQ(context->GetRetryTime(), 0); + context->Clear(); + RefObject::KillAndDecObjRef(context); +} #ifdef RUN_AS_ROOT /** * @tc.name: TimeChangeListenerTest001 @@ -1946,6 +2009,31 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncerCheck006, TestSize.Level1) delete syncDBInterface; } +/** + * @tc.name: SyncerCheck007 + * @tc.desc: Test syncer get sync data size without syncer lock. + * @tc.type: FUNC + * @tc.require: AR000CCPOM + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBMockSyncModuleTest, SyncerCheck007, TestSize.Level1) +{ + MockSingleVerKVSyncer syncer; + auto mockMeta = std::make_shared(); + auto metadata = std::static_pointer_cast(mockMeta); + EXPECT_CALL(*mockMeta, GetLocalWaterMark).WillRepeatedly([&syncer](const DeviceID &, uint64_t &) { + syncer.TestSyncerLock(); + }); + syncer.SetMetadata(metadata); + auto syncDBInterface = new VirtualSingleVerSyncDBInterface(); + ASSERT_NE(syncDBInterface, nullptr); + syncer.Init(nullptr, syncDBInterface, true); + size_t size = 0u; + EXPECT_EQ(syncer.GetSyncDataSize("device", size), E_OK); + syncer.SetMetadata(nullptr); + delete syncDBInterface; +} + /** * @tc.name: SessionId001 * @tc.desc: Test syncer call set sync retry before init. @@ -2018,4 +2106,23 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SingleVerDataSyncUtils001, TestSize.Le SingleVerDataSyncUtils::TransSendDataItemToLocal(&context, "", data); EXPECT_NE(data[0]->GetTimestamp(), data[1]->GetTimestamp()); SingleVerKvEntry::Release(data); +} + +/** + * @tc.name: SyncTimerResetTest001 + * @tc.desc: Test it will retrurn ok when sync with a timer already exists. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangshijie + */ +HWTEST_F(DistributedDBMockSyncModuleTest, SyncTimerResetTest001, TestSize.Level1) { + MockSingleVerStateMachine stateMachine; + MockSyncTaskContext syncTaskContext; + MockCommunicator communicator; + VirtualSingleVerSyncDBInterface dbSyncInterface; + Init(stateMachine, syncTaskContext, communicator, dbSyncInterface); + + EXPECT_EQ(stateMachine.CallStartWatchDog(), E_OK); + EXPECT_EQ(stateMachine.CallPrepareNextSyncTask(), E_OK); +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_ver_p2p_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_ver_p2p_sync_test.cpp index d7b40533..96f00bbe 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_ver_p2p_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_ver_p2p_sync_test.cpp @@ -2117,6 +2117,26 @@ HWTEST_F(DistributedDBRelationalVerP2PSyncTest, RemoteQuery011, TestSize.Level1) EXPECT_EQ(result, nullptr); } +/** +* @tc.name: remote query 012 +* @tc.desc: Test rdb remote query with invalid dev +* @tc.type: FUNC +* @tc.require: AR000GK58G +* @tc.author: zhangqiquan +*/ +HWTEST_F(DistributedDBRelationalVerP2PSyncTest, RemoteQuery012, TestSize.Level1) +{ + std::map dataMap; + std::string invalidDev = std::string(DBConstant::MAX_DEV_LENGTH + 1, '0'); + PrepareEnvironment(dataMap, {g_deviceB}); + ASSERT_NE(g_rdbDelegatePtr, nullptr); + RemoteCondition condition; + condition.sql = "SELECT * FROM " + g_tableName; + std::shared_ptr result = nullptr; + EXPECT_EQ(g_rdbDelegatePtr->RemoteQuery(invalidDev, condition, DBConstant::MIN_TIMEOUT, result), INVALID_ARGS); + EXPECT_EQ(result, nullptr); +} + /** * @tc.name: RelationalPemissionTest001 * @tc.desc: deviceB PermissionCheck not pass test, SYNC_MODE_PUSH_ONLY diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_simple_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_simple_sync_test.cpp index 4faed0f4..20c4d463 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_simple_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_simple_sync_test.cpp @@ -745,8 +745,10 @@ HWTEST_F(DistributedDBSingleVerP2PSimpleSyncTest, NormalSync010, TestSize.Level1 { DBStatus status = OK; std::vector devices; + std::string invalidDev = std::string(DBConstant::MAX_DEV_LENGTH + 1, '0'); devices.push_back(DEVICE_A); devices.push_back(g_deviceB->GetDeviceId()); + devices.push_back(invalidDev); std::map result; status = g_tool.SyncTest(g_kvDelegatePtr, devices, SYNC_MODE_PUSH_ONLY, result); @@ -754,6 +756,7 @@ HWTEST_F(DistributedDBSingleVerP2PSimpleSyncTest, NormalSync010, TestSize.Level1 ASSERT_EQ(result.size(), devices.size()); EXPECT_EQ(result[DEVICE_A], INVALID_ARGS); + EXPECT_EQ(result[invalidDev], INVALID_ARGS); EXPECT_EQ(result[DEVICE_B], OK); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_meta_data.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_meta_data.h index c1e83d6e..b9a29d0d 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_meta_data.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_meta_data.h @@ -24,6 +24,8 @@ public: MOCK_METHOD3(SetLastQueryTime, int(const std::string &, const std::string &, const Timestamp &)); MOCK_METHOD3(GetLastQueryTime, int(const std::string &, const std::string &, Timestamp &)); + + MOCK_METHOD2(GetLocalWaterMark, void(const DeviceID &, uint64_t &)); }; } // namespace DistributedDB #endif // #define MOCK_META_DATA_H \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_data_sync.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_data_sync.h index 550ece3d..c8d28c51 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_data_sync.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_data_sync.h @@ -42,6 +42,16 @@ public: return SingleVerDataSync::RemoveDeviceDataIfNeed(context); } + int CallDoAbilitySyncIfNeed(SingleVerSyncTaskContext *context, const Message *message, bool isControlMsg) + { + return SingleVerDataSync::DoAbilitySyncIfNeed(context, message, isControlMsg); + } + + void SetCommunicatorHandle(ICommunicator *communicator) + { + communicateHandle_ = communicator; + } + MOCK_METHOD1(RemoveDeviceDataIfNeed, int(SingleVerSyncTaskContext *)); }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_kv_syncer.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_kv_syncer.h index a479a092..4bb7d46e 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_kv_syncer.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_kv_syncer.h @@ -47,6 +47,13 @@ public: { metadata_ = metadata; } + + void TestSyncerLock() + { + LOGD("begin get lock"); + std::lock_guard autoLock(syncerLock_); + LOGD("get lock success"); + } }; } #endif // MOCK_SINGLE_VER_KV_SYNCER_H diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_state_machine.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_state_machine.h index 9b7fbb37..8598c3b5 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_state_machine.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_single_ver_state_machine.h @@ -57,6 +57,16 @@ public: SyncStateMachine::SwitchMachineState(event); } + int CallPrepareNextSyncTask() + { + return SingleVerSyncStateMachine::PrepareNextSyncTask(); + } + + int CallStartWatchDog() + { + return SingleVerSyncStateMachine::StartWatchDog(); + } + uint8_t GetCurrentState() { return currentState_; diff --git a/kv_store/interfaces/innerkits/distributeddata/BUILD.gn b/kv_store/interfaces/innerkits/distributeddata/BUILD.gn index 9b6da14b..9d75c7cc 100644 --- a/kv_store/interfaces/innerkits/distributeddata/BUILD.gn +++ b/kv_store/interfaces/innerkits/distributeddata/BUILD.gn @@ -91,10 +91,10 @@ deps_config = [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distri external_deps_config = [ "c_utils:utils", "device_manager:devicemanagersdk", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", + "hilog:libhilog", "huks:libhukssdk", "ipc:ipc_single", "samgr:samgr_proxy", diff --git a/kv_store/interfaces/jskits/distributeddata/BUILD.gn b/kv_store/interfaces/jskits/distributeddata/BUILD.gn index e046791e..3957fda7 100644 --- a/kv_store/interfaces/jskits/distributeddata/BUILD.gn +++ b/kv_store/interfaces/jskits/distributeddata/BUILD.gn @@ -75,7 +75,7 @@ ohos_shared_library("distributeddata") { "ability_runtime:napi_base_context", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "napi:ace_napi", ] diff --git a/kv_store/interfaces/jskits/distributedkvstore/BUILD.gn b/kv_store/interfaces/jskits/distributedkvstore/BUILD.gn index 832daa84..0f871bf6 100644 --- a/kv_store/interfaces/jskits/distributedkvstore/BUILD.gn +++ b/kv_store/interfaces/jskits/distributedkvstore/BUILD.gn @@ -75,7 +75,7 @@ ohos_shared_library("distributedkvstore") { "ability_runtime:napi_base_context", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "napi:ace_napi", ] diff --git a/kv_store/test/distributedtest/single_kvstore_client/BUILD.gn b/kv_store/test/distributedtest/single_kvstore_client/BUILD.gn index 7ce4568d..56479110 100644 --- a/kv_store/test/distributedtest/single_kvstore_client/BUILD.gn +++ b/kv_store/test/distributedtest/single_kvstore_client/BUILD.gn @@ -92,10 +92,10 @@ ohos_distributedtest("DistributedTest") { external_deps = [ "c_utils:utils", "device_manager:devicemanagersdk", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", "huks:libhukssdk", "ipc:ipc_core", "samgr:samgr_proxy", @@ -120,10 +120,10 @@ ohos_distributedtest("DistributedTestAgent") { external_deps = [ "c_utils:utils", "device_manager:devicemanagersdk", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", "huks:libhukssdk", "ipc:ipc_core", "samgr:samgr_proxy", diff --git a/kv_store/test/fuzztest/blob_fuzzer/BUILD.gn b/kv_store/test/fuzztest/blob_fuzzer/BUILD.gn index edc1b818..80279776 100644 --- a/kv_store/test/fuzztest/blob_fuzzer/BUILD.gn +++ b/kv_store/test/fuzztest/blob_fuzzer/BUILD.gn @@ -45,7 +45,7 @@ ohos_fuzztest("BlobFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", ] } diff --git a/kv_store/test/fuzztest/devicekvstore_fuzzer/BUILD.gn b/kv_store/test/fuzztest/devicekvstore_fuzzer/BUILD.gn index b1fbfb4b..b6e3d4bb 100644 --- a/kv_store/test/fuzztest/devicekvstore_fuzzer/BUILD.gn +++ b/kv_store/test/fuzztest/devicekvstore_fuzzer/BUILD.gn @@ -35,7 +35,7 @@ ohos_fuzztest("DeviceKvStoreFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "kv_store:distributeddata_inner", ] } diff --git a/kv_store/test/fuzztest/distributedkvdatamanager_fuzzer/BUILD.gn b/kv_store/test/fuzztest/distributedkvdatamanager_fuzzer/BUILD.gn index 2f838ded..4d286a2d 100644 --- a/kv_store/test/fuzztest/distributedkvdatamanager_fuzzer/BUILD.gn +++ b/kv_store/test/fuzztest/distributedkvdatamanager_fuzzer/BUILD.gn @@ -40,7 +40,7 @@ ohos_fuzztest("DistributedKvDataManagerFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "kv_store:distributeddata_inner", ] } diff --git a/kv_store/test/fuzztest/singlekvstore_fuzzer/BUILD.gn b/kv_store/test/fuzztest/singlekvstore_fuzzer/BUILD.gn index b5f62a24..d767c8b1 100644 --- a/kv_store/test/fuzztest/singlekvstore_fuzzer/BUILD.gn +++ b/kv_store/test/fuzztest/singlekvstore_fuzzer/BUILD.gn @@ -41,7 +41,7 @@ ohos_fuzztest("SingleKvStoreFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "kv_store:distributeddata_inner", ] } diff --git a/kv_store/test/fuzztest/typesutil_fuzzer/BUILD.gn b/kv_store/test/fuzztest/typesutil_fuzzer/BUILD.gn index 77818a65..f60d24c0 100644 --- a/kv_store/test/fuzztest/typesutil_fuzzer/BUILD.gn +++ b/kv_store/test/fuzztest/typesutil_fuzzer/BUILD.gn @@ -48,7 +48,7 @@ ohos_fuzztest("TypesUtilFuzzTest") { external_deps = [ "c_utils:utils", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", "kv_store:distributeddata_inner", ] diff --git a/mock/napi/native_common.h b/mock/napi/native_common.h index 188c3c0c..06d4d094 100644 --- a/mock/napi/native_common.h +++ b/mock/napi/native_common.h @@ -18,7 +18,7 @@ #define DEPRECATED __attribute__((__deprecated__)) #ifndef NAPI_VERSION -#define NAPI_VERSION 2 +#define NAPI_VERSION 8 #endif #define NAPI_RETVAL_NOTHING diff --git a/mock/napi/src/js_native_api.h b/mock/napi/src/js_native_api.h index 5daa20f9..c474debe 100644 --- a/mock/napi/src/js_native_api.h +++ b/mock/napi/src/js_native_api.h @@ -69,6 +69,9 @@ NAPI_EXTERN napi_status napi_create_array_with_length(napi_env env, NAPI_EXTERN napi_status napi_create_double(napi_env env, double value, napi_value* result); +NAPI_EXTERN napi_status napi_create_double(napi_env env, + double value, + napi_value* result); NAPI_EXTERN napi_status napi_create_int32(napi_env env, int32_t value, napi_value* result); diff --git a/mock/src/mock_js_napi.cpp b/mock/src/mock_js_napi.cpp index be4d6188..9b6e0a78 100644 --- a/mock/src/mock_js_napi.cpp +++ b/mock/src/mock_js_napi.cpp @@ -58,6 +58,7 @@ napi_status napi_create_typedarray(napi_env env, napi_typedarray_type type, size napi_status napi_create_int32(napi_env env, int32_t value, napi_value *result) { return napi_ok; } napi_status napi_create_int64(napi_env env, int64_t value, napi_value *result) { return napi_ok; } napi_status napi_create_double(napi_env env, double value, napi_value *result) { return napi_ok; } +napi_status napi_create_date(napi_env env, double value, napi_value *result) { return napi_ok; } napi_status napi_get_boolean(napi_env env, bool value, napi_value *result) { return napi_ok; } napi_status napi_define_class(napi_env env, const char *utf8name, size_t length, napi_callback constructor, void *callback_data, size_t property_count, const napi_property_descriptor *properties, diff --git a/relational_store/CMakeLists.txt b/relational_store/CMakeLists.txt index 9abf12e4..964f741a 100644 --- a/relational_store/CMakeLists.txt +++ b/relational_store/CMakeLists.txt @@ -12,8 +12,9 @@ set(MOCK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../mock) set(KV_STORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../kv_store) add_definitions(-DNAPI_EXPERIMENTAL) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/common/src relational_store_src) -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/dataability/src relational_store_src) -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/rdb/src relational_store_src) +#aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/dataability/src relational_store_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/relationalstore/src relational_store_src) +#aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/rdb/src relational_store_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/appdatafwk/src relational_store_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/dataability/src relational_store_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/rdb/src relational_store_src) @@ -30,8 +31,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/inner_api/rdb_data_ab include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/inner_api/rdb_data_share_adapter/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/common/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/common/include) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/dataability/include) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/rdb/include) +#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/dataability/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/relationalstore/include) +#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/rdb/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/dataability/src) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/rdb/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/rdb_device_manager_adapter/include) diff --git a/relational_store/bundle.json b/relational_store/bundle.json index 020d453b..cb43a48b 100644 --- a/relational_store/bundle.json +++ b/relational_store/bundle.json @@ -53,9 +53,8 @@ "common_event_service", "c_utils", "device_manager", - "hilog_native", - "hitrace_native", - "hiviewdfx_hilog_native", + "hilog", + "hitrace", "huks", "ipc", "napi", diff --git a/relational_store/frameworks/js/napi/cloud_data/BUILD.gn b/relational_store/frameworks/js/napi/cloud_data/BUILD.gn index 0991ef48..2aaac109 100644 --- a/relational_store/frameworks/js/napi/cloud_data/BUILD.gn +++ b/relational_store/frameworks/js/napi/cloud_data/BUILD.gn @@ -49,9 +49,8 @@ ohos_shared_library("clouddata") { "ability_runtime:abilitykit_native", "ability_runtime:napi_base_context", "c_utils:utils", - "hilog_native:libhilog", - "hitrace_native:hitrace_meter", - "hiviewdfx_hilog_native:libhilog", + "hilog:libhilog", + "hitrace:hitrace_meter", "ipc:ipc_core", "napi:ace_napi", "samgr:samgr_proxy", diff --git a/relational_store/frameworks/js/napi/common/include/js_utils.h b/relational_store/frameworks/js/napi/common/include/js_utils.h index 5f078525..0f2f3d86 100644 --- a/relational_store/frameworks/js/napi/common/include/js_utils.h +++ b/relational_store/frameworks/js/napi/common/include/js_utils.h @@ -113,9 +113,27 @@ napi_value Convert2JSValue(napi_env env, const T &value); template napi_value Convert2JSValue(napi_env env, const std::vector &value); +template +napi_value Convert2JSValue(napi_env env, const std::map &value); + template napi_value Convert2JSValue(napi_env env, const std::variant &value); +template +std::string ToString(const T &key); + +template +std::enable_if_t, std::string> ConvertMapKey(const K &key) +{ + return ToString(key); +} + +template +std::enable_if_t, const std::string &> ConvertMapKey(const K &key) +{ + return key; +} + template int32_t GetCPPValue(napi_env env, napi_value jsValue, T &value) { @@ -179,6 +197,25 @@ int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::vector return napi_ok; } +template +napi_value JSUtils::Convert2JSValue(napi_env env, const std::map &value) +{ + napi_value jsValue; + napi_status status = napi_create_object(env, &jsValue); + if (status != napi_ok) { + return nullptr; + } + + for (const auto &[key, val] : value) { + const std::string &name = ConvertMapKey(key); + status = napi_set_named_property(env, jsValue, name.c_str(), Convert2JSValue(env, val)); + if (status != napi_ok) { + return nullptr; + } + } + return jsValue; +} + template int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::variant &value) { diff --git a/relational_store/frameworks/js/napi/common/include/js_uv_queue.h b/relational_store/frameworks/js/napi/common/include/js_uv_queue.h new file mode 100644 index 00000000..f9fb07c8 --- /dev/null +++ b/relational_store/frameworks/js/napi/common/include/js_uv_queue.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef DISTRIBUTEDDATAMGR_APPDATAMGR_UV_QUEUE_H +#define DISTRIBUTEDDATAMGR_APPDATAMGR_UV_QUEUE_H +#include +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "uv.h" + +namespace OHOS::AppDataMgrJsKit { +class UvQueue final { +public: + using ArgsGenerator = std::function; + using CallbackGetter = std::function; + struct UvCallback { + napi_ref callback_ = nullptr; + bool repeat_ = false; + CallbackGetter getter_; + UvCallback(napi_ref callback, bool repeat = false) : callback_(callback), repeat_(repeat) {} + UvCallback(CallbackGetter getter) : getter_(std::move(getter)) {} + bool IsNull() + { + return (callback_ == nullptr && getter_ == nullptr); + } + }; + + explicit UvQueue(napi_env env); + ~UvQueue(); + + napi_env GetEnv(); + void AsyncCall(UvCallback callback, ArgsGenerator genArgs = ArgsGenerator()); +private: + struct UvEntry { + napi_env env; + napi_ref callback; + bool repeat = false; + CallbackGetter getter; + ArgsGenerator args; + ~UvEntry() + { + if (callback != nullptr && !repeat) { + napi_delete_reference(env, callback); + } + } + }; + napi_env env_ = nullptr; + uv_loop_s* loop_ = nullptr; +}; +} // namespace OHOS::AppDataMgrJsKit +#endif // DISTRIBUTEDDATAMGR_APPDATAMGR_UV_QUEUE_H diff --git a/relational_store/frameworks/js/napi/common/src/js_uv_queue.cpp b/relational_store/frameworks/js/napi/common/src/js_uv_queue.cpp new file mode 100644 index 00000000..100f80e3 --- /dev/null +++ b/relational_store/frameworks/js/napi/common/src/js_uv_queue.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "js_uv_queue.h" +#include "logger.h" + +namespace OHOS::AppDataMgrJsKit { +using namespace OHOS::Rdb; +constexpr size_t ARGC_MAX = 6; +UvQueue::UvQueue(napi_env env) + : env_(env) +{ + if (env != nullptr) { + napi_get_uv_event_loop(env, &loop_); + } +} + +UvQueue::~UvQueue() +{ + LOG_DEBUG("no memory leak for queue-callback"); + env_ = nullptr; +} + +void UvQueue::AsyncCall(UvCallback callback, ArgsGenerator genArgs) +{ + if (loop_ == nullptr || callback.IsNull()) { + LOG_ERROR("loop_ or callback is nullptr"); + return; + } + + uv_work_t* work = new (std::nothrow) uv_work_t; + if (work == nullptr) { + LOG_ERROR("no memory for uv_work_t"); + return; + } + work->data = new (std::nothrow) + UvEntry{ env_, callback.callback_, callback.repeat_, std::move(callback.getter_), std::move(genArgs) }; + uv_queue_work( + loop_, work, [](uv_work_t* work) {}, + [](uv_work_t* work, int uvstatus) { + std::shared_ptr entry(static_cast(work->data), [work](UvEntry *data) { + delete data; + delete work; + }); + napi_handle_scope scope = nullptr; + napi_open_handle_scope(entry->env, &scope); + napi_value method = nullptr; + if (entry->callback != nullptr) { + napi_get_reference_value(entry->env, entry->callback, &method); + } else { + method = entry->getter(entry->env); + } + if (method == nullptr) { + LOG_ERROR("the callback is invalid, maybe is cleared!"); + if (scope != nullptr) { + napi_close_handle_scope(entry->env, scope); + } + return; + } + int argc = 0; + napi_value argv[ARGC_MAX] = { nullptr }; + if (entry->args) { + argc = ARGC_MAX; + entry->args(entry->env, argc, argv); + } + LOG_DEBUG("queue uv_after_work_cb"); + napi_value global = nullptr; + napi_get_global(entry->env, &global); + napi_value result; + napi_status status = napi_call_function(entry->env, global, method, argc, argv, &result); + if (status != napi_ok) { + LOG_ERROR("notify data change failed status:%{public}d.", status); + } + if (scope != nullptr) { + napi_close_handle_scope(entry->env, scope); + } + }); +} + +napi_env UvQueue::GetEnv() +{ + return env_; +} +} // namespace OHOS::AppDataMgrJsKit diff --git a/relational_store/frameworks/js/napi/dataability/BUILD.gn b/relational_store/frameworks/js/napi/dataability/BUILD.gn index 7678a062..7d79cc09 100644 --- a/relational_store/frameworks/js/napi/dataability/BUILD.gn +++ b/relational_store/frameworks/js/napi/dataability/BUILD.gn @@ -43,7 +43,7 @@ ohos_shared_library("dataability") { ] external_deps = [ - "hilog_native:libhilog", + "hilog:libhilog", "napi:ace_napi", ] diff --git a/relational_store/frameworks/js/napi/rdb/BUILD.gn b/relational_store/frameworks/js/napi/rdb/BUILD.gn index 78d97256..6a810946 100644 --- a/relational_store/frameworks/js/napi/rdb/BUILD.gn +++ b/relational_store/frameworks/js/napi/rdb/BUILD.gn @@ -87,8 +87,8 @@ ohos_shared_library("napi_rdb") { "ability_runtime:napi_base_context", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hilog_native:libhilog", - "hitrace_native:hitrace_meter", + "hilog:libhilog", + "hitrace:hitrace_meter", "napi:ace_napi", ] } @@ -149,8 +149,8 @@ ohos_shared_library("rdb") { "ability_runtime:abilitykit_native", "ability_runtime:napi_base_context", "c_utils:utils", - "hilog_native:libhilog", - "hitrace_native:hitrace_meter", + "hilog:libhilog", + "hitrace:hitrace_meter", "napi:ace_napi", ] } diff --git a/relational_store/frameworks/js/napi/rdb/include/napi_rdb_error.h b/relational_store/frameworks/js/napi/rdb/include/napi_rdb_error.h index 12a500ae..19578ca7 100644 --- a/relational_store/frameworks/js/napi/rdb/include/napi_rdb_error.h +++ b/relational_store/frameworks/js/napi/rdb/include/napi_rdb_error.h @@ -15,8 +15,6 @@ #ifndef RDB_JS_NAPI_ERROR_H #define RDB_JS_NAPI_ERROR_H -#include - #include "logger.h" namespace OHOS { diff --git a/relational_store/frameworks/js/napi/relationalstore/BUILD.gn b/relational_store/frameworks/js/napi/relationalstore/BUILD.gn index 29ba7dee..62be81b2 100644 --- a/relational_store/frameworks/js/napi/relationalstore/BUILD.gn +++ b/relational_store/frameworks/js/napi/relationalstore/BUILD.gn @@ -23,6 +23,7 @@ ohos_copy("relational_store_declaration") { sources = [ "../common/src/js_utils.cpp", + "../common/src/js_uv_queue.cpp", "src/entry_point.cpp", "src/napi_async_call.cpp", "src/napi_rdb_const_properties.cpp", @@ -62,8 +63,8 @@ if (is_ohos) { "ability_runtime:napi_base_context", "c_utils:utils", "common_event_service:cesfwk_innerkits", - "hilog_native:libhilog", - "hitrace_native:hitrace_meter", + "hilog:libhilog", + "hitrace:hitrace_meter", "napi:ace_napi", ] diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_async_call.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_async_call.h index 621d193e..f6c73cb3 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_async_call.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_async_call.h @@ -34,6 +34,7 @@ using ExecuteAction = std::function; class Context { public: void SetAction(napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output); + void SetAll(napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output); void SetError(std::shared_ptr error); virtual ~Context(); diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h index f0678c74..8777074e 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h @@ -16,6 +16,7 @@ #define RDB_JS_NAPI_ERROR_H #include +#include #include "logger.h" #include "rdb_errno.h" diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h index 97a3cbbf..5f25014d 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h @@ -27,7 +27,9 @@ namespace OHOS::AppDataMgrJsKit { namespace JSUtils { using Asset = OHOS::NativeRdb::AssetValue; using RowEntity = OHOS::NativeRdb::RowEntity; +using Date = OHOS::DistributedRdb::Date; using JSChangeInfo = OHOS::RelationalStoreJsKit::NapiRdbStoreObserver::JSChangeInfo; +using PRIKey = OHOS::DistributedRdb::RdbStoreObserver::PrimaryKey; template<> int32_t Convert2Value(napi_env env, napi_value input, Asset &output); @@ -50,6 +52,10 @@ template<> napi_value Convert2JSValue(napi_env env, const DistributedRdb::Details &details); template<> napi_value Convert2JSValue(napi_env env, const JSChangeInfo &value); +template<> +napi_value Convert2JSValue(napi_env env, const Date &date); +template<> +std::string ToString(const PRIKey &key); }; // namespace JSUtils } // namespace OHOS::AppDataMgrJsKit #endif // RDB_JSKIT_NAPI_RDB_JS_UTILS_H diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h index fcadeea4..7a02f052 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h @@ -19,6 +19,7 @@ #include #include +#include "js_uv_queue.h" #include "napi/native_api.h" #include "napi/native_common.h" #include "napi/native_node_api.h" @@ -70,6 +71,7 @@ private: static napi_value ObtainDistributedTableName(napi_env env, napi_callback_info info); static napi_value Sync(napi_env env, napi_callback_info info); static napi_value CloudSync(napi_env env, napi_callback_info info); + static napi_value GetModifyTime(napi_env env, napi_callback_info info); static napi_value OnEvent(napi_env env, napi_callback_info info); static napi_value OffEvent(napi_env env, napi_callback_info info); @@ -89,6 +91,7 @@ private: std::mutex mutex_; bool isSystemAppCalled_ = false; + std::shared_ptr queue_; std::list> observers_[DistributedRdb::SUBSCRIBE_MODE_MAX]; }; } // namespace RelationalStoreJsKit diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp index 513925a0..2ceff6f6 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp @@ -49,6 +49,25 @@ void Context::SetAction( napi_create_reference(env, self, 1, &self_); } +void Context::SetAll( + napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output) +{ + env_ = env; + size_t argc = MAX_INPUT_COUNT; + napi_value self = nullptr; + napi_value argv[MAX_INPUT_COUNT] = { nullptr }; + NAPI_CALL_RETURN_VOID(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + + // int -->input_(env, argc, argv, self) + input(env, argc, argv, self); + + // if input return is not ok, then napi_throw_error context error + RDB_NAPI_ASSERT_BASE(env, error == nullptr, error, NAPI_RETVAL_NOTHING); + output_ = std::move(output); + exec_ = std::move(exec); + napi_create_reference(env, self, 1, &self_); +} + void Context::SetError(std::shared_ptr err) { error = err; diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp index 91011b85..56e9cf5e 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp @@ -205,5 +205,34 @@ napi_value Convert2JSValue(napi_env env, const JSChangeInfo &value) ADD_JS_PROPERTY(env, object, value, deleted); return object; } + +template<> +napi_value Convert2JSValue(napi_env env, const Date &date) +{ + napi_value jsValue; + napi_status status = napi_create_date(env, date, &jsValue); + if (status != napi_ok) { + return nullptr; + } + return jsValue; +} + +template<> +std::string ToString(const PRIKey &key) +{ + auto strVal = std::get_if(&key); + if (strVal != nullptr) { + return *strVal; + } + auto intVal = std::get_if(&key); + if (intVal != nullptr) { + return std::to_string(*intVal); + } + auto dbVal = std::get_if(&key); + if (dbVal != nullptr) { + return std::to_string(static_cast(*dbVal)); + } + return {}; +} }; // namespace JSUtils } // namespace OHOS::AppDataMgrJsKit \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp index 29710b4c..b304a6b5 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp @@ -77,14 +77,17 @@ struct RdbStoreContext : public Context { std::string aliasName; std::string pathName; std::string srcName; + std::string columnName; int32_t enumArg; int32_t distributedType; int32_t syncMode; DistributedRdb::DistributedConfig distributedConfig; + napi_ref asyncHolder = nullptr; NativeRdb::ConflictResolution conflictResolution; DistributedRdb::SyncResult syncResult; - napi_value cloudSyncCallback = nullptr; std::shared_ptr rdbPredicates = nullptr; + std::vector keys; + std::map modifyTime; RdbStoreContext() : predicatesProxy(nullptr), int64Output(0), intOutput(0), enumArg(-1), @@ -158,6 +161,7 @@ void RdbStoreProxy::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("obtainDistributedTableName", ObtainDistributedTableName), DECLARE_NAPI_FUNCTION("sync", Sync), DECLARE_NAPI_FUNCTION("cloudSync", CloudSync), + DECLARE_NAPI_FUNCTION("getModifyTime", GetModifyTime), DECLARE_NAPI_FUNCTION("on", OnEvent), DECLARE_NAPI_FUNCTION("off", OffEvent), #endif @@ -217,6 +221,7 @@ napi_value RdbStoreProxy::NewInstance(napi_env env, std::shared_ptrqueue_ = std::make_shared(env); proxy->rdbStore_ = std::move(value); proxy->isSystemAppCalled_ = isSystemAppCalled; return instance; @@ -251,6 +256,20 @@ int ParseTableName(const napi_env &env, const napi_value &arg, std::shared_ptr context) +{ + context->columnName = JSUtils::Convert2String(env, arg); + CHECK_RETURN_SET(!context->columnName.empty(), std::make_shared("columnName", "not string")); + return OK; +} + +int ParsePrimaryKey(const napi_env &env, const napi_value &arg, std::shared_ptr context) +{ + JSUtils::Convert2Value(env, arg, context->keys); + CHECK_RETURN_SET(!context->keys.empty(), std::make_shared("PRIKey", "not number or string")); + return OK; +} + int ParseDevice(const napi_env &env, const napi_value &arg, std::shared_ptr context) { context->device = JSUtils::Convert2String(env, arg); @@ -323,7 +342,7 @@ int ParseCloudSyncCallback(const napi_env &env, const napi_value &arg, std::shar napi_valuetype valueType = napi_undefined; napi_typeof(env, arg, &valueType); CHECK_RETURN_SET(valueType == napi_function, std::make_shared("a callback type")); - context->cloudSyncCallback = arg; + napi_create_reference(env, arg, 1, &context->asyncHolder); LOG_DEBUG("ParseCloudSyncCallback end"); return OK; @@ -1156,7 +1175,7 @@ napi_value RdbStoreProxy::CloudSync(napi_env env, napi_callback_info info) LOG_DEBUG("RdbStoreProxy::CloudSync start"); auto context = std::make_shared(); auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { - CHECK_RETURN_SET_E(argc == 2 || argc == 3, std::make_shared("2 - 4")); + CHECK_RETURN_SET_E(argc > 1 && argc < 5, std::make_shared("2 - 4")); CHECK_RETURN(OK == ParserThis(env, self, context)); CHECK_RETURN(OK == ParseCloudSyncModeArg(env, argv[0], context)); uint32_t index = 1; @@ -1166,7 +1185,16 @@ napi_value RdbStoreProxy::CloudSync(napi_env env, napi_callback_info info) CHECK_RETURN(OK == ParseTablesName(env, argv[index], context)); index++; } - CHECK_RETURN(OK == ParseCloudSyncCallback(env, argv[index], context)); + CHECK_RETURN(OK == ParseCloudSyncCallback(env, argv[index++], context)); + CHECK_RETURN_SET_E(index == argc - 1 || index == argc, std::make_shared("2 - 4")); + if (index == argc - 1) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[index], &valueType); + if (valueType == napi_function) { + LOG_INFO("asyncCall set callback"); + NAPI_CALL_RETURN_VOID(env, napi_create_reference(env, argv[index], 1, &context->callback_)); + } + } }; auto exec = [context]() -> int { LOG_DEBUG("RdbStoreProxy::CloudSync Async"); @@ -1175,18 +1203,57 @@ napi_value RdbStoreProxy::CloudSync(napi_env env, napi_callback_info info) option.mode = static_cast(context->syncMode); option.isBlock = false; - return obj->rdbStore_->Sync(option, context->tablesNames, [context](const Details &details) { - auto callback = std::make_shared(context->env_, context->cloudSyncCallback); - callback->OnSyncCompelete(details); - }); + context->execCode_ = obj->rdbStore_->Sync(option, context->tablesNames, + [queue = obj->queue_, callback = context->asyncHolder](const Details &details) { + if (queue == nullptr || callback == nullptr) { + return; + } + bool repeat = !details.empty() && details.begin()->second.progress != DistributedRdb::SYNC_FINISH; + queue->AsyncCall({ callback, repeat }, [details](napi_env env, int &argc, napi_value *argv) -> void { + argc = 1; + argv[0] = details.empty() ? nullptr : JSUtils::Convert2JSValue(env, details.begin()->second); + }); + }); + return OK; }; auto output = [context](napi_env env, napi_value &result) { LOG_DEBUG("RdbStoreProxy::CloudSync output"); + if (context->execCode_ != E_OK && context->asyncHolder != nullptr) { + napi_delete_reference(env, context->asyncHolder); + } napi_status status = napi_get_undefined(env, &result); CHECK_RETURN_SET_E(status == napi_ok, std::make_shared(E_ERROR)); }; + context->SetAll(env, info, input, exec, output); + + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return AsyncCall::Call(env, context); +} + +napi_value RdbStoreProxy::GetModifyTime(napi_env env, napi_callback_info info) +{ + LOG_DEBUG("RdbStoreProxy::GetModifyTime start"); + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + CHECK_RETURN_SET_E(argc == 3, std::make_shared("3 - 4")); + CHECK_RETURN(OK == ParserThis(env, self, context)); + CHECK_RETURN(OK == ParseTableName(env, argv[0], context)); + CHECK_RETURN(OK == ParseColumnName(env, argv[1], context)); + CHECK_RETURN(OK == ParsePrimaryKey(env, argv[2], context)); + }; + auto exec = [context]() -> int { + LOG_DEBUG("RdbStoreProxy::GetModifyTime Async"); + auto *obj = reinterpret_cast(context->boundObj); + context->modifyTime = obj->rdbStore_->GetModifyTime(context->tableName, context->columnName, context->keys); + return context->modifyTime.empty() ? E_ERROR : E_OK; + }; + auto output = [context](napi_env env, napi_value &result) { + LOG_DEBUG("RdbStoreProxy::GetModifyTime output"); + result = JSUtils::Convert2JSValue(env, context->modifyTime); + CHECK_RETURN_SET_E(result != nullptr, std::make_shared(E_ERROR)); + }; context->SetAction(env, info, input, exec, output); CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp index 951de5c0..05ba2c8e 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp @@ -457,6 +457,10 @@ napi_value ResultSetProxy::GetAsset(napi_env env, napi_callback_info info) Asset result; int errCode = resultSetProxy->resultSet_->GetAsset(columnIndex, result); + if (errCode == E_NULL_OBJECT) { + LOG_DEBUG("getAsset col %{public}d is null ", columnIndex); + return JSUtils::Convert2JSValue(env, std::monostate()); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); @@ -471,6 +475,10 @@ napi_value ResultSetProxy::GetAssets(napi_env env, napi_callback_info info) Assets result; int errCode = resultSetProxy->resultSet_->GetAssets(columnIndex, result); + if (errCode == E_NULL_OBJECT) { + LOG_DEBUG("getAssets col %{public}d is null ", columnIndex); + return JSUtils::Convert2JSValue(env, std::monostate()); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); diff --git a/relational_store/frameworks/native/appdatafwk/src/general_endian.cpp b/relational_store/frameworks/native/appdatafwk/src/general_endian.cpp new file mode 100644 index 00000000..295c2c09 --- /dev/null +++ b/relational_store/frameworks/native/appdatafwk/src/general_endian.cpp @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "multi_platform_endian.h" +#include + +#if defined(WINDOWS_PLATFORM) +namespace OHOS { +uint16_t Endian::LeToH(uint16_t value) +{ + return le16toh(value); +} +uint16_t Endian::HToLe(uint16_t value) +{ + return htole16(value); +} + +uint32_t Endian::LeToH(uint32_t value) +{ + return le32toh(value); +} +uint32_t Endian::HToLe(uint32_t value) +{ + return htole32(value); +} +} +#endif diff --git a/relational_store/frameworks/native/cloud_data/include/icloud_service.h b/relational_store/frameworks/native/cloud_data/include/icloud_service.h index a21def4f..fe6c3e54 100644 --- a/relational_store/frameworks/native/cloud_data/include/icloud_service.h +++ b/relational_store/frameworks/native/cloud_data/include/icloud_service.h @@ -18,6 +18,7 @@ #include "cloud_service.h" #include "iremote_broker.h" +#include "distributeddata_relational_store_ipc_interface_code.h" namespace OHOS::CloudData { class ICloudService : public CloudService, public IRemoteBroker { @@ -27,8 +28,6 @@ public: class IKvStoreDataService : public IRemoteBroker { public: - enum { GET_FEATURE_INTERFACE = 0 }; - virtual sptr GetFeatureInterface(const std::string &name) = 0; DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.DistributedKv.IKvStoreDataService"); diff --git a/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp b/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp index 43bf0dd3..b138cbde 100644 --- a/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp +++ b/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp @@ -24,6 +24,7 @@ namespace OHOS::CloudData { using namespace OHOS::Rdb; +using namespace OHOS::DistributedRdb::RelationalStore; class DataMgrService : public IRemoteProxy { public: @@ -120,7 +121,8 @@ sptr DataMgrService::GetFeatureInterface(const std::string &name) MessageParcel reply; MessageOption mo{ MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(GET_FEATURE_INTERFACE, data, reply, mo); + int32_t error = Remote()->SendRequest( + static_cast(CloudKvStoreInterfaceCode::GET_FEATURE_INTERFACE), data, reply, mo); if (error != 0) { LOG_ERROR("SendRequest returned %{public}d", error); return nullptr; diff --git a/relational_store/frameworks/native/dataability/src/ishared_result_set_proxy.cpp b/relational_store/frameworks/native/dataability/src/ishared_result_set_proxy.cpp index 6ede53ae..aa11c7b2 100644 --- a/relational_store/frameworks/native/dataability/src/ishared_result_set_proxy.cpp +++ b/relational_store/frameworks/native/dataability/src/ishared_result_set_proxy.cpp @@ -23,6 +23,8 @@ namespace OHOS::NativeRdb { using namespace OHOS::Rdb; +using ResultSetCode = OHOS::DistributedRdb::RelationalStore::IResultSetInterfaceCode; + std::function( MessageParcel &parcel)> ISharedResultSet::consumerCreator_ = ISharedResultSetProxy::CreateProxy; BrokerDelegator ISharedResultSetProxy::delegator_; @@ -55,7 +57,8 @@ int ISharedResultSetProxy::GetAllColumnNames(std::vector &columnNam request.WriteInterfaceToken(GetDescriptor()); MessageParcel reply; MessageOption msgOption; - int errCode = Remote()->SendRequest(FUNC_GET_ALL_COLUMN_NAMES, request, reply, msgOption); + int errCode = Remote()->SendRequest( + static_cast(ResultSetCode::FUNC_GET_ALL_COLUMN_NAMES), request, reply, msgOption); if (errCode != 0) { LOG_ERROR("GetAllColumnNames IPC Error %{public}x", errCode); return -errCode; @@ -83,7 +86,8 @@ int ISharedResultSetProxy::GetRowCount(int &count) request.WriteInterfaceToken(GetDescriptor()); MessageParcel reply; MessageOption msgOption; - int errCode = Remote()->SendRequest(FUNC_GET_ROW_COUNT, request, reply, msgOption); + int errCode = Remote()->SendRequest( + static_cast(ResultSetCode::FUNC_GET_ROW_COUNT), request, reply, msgOption); if (errCode != 0) { LOG_ERROR("GetRowCount IPC Error %{public}x", errCode); return -errCode; @@ -108,7 +112,7 @@ bool ISharedResultSetProxy::OnGo(int oldRowIndex, int newRowIndex) request.WriteInt32(newRowIndex); MessageParcel reply; MessageOption msgOption; - int errCode = Remote()->SendRequest(FUNC_ON_GO, request, reply, msgOption); + int errCode = Remote()->SendRequest(static_cast(ResultSetCode::FUNC_ON_GO), request, reply, msgOption); if (errCode != 0) { LOG_ERROR("OnGo IPC Error %{public}x", errCode); return -errCode; @@ -124,7 +128,7 @@ int ISharedResultSetProxy::Close() request.WriteInterfaceToken(GetDescriptor()); MessageParcel reply; MessageOption msgOption; - int errCode = Remote()->SendRequest(FUNC_CLOSE, request, reply, msgOption); + int errCode = Remote()->SendRequest(static_cast(ResultSetCode::FUNC_CLOSE), request, reply, msgOption); if (errCode != 0) { LOG_ERROR("Close IPC Error %{public}x", errCode); return -errCode; diff --git a/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.cpp b/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.cpp index ac0e92dd..39e78db2 100644 --- a/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.cpp +++ b/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.cpp @@ -25,7 +25,7 @@ using namespace OHOS::Rdb; std::function(std::shared_ptr, MessageParcel &)> ISharedResultSet::providerCreator_ = ISharedResultSetStub::CreateStub; -constexpr ISharedResultSetStub::Handler ISharedResultSetStub::handlers[ISharedResultSet::FUNC_BUTT]; +constexpr ISharedResultSetStub::Handler ISharedResultSetStub::handlers[static_cast(ResultSetCode::FUNC_BUTT)]; sptr ISharedResultSetStub::CreateStub(std::shared_ptr result, OHOS::MessageParcel &parcel) @@ -71,7 +71,7 @@ int ISharedResultSetStub::OnRemoteRequest(uint32_t code, OHOS::MessageParcel &da return INVALID_FD; } - if (code >= FUNC_BUTT) { + if (code >= static_cast(ResultSetCode::FUNC_BUTT)) { LOG_ERROR("OnRemoteRequest method code(%{public}d) out of range", code); return IPCObjectStub::OnRemoteRequest(code, data, reply, option); } diff --git a/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.h b/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.h index 2f0dda82..a7be30c7 100644 --- a/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.h +++ b/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.h @@ -21,6 +21,8 @@ #include "ishared_result_set.h" #include "iremote_stub.h" namespace OHOS::NativeRdb { +using ResultSetCode = OHOS::DistributedRdb::RelationalStore::IResultSetInterfaceCode; + class ISharedResultSetStub : public IRemoteStub { public: explicit ISharedResultSetStub(std::shared_ptr resultSet); @@ -55,7 +57,7 @@ private: SafeBlockQueue> runnables_; bool isRunning_ = true; std::thread thread_; - static constexpr Handler handlers[FUNC_BUTT] { + static constexpr Handler handlers[static_cast(ResultSetCode::FUNC_BUTT)] { &ISharedResultSetStub::HandleGetRowCountRequest, &ISharedResultSetStub::HandleGetAllColumnNamesRequest, &ISharedResultSetStub::HandleOnGoRequest, diff --git a/relational_store/frameworks/native/rdb/include/irdb_service.h b/relational_store/frameworks/native/rdb/include/irdb_service.h index 4ab69877..35b30c87 100644 --- a/relational_store/frameworks/native/rdb/include/irdb_service.h +++ b/relational_store/frameworks/native/rdb/include/irdb_service.h @@ -20,6 +20,8 @@ #include "iremote_broker.h" #include "rdb_service.h" +#include "distributeddata_relational_store_ipc_interface_code.h" + namespace OHOS::DistributedRdb { class IRdbService : public RdbService, public IRemoteBroker { public: @@ -28,11 +30,6 @@ public: class IKvStoreDataService : public IRemoteBroker { public: - enum { - GET_FEATURE_INTERFACE = 0, - REGISTER_DEATH_OBSERVER, - }; - DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.DistributedKv.IKvStoreDataService"); virtual sptr GetFeatureInterface(const std::string &name) = 0; virtual int32_t RegisterDeathObserver(const std::string &bundleName, sptr observer) = 0; diff --git a/relational_store/frameworks/native/rdb/include/rdb_notifier_stub.h b/relational_store/frameworks/native/rdb/include/rdb_notifier_stub.h index f9e35df6..35663b0b 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_notifier_stub.h +++ b/relational_store/frameworks/native/rdb/include/rdb_notifier_stub.h @@ -19,6 +19,8 @@ #include #include namespace OHOS::DistributedRdb { +using NotifierIFCode = RelationalStore::IRdbNotifierInterfaceCode; + class RdbNotifierStubBroker : public IRdbNotifier, public IRemoteBroker { public: DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.DistributedRdb.IRdbNotifier"); @@ -42,9 +44,9 @@ private: bool CheckInterfaceToken(MessageParcel& data); using RequestHandle = int32_t (RdbNotifierStub::*)(MessageParcel&, MessageParcel&); - static constexpr RequestHandle HANDLES[RDB_NOTIFIER_CMD_MAX] = { - [RDB_NOTIFIER_CMD_SYNC_COMPLETE] = &RdbNotifierStub::OnCompleteInner, - [RDB_NOTIFIER_CMD_DATA_CHANGE] = &RdbNotifierStub::OnChangeInner, + static constexpr RequestHandle HANDLES[static_cast(NotifierIFCode::RDB_NOTIFIER_CMD_MAX)] = { + [static_cast(NotifierIFCode::RDB_NOTIFIER_CMD_SYNC_COMPLETE)] = &RdbNotifierStub::OnCompleteInner, + [static_cast(NotifierIFCode::RDB_NOTIFIER_CMD_DATA_CHANGE)] = &RdbNotifierStub::OnChangeInner, }; SyncCompleteHandler completeNotifier_; diff --git a/relational_store/frameworks/native/rdb/include/rdb_store_impl.h b/relational_store/frameworks/native/rdb/include/rdb_store_impl.h index 73929f4e..9513c388 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_store_impl.h +++ b/relational_store/frameworks/native/rdb/include/rdb_store_impl.h @@ -91,6 +91,7 @@ public: std::string GetFileType(); std::shared_ptr QueryByStep(const std::string &sql, const std::vector &selectionArgs) override; + std::shared_ptr QueryByStep(const std::string &sql, std::vector &&args) override; std::shared_ptr QueryByStep( const AbsRdbPredicates &predicates, const std::vector columns) override; std::shared_ptr Query( @@ -118,6 +119,9 @@ public: // user must use UDID bool DropDeviceData(const std::vector& devices, const DropOption& option) override; + std::map GetModifyTime( + const std::string &table, const std::string &columnName, std::vector &keys) override; + private: int InnerOpen(); int InnerInsert(int64_t &outRowId, const std::string &table, ValuesBucket values, @@ -134,6 +138,9 @@ private: void DoCloudSync(const std::string &table); int InnerBackup(const std::string databasePath, const std::vector destEncryptKey = std::vector()); + std::map GetModifyTimeByRowId( + const std::string &logTable, std::vector &keys); + std::string GetSqlArgs(size_t size); const RdbStoreConfig rdbStoreConfig; SqliteConnectionPool *connectionPool; diff --git a/relational_store/frameworks/native/rdb/include/sqlite_connection.h b/relational_store/frameworks/native/rdb/include/sqlite_connection.h index ec242bf2..945f5ee1 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_connection.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_connection.h @@ -47,6 +47,8 @@ public: const std::vector &bindArgs = std::vector()); std::shared_ptr BeginStepQuery(int &errCode, const std::string &sql, const std::vector &selectionArgs) const; + std::shared_ptr BeginStepQuery(int &errCode, const std::string &sql, + const std::vector &args) const; int DesFinalize(); int EndStepQuery(); void SetInTransaction(bool transaction); diff --git a/relational_store/frameworks/native/rdb/include/step_result_set.h b/relational_store/frameworks/native/rdb/include/step_result_set.h index 11937128..c7c4c207 100644 --- a/relational_store/frameworks/native/rdb/include/step_result_set.h +++ b/relational_store/frameworks/native/rdb/include/step_result_set.h @@ -31,6 +31,8 @@ class StepResultSet : public AbsResultSet { public: StepResultSet(std::shared_ptr rdb, SqliteConnectionPool *connectionPool, const std::string &sql, const std::vector &selectionArgs); + StepResultSet(std::shared_ptr rdb, SqliteConnectionPool *pool, const std::string &sql, + std::vector &&args); ~StepResultSet() override; int GetAllColumnNames(std::vector &columnNames) override; @@ -66,6 +68,7 @@ private: SqliteConnectionPool *connectionPool_; std::string sql; std::vector selectionArgs; + std::vector args_; // Whether reach the end of this result set or not bool isAfterLast; // The value indicates the row count of the result set diff --git a/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h b/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h index 6da70afb..1d41bac9 100644 --- a/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h +++ b/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h @@ -83,6 +83,7 @@ public: std::string GetFileType(); std::shared_ptr QueryByStep(const std::string &sql, const std::vector &selectionArgs) override; + std::shared_ptr QueryByStep(const std::string &sql, std::vector &&args) override; std::shared_ptr Query( const AbsRdbPredicates &predicates, const std::vector columns) override; int Count(int64_t &outValue, const AbsRdbPredicates &predicates) override; diff --git a/relational_store/frameworks/native/rdb/mock/include/sqlite_connection.h b/relational_store/frameworks/native/rdb/mock/include/sqlite_connection.h index 284464f7..9f2f368b 100644 --- a/relational_store/frameworks/native/rdb/mock/include/sqlite_connection.h +++ b/relational_store/frameworks/native/rdb/mock/include/sqlite_connection.h @@ -45,6 +45,8 @@ public: const std::vector &bindArgs = std::vector()); std::shared_ptr BeginStepQuery(int &errCode, const std::string &sql, const std::vector &selectionArgs) const; + std::shared_ptr BeginStepQuery(int &errCode, const std::string &sql, + const std::vector &args) const; int DesFinalize(); int EndStepQuery(); void SetInTransaction(bool transaction); @@ -73,7 +75,8 @@ private: int SetBusyTimeout(int timeout); int RegDefaultFunctions(sqlite3 *dbHandle); static void MergeAssets(sqlite3_context *ctx, int argc, sqlite3_value **argv); - static void CompAssets(std::map &oldAssets, std::map &newAssets); + static void CompAssets(std::map &oldAssets, std::map &newAssets); static void MergeAsset(ValueObject::Asset &oldAsset, ValueObject::Asset &newAsset); int SetCustomFunctions(const RdbStoreConfig &config); int SetCustomScalarFunction(const std::string &functionName, int argc, ScalarFunction *function); diff --git a/relational_store/frameworks/native/rdb/mock/include/step_result_set.h b/relational_store/frameworks/native/rdb/mock/include/step_result_set.h index 11937128..c7c4c207 100644 --- a/relational_store/frameworks/native/rdb/mock/include/step_result_set.h +++ b/relational_store/frameworks/native/rdb/mock/include/step_result_set.h @@ -31,6 +31,8 @@ class StepResultSet : public AbsResultSet { public: StepResultSet(std::shared_ptr rdb, SqliteConnectionPool *connectionPool, const std::string &sql, const std::vector &selectionArgs); + StepResultSet(std::shared_ptr rdb, SqliteConnectionPool *pool, const std::string &sql, + std::vector &&args); ~StepResultSet() override; int GetAllColumnNames(std::vector &columnNames) override; @@ -66,6 +68,7 @@ private: SqliteConnectionPool *connectionPool_; std::string sql; std::vector selectionArgs; + std::vector args_; // Whether reach the end of this result set or not bool isAfterLast; // The value indicates the row count of the result set diff --git a/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp b/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp index 88568f61..3f96739f 100644 --- a/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp +++ b/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp @@ -173,22 +173,22 @@ int AbsSharedResultSet::GetBlob(int columnIndex, std::vector &value) } return E_OK; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_INTEGER) { - LOG_ERROR("AbsSharedResultSet::GetDouble AppDataFwk::SharedBlock::CELL_UNIT_TYPE_INTEGER!"); + LOG_ERROR("AbsSharedResultSet::GetBlob AppDataFwk::SharedBlock::CELL_UNIT_TYPE_INTEGER!"); return E_OK; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_NULL) { - LOG_ERROR("AbsSharedResultSet::GetDouble AppDataFwk::SharedBlock::CELL_UNIT_TYPE_NULL!"); + LOG_ERROR("AbsSharedResultSet::GetBlob AppDataFwk::SharedBlock::CELL_UNIT_TYPE_NULL!"); return E_OK; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_FLOAT) { - LOG_ERROR("AbsSharedResultSet::GetDouble AppDataFwk::SharedBlock::CELL_UNIT_TYPE_FLOAT!"); + LOG_ERROR("AbsSharedResultSet::GetBlob AppDataFwk::SharedBlock::CELL_UNIT_TYPE_FLOAT!"); return E_OK; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET) { - LOG_ERROR("AbsSharedResultSet::GetDouble AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET!"); - return E_OK; + LOG_ERROR("AbsSharedResultSet::GetBlob AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET!"); + return E_INVALID_OBJECT_TYPE; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS) { - LOG_ERROR("AbsSharedResultSet::GetDouble AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS!"); - return E_OK; + LOG_ERROR("AbsSharedResultSet::GetBlob AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS!"); + return E_INVALID_OBJECT_TYPE; } else { - LOG_ERROR("AbsSharedResultSet::GetDouble AppDataFwk::SharedBlock::nothing !"); + LOG_ERROR("AbsSharedResultSet::GetBlob AppDataFwk::SharedBlock::nothing !"); return E_INVALID_OBJECT_TYPE; } } @@ -230,9 +230,11 @@ int AbsSharedResultSet::GetString(int columnIndex, std::string &value) } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_BLOB) { return E_OK; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET) { - return E_OK; + LOG_ERROR("AbsSharedResultSet::GetString AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET !"); + return E_INVALID_OBJECT_TYPE; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS) { - return E_OK; + LOG_ERROR("AbsSharedResultSet::GetString AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS !"); + return E_INVALID_OBJECT_TYPE; } else { LOG_ERROR("AbsSharedResultSet::GetString is failed!"); return E_ERROR; @@ -288,11 +290,11 @@ int AbsSharedResultSet::GetLong(int columnIndex, int64_t &value) value = 0L; return E_OK; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET) { - value = 0L; - return E_OK; + LOG_ERROR("AbsSharedResultSet::GetLong AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET !"); + return E_INVALID_OBJECT_TYPE; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS) { - value = 0L; - return E_OK; + LOG_ERROR("AbsSharedResultSet::GetLong AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS !"); + return E_INVALID_OBJECT_TYPE; } else { LOG_ERROR("AbsSharedResultSet::GetLong Nothing !"); return E_INVALID_OBJECT_TYPE; @@ -333,12 +335,10 @@ int AbsSharedResultSet::GetDouble(int columnIndex, double &value) return E_OK; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET) { LOG_ERROR("AbsSharedResultSet::GetDouble AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET!"); - value = 0.0; - return E_OK; + return E_INVALID_OBJECT_TYPE; } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS) { LOG_ERROR("AbsSharedResultSet::GetDouble AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS!"); - value = 0.0; - return E_OK; + return E_INVALID_OBJECT_TYPE; } else { LOG_ERROR("AbsSharedResultSet::GetDouble AppDataFwk::SharedBlock::nothing !"); value = 0.0; @@ -360,8 +360,14 @@ int AbsSharedResultSet::GetAsset(int32_t col, ValueObject::Asset &value) return E_ERROR; } + if (cellUnit->type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_NULL) { + LOG_ERROR("GetAsset the type of cell is null !"); + return E_NULL_OBJECT; + } + if (cellUnit->type != AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET) { - LOG_ERROR("GetAsset AppDataFwk::SharedBlock::nothing !"); + LOG_ERROR("GetAssets the type of cell is not assets, type is %{public}d, col is %{public}d!", cellUnit->type, + col); return E_INVALID_OBJECT_TYPE; } @@ -387,8 +393,14 @@ int AbsSharedResultSet::GetAssets(int32_t col, ValueObject::Assets &value) return E_ERROR; } + if (cellUnit->type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_NULL) { + LOG_ERROR("GetAssets the type of cell is null !"); + return E_NULL_OBJECT; + } + if (cellUnit->type != AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS) { - LOG_ERROR("GetAssets AppDataFwk::SharedBlock::nothing !"); + LOG_ERROR("GetAssets the type of cell is not assets, type is %{public}d, col is %{public}d!", cellUnit->type, + col); return E_INVALID_OBJECT_TYPE; } diff --git a/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp b/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp index 752fc71d..563b2185 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp @@ -30,6 +30,7 @@ namespace OHOS::DistributedRdb { using namespace OHOS::Rdb; using RdbServiceProxy = DistributedRdb::RdbServiceProxy; using namespace OHOS::NativeRdb; +using namespace OHOS::DistributedRdb::RelationalStore; class DeathStub : public IRemoteBroker { public: @@ -188,7 +189,8 @@ sptr RdbStoreDataServiceProxy::GetFeatureInterface(const std::str MessageParcel reply; MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(GET_FEATURE_INTERFACE, data, reply, mo); + int32_t error = Remote()->SendRequest( + static_cast(KvStoreInterfaceCode::GET_FEATURE_INTERFACE), data, reply, mo); if (error != 0) { LOG_ERROR("SendRequest returned %{public}d", error); return nullptr; @@ -217,7 +219,8 @@ int32_t RdbStoreDataServiceProxy::RegisterDeathObserver(const std::string &bundl MessageParcel reply; MessageOption mo { MessageOption::TF_SYNC }; - int32_t error = Remote()->SendRequest(REGISTER_DEATH_OBSERVER, data, reply, mo); + int32_t error = Remote()->SendRequest( + static_cast(KvStoreInterfaceCode::REGISTER_DEATH_OBSERVER), data, reply, mo); if (error != 0) { LOG_ERROR("SendRequest returned %{public}d", error); return E_ERROR; diff --git a/relational_store/frameworks/native/rdb/src/rdb_notifier_stub.cpp b/relational_store/frameworks/native/rdb/src/rdb_notifier_stub.cpp index e5b79ed8..c559c541 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_notifier_stub.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_notifier_stub.cpp @@ -53,7 +53,7 @@ int RdbNotifierStub::OnRemoteRequest(uint32_t code, MessageParcel &data, Message return RDB_ERROR; } - if (code >= 0 && code < RDB_NOTIFIER_CMD_MAX) { + if (code >= 0 && code < static_cast(NotifierIFCode::RDB_NOTIFIER_CMD_MAX)) { return (this->*HANDLES[code])(data, reply); } diff --git a/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp b/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp index a89ae9aa..6856f87d 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp @@ -22,6 +22,7 @@ namespace OHOS::DistributedRdb { using namespace OHOS::Rdb; using SqliteUtils = OHOS::NativeRdb::SqliteUtils; +using RdbServiceCode = OHOS::DistributedRdb::RelationalStore::RdbServiceInterfaceCode; #define IPC_SEND(code, reply, ...) \ ({ \ @@ -83,7 +84,7 @@ void RdbServiceProxy::OnDataChange(const Origin &origin, const PrimaryFields &pr std::string RdbServiceProxy::ObtainDistributedTableName(const std::string &device, const std::string &table) { MessageParcel reply; - int32_t status = IPC_SEND(RDB_SERVICE_CMD_OBTAIN_TABLE, reply, device, table); + int32_t status = IPC_SEND(static_cast(RdbServiceCode::RDB_SERVICE_CMD_OBTAIN_TABLE), reply, device, table); if (status != RDB_OK) { LOG_ERROR("status:%{public}d, device:%{public}.6s, table:%{public}s", status, SqliteUtils::Anonymous(device).c_str(), SqliteUtils::Anonymous(table).c_str()); @@ -118,7 +119,8 @@ int32_t RdbServiceProxy::InitNotifier(const RdbSyncerParam ¶m) int32_t RdbServiceProxy::InitNotifier(const RdbSyncerParam ¶m, sptr notifier) { MessageParcel reply; - int32_t status = IPC_SEND(RDB_SERVICE_CMD_INIT_NOTIFIER, reply, param, notifier); + int32_t status = IPC_SEND( + static_cast(RdbServiceCode::RDB_SERVICE_CMD_INIT_NOTIFIER), reply, param, notifier); if (status != RDB_OK) { LOG_ERROR("status:%{public}d, bundleName:%{public}s", status, param.bundleName_.c_str()); } @@ -140,7 +142,7 @@ std::pair RdbServiceProxy::DoSync(const RdbSyncerParam& param, std::pair result{RDB_ERROR, {}}; MessageParcel reply; auto &[status, details] = result; - status = IPC_SEND(RDB_SERVICE_CMD_SYNC, reply, param, option, predicates); + status = IPC_SEND(static_cast(RdbServiceCode::RDB_SERVICE_CMD_SYNC), reply, param, option, predicates); if (status != RDB_OK) { LOG_ERROR("status:%{public}d, bundleName:%{public}s, storeName:%{public}s", status, param.bundleName_.c_str(), SqliteUtils::Anonymous(param.storeName_).c_str()); @@ -174,7 +176,8 @@ int32_t RdbServiceProxy::DoSync(const RdbSyncerParam ¶m, const Option &optio int32_t RdbServiceProxy::DoAsync(const RdbSyncerParam ¶m, const Option &option, const PredicatesMemo &predicates) { MessageParcel reply; - int32_t status = IPC_SEND(RDB_SERVICE_CMD_ASYNC, reply, param, option, predicates); + int32_t status = IPC_SEND( + static_cast(RdbServiceCode::RDB_SERVICE_CMD_ASYNC), reply, param, option, predicates); if (status != RDB_OK) { LOG_ERROR("status:%{public}d, bundleName:%{public}s, storeName:%{public}s, seqNum:%{public}u", status, param.bundleName_.c_str(), SqliteUtils::Anonymous(param.storeName_).c_str(), option.seqNum); @@ -208,7 +211,8 @@ int32_t RdbServiceProxy::SetDistributedTables(const RdbSyncerParam& param, const int32_t type) { MessageParcel reply; - int32_t status = IPC_SEND(RDB_SERVICE_CMD_SET_DIST_TABLE, reply, param, tables, type); + int32_t status = IPC_SEND( + static_cast(RdbServiceCode::RDB_SERVICE_CMD_SET_DIST_TABLE), reply, param, tables, type); if (status != RDB_OK) { LOG_ERROR("status:%{public}d, bundleName:%{public}s, storeName:%{public}s, type:%{public}d", status, param.bundleName_.c_str(), SqliteUtils::Anonymous(param.storeName_).c_str(), type); @@ -264,7 +268,8 @@ int32_t RdbServiceProxy::Subscribe(const RdbSyncerParam ¶m, const SubscribeO int32_t RdbServiceProxy::DoSubscribe(const RdbSyncerParam ¶m, const SubscribeOption &option) { MessageParcel reply; - int32_t status = IPC_SEND(RDB_SERVICE_CMD_SUBSCRIBE, reply, param, option); + int32_t status = IPC_SEND( + static_cast(RdbServiceCode::RDB_SERVICE_CMD_SUBSCRIBE), reply, param, option); if (status != RDB_OK) { LOG_ERROR("status:%{public}d, bundleName:%{public}s, storeName:%{public}s", status, param.bundleName_.c_str(), SqliteUtils::Anonymous(param.storeName_).c_str()); @@ -290,7 +295,7 @@ int32_t RdbServiceProxy::UnSubscribe(const RdbSyncerParam ¶m, const Subscrib int32_t RdbServiceProxy::DoUnSubscribe(const RdbSyncerParam ¶m) { MessageParcel reply; - int32_t status = IPC_SEND(RDB_SERVICE_CMD_UNSUBSCRIBE, reply, param); + int32_t status = IPC_SEND(static_cast(RdbServiceCode::RDB_SERVICE_CMD_UNSUBSCRIBE), reply, param); if (status != RDB_OK) { LOG_ERROR("status:%{public}d, bundleName:%{public}s, storeName:%{public}s", status, param.bundleName_.c_str(), SqliteUtils::Anonymous(param.storeName_).c_str()); @@ -302,7 +307,8 @@ int32_t RdbServiceProxy::RemoteQuery(const RdbSyncerParam& param, const std::str const std::vector& selectionArgs, sptr& resultSet) { MessageParcel reply; - int32_t status = IPC_SEND(RDB_SERVICE_CMD_REMOTE_QUERY, reply, param, device, sql, selectionArgs); + int32_t status = IPC_SEND( + static_cast(RdbServiceCode::RDB_SERVICE_CMD_REMOTE_QUERY), reply, param, device, sql, selectionArgs); if (status != RDB_OK) { LOG_ERROR("status:%{public}d, bundleName:%{public}s, storeName:%{public}s, device:%{public}.6s", status, param.bundleName_.c_str(), SqliteUtils::Anonymous(param.storeName_).c_str(), device.c_str()); @@ -338,7 +344,7 @@ void RdbServiceProxy::ImportObservers(ObserverMap &observers) int32_t RdbServiceProxy::GetSchema(const RdbSyncerParam ¶m) { MessageParcel reply; - int32_t status = IPC_SEND(RDB_SERVICE_CMD_GET_SCHEMA, reply, param); + int32_t status = IPC_SEND(static_cast(RdbServiceCode::RDB_SERVICE_CMD_GET_SCHEMA), reply, param); if (status != RDB_OK) { LOG_ERROR("status:%{public}d, bundleName:%{public}s, storeName:%{public}s", status, param.bundleName_.c_str(), SqliteUtils::Anonymous(param.storeName_).c_str()); diff --git a/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp b/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp index b24e2769..bf73df71 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp @@ -21,6 +21,7 @@ #include "logger.h" #include "rdb_errno.h" +#include "rdb_store.h" #include "rdb_trace.h" #include "rdb_sql_utils.h" #include "sqlite_global_config.h" @@ -36,6 +37,7 @@ #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) #include "iresult_set.h" +#include "raw_data_parser.h" #include "rdb_device_manager_adapter.h" #include "rdb_manager_impl.h" #include "relational_store_manager.h" @@ -107,6 +109,102 @@ void RdbStoreImpl::GetSchema(const RdbStoreConfig &config) }); } } + +std::map RdbStoreImpl::GetModifyTime( + const std::string &table, const std::string &columnName, std::vector &keys) +{ + if (table.empty() || columnName.empty() || keys.empty()) { + LOG_ERROR("invalid para."); + return {}; + } + + auto logTable = DistributedDB::RelationalStoreManager::GetDistributedLogTableName(table); + if (columnName == "rowid") { + return GetModifyTimeByRowId(logTable, keys); + } + std::vector hashKeys; + hashKeys.reserve(keys.size()); + std::map, PRIKey> keyMap; + std::map tmp; + for (const auto &key : keys) { + DistributedDB::Type value; + RawDataParser::Convert(key, value); + tmp[columnName] = value; + auto hashKey = DistributedDB::RelationalStoreManager::CalcPrimaryKeyHash(tmp); + if (hashKey.empty()) { + LOG_DEBUG("hash key fail"); + continue; + } + hashKeys.emplace_back(ValueObject(hashKey)); + keyMap[hashKey] = key; + } + + std::string sql; + sql.append("select hash_key, timestamp/10000 from "); + sql.append(logTable); + sql.append(" where hash_key in ("); + sql.append(GetSqlArgs(hashKeys.size())); + sql.append(")"); + auto resultSet = QueryByStep(sql, std::move(hashKeys)); + int count = 0; + if (resultSet == nullptr || resultSet->GetRowCount(count) != E_OK || count <= 0) { + LOG_ERROR("get resultSet err."); + return {}; + } + std::map result; + for (int i = 0; i < count; i++) { + resultSet->GoToRow(i); + std::vector hashKey; + int64_t timeStamp; + resultSet->GetBlob(0, hashKey); + resultSet->GetLong(1, timeStamp); + result[keyMap[hashKey]] = Date(timeStamp); + } + return result; +} + +std::map RdbStoreImpl::GetModifyTimeByRowId( + const std::string &logTable, std::vector &keys) +{ + std::string sql; + sql.append("select data_key, timestamp/10000 from "); + sql.append(logTable); + sql.append(" where data_key in ("); + sql.append(GetSqlArgs(keys.size())); + sql.append(")"); + std::vector args; + args.reserve(keys.size()); + for (auto &key : keys) { + ValueObject::Type value; + RawDataParser::Convert(key, value); + args.emplace_back(ValueObject(value)); + } + auto resultSet = QueryByStep(sql, std::move(args)); + int count = 0; + if (resultSet == nullptr || resultSet->GetRowCount(count) != E_OK || count <= 0) { + LOG_ERROR("get resultSet err."); + return {}; + } + std::map result; + for (int i = 0; i < count; i++) { + resultSet->GoToRow(i); + int rowId; + int64_t timeStamp; + resultSet->GetInt(0, rowId); + resultSet->GetLong(1, timeStamp); + result[rowId] = Date(timeStamp); + } + return result; +} + +std::string RdbStoreImpl::GetSqlArgs(size_t size) +{ + std::string args((size << 1) - 1, '?'); + for (size_t i = 1; i < size; ++i) { + args[(i << 1) - 1] = ','; + } + return args; +} #endif RdbStoreImpl::RdbStoreImpl(const RdbStoreConfig &config, int &errCode) @@ -268,7 +366,8 @@ int RdbStoreImpl::InnerInsert(int64_t &outRowId, const std::string &table, for (auto &[key, val] : values.values_) { sql << split; sql << key; // columnName - if (val.GetType() == ValueObject::TYPE_ASSETS && conflictResolution == ConflictResolution::ON_CONFLICT_REPLACE) { + if (val.GetType() == ValueObject::TYPE_ASSETS && + conflictResolution == ConflictResolution::ON_CONFLICT_REPLACE) { return E_INVALID_ARGS; } if (val.GetType() == ValueObject::TYPE_ASSET || val.GetType() == ValueObject::TYPE_ASSETS) { @@ -608,6 +707,7 @@ int RdbStoreImpl::GetDataBasePath(const std::string &databasePath, std::string & if (ISFILE(databasePath)) { backupFilePath = ExtractFilePath(path) + databasePath; } else { + // 2 represents two characters starting from the len - 2 position if (!PathToRealPath(ExtractFilePath(databasePath), backupFilePath) || databasePath.back() == '/' || databasePath.substr(databasePath.length() - 2, 2) == "\\") { LOG_ERROR("Invalid databasePath."); @@ -1184,6 +1284,11 @@ std::shared_ptr RdbStoreImpl::QueryByStep(const std::string &sql, return std::make_shared(shared_from_this(), connectionPool, sql, selectionArgs); } +std::shared_ptr RdbStoreImpl::QueryByStep(const std::string &sql, std::vector &&args) +{ + return std::make_shared(shared_from_this(), connectionPool, sql, std::move(args)); +} + #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) int RdbStoreImpl::SetDistributedTables(const std::vector &tables, int32_t type, const DistributedRdb::DistributedConfig &distributedConfig) diff --git a/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp b/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp index ec8ca655..88ebca6a 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp @@ -159,12 +159,11 @@ bool Unmarshalling(PrimaryKeys &output, MessageParcel &data) template<> bool Marshalling(const Origin &input, MessageParcel &data) { - return Marshal(data, input.origin, input.id, input.store); + return Marshal(data, input.origin, input.dataType, input.id, input.store); } - template<> bool Unmarshalling(Origin &output, MessageParcel &data) { - return Unmarshal(data, output.origin, output.id, output.store); + return Unmarshal(data, output.origin, output.dataType, output.id, output.store); } } diff --git a/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp b/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp index fbdec807..6f948b7b 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp @@ -374,6 +374,7 @@ int SqliteConnection::RegDefaultFunctions(sqlite3 *dbHandle) if (dbHandle == nullptr) { return SQLITE_OK; } + // The number of parameters is 2 return sqlite3_create_function_v2(dbHandle, "merge_assets", 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr, &MergeAssets, nullptr, nullptr, nullptr); } @@ -706,6 +707,20 @@ std::shared_ptr SqliteConnection::BeginStepQuery( return stepStatement; } +std::shared_ptr SqliteConnection::BeginStepQuery(int &errCode, const std::string &sql, + const std::vector &args) const +{ + errCode = stepStatement->Prepare(dbHandle, sql); + if (errCode != E_OK) { + return nullptr; + } + errCode = stepStatement->BindArguments(args); + if (errCode != E_OK) { + return nullptr; + } + return stepStatement; +} + int SqliteConnection::DesFinalize() { int errCode = 0; @@ -895,6 +910,7 @@ int SqliteConnection::LimitWalSize() void SqliteConnection::MergeAssets(sqlite3_context *ctx, int argc, sqlite3_value **argv) { LOG_DEBUG("merge assets begin"); + // 2 is the number of parameters if (ctx == nullptr || argc != 2 || argv == nullptr) { LOG_ERROR("Parameter does not meet restrictions."); return; @@ -919,12 +935,13 @@ void SqliteConnection::MergeAssets(sqlite3_context *ctx, int argc, sqlite3_value sqlite3_result_blob(ctx, blob.data(), blob.size(), SQLITE_TRANSIENT); } -void SqliteConnection::CompAssets(std::map &assets, std::map &newAssets) +void SqliteConnection::CompAssets(std::map &assets, std::map &newAssets) { using Status = ValueObject::Asset::Status; auto oldIt = assets.begin(); auto newIt = newAssets.begin(); - for (; oldIt != assets.end() && newIt != newAssets.end(); ) { + for (; oldIt != assets.end() && newIt != newAssets.end();) { if (oldIt->first == newIt->first) { if (newIt->second.status == Status::STATUS_DELETE) { oldIt->second.status = Status::STATUS_DELETE; @@ -969,7 +986,8 @@ void SqliteConnection::MergeAsset(ValueObject::Asset &oldAsset, ValueObject::Ass oldAsset.path = newAsset.path; oldAsset.status = Status ::STATUS_UPDATE; } - default:; + default: + return; } } } // namespace NativeRdb diff --git a/relational_store/frameworks/native/rdb/src/step_result_set.cpp b/relational_store/frameworks/native/rdb/src/step_result_set.cpp index bea159a0..97cfff20 100644 --- a/relational_store/frameworks/native/rdb/src/step_result_set.cpp +++ b/relational_store/frameworks/native/rdb/src/step_result_set.cpp @@ -31,7 +31,17 @@ using namespace OHOS::Rdb; StepResultSet::StepResultSet(std::shared_ptr rdb, SqliteConnectionPool *connectionPool, const std::string &sql, const std::vector &selectionArgs) - : rdb(rdb), connectionPool_(connectionPool), sql(sql), selectionArgs(selectionArgs), isAfterLast(false), + : rdb(rdb), connectionPool_(connectionPool), sql(sql), isAfterLast(false), + rowCount(INIT_POS), sqliteStatement(nullptr), connection_(connectionPool_->AcquireConnection(true)) +{ + for (auto arg : selectionArgs) { + args_.push_back(ValueObject(std::move(arg))); + } +} + +StepResultSet::StepResultSet(std::shared_ptr rdb, SqliteConnectionPool *pool, + const std::string &sql, std::vector &&args) + : rdb(rdb), connectionPool_(pool), sql(sql), args_(std::move(args)), isAfterLast(false), rowCount(INIT_POS), sqliteStatement(nullptr), connection_(connectionPool_->AcquireConnection(true)) { } @@ -256,7 +266,7 @@ int StepResultSet::PrepareStep() } int errCode; - sqliteStatement = connection_->BeginStepQuery(errCode, sql, selectionArgs); + sqliteStatement = connection_->BeginStepQuery(errCode, sql, args_); if (sqliteStatement == nullptr) { connection_->EndStepQuery(); LOG_ERROR("BeginStepQuery ret is %{public}d", errCode); diff --git a/relational_store/interfaces/inner_api/appdatafwk/BUILD.gn b/relational_store/interfaces/inner_api/appdatafwk/BUILD.gn index df0cead5..97b2755a 100644 --- a/relational_store/interfaces/inner_api/appdatafwk/BUILD.gn +++ b/relational_store/interfaces/inner_api/appdatafwk/BUILD.gn @@ -107,7 +107,7 @@ ohos_shared_library("native_appdatafwk") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", ] diff --git a/relational_store/interfaces/inner_api/dataability/BUILD.gn b/relational_store/interfaces/inner_api/dataability/BUILD.gn index c3768e76..510d7bc7 100644 --- a/relational_store/interfaces/inner_api/dataability/BUILD.gn +++ b/relational_store/interfaces/inner_api/dataability/BUILD.gn @@ -52,7 +52,7 @@ ohos_shared_library("native_dataability") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_single", ] diff --git a/relational_store/interfaces/inner_api/dataability/include/ishared_result_set.h b/relational_store/interfaces/inner_api/dataability/include/ishared_result_set.h index aaa80e1b..23e3941c 100644 --- a/relational_store/interfaces/inner_api/dataability/include/ishared_result_set.h +++ b/relational_store/interfaces/inner_api/dataability/include/ishared_result_set.h @@ -18,6 +18,7 @@ #include #include "iremote_broker.h" #include "abs_shared_result_set.h" +#include "distributeddata_relational_store_ipc_interface_code.h" namespace OHOS::NativeRdb { class API_EXPORT ISharedResultSet : public AbsSharedResultSet, public IRemoteBroker { public: @@ -25,38 +26,7 @@ public: API_EXPORT static std::shared_ptr ReadFromParcel(MessageParcel &parcel); API_EXPORT static sptr WriteToParcel( std::shared_ptr resultSet, MessageParcel &parcel); - -protected: - enum { - FUNC_GET_ROW_COUNT, - FUNC_GET_ALL_COLUMN_NAMES, - FUNC_ON_GO, - FUNC_CLOSE, - FUNC_GET_BLOB, - FUNC_GET_STRING, - FUNC_GET_INT, - FUNC_GET_LONG, - FUNC_GET_DOUBLE, - FUNC_IS_COLUMN_NULL, - FUNC_GO_TO, - FUNC_GO_TO_ROW, - FUNC_GO_TO_FISTR_ROW, - FUNC_GO_TO_LAST_ROW, - FUNC_GO_TO_NEXT_ROW, - FUNC_GO_TO_PREV_ROW, - FUNC_IS_AT_FIRST_ROW, - FUNC_IS_AT_LAST_ROW, - FUNC_IS_STARTED_ROW, - FUNC_IS_ENDED_ROW, - FUNC_IS_CLOSED, - FUNC_GET_COLUMN_COUNT, - FUNC_GET_COLUMN_INDEX, - FUNC_GET_COLUMN_NAME, - FUNC_GET_COLUMN_TYPE, - FUNC_GET_ROW_INDEX, - FUNC_BUTT - }; - + private: static std::function(MessageParcel &parcel)> consumerCreator_; static std::function(std::shared_ptr, MessageParcel &)> providerCreator_; diff --git a/relational_store/interfaces/inner_api/rdb/BUILD.gn b/relational_store/interfaces/inner_api/rdb/BUILD.gn index 42fab011..cae6ea39 100644 --- a/relational_store/interfaces/inner_api/rdb/BUILD.gn +++ b/relational_store/interfaces/inner_api/rdb/BUILD.gn @@ -123,8 +123,8 @@ if (is_ohos) { external_deps = [ "c_utils:utils", "device_manager:devicemanagersdk", - "hilog_native:libhilog", - "hitrace_native:hitrace_meter", + "hilog:libhilog", + "hitrace:hitrace_meter", "huks:libhukssdk", "ipc:ipc_core", "samgr:samgr_proxy", @@ -172,8 +172,8 @@ if (is_ohos) { external_deps = [ "c_utils:utils", "device_manager:devicemanagersdk", - "hilog_native:libhilog", - "hitrace_native:hitrace_meter", + "hilog:libhilog", + "hitrace:hitrace_meter", "huks:libhukssdk", "ipc:ipc_core", "samgr:samgr_proxy", diff --git a/relational_store/interfaces/inner_api/rdb/include/distributeddata_relational_store_ipc_interface_code.h b/relational_store/interfaces/inner_api/rdb/include/distributeddata_relational_store_ipc_interface_code.h new file mode 100644 index 00000000..69ca73e6 --- /dev/null +++ b/relational_store/interfaces/inner_api/rdb/include/distributeddata_relational_store_ipc_interface_code.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* SAID:1301 */ +/* FeatureSystem: rdb_service */ +#ifndef DISTRIBUTEDDATA_RELATIONAL_STORE_IPC_INTERFACE_H +#define DISTRIBUTEDDATA_RELATIONAL_STORE_IPC_INTERFACE_H + +namespace OHOS::DistributedRdb { +namespace RelationalStore { +enum class IRdbNotifierInterfaceCode { + RDB_NOTIFIER_CMD_SYNC_COMPLETE = 0, + RDB_NOTIFIER_CMD_DATA_CHANGE, + RDB_NOTIFIER_CMD_MAX +}; + +enum class IResultSetInterfaceCode { + FUNC_GET_ROW_COUNT, + FUNC_GET_ALL_COLUMN_NAMES, + FUNC_ON_GO, + FUNC_CLOSE, + FUNC_GET_BLOB, + FUNC_GET_STRING, + FUNC_GET_INT, + FUNC_GET_LONG, + FUNC_GET_DOUBLE, + FUNC_IS_COLUMN_NULL, + FUNC_GO_TO, + FUNC_GO_TO_ROW, + FUNC_GO_TO_FISTR_ROW, + FUNC_GO_TO_LAST_ROW, + FUNC_GO_TO_NEXT_ROW, + FUNC_GO_TO_PREV_ROW, + FUNC_IS_AT_FIRST_ROW, + FUNC_IS_AT_LAST_ROW, + FUNC_IS_STARTED_ROW, + FUNC_IS_ENDED_ROW, + FUNC_IS_CLOSED, + FUNC_GET_COLUMN_COUNT, + FUNC_GET_COLUMN_INDEX, + FUNC_GET_COLUMN_NAME, + FUNC_GET_COLUMN_TYPE, + FUNC_GET_ROW_INDEX, + FUNC_BUTT, +}; + +enum class KvStoreInterfaceCode { + GET_FEATURE_INTERFACE = 0, + REGISTER_DEATH_OBSERVER, +}; + +enum class CloudKvStoreInterfaceCode { + GET_FEATURE_INTERFACE = 0 +}; + +enum class RdbServiceInterfaceCode { + RDB_SERVICE_CMD_OBTAIN_TABLE, + RDB_SERVICE_CMD_INIT_NOTIFIER, + RDB_SERVICE_CMD_SET_DIST_TABLE, + RDB_SERVICE_CMD_SYNC, + RDB_SERVICE_CMD_ASYNC, + RDB_SERVICE_CMD_SUBSCRIBE, + RDB_SERVICE_CMD_UNSUBSCRIBE, + RDB_SERVICE_CMD_REMOTE_QUERY, + RDB_SERVICE_CMD_GET_SCHEMA, + RDB_SERVICE_CMD_MAX +}; +} // namespace RelationalStore +} // namespace OHOS::DistributedRdb + +#endif // DISTRIBUTEDDATA_RELATIONAL_STORE_IPC_INTERFACE_H \ No newline at end of file diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h b/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h index 19e59064..51aa2c50 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h @@ -278,6 +278,11 @@ static constexpr int E_WAL_SIZE_OVER_LIMIT = (E_BASE + 47); * @brief The error when the connection count is used up. */ static constexpr int E_CON_OVER_LIMIT = (E_BASE + 48); + +/** +* @brief The error when the sharedblock unit is null. +*/ +static constexpr int E_NULL_OBJECT = (E_BASE + 49); } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_notifier.h b/relational_store/interfaces/inner_api/rdb/include/rdb_notifier.h index e61872a3..11d5e0b9 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_notifier.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_notifier.h @@ -16,16 +16,12 @@ #ifndef DISTRIBUTED_RDB_RDB_NOTIFIER_H #define DISTRIBUTED_RDB_RDB_NOTIFIER_H #include "rdb_types.h" +#include "distributeddata_relational_store_ipc_interface_code.h" namespace OHOS::DistributedRdb { class IRdbNotifier { public: using ChangeInfo = RdbStoreObserver::ChangeInfo; using PrimaryFields = std::map; - enum Code : int32_t { - RDB_NOTIFIER_CMD_SYNC_COMPLETE, - RDB_NOTIFIER_CMD_DATA_CHANGE, - RDB_NOTIFIER_CMD_MAX - }; virtual int32_t OnComplete(uint32_t seqNum, Details &&result) = 0; virtual int32_t OnChange(const Origin &origin, const PrimaryFields &primaries, ChangeInfo &&changeInfo) = 0; diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_service.h b/relational_store/interfaces/inner_api/rdb/include/rdb_service.h index b126c156..891da413 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_service.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_service.h @@ -21,6 +21,7 @@ #include "rdb_types.h" #include "rdb_notifier.h" +#include "distributeddata_relational_store_ipc_interface_code.h" namespace OHOS { template @@ -29,19 +30,6 @@ class IRemoteObject; namespace DistributedRdb { class RdbService { public: - enum { - RDB_SERVICE_CMD_OBTAIN_TABLE, - RDB_SERVICE_CMD_INIT_NOTIFIER, - RDB_SERVICE_CMD_SET_DIST_TABLE, - RDB_SERVICE_CMD_SYNC, - RDB_SERVICE_CMD_ASYNC, - RDB_SERVICE_CMD_SUBSCRIBE, - RDB_SERVICE_CMD_UNSUBSCRIBE, - RDB_SERVICE_CMD_REMOTE_QUERY, - RDB_SERVICE_CMD_GET_SCHEMA, - RDB_SERVICE_CMD_MAX - }; - struct Option { int32_t mode; uint32_t seqNum = 0; diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_store.h b/relational_store/interfaces/inner_api/rdb/include/rdb_store.h index b420aec9..fe99849a 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_store.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_store.h @@ -69,6 +69,12 @@ public: * @brief Use RdbStoreObserver replace DistributedRdb::RdbStoreObserver namespace. */ using RdbStoreObserver = DistributedRdb::RdbStoreObserver; + using PRIKey = RdbStoreObserver::PrimaryKey; + + /** + * @brief Use Date replace DistributedRdb::Date namespace. + */ + using Date = DistributedRdb::Date; /** * @brief Destructor. @@ -413,6 +419,26 @@ public: * @param option Indicates the drop option. */ virtual bool DropDeviceData(const std::vector& devices, const DropOption& option) = 0; + + /** + * @brief Get the the specified column modify time. + * + * @param table Indicates the specified table. + * @param columnName Indicates the column. + * @param PRIKey Indicates the primary key. + * + * @return Returns the specified column modify time. + */ + virtual std::map GetModifyTime( + const std::string &table, const std::string &columnName, std::vector &keys) = 0; + + /** + * @brief Queries data in the database based on SQL statement. + * + * @param sql Indicates the SQL statement to execute. + * @param args Indicates the selection arguments. + */ + virtual std::shared_ptr QueryByStep(const std::string &sql, std::vector &&args) = 0; }; } // namespace OHOS::NativeRdb #endif diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_types.h b/relational_store/interfaces/inner_api/rdb/include/rdb_types.h index 62e02489..44ecbdfe 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_types.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_types.h @@ -82,10 +82,10 @@ enum Progress { }; struct Statistic { - int32_t total; - int32_t success; - int32_t failed; - int32_t untreated; + uint32_t total; + uint32_t success; + uint32_t failed; + uint32_t untreated; }; struct TableDetail { @@ -142,6 +142,16 @@ struct PredicatesMemo { std::vector operations_; }; +struct Date { + Date() {} + Date(int64_t date) : date(date) {} + operator double() const + { + return static_cast(date); + } + int64_t date; +}; + enum SubscribeMode { REMOTE, CLOUD, @@ -183,7 +193,7 @@ public: CHG_TYPE_DELETE, CHG_TYPE_BUTT }; - using PrimaryKey = std::variant; + using PrimaryKey = std::variant; using ChangeInfo = std::map[CHG_TYPE_BUTT]>; using PrimaryFields = std::map; virtual void OnChange(const std::vector &devices) = 0; // networkid diff --git a/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store.h b/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store.h index 37c7e306..71d0bf32 100644 --- a/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store.h +++ b/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store.h @@ -37,7 +37,8 @@ public: virtual int BatchInsert(int64_t &outInsertNum, const std::string &table, const std::vector &initialBatchValues) = 0; virtual int Replace(int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues) = 0; - virtual int InsertWithConflictResolution(int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues, + virtual int InsertWithConflictResolution( + int64_t &outRowId, const std::string &table, const ValuesBucket &initialValues, ConflictResolution conflictResolution = ConflictResolution::ON_CONFLICT_NONE) = 0; virtual int Update(int &changedRows, const std::string &table, const ValuesBucket &values, const std::string &whereClause = "", @@ -82,6 +83,7 @@ public: virtual bool IsReadOnly() const = 0; virtual bool IsMemoryRdb() const = 0; virtual int Restore(const std::string backupPath, const std::vector &newKey = std::vector()) = 0; + virtual std::shared_ptr QueryByStep(const std::string &sql, std::vector &&args) = 0; }; } // namespace OHOS::NativeRdb #endif diff --git a/relational_store/interfaces/inner_api/rdb_bms_adapter/BUILD.gn b/relational_store/interfaces/inner_api/rdb_bms_adapter/BUILD.gn index f3b822d1..93e2b904 100644 --- a/relational_store/interfaces/inner_api/rdb_bms_adapter/BUILD.gn +++ b/relational_store/interfaces/inner_api/rdb_bms_adapter/BUILD.gn @@ -55,7 +55,7 @@ ohos_shared_library("rdb_bms_adapter") { "bundle_framework:appexecfwk_base", "bundle_framework:appexecfwk_core", "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "resource_management:global_resmgr", ] diff --git a/relational_store/interfaces/inner_api/rdb_bms_adapter/include/data_properties.h b/relational_store/interfaces/inner_api/rdb_bms_adapter/include/data_properties.h index 6416a42a..32eea4fa 100644 --- a/relational_store/interfaces/inner_api/rdb_bms_adapter/include/data_properties.h +++ b/relational_store/interfaces/inner_api/rdb_bms_adapter/include/data_properties.h @@ -17,7 +17,6 @@ #define DATA_PROPERTIES_H #include "serializable.h" - namespace OHOS::RdbBMSAdapter { struct API_EXPORT DataProperties : public Serializable { virtual ~DataProperties() = default; diff --git a/relational_store/interfaces/inner_api/rdb_data_share_adapter/BUILD.gn b/relational_store/interfaces/inner_api/rdb_data_share_adapter/BUILD.gn index eed23df4..75849e9a 100644 --- a/relational_store/interfaces/inner_api/rdb_data_share_adapter/BUILD.gn +++ b/relational_store/interfaces/inner_api/rdb_data_share_adapter/BUILD.gn @@ -52,7 +52,7 @@ ohos_shared_library("rdb_data_share_adapter") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", ] public_configs = [ ":rdb_data_share_adapter_public_config" ] diff --git a/relational_store/interfaces/ndk/BUILD.gn b/relational_store/interfaces/ndk/BUILD.gn index 9fa6476e..4326da78 100644 --- a/relational_store/interfaces/ndk/BUILD.gn +++ b/relational_store/interfaces/ndk/BUILD.gn @@ -29,11 +29,18 @@ ohos_ndk_headers("native_rdb_ndk_header") { ohos_ndk_library("libnative_rdb_ndk") { output_name = "native_rdb_ndk" - output_extension = "so" - ndk_description_file = "./libnative_rdb.ndk.json" system_capability = "SystemCapability.DistributedDataManager.RelationalStore.Core" + ndk_description_file = "./libnative_rdb.ndk.json" min_compact_version = "10" + system_capability_headers = [ + "$ndk_headers_out_dir/database/rdb/oh_cursor.h", + "$ndk_headers_out_dir/database/rdb/oh_predicates.h", + "$ndk_headers_out_dir/database/rdb/oh_value_object.h", + "$ndk_headers_out_dir/database/rdb/oh_values_bucket.h", + "$ndk_headers_out_dir/database/rdb/relational_store.h", + "$ndk_headers_out_dir/database/rdb/relational_store_error_code.h", + ] } ohos_shared_library("native_rdb_ndk") { @@ -56,9 +63,10 @@ ohos_shared_library("native_rdb_ndk") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", ] + relative_install_dir = "ndk" part_name = "relational_store" subsystem_name = "distributeddatamgr" } diff --git a/relational_store/test/js/clouddata/unittest/src/CloudSyncConfigCallback.js b/relational_store/test/js/clouddata/unittest/src/CloudSyncConfigCallback.js index 33e3653e..d3bcf18c 100644 --- a/relational_store/test/js/clouddata/unittest/src/CloudSyncConfigCallback.js +++ b/relational_store/test/js/clouddata/unittest/src/CloudSyncConfigCallback.js @@ -17,7 +17,7 @@ import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from 'deccjsunit/index' import cloudData from '@ohos.data.cloudData'; -describe('CloudConfigTest', function () { +describe('CloudConfigCallbackTest', function () { /** * @tc.name EnabledCloudInvalidArgsCallbackTest * @tc.desc Test Js Api EnabledCloud with invalid args diff --git a/relational_store/test/js/clouddata/unittest/src/CloudSyncConfigPromise.js b/relational_store/test/js/clouddata/unittest/src/CloudSyncConfigPromise.js index 4e64a9e9..8c9e034a 100644 --- a/relational_store/test/js/clouddata/unittest/src/CloudSyncConfigPromise.js +++ b/relational_store/test/js/clouddata/unittest/src/CloudSyncConfigPromise.js @@ -17,7 +17,7 @@ import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from 'deccjsunit/index' import cloudData from '@ohos.data.cloudData'; -describe('CloudConfigTest', function () { +describe('CloudConfigPromiseTest', function () { /** * @tc.name EnabledCloudInvalidArgsTest * @tc.desc Test Js Api EnabledCloud with invalid args diff --git a/relational_store/test/js/rdb/unittest/src/RdbstoreStoreExcuteSqlJsunit.test.js b/relational_store/test/js/rdb/unittest/src/RdbstoreStoreExcuteSqlJsunit.test.js index 09b9b044..2fef3b4b 100644 --- a/relational_store/test/js/rdb/unittest/src/RdbstoreStoreExcuteSqlJsunit.test.js +++ b/relational_store/test/js/rdb/unittest/src/RdbstoreStoreExcuteSqlJsunit.test.js @@ -24,7 +24,7 @@ const STORE_CONFIG = { } var rdbStore = undefined; -describe('rdbStoreInsertTest', function () { +describe('rdbStoreExcuteSqlTest', function () { beforeAll(async function () { console.info(TAG + 'beforeAll') rdbStore = await dataRdb.getRdbStore(STORE_CONFIG, 1); diff --git a/relational_store/test/js/rdb/unittest/src/RdbstoreTransactionJsunit.test.js b/relational_store/test/js/rdb/unittest/src/RdbstoreTransactionJsunit.test.js index 3e4e4c8b..977d795c 100644 --- a/relational_store/test/js/rdb/unittest/src/RdbstoreTransactionJsunit.test.js +++ b/relational_store/test/js/rdb/unittest/src/RdbstoreTransactionJsunit.test.js @@ -26,7 +26,7 @@ const STORE_CONFIG = { var rdbStore = undefined; -describe('rdbStoreInsertTest', function () { +describe('rdbStoreTransactionTest', function () { beforeAll(async function () { console.info(TAG + 'beforeAll') rdbStore = await dataRdb.getRdbStore(STORE_CONFIG, 1); diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreAssetResultSetJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreAssetResultSetJsunit.test.js index 1a12808b..e30ef45c 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbStoreAssetResultSetJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreAssetResultSetJsunit.test.js @@ -64,7 +64,7 @@ const asset4 = { } var rdbStore = undefined; -describe('rdbResultSetTest', function () { +describe('rdbAssetResultSetTest', function () { beforeAll(async function () { console.info(TAG + 'beforeAll') rdbStore = await data_relationalStore.getRdbStore(context, STORE_CONFIG); @@ -106,6 +106,7 @@ describe('rdbResultSetTest', function () { await rdbStore.insert("test", valuesBucket) valuesBucket = { "data1": asset1, + "data3": new Array(), } await rdbStore.insert("test", valuesBucket) console.log(TAG + "createTest data end"); @@ -213,16 +214,17 @@ describe('rdbResultSetTest', function () { expect(true).assertEqual(resultSet.goToNextRow()) const id = resultSet.getLong(resultSet.getColumnIndex("id")) const data2 = resultSet.getAsset(resultSet.getColumnIndex("data2")) - expect(null).assertFail(); - } catch (e) { - expect(e.code == 14800000).assertTrue() - } finally { + console.log(TAG + "id=" + id + ", data2=" + data2); + expect(data2).assertEqual(null); + resultSet.close(); expect(true).assertEqual(resultSet.isClosed) - resultSet = null - done(); - console.log(TAG + "************* testGetAsset0003 end *************"); + } catch (e) { + expect(null).assertFail(); } + resultSet = null + done(); + console.log(TAG + "************* testGetAsset0003 end *************"); }) /** @@ -511,16 +513,17 @@ describe('rdbResultSetTest', function () { expect(true).assertEqual(resultSet.goToNextRow()) const id = resultSet.getLong(resultSet.getColumnIndex("id")) const data3 = resultSet.getAssets(resultSet.getColumnIndex("data3")) - expect(null).assertFail(); - } catch (e) { - expect(e.code == 14800000).assertTrue() - } finally { + console.log(TAG + "id=" + id + ", data3=" + data3); + expect(data3.length).assertEqual(0); + resultSet.close(); expect(true).assertEqual(resultSet.isClosed) - resultSet = null - done(); - console.log(TAG + "************* testGetAsset0003 end *************"); + } catch (e) { + expect(null).assertFail(); } + resultSet = null + done(); + console.log(TAG + "************* testGetAssets0003 end *************"); }) /** diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbstoreStoreExcuteSqlJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbstoreStoreExcuteSqlJsunit.test.js index aa28d45e..45494e59 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbstoreStoreExcuteSqlJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbstoreStoreExcuteSqlJsunit.test.js @@ -27,7 +27,7 @@ const STORE_CONFIG = { } var rdbStore = undefined; -describe('rdbStoreInsertTest', function () { +describe('rdbStoreExcuteSqlTest', function () { beforeAll(async function () { console.info(TAG + 'beforeAll') rdbStore = await data_relationalStore.getRdbStore(context, STORE_CONFIG); diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbstoreTransactionJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbstoreTransactionJsunit.test.js index 96b97fc0..416448a2 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbstoreTransactionJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbstoreTransactionJsunit.test.js @@ -29,7 +29,7 @@ const STORE_CONFIG = { var rdbStore = undefined; -describe('rdbStoreInsertTest', function () { +describe('rdbStoreTransactionTest', function () { beforeAll(async function () { console.info(TAG + 'beforeAll') rdbStore = await data_relationalStore.getRdbStore(context, STORE_CONFIG); diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbstoreUpdateJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbstoreUpdateJsunit.test.js index 864ab835..e76939e2 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbstoreUpdateJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbstoreUpdateJsunit.test.js @@ -778,7 +778,7 @@ describe('rdbStoreUpdateTest', function () { await predicates.equalTo("age", "19") let updatePromise = rdbStore.update(valueBucket, predicates, data_relationalStore.ConflictResolution.ON_CONFLICT_ROLLBACK); updatePromise.then(async (ret) => { - aexpect(null).assertFail(); + expect(null).assertFail(); await console.log(TAG + "update done: " + ret); }).catch((err) => { expect(null).assertFail(); diff --git a/relational_store/test/native/dataability/BUILD.gn b/relational_store/test/native/dataability/BUILD.gn index 7926c603..77b788c2 100644 --- a/relational_store/test/native/dataability/BUILD.gn +++ b/relational_store/test/native/dataability/BUILD.gn @@ -35,7 +35,7 @@ ohos_unittest("NativeDataAbilityTest") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "relational_store:native_dataability", "relational_store:native_rdb", ] diff --git a/relational_store/test/native/rdb/BUILD.gn b/relational_store/test/native/rdb/BUILD.gn index 9543b509..811f11d0 100644 --- a/relational_store/test/native/rdb/BUILD.gn +++ b/relational_store/test/native/rdb/BUILD.gn @@ -72,7 +72,7 @@ ohos_unittest("NativeRdbTest") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "huks:libhukssdk", "ipc:ipc_core", ] diff --git a/relational_store/test/native/rdb/distributedtest/rdb_store_impl_test/BUILD.gn b/relational_store/test/native/rdb/distributedtest/rdb_store_impl_test/BUILD.gn index 1759e451..2c8c284d 100644 --- a/relational_store/test/native/rdb/distributedtest/rdb_store_impl_test/BUILD.gn +++ b/relational_store/test/native/rdb/distributedtest/rdb_store_impl_test/BUILD.gn @@ -46,7 +46,7 @@ ohos_distributedtest("DistributedTest") { external_deps = [ "c_utils:utils", "device_manager:devicemanagersdk", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", "relational_store:native_rdb", ] @@ -67,7 +67,7 @@ ohos_distributedtest("DistributedTestAgent") { external_deps = [ "c_utils:utils", "device_manager:devicemanagersdk", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", "relational_store:native_rdb", ] diff --git a/relational_store/test/native/rdb/fuzztest/rdbimpl_fuzzer/BUILD.gn b/relational_store/test/native/rdb/fuzztest/rdbimpl_fuzzer/BUILD.gn index e806d5d1..ab97a101 100644 --- a/relational_store/test/native/rdb/fuzztest/rdbimpl_fuzzer/BUILD.gn +++ b/relational_store/test/native/rdb/fuzztest/rdbimpl_fuzzer/BUILD.gn @@ -61,7 +61,7 @@ ohos_fuzztest("RdbImplFuzzTest") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "ipc:ipc_core", ] } diff --git a/relational_store/test/native/rdb/fuzztest/rdbstore_fuzzer/BUILD.gn b/relational_store/test/native/rdb/fuzztest/rdbstore_fuzzer/BUILD.gn index 0e2743a9..bd277be0 100644 --- a/relational_store/test/native/rdb/fuzztest/rdbstore_fuzzer/BUILD.gn +++ b/relational_store/test/native/rdb/fuzztest/rdbstore_fuzzer/BUILD.gn @@ -35,7 +35,7 @@ ohos_fuzztest("RdbStoreFuzzTest") { sources = [ "rdbstore_fuzzer.cpp" ] external_deps = [ - "hilog_native:libhilog", + "hilog:libhilog", "relational_store:native_rdb", ] } diff --git a/relational_store/test/native/rdb_data_ability_adapter/BUILD.gn b/relational_store/test/native/rdb_data_ability_adapter/BUILD.gn index df213be1..9b0ceb9d 100644 --- a/relational_store/test/native/rdb_data_ability_adapter/BUILD.gn +++ b/relational_store/test/native/rdb_data_ability_adapter/BUILD.gn @@ -37,7 +37,7 @@ ohos_unittest("NativeDataAbilityAdapterTest") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "relational_store:native_dataability", "relational_store:native_rdb", "relational_store:rdb_data_ability_adapter", diff --git a/relational_store/test/native/rdb_data_share_adapter/BUILD.gn b/relational_store/test/native/rdb_data_share_adapter/BUILD.gn index a9d8934f..68cacefd 100644 --- a/relational_store/test/native/rdb_data_share_adapter/BUILD.gn +++ b/relational_store/test/native/rdb_data_share_adapter/BUILD.gn @@ -51,7 +51,7 @@ ohos_unittest("RdbDataShareAdapterTest") { external_deps = [ "c_utils:utils", - "hilog_native:libhilog", + "hilog:libhilog", "relational_store:native_rdb", "relational_store:rdb_data_share_adapter", ] diff --git a/relational_store/test/ndk/BUILD.gn b/relational_store/test/ndk/BUILD.gn index a2ac85a7..47d3a71e 100644 --- a/relational_store/test/ndk/BUILD.gn +++ b/relational_store/test/ndk/BUILD.gn @@ -24,6 +24,8 @@ config("module_private_config") { "${relational_store_innerapi_path}/rdb/include", "${relational_store_innerapi_path}/appdatafwk/include", "${relational_store_base_path}/interfaces/ndk/src", + "${relational_store_common_path}/include", + "${relational_store_native_path}/rdb/include", ] } @@ -31,6 +33,11 @@ ohos_unittest("NativeRdbNdkTest") { module_out_path = module_output_path sources = [ + "${relational_store_base_path}/interfaces/ndk/src/relational_cursor.cpp", + "${relational_store_base_path}/interfaces/ndk/src/relational_predicates.cpp", + "${relational_store_base_path}/interfaces/ndk/src/relational_store.cpp", + "${relational_store_base_path}/interfaces/ndk/src/relational_value_object.cpp", + "${relational_store_base_path}/interfaces/ndk/src/relational_values_bucket.cpp", "unittest/rdb_cursor_test.cpp", "unittest/rdb_predicates_test.cpp", "unittest/rdb_store_test.cpp", @@ -39,11 +46,14 @@ ohos_unittest("NativeRdbNdkTest") { configs = [ ":module_private_config" ] external_deps = [ - "hilog_native:libhilog", - "relational_store:native_rdb_ndk", + "c_utils:utils", + "hilog:libhilog", ] - deps = [ "//third_party/googletest:gtest_main" ] + deps = [ + "${relational_store_innerapi_path}/rdb:native_rdb", + "//third_party/googletest:gtest_main", + ] } ############################################################################### diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3e66eac8..c535ed67 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -37,7 +37,7 @@ aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/../preferences/test/native/unit #aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/test/native/dataability/unittest localTestSrc) #aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/test/native/rdb/unittest localTestSrc) #aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/test/native/rdb_data_share_adapter/unittest localTestSrc) -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/../udmf/framework/innerkitsimpl/test/unittest remoteTestSrc) +#aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/../udmf/framework/innerkitsimpl/test/unittest remoteTestSrc) set(links secure mock relational_store data_share preferences jsoncpp crypto distributeddb data_object app adapter svcFwk kvdb service udmf) diff --git a/test/include/CMakeLists.txt b/test/include/CMakeLists.txt index 37066cd5..37e1580c 100644 --- a/test/include/CMakeLists.txt +++ b/test/include/CMakeLists.txt @@ -64,6 +64,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../data_share/interfaces/inner_a include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../data_share/interfaces/inner_api/provider/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../data_share/frameworks/native/common/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../udmf) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../udmf/framework/common) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../udmf/interfaces/innerkits/client) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../udmf/interfaces/innerkits/common) diff --git a/udmf b/udmf deleted file mode 160000 index 5edbfe95..00000000 --- a/udmf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5edbfe95a814f28c6659b68d3267072e195cdc5c -- Gitee From 35e366d537f465bc8872816ec73f773858731ac8 Mon Sep 17 00:00:00 2001 From: htt1997 Date: Wed, 5 Jul 2023 10:24:54 +0800 Subject: [PATCH 2/2] add udmf Signed-off-by: htt1997 --- udmf/BUILD.gn | 39 + udmf/CMakeLists.txt | 42 + udmf/CODEOWNERS | 15 + udmf/LICENSE | 177 ++ udmf/OAT.xml | 68 + udmf/README_zh.md | 106 + udmf/bundle.json | 121 ++ udmf/figures/udmf_architecture.png | Bin 0 -> 53496 bytes udmf/figures/udmf_type_ADT.png | Bin 0 -> 6016 bytes udmf/figures/udmf_type_File.png | Bin 0 -> 19605 bytes udmf/figures/udmf_type_SDT.png | Bin 0 -> 10140 bytes udmf/figures/udmf_type_Text.png | Bin 0 -> 7590 bytes udmf/framework/common/endian_converter.h | 123 ++ udmf/framework/common/logger.h | 93 + udmf/framework/common/tlv_object.h | 478 +++++ udmf/framework/common/tlv_util.cpp | 1463 ++++++++++++++ udmf/framework/common/tlv_util.h | 223 +++ udmf/framework/common/udmf_types_util.cpp | 198 ++ udmf/framework/common/udmf_types_util.h | 76 + .../innerkitsimpl/client/udmf_client.cpp | 162 ++ .../innerkitsimpl/common/unified_key.cpp | 152 ++ .../innerkitsimpl/common/unified_meta.cpp | 108 + .../data/application_defined_record.cpp | 61 + udmf/framework/innerkitsimpl/data/audio.cpp | 29 + udmf/framework/innerkitsimpl/data/file.cpp | 64 + udmf/framework/innerkitsimpl/data/folder.cpp | 29 + udmf/framework/innerkitsimpl/data/html.cpp | 66 + udmf/framework/innerkitsimpl/data/image.cpp | 29 + udmf/framework/innerkitsimpl/data/link.cpp | 69 + .../innerkitsimpl/data/plain_text.cpp | 65 + .../data/system_defined_appitem.cpp | 91 + .../data/system_defined_form.cpp | 81 + .../data/system_defined_pixelmap.cpp | 46 + .../data/system_defined_record.cpp | 58 + udmf/framework/innerkitsimpl/data/text.cpp | 44 + .../innerkitsimpl/data/unified_data.cpp | 84 + .../innerkitsimpl/data/unified_record.cpp | 58 + udmf/framework/innerkitsimpl/data/video.cpp | 29 + .../innerkitsimpl/test/fuzztest/BUILD.gn | 21 + .../test/fuzztest/udmfclient_fuzzer/BUILD.gn | 67 + .../fuzztest/udmfclient_fuzzer/corpus/init | 16 + .../fuzztest/udmfclient_fuzzer/project.xml | 25 + .../udmfclient_fuzzer/udmf_client_fuzzer.cpp | 658 ++++++ .../udmfclient_fuzzer/udmf_client_fuzzer.h | 21 + .../innerkitsimpl/test/unittest/BUILD.gn | 61 + .../test/unittest/udmf_client_test.cpp | 1755 +++++++++++++++++ .../jskitsimpl/common/napi_data_utils.cpp | 443 +++++ .../jskitsimpl/common/napi_error_utils.cpp | 94 + .../jskitsimpl/common/napi_queue.cpp | 175 ++ .../data/application_defined_record_napi.cpp | 143 ++ udmf/framework/jskitsimpl/data/audio_napi.cpp | 114 ++ udmf/framework/jskitsimpl/data/file_napi.cpp | 142 ++ .../framework/jskitsimpl/data/folder_napi.cpp | 113 ++ udmf/framework/jskitsimpl/data/html_napi.cpp | 145 ++ udmf/framework/jskitsimpl/data/image_napi.cpp | 114 ++ udmf/framework/jskitsimpl/data/link_napi.cpp | 146 ++ .../jskitsimpl/data/plain_text_napi.cpp | 145 ++ .../jskitsimpl/data/summary_napi.cpp | 100 + .../data/system_defined_appitem_napi.cpp | 274 +++ .../data/system_defined_form_napi.cpp | 242 +++ .../data/system_defined_pixelmap_napi.cpp | 114 ++ .../data/system_defined_record_napi.cpp | 113 ++ udmf/framework/jskitsimpl/data/text_napi.cpp | 109 + udmf/framework/jskitsimpl/data/udmf_napi.cpp | 300 +++ .../jskitsimpl/data/unified_data_napi.cpp | 216 ++ .../jskitsimpl/data/unified_record_napi.cpp | 79 + udmf/framework/jskitsimpl/data/video_napi.cpp | 114 ++ udmf/framework/jskitsimpl/unittest/BUILD.gn | 30 + .../jskitsimpl/unittest/UdmfCallbackJsTest.js | 344 ++++ .../jskitsimpl/unittest/UdmfJsTest.js | 416 ++++ .../jskitsimpl/unittest/UdmfPromiseJsTest.js | 411 ++++ .../framework/jskitsimpl/unittest/config.json | 62 + .../distributeddata_udmf_ipc_interface_code.h | 34 + udmf/framework/service/udmf_service.h | 54 + .../framework/service/udmf_service_client.cpp | 125 ++ udmf/framework/service/udmf_service_client.h | 54 + udmf/framework/service/udmf_service_proxy.cpp | 265 +++ udmf/framework/service/udmf_service_proxy.h | 54 + udmf/interfaces/innerkits/BUILD.gn | 78 + .../interfaces/innerkits/client/udmf_client.h | 44 + udmf/interfaces/innerkits/common/error_code.h | 46 + .../interfaces/innerkits/common/unified_key.h | 40 + .../innerkits/common/unified_meta.h | 135 ++ .../innerkits/common/unified_types.h | 83 + udmf/interfaces/innerkits/common/visibility.h | 23 + .../data/application_defined_record.h | 43 + udmf/interfaces/innerkits/data/audio.h | 31 + udmf/interfaces/innerkits/data/file.h | 45 + udmf/interfaces/innerkits/data/folder.h | 30 + udmf/interfaces/innerkits/data/html.h | 42 + udmf/interfaces/innerkits/data/image.h | 31 + udmf/interfaces/innerkits/data/link.h | 42 + udmf/interfaces/innerkits/data/plain_text.h | 42 + .../innerkits/data/system_defined_appitem.h | 52 + .../innerkits/data/system_defined_form.h | 49 + .../innerkits/data/system_defined_pixelmap.h | 37 + .../innerkits/data/system_defined_record.h | 39 + udmf/interfaces/innerkits/data/text.h | 40 + udmf/interfaces/innerkits/data/unified_data.h | 47 + .../innerkits/data/unified_record.h | 49 + udmf/interfaces/innerkits/data/video.h | 30 + udmf/interfaces/jskits/BUILD.gn | 134 ++ .../jskits/common/napi_data_utils.h | 120 ++ .../jskits/common/napi_error_utils.h | 78 + udmf/interfaces/jskits/common/napi_queue.h | 168 ++ .../data/application_defined_record_napi.h | 48 + udmf/interfaces/jskits/data/audio_napi.h | 44 + udmf/interfaces/jskits/data/file_napi.h | 47 + udmf/interfaces/jskits/data/folder_napi.h | 44 + udmf/interfaces/jskits/data/html_napi.h | 47 + udmf/interfaces/jskits/data/image_napi.h | 44 + udmf/interfaces/jskits/data/link_napi.h | 48 + udmf/interfaces/jskits/data/plain_text_napi.h | 47 + udmf/interfaces/jskits/data/summary_napi.h | 44 + .../jskits/data/system_defined_appitem_napi.h | 62 + .../jskits/data/system_defined_form_napi.h | 59 + .../data/system_defined_pixelmap_napi.h | 47 + .../jskits/data/system_defined_record_napi.h | 45 + udmf/interfaces/jskits/data/text_napi.h | 44 + udmf/interfaces/jskits/data/udmf_napi.h | 44 + .../jskits/data/unified_data_napi.h | 44 + .../jskits/data/unified_record_napi.h | 42 + udmf/interfaces/jskits/data/video_napi.h | 44 + .../jskits/module/udmf_napi_module.cpp | 98 + udmf/udmf.gni | 44 + 125 files changed, 15039 insertions(+) create mode 100644 udmf/BUILD.gn create mode 100644 udmf/CMakeLists.txt create mode 100644 udmf/CODEOWNERS create mode 100644 udmf/LICENSE create mode 100644 udmf/OAT.xml create mode 100644 udmf/README_zh.md create mode 100644 udmf/bundle.json create mode 100644 udmf/figures/udmf_architecture.png create mode 100644 udmf/figures/udmf_type_ADT.png create mode 100644 udmf/figures/udmf_type_File.png create mode 100644 udmf/figures/udmf_type_SDT.png create mode 100644 udmf/figures/udmf_type_Text.png create mode 100644 udmf/framework/common/endian_converter.h create mode 100644 udmf/framework/common/logger.h create mode 100644 udmf/framework/common/tlv_object.h create mode 100644 udmf/framework/common/tlv_util.cpp create mode 100644 udmf/framework/common/tlv_util.h create mode 100644 udmf/framework/common/udmf_types_util.cpp create mode 100644 udmf/framework/common/udmf_types_util.h create mode 100644 udmf/framework/innerkitsimpl/client/udmf_client.cpp create mode 100644 udmf/framework/innerkitsimpl/common/unified_key.cpp create mode 100644 udmf/framework/innerkitsimpl/common/unified_meta.cpp create mode 100644 udmf/framework/innerkitsimpl/data/application_defined_record.cpp create mode 100644 udmf/framework/innerkitsimpl/data/audio.cpp create mode 100644 udmf/framework/innerkitsimpl/data/file.cpp create mode 100644 udmf/framework/innerkitsimpl/data/folder.cpp create mode 100644 udmf/framework/innerkitsimpl/data/html.cpp create mode 100644 udmf/framework/innerkitsimpl/data/image.cpp create mode 100644 udmf/framework/innerkitsimpl/data/link.cpp create mode 100644 udmf/framework/innerkitsimpl/data/plain_text.cpp create mode 100644 udmf/framework/innerkitsimpl/data/system_defined_appitem.cpp create mode 100644 udmf/framework/innerkitsimpl/data/system_defined_form.cpp create mode 100644 udmf/framework/innerkitsimpl/data/system_defined_pixelmap.cpp create mode 100644 udmf/framework/innerkitsimpl/data/system_defined_record.cpp create mode 100644 udmf/framework/innerkitsimpl/data/text.cpp create mode 100644 udmf/framework/innerkitsimpl/data/unified_data.cpp create mode 100644 udmf/framework/innerkitsimpl/data/unified_record.cpp create mode 100644 udmf/framework/innerkitsimpl/data/video.cpp create mode 100644 udmf/framework/innerkitsimpl/test/fuzztest/BUILD.gn create mode 100644 udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/BUILD.gn create mode 100644 udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/corpus/init create mode 100644 udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/project.xml create mode 100644 udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.cpp create mode 100644 udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.h create mode 100644 udmf/framework/innerkitsimpl/test/unittest/BUILD.gn create mode 100644 udmf/framework/innerkitsimpl/test/unittest/udmf_client_test.cpp create mode 100644 udmf/framework/jskitsimpl/common/napi_data_utils.cpp create mode 100644 udmf/framework/jskitsimpl/common/napi_error_utils.cpp create mode 100644 udmf/framework/jskitsimpl/common/napi_queue.cpp create mode 100644 udmf/framework/jskitsimpl/data/application_defined_record_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/audio_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/file_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/folder_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/html_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/image_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/link_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/plain_text_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/summary_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/system_defined_appitem_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/system_defined_form_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/system_defined_pixelmap_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/system_defined_record_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/text_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/udmf_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/unified_data_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/unified_record_napi.cpp create mode 100644 udmf/framework/jskitsimpl/data/video_napi.cpp create mode 100644 udmf/framework/jskitsimpl/unittest/BUILD.gn create mode 100644 udmf/framework/jskitsimpl/unittest/UdmfCallbackJsTest.js create mode 100644 udmf/framework/jskitsimpl/unittest/UdmfJsTest.js create mode 100644 udmf/framework/jskitsimpl/unittest/UdmfPromiseJsTest.js create mode 100644 udmf/framework/jskitsimpl/unittest/config.json create mode 100644 udmf/framework/service/distributeddata_udmf_ipc_interface_code.h create mode 100644 udmf/framework/service/udmf_service.h create mode 100644 udmf/framework/service/udmf_service_client.cpp create mode 100644 udmf/framework/service/udmf_service_client.h create mode 100644 udmf/framework/service/udmf_service_proxy.cpp create mode 100644 udmf/framework/service/udmf_service_proxy.h create mode 100644 udmf/interfaces/innerkits/BUILD.gn create mode 100644 udmf/interfaces/innerkits/client/udmf_client.h create mode 100644 udmf/interfaces/innerkits/common/error_code.h create mode 100644 udmf/interfaces/innerkits/common/unified_key.h create mode 100644 udmf/interfaces/innerkits/common/unified_meta.h create mode 100644 udmf/interfaces/innerkits/common/unified_types.h create mode 100644 udmf/interfaces/innerkits/common/visibility.h create mode 100644 udmf/interfaces/innerkits/data/application_defined_record.h create mode 100644 udmf/interfaces/innerkits/data/audio.h create mode 100644 udmf/interfaces/innerkits/data/file.h create mode 100644 udmf/interfaces/innerkits/data/folder.h create mode 100644 udmf/interfaces/innerkits/data/html.h create mode 100644 udmf/interfaces/innerkits/data/image.h create mode 100644 udmf/interfaces/innerkits/data/link.h create mode 100644 udmf/interfaces/innerkits/data/plain_text.h create mode 100644 udmf/interfaces/innerkits/data/system_defined_appitem.h create mode 100644 udmf/interfaces/innerkits/data/system_defined_form.h create mode 100644 udmf/interfaces/innerkits/data/system_defined_pixelmap.h create mode 100644 udmf/interfaces/innerkits/data/system_defined_record.h create mode 100644 udmf/interfaces/innerkits/data/text.h create mode 100644 udmf/interfaces/innerkits/data/unified_data.h create mode 100644 udmf/interfaces/innerkits/data/unified_record.h create mode 100644 udmf/interfaces/innerkits/data/video.h create mode 100644 udmf/interfaces/jskits/BUILD.gn create mode 100644 udmf/interfaces/jskits/common/napi_data_utils.h create mode 100644 udmf/interfaces/jskits/common/napi_error_utils.h create mode 100644 udmf/interfaces/jskits/common/napi_queue.h create mode 100644 udmf/interfaces/jskits/data/application_defined_record_napi.h create mode 100644 udmf/interfaces/jskits/data/audio_napi.h create mode 100644 udmf/interfaces/jskits/data/file_napi.h create mode 100644 udmf/interfaces/jskits/data/folder_napi.h create mode 100644 udmf/interfaces/jskits/data/html_napi.h create mode 100644 udmf/interfaces/jskits/data/image_napi.h create mode 100644 udmf/interfaces/jskits/data/link_napi.h create mode 100644 udmf/interfaces/jskits/data/plain_text_napi.h create mode 100644 udmf/interfaces/jskits/data/summary_napi.h create mode 100644 udmf/interfaces/jskits/data/system_defined_appitem_napi.h create mode 100644 udmf/interfaces/jskits/data/system_defined_form_napi.h create mode 100644 udmf/interfaces/jskits/data/system_defined_pixelmap_napi.h create mode 100644 udmf/interfaces/jskits/data/system_defined_record_napi.h create mode 100644 udmf/interfaces/jskits/data/text_napi.h create mode 100644 udmf/interfaces/jskits/data/udmf_napi.h create mode 100644 udmf/interfaces/jskits/data/unified_data_napi.h create mode 100644 udmf/interfaces/jskits/data/unified_record_napi.h create mode 100644 udmf/interfaces/jskits/data/video_napi.h create mode 100644 udmf/interfaces/jskits/module/udmf_napi_module.cpp create mode 100644 udmf/udmf.gni diff --git a/udmf/BUILD.gn b/udmf/BUILD.gn new file mode 100644 index 00000000..8cc737b8 --- /dev/null +++ b/udmf/BUILD.gn @@ -0,0 +1,39 @@ +# Copyright (c) 2022-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +group("udmf_packages") { + if (is_standard_system) { + deps = [ + "interfaces/innerkits:udmf_client", + "interfaces/jskits:udmf_data_napi", + "interfaces/jskits:udmf_napi", + ] + } +} + +group("unittest") { + testonly = true + + deps = [ + "framework/innerkitsimpl/test/unittest:unittest", + "framework/jskitsimpl/unittest:unittest", + ] +} + +group("fuzztest") { + testonly = true + + deps = [ "framework/innerkitsimpl/test/fuzztest:fuzztest" ] +} diff --git a/udmf/CMakeLists.txt b/udmf/CMakeLists.txt new file mode 100644 index 00000000..416e22bb --- /dev/null +++ b/udmf/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 3.10.2) +project(udmf) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -fno-rtti -fvisibility=default -D_GNU_SOURCE") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -fPIC -fpic -ffunction-sections -D_GLIBC_MOCK") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--no-as-needed -ldl") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=0") + +set(MOCK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../mock) +set(KV_STORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../kv_store) +add_definitions(-DNAPI_EXPERIMENTAL) + +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/common udmf_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/client udmf_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/common udmf_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/data udmf_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/jskitsimpl/common udmf_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/jskitsimpl/data udmf_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/service udmf_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/jskits/module udmf_src) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/framework/common) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/framework/service) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/innerkits/client) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/innerkits/common) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/innerkits/data) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/jskits/common) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/jskits/data) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../kv_store/common) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../kv_store/innerkitsimpl/distributeddatafwk/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../kv_store/innerkitsimpl/distributeddatafwk/src) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../kv_store/innerkits/distributeddata/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../utils_native/base/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../utils_native/safwk/native/include) + +include(${MOCK_DIR}/include/CMakeLists.txt OPTIONAL) +include(${KV_STORE_DIR}/interfaces/CMakeLists.txt OPTIONAL) + +set(links secure mock distributeddb kvdb) +add_library(udmf SHARED ${udmf_src}) +target_link_libraries(udmf ${links}) \ No newline at end of file diff --git a/udmf/CODEOWNERS b/udmf/CODEOWNERS new file mode 100644 index 00000000..df88964e --- /dev/null +++ b/udmf/CODEOWNERS @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# any change to framework/service/distributeddata_udmf_ipc_interface_code.h needs to be reviewed by @leonchan5 +framework/service/distributeddata_udmf_ipc_interface_code.h @leonchan5 \ No newline at end of file diff --git a/udmf/LICENSE b/udmf/LICENSE new file mode 100644 index 00000000..4947287f --- /dev/null +++ b/udmf/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/udmf/OAT.xml b/udmf/OAT.xml new file mode 100644 index 00000000..118a8533 --- /dev/null +++ b/udmf/OAT.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + diff --git a/udmf/README_zh.md b/udmf/README_zh.md new file mode 100644 index 00000000..4b8036d8 --- /dev/null +++ b/udmf/README_zh.md @@ -0,0 +1,106 @@ +# 统一数据管理框架 + +## 简介 +从数据管理角度出发,随着OpenHarmony中数据跨应用、跨设备流转场景和需求的不断增加,流转过程中会存在数据协同通道繁杂、数据协同标准不一致、数据协同安全策略不一致、应用适配复杂度高、开发工作量增多等诸多痛点问题。统一数据管理框架(Unified Data Management Framework, UDMF)旨在定义数据跨应用、跨设备以及跨平台过程中的各项标准,提供统一的OpenHarmony数据语言和标准化的数据接入与读取通路。 + +## 架构介绍 +UDMF提供统一的OpenHarmony数据语言和标准化的数据接入与读取通路。 + +**统一的OpenHarmony数据语言:** 构建OpenHarmony数据跨应用、跨设备交互的标准定义,降低应用/业务数据交互成本,促进数据生态建设。 + +**标准化的数据接入与读取通路:** 提供安全、标准化的数据通路,降低业务跨应用、跨设备数据交互的成本。 + +UDMF的整体架构如图1所示,业务层对外提供标准化的数据定义和数据接入与读取的业务接口。统一数据管理框架层提供标准化数据定义和数据接入与读取的具体实现,同时负责管理数据的生命周期、安全性、权限和存储。存储模块层负责数据的具体保存,可以使用分布式KVDB、分布式数据对象和分布式RDB进行数据存储。 + +**图1** UDMF架构图 + +![架构图](figures/udmf_architecture.png) + +### 标准化数据定义 + +UDMF提供了标准化的数据定义,统一定义了以下几种不同的数据类型。 + +**基础数据类型:** File、Text等,能够进行跨应用、跨设备以及跨平台流转。File、Text数据类型可见图2和图3,它们具有继承关系和层次结构,衍生出多种具体子类。 + +**图2** UDMF File数据类型示意图 + +![架构图](figures/udmf_type_File.png) + +**图3** UDMF Text数据类型示意图 + +![架构图](figures/udmf_type_Text.png) + +**系统相关数据类型(System Defined Type, SDT):** 与具体的平台/操作系统绑定,如Form(UI卡片信息)、AppItem(App描述信息)、PixelMap(缩略图格式)等,该类数据可以实现系统/平台内的跨应用、跨设备流转,如图4所示。 + +**图4** UDMF SDT数据类型示意图 + +![架构图](figures/udmf_type_SDT.png) + +**应用自定义数据类型(App Defined Type, ADT):** 单个应用自定义的数据,该类数据可以实现应用内的跨平台与跨设备流转,如图5所示为例,应用可自定义MyFile类型文件格式在应用生态内部使用。 + +**图5** UDMF ADT数据类型示意图 + +![架构图](figures/udmf_type_ADT.png) + +### 标准化数据通路 + +UDMF定义了标准化的数据接入与读取通路,为各种业务场景(如跨应用跨设备数据拖拽)提供了跨应用、跨设备的数据接入与读取通路,通路中的数据URI定义为udmf://intension/bundleName/groupName/guid,其中各组成部分的含义分别为: +**udmf:** 协议名,表示使用UDMF提供的数据通路。 +**intension:** 通道分类,对应不同的业务场景(如数据拖拽)。 +**bundleName:** 数据来源应用的包名称。 +**groupName:** 分组名称,支持批量数据分组管理。 +**guid:** 系统生成的数据id,全局唯一。 + +## 约束限制 + +- UDMF中每条数据记录大小不超过2MB。 +- UDMF支持批量数据记录的分组管理,每个分组整体大小不超过4MB。 + +## 目录 + +UDMF代码仓的目录结构和对应目录的功能描述如下: + +```undefined +foundation/distributeddatamgr/udmf # udmf统一数据管理部件 +├── frameworks # udmf的核心逻辑 +│ ├── common # 公共工具 +│ ├── innerkitsimpl # nativie接口具体实现 +│ │ ├── client # native客户端 +│ │ ├── common # native接口公共工具类 +│ │ ├── data # 数据结构定义 +│ │ └── test # 测试目录 +│ ├── jskitsimpl # js接口具体实现 +│ │ ├── common # js接口公共工具类 +│ │ |── data # 统一数据公共接口实现 +| | └── unittest # js单元测试目录 +│ ├── manager # 数据管理核心类 +| | ├── lifecycle # 生命周期管理 +| | ├── permission # 权限管理 +│ │ ├── preprocess # 预处理 +│ │ └── store # 存储策略 +│ └── service # 服务模块 +├── interfaces # udmf对外接口声明 +│ ├── innerkits # nativie接口声明 +│ │ ├── client # client接口声明 +│ │ ├── common # 公共工具类声明 +│ │ └── data # 数据结构声明 +│ └── jskits # napi接口声明 +│ ├── common # napi工具类声明 +│ ├── data # napi数据封装声明 +│ └── module # 统一数据模块注册 +├── service # udmf服务框架代码 +│ ├── include # 服务端声明 +│ ├── src # 服务端具体实现 +| └── test # 测试目录 +├── BUILD.gn # 编译配置文件 +├── bundle.json # 模块配置文件 +├── LICENSE # License文件 +├── OAT.xml # OAT扫描策略 +├── README_zh.md # Readme中文介绍 +└── udmf.gni # 编译配置头文件 +``` +## 相关仓 + +- [分布式数据管理子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E5%88%86%E5%B8%83%E5%BC%8F%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86%E5%AD%90%E7%B3%BB%E7%BB%9F.md) + +- [**distributeddatamgr\_kv_store**](https://gitee.com/openharmony/distributeddatamgr_kv_store/blob/master/README_zh.md) \ No newline at end of file diff --git a/udmf/bundle.json b/udmf/bundle.json new file mode 100644 index 00000000..6e27f3c8 --- /dev/null +++ b/udmf/bundle.json @@ -0,0 +1,121 @@ +{ + "name": "@ohos/udmf", + "description": "Provide unified data management service for 3rd party app", + "version": "4.0", + "license": "Apache License 2.0", + "publishAs": "code-segment", + "segment": { + "destPath": "foundation/distributeddatamgr/udmf" + }, + "dirs": {}, + "scripts": {}, + "component": { + "name": "udmf", + "subsystem": "distributeddatamgr", + "syscap": [ + "SystemCapability.DistributedDataManager.UDMF.Core" + ], + "features": [ + ], + "adapted_system_type": [ + "standard" + ], + "rom": "1000KB", + "ram": "636KB", + "deps": { + "components": [ + "ability_base", + "ability_runtime", + "access_token", + "bundle_framework", + "c_utils", + "hilog", + "hitrace", + "ipc", + "kv_store", + "napi", + "samgr" + ], + "third_party": [ + "bounds_checking_function", + "googletest" + ] + }, + "build": { + "sub_component": [ + "//foundation/distributeddatamgr/udmf:udmf_packages" + ], + "inner_kits": [ + { + "name": "//foundation/distributeddatamgr/udmf/interfaces/innerkits:udmf_client", + "header": { + "header_files": [ + "udmf_client.h" + ], + "header_base":"//foundation/distributeddatamgr/udmf/interfaces/innerkits/client" + } + }, + { + "name": "//foundation/distributeddatamgr/udmf/interfaces/innerkits:udmf_client", + "header": { + "header_files": [ + "error_code.h", + "unified_key.h", + "unified_meta.h", + "unified_types.h", + "visibility.h" + ], + "header_base":"//foundation/distributeddatamgr/udmf/interfaces/innerkits/common" + } + }, + { + "name": "//foundation/distributeddatamgr/udmf/interfaces/innerkits:udmf_client", + "header": { + "header_files": [ + "application_defined_record.h", + "audio.h", + "file.h", + "folder.h", + "html.h", + "image.h", + "link.h", + "plain_text.h", + "system_defined_appitem.h", + "system_defined_form.h", + "system_defined_pixelmap.h", + "system_defined_record.h", + "text.h", + "unified_data.h", + "unified_record.h", + "video.h" + ], + "header_base":"//foundation/distributeddatamgr/udmf/interfaces/innerkits/data" + } + }, + { + "name": "//foundation/distributeddatamgr/udmf/interfaces/jskits:udmf_data_napi", + "header": { + "header_files": [ + "unified_data_napi.h", + "summary_napi.h" + ], + "header_base":"//foundation/distributeddatamgr/udmf/interfaces/jskits/data" + } + }, + { + "name": "//foundation/distributeddatamgr/udmf/interfaces/jskits:udmf_data_napi", + "header": { + "header_files": [ + "napi_queue.h" + ], + "header_base":"//foundation/distributeddatamgr/udmf/interfaces/jskits/common" + } + } + ], + "test": [ + "//foundation/distributeddatamgr/udmf:unittest", + "//foundation/distributeddatamgr/udmf:fuzztest" + ] + } + } +} diff --git a/udmf/figures/udmf_architecture.png b/udmf/figures/udmf_architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..78281a43dc5debb18f4fec9aee9b1f6816fca429 GIT binary patch literal 53496 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%0AdAE9vU;MPjf5}JeaZgPjw^6I~<2(I+H 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 z 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 F_!sxKS4IE; literal 0 HcmV?d00001 diff --git a/udmf/figures/udmf_type_File.png b/udmf/figures/udmf_type_File.png new file mode 100644 index 0000000000000000000000000000000000000000..80bbec073de7e4e75da239a8a073453545260cc1 GIT binary patch literal 19605 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 w>`>18&%m? +#include + +namespace OHOS { +namespace UDMF { +static inline int8_t HostToNet(int8_t value) +{ + return value; +} +static inline int16_t HostToNet(int16_t value) +{ + return htole16(value); +} + +static inline int16_t NetToHost(int16_t value) +{ + return le16toh(value); +} + +static inline int32_t HostToNet(int32_t value) +{ + return htole32(value); +} + +static inline int8_t NetToHost(int8_t value) +{ + return le32toh(value); +} + +static inline int32_t NetToHost(int32_t value) +{ + return le32toh(value); +} + +static inline int64_t HostToNet(int64_t value) +{ + return htole64(value); +} + +static inline int64_t NetToHost(int64_t value) +{ + return le64toh(value); +} + +static inline uint8_t HostToNet(uint8_t value) +{ + return value; +} +static inline uint16_t HostToNet(uint16_t value) +{ + return htole16(value); +} + +static inline uint16_t NetToHost(uint16_t value) +{ + return le16toh(value); +} + +static inline uint32_t HostToNet(uint32_t value) +{ + return htole32(value); +} + +static inline uint8_t NetToHost(uint8_t value) +{ + return le32toh(value); +} + +static inline uint32_t NetToHost(uint32_t value) +{ + return le32toh(value); +} + +static inline uint64_t HostToNet(uint64_t value) +{ + return htole64(value); +} + +static inline uint64_t NetToHost(uint64_t value) +{ + return le64toh(value); +} + +static inline float HostToNet(float value) +{ + return htole32(*reinterpret_cast(&value)); +} + +static inline float NetToHost(float value) +{ + return le32toh(*reinterpret_cast(&value)); +} + +static inline double HostToNet(double value) +{ + return htole64(*reinterpret_cast(&value)); +} + +static inline double NetToHost(double value) +{ + return le64toh(*reinterpret_cast(&value)); +} +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_ENDIAN_CONVERTER_H diff --git a/udmf/framework/common/logger.h b/udmf/framework/common/logger.h new file mode 100644 index 00000000..370b3834 --- /dev/null +++ b/udmf/framework/common/logger.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_LOGGER_H +#define UDMF_LOGGER_H +#include + +#include "hilog/log.h" + +namespace OHOS { +namespace UDMF { +// param of log interface, such as UDMF_LABEL. +enum UdmfSubModule { + UDMF_FRAMEWORK = 0, // for framework core module + UDMF_KITS_INNER, // for udmf innerkits module + UDMF_KITS_NAPI, // for udmf napi kits module + UDMF_CLIENT, // for udmf client module + UDMF_SERVICE, // for udmf service module + UDMF_TEST, // for udmf test module +}; + +// 0xD001600: subsystem:distributeddatamgr module:udmf, 8 bits reserved. +static inline OHOS::HiviewDFX::HiLogLabel LogLabel() +{ + return { LOG_CORE, 0xD001656, "UDMF" }; +} + +// In order to improve performance, do not check the module range. +// Besides, make sure module is less than UDMF_SERVICE. +#define LOG_FATAL(module, fmt, ...) \ + do { \ + using HiLog = OHOS::HiviewDFX::HiLog; \ + auto lable = LogLabel(); \ + if (!HiLogIsLoggable(lable.domain, lable.tag, LogLevel::LOG_FATAL)) { \ + break; \ + } \ + HiLog::Fatal(lable, "%{public}d: %{public}s " fmt " ", __LINE__, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + +#define LOG_ERROR(module, fmt, ...) \ + do { \ + using HiLog = OHOS::HiviewDFX::HiLog; \ + auto lable = LogLabel(); \ + if (!HiLogIsLoggable(lable.domain, lable.tag, LogLevel::LOG_ERROR)) { \ + break; \ + } \ + HiLog::Error(lable, "%{public}d: %{public}s " fmt " ", __LINE__, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + +#define LOG_WARN(module, fmt, ...) \ + do { \ + using HiLog = OHOS::HiviewDFX::HiLog; \ + auto lable = LogLabel(); \ + if (!HiLogIsLoggable(lable.domain, lable.tag, LogLevel::LOG_WARN)) { \ + break; \ + } \ + HiLog::Warn(lable, "%{public}d: %{public}s " fmt " ", __LINE__, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + +#define LOG_INFO(module, fmt, ...) \ + do { \ + using HiLog = OHOS::HiviewDFX::HiLog; \ + auto lable = LogLabel(); \ + if (!HiLogIsLoggable(lable.domain, lable.tag, LogLevel::LOG_INFO)) { \ + break; \ + } \ + HiLog::Info(lable, "%{public}d: %{public}s " fmt " ", __LINE__, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + +#define LOG_DEBUG(module, fmt, ...) \ + do { \ + using HiLog = OHOS::HiviewDFX::HiLog; \ + auto lable = LogLabel(); \ + if (!HiLogIsLoggable(lable.domain, lable.tag, LogLevel::LOG_DEBUG)) { \ + break; \ + } \ + HiLog::Debug(lable, "%{public}d: %{public}s " fmt " ", __LINE__, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_LOGGER_H diff --git a/udmf/framework/common/tlv_object.h b/udmf/framework/common/tlv_object.h new file mode 100644 index 00000000..cca092be --- /dev/null +++ b/udmf/framework/common/tlv_object.h @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_TLV_OBJECT_H +#define UDMF_TLV_OBJECT_H + +#include "securec.h" +#include "error_code.h" +#include "unified_meta.h" +#include "unified_types.h" +#include "endian_converter.h" + +namespace OHOS { +namespace UDMF { +enum TAG : uint16_t { + TAG_INT32 = 0x0000, + TAG_INT64, + TAG_UINT32, + TAG_UINT64, + TAG_BOOL, + TAG_DOUBLE, + TAG_STRING, + TAG_VECTOR, + TAG_MAP, + TAG_BUTT, +}; + +#pragma pack(1) +struct TLVHead { + uint16_t tag; + uint32_t len; + std::uint8_t value[0]; +}; +#pragma pack() + +class TLVObject { +public: + TLVObject() = default; + ~TLVObject() = default; + explicit TLVObject(std::vector &buffer) + { + total_ += buffer.size(); + buffer_ = &buffer; + cursor_ = 0; + } + + void UpdateSize() + { + buffer_->resize(total_); + } + + std::vector GetBuffer() + { + return *buffer_; + } + + void Count(const uint32_t value) + { + total_ += sizeof(value) + sizeof(TLVHead); + } + + void Count(const uint64_t value) + { + total_ += sizeof(value) + sizeof(TLVHead); + } + + void Count(const int32_t value) + { + total_ += sizeof(value) + sizeof(TLVHead); + } + + void Count(const int64_t value) + { + total_ += sizeof(value) + sizeof(TLVHead); + } + + void Count(const float value) + { + total_ += sizeof(value) + sizeof(TLVHead); + } + + void Count(const double value) + { + total_ += sizeof(value) + sizeof(TLVHead); + } + + void Count(const std::string &value) + { + total_ += value.size() + sizeof(TLVHead); + } + + void Count(const std::vector &value) + { + std::size_t expectSize = sizeof(TLVHead); + expectSize += value.size(); + total_ += expectSize; + } + + void Count(const UDVariant &value) + { + total_ += sizeof(TLVHead); + auto int32Value = std::get_if(&value); + if (int32Value != nullptr) { + Count(std::get(value)); + return; + } + auto int64Value = std::get_if(&value); + if (int64Value != nullptr) { + Count(std::get(value)); + return; + } + auto boolValue = std::get_if(&value); + if (boolValue != nullptr) { + Count(std::get(value)); + return; + } + auto doubleValue = std::get_if(&value); + if (doubleValue != nullptr) { + Count(std::get(value)); + return; + } + auto strValue = std::get_if(&value); + if (strValue != nullptr) { + Count(std::get(value)); + return; + } + auto vecValue = std::get_if>(&value); + if (vecValue != nullptr) { + Count(std::get>(value)); + return; + } + total_ += sizeof(TLVHead); + } + + void Count(const UDDetails &value) + { + for (auto &item : value) { + Count(item.first); + Count(item.second); + } + total_ += sizeof(TLVHead); + } + + void Count(const UnifiedKey &value) + { + Count(value.key); + Count(value.intention); + Count(value.bundleName); + Count(value.groupId); + } + + void Count(const Privilege &value) + { + Count(value.tokenId); + Count(value.readPermission); + Count(value.writePermission); + } + + template + bool WriteBasic(uint16_t type, const T &value) + { + if (!HasExpectBuffer(sizeof(TLVHead) + sizeof(value))) { + return false; + } + auto *tlvHead = reinterpret_cast(buffer_->data() + cursor_); + tlvHead->tag = HostToNet(type); + tlvHead->len = HostToNet((uint32_t)sizeof(value)); + auto valueBuff = HostToNet(value); + auto ret = memcpy_s(tlvHead->value, sizeof(value), &valueBuff, sizeof(value)); + if (ret != EOK) { + return false; + } + cursor_ += sizeof(TLVHead) + sizeof(value); + return true; + } + + template + bool ReadBasic(T &value) + { + TLVHead head {}; + if (!ReadHead(head)) { + return false; + } + if (head.len == 0) { + return false; + } + if (!HasExpectBuffer(head.len)) { + return false; + } + auto ret = memcpy_s(&value, sizeof(T), buffer_->data() + cursor_, sizeof(T)); + if (ret != EOK) { + return false; + } + value = NetToHost(value); + cursor_ += sizeof(T); + return true; + } + + bool WriteString(const std::string &value) + { + if (!HasExpectBuffer(sizeof(TLVHead) + value.size())) { + return false; + } + auto *tlvHead = reinterpret_cast(buffer_->data() + cursor_); + tlvHead->tag = HostToNet(TAG_STRING); + tlvHead->len = HostToNet((uint32_t)value.size()); + if (!value.empty()) { + auto err = memcpy_s(tlvHead->value, value.size(), value.c_str(), value.size()); + if (err != EOK) { + return false; + } + } + cursor_ += sizeof(TLVHead) + value.size(); + return true; + } + + bool ReadString(std::string &value) + { + TLVHead head {}; + if (!ReadHead(head)) { + return false; + } + if (!HasExpectBuffer(head.len)) { + return false; + } + value.append(reinterpret_cast(buffer_->data() + cursor_), head.len); + cursor_ += head.len; + return true; + } + + bool WriteVector(const std::vector &value) + { + if (!HasExpectBuffer(sizeof(TLVHead) + value.size())) { + return false; + } + WriteHead(TAG_VECTOR, cursor_, value.size()); + cursor_ += sizeof(TLVHead); + + if (!value.empty()) { + auto err = memcpy_s(buffer_->data() + cursor_, buffer_->size() - cursor_, value.data(), value.size()); + if (err != EOK) { + return false; + } + } + cursor_ += value.size(); + return true; + } + + bool ReadVector(std::vector &value) + { + TLVHead head {}; + if (!ReadHead(head)) { + return false; + } + if (!HasExpectBuffer(head.len)) { + return false; + } + std::vector buff(buffer_->data() + cursor_, buffer_->data() + cursor_ + head.len); + value = std::move(buff); + cursor_ += head.len; + return true; + } + + bool WriteVariant(const UDVariant &value) + { + if (!HasExpectBuffer(sizeof(TLVHead))) { + return false; + } + auto tagCursor = cursor_; + cursor_ += sizeof(TLVHead); + auto valueCursor = cursor_; + TAG tag = TAG::TAG_BUTT; + auto int32Value = std::get_if(&value); + if (int32Value != nullptr) { + if (!WriteBasic(TAG_INT32, std::get(value))) { + return false; + } + tag = TAG::TAG_INT32; + } + auto int64Value = std::get_if(&value); + if (int64Value != nullptr) { + if (!WriteBasic(TAG_INT64, std::get(value))) { + return false; + } + tag = TAG::TAG_INT64; + } + auto boolValue = std::get_if(&value); + if (boolValue != nullptr) { + if (!WriteBasic(TAG_BOOL, std::get(value))) { + return false; + } + tag = TAG::TAG_BOOL; + } + auto doubleValue = std::get_if(&value); + if (doubleValue != nullptr) { + if (!WriteBasic(TAG_DOUBLE, std::get(value))) { + return false; + } + tag = TAG::TAG_DOUBLE; + } + auto stringValue = std::get_if(&value); + if (stringValue != nullptr) { + if (!WriteString(std::get(value))) { + return false; + } + tag = TAG::TAG_STRING; + } + auto vectorValue = std::get_if>(&value); + if (vectorValue != nullptr) { + if (!WriteVector(std::get>(value))) { + return false; + } + tag = TAG::TAG_VECTOR; + } + WriteHead(tag, tagCursor, cursor_ - valueCursor); + return true; + } + + bool ReadVariant(UDVariant &value) + { + TLVHead head {}; + if (!ReadHead(head)) { + return false; + } + if (!HasExpectBuffer(head.len)) { + return false; + } + switch (head.tag) { + case static_cast(TAG::TAG_INT32): { + int32_t int32Value; + if (!ReadBasic(int32Value)) { + return false; + } + value.emplace(int32Value); + break; + } + case static_cast(TAG::TAG_INT64): { + int64_t int64Value; + if (!ReadBasic(int64Value)) { + return false; + } + value.emplace(int64Value); + break; + } + case static_cast(TAG::TAG_BOOL): { + bool boolValue; + if (!ReadBasic(boolValue)) { + return false; + } + value.emplace(boolValue); + break; + } + case static_cast(TAG::TAG_DOUBLE): { + double doubleValue; + if (!ReadBasic(doubleValue)) { + return false; + } + value.emplace(doubleValue); + break; + } + case static_cast(TAG::TAG_STRING): { + std::string stringValue; + if (!ReadString(stringValue)) { + return false; + } + value.emplace(stringValue); + break; + } + case static_cast(TAG::TAG_VECTOR): { + std::vector vectorValue; + if (!ReadVector(vectorValue)) { + return false; + } + value.emplace>(vectorValue); + break; + } + default: { + return false; + } + } + return true; + } + + bool WriteMap(const UDDetails &value) + { + if (!HasExpectBuffer(sizeof(TLVHead))) { + return false; + } + + auto tagCursor = cursor_; + cursor_ += sizeof(TLVHead); + auto valueCursor = cursor_; + + for (const auto &item : value) { + if (!WriteString(item.first)) { + return false; + } + if (!WriteVariant(item.second)) { + return false; + } + } + + WriteHead(TAG_MAP, tagCursor, cursor_ - valueCursor); + return true; + } + + bool ReadMap(UDDetails &value) + { + TLVHead head {}; + if (!ReadHead(head)) { + return false; + } + if (!HasExpectBuffer(head.len)) { + return false; + } + auto mapEnd = cursor_ + head.len; + while (cursor_ < mapEnd) { + std::string itemKey; + if (!ReadString(itemKey)) { + return false; + } + UDVariant itemValue; + if (!ReadVariant(itemValue)) { + return false; + } + value.emplace(itemKey, itemValue); + } + return true; + } + +private: + inline bool ReadHead(TLVHead &head) + { + if (!HasExpectBuffer(sizeof(TLVHead))) { + return false; + } + const auto *pHead = reinterpret_cast(buffer_->data() + cursor_); + if (!HasExpectBuffer(NetToHost(pHead->len)) && + !HasExpectBuffer(NetToHost(pHead->len) + sizeof(TLVHead))) { + return false; + } + head.tag = NetToHost(pHead->tag); + head.len = NetToHost(pHead->len); + cursor_ += sizeof(TLVHead); + return true; + } + + inline void WriteHead(uint16_t type, size_t tagCursor, uint32_t len) + { + auto *tlvHead = reinterpret_cast(buffer_->data() + tagCursor); + tlvHead->tag = HostToNet(type); + tlvHead->len = HostToNet(len); + } + + inline bool HasExpectBuffer(const uint32_t expectLen) const + { + return buffer_->size() >= cursor_ && buffer_->size() - cursor_ >= expectLen; + } + + std::size_t total_ = 0; + std::size_t cursor_ = 0; + std::vector *buffer_; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_TLV_OBJECT_H \ No newline at end of file diff --git a/udmf/framework/common/tlv_util.cpp b/udmf/framework/common/tlv_util.cpp new file mode 100644 index 00000000..235d1417 --- /dev/null +++ b/udmf/framework/common/tlv_util.cpp @@ -0,0 +1,1463 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "tlv_util.h" + +namespace OHOS { +namespace TLVUtil { +template<> +bool CountBufferSize(const std::shared_ptr &input, TLVObject &data) +{ + data.Count(input->GetType()); + data.Count(input->GetUid()); + auto type = input->GetType(); + switch (type) { + case UDType::TEXT: { + auto text = static_cast(input.get()); + if (text == nullptr) { + return false; + } + data.Count(text->GetDetails()); + break; + } + case UDType::PLAIN_TEXT: { + auto plainText = static_cast

(input.get()); + if (plainText == nullptr) { + return false; + } + data.Count(plainText->GetContent()); + data.Count(plainText->GetAbstract()); + auto text = static_cast<Text *>(input.get()); + if (text == nullptr) { + return false; + } + data.Count(text->GetDetails()); + break; + } + case UDType::HTML: { + auto html = static_cast<Html *>(input.get()); + if (html == nullptr) { + return false; + } + data.Count(html->GetHtmlContent()); + data.Count(html->GetPlainContent()); + auto text = static_cast<Text *>(input.get()); + if (text == nullptr) { + return false; + } + data.Count(text->GetDetails()); + break; + } + case UDType::HYPERLINK: { + auto link = static_cast<Link *>(input.get()); + if (link == nullptr) { + return false; + } + data.Count(link->GetUrl()); + data.Count(link->GetDescription()); + auto text = static_cast<Text *>(input.get()); + if (text == nullptr) { + return false; + } + data.Count(text->GetDetails()); + break; + } + case UDType::FILE: { + auto file = static_cast<File *>(input.get()); + if (file == nullptr) { + return false; + } + data.Count(file->GetUri()); + data.Count(file->GetRemoteUri()); + data.Count(file->GetDetails()); + break; + } + case UDType::IMAGE: { + auto image = static_cast<Image *>(input.get()); + if (image == nullptr) { + return false; + } + data.Count(image->GetUri()); + data.Count(image->GetRemoteUri()); + auto file = static_cast<File *>(input.get()); + if (file == nullptr) { + return false; + } + data.Count(file->GetDetails()); + break; + } + case UDType::VIDEO: { + auto video = static_cast<Video *>(input.get()); + if (video == nullptr) { + return false; + } + data.Count(video->GetUri()); + data.Count(video->GetRemoteUri()); + auto file = static_cast<File *>(input.get()); + if (file == nullptr) { + return false; + } + data.Count(file->GetDetails()); + break; + } + case UDType::AUDIO: { + auto audio = static_cast<Audio *>(input.get()); + if (audio == nullptr) { + return false; + } + data.Count(audio->GetUri()); + data.Count(audio->GetRemoteUri()); + auto file = static_cast<File *>(input.get()); + if (file == nullptr) { + return false; + } + data.Count(file->GetDetails()); + break; + } + case UDType::FOLDER: { + auto folder = static_cast<Folder *>(input.get()); + if (folder == nullptr) { + return false; + } + data.Count(folder->GetUri()); + data.Count(folder->GetRemoteUri()); + auto file = static_cast<File *>(input.get()); + if (file == nullptr) { + return false; + } + data.Count(file->GetDetails()); + break; + } + case UDType::SYSTEM_DEFINED_RECORD: { + auto sdRecord = static_cast<SystemDefinedRecord *>(input.get()); + if (sdRecord == nullptr) { + return false; + } + data.Count(sdRecord->GetDetails()); + break; + } + case UDType::SYSTEM_DEFINED_FORM: { + auto form = static_cast<SystemDefinedForm *>(input.get()); + if (form == nullptr) { + return false; + } + data.Count(form->GetFormId()); + data.Count(form->GetFormName()); + data.Count(form->GetBundleName()); + data.Count(form->GetAbilityName()); + data.Count(form->GetModule()); + auto sdRecord = static_cast<SystemDefinedRecord *>(input.get()); + if (sdRecord == nullptr) { + return false; + } + data.Count(sdRecord->GetDetails()); + break; + } + case UDType::SYSTEM_DEFINED_APP_ITEM: { + auto appItem = static_cast<SystemDefinedAppItem *>(input.get()); + if (appItem == nullptr) { + return false; + } + data.Count(appItem->GetAppId()); + data.Count(appItem->GetAppName()); + data.Count(appItem->GetAppIconId()); + data.Count(appItem->GetAppLabelId()); + data.Count(appItem->GetBundleName()); + data.Count(appItem->GetAbilityName()); + auto sdRecord = static_cast<SystemDefinedRecord *>(input.get()); + if (sdRecord == nullptr) { + return false; + } + data.Count(sdRecord->GetDetails()); + break; + } + case UDType::SYSTEM_DEFINED_PIXEL_MAP: { + auto pixelMap = static_cast<SystemDefinedPixelMap *>(input.get()); + if (pixelMap == nullptr) { + return false; + } + data.Count(pixelMap->GetRawData()); + auto sdRecord = static_cast<SystemDefinedRecord *>(input.get()); + if (sdRecord == nullptr) { + return false; + } + data.Count(sdRecord->GetDetails()); + break; + } + case UDType::APPLICATION_DEFINED_RECORD: { + auto record = static_cast<ApplicationDefinedRecord *>(input.get()); + if (record == nullptr) { + return false; + } + data.Count(record->GetApplicationDefinedType()); + data.Count(record->GetRawData()); + break; + } + default: { + return false; + } + } + return true; +} + +template<> +bool CountBufferSize(const Runtime &input, TLVObject &data) +{ + data.Count(input.key); + data.Count(input.isPrivate); + uint32_t size = static_cast<uint32_t>(input.privileges.size()); + data.Count(size); + for (uint32_t i = 0; i < size; ++i) { + data.Count(input.privileges[i]); + } + data.Count(static_cast<int64_t>(input.createTime)); + data.Count(static_cast<int64_t>(input.lastModifiedTime)); + data.Count(input.sourcePackage); + data.Count(static_cast<int32_t>(input.dataStatus)); + data.Count(input.dataVersion); + data.Count(input.createPackage); + data.Count(input.deviceId); + return true; +} + +template<> +bool CountBufferSize(const UnifiedData &input, TLVObject &data) +{ + int32_t size = input.GetRecords().size(); + data.Count(size); + for (auto record : input.GetRecords()) { + if (!CountBufferSize(record, data)) { + return false; + } + } + return true; +} + +template<> +bool CountBufferSize(const std::vector<UnifiedData> &input, TLVObject &data) +{ + int32_t size = input.size(); + data.Count(size); + for (auto unifiedData : input) { + if (!CountBufferSize(unifiedData, data)) { + return false; + } + } + return true; +} + +template<typename T> +bool Writing(const T &input, TLVObject &data); + +template<typename T> +bool Reading(T &output, TLVObject &data); + +template<> +bool Writing(const int32_t &input, TLVObject &data) +{ + return data.WriteBasic(TAG_INT32, input); +} + +template<> +bool Reading(int32_t &output, TLVObject &data) +{ + return data.ReadBasic(output); +} + +template<> +bool Writing(const int64_t &input, TLVObject &data) +{ + return data.WriteBasic(TAG_INT64, input); +} + +template<> +bool Reading(int64_t &output, TLVObject &data) +{ + return data.ReadBasic(output); +} + +template<> +bool Reading(uint32_t &output, TLVObject &data) +{ + return data.ReadBasic(output); +} + +template<> +bool Writing(const uint32_t &input, TLVObject &data) +{ + return data.WriteBasic(TAG_UINT32, input); +} + +template<> +bool Reading(uint64_t &output, TLVObject &data) +{ + return data.ReadBasic(output); +} + +template<> +bool Writing(const uint64_t &input, TLVObject &data) +{ + return data.WriteBasic(TAG_UINT64, input); +} + +template<> +bool Writing(const bool &input, TLVObject &data) +{ + return data.WriteBasic(TAG_BOOL, input); +} + +template<> +bool Reading(bool &output, TLVObject &data) +{ + return data.ReadBasic(output); +} + +template<> +bool Writing(const std::string &input, TLVObject &data) +{ + return data.WriteString(input); +} + +template<> +bool Reading(std::string &output, TLVObject &data) +{ + return data.ReadString(output); +} + +template<> +bool Writing(const std::vector<uint8_t> &input, TLVObject &data) +{ + return data.WriteVector(input); +} + +template<> +bool Reading(std::vector<uint8_t> &output, TLVObject &data) +{ + return data.ReadVector(output); +} + +template<> +bool Writing(const UDVariant &input, TLVObject &data) +{ + return data.WriteVariant(input); +} + +template<> +bool Reading(UDVariant &output, TLVObject &data) +{ + return data.ReadVariant(output); +} + +template<> +bool Writing(const UDDetails &input, TLVObject &data) +{ + return data.WriteMap(input); +} + +template<> +bool Reading(UDDetails &output, TLVObject &data) +{ + return data.ReadMap(output); +} + +template<> +bool Writing(const UDType &input, TLVObject &data) +{ + int32_t type = input; + return Writing(type, data); +} + +template<> +bool Reading(UDType &output, TLVObject &data) +{ + int32_t type; + if (!Reading(type, data)) { + return false; + } + if (type < UDType::TEXT || type >= UDType::UD_BUTT) { + return false; + } + output = static_cast<UDType>(type); + return true; +} + +template<> +bool Writing(const Text &input, TLVObject &data) +{ + return Writing(input.GetDetails(), data); +} + +template<> +bool Reading(Text &output, TLVObject &data) +{ + UDDetails details; + if (!Reading(details, data)) { + return false; + } + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const PlainText &input, TLVObject &data) +{ + if (!Writing(input.GetContent(), data)) { + return false; + } + if (!Writing(input.GetAbstract(), data)) { + return false; + } + return true; +} + +template<> +bool Reading(PlainText &output, TLVObject &data) +{ + std::string content; + std::string abstract; + UDDetails details; + if (!Reading(content, data)) { + return false; + } + if (!Reading(abstract, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetContent(content); + output.SetAbstract(abstract); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const Html &input, TLVObject &data) +{ + if (!Writing(input.GetHtmlContent(), data)) { + return false; + } + if (!Writing(input.GetPlainContent(), data)) { + return false; + } + return true; +} + +template<> +bool Reading(Html &output, TLVObject &data) +{ + std::string htmlContent; + std::string plainContent; + UDDetails details; + if (!Reading(htmlContent, data)) { + return false; + } + if (!Reading(plainContent, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetHtmlContent(htmlContent); + output.SetPlainContent(plainContent); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const Link &input, TLVObject &data) +{ + if (!Writing(input.GetUrl(), data)) { + return false; + } + if (!Writing(input.GetDescription(), data)) { + return false; + } + return true; +} + +template<> +bool Reading(Link &output, TLVObject &data) +{ + std::string url; + std::string description; + UDDetails details; + if (!Reading(url, data)) { + return false; + } + if (!Reading(description, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetUrl(url); + output.SetDescription(description); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const File &input, TLVObject &data) +{ + if (!Writing(input.GetUri(), data)) { + return false; + } + if (!Writing(input.GetRemoteUri(), data)) { + return false; + } + if (!Writing(input.GetDetails(), data)) { + return false; + } + return true; +} + +template<> +bool Reading(File &output, TLVObject &data) +{ + std::string uri; + std::string remoteUri; + UDDetails details; + if (!Reading(uri, data)) { + return false; + } + if (!Reading(remoteUri, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetUri(uri); + output.SetRemoteUri(remoteUri); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const Image &input, TLVObject &data) +{ + return true; +} + +template<> +bool Reading(Image &output, TLVObject &data) +{ + std::string uri; + std::string remoteUri; + UDDetails details; + if (!Reading(uri, data)) { + return false; + } + if (!Reading(remoteUri, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetUri(uri); + output.SetRemoteUri(remoteUri); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const Video &input, TLVObject &data) +{ + return true; +} + +template<> +bool Reading(Video &output, TLVObject &data) +{ + std::string uri; + std::string remoteUri; + UDDetails details; + if (!Reading(uri, data)) { + return false; + } + if (!Reading(remoteUri, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetUri(uri); + output.SetRemoteUri(remoteUri); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const Audio &input, TLVObject &data) +{ + return true; +} + +template<> +bool Reading(Audio &output, TLVObject &data) +{ + std::string uri; + std::string remoteUri; + UDDetails details; + if (!Reading(uri, data)) { + return false; + } + if (!Reading(remoteUri, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetUri(uri); + output.SetRemoteUri(remoteUri); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const Folder &input, TLVObject &data) +{ + return true; +} + +template<> +bool Reading(Folder &output, TLVObject &data) +{ + std::string uri; + std::string remoteUri; + UDDetails details; + if (!Reading(uri, data)) { + return false; + } + if (!Reading(remoteUri, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetUri(uri); + output.SetRemoteUri(remoteUri); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const SystemDefinedRecord &input, TLVObject &data) +{ + if (!Writing(input.GetDetails(), data)) { + return false; + } + return true; +} + +template<> +bool Reading(SystemDefinedRecord &output, TLVObject &data) +{ + UDDetails details; + if (!Reading(details, data)) { + return false; + } + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const SystemDefinedForm &input, TLVObject &data) +{ + if (!Writing(input.GetFormId(), data)) { + return false; + } + if (!Writing(input.GetFormName(), data)) { + return false; + } + if (!Writing(input.GetBundleName(), data)) { + return false; + } + if (!Writing(input.GetAbilityName(), data)) { + return false; + } + if (!Writing(input.GetModule(), data)) { + return false; + } + return true; +} + +template<> +bool Reading(SystemDefinedForm &output, TLVObject &data) +{ + int32_t formId; + std::string formName; + std::string bundleName; + std::string abilityName; + std::string module; + UDDetails details; + if (!Reading(formId, data)) { + return false; + } + if (!Reading(formName, data)) { + return false; + } + if (!Reading(bundleName, data)) { + return false; + } + if (!Reading(abilityName, data)) { + return false; + } + if (!Reading(module, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetFormId(formId); + output.SetFormName(formName); + output.SetBundleName(bundleName); + output.SetAbilityName(abilityName); + output.SetModule(module); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const SystemDefinedAppItem &input, TLVObject &data) +{ + if (!Writing(input.GetAppId(), data)) { + return false; + } + if (!Writing(input.GetAppName(), data)) { + return false; + } + if (!Writing(input.GetAppIconId(), data)) { + return false; + } + if (!Writing(input.GetAppLabelId(), data)) { + return false; + } + if (!Writing(input.GetBundleName(), data)) { + return false; + } + if (!Writing(input.GetAbilityName(), data)) { + return false; + } + return true; +} + +template<> +bool Reading(SystemDefinedAppItem &output, TLVObject &data) +{ + std::string appId; + std::string appName; + std::string appIconId; + std::string appLabelId; + std::string bundleName; + std::string abilityName; + UDDetails details; + if (!Reading(appId, data)) { + return false; + } + if (!Reading(appName, data)) { + return false; + } + if (!Reading(appIconId, data)) { + return false; + } + if (!Reading(appLabelId, data)) { + return false; + } + if (!Reading(bundleName, data)) { + return false; + } + if (!Reading(abilityName, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetAppId(appId); + output.SetAppName(appName); + output.SetAppIconId(appIconId); + output.SetAppLabelId(appLabelId); + output.SetBundleName(bundleName); + output.SetAbilityName(abilityName); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const SystemDefinedPixelMap &input, TLVObject &data) +{ + if (!Writing(input.GetRawData(), data)) { + return false; + } + return true; +} + +template<> +bool Reading(SystemDefinedPixelMap &output, TLVObject &data) +{ + std::vector<uint8_t> rawData; + UDDetails details; + if (!Reading(rawData, data)) { + return false; + } + if (!Reading(details, data)) { + return false; + } + output.SetRawData(rawData); + output.SetDetails(details); + return true; +} + +template<> +bool Writing(const ApplicationDefinedRecord &input, TLVObject &data) +{ + if (!Writing(input.GetApplicationDefinedType(), data)) { + return false; + } + if (!Writing(input.GetRawData(), data)) { + return false; + } + return true; +} + +template<> +bool Reading(ApplicationDefinedRecord &output, TLVObject &data) +{ + std::string type; + std::vector<uint8_t> rawData; + if (!Reading(type, data)) { + return false; + } + if (!Reading(rawData, data)) { + return false; + } + output.SetApplicationDefinedType(type); + output.SetRawData(rawData); + return true; +} + +template<> +bool Writing(const std::shared_ptr<UnifiedRecord> &input, TLVObject &data) +{ + if (data.GetBuffer().size() == 0) { + if (!CountBufferSize(input, data)) { + return false; + } + data.UpdateSize(); + } + + if (!Writing(input->GetType(), data)) { + return false; + } + if (!Writing(input->GetUid(), data)) { + return false; + } + auto type = input->GetType(); + switch (type) { + case UDType::TEXT: { + auto text = static_cast<Text *>(input.get()); + if (text == nullptr) { + return false; + } + return Writing(*text, data); + } + case UDType::PLAIN_TEXT: { + auto plainText = static_cast<PlainText *>(input.get()); + if (plainText == nullptr) { + return false; + } + if (!Writing(*plainText, data)) { + return false; + } + auto text = static_cast<Text *>(input.get()); + if (text == nullptr) { + return false; + } + return Writing(*text, data); + } + case UDType::HTML: { + auto html = static_cast<Html *>(input.get()); + if (html == nullptr) { + return false; + } + if (!Writing(*html, data)) { + return false; + } + auto text = static_cast<Text *>(input.get()); + if (text == nullptr) { + return false; + } + return Writing(*text, data); + } + case UDType::HYPERLINK: { + auto link = static_cast<Link *>(input.get()); + if (link == nullptr) { + return false; + } + if (!Writing(*link, data)) { + return false; + } + auto text = static_cast<Text *>(input.get()); + if (text == nullptr) { + return false; + } + return Writing(*text, data); + } + case UDType::FILE: { + auto file = static_cast<File *>(input.get()); + if (file == nullptr) { + return false; + } + return Writing(*file, data); + } + case UDType::IMAGE: { + auto image = static_cast<Image *>(input.get()); + if (image == nullptr) { + return false; + } + if (!Writing(*image, data)) { + return false; + } + auto file = static_cast<File *>(input.get()); + if (file == nullptr) { + return false; + } + return Writing(*file, data); + } + case UDType::VIDEO: { + auto video = static_cast<Video *>(input.get()); + if (video == nullptr) { + return false; + } + if (!Writing(*video, data)) { + return false; + } + auto file = static_cast<File *>(input.get()); + if (file == nullptr) { + return false; + } + return Writing(*file, data); + } + case UDType::AUDIO: { + auto audio = static_cast<Audio *>(input.get()); + if (audio == nullptr) { + return false; + } + if (!Writing(*audio, data)) { + return false; + } + auto file = static_cast<File *>(input.get()); + if (file == nullptr) { + return false; + } + return Writing(*file, data); + } + case UDType::FOLDER: { + auto folder = static_cast<Folder *>(input.get()); + if (folder == nullptr) { + return false; + } + if (!Writing(*folder, data)) { + return false; + } + auto file = static_cast<File *>(input.get()); + if (file == nullptr) { + return false; + } + return Writing(*file, data); + } + case UDType::SYSTEM_DEFINED_RECORD: { + auto sdRecord = static_cast<SystemDefinedRecord *>(input.get()); + if (sdRecord == nullptr) { + return false; + } + return Writing(*sdRecord, data); + } + case UDType::SYSTEM_DEFINED_FORM: { + auto form = static_cast<SystemDefinedForm *>(input.get()); + if (form == nullptr) { + return false; + } + if (!Writing(*form, data)) { + return false; + } + auto sdRecord = static_cast<SystemDefinedRecord *>(input.get()); + if (sdRecord == nullptr) { + return false; + } + return Writing(*sdRecord, data); + } + case UDType::SYSTEM_DEFINED_APP_ITEM: { + auto appItem = static_cast<SystemDefinedAppItem *>(input.get()); + if (appItem == nullptr) { + return false; + } + if (!Writing(*appItem, data)) { + return false; + } + auto sdRecord = static_cast<SystemDefinedRecord *>(input.get()); + if (sdRecord == nullptr) { + return false; + } + return Writing(*sdRecord, data); + } + case UDType::SYSTEM_DEFINED_PIXEL_MAP: { + auto pixelMap = static_cast<SystemDefinedPixelMap *>(input.get()); + if (pixelMap == nullptr) { + return false; + } + if (!Writing(*pixelMap, data)) { + return false; + } + auto sdRecord = static_cast<SystemDefinedRecord *>(input.get()); + if (sdRecord == nullptr) { + return false; + } + return Writing(*sdRecord, data); + } + case UDType::APPLICATION_DEFINED_RECORD: { + auto record = static_cast<ApplicationDefinedRecord *>(input.get()); + if (record == nullptr) { + return false; + } + return Writing(*record, data); + } + default: { + return false; + } + } +} + +template<> +bool Reading(std::shared_ptr<UnifiedRecord> &output, TLVObject &data) +{ + UDType type ; + if (!Reading(type, data)) { + return false; + } + std::string uid; + if (!Reading(uid, data)) { + return false; + } + switch (type) { + case UDType::TEXT: { + std::shared_ptr<Text> text = std::make_shared<Text>(); + if (!Reading(*text, data)) { + return false; + } + output = text; + break; + } + case UDType::PLAIN_TEXT: { + std::shared_ptr<PlainText> plainText = std::make_shared<PlainText>(); + if (!Reading(*plainText, data)) { + return false; + } + output = plainText; + break; + } + case UDType::HTML: { + std::shared_ptr<Html> html = std::make_shared<Html>(); + if (!Reading(*html, data)) { + return false; + } + output = html; + break; + } + case UDType::HYPERLINK: { + std::shared_ptr<Link> link = std::make_shared<Link>(); + if (!Reading(*link, data)) { + return false; + } + output = link; + break; + } + case UDType::FILE: { + std::shared_ptr<File> file = std::make_shared<File>(); + if (!Reading(*file, data)) { + return false; + } + output = file; + break; + } + case UDType::IMAGE: { + std::shared_ptr<Image> image = std::make_shared<Image>(); + if (!Reading(*image, data)) { + return false; + } + output = image; + break; + } + case UDType::VIDEO: { + std::shared_ptr<Video> video = std::make_shared<Video>(); + if (!Reading(*video, data)) { + return false; + } + output = video; + break; + } + case UDType::AUDIO: { + std::shared_ptr<Audio> audio = std::make_shared<Audio>(); + if (!Reading(*audio, data)) { + return false; + } + output = audio; + break; + } + case UDType::FOLDER: { + std::shared_ptr<Folder> folder = std::make_shared<Folder>(); + if (!Reading(*folder, data)) { + return false; + } + output = folder; + break; + } + case UDType::SYSTEM_DEFINED_RECORD: { + std::shared_ptr<SystemDefinedRecord> sdRecord = std::make_shared<SystemDefinedRecord>(); + if (!Reading(*sdRecord, data)) { + return false; + } + output = sdRecord; + break; + } + case UDType::SYSTEM_DEFINED_FORM: { + std::shared_ptr<SystemDefinedForm> form = std::make_shared<SystemDefinedForm>(); + if (!Reading(*form, data)) { + return false; + } + output = form; + break; + } + case UDType::SYSTEM_DEFINED_APP_ITEM: { + std::shared_ptr<SystemDefinedAppItem> appItem = std::make_shared<SystemDefinedAppItem>(); + if (!Reading(*appItem, data)) { + return false; + } + output = appItem; + break; + } + case UDType::SYSTEM_DEFINED_PIXEL_MAP: { + std::shared_ptr<SystemDefinedPixelMap> pixelMap = std::make_shared<SystemDefinedPixelMap>(); + if (!Reading(*pixelMap, data)) { + return false; + } + output = pixelMap; + break; + } + case UDType::APPLICATION_DEFINED_RECORD: { + std::shared_ptr<ApplicationDefinedRecord> record = std::make_shared<ApplicationDefinedRecord>(); + if (!Reading(*record, data)) { + return false; + } + output = record; + break; + } + default: { + return false; + } + } + output->SetUid(uid); + output->SetType(type); + return true; +} + +template<> +bool Writing(const UnifiedData &input, TLVObject &data) +{ + if (data.GetBuffer().size() == 0) { + if (!CountBufferSize(input, data)) { + return false; + } + data.UpdateSize(); + } + + int32_t size = input.GetRecords().size(); + if (!Writing(size, data)) { + return false; + } + + for (auto record : input.GetRecords()) { + if (!Writing(record, data)) { + return false; + } + } + return true; +} + +template<> +bool Reading(UnifiedData &output, TLVObject &data) +{ + int32_t size; + if (!Reading(size, data)) { + return false; + } + while (size-- > 0) { + std::shared_ptr<UnifiedRecord> record; + if (!Reading(record, data)) { + return false; + } + output.AddRecord(record); + } + return true; +} + +template<> +bool Writing(const std::vector<UnifiedData> &input, TLVObject &data) +{ + if (!CountBufferSize(input, data)) { + return false; + } + data.UpdateSize(); + + int32_t size = input.size(); + if (!Writing(size, data)) { + return false; + } + + for (auto unifiedData : input) { + if (!Writing(unifiedData, data)) { + return false; + } + } + return true; +} + +template<> +bool Reading(std::vector<UnifiedData> &output, TLVObject &data) +{ + int32_t size; + if (!Reading(size, data)) { + return false; + } + while (size-- > 0) { + UnifiedData unifiedData; + if (!Reading(unifiedData, data)) { + return false; + } + output.push_back(unifiedData); + } + return true; +} + +template<> +bool Writing(const UnifiedKey &input, TLVObject &data) +{ + if (!Writing(input.key, data)) { + return false; + } + if (!Writing(input.intention, data)) { + return false; + } + if (!Writing(input.bundleName, data)) { + return false; + } + if (!Writing(input.groupId, data)) { + return false; + } + return true; +} + +template<> +bool Reading(UnifiedKey &output, TLVObject &data) +{ + std::string key; + std::string intention; + std::string bundleName; + std::string groupId; + if (!Reading(key, data)) { + return false; + } + if (!Reading(intention, data)) { + return false; + } + if (!Reading(bundleName, data)) { + return false; + } + if (!Reading(groupId, data)) { + return false; + } + output.key = key; + output.intention = intention; + output.bundleName = bundleName; + output.groupId = groupId; + return true; +} + +template<> +bool Writing(const Privilege &input, TLVObject &data) +{ + if (!Writing(input.tokenId, data)) { + return false; + } + if (!Writing(input.readPermission, data)) { + return false; + } + if (!Writing(input.writePermission, data)) { + return false; + } + return true; +} + +template<> +bool Reading(Privilege &output, TLVObject &data) +{ + uint32_t tokenId; + std::string readPermission; + std::string writePermission; + if (!Reading(tokenId, data)) { + return false; + } + if (!Reading(readPermission, data)) { + return false; + } + if (!Reading(writePermission, data)) { + return false; + } + output.tokenId = tokenId; + output.readPermission = readPermission; + output.writePermission = writePermission; + return true; +} + +template<> +bool Writing(const DataStatus &input, TLVObject &data) +{ + int32_t status = input; + return Writing(status, data); +} + +template<> +bool Reading(DataStatus &output, TLVObject &data) +{ + int32_t status; + if (!Reading(status, data)) { + return false; + } + if (status < DataStatus::WORKING || status >= DataStatus::FADE) { + return false; + } + output = static_cast<DataStatus>(status); + return true; +} + +template<> +bool Writing(const Runtime &input, TLVObject &data) +{ + (void)CountBufferSize(input, data); + data.UpdateSize(); + if (!Writing(input.key, data)) { + return false; + } + if (!Writing(input.isPrivate, data)) { + return false; + } + uint32_t size = static_cast<uint32_t>(input.privileges.size()); + if (!Writing(size, data)) { + return false; + } + for (uint32_t i = 0; i < size; ++i) { + if (!Writing(input.privileges[i], data)) { + return false; + } + } + if (!Writing(static_cast<int64_t>(input.createTime), data)) { + return false; + } + if (!Writing(input.sourcePackage, data)) { + return false; + } + if (!Writing(input.dataStatus, data)) { + return false; + } + if (!Writing(input.dataVersion, data)) { + return false; + } + if (!Writing(static_cast<int64_t>(input.lastModifiedTime), data)) { + return false; + } + if (!Writing(input.createPackage, data)) { + return false; + } + if (!Writing(input.deviceId, data)) { + return false; + } + return true; +} + +template<> +bool Reading(Runtime &output, TLVObject &data) +{ + UnifiedKey key; + bool isPrivate; + uint32_t size; + std::vector<Privilege> privileges; + int64_t createTime; + std::string sourcePackage; + DataStatus dataStatus; + int32_t dataVersion; + int64_t lastModifiedTime; + std::string createPackage; + std::string deviceId; + if (!Reading(key, data)) { + return false; + } + if (!Reading(isPrivate, data)) { + return false; + } + if (!Reading(size, data)) { + return false; + } + for (uint32_t i = 0; i < size; ++i) { + Privilege privilege; + if (!Reading(privilege, data)) { + return false; + } + privileges.emplace_back(privilege); + } + if (!Reading(createTime, data)) { + return false; + } + if (!Reading(sourcePackage, data)) { + return false; + } + if (!Reading(dataStatus, data)) { + return false; + } + if (!Reading(dataVersion, data)) { + return false; + } + if (!Reading(lastModifiedTime, data)) { + return false; + } + if (!Reading(createPackage, data)) { + return false; + } + if (!Reading(deviceId, data)) { + return false; + } + output.key = key; + output.isPrivate = isPrivate; + output.privileges = privileges; + output.createTime = createTime; + output.sourcePackage = sourcePackage; + output.dataStatus = dataStatus; + output.dataVersion = dataVersion; + output.lastModifiedTime = lastModifiedTime; + output.createPackage = createPackage; + output.deviceId = deviceId; + return true; +} +} // namespace TLVUtil +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/common/tlv_util.h b/udmf/framework/common/tlv_util.h new file mode 100644 index 00000000..e3d330b0 --- /dev/null +++ b/udmf/framework/common/tlv_util.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_TLV_UTIL_H +#define UDMF_TLV_UTIL_H + +#include <type_traits> + +#include "application_defined_record.h" +#include "audio.h" +#include "file.h" +#include "folder.h" +#include "html.h" +#include "image.h" +#include "link.h" +#include "plain_text.h" +#include "system_defined_appitem.h" +#include "system_defined_form.h" +#include "system_defined_pixelmap.h" +#include "system_defined_record.h" +#include "text.h" +#include "tlv_object.h" +#include "unified_data.h" +#include "unified_key.h" +#include "unified_meta.h" +#include "unified_record.h" +#include "unified_types.h" +#include "video.h" + +namespace OHOS { +namespace TLVUtil { +using namespace OHOS::UDMF; +template<typename T> +bool CountBufferSize(const T &input, TLVObject &data); + +template<> +bool CountBufferSize(const std::shared_ptr<UnifiedRecord> &input, TLVObject &data); + +template<> +bool CountBufferSize(const Runtime &input, TLVObject &data); + +template<> +bool CountBufferSize(const UnifiedData &input, TLVObject &data); + +template<> +bool CountBufferSize(const std::vector<UnifiedData> &input, TLVObject &data); + +template<typename T> +bool Writing(const T &input, TLVObject &data); +template<typename T> +bool Reading(T &output, TLVObject &data); + +template<> +bool Writing(const int32_t &input, TLVObject &data); +template<> +bool Reading(int32_t &output, TLVObject &data); + +template<> +bool Writing(const int64_t &input, TLVObject &data); +template<> +bool Reading(int64_t &output, TLVObject &data); + +template<> +bool Writing(const bool &input, TLVObject &data); +template<> +bool Reading(bool &output, TLVObject &data); + +template<> +bool Reading(uint32_t &output, TLVObject &data); + +template<> +bool Writing(const uint32_t &input, TLVObject &data); + +template<> +bool Reading(uint64_t &output, TLVObject &data); + +template<> +bool Writing(const uint64_t &input, TLVObject &data); + +template<> +bool Writing(const std::string &input, TLVObject &data); +template<> +bool Reading(std::string &output, TLVObject &data); + +template<> +bool Writing(const std::vector<uint8_t> &input, TLVObject &data); +template<> +bool Reading(std::vector<uint8_t> &output, TLVObject &data); + +template<> +bool Writing(const UDVariant &input, TLVObject &data); +template<> +bool Reading(UDVariant &output, TLVObject &data); + +template<> +bool Writing(const UDDetails &input, TLVObject &data); +template<> +bool Reading(UDDetails &output, TLVObject &data); + +template<> +bool Writing(const UDType &input, TLVObject &data); +template<> +bool Reading(UDType &output, TLVObject &data); + +template<> +bool Writing(const Text &input, TLVObject &data); +template<> +bool Reading(Text &output, TLVObject &data); + +template<> +bool Writing(const PlainText &input, TLVObject &data); +template<> +bool Reading(PlainText &output, TLVObject &data); + +template<> +bool Writing(const Html &input, TLVObject &data); +template<> +bool Reading(Html &output, TLVObject &data); + +template<> +bool Writing(const Link &input, TLVObject &data); +template<> +bool Reading(Link &output, TLVObject &data); + +template<> +bool Writing(const File &input, TLVObject &data); +template<> +bool Reading(File &output, TLVObject &data); + +template<> +bool Writing(const Image &input, TLVObject &data); +template<> +bool Reading(Image &output, TLVObject &data); + +template<> +bool Writing(const Video &input, TLVObject &data); +template<> +bool Reading(Video &output, TLVObject &data); + +template<> +bool Writing(const Audio &input, TLVObject &data); +template<> +bool Reading(Audio &output, TLVObject &data); + +template<> +bool Writing(const Folder &input, TLVObject &data); +template<> +bool Reading(Folder &output, TLVObject &data); + +template<> +bool Writing(const SystemDefinedRecord &input, TLVObject &data); +template<> +bool Reading(SystemDefinedRecord &output, TLVObject &data); + +template<> +bool Writing(const SystemDefinedForm &input, TLVObject &data); +template<> +bool Reading(SystemDefinedForm &output, TLVObject &data); + +template<> +bool Writing(const SystemDefinedAppItem &input, TLVObject &data); +template<> +bool Reading(SystemDefinedAppItem &output, TLVObject &data); + +template<> +bool Writing(const SystemDefinedPixelMap &input, TLVObject &data); +template<> +bool Reading(SystemDefinedPixelMap &output, TLVObject &data); + +template<> +bool Writing(const ApplicationDefinedRecord &input, TLVObject &data); +template<> +bool Reading(ApplicationDefinedRecord &output, TLVObject &data); + +template<> +bool Writing(const std::shared_ptr<UnifiedRecord> &input, TLVObject &data); +template<> +bool Reading(std::shared_ptr<UnifiedRecord> &output, TLVObject &data); + +template<> +bool Writing(const UnifiedData &input, TLVObject &data); +template<> +bool Reading(UnifiedData &output, TLVObject &data); + +template<> +bool Writing(const std::vector<UnifiedData> &input, TLVObject &data); +template<> +bool Reading(std::vector<UnifiedData> &output, TLVObject &data); + +template<> +bool Writing(const UnifiedKey &input, TLVObject &data); +template<> +bool Reading(UnifiedKey &output, TLVObject &data); + +template<> +bool Writing(const Privilege &input, TLVObject &data); +template<> +bool Reading(Privilege &output, TLVObject &data); + +template<> +bool Writing(const DataStatus &input, TLVObject &data); +template<> +bool Reading(DataStatus &output, TLVObject &data); + +template<> +bool Writing(const Runtime &input, TLVObject &data); +template<> +bool Reading(Runtime &output, TLVObject &data); +} // namespace TLVUtil +} // namespace OHOS +#endif // UDMF_TLV_UTIL_H \ No newline at end of file diff --git a/udmf/framework/common/udmf_types_util.cpp b/udmf/framework/common/udmf_types_util.cpp new file mode 100644 index 00000000..261eb143 --- /dev/null +++ b/udmf/framework/common/udmf_types_util.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "udmf_types_util.h" + +#include <string> + +#include "logger.h" +#include "tlv_util.h" + +namespace OHOS { +namespace ITypesUtil { +using namespace UDMF; +template<> +bool Marshalling(const UnifiedData &input, MessageParcel &parcel) +{ + std::vector<uint8_t> dataBytes; + auto recordTlv = TLVObject(dataBytes); + if (!TLVUtil::Writing(input, recordTlv)) { + LOG_ERROR(UDMF_SERVICE, "TLV writing failed!"); + return false; + } + if (!parcel.WriteInt32(static_cast<int32_t>(dataBytes.size())) + || !parcel.WriteRawData(dataBytes.data(), dataBytes.size())) { + LOG_ERROR(UDMF_SERVICE, "Marshall unified data failed!"); + return false; + } + return true; +} + +template<> +bool Unmarshalling(UnifiedData &output, MessageParcel &parcel) +{ + auto size = parcel.ReadInt32(); + if (size == 0) { + LOG_ERROR(UDMF_SERVICE, "UnifiedData is empty!"); + return false; + } + const uint8_t *rawData = reinterpret_cast<const uint8_t *>(parcel.ReadRawData(size)); + if (rawData == nullptr) { + LOG_ERROR(UDMF_SERVICE, "RawData is null!"); + return false; + } + std::vector<uint8_t> dataBytes(rawData, rawData + size); + auto recordTlv = TLVObject(dataBytes); + if (!TLVUtil::Reading(output, recordTlv)) { + LOG_ERROR(UDMF_SERVICE, "Unmarshall unified data failed!"); + return false; + } + return true; +} + +template<> +bool Marshalling(const std::vector<UnifiedData> &input, MessageParcel &parcel) +{ + std::vector<uint8_t> dataSetBytes; + auto recordTlv = TLVObject(dataSetBytes); + if (!TLVUtil::Writing(input, recordTlv)) { + LOG_ERROR(UDMF_SERVICE, "TLV writing failed!"); + return false; + } + if (!parcel.WriteInt32(static_cast<int32_t>(dataSetBytes.size())) + || !parcel.WriteRawData(dataSetBytes.data(), dataSetBytes.size())) { + LOG_ERROR(UDMF_SERVICE, "Marshall unified data set failed!"); + return false; + } + return true; +} + +template<> +bool Unmarshalling(std::vector<UnifiedData> &output, MessageParcel &parcel) +{ + auto size = parcel.ReadInt32(); + if (size == 0) { + LOG_ERROR(UDMF_SERVICE, "UnifiedDataSet is empty!"); + return false; + } + const uint8_t *rawData = reinterpret_cast<const uint8_t *>(parcel.ReadRawData(size)); + if (rawData == nullptr) { + LOG_ERROR(UDMF_SERVICE, "RawData is null!"); + return false; + } + std::vector<uint8_t> dataSetBytes(rawData, rawData + size); + auto recordTlv = TLVObject(dataSetBytes); + if (!TLVUtil::Reading(output, recordTlv)) { + LOG_ERROR(UDMF_SERVICE, "Unmarshall unified data set failed!"); + return false; + } + return true; +} + +template<> +bool Marshalling(const Summary &input, MessageParcel &parcel) +{ + return ITypesUtil::Marshal(parcel, input.summary, input.totalSize); +} + +template<> +bool Unmarshalling(Summary &output, MessageParcel &parcel) +{ + return ITypesUtil::Unmarshal(parcel, output.summary, output.totalSize); +} + +template<> +bool Marshalling(const Privilege &input, MessageParcel &parcel) +{ + return ITypesUtil::Marshal(parcel, input.tokenId, input.readPermission, input.writePermission); +} + +template<> +bool Unmarshalling(Privilege &output, MessageParcel &parcel) +{ + return ITypesUtil::Unmarshal(parcel, output.tokenId, output.readPermission, output.writePermission); +} + +template<> +bool Marshalling(const CustomOption &input, MessageParcel &parcel) +{ + return ITypesUtil::Marshal(parcel, input.intention); +} + +template<> +bool Unmarshalling(CustomOption &output, MessageParcel &parcel) +{ + return ITypesUtil::Unmarshal(parcel, output.intention); +} + +template<> +bool Marshalling(const QueryOption &input, MessageParcel &parcel) +{ + return ITypesUtil::Marshal(parcel, input.key, input.intention); +} + +template<> +bool Unmarshalling(QueryOption &output, MessageParcel &parcel) +{ + return ITypesUtil::Unmarshal(parcel, output.key, output.intention); +} + +template<> +bool Marshalling(const UDType &input, MessageParcel &parcel) +{ + int32_t type = input; + return ITypesUtil::Marshal(parcel, type); +} + +template<> +bool Unmarshalling(UDType &output, MessageParcel &parcel) +{ + int32_t type; + if (!ITypesUtil::Unmarshal(parcel, type)) { + LOG_ERROR(UDMF_FRAMEWORK, "Unmarshal UDType failed!"); + return false; + } + if (type < TEXT || type >= UD_BUTT) { + LOG_ERROR(UDMF_FRAMEWORK, "invalid UDType!"); + return false; + } + output = static_cast<UDType>(type); + return true; +} + +template<> +bool Marshalling(const Intention &input, MessageParcel &parcel) +{ + int32_t intention = input; + return ITypesUtil::Marshal(parcel, intention); +} + +template<> +bool Unmarshalling(Intention &output, MessageParcel &parcel) +{ + int32_t intention; + if (!ITypesUtil::Unmarshal(parcel, intention)) { + LOG_ERROR(UDMF_FRAMEWORK, "Unmarshal Intention failed!"); + return false; + } + if (intention < UD_INTENTION_BASE || intention > UD_INTENTION_BUTT) { + LOG_ERROR(UDMF_FRAMEWORK, "invalid Intention!"); + return false; + } + output = static_cast<Intention>(intention); + return true; +} +} // namespace ITypesUtil +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/common/udmf_types_util.h b/udmf/framework/common/udmf_types_util.h new file mode 100644 index 00000000..53f181cc --- /dev/null +++ b/udmf/framework/common/udmf_types_util.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_TYPES_UTIL_H +#define UDMF_TYPES_UTIL_H + +#include "itypes_util.h" + +#include "unified_data.h" +#include "unified_meta.h" +#include "unified_types.h" + +namespace OHOS { +namespace ITypesUtil { +using UnifiedData = UDMF::UnifiedData; +using Summary = UDMF::Summary; +using Privilege = UDMF::Privilege; +using CustomOption = UDMF::CustomOption; +using QueryOption = UDMF::QueryOption; +using UDType = UDMF::UDType; +using Intention = UDMF::Intention; + +template<> +bool Marshalling(const UnifiedData &input, MessageParcel &parcel); +template<> +bool Unmarshalling(UnifiedData &output, MessageParcel &parcel); + +template<> +bool Marshalling(const std::vector<UnifiedData> &input, MessageParcel &parcel); +template<> +bool Unmarshalling(std::vector<UnifiedData> &output, MessageParcel &parcel); + +template<> +bool Marshalling(const Summary &input, MessageParcel &parcel); +template<> +bool Unmarshalling(Summary &output, MessageParcel &parcel); + +template<> +bool Marshalling(const Privilege &input, MessageParcel &parcel); +template<> +bool Unmarshalling(Privilege &output, MessageParcel &parcel); + +template<> +bool Marshalling(const CustomOption &input, MessageParcel &parcel); +template<> +bool Unmarshalling(CustomOption &output, MessageParcel &parcel); + +template<> +bool Marshalling(const QueryOption &input, MessageParcel &parcel); +template<> +bool Unmarshalling(QueryOption &output, MessageParcel &parcel); + +template<> +bool Marshalling(const UDType &input, MessageParcel &parcel); +template<> +bool Unmarshalling(UDType &output, MessageParcel &parcel); + +template<> +bool Marshalling(const Intention &input, MessageParcel &parcel); +template<> +bool Unmarshalling(Intention &output, MessageParcel &parcel); +} // namespace ITypesUtil +} // namespace OHOS +#endif // UDMF_TYPES_UTIL_H \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/client/udmf_client.cpp b/udmf/framework/innerkitsimpl/client/udmf_client.cpp new file mode 100644 index 00000000..91dab5cf --- /dev/null +++ b/udmf/framework/innerkitsimpl/client/udmf_client.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "udmf_client.h" + +#include "dds_trace.h" + +#include "error_code.h" +#include "logger.h" +#include "udmf_service_client.h" + +namespace OHOS { +namespace UDMF { +const std::string TAG = "UdmfClient::"; +using namespace OHOS::DistributedDataDfx; +UdmfClient &UdmfClient::GetInstance() +{ + static auto instance_ = new UdmfClient(); + return *instance_; +} + +Status UdmfClient::SetData(CustomOption &option, UnifiedData &unifiedData, std::string &key) +{ + DdsTrace trace( + std::string(TAG) + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); + auto service = UdmfServiceClient::GetInstance(); + if (service == nullptr) { + LOG_ERROR(UDMF_CLIENT, "Service unavailable"); + return E_IPC; + } + int32_t ret = service->SetData(option, unifiedData, key); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); + } + return static_cast<Status>(ret); +} + +Status UdmfClient::GetData(const QueryOption &query, UnifiedData &unifiedData) +{ + DdsTrace trace( + std::string(TAG) + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); + auto service = UdmfServiceClient::GetInstance(); + if (service == nullptr) { + LOG_ERROR(UDMF_CLIENT, "Service unavailable"); + return E_IPC; + } + int32_t ret = service->GetData(query, unifiedData); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); + } + return static_cast<Status>(ret); +} + +Status UdmfClient::GetBatchData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) +{ + DdsTrace trace( + std::string(TAG) + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); + auto service = UdmfServiceClient::GetInstance(); + if (service == nullptr) { + LOG_ERROR(UDMF_CLIENT, "Service unavailable"); + return E_IPC; + } + int32_t ret = service->GetBatchData(query, unifiedDataSet); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); + } + return static_cast<Status>(ret); +} + +Status UdmfClient::UpdateData(const QueryOption &query, UnifiedData &unifiedData) +{ + DdsTrace trace( + std::string(TAG) + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); + auto service = UdmfServiceClient::GetInstance(); + if (service == nullptr) { + LOG_ERROR(UDMF_CLIENT, "Service unavailable"); + return E_IPC; + } + int32_t ret = service->UpdateData(query, unifiedData); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); + } + return static_cast<Status>(ret); +} + +Status UdmfClient::DeleteData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) +{ + DdsTrace trace( + std::string(TAG) + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); + auto service = UdmfServiceClient::GetInstance(); + if (service == nullptr) { + LOG_ERROR(UDMF_CLIENT, "Service unavailable"); + return E_IPC; + } + int32_t ret = service->DeleteData(query, unifiedDataSet); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); + } + return static_cast<Status>(ret); +} + +Status UdmfClient::GetSummary(const QueryOption &query, Summary &summary) +{ + DdsTrace trace( + std::string(TAG) + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); + auto service = UdmfServiceClient::GetInstance(); + if (service == nullptr) { + LOG_ERROR(UDMF_CLIENT, "Service unavailable"); + return E_IPC; + } + int32_t ret = service->GetSummary(query, summary); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); + } + return static_cast<Status>(ret); +} + +Status UdmfClient::AddPrivilege(const QueryOption &query, Privilege &privilege) +{ + DdsTrace trace( + std::string(TAG) + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); + auto service = UdmfServiceClient::GetInstance(); + if (service == nullptr) { + LOG_ERROR(UDMF_CLIENT, "Service unavailable"); + return E_IPC; + } + int32_t ret = service->AddPrivilege(query, privilege); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); + } + return static_cast<Status>(ret); +} + +Status UdmfClient::Sync(const QueryOption &query, const std::vector<std::string> &devices) +{ + DdsTrace trace( + std::string(TAG) + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); + auto service = UdmfServiceClient::GetInstance(); + if (service == nullptr) { + LOG_ERROR(UDMF_CLIENT, "Service unavailable"); + return E_IPC; + } + int32_t ret = service->Sync(query, devices); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); + } + return static_cast<Status>(ret); +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/common/unified_key.cpp b/udmf/framework/innerkitsimpl/common/unified_key.cpp new file mode 100644 index 00000000..03abf4bd --- /dev/null +++ b/udmf/framework/innerkitsimpl/common/unified_key.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unified_key.h" + +#include "logger.h" + +namespace OHOS { +namespace UDMF { +static std::bitset<MAX_BIT_SIZE> g_ruleIntention; +static std::bitset<MAX_BIT_SIZE> g_ruleBundleName; +static std::bitset<MAX_BIT_SIZE> g_ruleGroupId; +static const std::string UNIFIED_KEY_SCHEMA = "udmf://"; +static const std::string ALPHA_AGGREGATE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static const std::string DIGIT_AGGREGATE = "0123456789"; +static const std::string SYMBOL_AGGREGATE = ":;<=>?@[\\]_`"; +UnifiedKey::UnifiedKey(std::string key) +{ + this->key = std::move(key); +} + +UnifiedKey::UnifiedKey(std::string intention, std::string bundle, std::string groupId) +{ + this->intention = std::move(intention); + this->bundleName = std::move(bundle); + this->groupId = std::move(groupId); +} + +std::string UnifiedKey::GetUnifiedKey() +{ + if (!this->key.empty()) { + return this->key; + } + if (this->intention.empty() || this->groupId.empty()) { + return ""; + } + // Uri-compliant structure, example: udmf://drag/com.ohos.test/012345679abc + this->key = UNIFIED_KEY_SCHEMA + this->intention + "/" + this->bundleName + "/" + this->groupId; + return this->key; +} + +bool UnifiedKey::IsValid() +{ + if (this->key.empty()) { + LOG_DEBUG(UDMF_FRAMEWORK, "empty key"); + return false; + } + PreliminaryWork(); + + std::string data = this->key; // schema/intention/groupId + std::string separator = "://"; + size_t pos = data.find(separator); + if (pos == std::string::npos) { + return false; + } + std::string schema = data.substr(0, pos + separator.size()); // schema + if (UNIFIED_KEY_SCHEMA != schema) { + LOG_DEBUG(UDMF_FRAMEWORK, "wrong schema"); + return false; + } + + data = data.substr(pos + separator.size()); // intention/bundleName/groupId + pos = data.find('/'); // intention + if (pos == std::string::npos) { + return false; + } + std::string intentionTmp = data.substr(0, pos); + if (!CheckCharacter(intentionTmp, g_ruleIntention)) { + return false; + } + this->intention = intentionTmp; + + data = data.substr(pos + 1); + pos = data.find('/'); // bundleName + if (pos == std::string::npos) { + return false; + } + std::string bundle = data.substr(0, pos); + if (!CheckCharacter(bundle, g_ruleBundleName)) { + LOG_DEBUG(UDMF_FRAMEWORK, "wrong bundle"); + return false; + } + this->bundleName = bundle; + + data = data.substr(pos + 1); // groupId + if (data.empty()) { + return false; + } + if (!CheckCharacter(data, g_ruleGroupId)) { + LOG_DEBUG(UDMF_FRAMEWORK, "wrong groupId"); + return false; + } + this->groupId = data; + return true; +} + +bool UnifiedKey::CheckCharacter(std::string data, std::bitset<MAX_BIT_SIZE> rule) +{ + if (data.empty()) { + LOG_DEBUG(UDMF_FRAMEWORK, "empty key"); + return false; + } + size_t dataLen = data.size(); + for (size_t i = 0; i < dataLen; ++i) { + if (static_cast<int>(data[i]) >= 0 && static_cast<int>(data[i]) < 128) { // 128:ASCII Max Number + bool isLegal = rule.test(data[i]); + if (!isLegal) { + return false; + } + } + } + return true; +} + +void UnifiedKey::PreliminaryWork() +{ + // All intentions are composed of uppercase and lowercase letters and underscores. + if (g_ruleIntention.none()) { + std::string intentionTmp = ALPHA_AGGREGATE + "_"; + for (char i : intentionTmp) { + g_ruleIntention.set(i); + } + } + // All bundle name are composed of uppercase and lowercase letters and dots. + if (g_ruleBundleName.none()) { + std::string bundleAggregate = ALPHA_AGGREGATE + DIGIT_AGGREGATE + "._"; + for (char i : bundleAggregate) { + g_ruleBundleName.set(i); + } + } + // Characters of groupId are taken from Ascii codes 48 to 122. + if (g_ruleGroupId.none()) { + std::string idAggregate = DIGIT_AGGREGATE + ALPHA_AGGREGATE + SYMBOL_AGGREGATE; + for (char i : idAggregate) { + g_ruleGroupId.set(i); + } + } +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/common/unified_meta.cpp b/udmf/framework/innerkitsimpl/common/unified_meta.cpp new file mode 100644 index 00000000..6bad218c --- /dev/null +++ b/udmf/framework/innerkitsimpl/common/unified_meta.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unified_meta.h" + +#include "unified_key.h" + +namespace OHOS { +namespace UDMF { +bool UnifiedDataUtils::IsValidType(int32_t value) +{ + return value >= TEXT && value < UD_BUTT; +} + +bool UnifiedDataUtils::IsValidIntention(int32_t value) +{ + return value > UD_INTENTION_BASE && value < UD_INTENTION_BUTT; +} + +size_t UnifiedDataUtils::GetVariantSize(UDVariant &variant) +{ + auto int32Value = std::get_if<int32_t>(&variant); + if (int32Value != nullptr) { + return sizeof(std::get<int32_t>(variant)); + } + auto int64Value = std::get_if<int64_t>(&variant); + if (int64Value != nullptr) { + return sizeof(std::get<int64_t>(variant)); + } + auto boolValue = std::get_if<bool>(&variant); + if (boolValue != nullptr) { + return sizeof(std::get<bool>(variant)); + } + auto doubleValue = std::get_if<double>(&variant); + if (doubleValue != nullptr) { + return sizeof(std::get<double>(variant)); + } + auto strValue = std::get_if<std::string>(&variant); + if (strValue != nullptr) { + return std::get<std::string>(variant).size(); + } + auto vecValue = std::get_if<std::vector<uint8_t>>(&variant); + if (vecValue != nullptr) { + return std::get<std::vector<uint8_t>>(variant).size(); + } + return 0; +} + +size_t UnifiedDataUtils::GetDetailsSize(UDDetails &details) +{ + size_t total = 0; + for (std::pair<std::string, UDVariant> prop : details) { + total += prop.first.size(); + total += GetVariantSize(prop.second); + } + return total; +} + +bool UnifiedDataUtils::IsPersist(const Intention &intention) +{ + return intention >= UD_INTENTION_DATA_HUB && intention < UD_INTENTION_BUTT; +} + +bool UnifiedDataUtils::IsPersist(const std::string &intention) +{ + return IsPersist(GetIntentionByString(intention)); +} + +Intention UnifiedDataUtils::GetIntentionByString(const std::string &intention) +{ + for (const auto &it : UD_INTENTION_MAP) { + if (it.second == intention) { + return static_cast<Intention>(it.first); + } + } + return UD_INTENTION_BUTT; +} + +bool UnifiedDataUtils::IsValidOptions(const std::string &key, std::string &intention) +{ + UnifiedKey unifiedKey(key); + auto isValidKey = unifiedKey.IsValid(); + if (key.empty() && IsPersist(intention)) { + return true; + } + if (intention.empty() && isValidKey && IsPersist(unifiedKey.intention)) { + return true; + } + if (isValidKey && unifiedKey.intention == intention && IsPersist(intention)) { + intention = ""; + return true; + } + return false; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/application_defined_record.cpp b/udmf/framework/innerkitsimpl/data/application_defined_record.cpp new file mode 100644 index 00000000..cc6c8c04 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/application_defined_record.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "application_defined_record.h" + +namespace OHOS { +namespace UDMF { +ApplicationDefinedRecord::ApplicationDefinedRecord() : UnifiedRecord(APPLICATION_DEFINED_RECORD) +{ +} + +ApplicationDefinedRecord::ApplicationDefinedRecord(std::string type) : UnifiedRecord(APPLICATION_DEFINED_RECORD) +{ + this->applicationDefinedType = std::move(type); +} + +ApplicationDefinedRecord::ApplicationDefinedRecord(std::string type, std::vector<uint8_t> &data) + : UnifiedRecord(APPLICATION_DEFINED_RECORD) +{ + this->applicationDefinedType = std::move(type); + this->rawData_ = std::move(data); +} + +int64_t ApplicationDefinedRecord::GetSize() +{ + return rawData_.size(); +} + +std::string ApplicationDefinedRecord::GetApplicationDefinedType() const +{ + return this->applicationDefinedType; +} + +void ApplicationDefinedRecord::SetApplicationDefinedType(const std::string &type) +{ + this->applicationDefinedType = type; +} + +std::vector<uint8_t> ApplicationDefinedRecord::GetRawData() const +{ + return this->rawData_; +} + +void ApplicationDefinedRecord::SetRawData(const std::vector<uint8_t> &rawData) +{ + this->rawData_ = rawData; +} +} // namespace UDMF +} // namespace OHOS diff --git a/udmf/framework/innerkitsimpl/data/audio.cpp b/udmf/framework/innerkitsimpl/data/audio.cpp new file mode 100644 index 00000000..9f6a1bae --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/audio.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "audio.h" + +namespace OHOS { +namespace UDMF { +Audio::Audio() : Audio("") +{ +} + +Audio::Audio(const std::string &uri) : File(uri) +{ + this->dataType_ = AUDIO; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/file.cpp b/udmf/framework/innerkitsimpl/data/file.cpp new file mode 100644 index 00000000..0502b503 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/file.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "file.h" + +namespace OHOS { +namespace UDMF { +File::File() : UnifiedRecord(FILE) +{ +} + +File::File(const std::string &uri) : UnifiedRecord(FILE) +{ + this->oriUri_ = uri; +} + +int64_t File::GetSize() +{ + return this->oriUri_.size() + this->remoteUri_.size(); +} + +std::string File::GetUri() const +{ + return this->oriUri_; +} + +void File::SetUri(const std::string &uri) +{ + this->oriUri_ = uri; +} + +std::string File::GetRemoteUri() const +{ + return this->remoteUri_; +} + +void File::SetRemoteUri(const std::string &uri) +{ + this->remoteUri_ = uri; +} + +void File::SetDetails(UDDetails &variantMap) +{ + this->details_ = variantMap; +} + +UDDetails File::GetDetails() const +{ + return this->details_; +} +} // namespace UDMF +} // namespace OHOS diff --git a/udmf/framework/innerkitsimpl/data/folder.cpp b/udmf/framework/innerkitsimpl/data/folder.cpp new file mode 100644 index 00000000..6961eb66 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/folder.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "folder.h" + +namespace OHOS { +namespace UDMF { +Folder::Folder() : Folder("") +{ +} + +Folder::Folder(const std::string &uri) : File(uri) +{ + this->dataType_ = FOLDER; +} +} // namespace UDMF +} // namespace OHOS diff --git a/udmf/framework/innerkitsimpl/data/html.cpp b/udmf/framework/innerkitsimpl/data/html.cpp new file mode 100644 index 00000000..8bc129be --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/html.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "html.h" + +namespace OHOS { +namespace UDMF { +Html::Html() +{ + this->dataType_ = HTML; +} + +Html::Html(const std::string &htmlContent, const std::string &plainContent) +{ + if (plainContent.length() >= MAX_TEXT_LEN || htmlContent.length() >= MAX_TEXT_LEN) { + return; + } + this->dataType_ = HTML; + this->htmlContent_ = htmlContent; + this->plainContent_ = plainContent; +} + +int64_t Html::GetSize() +{ + return UnifiedDataUtils::GetDetailsSize(this->details_) + this->htmlContent_.size() + this->plainContent_.size(); +} + +std::string Html::GetHtmlContent() const +{ + return this->htmlContent_; +} + +void Html::SetHtmlContent(const std::string &htmlContent) +{ + if (htmlContent.length() >= MAX_TEXT_LEN) { + return; + } + this->htmlContent_ = htmlContent; +} + +std::string Html::GetPlainContent() const +{ + return this->plainContent_; +} + +void Html::SetPlainContent(const std::string &plainContent) +{ + if (plainContent.length() >= MAX_TEXT_LEN) { + return; + } + this->plainContent_ = plainContent; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/image.cpp b/udmf/framework/innerkitsimpl/data/image.cpp new file mode 100644 index 00000000..dce12163 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/image.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image.h" + +namespace OHOS { +namespace UDMF { +Image::Image() : Image("") +{ +} + +Image::Image(const std::string &uri) : File(uri) +{ + this->dataType_ = IMAGE; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/link.cpp b/udmf/framework/innerkitsimpl/data/link.cpp new file mode 100644 index 00000000..6ab4f994 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/link.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "link.h" + +namespace OHOS { +namespace UDMF { +Link::Link() : Link("", "") +{ +} + +Link::Link(const std::string &url) : Link(url, "") +{ +} + +Link::Link(const std::string &url, const std::string &description) +{ + if (url.length() >= MAX_TEXT_LEN || description.length() >= MAX_TEXT_LEN) { + return; + } + this->dataType_ = HYPERLINK; + this->url_ = url; + this->description_ = description; +} + +int64_t Link::GetSize() +{ + return UnifiedDataUtils::GetDetailsSize(this->details_) + this->url_.size() + this->description_.size(); +} + +std::string Link::GetUrl() const +{ + return this->url_; +} + +void Link::SetUrl(const std::string &url) +{ + if (url.length() >= MAX_TEXT_LEN) { + return; + } + this->url_ = url; +} + +std::string Link::GetDescription() const +{ + return this->description_; +} + +void Link::SetDescription(const std::string &description) +{ + if (description.length() >= MAX_TEXT_LEN) { + return; + } + this->description_ = description; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/plain_text.cpp b/udmf/framework/innerkitsimpl/data/plain_text.cpp new file mode 100644 index 00000000..99167635 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/plain_text.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plain_text.h" + +namespace OHOS { +namespace UDMF { +PlainText::PlainText() : PlainText("", "") +{ +} + +PlainText::PlainText(const std::string &content, const std::string &abstract) +{ + if (content.length() >= MAX_TEXT_LEN) { + return; + } + this->dataType_ = PLAIN_TEXT; + this->content_ = content; + this->abstract_ = abstract; +} + +int64_t PlainText::GetSize() +{ + return UnifiedDataUtils::GetDetailsSize(this->details_) + this->content_.size() + this->abstract_.size(); +} + +std::string PlainText::GetContent() const +{ + return this->content_; +} + +void PlainText::SetContent(const std::string &text) +{ + if (text.length() >= MAX_TEXT_LEN) { + return; + } + this->content_ = text; +} + +std::string PlainText::GetAbstract() const +{ + return this->abstract_; +} + +void PlainText::SetAbstract(const std::string &abstract) +{ + if (abstract.length() >= MAX_TEXT_LEN) { + return; + } + this->abstract_ = abstract; +} +} // namespace UDMF +} // namespace OHOS diff --git a/udmf/framework/innerkitsimpl/data/system_defined_appitem.cpp b/udmf/framework/innerkitsimpl/data/system_defined_appitem.cpp new file mode 100644 index 00000000..d9f18a3f --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/system_defined_appitem.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "system_defined_appitem.h" + +namespace OHOS { +namespace UDMF { +SystemDefinedAppItem::SystemDefinedAppItem() +{ + this->dataType_ = SYSTEM_DEFINED_APP_ITEM; +} + +int64_t SystemDefinedAppItem::GetSize() +{ + return UnifiedDataUtils::GetDetailsSize(this->details_) + this->appId_.size() + this->appName_.size() + + this->appIconId_.size() + this->appLabelId_.size() + this->bundleName_.size() + this->abilityName_.size(); +} + +std::string SystemDefinedAppItem::GetAppId() const +{ + return this->appId_; +} + +void SystemDefinedAppItem::SetAppId(const std::string &appId) +{ + this->appId_ = appId; +} + +std::string SystemDefinedAppItem::GetAppName() const +{ + return this->appName_; +} + +void SystemDefinedAppItem::SetAppName(const std::string &appName) +{ + this->appName_ = appName; +} + +std::string SystemDefinedAppItem::GetAppIconId() const +{ + return this->appIconId_; +} + +void SystemDefinedAppItem::SetAppIconId(const std::string &appIconId) +{ + this->appIconId_ = appIconId; +} + +std::string SystemDefinedAppItem::GetAppLabelId() const +{ + return this->appLabelId_; +} + +void SystemDefinedAppItem::SetAppLabelId(const std::string &appLabelId) +{ + this->appLabelId_ = appLabelId; +} + +std::string SystemDefinedAppItem::GetBundleName() const +{ + return this->bundleName_; +} + +void SystemDefinedAppItem::SetBundleName(const std::string &bundleName) +{ + this->bundleName_ = bundleName; +} + +std::string SystemDefinedAppItem::GetAbilityName() const +{ + return this->abilityName_; +} + +void SystemDefinedAppItem::SetAbilityName(const std::string &abilityName) +{ + this->abilityName_ = abilityName; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/system_defined_form.cpp b/udmf/framework/innerkitsimpl/data/system_defined_form.cpp new file mode 100644 index 00000000..7714a329 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/system_defined_form.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "system_defined_form.h" + +namespace OHOS { +namespace UDMF { +SystemDefinedForm::SystemDefinedForm() +{ + this->dataType_ = SYSTEM_DEFINED_FORM; +} + +int64_t SystemDefinedForm::GetSize() +{ + return UnifiedDataUtils::GetDetailsSize(this->details_) + sizeof(formId_) + this->formName_.size() + + this->bundleName_.size() + this->abilityName_.size() + this->module_.size(); +} + +int32_t SystemDefinedForm::GetFormId() const +{ + return this->formId_; +} + +void SystemDefinedForm::SetFormId(const int32_t &formId) +{ + this->formId_ = formId; +} + +std::string SystemDefinedForm::GetFormName() const +{ + return this->formName_; +} + +void SystemDefinedForm::SetFormName(const std::string &formName) +{ + this->formName_ = formName; +} + +std::string SystemDefinedForm::GetBundleName() const +{ + return this->bundleName_; +} + +void SystemDefinedForm::SetBundleName(const std::string &bundleName) +{ + this->bundleName_ = bundleName; +} + +std::string SystemDefinedForm::GetAbilityName() const +{ + return this->abilityName_; +} + +void SystemDefinedForm::SetAbilityName(const std::string &abilityName) +{ + this->abilityName_ = abilityName; +} + +std::string SystemDefinedForm::GetModule() const +{ + return this->module_; +} + +void SystemDefinedForm::SetModule(const std::string &module) +{ + this->module_ = module; +} +} // namespace UDMF +} // namespace OHOS diff --git a/udmf/framework/innerkitsimpl/data/system_defined_pixelmap.cpp b/udmf/framework/innerkitsimpl/data/system_defined_pixelmap.cpp new file mode 100644 index 00000000..85660988 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/system_defined_pixelmap.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "system_defined_pixelmap.h" + +namespace OHOS { +namespace UDMF { +SystemDefinedPixelMap::SystemDefinedPixelMap() +{ + this->dataType_ = SYSTEM_DEFINED_PIXEL_MAP; +} + +SystemDefinedPixelMap::SystemDefinedPixelMap(std::vector<uint8_t> &data) +{ + this->dataType_ = SYSTEM_DEFINED_PIXEL_MAP; + this->rawData_ = std::move(data); +} + +int64_t SystemDefinedPixelMap::GetSize() +{ + return UnifiedDataUtils::GetDetailsSize(this->details_) + rawData_.size(); +} + +std::vector<uint8_t> SystemDefinedPixelMap::GetRawData() const +{ + return this->rawData_; +} + +void SystemDefinedPixelMap::SetRawData(const std::vector<uint8_t> &rawData) +{ + this->rawData_ = rawData; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/system_defined_record.cpp b/udmf/framework/innerkitsimpl/data/system_defined_record.cpp new file mode 100644 index 00000000..fe125ea6 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/system_defined_record.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "system_defined_record.h" + +namespace OHOS { +namespace UDMF { +SystemDefinedRecord::SystemDefinedRecord() : UnifiedRecord(SYSTEM_DEFINED_RECORD) +{ +} + +int64_t SystemDefinedRecord::GetSize() +{ + return UnifiedDataUtils::GetDetailsSize(this->details_); +} + +void SystemDefinedRecord::AddProperty(const std::string &property, UDVariant &value) +{ + auto it = details_.find(property); + if (it == details_.end()) { + details_.insert(std::make_pair(property, value)); + } else { + details_[property] = value; + } +} + +UDVariant SystemDefinedRecord::GetPropertyByName(const std::string &property) const +{ + auto it = details_.find(property); + if (it == details_.end()) { + return nullptr; + } + return it->second; +} + +void SystemDefinedRecord::SetDetails(UDDetails &details) +{ + this->details_ = details; +} + +UDDetails SystemDefinedRecord::GetDetails() const +{ + return this->details_; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/text.cpp b/udmf/framework/innerkitsimpl/data/text.cpp new file mode 100644 index 00000000..29aafc8e --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/text.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "text.h" + +namespace OHOS { +namespace UDMF { +Text::Text() : UnifiedRecord(TEXT) +{ +} + +Text::Text(UDDetails &variantMap) : UnifiedRecord(TEXT) +{ + this->details_ = variantMap; +} + +int64_t Text::GetSize() +{ + return UnifiedDataUtils::GetDetailsSize(this->details_); +} + +void Text::SetDetails(UDDetails &variantMap) +{ + this->details_ = variantMap; +} + +UDDetails Text::GetDetails() const +{ + return this->details_; +} +} // namespace UDMF +} // namespace OHOS diff --git a/udmf/framework/innerkitsimpl/data/unified_data.cpp b/udmf/framework/innerkitsimpl/data/unified_data.cpp new file mode 100644 index 00000000..7062a7e0 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/unified_data.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unified_data.h" + +namespace OHOS { +namespace UDMF { +int64_t UnifiedData::GetSize() +{ + int64_t totalSize = 0; + for (const auto &record : this->records_) { + totalSize += record->GetSize(); + } + return totalSize; +} + +std::string UnifiedData::GetGroupId() const +{ + return this->runtime_->key.groupId; +} + +std::shared_ptr<Runtime> UnifiedData::GetRuntime() const +{ + return this->runtime_; +} + +void UnifiedData::SetRuntime(Runtime &runtime) +{ + this->runtime_ = std::make_shared<Runtime>(runtime); +} + +void UnifiedData::AddRecord(const std::shared_ptr<UnifiedRecord> &record) +{ + if (record == nullptr) { + return; + } + this->records_.push_back(record); +} + +std::shared_ptr<UnifiedRecord> UnifiedData::GetRecordAt(std::size_t index) +{ + if (records_.size() > index) { + return records_[index]; + } + return nullptr; +} + +void UnifiedData::SetRecords(std::vector<std::shared_ptr<UnifiedRecord>> records) +{ + this->records_ = std::move(records); +} + +std::vector<std::shared_ptr<UnifiedRecord>> UnifiedData::GetRecords() const +{ + return this->records_; +} + +std::vector<UDType> UnifiedData::GetUDTypes() +{ + std::vector<UDType> typeSet; + for (const std::shared_ptr<UnifiedRecord> &record : records_) { + typeSet.push_back(record->GetType()); + } + return typeSet; +} + +bool UnifiedData::IsEmpty() const +{ + return records_.empty(); +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/unified_record.cpp b/udmf/framework/innerkitsimpl/data/unified_record.cpp new file mode 100644 index 00000000..a6d7eb08 --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/unified_record.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unified_record.h" + +namespace OHOS { +namespace UDMF { +UnifiedRecord::UnifiedRecord() +{ + dataType_ = UD_BUTT; +} + +UnifiedRecord::UnifiedRecord(UDType type) +{ + if (type < TEXT || type > UD_BUTT) { + dataType_ = UD_BUTT; + } + dataType_ = type; +} + +UDType UnifiedRecord::GetType() const +{ + return this->dataType_; +} + +void UnifiedRecord::SetType(const UDType &type) +{ + this->dataType_ = type; +} + +int64_t UnifiedRecord::GetSize() +{ + return 0; +} + +std::string UnifiedRecord::GetUid() const +{ + return this->uid_; +} + +void UnifiedRecord::SetUid(const std::string &id) +{ + this->uid_ = id; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/video.cpp b/udmf/framework/innerkitsimpl/data/video.cpp new file mode 100644 index 00000000..db247ebc --- /dev/null +++ b/udmf/framework/innerkitsimpl/data/video.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "video.h" + +namespace OHOS { +namespace UDMF { +Video::Video() : Video("") +{ +} + +Video::Video(const std::string &uri) : File(uri) +{ + this->dataType_ = VIDEO; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/test/fuzztest/BUILD.gn b/udmf/framework/innerkitsimpl/test/fuzztest/BUILD.gn new file mode 100644 index 00000000..f0423470 --- /dev/null +++ b/udmf/framework/innerkitsimpl/test/fuzztest/BUILD.gn @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +######################################################################################### +group("fuzztest") { + testonly = true + + deps = [ "udmfclient_fuzzer:fuzztest" ] +} diff --git a/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/BUILD.gn b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/BUILD.gn new file mode 100644 index 00000000..0d066a76 --- /dev/null +++ b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/BUILD.gn @@ -0,0 +1,67 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//build/config/features.gni") + +#####################hydra-fuzz################### +import("//build/test.gni") +import("//foundation/distributeddatamgr/udmf/udmf.gni") + +##############################fuzztest########################################## +ohos_fuzztest("UdmfClientFuzzTest") { + module_out_path = "udmf/innerkitsImpl" + + include_dirs = [ + "${udmf_interfaces_path}/innerkits/client", + "${udmf_interfaces_path}/innerkits/common", + "${udmf_interfaces_path}/innerkits/data", + "${udmf_framework_path}/common", + "${udmf_framework_path}/service", + ] + + fuzz_config_file = + "${udmf_framework_path}/innerkitsimpl/test/fuzztest/udmfclient_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ "udmf_client_fuzzer.cpp" ] + + deps = [ "${udmf_interfaces_path}/innerkits:udmf_client" ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "samgr:samgr_proxy", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + deps = [] + deps += [ + # deps file + ":UdmfClientFuzzTest", + ] +} +############################################################################### diff --git a/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/corpus/init b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/corpus/init new file mode 100644 index 00000000..2b595da0 --- /dev/null +++ b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/project.xml b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/project.xml new file mode 100644 index 00000000..4fdbc407 --- /dev/null +++ b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/project.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (c) 2023 Huawei Device Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<fuzz_config> + <fuzztest> + <!-- maximum length of a test input --> + <max_len>1000</max_len> + <!-- maximum total time in seconds to run the fuzzer --> + <max_total_time>300</max_total_time> + <!-- memory usage limit in Mb --> + <rss_limit_mb>4096</rss_limit_mb> + </fuzztest> +</fuzz_config> diff --git a/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.cpp b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.cpp new file mode 100644 index 00000000..179454fd --- /dev/null +++ b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.cpp @@ -0,0 +1,658 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "udmf_client_fuzzer.h" + +#include <unistd.h> + +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +#include "udmf_client.h" +#include "text.h" +#include "plain_text.h" +#include "html.h" +#include "link.h" +#include "file.h" +#include "image.h" +#include "video.h" +#include "system_defined_record.h" +#include "system_defined_form.h" +#include "system_defined_appitem.h" +#include "system_defined_pixelmap.h" + +using namespace OHOS; +using namespace OHOS::Security::AccessToken; +using namespace OHOS::UDMF; + +namespace OHOS { +void AllocHapToken() +{ + HapInfoParams info = { + .userID = 100, + .bundleName = "ohos.test.demo", + .instIndex = 0, + .appIDDesc = "ohos.test.demo" + }; + + HapPolicyParams policy = { + .apl = APL_NORMAL, + .domain = "test.domain", + .permList = { + { + .permissionName = "ohos.permission.test", + .bundleName = "ohos.test.demo", + .grantMode = 1, + .availableLevel = APL_NORMAL, + .label = "label", + .labelId = 1, + .description = "test", + .descriptionId = 1 + } + }, + .permStateList = { + { + .permissionName = "ohos.permission.test", + .isGeneral = true, + .resDeviceID = {"local"}, + .grantStatus = {PermissionState::PERMISSION_GRANTED}, + .grantFlags = {1} + } + } + }; + auto tokenID = AccessTokenKit::AllocHapToken(info, policy); + SetSelfTokenID(tokenID.tokenIDEx); +} + +void SetUpTestCase() +{ + AllocHapToken(); +} + +void TearDown() +{ +} + +void SetNativeToken() +{ + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, + .permsNum = 0, + .aclsNum = 0, + .dcaps = nullptr, + .perms = nullptr, + .acls = nullptr, + .processName = "msdp_sa", + .aplStr = "system_core", + }; + auto tokenId = GetAccessTokenId(&infoInstance); + SetSelfTokenID(tokenId); + AccessTokenKit::ReloadNativeTokenInfo(); +} + +void SetHapToken() +{ + auto tokenId = AccessTokenKit::GetHapTokenID(100, "ohos.test.demo", 0); + SetSelfTokenID(tokenId); +} + +void SetDataTextFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + std::string svalue(data, data + size); + UnifiedData unifiedData; + CustomOption option = {.intention = Intention::UD_INTENTION_BUTT}; + Text text; + UDDetails details; + details.insert({skey, svalue}); + text.SetDetails(details); + std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); + unifiedData.AddRecord(record); + std::string key; + UdmfClient::GetInstance().SetData(option, unifiedData, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void SetDataPlainTextFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData data1; + PlainText plainText1; + UDDetails details1; + details1.insert({skey, svalue}); + plainText1.SetDetails(details1); + plainText1.SetContent(svalue + "content"); + plainText1.SetAbstract(svalue + "abstract"); + plainText1.GetContent(); + plainText1.GetAbstract(); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText1); + data1.AddRecord(record1); + std::string key; + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void SetDataHtmlFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData data1; + std::string key; + Html html1; + UDDetails details1; + details1.insert({skey, svalue}); + html1.SetDetails(details1); + html1.SetHtmlContent(svalue + "htmlcontent"); + html1.SetPlainContent(svalue + "plainContent"); + html1.GetHtmlContent(); + html1.GetPlainContent(); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Html>(html1); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void SetDataLinkFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData data1; + std::string key; + Link link1; + UDDetails details1; + details1.insert({skey, svalue}); + link1.SetDetails(details1); + link1.SetUrl(svalue + "url"); + link1.SetDescription(svalue + "description"); + link1.GetUrl(); + link1.GetDescription(); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Link>(link1); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void SetDataFileFuzz(const uint8_t *data, size_t size) +{ + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData data1; + std::string key; + File file1; + file1.SetUri(svalue + "uri"); + file1.SetRemoteUri(svalue + "remoteUri"); + file1.GetUri(); + file1.GetRemoteUri(); + file1.GetSize(); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<File>(file1); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void SetDataImageFuzz(const uint8_t *data, size_t size) +{ + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData data1; + std::string key; + Image image1; + image1.SetUri(svalue + "uri"); + image1.SetRemoteUri(svalue + "remoteUri"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Image>(image1); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void SetDataVideoFuzz(const uint8_t *data, size_t size) +{ + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData data1; + std::string key; + Video video1; + video1.SetUri(svalue + "uri"); + video1.SetRemoteUri(svalue + "remoteUri"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Video>(video1); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void SetDataSystemDefinedRecordFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData data1; + std::string key; + SystemDefinedRecord systemDefinedRecord1; + UDDetails details1; + details1.insert({skey, svalue}); + systemDefinedRecord1.SetDetails(details1); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedRecord>(systemDefinedRecord1); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void SetDataSystemDefinedFormFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData data1; + std::string key; + SystemDefinedForm systemDefinedForm1; + UDDetails details1; + details1.insert({skey, svalue}); + systemDefinedForm1.SetDetails(details1); + auto formId = 123; + systemDefinedForm1.SetFormId(formId); + systemDefinedForm1.SetFormName(svalue + "formName"); + systemDefinedForm1.SetModule(svalue + "module"); + systemDefinedForm1.SetAbilityName(svalue + "abilityName"); + systemDefinedForm1.SetBundleName(svalue + "bundleName"); + systemDefinedForm1.GetFormId(); + systemDefinedForm1.GetFormName(); + systemDefinedForm1.GetBundleName(); + systemDefinedForm1.GetAbilityName(); + systemDefinedForm1.GetModule(); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedForm>(systemDefinedForm1); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void SetDataSystemDefinedAppItemFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData data1; + std::string key; + SystemDefinedAppItem systemDefinedAppItem1; + UDDetails details1; + details1.insert({skey, svalue}); + systemDefinedAppItem1.SetDetails(details1); + systemDefinedAppItem1.SetAppId(svalue + "appId"); + systemDefinedAppItem1.SetAppName(svalue + "appName"); + systemDefinedAppItem1.SetAppIconId(svalue + "appIconId"); + systemDefinedAppItem1.SetAppLabelId(svalue + "appLabelId"); + systemDefinedAppItem1.SetBundleName(svalue + "bundleName"); + systemDefinedAppItem1.SetAbilityName(svalue + "abilityName"); + systemDefinedAppItem1.GetAppId(); + systemDefinedAppItem1.GetAppName(); + systemDefinedAppItem1.GetBundleName(); + systemDefinedAppItem1.GetAbilityName(); + systemDefinedAppItem1.GetAppIconId(); + systemDefinedAppItem1.GetAppLabelId(); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedAppItem>(systemDefinedAppItem1); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void SetDataSystemDefinedPixelMapFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData data1; + std::string key; + SystemDefinedPixelMap systemDefinedPixelMap1; + UDDetails details1; + details1.insert({skey, svalue}); + systemDefinedPixelMap1.SetDetails(details1); + std::vector<uint8_t> rawData1 = {1, 2, 3, 4, 5}; + systemDefinedPixelMap1.SetRawData(rawData1); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedPixelMap>(systemDefinedPixelMap1); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetNativeToken(); + + QueryOption option2 = {.key = key}; + Privilege privilege; + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + UdmfClient::GetInstance().AddPrivilege(option2, privilege); + + SetHapToken(); + + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void GetSummaryFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + std::string svalue(data, data + size); + CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; + UnifiedData UData; + std::string key; + + UDDetails details; + details.insert({skey, svalue}); + + Text text; + text.SetDetails(details); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Text>(text); + UData.AddRecord(record1); + + PlainText plainText; + plainText.SetDetails(details); + plainText.SetContent(svalue + "content"); + plainText.SetAbstract(svalue + "abstract"); + std::shared_ptr<UnifiedRecord> record2 = std::make_shared<PlainText>(plainText); + UData.AddRecord(record2); + + File file; + file.SetUri(svalue + "uri"); + file.SetRemoteUri(svalue + "remoteUri"); + std::shared_ptr<UnifiedRecord> record3 = std::make_shared<File>(file); + UData.AddRecord(record3); + + Image image; + image.SetUri(svalue + "uri"); + image.SetRemoteUri(svalue + "remoteUri"); + std::shared_ptr<UnifiedRecord> record4 = std::make_shared<Image>(image); + UData.AddRecord(record4); + + SystemDefinedRecord systemDefinedRecord; + systemDefinedRecord.SetDetails(details); + std::shared_ptr<UnifiedRecord> record5 = std::make_shared<SystemDefinedRecord>(systemDefinedRecord); + UData.AddRecord(record5); + + SystemDefinedForm systemDefinedForm; + systemDefinedForm.SetDetails(details); + auto formId = 123; + systemDefinedForm.SetFormId(formId); + systemDefinedForm.SetFormName(svalue + "formName"); + systemDefinedForm.SetModule(svalue + "module"); + systemDefinedForm.SetAbilityName(svalue + "abilityName"); + systemDefinedForm.SetBundleName(svalue + "bundleName"); + std::shared_ptr<UnifiedRecord> record6 = std::make_shared<SystemDefinedForm>(systemDefinedForm); + UData.AddRecord(record6); + + UdmfClient::GetInstance().SetData(option1, UData, key); + + QueryOption option2 = {.key = key}; + Summary summary; + UdmfClient::GetInstance().GetSummary(option2, summary); + UnifiedData data2; + UdmfClient::GetInstance().GetData(option2, data2); +} + +void GetBatchDataByKeyFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; + UnifiedData data1; + std::string key; + PlainText plainText(skey, skey); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetHapToken(); + QueryOption option2 = { .key = key }; + std::vector<UnifiedData> dataSet2; + UdmfClient::GetInstance().GetBatchData(option2, dataSet2); + + SetHapToken(); + QueryOption option3 = { .key = skey }; + std::vector<UnifiedData> dataSet3; + UdmfClient::GetInstance().GetBatchData(option3, dataSet3); +} + +void GetBatchDataByIntentionFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; + UnifiedData data1; + std::string key; + PlainText plainText(skey, skey); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetHapToken(); + Intention intention = UnifiedDataUtils::GetIntentionByString(skey); + QueryOption option2 = { .intention = intention }; + std::vector<UnifiedData> dataSet; + UdmfClient::GetInstance().GetBatchData(option2, dataSet); +} + +void DeleteDataByKeyFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; + UnifiedData data1; + std::string key; + PlainText plainText(skey, skey); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetHapToken(); + QueryOption option2 = { .key = key }; + std::vector<UnifiedData> dataSet2; + UdmfClient::GetInstance().DeleteData(option2, dataSet2); + + SetHapToken(); + QueryOption option3 = { .key = skey }; + std::vector<UnifiedData> dataSet3; + UdmfClient::GetInstance().DeleteData(option3, dataSet3); +} + +void DeleteDataByIntentionFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; + UnifiedData data1; + std::string key; + PlainText plainText(skey, skey); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetHapToken(); + Intention intention = UnifiedDataUtils::GetIntentionByString(skey); + QueryOption option2 = { .intention = intention }; + std::vector<UnifiedData> dataSet; + UdmfClient::GetInstance().DeleteData(option2, dataSet); +} + +void UpdateDataFuzz(const uint8_t *data, size_t size) +{ + std::string skey(data, data + size); + CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; + UnifiedData data1; + std::string key; + PlainText plainText(skey, skey); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); + data1.AddRecord(record1); + UdmfClient::GetInstance().SetData(option1, data1, key); + + SetHapToken(); + UnifiedData data2; + PlainText plainText2(skey + "2", skey + "2"); + record1 = std::make_shared<PlainText>(plainText2); + data2.AddRecord(record1); + QueryOption option2 = { .key = key }; + UdmfClient::GetInstance().UpdateData(option2, data2); + + SetHapToken(); + UnifiedData data3; + PlainText plainText3(skey + "3", skey + "3"); + record1 = std::make_shared<PlainText>(plainText3); + data3.AddRecord(record1); + QueryOption option3 = { .key = skey }; + UdmfClient::GetInstance().UpdateData(option3, data3); +} +} + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Run your code on data */ + OHOS::SetUpTestCase(); + OHOS::SetDataFileFuzz(data, size); + OHOS::SetDataHtmlFuzz(data, size); + OHOS::SetDataImageFuzz(data, size); + OHOS::SetDataLinkFuzz(data, size); + OHOS::SetDataPlainTextFuzz(data, size); + OHOS::SetDataSystemDefinedAppItemFuzz(data, size); + OHOS::SetDataSystemDefinedFormFuzz(data, size); + OHOS::SetDataSystemDefinedPixelMapFuzz(data, size); + OHOS::SetDataSystemDefinedRecordFuzz(data, size); + OHOS::SetDataTextFuzz(data, size); + OHOS::SetDataVideoFuzz(data, size); + OHOS::GetSummaryFuzz(data, size); + OHOS::GetBatchDataByKeyFuzz(data, size); + OHOS::GetBatchDataByIntentionFuzz(data, size); + OHOS::DeleteDataByKeyFuzz(data, size); + OHOS::DeleteDataByIntentionFuzz(data, size); + OHOS::UpdateDataFuzz(data, size); + OHOS::TearDown(); + return 0; +} \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.h b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.h new file mode 100644 index 00000000..a535292c --- /dev/null +++ b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_UDMF_CLIENT_FUZZER_H +#define UDMF_UDMF_CLIENT_FUZZER_H + +#define FUZZ_PROJECT_NAME "udmfclient_fuzzer" + +#endif // UDMF_UDMF_CLIENT_FUZZER_H diff --git a/udmf/framework/innerkitsimpl/test/unittest/BUILD.gn b/udmf/framework/innerkitsimpl/test/unittest/BUILD.gn new file mode 100644 index 00000000..fae602a0 --- /dev/null +++ b/udmf/framework/innerkitsimpl/test/unittest/BUILD.gn @@ -0,0 +1,61 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//build/test.gni") +import("//foundation/distributeddatamgr/udmf/udmf.gni") + +module_output_path = "udmf/innerkitsImpl" + +############################################################################### +config("module_private_config") { + include_dirs = [ + "${udmf_interfaces_path}/innerkits/client", + "${udmf_interfaces_path}/innerkits/common", + "${udmf_interfaces_path}/innerkits/data", + "${udmf_framework_path}/common", + "${udmf_framework_path}/service", + ] +} + +common_deps = [ "${udmf_interfaces_path}/innerkits:udmf_client" ] + +common_external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "samgr:samgr_proxy", +] + +ohos_unittest("UdmfClientTest") { + module_out_path = module_output_path + + sources = [ "udmf_client_test.cpp" ] + + configs = [ ":module_private_config" ] + + deps = common_deps + + external_deps = common_external_deps +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [ ":UdmfClientTest" ] +} +############################################################################### diff --git a/udmf/framework/innerkitsimpl/test/unittest/udmf_client_test.cpp b/udmf/framework/innerkitsimpl/test/unittest/udmf_client_test.cpp new file mode 100644 index 00000000..ceb0b5ca --- /dev/null +++ b/udmf/framework/innerkitsimpl/test/unittest/udmf_client_test.cpp @@ -0,0 +1,1755 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +#include <unistd.h> + +#include "token_setproc.h" +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" + +#include "framework/common/logger.h" +#include "udmf_client.h" +#include "application_defined_record.h" +#include "audio.h" +#include "file.h" +#include "folder.h" +#include "html.h" +#include "image.h" +#include "link.h" +#include "plain_text.h" +#include "system_defined_appitem.h" +#include "system_defined_form.h" +#include "system_defined_pixelmap.h" +#include "system_defined_record.h" +#include "text.h" +#include "video.h" + +using namespace testing::ext; +using namespace OHOS::Security::AccessToken; +using namespace OHOS::UDMF; +using namespace OHOS; +namespace OHOS::Test { +class UdmfClientTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; + + void SetNativeToken(); + static void AllocHapToken1(); + static void AllocHapToken2(); + void SetHapToken1(); + void SetHapToken2(); + + void AddPrivilege(QueryOption &option); + void CompareDetails(const UDDetails &details); + void GetEmptyData(QueryOption &option); + + static constexpr int USER_ID = 100; + static constexpr int INST_INDEX = 0; +}; + +void UdmfClientTest::SetUpTestCase() +{ + AllocHapToken1(); + AllocHapToken2(); +} + +void UdmfClientTest::TearDownTestCase() +{ + auto tokenId = AccessTokenKit::GetHapTokenID(USER_ID, "ohos.test.demo1", INST_INDEX); + AccessTokenKit::DeleteToken(tokenId); + tokenId = AccessTokenKit::GetHapTokenID(USER_ID, "ohos.test.demo2", INST_INDEX); + AccessTokenKit::DeleteToken(tokenId); +} + +void UdmfClientTest::SetUp() +{ + SetHapToken1(); +} + +void UdmfClientTest::TearDown() +{ +} + +void UdmfClientTest::SetNativeToken() +{ + auto tokenId = AccessTokenKit::GetNativeTokenId("msdp_sa"); + SetSelfTokenID(tokenId); +} + +void UdmfClientTest::AllocHapToken1() +{ + HapInfoParams info = { + .userID = USER_ID, + .bundleName = "ohos.test.demo1", + .instIndex = INST_INDEX, + .appIDDesc = "ohos.test.demo1" + }; + + HapPolicyParams policy = { + .apl = APL_NORMAL, + .domain = "test.domain", + .permList = { + { + .permissionName = "ohos.permission.test", + .bundleName = "ohos.test.demo1", + .grantMode = 1, + .availableLevel = APL_NORMAL, + .label = "label", + .labelId = 1, + .description = "test1", + .descriptionId = 1 + } + }, + .permStateList = { + { + .permissionName = "ohos.permission.test", + .isGeneral = true, + .resDeviceID = { "local" }, + .grantStatus = { PermissionState::PERMISSION_GRANTED }, + .grantFlags = { 1 } + } + } + }; + auto tokenID = AccessTokenKit::AllocHapToken(info, policy); + SetSelfTokenID(tokenID.tokenIDEx); +} + +void UdmfClientTest::AllocHapToken2() +{ + HapInfoParams info = { + .userID = USER_ID, + .bundleName = "ohos.test.demo2", + .instIndex = INST_INDEX, + .appIDDesc = "ohos.test.demo2" + }; + + HapPolicyParams policy = { + .apl = APL_NORMAL, + .domain = "test.domain", + .permList = { + { + .permissionName = "ohos.permission.test", + .bundleName = "ohos.test.demo2", + .grantMode = 1, + .availableLevel = APL_NORMAL, + .label = "label", + .labelId = 1, + .description = "test2", + .descriptionId = 1 + } + }, + .permStateList = { + { + .permissionName = "ohos.permission.test", + .isGeneral = true, + .resDeviceID = { "local" }, + .grantStatus = { PermissionState::PERMISSION_GRANTED }, + .grantFlags = { 1 } + } + } + }; + auto tokenID = AccessTokenKit::AllocHapToken(info, policy); + SetSelfTokenID(tokenID.tokenIDEx); +} + +void UdmfClientTest::SetHapToken1() +{ + auto tokenId = AccessTokenKit::GetHapTokenID(USER_ID, "ohos.test.demo1", INST_INDEX); + SetSelfTokenID(tokenId); +} + +void UdmfClientTest::SetHapToken2() +{ + auto tokenId = AccessTokenKit::GetHapTokenID(USER_ID, "ohos.test.demo2", INST_INDEX); + SetSelfTokenID(tokenId); +} + +void UdmfClientTest::AddPrivilege(QueryOption &option) +{ + Privilege privilege; + privilege.tokenId = AccessTokenKit::GetHapTokenID(USER_ID, "ohos.test.demo2", INST_INDEX); + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + SetNativeToken(); + auto status = UdmfClient::GetInstance().AddPrivilege(option, privilege); + ASSERT_EQ(status, E_OK); +} + +void UdmfClientTest::CompareDetails(const UDDetails &details) +{ + for (const auto &detail : details) { + auto key = detail.first; + EXPECT_EQ(key, "udmf_key"); + auto value = detail.second; + auto str = std::get<std::string>(value); + EXPECT_EQ(str, "udmf_value"); + } +} + +void UdmfClientTest::GetEmptyData(QueryOption &option) +{ + UnifiedData data; + auto status = UdmfClient::GetInstance().GetData(option, data); + EXPECT_EQ(status, E_OK); + EXPECT_TRUE(data.IsEmpty()); +} + +/** +* @tc.name: SetData001 +* @tc.desc: Set data with invalid params +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData001 begin."); + + CustomOption option = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data; + std::string key; + auto status = UdmfClient::GetInstance().SetData(option, data, key); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option = { .intention = Intention::UD_INTENTION_BUTT }; + Text text; + UDDetails details; + details.insert({ "udmf_key", "udmf_value" }); + text.SetDetails(details); + std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); + data.AddRecord(record); + status = UdmfClient::GetInstance().SetData(option, data, key); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option = {}; + status = UdmfClient::GetInstance().SetData(option, data, key); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option = { .intention = Intention::UD_INTENTION_BASE }; + status = UdmfClient::GetInstance().SetData(option, data, key); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + LOG_INFO(UDMF_TEST, "SetData001 end."); +} + +/** +* @tc.name: SetData002 +* @tc.desc: Set Text record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData002, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData002 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + Text text1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + text1.SetDetails(details1); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Text>(text1); + data1.AddRecord(record1); + std::string key; + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + EXPECT_EQ(type, UDType::TEXT); + + auto text2 = static_cast<Text *>(record2.get()); + ASSERT_NE(text2, nullptr); + CompareDetails(text2->GetDetails()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData002 end."); +} + +/** +* @tc.name: SetData003 +* @tc.desc: Set PlainText record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData003, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData003 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + PlainText plainText1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + plainText1.SetDetails(details1); + plainText1.SetContent("content"); + plainText1.SetAbstract("abstract"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText1); + data1.AddRecord(record1); + std::string key; + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::PLAIN_TEXT); + + auto text2 = static_cast<Text *>(record2.get()); + ASSERT_NE(text2, nullptr); + CompareDetails(text2->GetDetails()); + + auto plainText2 = static_cast<PlainText *>(record2.get()); + ASSERT_NE(plainText2, nullptr); + EXPECT_EQ(plainText1.GetContent(), plainText2->GetContent()); + EXPECT_EQ(plainText1.GetAbstract(), plainText2->GetAbstract()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData003 end."); +} + +/** +* @tc.name: SetData004 +* @tc.desc: Set Html record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData004, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData004 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + Html html1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + html1.SetDetails(details1); + html1.SetHtmlContent("htmlcontent"); + html1.SetPlainContent("plainContent"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Html>(html1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::HTML); + + auto text2 = static_cast<Text *>(record2.get()); + ASSERT_NE(text2, nullptr); + CompareDetails(text2->GetDetails()); + + auto html2 = static_cast<Html *>(record2.get()); + ASSERT_NE(html2, nullptr); + EXPECT_EQ(html1.GetHtmlContent(), html2->GetHtmlContent()); + EXPECT_EQ(html1.GetPlainContent(), html2->GetPlainContent()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData004 end."); +} + +/** +* @tc.name: SetData005 +* @tc.desc: Set Link record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData005, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData005 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + Link link1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + link1.SetDetails(details1); + link1.SetUrl("url"); + link1.SetDescription("description"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Link>(link1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::HYPERLINK); + + auto text2 = static_cast<Text *>(record2.get()); + ASSERT_NE(text2, nullptr); + CompareDetails(text2->GetDetails()); + + auto link2 = static_cast<Link *>(record2.get()); + ASSERT_NE(link2, nullptr); + EXPECT_EQ(link1.GetUrl(), link2->GetUrl()); + EXPECT_EQ(link1.GetDescription(), link2->GetDescription()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData005 end."); +} + +/** +* @tc.name: SetData006 +* @tc.desc: Set File record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData006, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData006 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + File file1; + file1.SetRemoteUri("remoteUri"); + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + file1.SetDetails(details1); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<File>(file1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::FILE); + + auto file2 = static_cast<File *>(record2.get()); + ASSERT_NE(file2, nullptr); + EXPECT_EQ(file1.GetRemoteUri(), file2->GetRemoteUri()); + CompareDetails(file2->GetDetails()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData006 end."); +} + +/** +* @tc.name: SetData007 +* @tc.desc: Set Image record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData007, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData007 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + Image image1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + image1.SetDetails(details1); + image1.SetRemoteUri("remoteUri"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Image>(image1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::IMAGE); + + auto file2 = static_cast<File *>(record2.get()); + ASSERT_NE(file2, nullptr); + CompareDetails(file2->GetDetails()); + + auto image2 = static_cast<Image *>(record2.get()); + ASSERT_NE(image2, nullptr); + EXPECT_EQ(image1.GetRemoteUri(), image2->GetRemoteUri()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData007 end."); +} + +/** +* @tc.name: SetData008 +* @tc.desc: Set Video record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData008, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData008 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + Video video1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + video1.SetDetails(details1); + video1.SetRemoteUri("remoteUri"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Video>(video1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + EXPECT_EQ(type, UDType::VIDEO); + + auto file2 = static_cast<File *>(record2.get()); + ASSERT_NE(file2, nullptr); + CompareDetails(file2->GetDetails()); + + auto video2 = static_cast<Video *>(record2.get()); + ASSERT_NE(video2, nullptr); + EXPECT_EQ(video1.GetRemoteUri(), video2->GetRemoteUri()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData008 end."); +} + +/** +* @tc.name: SetData009 +* @tc.desc: Set Audio record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData009, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData009 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + Audio audio1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + audio1.SetDetails(details1); + audio1.SetRemoteUri("remoteUri"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Audio>(audio1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + EXPECT_EQ(type, UDType::AUDIO); + + auto file2 = static_cast<File *>(record2.get()); + ASSERT_NE(file2, nullptr); + CompareDetails(file2->GetDetails()); + + auto audio2 = static_cast<Audio *>(record2.get()); + ASSERT_NE(audio2, nullptr); + EXPECT_EQ(audio1.GetRemoteUri(), audio2->GetRemoteUri()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData009 end."); +} + +/** +* @tc.name: SetData010 +* @tc.desc: Set Folder record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData010, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData010 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + Folder folder1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + folder1.SetDetails(details1); + folder1.SetRemoteUri("remoteUri"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Folder>(folder1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + EXPECT_EQ(type, UDType::FOLDER); + + auto file2 = static_cast<File *>(record2.get()); + ASSERT_NE(file2, nullptr); + CompareDetails(file2->GetDetails()); + + auto folder2 = static_cast<Folder *>(record2.get()); + ASSERT_NE(folder2, nullptr); + EXPECT_EQ(folder1.GetRemoteUri(), folder2->GetRemoteUri()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData010 end."); +} + +/** +* @tc.name: SetData011 +* @tc.desc: Set SystemDefined record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData011, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData011 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + SystemDefinedRecord systemDefinedRecord1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + systemDefinedRecord1.SetDetails(details1); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedRecord>(systemDefinedRecord1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::SYSTEM_DEFINED_RECORD); + + auto systemDefinedRecord2 = static_cast<SystemDefinedRecord *>(record2.get()); + ASSERT_NE(systemDefinedRecord2, nullptr); + CompareDetails(systemDefinedRecord2->GetDetails()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData011 end."); +} + +/** +* @tc.name: SetData012 +* @tc.desc: Set Form record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData012, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData012 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + SystemDefinedForm systemDefinedForm1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + systemDefinedForm1.SetDetails(details1); + systemDefinedForm1.SetFormId(123); + systemDefinedForm1.SetFormName("formName"); + systemDefinedForm1.SetModule("module"); + systemDefinedForm1.SetAbilityName("abilityName"); + systemDefinedForm1.SetBundleName("bundleName"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedForm>(systemDefinedForm1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::SYSTEM_DEFINED_FORM); + + auto systemDefinedRecord2 = static_cast<SystemDefinedRecord *>(record2.get()); + ASSERT_NE(systemDefinedRecord2, nullptr); + CompareDetails(systemDefinedRecord2->GetDetails()); + + auto systemDefinedForm2 = static_cast<SystemDefinedForm *>(record2.get()); + ASSERT_NE(systemDefinedForm2, nullptr); + EXPECT_EQ(systemDefinedForm1.GetFormId(), systemDefinedForm2->GetFormId()); + EXPECT_EQ(systemDefinedForm1.GetFormName(), systemDefinedForm2->GetFormName()); + EXPECT_EQ(systemDefinedForm1.GetBundleName(), systemDefinedForm2->GetBundleName()); + EXPECT_EQ(systemDefinedForm1.GetAbilityName(), systemDefinedForm2->GetAbilityName()); + EXPECT_EQ(systemDefinedForm1.GetModule(), systemDefinedForm2->GetModule()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData012 end."); +} + +/** +* @tc.name: SetData013 +* @tc.desc: Set AppItem record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData013, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData013 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + SystemDefinedAppItem systemDefinedAppItem1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + systemDefinedAppItem1.SetDetails(details1); + systemDefinedAppItem1.SetAppId("appId"); + systemDefinedAppItem1.SetAppName("appName"); + systemDefinedAppItem1.SetAppIconId("appIconId"); + systemDefinedAppItem1.SetAppLabelId("appLabelId"); + systemDefinedAppItem1.SetBundleName("bundleName"); + systemDefinedAppItem1.SetAbilityName("abilityName"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedAppItem>(systemDefinedAppItem1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::SYSTEM_DEFINED_APP_ITEM); + + auto systemDefinedRecord2 = static_cast<SystemDefinedRecord *>(record2.get()); + ASSERT_NE(systemDefinedRecord2, nullptr); + CompareDetails(systemDefinedRecord2->GetDetails()); + + auto systemDefinedAppItem2 = static_cast<SystemDefinedAppItem *>(record2.get()); + ASSERT_NE(systemDefinedAppItem2, nullptr); + EXPECT_EQ(systemDefinedAppItem1.GetAppId(), systemDefinedAppItem2->GetAppId()); + EXPECT_EQ(systemDefinedAppItem1.GetAppName(), systemDefinedAppItem2->GetAppName()); + EXPECT_EQ(systemDefinedAppItem1.GetBundleName(), systemDefinedAppItem2->GetBundleName()); + EXPECT_EQ(systemDefinedAppItem1.GetAbilityName(), systemDefinedAppItem2->GetAbilityName()); + EXPECT_EQ(systemDefinedAppItem1.GetAppIconId(), systemDefinedAppItem2->GetAppIconId()); + EXPECT_EQ(systemDefinedAppItem1.GetAppLabelId(), systemDefinedAppItem2->GetAppLabelId()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData013 end."); +} + +/** +* @tc.name: SetData014 +* @tc.desc: Set PixelMap record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData014, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData014 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + SystemDefinedPixelMap systemDefinedPixelMap1; + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + systemDefinedPixelMap1.SetDetails(details1); + std::vector<uint8_t> rawData1 = { 1, 2, 3, 4, 5 }; + systemDefinedPixelMap1.SetRawData(rawData1); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedPixelMap>(systemDefinedPixelMap1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::SYSTEM_DEFINED_PIXEL_MAP); + + auto systemDefinedRecord2 = static_cast<SystemDefinedRecord *>(record2.get()); + ASSERT_NE(systemDefinedRecord2, nullptr); + CompareDetails(systemDefinedRecord2->GetDetails()); + + auto systemDefinedPixelMap2 = static_cast<SystemDefinedPixelMap *>(record2.get()); + ASSERT_NE(systemDefinedPixelMap2, nullptr); + auto rawData2 = systemDefinedPixelMap2->GetRawData(); + EXPECT_EQ(rawData1.size(), rawData2.size()); + for (uint32_t i = 0; i < rawData1.size(); ++i) { + EXPECT_EQ(rawData1[i], rawData2[i]); + } + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData014 end."); +} + +/** +* @tc.name: SetData015 +* @tc.desc: Set Application Defined record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData015, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData015 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + ApplicationDefinedRecord applicationDefinedRecord1; + applicationDefinedRecord1.SetApplicationDefinedType("applicationDefinedType"); + std::vector<uint8_t> rawData1 = { 1, 2, 3, 4, 5 }; + applicationDefinedRecord1.SetRawData(rawData1); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<ApplicationDefinedRecord>(applicationDefinedRecord1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken2(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::APPLICATION_DEFINED_RECORD); + + auto applicationDefinedRecord2 = static_cast<ApplicationDefinedRecord *>(record2.get()); + ASSERT_NE(applicationDefinedRecord2, nullptr); + EXPECT_EQ(applicationDefinedRecord1.GetApplicationDefinedType(), + applicationDefinedRecord2->GetApplicationDefinedType()); + auto rawData2 = applicationDefinedRecord2->GetRawData(); + EXPECT_EQ(rawData1.size(), rawData2.size()); + for (uint32_t i = 0; i < rawData1.size(); ++i) { + EXPECT_EQ(rawData1[i], rawData2[i]); + } + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "SetData015 end."); +} + +/** +* @tc.name: SetData016 +* @tc.desc: Set multiple record with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData016, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData016 begin."); + + CustomOption customOption = {.intention = Intention::UD_INTENTION_DRAG}; + std::string key; + UnifiedData inputData; + std::vector<std::shared_ptr<UnifiedRecord>> inputRecords = { + std::make_shared<Text>(), + std::make_shared<PlainText>(), + std::make_shared<File>(), + std::make_shared<Image>(), + std::make_shared<SystemDefinedRecord>(), + std::make_shared<SystemDefinedForm>(), + std::make_shared<ApplicationDefinedRecord>() + }; + inputData.SetRecords(inputRecords); + + auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); + ASSERT_EQ(status, E_OK); + + QueryOption queryOption = { .key = key }; + UnifiedData outputData; + status = UdmfClient::GetInstance().GetData(queryOption, outputData); + ASSERT_EQ(status, E_OK); + auto outputRecords = outputData.GetRecords(); + ASSERT_EQ(inputRecords.size(), outputRecords.size()); + for (size_t i = 0; i < outputRecords.size(); ++i) { + ASSERT_EQ(outputRecords[i]->GetType(), inputRecords[i]->GetType()); + } + + LOG_INFO(UDMF_TEST, "SetData016 end."); +} + +/** +* @tc.name: SetData017 +* @tc.desc: Set 512 records with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData017, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData017 begin."); + + CustomOption customOption = {.intention = Intention::UD_INTENTION_DRAG}; + std::string key; + UnifiedData inputData; + std::vector<std::shared_ptr<UnifiedRecord>> inputRecords; + for (int32_t i = 0; i < 512; ++i) { + inputRecords.emplace_back(std::make_shared<Text>()); + } + inputData.SetRecords(inputRecords); + + auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); + ASSERT_EQ(status, E_OK); + + QueryOption queryOption = { .key = key }; + UnifiedData outputData; + status = UdmfClient::GetInstance().GetData(queryOption, outputData); + ASSERT_EQ(status, E_OK); + auto outputRecords = outputData.GetRecords(); + ASSERT_EQ(inputRecords.size(), outputRecords.size()); + + LOG_INFO(UDMF_TEST, "SetData017 end."); +} + +/** +* @tc.name: SetData018 +* @tc.desc: Set one 2MB record of data with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData018, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData018 begin."); + + CustomOption customOption = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData inputData; + std::string key; + UDDetails details; + std::string value; + int64_t maxSize = 512 * 1024; + for (int64_t i = 0; i < maxSize; ++i) { + value += "11"; + } + details.insert({ value, value }); + Text text; + text.SetDetails(details); + std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); + inputData.AddRecord(record); + + auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); + ASSERT_EQ(status, E_OK); + + QueryOption queryOption = { .key = key }; + UnifiedData outputData; + status = UdmfClient::GetInstance().GetData(queryOption, outputData); + ASSERT_EQ(status, E_OK); + + LOG_INFO(UDMF_TEST, "SetData018 end."); +} + +/** +* @tc.name: SetData019 +* @tc.desc: Set one over 4MB record of data with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData019, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData019 begin."); + + CustomOption customOption = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData inputData; + std::string key; + UDDetails details; + std::string value; + int64_t maxSize = 512 * 1024; + for (int64_t i = 0; i < maxSize; ++i) { + value += "1111"; + } + details.insert({ value, value }); + details.insert({ "udmf_key", "udmf_value" }); + Text text; + text.SetDetails(details); + std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); + inputData.AddRecord(record); + + auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + LOG_INFO(UDMF_TEST, "SetData019 end."); +} + +/** +* @tc.name: SetData020 +* @tc.desc: Set two 2MB record of data with valid params and get data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData020, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData020 begin."); + + CustomOption customOption = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData inputData; + std::string key; + UDDetails details; + std::string value; + int64_t maxSize = 512 * 1024; + for (int64_t i = 0; i < maxSize; ++i) { + value += "11"; + } + details.insert({ value, value }); + Text text; + text.SetDetails(details); + std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); + for (int i = 0; i < 2; ++i) { + inputData.AddRecord(record); + } + auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); + ASSERT_EQ(status, E_OK); + + QueryOption queryOption = { .key = key }; + UnifiedData outputData; + status = UdmfClient::GetInstance().GetData(queryOption, outputData); + ASSERT_EQ(status, E_OK); + + LOG_INFO(UDMF_TEST, "SetData020 end."); +} + +/** +* @tc.name: GetData001 +* @tc.desc: Get data with invalid key +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, GetData001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "GetData001 begin."); + + QueryOption option; + UnifiedData data; + auto status = UdmfClient::GetInstance().GetData(option, data); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf"; + status = UdmfClient::GetInstance().GetData(option, data); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "odmf://"; + status = UdmfClient::GetInstance().GetData(option, data); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag"; + status = UdmfClient::GetInstance().GetData(option, data); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://123/bundle/group"; + status = UdmfClient::GetInstance().GetData(option, data); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle"; + status = UdmfClient::GetInstance().GetData(option, data); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle***/group"; + status = UdmfClient::GetInstance().GetData(option, data); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle/"; + status = UdmfClient::GetInstance().GetData(option, data); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle/group###"; + status = UdmfClient::GetInstance().GetData(option, data); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + LOG_INFO(UDMF_TEST, "GetData001 end."); +} + +/** +* @tc.name: GetSummary001 +* @tc.desc: Get summary data +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, GetSummary001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "GetSummary001 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data; + std::string key; + + UDDetails details; + details.insert({ "udmf_key", "udmf_value" }); + + Text text; + text.SetDetails(details); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Text>(text); + data.AddRecord(record1); + + PlainText plainText; + plainText.SetDetails(details); + plainText.SetContent("content"); + plainText.SetAbstract("abstract"); + std::shared_ptr<UnifiedRecord> record2 = std::make_shared<PlainText>(plainText); + data.AddRecord(record2); + + File file; + file.SetDetails(details); + file.SetUri("uri"); + file.SetRemoteUri("remoteUri"); + std::shared_ptr<UnifiedRecord> record3 = std::make_shared<File>(file); + data.AddRecord(record3); + + Image image; + file.SetDetails(details); + image.SetUri("uri"); + image.SetRemoteUri("remoteUri"); + std::shared_ptr<UnifiedRecord> record4 = std::make_shared<Image>(image); + data.AddRecord(record4); + + SystemDefinedRecord systemDefinedRecord; + systemDefinedRecord.SetDetails(details); + std::shared_ptr<UnifiedRecord> record5 = std::make_shared<SystemDefinedRecord>(systemDefinedRecord); + data.AddRecord(record5); + + SystemDefinedForm systemDefinedForm; + systemDefinedForm.SetDetails(details); + systemDefinedForm.SetFormId(123); + systemDefinedForm.SetFormName("formName"); + systemDefinedForm.SetModule("module"); + systemDefinedForm.SetAbilityName("abilityName"); + systemDefinedForm.SetBundleName("bundleName"); + std::shared_ptr<UnifiedRecord> record6 = std::make_shared<SystemDefinedForm>(systemDefinedForm); + data.AddRecord(record6); + + ApplicationDefinedRecord applicationDefinedRecord; + applicationDefinedRecord.SetApplicationDefinedType("applicationDefinedType"); + std::vector<uint8_t> rawData = { 1, 2, 3, 4, 5 }; + applicationDefinedRecord.SetRawData(rawData); + std::shared_ptr<UnifiedRecord> record7 = std::make_shared<ApplicationDefinedRecord>(applicationDefinedRecord); + data.AddRecord(record7); + + auto status = UdmfClient::GetInstance().SetData(option1, data, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + Summary summary; + status = UdmfClient::GetInstance().GetSummary(option2, summary); + + auto size = record1->GetSize(); + size += record2->GetSize(); + size += record3->GetSize(); + size += record4->GetSize(); + size += record5->GetSize(); + size += record6->GetSize(); + size += record7->GetSize(); + + ASSERT_EQ(status, E_OK); + ASSERT_EQ(summary.totalSize, size); + ASSERT_EQ(summary.summary["Text"], record1->GetSize()); + ASSERT_EQ(summary.summary["Text.PlainText"], record2->GetSize()); + ASSERT_EQ(summary.summary["File"], record3->GetSize()); + ASSERT_EQ(summary.summary["File.Media.Image"], record4->GetSize()); + ASSERT_EQ(summary.summary["SystemDefinedType"], record5->GetSize()); + ASSERT_EQ(summary.summary["SystemDefinedType.Form"], record6->GetSize()); + ASSERT_EQ(summary.summary["ApplicationDefinedType"], record7->GetSize()); + + LOG_INFO(UDMF_TEST, "GetSummary001 end."); +} + + +/** +* @tc.name: GetSummary002 +* @tc.desc: Get summary with invalid key +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, GetSummary002, TestSize.Level1) +{ + LOG_INFO(UDMF_FRAMEWORK, "GetSummary002 begin."); + + QueryOption option; + Summary summary; + auto status = UdmfClient::GetInstance().GetSummary(option, summary); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf"; + status = UdmfClient::GetInstance().GetSummary(option, summary); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "odmf://"; + status = UdmfClient::GetInstance().GetSummary(option, summary); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag"; + status = UdmfClient::GetInstance().GetSummary(option, summary); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://123/bundle/group"; + status = UdmfClient::GetInstance().GetSummary(option, summary); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle"; + status = UdmfClient::GetInstance().GetSummary(option, summary); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle***/group"; + status = UdmfClient::GetInstance().GetSummary(option, summary); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle/"; + status = UdmfClient::GetInstance().GetSummary(option, summary); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle/group###"; + status = UdmfClient::GetInstance().GetSummary(option, summary); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + LOG_INFO(UDMF_FRAMEWORK, "GetSummary002 end."); +} + +/** +* @tc.name: AddPrivilege001 +* @tc.desc: Add privilege with valid params +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, AddPrivilege001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "AddPrivilege001 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data; + Text text; + UDDetails details; + details.insert({ "udmf_key", "udmf_value" }); + text.SetDetails(details); + std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); + data.AddRecord(record); + std::string key; + auto status = UdmfClient::GetInstance().SetData(option1, data, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + Privilege privilege; + SetHapToken2(); + privilege.tokenId = AccessTokenKit::GetHapTokenID(100, "ohos.test.demo2", 0); + privilege.readPermission = "readPermission"; + privilege.writePermission = "writePermission"; + SetNativeToken(); + status = UdmfClient::GetInstance().AddPrivilege(option2, privilege); + ASSERT_EQ(status, E_OK); + + LOG_INFO(UDMF_TEST, "AddPrivilege001 end."); +} + +/** +* @tc.name: AddPrivilege002 +* @tc.desc: Add Privilege with invalid params +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, AddPrivilege002, TestSize.Level1) +{ + LOG_INFO(UDMF_FRAMEWORK, "AddPrivilege002 begin."); + + QueryOption option; + Privilege privilege; + auto status = UdmfClient::GetInstance().AddPrivilege(option, privilege); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf"; + status = UdmfClient::GetInstance().AddPrivilege(option, privilege); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "odmf://"; + status = UdmfClient::GetInstance().AddPrivilege(option, privilege); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag"; + status = UdmfClient::GetInstance().AddPrivilege(option, privilege); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://123/bundle/group"; + status = UdmfClient::GetInstance().AddPrivilege(option, privilege); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle"; + status = UdmfClient::GetInstance().AddPrivilege(option, privilege); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle***/group"; + status = UdmfClient::GetInstance().AddPrivilege(option, privilege); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle/"; + status = UdmfClient::GetInstance().AddPrivilege(option, privilege); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + option.key = "udmf://drag/bundle/group###"; + status = UdmfClient::GetInstance().AddPrivilege(option, privilege); + EXPECT_EQ(status, E_INVALID_PARAMETERS); + + LOG_INFO(UDMF_FRAMEWORK, "AddPrivilege002 end."); +} + +/** +* @tc.name: GetSelfData001 +* @tc.desc: Set File record with valid params and no add privilege and get data by self +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, GetSelfData001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "GetSelfData001 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + File file1; + file1.SetRemoteUri("remoteUri"); + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + file1.SetDetails(details1); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<File>(file1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::FILE); + + auto file2 = static_cast<File *>(record2.get()); + ASSERT_NE(file2, nullptr); + EXPECT_EQ(file1.GetRemoteUri(), file2->GetRemoteUri()); + CompareDetails(file2->GetDetails()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "GetSelfData001 end."); +} + +/** +* @tc.name: GetSelfData002 +* @tc.desc: Set File record with valid params and add privilege and get data by self +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, GetSelfData002, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "GetSelfData002 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data1; + std::string key; + File file1; + file1.SetRemoteUri("remoteUri"); + UDDetails details1; + details1.insert({ "udmf_key", "udmf_value" }); + file1.SetDetails(details1); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<File>(file1); + data1.AddRecord(record1); + auto status = UdmfClient::GetInstance().SetData(option1, data1, key); + ASSERT_EQ(status, E_OK); + + QueryOption option2 = { .key = key }; + AddPrivilege(option2); + SetHapToken1(); + UnifiedData data2; + status = UdmfClient::GetInstance().GetData(option2, data2); + ASSERT_EQ(status, E_OK); + + std::shared_ptr<UnifiedRecord> record2 = data2.GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::FILE); + + auto file2 = static_cast<File *>(record2.get()); + ASSERT_NE(file2, nullptr); + EXPECT_EQ(file1.GetRemoteUri(), file2->GetRemoteUri()); + CompareDetails(file2->GetDetails()); + + GetEmptyData(option2); + + LOG_INFO(UDMF_TEST, "GetSelfData002 end."); +} + +/** +* @tc.name: SetData021 +* @tc.desc: Set datas with intention ${UD_INTENTION_DATA_HUB} and manually check db is cleared before set or not +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, SetData021, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "SetData021 begin."); + QueryOption query = { .intention = Intention::UD_INTENTION_DATA_HUB }; + std::vector<UnifiedData> unifiedDataSet; + auto status = UdmfClient::GetInstance().DeleteData(query, unifiedDataSet); + ASSERT_EQ(status, E_OK); + unifiedDataSet.clear(); + status = UdmfClient::GetInstance().GetBatchData(query, unifiedDataSet); + ASSERT_EQ(status, E_OK); + ASSERT_TRUE(unifiedDataSet.empty()); + + CustomOption customOption = { .intention = Intention::UD_INTENTION_DATA_HUB }; + UnifiedData data1; + PlainText plainText1; + plainText1.SetContent("content1"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText1); + data1.AddRecord(record1); + std::string key; + status = UdmfClient::GetInstance().SetData(customOption, data1, key); + ASSERT_EQ(status, E_OK); + + UnifiedData data2; + PlainText plainText2; + plainText1.SetContent("content2"); + std::shared_ptr<UnifiedRecord> record2 = std::make_shared<PlainText>(plainText1); + data2.AddRecord(record2); + status = UdmfClient::GetInstance().SetData(customOption, data2, key); + ASSERT_EQ(status, E_OK); + + SetHapToken2(); + status = UdmfClient::GetInstance().GetBatchData(query, unifiedDataSet); + ASSERT_EQ(status, E_OK); + auto size = static_cast<int32_t>(unifiedDataSet.size()); + ASSERT_EQ(size, 2); + LOG_INFO(UDMF_TEST, "SetData021 end."); +} + +/** +* @tc.name: UpdateData001 +* @tc.desc: Update data with invalid params +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, UpdateData001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "UpdateData001 begin."); + + UnifiedData data; + QueryOption queryOption = { .key = "" }; + auto status = UdmfClient::GetInstance().UpdateData(queryOption, data); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + queryOption = { .key = "udmf://drag/ohos.test.demo1/abcde" }; + status = UdmfClient::GetInstance().UpdateData(queryOption, data); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + CustomOption customOption = { .intention = Intention::UD_INTENTION_DATA_HUB }; + UnifiedData data1; + PlainText plainText1; + plainText1.SetContent("content1"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText1); + data1.AddRecord(record1); + std::string key; + status = UdmfClient::GetInstance().SetData(customOption, data1, key); + ASSERT_EQ(status, E_OK); + + queryOption = { .key = key }; + SetHapToken2(); + status = UdmfClient::GetInstance().UpdateData(queryOption, data); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + LOG_INFO(UDMF_TEST, "UpdateData001 end."); +} + +/** +* @tc.name: UpdateData002 +* @tc.desc: Update data with valid params +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, UpdateData002, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "UpdateData002 begin."); + + UnifiedData data; + PlainText plainText; + plainText.SetContent("content"); + std::shared_ptr<UnifiedRecord> record = std::make_shared<PlainText>(plainText); + data.AddRecord(record); + + CustomOption customOption = { .intention = Intention::UD_INTENTION_DATA_HUB }; + UnifiedData data1; + PlainText plainText1; + plainText1.SetContent("content1"); + std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText1); + data1.AddRecord(record1); + std::string key; + auto status = UdmfClient::GetInstance().SetData(customOption, data1, key); + + ASSERT_EQ(status, E_OK); + QueryOption queryOption = { .key = key }; + SetHapToken2(); + status = UdmfClient::GetInstance().UpdateData(queryOption, data); + ASSERT_EQ(status, E_OK); + + std::vector<UnifiedData> dataSet; + status = UdmfClient::GetInstance().GetBatchData(queryOption, dataSet); + std::shared_ptr<UnifiedRecord> record2 = dataSet[0].GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::PLAIN_TEXT); + auto plainText2 = static_cast<PlainText *>(record2.get()); + ASSERT_EQ(plainText2->GetContent(), "content"); + + LOG_INFO(UDMF_TEST, "UpdateData002 end."); +} + +/** +* @tc.name: QueryData001 +* @tc.desc: Query data with invalid params +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, QueryData001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "QueryData001 begin."); + std::vector<UnifiedData> unifiedDataSet; + QueryOption queryOption = {}; + auto status = UdmfClient::GetInstance().GetBatchData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + queryOption = { .key = "udmf://drag/ohos.test.demo1/abcde" }; + status = UdmfClient::GetInstance().GetBatchData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + queryOption = { .intention = UD_INTENTION_DRAG }; + status = UdmfClient::GetInstance().GetBatchData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + queryOption = { .key = "udmf://DataHub/ohos.test.demo1/abcde", .intention = UD_INTENTION_DRAG }; + status = UdmfClient::GetInstance().GetBatchData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + queryOption = { .key = "udmf://drag/ohos.test.demo1/abcde", .intention = UD_INTENTION_DATA_HUB }; + status = UdmfClient::GetInstance().GetBatchData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + LOG_INFO(UDMF_TEST, "QueryData001 end."); +} + +/** +* @tc.name: QueryData002 +* @tc.desc: Query data with valid params +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, QueryData002, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "QueryData002 begin."); + + QueryOption query = { .intention = Intention::UD_INTENTION_DATA_HUB }; + std::vector<UnifiedData> unifiedDataSet; + auto status = UdmfClient::GetInstance().DeleteData(query, unifiedDataSet); + ASSERT_EQ(status, E_OK); + unifiedDataSet.clear(); + status = UdmfClient::GetInstance().GetBatchData(query, unifiedDataSet); + ASSERT_EQ(status, E_OK); + ASSERT_TRUE(unifiedDataSet.empty()); + + CustomOption customOption = { .intention = Intention::UD_INTENTION_DATA_HUB }; + UnifiedData data; + PlainText plainText; + plainText.SetContent("content1"); + std::shared_ptr<UnifiedRecord> record = std::make_shared<PlainText>(plainText); + data.AddRecord(record); + std::string key; + status = UdmfClient::GetInstance().SetData(customOption, data, key); + ASSERT_EQ(status, E_OK); + + query = { .key = key }; + status = UdmfClient::GetInstance().GetBatchData(query, unifiedDataSet); + ASSERT_EQ(status, E_OK); + auto size = static_cast<int32_t>(unifiedDataSet.size()); + ASSERT_EQ(size, 1); + std::shared_ptr<UnifiedRecord> record2 = unifiedDataSet[0].GetRecordAt(0); + ASSERT_NE(record2, nullptr); + auto type = record2->GetType(); + ASSERT_EQ(type, UDType::PLAIN_TEXT); + auto plainText2 = static_cast<PlainText *>(record2.get()); + ASSERT_EQ(plainText2->GetContent(), "content1"); + + UnifiedData data2; + plainText.SetContent("content2"); + record = std::make_shared<PlainText>(plainText); + data2.AddRecord(record); + status = UdmfClient::GetInstance().SetData(customOption, data2, key); + ASSERT_EQ(status, E_OK); + + unifiedDataSet.clear(); + query = { .key = key, .intention = UD_INTENTION_DATA_HUB }; + status = UdmfClient::GetInstance().GetBatchData(query, unifiedDataSet); + ASSERT_EQ(status, E_OK); + size = static_cast<int32_t>(unifiedDataSet.size()); + ASSERT_EQ(size, 1); + record2 = unifiedDataSet[0].GetRecordAt(0); + ASSERT_NE(record2, nullptr); + type = record2->GetType(); + ASSERT_EQ(type, UDType::PLAIN_TEXT); + plainText2 = static_cast<PlainText *>(record2.get()); + ASSERT_EQ(plainText2->GetContent(), "content2"); + + unifiedDataSet.clear(); + query = { .intention = UD_INTENTION_DATA_HUB }; + status = UdmfClient::GetInstance().GetBatchData(query, unifiedDataSet); + ASSERT_EQ(status, E_OK); + size = static_cast<int32_t>(unifiedDataSet.size()); + ASSERT_EQ(size, 2); + + LOG_INFO(UDMF_TEST, "QueryData002 end."); +} + +/** +* @tc.name: DeleteData001 +* @tc.desc: Delete data with invalid params +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, DeleteData001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "DeleteData001 begin."); + std::vector<UnifiedData> unifiedDataSet; + QueryOption queryOption = {}; + auto status = UdmfClient::GetInstance().DeleteData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + queryOption = { .key = "udmf://drag/ohos.test.demo1/abcde" }; + status = UdmfClient::GetInstance().DeleteData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + queryOption = { .intention = UD_INTENTION_DRAG }; + status = UdmfClient::GetInstance().DeleteData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + queryOption = { .key = "udmf://DataHub/ohos.test.demo1/abcde", .intention = UD_INTENTION_DRAG }; + status = UdmfClient::GetInstance().DeleteData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + + queryOption = { .key = "udmf://drag/ohos.test.demo1/abcde", .intention = UD_INTENTION_DATA_HUB }; + status = UdmfClient::GetInstance().DeleteData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_INVALID_PARAMETERS); + LOG_INFO(UDMF_TEST, "DeleteData001 end."); +} + +/** +* @tc.name: DeleteData002 +* @tc.desc: Delete data with valid params +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, DeleteData002, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "DeleteData002 begin."); + + CustomOption customOption = { .intention = UD_INTENTION_DATA_HUB }; + UnifiedData data; + PlainText plainText; + plainText.SetContent("content1"); + std::shared_ptr<UnifiedRecord> record = std::make_shared<PlainText>(plainText); + data.AddRecord(record); + std::string key; + auto status = UdmfClient::GetInstance().SetData(customOption, data, key); + ASSERT_EQ(status, E_OK); + status = UdmfClient::GetInstance().SetData(customOption, data, key); + ASSERT_EQ(status, E_OK); + status = UdmfClient::GetInstance().SetData(customOption, data, key); + ASSERT_EQ(status, E_OK); + + QueryOption queryOption = { .key = key }; + SetHapToken2(); + + std::vector<UnifiedData> unifiedDataSet; + status = UdmfClient::GetInstance().DeleteData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_OK); + + unifiedDataSet.clear(); + status = UdmfClient::GetInstance().GetBatchData(queryOption, unifiedDataSet); + ASSERT_TRUE(unifiedDataSet.empty()); + + queryOption = { .intention = UD_INTENTION_DATA_HUB }; + unifiedDataSet.clear(); + status = UdmfClient::GetInstance().GetBatchData(queryOption, unifiedDataSet); + ASSERT_TRUE(!unifiedDataSet.empty()); + + status = UdmfClient::GetInstance().DeleteData(queryOption, unifiedDataSet); + ASSERT_EQ(status, E_OK); + + unifiedDataSet.clear(); + status = UdmfClient::GetInstance().GetBatchData(queryOption, unifiedDataSet); + ASSERT_TRUE(unifiedDataSet.empty()); + LOG_INFO(UDMF_TEST, "DeleteData002 end."); +} +} // OHOS::Test \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/common/napi_data_utils.cpp b/udmf/framework/jskitsimpl/common/napi_data_utils.cpp new file mode 100644 index 00000000..8ec95699 --- /dev/null +++ b/udmf/framework/jskitsimpl/common/napi_data_utils.cpp @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "napi_data_utils.h" + +#include "napi_queue.h" + +namespace OHOS { +namespace UDMF { +constexpr int32_t STR_MAX_LENGTH = 4096; +constexpr size_t STR_TAIL_LENGTH = 1; + +/* napi_value <-> bool */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, bool &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- bool"); + return napi_get_value_bool(env, in, &out); +} + +napi_status NapiDataUtils::SetValue(napi_env env, const bool &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> bool"); + return napi_get_boolean(env, in, &out); +} + +/* napi_value <-> int32_t */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, int32_t &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> int32_t"); + return napi_get_value_int32(env, in, &out); +} + +napi_status NapiDataUtils::SetValue(napi_env env, const int32_t &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- int32_t"); + return napi_create_int32(env, in, &out); +} + +/* napi_value <-> int64_t */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, int64_t &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> int64_t"); + return napi_get_value_int64(env, in, &out); +} + +napi_status NapiDataUtils::SetValue(napi_env env, const int64_t &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- int64_t"); + return napi_create_int64(env, in, &out); +} + +/* napi_value <-> float */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, float &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> float"); + double tmp; + napi_status status = napi_get_value_double(env, in, &tmp); + out = tmp; + return status; +} + +napi_status NapiDataUtils::SetValue(napi_env env, const float &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- float"); + double tmp = in; + return napi_create_double(env, tmp, &out); +} + +/* napi_value <-> double */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, double &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> double"); + return napi_get_value_double(env, in, &out); +} + +napi_status NapiDataUtils::SetValue(napi_env env, const double &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- double"); + return napi_create_double(env, in, &out); +} + +/* napi_value <-> std::string */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::string &out) +{ + size_t maxLen = STR_MAX_LENGTH; + napi_status status = napi_get_value_string_utf8(env, in, NULL, 0, &maxLen); + if (maxLen == 0) { + GET_AND_THROW_LAST_ERROR(env); + return status; + } + char *buf = new (std::nothrow) char[maxLen + STR_TAIL_LENGTH]; + if (buf != nullptr) { + size_t len = 0; + status = napi_get_value_string_utf8(env, in, buf, maxLen + STR_TAIL_LENGTH, &len); + if (status != napi_ok) { + GET_AND_THROW_LAST_ERROR(env); + } + buf[len] = 0; + out = std::string(buf); + delete[] buf; + } else { + status = napi_generic_failure; + } + return status; +} + +napi_status NapiDataUtils::SetValue(napi_env env, const std::string &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::string %{public}d", (int)in.length()); + return napi_create_string_utf8(env, in.c_str(), in.size(), &out); +} + +/* napi_value <-> std::vector<std::string> */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::vector<std::string> &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::vector<std::string>"); + bool isArray = false; + napi_is_array(env, in, &isArray); + LOG_ERROR_RETURN(isArray, "not an array", napi_invalid_arg); + + uint32_t length = 0; + napi_status status = napi_get_array_length(env, in, &length); + LOG_ERROR_RETURN((status == napi_ok) && (length > 0), "get_array failed!", napi_invalid_arg); + for (uint32_t i = 0; i < length; ++i) { + napi_value item = nullptr; + status = napi_get_element(env, in, i, &item); + LOG_ERROR_RETURN((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg); + std::string value; + status = GetValue(env, item, value); + LOG_ERROR_RETURN(status == napi_ok, "not a string", napi_invalid_arg); + out.push_back(value); + } + return status; +} + +napi_status NapiDataUtils::SetValue(napi_env env, const std::vector<std::string> &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::vector<std::string>"); + napi_status status = napi_create_array_with_length(env, in.size(), &out); + LOG_ERROR_RETURN(status == napi_ok, "create array failed!", status); + int index = 0; + for (auto &item : in) { + napi_value element = nullptr; + SetValue(env, item, element); + status = napi_set_element(env, out, index++, element); + LOG_ERROR_RETURN((status == napi_ok), "napi_set_element failed!", status); + } + return status; +} + +/* napi_value <-> std::vector<uint8_t> */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::vector<uint8_t> &out) +{ + out.clear(); + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::vector<uint8_t> "); + napi_typedarray_type type = napi_biguint64_array; + size_t length = 0; + napi_value buffer = nullptr; + size_t offset = 0; + void *data = nullptr; + napi_status status = napi_get_typedarray_info(env, in, &type, &length, &data, &buffer, &offset); + LOG_DEBUG(UDMF_KITS_NAPI, "array type=%{public}d length=%{public}d offset=%{public}d status=%{public}d", + (int)type, (int)length, (int)offset, status); + LOG_ERROR_RETURN(status == napi_ok, "napi_get_typedarray_info failed!", napi_invalid_arg); + LOG_ERROR_RETURN(type == napi_uint8_array, "is not Uint8Array!", napi_invalid_arg); + LOG_ERROR_RETURN((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg); + out.assign(reinterpret_cast<uint8_t *>(data), reinterpret_cast<uint8_t *>(data) + length); + return status; +} + +napi_status NapiDataUtils::SetValue(napi_env env, const std::vector<uint8_t> &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::vector<uint8_t> "); + LOG_ERROR_RETURN(in.size() > 0, "invalid std::vector<uint8_t>", napi_invalid_arg); + void *data = nullptr; + napi_value buffer = nullptr; + napi_status status = napi_create_arraybuffer(env, in.size(), &data, &buffer); + LOG_ERROR_RETURN((status == napi_ok), "create array buffer failed!", status); + + if (memcpy_s(data, in.size(), in.data(), in.size()) != EOK) { + LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s not EOK"); + return napi_invalid_arg; + } + status = napi_create_typedarray(env, napi_uint8_array, in.size(), buffer, 0, &out); + LOG_ERROR_RETURN((status == napi_ok), "napi_value <- std::vector<uint8_t> invalid value", status); + return status; +} + +/* napi_value <-> std::map<std::string, int32_t> */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::map<std::string, int32_t> &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::map<std::string, int32_t> "); + (void)(env); + (void)(in); + (void)(out); + LOG_ERROR_RETURN(false, "std::map<std::string, uint32_t> from napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; +} + +napi_status NapiDataUtils::SetValue(napi_env env, const std::map<std::string, int32_t> &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::map<std::string, int32_t> "); + napi_status status = napi_create_array_with_length(env, in.size(), &out); + LOG_ERROR_RETURN((status == napi_ok), "invalid object", status); + int index = 0; + for (const auto &[key, value] : in) { + napi_value element = nullptr; + napi_create_array_with_length(env, TUPLE_SIZE, &element); + napi_value jsKey = nullptr; + napi_create_string_utf8(env, key.c_str(), key.size(), &jsKey); + napi_set_element(env, element, TUPLE_KEY, jsKey); + napi_value jsValue = nullptr; + napi_create_int32(env, static_cast<int32_t>(value), &jsValue); + napi_set_element(env, element, TUPLE_VALUE, jsValue); + napi_set_element(env, out, index++, element); + } + return status; +} + +/* napi_value <-> std::map<std::string, int64_t> */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::map<std::string, int64_t> &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> std::map<std::string, int64_t> "); + (void)(env); + (void)(in); + (void)(out); + LOG_ERROR_RETURN(false, "std::map<std::string, int64_t> from napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; +} + +napi_status NapiDataUtils::SetValue(napi_env env, const std::map<std::string, int64_t> &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- std::map<std::string, int64_t> "); + napi_status status = napi_create_array_with_length(env, in.size(), &out); + LOG_ERROR_RETURN((status == napi_ok), "invalid object", status); + int index = 0; + for (const auto &[key, value] : in) { + napi_value element = nullptr; + napi_create_array_with_length(env, TUPLE_SIZE, &element); + napi_value jsKey = nullptr; + napi_create_string_utf8(env, key.c_str(), key.size(), &jsKey); + napi_set_element(env, element, TUPLE_KEY, jsKey); + napi_value jsValue = nullptr; + napi_create_int64(env, static_cast<int64_t>(value), &jsValue); + napi_set_element(env, element, TUPLE_VALUE, jsValue); + napi_set_element(env, out, index++, element); + } + return status; +} + +/* napi_value <-> UDVariant */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, UDVariant &out) +{ + napi_valuetype type = napi_undefined; + napi_status status = napi_typeof(env, in, &type); + LOG_ERROR_RETURN((status == napi_ok), "invalid type", status); + switch (type) { + case napi_boolean: { + bool vBool = false; + status = GetValue(env, in, vBool); + out = vBool; + break; + } + case napi_number: { + double vNum = 0.0f; + status = GetValue(env, in, vNum); + out = vNum; + break; + } + case napi_string: { + std::string vString; + status = GetValue(env, in, vString); + out = vString; + break; + } + case napi_object: { + std::vector<uint8_t> vct; + status = GetValue(env, in, vct); + out = vct; + break; + } + default: + LOG_ERROR(UDMF_KITS_NAPI, + "napi_value <- UDVariant not [Uint8Array | string | boolean | number] type=%{public}d", type); + status = napi_invalid_arg; + break; + } + return status; +} + +napi_status NapiDataUtils::SetValue(napi_env env, const UDVariant &in, napi_value &out) +{ + auto strValue = std::get_if<std::string>(&in); + if (strValue != nullptr) { + return SetValue(env, *strValue, out); + } + auto intValue = std::get_if<int32_t>(&in); + if (intValue != nullptr) { + return SetValue(env, *intValue, out); + } + auto pUint8 = std::get_if<std::vector<uint8_t>>(&in); + if (pUint8 != nullptr) { + return SetValue(env, *pUint8, out); + } + auto boolValue = std::get_if<bool>(&in); + if (boolValue != nullptr) { + return SetValue(env, *boolValue, out); + } + auto dblValue = std::get_if<double>(&in); + if (dblValue != nullptr) { + return SetValue(env, *dblValue, out); + } + + LOG_ERROR(UDMF_KITS_NAPI, "napi_value <- UDVariant INVALID value type"); + return napi_invalid_arg; +} + +/* napi_value <-> UDDetails */ +napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, UDDetails &out) +{ + if (!IsTypeForNapiValue(env, in, napi_object)) { + return napi_invalid_arg; + } + napi_value jsProNameList = nullptr; + uint32_t jsProCount = 0; + + NAPI_CALL_BASE(env, napi_get_property_names(env, in, &jsProNameList), napi_invalid_arg); + NAPI_CALL_BASE(env, napi_get_array_length(env, jsProNameList, &jsProCount), napi_invalid_arg); + + napi_value jsProName = nullptr; + napi_value jsProValue = nullptr; + for (uint32_t index = 0; index < jsProCount; index++) { + NAPI_CALL_BASE(env, napi_get_element(env, jsProNameList, index, &jsProName), napi_invalid_arg); + if (!IsTypeForNapiValue(env, jsProName, napi_string)) { + return napi_invalid_arg; + } + std::string strProName; + GetValue(env, jsProName, strProName); + + NAPI_CALL_BASE(env, napi_get_named_property(env, in, strProName.c_str(), &jsProValue), napi_invalid_arg); + UDVariant natValue; + GetValue(env, jsProValue, natValue); + out[strProName] = natValue; + } + return napi_ok; +} + +napi_status NapiDataUtils::SetValue(napi_env env, const UDDetails &in, napi_value &out) +{ + NAPI_CALL_BASE(env, napi_create_object(env, &out), napi_invalid_arg); + for (std::pair<std::string, UDVariant> prop : in) { + napi_value jsProValue = nullptr; + SetValue(env, prop.second, jsProValue); + NAPI_CALL_BASE(env, napi_set_named_property(env, out, prop.first.c_str(), jsProValue), napi_invalid_arg); + } + return napi_ok; +} + +bool NapiDataUtils::IsTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType) +{ + napi_valuetype valueType = napi_undefined; + + if (param == nullptr) { + return false; + } + + if (napi_typeof(env, param, &valueType) != napi_ok) { + return false; + } + + return valueType == expectType; +} + +bool NapiDataUtils::IsNull(napi_env env, napi_value value) +{ + napi_valuetype type = napi_undefined; + napi_status status = napi_typeof(env, value, &type); + if (status == napi_ok && (type == napi_undefined || type == napi_null)) { + return true; + } + if (type == napi_string) { + size_t len; + status = napi_get_value_string_utf8(env, value, NULL, 0, &len); + return len == 0; + } + return false; +} + +napi_value NapiDataUtils::DefineClass(napi_env env, const std::string &name, + const napi_property_descriptor *properties, size_t count, napi_callback newcb) +{ + // base64("data.udmf") as rootPropName, i.e. global.<root> + const std::string rootPropName = "ZGF0YS51ZG1m"; + napi_value root = nullptr; + bool hasRoot = false; + napi_value global = nullptr; + napi_get_global(env, &global); + napi_has_named_property(env, global, rootPropName.c_str(), &hasRoot); + if (hasRoot) { + napi_get_named_property(env, global, rootPropName.c_str(), &root); + } else { + napi_create_object(env, &root); + napi_set_named_property(env, global, rootPropName.c_str(), root); + } + + std::string propName = "constructor_of_" + name; + napi_value constructor = nullptr; + bool hasProp = false; + napi_has_named_property(env, root, propName.c_str(), &hasProp); + if (hasProp) { + napi_get_named_property(env, root, propName.c_str(), &constructor); + if (constructor != nullptr) { + LOG_DEBUG(UDMF_KITS_NAPI, "got data.distributeddata.%{public}s as constructor", propName.c_str()); + return constructor; + } + hasProp = false; // no constructor. + } + + NAPI_CALL_BASE(env, + napi_define_class(env, name.c_str(), name.size(), newcb, nullptr, count, properties, &constructor), + nullptr); + NAPI_ASSERT(env, constructor != nullptr, "napi_define_class failed!"); + + if (!hasProp) { + napi_set_named_property(env, root, propName.c_str(), constructor); + LOG_DEBUG(UDMF_KITS_NAPI, "save constructor to data.distributeddata.%{public}s", propName.c_str()); + } + return constructor; +} +} // namespace UDMF +} // namespace OHOS diff --git a/udmf/framework/jskitsimpl/common/napi_error_utils.cpp b/udmf/framework/jskitsimpl/common/napi_error_utils.cpp new file mode 100644 index 00000000..6b43b7e3 --- /dev/null +++ b/udmf/framework/jskitsimpl/common/napi_error_utils.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "napi_error_utils.h" + +#include <algorithm> + +namespace OHOS { +namespace UDMF { +using NapiErrorCode = OHOS::UDMF::NapiErrorCode; + +static const NapiErrorCode JS_ERROR_CODE_MSGS[] = { + { Status::E_NO_PERMISSION, 201, "Permission denied!" }, + { Status::E_INVALID_PARAMETERS, 401, "Parameter error." }, +}; + +const std::optional<NapiErrorCode> GetErrorCode(int32_t errorCode) +{ + auto napiErrorCode = NapiErrorCode{ errorCode, -1, "" }; + auto iter = std::lower_bound(JS_ERROR_CODE_MSGS, + JS_ERROR_CODE_MSGS + sizeof(JS_ERROR_CODE_MSGS) / sizeof(JS_ERROR_CODE_MSGS[0]), napiErrorCode, + [](const NapiErrorCode &napiErrorCode1, const NapiErrorCode &napiErrorCode2) { + return napiErrorCode1.status < napiErrorCode2.status; + }); + if (iter < JS_ERROR_CODE_MSGS + sizeof(JS_ERROR_CODE_MSGS) / sizeof(JS_ERROR_CODE_MSGS[0]) && + iter->status == errorCode) { + return *iter; + } + return std::nullopt; +} + +Status GenerateNapiError(Status error, int32_t &errCode, std::string &errMessage) +{ + auto errormsg = GetErrorCode(error); + if (errormsg.has_value()) { + auto napiError = errormsg.value(); + errCode = napiError.jsCode; + errMessage = napiError.message; + } else { + // unmatched status return unified error code + errCode = -1; + errMessage = ""; + } + LOG_DEBUG(UDMF_KITS_NAPI, "GenerateNapiError errCode is %{public}d", errCode); + if (errCode == 0) { + return Status::E_OK; + } + return error; +} + +void ThrowNapiError(napi_env env, int32_t status, const std::string &errMessage, bool isParamsCheck) +{ + LOG_INFO(UDMF_KITS_NAPI, "ThrowNapiError message: %{public}s", errMessage.c_str()); + if (status == Status::E_OK) { + return; + } + auto errorMsg = GetErrorCode(status); + NapiErrorCode napiError; + if (errorMsg.has_value()) { + napiError = errorMsg.value(); + } else { + napiError.jsCode = -1; + napiError.message = ""; + } + + std::string message(napiError.message); + if (isParamsCheck) { + auto paramsCheckError = 401; + napiError.jsCode = paramsCheckError; + message += errMessage; + } + + std::string jsCode; + if (napiError.jsCode == -1) { + jsCode = ""; + } else { + jsCode = std::to_string(napiError.jsCode); + } + napi_throw_error(env, jsCode.c_str(), message.c_str()); +} +} // namespace UDMF +} // namespace OHOS diff --git a/udmf/framework/jskitsimpl/common/napi_queue.cpp b/udmf/framework/jskitsimpl/common/napi_queue.cpp new file mode 100644 index 00000000..63b63ce3 --- /dev/null +++ b/udmf/framework/jskitsimpl/common/napi_queue.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "napi_queue.h" + +#include "logger.h" + +namespace OHOS { +namespace UDMF { +ContextBase::~ContextBase() +{ + LOG_DEBUG(UDMF_KITS_NAPI, "no memory leak after callback or promise[resolved/rejected]"); + if (env != nullptr) { + if (work != nullptr) { + napi_delete_async_work(env, work); + } + if (callbackRef != nullptr) { + napi_delete_reference(env, callbackRef); + } + napi_delete_reference(env, selfRef); + env = nullptr; + } +} + +void ContextBase::GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoParser parse, bool sync) +{ + env = envi; + size_t argc = ARGC_MAX; + napi_value argv[ARGC_MAX] = { nullptr }; + status = napi_get_cb_info(env, info, &argc, argv, &self, nullptr); + ASSERT_STATUS(this, "napi_get_cb_info failed!"); + ASSERT_ARGS(this, argc <= ARGC_MAX, "too many arguments!"); + ASSERT_ARGS(this, self != nullptr, "no JavaScript this argument!"); + if (!sync) { + napi_create_reference(env, self, 1, &selfRef); + } + status = napi_unwrap(env, self, &native); + ASSERT_STATUS(this, "self unwrap failed!"); + + if (!sync && (argc > 0)) { + // get the last arguments :: <callback> + size_t index = argc - 1; + napi_valuetype type = napi_undefined; + napi_status tyst = napi_typeof(env, argv[index], &type); + if ((tyst == napi_ok) && (type == napi_function)) { + status = napi_create_reference(env, argv[index], 1, &callbackRef); + ASSERT_STATUS(this, "ref callback failed!"); + argc = index; + LOG_DEBUG(UDMF_KITS_NAPI, "async callback, no promise"); + } else { + LOG_DEBUG(UDMF_KITS_NAPI, "no callback, async pormose"); + } + } + + if (parse) { + parse(argc, argv); + } else { + ASSERT_ARGS(this, argc == 0, "required no arguments!"); + } +} + +napi_value NapiQueue::AsyncWork(napi_env env, std::shared_ptr<ContextBase> ctxt, const std::string &name, + NapiAsyncExecute execute, NapiAsyncComplete complete) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork name = %{public}s", name.c_str()); + ctxt->execute = std::move(execute); + ctxt->complete = std::move(complete); + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork move func finish"); + napi_value promise = nullptr; + if (ctxt->callbackRef == nullptr) { + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork has promise"); + napi_create_promise(ctxt->env, &ctxt->deferred, &promise); + LOG_DEBUG(UDMF_KITS_NAPI, "create deferred promise"); + } else { + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork no promise"); + napi_get_undefined(ctxt->env, &promise); + } + napi_value resource = nullptr; + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork create string start"); + napi_create_string_utf8(ctxt->env, name.c_str(), NAPI_AUTO_LENGTH, &resource); + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork create string finish"); + napi_create_async_work(ctxt->env, nullptr, resource, + [](napi_env env, void *data) { + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork start execute"); + ASSERT_VOID(data != nullptr, "no data"); + auto ctxt = reinterpret_cast<ContextBase *>(data); + LOG_DEBUG(UDMF_KITS_NAPI, "napi_async_execute_callback ctxt->status = %{public}d", ctxt->status); + if (ctxt->execute && ctxt->status == napi_ok) { + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork do user design execute"); + ctxt->execute(); + } + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork finish execute"); + }, + [](napi_env env, napi_status status, void *data) { + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork start output"); + ASSERT_VOID(data != nullptr, "no data"); + auto ctxt = reinterpret_cast<ContextBase *>(data); + LOG_DEBUG(UDMF_KITS_NAPI, "napi_async_complete_callback status = %{public}d, ctxt->status = %{public}d", + status, ctxt->status); + if ((status != napi_ok) && (ctxt->status == napi_ok)) { + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork check status"); + ctxt->status = status; + } + if ((ctxt->complete) && (status == napi_ok) && (ctxt->status == napi_ok)) { + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork do user design output"); + ctxt->complete(ctxt->output); + } + GenerateOutput(ctxt); + LOG_DEBUG(UDMF_KITS_NAPI, "NapiQueue::AsyncWork finish output"); + }, + reinterpret_cast<void *>(ctxt.get()), &ctxt->work); + napi_queue_async_work(ctxt->env, ctxt->work); + ctxt->hold = ctxt; // save crossing-thread ctxt. + return promise; +} + +void NapiQueue::GenerateOutput(ContextBase *ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "GenerateOutput start"); + napi_value result[RESULT_ALL] = { nullptr }; + LOG_DEBUG(UDMF_KITS_NAPI, "GenerateOutput ctxt->status = %{public}d", ctxt->status); + if (ctxt->status == napi_ok) { + napi_get_undefined(ctxt->env, &result[RESULT_ERROR]); + if (ctxt->output == nullptr) { + napi_get_undefined(ctxt->env, &ctxt->output); + } + result[RESULT_DATA] = ctxt->output; + } else { + napi_value code = nullptr; + napi_value message = nullptr; + if (ctxt->jsCode != 0 && ctxt->jsCode != -1) { + napi_create_string_utf8(ctxt->env, std::to_string(ctxt->jsCode).c_str(), NAPI_AUTO_LENGTH, &code); + } + if (ctxt->jsCode == -1) { + std::string jsCode; + napi_create_string_utf8(ctxt->env, jsCode.c_str(), NAPI_AUTO_LENGTH, &code); + } + napi_create_string_utf8(ctxt->env, ctxt->error.c_str(), NAPI_AUTO_LENGTH, &message); + napi_create_error(ctxt->env, code, message, &result[RESULT_ERROR]); + napi_get_undefined(ctxt->env, &result[RESULT_DATA]); + } + if (ctxt->deferred != nullptr) { + LOG_DEBUG(UDMF_KITS_NAPI, "GenerateOutput deferred branch"); + if (ctxt->status == napi_ok) { + LOG_DEBUG(UDMF_KITS_NAPI, "deferred promise resolved"); + napi_resolve_deferred(ctxt->env, ctxt->deferred, result[RESULT_DATA]); + } else { + LOG_DEBUG(UDMF_KITS_NAPI, "deferred promise rejected"); + napi_reject_deferred(ctxt->env, ctxt->deferred, result[RESULT_ERROR]); + } + } else { + napi_value callback = nullptr; + napi_get_reference_value(ctxt->env, ctxt->callbackRef, &callback); + napi_value callbackResult = nullptr; + LOG_INFO(UDMF_KITS_NAPI, "GenerateOutput call callback function"); + LOG_DEBUG(UDMF_KITS_NAPI, "call callback function"); + napi_call_function(ctxt->env, nullptr, callback, RESULT_ALL, result, &callbackResult); + } + ctxt->hold.reset(); // release ctxt. + LOG_DEBUG(UDMF_KITS_NAPI, "GenerateOutput stop"); +} +} // namespace UDMF +} // namespace OHOS diff --git a/udmf/framework/jskitsimpl/data/application_defined_record_napi.cpp b/udmf/framework/jskitsimpl/data/application_defined_record_napi.cpp new file mode 100644 index 00000000..bf52d096 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/application_defined_record_napi.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "application_defined_record_napi.h" + +#include "application_defined_record.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value ApplicationDefinedRecordNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ApplicationDefinedRecordNapi"); + napi_property_descriptor properties[] = { + /* ApplicationDefinedRecord extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* ApplicationDefinedRecord properties */ + DECLARE_NAPI_GETTER_SETTER("applicationDefinedType", GetApplicationDefinedType, SetApplicationDefinedType), + DECLARE_NAPI_GETTER_SETTER("rawData", GetRawData, SetRawData), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass( + env, "ApplicationDefinedRecord", properties, count, ApplicationDefinedRecordNapi::New); +} + +napi_value ApplicationDefinedRecordNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ApplicationDefinedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *record = new (std::nothrow) ApplicationDefinedRecordNapi(); + ASSERT_ERR(ctxt->env, record != nullptr, Status::E_UNKNOWN, "no memory for application defined record!"); + record->value_ = std::make_shared<ApplicationDefinedRecord>(); + ASSERT_CALL(ctxt->env, napi_wrap(env, ctxt->self, record, Destructor, nullptr, nullptr), record); + return ctxt->self; +} + +void ApplicationDefinedRecordNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ApplicationDefinedRecordNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *record = new (std::nothrow) ApplicationDefinedRecordNapi(); + ASSERT_ERR_VOID(env, record != nullptr, Status::E_UNKNOWN, "no memory for application defined record!"); + record->value_ = std::static_pointer_cast<ApplicationDefinedRecord>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, record, Destructor, nullptr, nullptr), record); +} + +void ApplicationDefinedRecordNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ApplicationDefinedRecordNapi finalize."); + auto *record = static_cast<ApplicationDefinedRecordNapi *>(data); + ASSERT_VOID(record != nullptr, "finalize null!"); + delete record; +} + +ApplicationDefinedRecordNapi *ApplicationDefinedRecordNapi::GetApplicationDefinedRecord( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ApplicationDefinedRecordNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<ApplicationDefinedRecordNapi *>(ctxt->native); +} + +napi_value ApplicationDefinedRecordNapi::GetApplicationDefinedType(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ApplicationDefinedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto record = GetApplicationDefinedRecord(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (record != nullptr && record->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, record->value_->GetApplicationDefinedType(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set type failed!"); + return ctxt->output; +} + +napi_value ApplicationDefinedRecordNapi::SetApplicationDefinedType(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ApplicationDefinedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string type; + auto input = [env, ctxt, &type](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], type); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto record = static_cast<ApplicationDefinedRecordNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (record != nullptr && record->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + record->value_->SetApplicationDefinedType(type); + return nullptr; +} + +napi_value ApplicationDefinedRecordNapi::GetRawData(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ApplicationDefinedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto record = GetApplicationDefinedRecord(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (record != nullptr && record->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, record->value_->GetRawData(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set rawData failed!"); + return ctxt->output; +} + +napi_value ApplicationDefinedRecordNapi::SetRawData(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ApplicationDefinedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::vector<uint8_t> rawData; + auto input = [env, ctxt, &rawData](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], rawData); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto record = static_cast<ApplicationDefinedRecordNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (record != nullptr && record->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + record->value_->SetRawData(rawData); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS diff --git a/udmf/framework/jskitsimpl/data/audio_napi.cpp b/udmf/framework/jskitsimpl/data/audio_napi.cpp new file mode 100644 index 00000000..bc856168 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/audio_napi.cpp @@ -0,0 +1,114 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "audio_napi.h" + +#include "audio.h" +#include "file_napi.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value AudioNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "AudioNapi"); + napi_property_descriptor properties[] = { + /* Audio extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* Audio extends File */ + DECLARE_NAPI_GETTER_SETTER("details", FileNapi::GetDetails, FileNapi::SetDetails), + DECLARE_NAPI_GETTER_SETTER("uri", FileNapi::GetUri, FileNapi::SetUri), + /* Audio properties */ + DECLARE_NAPI_GETTER_SETTER("audioUri", GetAudioUri, SetAudioUri), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "Audio", properties, count, AudioNapi::New); +} + +napi_value AudioNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "AudioNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *audio = new (std::nothrow) AudioNapi(); + ASSERT_ERR(ctxt->env, audio != nullptr, Status::E_UNKNOWN, "no memory for audio!"); + audio->value_ = std::make_shared<Audio>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, audio, Destructor, nullptr, nullptr), audio); + return ctxt->self; +} + +void AudioNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "AudioNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *audio = new (std::nothrow) AudioNapi(); + ASSERT_ERR_VOID(env, audio != nullptr, Status::E_UNKNOWN, "no memory for audio!"); + audio->value_ = std::static_pointer_cast<Audio>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, audio, Destructor, nullptr, nullptr), audio); +} + +void AudioNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "AudioNapi finalize."); + auto *audio = static_cast<AudioNapi *>(data); + ASSERT_VOID(audio != nullptr, "finalize null!"); + delete audio; +} + +AudioNapi *AudioNapi::GetAudio(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "AudioNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<AudioNapi *>(ctxt->native); +} + +napi_value AudioNapi::GetAudioUri(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "AudioNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto audio = GetAudio(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (audio != nullptr && audio->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, audio->value_->GetUri(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set audio uri failed!"); + return ctxt->output; +} + +napi_value AudioNapi::SetAudioUri(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "AudioNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string uri; + auto input = [env, ctxt, &uri](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], uri); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto audio = static_cast<AudioNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (audio != nullptr && audio->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + audio->value_->SetUri(uri); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/file_napi.cpp b/udmf/framework/jskitsimpl/data/file_napi.cpp new file mode 100644 index 00000000..933663f2 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/file_napi.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "file_napi.h" + +#include "file.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value FileNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FileNapi"); + napi_property_descriptor properties[] = { + /* File extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* File properties */ + DECLARE_NAPI_GETTER_SETTER("details", GetDetails, SetDetails), + DECLARE_NAPI_GETTER_SETTER("uri", GetUri, SetUri), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "File", properties, count, FileNapi::New); +} + +napi_value FileNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FileNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *file = new (std::nothrow) FileNapi(); + ASSERT_ERR(ctxt->env, file != nullptr, Status::E_UNKNOWN, "no memory for file!"); + file->value_ = std::make_shared<File>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, file, Destructor, nullptr, nullptr), file); + return ctxt->self; +} + +void FileNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FileNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *file = new (std::nothrow) FileNapi(); + ASSERT_ERR_VOID(env, file != nullptr, Status::E_UNKNOWN, "no memory for file!"); + file->value_ = std::static_pointer_cast<File>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, file, Destructor, nullptr, nullptr), file); +} + +void FileNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FileNapi finalize."); + auto *file = static_cast<FileNapi *>(data); + ASSERT_VOID(file != nullptr, "finalize null!"); + delete file; +} + +FileNapi *FileNapi::GetFile(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FileNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<FileNapi *>(ctxt->native); +} + +napi_value FileNapi::GetDetails(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FileNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto file = GetFile(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (file != nullptr && file->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, file->value_->GetDetails(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set details failed!"); + return ctxt->output; +} + +napi_value FileNapi::SetDetails(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FileNapi"); + auto ctxt = std::make_shared<ContextBase>(); + UDDetails details; + auto input = [env, ctxt, &details](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], details); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto file = static_cast<FileNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (file != nullptr && file->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + file->value_->SetDetails(details); + return nullptr; +} + +napi_value FileNapi::GetUri(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FileNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto file = GetFile(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (file != nullptr && file->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, file->value_->GetUri(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set uri failed!"); + return ctxt->output; +} + +napi_value FileNapi::SetUri(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FileNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string uri; + auto input = [env, ctxt, &uri](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], uri); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto file = static_cast<FileNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (file != nullptr && file->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + file->value_->SetUri(uri); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/folder_napi.cpp b/udmf/framework/jskitsimpl/data/folder_napi.cpp new file mode 100644 index 00000000..f9d87e06 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/folder_napi.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "folder_napi.h" + +#include "file_napi.h" +#include "folder.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value FolderNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FolderNapi"); + napi_property_descriptor properties[] = { + /* Folder extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* Folder extends File */ + DECLARE_NAPI_GETTER_SETTER("details", FileNapi::GetDetails, FileNapi::SetDetails), + DECLARE_NAPI_GETTER_SETTER("uri", FileNapi::GetUri, FileNapi::SetUri), + /* Folder properties */ + DECLARE_NAPI_GETTER_SETTER("folderUri", GetFolderUri, SetFolderUri), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "Folder", properties, count, FolderNapi::New); +} + +napi_value FolderNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FolderNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *folder = new (std::nothrow) FolderNapi(); + ASSERT_ERR(ctxt->env, folder != nullptr, Status::E_UNKNOWN, "no memory for folder!"); + folder->value_ = std::make_shared<Folder>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, folder, Destructor, nullptr, nullptr), folder); + return ctxt->self; +} + +void FolderNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FolderNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *folder = new (std::nothrow) FolderNapi(); + ASSERT_ERR_VOID(env, folder != nullptr, Status::E_UNKNOWN, "no memory for folder!"); + folder->value_ = std::static_pointer_cast<Folder>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, folder, Destructor, nullptr, nullptr), folder); +} + +void FolderNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FolderNapi finalize."); + auto *folder = static_cast<FolderNapi *>(data); + ASSERT_VOID(folder != nullptr, "finalize null!"); + delete folder; +} + +FolderNapi *FolderNapi::GetFolder(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FolderNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<FolderNapi *>(ctxt->native); +} + +napi_value FolderNapi::GetFolderUri(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FolderNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto folder = GetFolder(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (folder != nullptr && folder->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, folder->value_->GetUri(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set folder uri failed!"); + return ctxt->output; +} + +napi_value FolderNapi::SetFolderUri(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "FolderNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string uri; + auto input = [env, ctxt, &uri](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], uri); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto folder = static_cast<FolderNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (folder != nullptr && folder->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + folder->value_->SetUri(uri); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/html_napi.cpp b/udmf/framework/jskitsimpl/data/html_napi.cpp new file mode 100644 index 00000000..7b2282b3 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/html_napi.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "html_napi.h" + +#include "html.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "text_napi.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value HtmlNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "HtmlNapi"); + napi_property_descriptor properties[] = { + /* Html extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* Html extends Text */ + DECLARE_NAPI_GETTER_SETTER("details", TextNapi::GetDetails, TextNapi::SetDetails), + /* Html properties */ + DECLARE_NAPI_GETTER_SETTER("htmlContent", GetHtmlContent, SetHtmlContent), + DECLARE_NAPI_GETTER_SETTER("plainContent", GetPlainContent, SetPlainContent), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "HTML", properties, count, HtmlNapi::New); +} + +napi_value HtmlNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "HtmlNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *html = new (std::nothrow) HtmlNapi(); + ASSERT_ERR(ctxt->env, html != nullptr, Status::E_UNKNOWN, "no memory for html!"); + html->value_ = std::make_shared<Html>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, html, Destructor, nullptr, nullptr), html); + return ctxt->self; +} + +void HtmlNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "HtmlNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *html = new (std::nothrow) HtmlNapi(); + ASSERT_ERR_VOID(env, html != nullptr, Status::E_UNKNOWN, "no memory for html!"); + html->value_ = std::static_pointer_cast<Html>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, html, Destructor, nullptr, nullptr), html); +} + +void HtmlNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "HtmlNapi finalize."); + auto *html = static_cast<HtmlNapi *>(data); + ASSERT_VOID(html != nullptr, "finalize null!"); + delete html; +} + +HtmlNapi *HtmlNapi::GetHtml(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "HtmlNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<HtmlNapi *>(ctxt->native); +} + +napi_value HtmlNapi::GetPlainContent(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "HtmlNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto html = GetHtml(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (html != nullptr && html->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, html->value_->GetPlainContent(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set plain content failed!"); + return ctxt->output; +} + +napi_value HtmlNapi::SetPlainContent(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "HtmlNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string plainContent; + auto input = [env, ctxt, &plainContent](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], plainContent); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto html = static_cast<HtmlNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (html != nullptr && html->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + html->value_->SetPlainContent(plainContent); + return nullptr; +} + +napi_value HtmlNapi::GetHtmlContent(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "HtmlNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto html = GetHtml(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (html != nullptr && html->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, html->value_->GetHtmlContent(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set html failed!"); + return ctxt->output; +} + +napi_value HtmlNapi::SetHtmlContent(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "HtmlNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string htmlContent; + auto input = [env, ctxt, &htmlContent](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], htmlContent); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto html = static_cast<HtmlNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (html != nullptr && html->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + html->value_->SetHtmlContent(htmlContent); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/image_napi.cpp b/udmf/framework/jskitsimpl/data/image_napi.cpp new file mode 100644 index 00000000..ba6c9234 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/image_napi.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_napi.h" + +#include "file_napi.h" +#include "image.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value ImageNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ImageNapi"); + napi_property_descriptor properties[] = { + /* Image extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* Image extends File */ + DECLARE_NAPI_GETTER_SETTER("details", FileNapi::GetDetails, FileNapi::SetDetails), + DECLARE_NAPI_GETTER_SETTER("uri", FileNapi::GetUri, FileNapi::SetUri), + /* Image properties */ + DECLARE_NAPI_GETTER_SETTER("imageUri", GetImageUri, SetImageUri), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "Image", properties, count, ImageNapi::New); +} + +napi_value ImageNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ImageNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *image = new (std::nothrow) ImageNapi(); + ASSERT_ERR(ctxt->env, image != nullptr, Status::E_UNKNOWN, "no memory for image!"); + image->value_ = std::make_shared<Image>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, image, Destructor, nullptr, nullptr), image); + return ctxt->self; +} + +void ImageNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ImageNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *image = new (std::nothrow) ImageNapi(); + ASSERT_ERR_VOID(env, image != nullptr, Status::E_UNKNOWN, "no memory for image!"); + image->value_ = std::static_pointer_cast<Image>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, image, Destructor, nullptr, nullptr), image); +} + +void ImageNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ImageNapi finalize."); + auto *image = static_cast<ImageNapi *>(data); + ASSERT_VOID(image != nullptr, "finalize null!"); + delete image; +} + +ImageNapi *ImageNapi::GetImage(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ImageNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<ImageNapi *>(ctxt->native); +} + +napi_value ImageNapi::GetImageUri(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ImageNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto image = GetImage(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (image != nullptr && image->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, image->value_->GetUri(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set image uri failed!"); + return ctxt->output; +} + +napi_value ImageNapi::SetImageUri(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "ImageNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string uri; + auto input = [env, ctxt, &uri](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], uri); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto image = static_cast<ImageNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (image != nullptr && image->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + image->value_->SetUri(uri); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/link_napi.cpp b/udmf/framework/jskitsimpl/data/link_napi.cpp new file mode 100644 index 00000000..40206fb0 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/link_napi.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "link_napi.h" + +#include "link.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "text_napi.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value LinkNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "LinkNapi"); + napi_property_descriptor properties[] = { + /* Link extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* Link extends Text */ + DECLARE_NAPI_GETTER_SETTER("details", TextNapi::GetDetails, TextNapi::SetDetails), + /* Link properties */ + DECLARE_NAPI_GETTER_SETTER("url", GetUrl, SetUrl), + DECLARE_NAPI_GETTER_SETTER("description", GetDescription, SetDescription), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "Hyperlink", properties, count, LinkNapi::New); +} + +napi_value LinkNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "LinkNapi"); + auto ctxt = std::make_shared<ContextBase>(); + + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *link = new (std::nothrow) LinkNapi(); + ASSERT_ERR(ctxt->env, link != nullptr, Status::E_UNKNOWN, "no memory for link!"); + link->value_ = std::make_shared<Link>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, link, Destructor, nullptr, nullptr), link); + return ctxt->self; +} + +void LinkNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "LinkNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *link = new (std::nothrow) LinkNapi(); + ASSERT_ERR_VOID(env, link != nullptr, Status::E_UNKNOWN, "no memory for link!"); + link->value_ = std::static_pointer_cast<Link>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, link, Destructor, nullptr, nullptr), link); +} + +void LinkNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "LinkNapi finalize."); + auto *link = static_cast<LinkNapi *>(data); + ASSERT_VOID(link != nullptr, "finalize null!"); + delete link; +} + +LinkNapi *LinkNapi::GetLink(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "LinkNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<LinkNapi *>(ctxt->native); +} + +napi_value LinkNapi::GetUrl(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "LinkNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto link = GetLink(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (link != nullptr && link->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, link->value_->GetUrl(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set url failed!"); + return ctxt->output; +} + +napi_value LinkNapi::SetUrl(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "LinkNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string url; + auto input = [env, ctxt, &url](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], url); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto link = static_cast<LinkNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (link != nullptr && link->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + link->value_->SetUrl(url); + return nullptr; +} + +napi_value LinkNapi::GetDescription(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "LinkNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto link = GetLink(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (link != nullptr && link->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, link->value_->GetDescription(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set description failed!"); + return ctxt->output; +} + +napi_value LinkNapi::SetDescription(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "LinkNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string description; + auto input = [env, ctxt, &description](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], description); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto link = static_cast<LinkNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (link != nullptr && link->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + link->value_->SetDescription(description); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/plain_text_napi.cpp b/udmf/framework/jskitsimpl/data/plain_text_napi.cpp new file mode 100644 index 00000000..d87ee77a --- /dev/null +++ b/udmf/framework/jskitsimpl/data/plain_text_napi.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#include "plain_text_napi.h" + +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "plain_text.h" +#include "text_napi.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value PlainTextNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "PlainTextNapi"); + napi_property_descriptor properties[] = { + /* PlainText extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* PlainText extends Text */ + DECLARE_NAPI_GETTER_SETTER("details", TextNapi::GetDetails, TextNapi::SetDetails), + /* PlainText properties */ + DECLARE_NAPI_GETTER_SETTER("textContent", GetContent, SetContent), + DECLARE_NAPI_GETTER_SETTER("abstract", GetAbstract, SetAbstract), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "PlainText", properties, count, PlainTextNapi::New); +} + +napi_value PlainTextNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "PlainTextNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *plainText = new (std::nothrow) PlainTextNapi(); + ASSERT_ERR(ctxt->env, plainText != nullptr, Status::E_UNKNOWN, "no memory for plain text!"); + plainText->value_ = std::make_shared<PlainText>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, plainText, Destructor, nullptr, nullptr), plainText); + return ctxt->self; +} + +void PlainTextNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "PlainTextNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *plainText = new (std::nothrow) PlainTextNapi(); + ASSERT_ERR_VOID(env, plainText != nullptr, Status::E_UNKNOWN, "no memory for plain text!"); + plainText->value_ = std::static_pointer_cast<PlainText>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, plainText, Destructor, nullptr, nullptr), plainText); +} + +void PlainTextNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "PlainTextNapi finalize."); + auto *plainText = static_cast<PlainTextNapi *>(data); + ASSERT_VOID(plainText != nullptr, "finalize null!"); + delete plainText; +} + +PlainTextNapi *PlainTextNapi::GetPlainText(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "PlainTextNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<PlainTextNapi *>(ctxt->native); +} + +napi_value PlainTextNapi::GetContent(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "PlainTextNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto plainText = GetPlainText(env, info, ctxt); + ASSERT_ERR(ctxt->env, (plainText != nullptr && plainText->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, plainText->value_->GetContent(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set text content failed!"); + return ctxt->output; +} + +napi_value PlainTextNapi::SetContent(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "PlainTextNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string content; + auto input = [env, ctxt, &content](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], content); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto plainText = static_cast<PlainTextNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (plainText != nullptr && plainText->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + plainText->value_->SetContent(content); + return nullptr; +} + +napi_value PlainTextNapi::GetAbstract(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "PlainTextNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto plainText = GetPlainText(env, info, ctxt); + ASSERT_ERR(ctxt->env, (plainText != nullptr && plainText->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, plainText->value_->GetAbstract(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set abstract failed!"); + return ctxt->output; +} + +napi_value PlainTextNapi::SetAbstract(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "PlainTextNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string abstract; + auto input = [env, ctxt, &abstract](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], abstract); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto plainText = static_cast<PlainTextNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (plainText != nullptr && plainText->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + plainText->value_->SetAbstract(abstract); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/summary_napi.cpp b/udmf/framework/jskitsimpl/data/summary_napi.cpp new file mode 100644 index 00000000..00a3795c --- /dev/null +++ b/udmf/framework/jskitsimpl/data/summary_napi.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#include "summary_napi.h" + +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_types.h" + +namespace OHOS { +namespace UDMF { +napi_value SummaryNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SummaryNapi"); + napi_property_descriptor properties[] = { + DECLARE_NAPI_GETTER_SETTER("summary", GetSummary, nullptr), + DECLARE_NAPI_GETTER_SETTER("totalSize", GetTotal, nullptr), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "Summary", properties, count, SummaryNapi::New); +} + +napi_value SummaryNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SummaryNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *summary = new (std::nothrow) SummaryNapi(); + ASSERT_ERR(ctxt->env, summary != nullptr, Status::E_UNKNOWN, "no memory for summary!"); + summary->value_ = std::make_shared<Summary>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, summary, Destructor, nullptr, nullptr), summary); + return ctxt->self; +} + +void SummaryNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SummaryNapi finalize."); + auto *summary = static_cast<SummaryNapi *>(data); + ASSERT_VOID(summary != nullptr, "finalize null!"); + delete summary; +} + +void SummaryNapi::NewInstance(napi_env env, std::shared_ptr<Summary> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SummaryNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *summary = new (std::nothrow) SummaryNapi(); + ASSERT_ERR_VOID(env, summary != nullptr, Status::E_UNKNOWN, "no memory for summary!"); + summary->value_ = in; + ASSERT_CALL_DELETE(env, napi_wrap(env, out, summary, Destructor, nullptr, nullptr), summary); +} + +SummaryNapi *SummaryNapi::GetDataSummary(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SummaryNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<SummaryNapi *>(ctxt->native); +} + +napi_value SummaryNapi::GetSummary(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SummaryNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto summary = GetDataSummary(env, info, ctxt); + ASSERT_ERR(ctxt->env, (summary != nullptr && summary->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, summary->value_->summary, ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set summery failed!"); + return ctxt->output; +} + +napi_value SummaryNapi::GetTotal(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SummaryNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto summary = GetDataSummary(env, info, ctxt); + ASSERT_ERR(ctxt->env, (summary != nullptr && summary->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, summary->value_->totalSize, ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set total failed!"); + return ctxt->output; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/system_defined_appitem_napi.cpp b/udmf/framework/jskitsimpl/data/system_defined_appitem_napi.cpp new file mode 100644 index 00000000..6a9bfe37 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/system_defined_appitem_napi.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "system_defined_appitem_napi.h" + +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "system_defined_appitem.h" +#include "system_defined_record_napi.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value SystemDefinedAppItemNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + napi_property_descriptor properties[] = { + /* SystemDefinedAppItem extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* SystemDefinedAppItem extends SystemDefinedRecord */ + DECLARE_NAPI_GETTER_SETTER("details", SystemDefinedRecordNapi::GetDetails, SystemDefinedRecordNapi::SetDetails), + /* SystemDefinedAppItem properties */ + DECLARE_NAPI_GETTER_SETTER("appId", GetAppId, SetAppId), + DECLARE_NAPI_GETTER_SETTER("appName", GetAppName, SetAppName), + DECLARE_NAPI_GETTER_SETTER("appIconId", GetAppIconId, SetAppIconId), + DECLARE_NAPI_GETTER_SETTER("appLabelId", GetAppLabelId, SetAppLabelId), + DECLARE_NAPI_GETTER_SETTER("bundleName", GetBundleName, SetBundleName), + DECLARE_NAPI_GETTER_SETTER("abilityName", GetAbilityName, SetAbilityName), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "SDAppItem", properties, count, SystemDefinedAppItemNapi::New); +} + +napi_value SystemDefinedAppItemNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *sdAppItem = new (std::nothrow) SystemDefinedAppItemNapi(); + ASSERT_ERR(ctxt->env, sdAppItem != nullptr, Status::E_UNKNOWN, "no memory for system defined appitem!"); + sdAppItem->value_ = std::make_shared<SystemDefinedAppItem>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, sdAppItem, Destructor, nullptr, nullptr), sdAppItem); + return ctxt->self; +} + +void SystemDefinedAppItemNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *sdAppItem = new (std::nothrow) SystemDefinedAppItemNapi(); + ASSERT_ERR_VOID(env, sdAppItem != nullptr, Status::E_UNKNOWN, "no memory for system defined appitem!"); + sdAppItem->value_ = std::static_pointer_cast<SystemDefinedAppItem>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, sdAppItem, Destructor, nullptr, nullptr), sdAppItem); +} + +void SystemDefinedAppItemNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi finalize."); + auto *sdAppItem = static_cast<SystemDefinedAppItemNapi *>(data); + ASSERT_VOID(sdAppItem != nullptr, "finalize null!"); + delete sdAppItem; +} + +SystemDefinedAppItemNapi *SystemDefinedAppItemNapi::GetSystemDefinedAppItem( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<SystemDefinedAppItemNapi *>(ctxt->native); +} + +napi_value SystemDefinedAppItemNapi::GetAppId(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdAppItem = GetSystemDefinedAppItem(env, info, ctxt); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdAppItem->value_->GetAppId(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set app id failed!"); + return ctxt->output; +} + +napi_value SystemDefinedAppItemNapi::SetAppId(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string appId; + auto input = [env, ctxt, &appId](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], appId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdAppItem = static_cast<SystemDefinedAppItemNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + sdAppItem->value_->SetAppId(appId); + return nullptr; +} + +napi_value SystemDefinedAppItemNapi::GetAppName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdAppItem = GetSystemDefinedAppItem(env, info, ctxt); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdAppItem->value_->GetAppName(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set app name failed!"); + return ctxt->output; +} + +napi_value SystemDefinedAppItemNapi::SetAppName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string appName; + auto input = [env, ctxt, &appName](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], appName); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdAppItem = static_cast<SystemDefinedAppItemNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + sdAppItem->value_->SetAppName(appName); + return nullptr; +} + +napi_value SystemDefinedAppItemNapi::GetAppIconId(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdAppItem = GetSystemDefinedAppItem(env, info, ctxt); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdAppItem->value_->GetAppIconId(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set app icon id failed!"); + return ctxt->output; +} + +napi_value SystemDefinedAppItemNapi::SetAppIconId(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string appIconId; + auto input = [env, ctxt, &appIconId](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], appIconId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdAppItem = static_cast<SystemDefinedAppItemNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + sdAppItem->value_->SetAppIconId(appIconId); + return nullptr; +} + +napi_value SystemDefinedAppItemNapi::GetAppLabelId(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdAppItem = GetSystemDefinedAppItem(env, info, ctxt); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdAppItem->value_->GetAppLabelId(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set app label id failed!"); + return ctxt->output; +} + +napi_value SystemDefinedAppItemNapi::SetAppLabelId(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string appLabelId; + auto input = [env, ctxt, &appLabelId](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], appLabelId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdAppItem = static_cast<SystemDefinedAppItemNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + sdAppItem->value_->SetAppLabelId(appLabelId); + return nullptr; +} + +napi_value SystemDefinedAppItemNapi::GetBundleName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdAppItem = GetSystemDefinedAppItem(env, info, ctxt); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdAppItem->value_->GetBundleName(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set bundle name failed!"); + return ctxt->output; +} + +napi_value SystemDefinedAppItemNapi::SetBundleName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string bundleName; + auto input = [env, ctxt, &bundleName](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], bundleName); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdAppItem = static_cast<SystemDefinedAppItemNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + sdAppItem->value_->SetBundleName(bundleName); + return nullptr; +} + +napi_value SystemDefinedAppItemNapi::GetAbilityName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdAppItem = GetSystemDefinedAppItem(env, info, ctxt); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdAppItem->value_->GetAbilityName(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set ability name failed!"); + return ctxt->output; +} + +napi_value SystemDefinedAppItemNapi::SetAbilityName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedAppItemNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string abilityName; + auto input = [env, ctxt, &abilityName](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], abilityName); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdAppItem = static_cast<SystemDefinedAppItemNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (sdAppItem != nullptr && sdAppItem->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + sdAppItem->value_->SetAbilityName(abilityName); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/system_defined_form_napi.cpp b/udmf/framework/jskitsimpl/data/system_defined_form_napi.cpp new file mode 100644 index 00000000..4425d3a9 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/system_defined_form_napi.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "system_defined_form_napi.h" + +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "system_defined_form.h" +#include "system_defined_record_napi.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value SystemDefinedFormNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + napi_property_descriptor properties[] = { + /* SystemDefinedForm extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* SystemDefinedForm extends SystemDefinedRecord */ + DECLARE_NAPI_GETTER_SETTER("details", SystemDefinedRecordNapi::GetDetails, SystemDefinedRecordNapi::SetDetails), + /* SystemDefinedForm properties */ + DECLARE_NAPI_GETTER_SETTER("formId", GetFormId, SetFormId), + DECLARE_NAPI_GETTER_SETTER("formName", GetFormName, SetFormName), + DECLARE_NAPI_GETTER_SETTER("bundleName", GetBundleName, SetBundleName), + DECLARE_NAPI_GETTER_SETTER("abilityName", GetAbilityName, SetAbilityName), + DECLARE_NAPI_GETTER_SETTER("module", GetModule, SetModule), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "SDForm", properties, count, SystemDefinedFormNapi::New); +} + +napi_value SystemDefinedFormNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *sdForm = new (std::nothrow) SystemDefinedFormNapi(); + ASSERT_ERR(ctxt->env, sdForm != nullptr, Status::E_UNKNOWN, "no memory for system defined form!"); + sdForm->value_ = std::make_shared<SystemDefinedForm>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, sdForm, Destructor, nullptr, nullptr), sdForm); + return ctxt->self; +} + +void SystemDefinedFormNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *sdForm = new (std::nothrow) SystemDefinedFormNapi(); + ASSERT_ERR_VOID(env, sdForm != nullptr, Status::E_UNKNOWN, "no memory for system defined form!"); + sdForm->value_ = std::static_pointer_cast<SystemDefinedForm>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, sdForm, Destructor, nullptr, nullptr), sdForm); +} + +void SystemDefinedFormNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi finalize."); + auto *sdForm = static_cast<SystemDefinedFormNapi *>(data); + ASSERT_VOID(sdForm != nullptr, "finalize null!"); + delete sdForm; +} + +SystemDefinedFormNapi *SystemDefinedFormNapi::GetSystemDefinedForm( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<SystemDefinedFormNapi *>(ctxt->native); +} + +napi_value SystemDefinedFormNapi::GetFormId(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdForm = GetSystemDefinedForm(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (sdForm != nullptr && sdForm->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdForm->value_->GetFormId(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set form id failed!"); + return ctxt->output; +} + +napi_value SystemDefinedFormNapi::SetFormId(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + int32_t formId = 0; + auto input = [env, ctxt, &formId](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], formId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdForm = static_cast<SystemDefinedFormNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (sdForm != nullptr && sdForm->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + sdForm->value_->SetFormId(formId); + return nullptr; +} + +napi_value SystemDefinedFormNapi::GetFormName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdForm = GetSystemDefinedForm(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (sdForm != nullptr && sdForm->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdForm->value_->GetFormName(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set form name failed!"); + return ctxt->output; +} + +napi_value SystemDefinedFormNapi::SetFormName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string formName; + auto input = [env, ctxt, &formName](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], formName); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdForm = static_cast<SystemDefinedFormNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (sdForm != nullptr && sdForm->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + sdForm->value_->SetFormName(formName); + return nullptr; +} + +napi_value SystemDefinedFormNapi::GetBundleName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdForm = GetSystemDefinedForm(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (sdForm != nullptr && sdForm->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdForm->value_->GetBundleName(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set bundle name failed!"); + return ctxt->output; +} + +napi_value SystemDefinedFormNapi::SetBundleName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string bundleName; + auto input = [env, ctxt, &bundleName](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], bundleName); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdForm = static_cast<SystemDefinedFormNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (sdForm != nullptr && sdForm->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + sdForm->value_->SetBundleName(bundleName); + return nullptr; +} + +napi_value SystemDefinedFormNapi::GetAbilityName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdForm = GetSystemDefinedForm(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (sdForm != nullptr && sdForm->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdForm->value_->GetAbilityName(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set ability name failed!"); + return ctxt->output; +} + +napi_value SystemDefinedFormNapi::SetAbilityName(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string abilityName; + auto input = [env, ctxt, &abilityName](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], abilityName); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdForm = static_cast<SystemDefinedFormNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (sdForm != nullptr && sdForm->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + sdForm->value_->SetAbilityName(abilityName); + return nullptr; +} + +napi_value SystemDefinedFormNapi::GetModule(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdForm = GetSystemDefinedForm(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (sdForm != nullptr && sdForm->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdForm->value_->GetModule(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set module failed!"); + return ctxt->output; +} + +napi_value SystemDefinedFormNapi::SetModule(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedFormNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string module; + auto input = [env, ctxt, &module](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], module); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdForm = static_cast<SystemDefinedFormNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (sdForm != nullptr && sdForm->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + sdForm->value_->SetModule(module); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/system_defined_pixelmap_napi.cpp b/udmf/framework/jskitsimpl/data/system_defined_pixelmap_napi.cpp new file mode 100644 index 00000000..e46eaa4b --- /dev/null +++ b/udmf/framework/jskitsimpl/data/system_defined_pixelmap_napi.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "system_defined_pixelmap_napi.h" + +#include "system_defined_pixelmap.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_record_napi.h" +#include "system_defined_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value SystemDefinedPixelMapNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedPixelMapNapi"); + napi_property_descriptor properties[] = { + /* SystemDefinedPixelMap extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* SystemDefinedPixelMap extends SystemDefinedRecord */ + DECLARE_NAPI_GETTER_SETTER("details", SystemDefinedRecordNapi::GetDetails, SystemDefinedRecordNapi::SetDetails), + /* SystemDefinedPixelMap properties */ + DECLARE_NAPI_GETTER_SETTER("rawData", GetRawData, SetRawData), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "SystemDefinedPixelMap", properties, count, SystemDefinedPixelMapNapi::New); +} + +napi_value SystemDefinedPixelMapNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedPixelMapNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *sdPixelMap = new (std::nothrow) SystemDefinedPixelMapNapi(); + ASSERT_ERR(ctxt->env, sdPixelMap != nullptr, Status::E_UNKNOWN, "no memory for system defined pixel map!"); + sdPixelMap->value_ = std::make_shared<SystemDefinedPixelMap>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, sdPixelMap, Destructor, nullptr, nullptr), sdPixelMap); + return ctxt->self; +} + +void SystemDefinedPixelMapNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedPixelMapNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *sdPixelMap = new (std::nothrow) SystemDefinedPixelMapNapi(); + ASSERT_ERR_VOID(env, sdPixelMap != nullptr, Status::E_UNKNOWN, "no memory for system defined pixel map!"); + sdPixelMap->value_ = std::static_pointer_cast<SystemDefinedPixelMap>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, sdPixelMap, Destructor, nullptr, nullptr), sdPixelMap); +} + +void SystemDefinedPixelMapNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedPixelMapNapi finalize."); + auto *sdPixelMap = static_cast<SystemDefinedPixelMapNapi *>(data); + ASSERT_VOID(sdPixelMap != nullptr, "finalize null!"); + delete sdPixelMap; +} + +SystemDefinedPixelMapNapi *SystemDefinedPixelMapNapi::GetSystemDefinedPixelMap( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedPixelMapNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<SystemDefinedPixelMapNapi *>(ctxt->native); +} + +napi_value SystemDefinedPixelMapNapi::GetRawData(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedPixelMapNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdPixelMap = GetSystemDefinedPixelMap(env, info, ctxt); + ASSERT_ERR(ctxt->env, (sdPixelMap != nullptr && sdPixelMap->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdPixelMap->value_->GetRawData(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set raw data failed!"); + return ctxt->output; +} + +napi_value SystemDefinedPixelMapNapi::SetRawData(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedPixelMapNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::vector<uint8_t> pixelMap; + auto input = [env, ctxt, &pixelMap](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], pixelMap); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdPixelMap = static_cast<SystemDefinedPixelMapNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (sdPixelMap != nullptr && sdPixelMap->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + sdPixelMap->value_->SetRawData(pixelMap); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/system_defined_record_napi.cpp b/udmf/framework/jskitsimpl/data/system_defined_record_napi.cpp new file mode 100644 index 00000000..ddbf7363 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/system_defined_record_napi.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#include "system_defined_record_napi.h" + +#include "system_defined_record.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value SystemDefinedRecordNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedRecordNapi"); + napi_property_descriptor properties[] = { + /* SystemDefinedRecord extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* SystemDefinedRecord properties */ + DECLARE_NAPI_GETTER_SETTER("details", GetDetails, SetDetails), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "SystemDefinedRecord", properties, count, SystemDefinedRecordNapi::New); +} + +napi_value SystemDefinedRecordNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *sdRecord = new (std::nothrow) SystemDefinedRecordNapi(); + ASSERT_ERR(ctxt->env, sdRecord != nullptr, Status::E_UNKNOWN, "no memory for system defined record!"); + sdRecord->value_ = std::make_shared<SystemDefinedRecord>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, sdRecord, Destructor, nullptr, nullptr), sdRecord); + return ctxt->self; +} + +void SystemDefinedRecordNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedRecordNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *sdRecord = new (std::nothrow) SystemDefinedRecordNapi(); + ASSERT_ERR_VOID(env, sdRecord != nullptr, Status::E_UNKNOWN, "no memory for system defined record!"); + sdRecord->value_ = std::static_pointer_cast<SystemDefinedRecord>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, sdRecord, Destructor, nullptr, nullptr), sdRecord); +} + +void SystemDefinedRecordNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedRecordNapi finalize."); + auto *sdRecord = static_cast<SystemDefinedRecordNapi *>(data); + ASSERT_VOID(sdRecord != nullptr, "finalize null!"); + delete sdRecord; +} + +SystemDefinedRecordNapi *SystemDefinedRecordNapi::GetSystemDefinedRecord( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedRecordNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<SystemDefinedRecordNapi *>(ctxt->native); +} + +napi_value SystemDefinedRecordNapi::GetDetails(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto sdRecord = GetSystemDefinedRecord(env, info, ctxt); + ASSERT_ERR(ctxt->env, (sdRecord != nullptr && sdRecord->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, sdRecord->value_->GetDetails(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set details failed!"); + return ctxt->output; +} + +napi_value SystemDefinedRecordNapi::SetDetails(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "SystemDefinedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + + UDDetails details; + auto input = [env, ctxt, &details](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], details); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto sdRecord = static_cast<SystemDefinedRecordNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (sdRecord != nullptr && sdRecord->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + sdRecord->value_->SetDetails(details); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/text_napi.cpp b/udmf/framework/jskitsimpl/data/text_napi.cpp new file mode 100644 index 00000000..9cae4d94 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/text_napi.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +#include "text_napi.h" + +#include "text.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_record_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value TextNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "TextNapi"); + napi_property_descriptor properties[] = { + /* Text extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* Text properties */ + DECLARE_NAPI_GETTER_SETTER("details", GetDetails, SetDetails), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "Text", properties, count, TextNapi::New); +} + +napi_value TextNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "TextNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *text = new (std::nothrow) TextNapi(); + ASSERT_ERR(ctxt->env, text != nullptr, Status::E_UNKNOWN, "no memory for text!"); + text->value_ = std::make_shared<Text>(); + ASSERT_CALL(ctxt->env, napi_wrap(env, ctxt->self, text, Destructor, nullptr, nullptr), text); + return ctxt->self; +} + +void TextNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "TextNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *text = new (std::nothrow) TextNapi(); + ASSERT_ERR_VOID(env, text != nullptr, Status::E_UNKNOWN, "no memory for text!"); + text->value_ = std::static_pointer_cast<Text>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, text, Destructor, nullptr, nullptr), text); +} + +void TextNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "TextNapi finalize."); + auto *text = static_cast<TextNapi *>(data); + ASSERT_VOID(text != nullptr, "finalize null!"); + delete text; +} + +TextNapi *TextNapi::GetText(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "TextNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<TextNapi *>(ctxt->native); +} + +napi_value TextNapi::GetDetails(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "TextNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto text = GetText(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (text != nullptr && text->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, text->value_->GetDetails(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set details failed!"); + return ctxt->output; +} + +napi_value TextNapi::SetDetails(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "TextNapi"); + auto ctxt = std::make_shared<ContextBase>(); + UDDetails details; + auto input = [env, ctxt, &details](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], details); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto text = static_cast<TextNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (text != nullptr && text->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + text->value_->SetDetails(details); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/udmf_napi.cpp b/udmf/framework/jskitsimpl/data/udmf_napi.cpp new file mode 100644 index 00000000..d437acc3 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/udmf_napi.cpp @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "udmf_napi.h" + +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "udmf_client.h" +#include "unified_data_napi.h" +#include "unified_meta.h" + +namespace OHOS { +namespace UDMF { +napi_value UDMFNapi::UDMFInit(napi_env env, napi_value exports) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UDMFNapi"); + napi_value unifiedDataType = CreateUnifiedDataType(env); + napi_value intention = CreateIntention(env); + napi_property_descriptor desc[] = { + DECLARE_NAPI_PROPERTY("UnifiedDataType", unifiedDataType), + DECLARE_NAPI_PROPERTY("Intention", intention), + DECLARE_NAPI_FUNCTION("insertData", InsertData), + DECLARE_NAPI_FUNCTION("updateData", UpdateData), + DECLARE_NAPI_FUNCTION("queryData", QueryData), + DECLARE_NAPI_FUNCTION("deleteData", DeleteData), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} + +napi_value UDMFNapi::CreateUnifiedDataType(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UDMFNapi"); + napi_value unifiedDataType = nullptr; + napi_create_object(env, &unifiedDataType); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(TEXT), UD_TYPE_MAP.at(TEXT)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(PLAIN_TEXT), UD_TYPE_MAP.at(PLAIN_TEXT)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(HTML), UD_TYPE_MAP.at(HTML)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(HYPERLINK), UD_TYPE_MAP.at(HYPERLINK)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(FILE), UD_TYPE_MAP.at(FILE)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(IMAGE), UD_TYPE_MAP.at(IMAGE)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(VIDEO), UD_TYPE_MAP.at(VIDEO)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(AUDIO), UD_TYPE_MAP.at(AUDIO)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(FOLDER), UD_TYPE_MAP.at(FOLDER)); + SetNamedProperty( + env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(SYSTEM_DEFINED_RECORD), UD_TYPE_MAP.at(SYSTEM_DEFINED_RECORD)); + SetNamedProperty( + env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(SYSTEM_DEFINED_FORM), UD_TYPE_MAP.at(SYSTEM_DEFINED_FORM)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(SYSTEM_DEFINED_APP_ITEM), + UD_TYPE_MAP.at(SYSTEM_DEFINED_APP_ITEM)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(SYSTEM_DEFINED_PIXEL_MAP), + UD_TYPE_MAP.at(SYSTEM_DEFINED_PIXEL_MAP)); + SetNamedProperty(env, unifiedDataType, JS_UD_TYPE_NAME_MAP.at(APPLICATION_DEFINED_RECORD), + UD_TYPE_MAP.at(APPLICATION_DEFINED_RECORD)); + napi_object_freeze(env, unifiedDataType); + return unifiedDataType; +} + +napi_value UDMFNapi::CreateIntention(napi_env env) +{ + napi_value intention = nullptr; + napi_create_object(env, &intention); + SetNamedProperty(env, intention, JS_UD_INTENTION_NAME_MAP.at(UD_INTENTION_DATA_HUB), + UD_INTENTION_MAP.at(UD_INTENTION_DATA_HUB)); + napi_object_freeze(env, intention); + return intention; +} + +napi_status UDMFNapi::SetNamedProperty(napi_env env, napi_value &obj, const std::string &name, const std::string &value) +{ + napi_value property = nullptr; + napi_status status = NapiDataUtils::SetValue(env, value, property); + ASSERT(status == napi_ok, "string to napi_value failed!", status); + status = napi_set_named_property(env, obj, name.c_str(), property); + ASSERT(status == napi_ok, "napi_set_named_property failed!", status); + return status; +} + +napi_value UDMFNapi::InsertData(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "InsertData is called!"); + struct InsertContext : public ContextBase { + std::string key; + Intention intention; + std::shared_ptr<UnifiedData> unifiedData; + }; + std::string intention; + auto unifiedDataNapi = new (std::nothrow) UnifiedDataNapi(); + auto ctxt = std::make_shared<InsertContext>(); + auto input = [env, ctxt, &intention, &unifiedDataNapi](size_t argc, napi_value *argv) { + // require 2 arguments <options, unifiedData> + ASSERT_BUSINESS_ERR(ctxt, argc >= 2, E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = GetNamedProperty(env, argv[0], "intention", intention); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok && UnifiedDataUtils::IsPersist(intention), + E_INVALID_PARAMETERS, "invalid arg[0], i.e. invalid intention!"); + ctxt->status = napi_unwrap(env, argv[1], reinterpret_cast<void **>(&unifiedDataNapi)); + ASSERT_BUSINESS_ERR( + ctxt, ctxt->status == napi_ok, E_INVALID_PARAMETERS, "invalid arg[1], i.e. invalid unifiedData!"); + }; + ctxt->GetCbInfo(env, info, input); + ASSERT_NULL(!ctxt->isThrowError, "Insert Exit"); + ctxt->unifiedData = unifiedDataNapi->value_; + ctxt->intention = UnifiedDataUtils::GetIntentionByString(intention); + auto execute = [ctxt]() { + CustomOption option = { .intention = ctxt->intention }; + auto status = UdmfClient::GetInstance().SetData(option, *(ctxt->unifiedData), ctxt->key); + ASSERT_WITH_ERRCODE(ctxt, status == E_OK, status, "InsertData failed!"); + }; + + auto output = [env, ctxt](napi_value &result) { + ctxt->status = NapiDataUtils::SetValue(env, ctxt->key, result); + ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "output failed!"); + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output); +} + +napi_value UDMFNapi::UpdateData(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UpdateData is called!"); + struct UpdateContext : public ContextBase { + std::string key; + std::shared_ptr<UnifiedData> unifiedData; + }; + std::string key; + auto unifiedDataNapi = new (std::nothrow) UnifiedDataNapi(); + auto ctxt = std::make_shared<UpdateContext>(); + auto input = [env, ctxt, &unifiedDataNapi](size_t argc, napi_value *argv) { + // require 2 arguments <options, unifiedData> + ASSERT_BUSINESS_ERR(ctxt, argc >= 2, E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = GetNamedProperty(env, argv[0], "key", ctxt->key); + UnifiedKey key(ctxt->key); + ASSERT_BUSINESS_ERR(ctxt, + ctxt->status == napi_ok && key.IsValid() && UnifiedDataUtils::IsPersist(key.intention), + E_INVALID_PARAMETERS, "invalid arg[0], i.e. invalid key!"); + ctxt->status = napi_unwrap(env, argv[1], reinterpret_cast<void **>(&unifiedDataNapi)); + ASSERT_BUSINESS_ERR( + ctxt, ctxt->status == napi_ok, E_INVALID_PARAMETERS, "invalid arg[1], i.e. invalid unifiedData!"); + }; + ctxt->GetCbInfo(env, info, input); + ASSERT_NULL(!ctxt->isThrowError, "Update Exit"); + ctxt->unifiedData = unifiedDataNapi->value_; + auto execute = [ctxt]() { + QueryOption option = { .key = ctxt->key }; + auto status = UdmfClient::GetInstance().UpdateData(option, *(ctxt->unifiedData)); + ASSERT_WITH_ERRCODE(ctxt, status == E_OK, status, "UpdateData failed!"); + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} + +napi_value UDMFNapi::QueryData(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "QueryData is called!"); + struct QueryContext : public ContextBase { + std::string key; + Intention intention; + std::vector<UnifiedData> unifiedDataSet; + }; + std::string intention; + auto ctxt = std::make_shared<QueryContext>(); + auto input = [env, ctxt, &intention](size_t argc, napi_value *argv) { + // require 1 arguments <options> + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, E_INVALID_PARAMETERS, "invalid arguments!"); + napi_status keyStatus; + napi_status intentionStatus; + auto options = argv[0]; + keyStatus = GetNamedProperty(env, options, "key", ctxt->key); + intentionStatus = GetNamedProperty(env, options, "intention", intention); + ASSERT_BUSINESS_ERR(ctxt, + (keyStatus == napi_ok || intentionStatus == napi_ok) + && UnifiedDataUtils::IsValidOptions(ctxt->key, intention), + E_INVALID_PARAMETERS, "invalid arg[0], i.e. invalid options!"); + }; + ctxt->GetCbInfo(env, info, input); + ASSERT_NULL(!ctxt->isThrowError, "Query Exit"); + ctxt->intention = UnifiedDataUtils::GetIntentionByString(intention); + auto execute = [env, ctxt]() { + QueryOption option = { + .key = ctxt->key, + .intention = ctxt->intention, + }; + auto status = UdmfClient::GetInstance().GetBatchData(option, ctxt->unifiedDataSet); + LOG_DEBUG(UDMF_SERVICE, "GetBatchData : status = %{public}d!", status); + ASSERT_WITH_ERRCODE(ctxt, status == E_OK, status, "QueryData failed!"); + }; + auto output = [env, ctxt](napi_value &result) { + ASSERT_WITH_ERRCODE(ctxt, !ctxt->unifiedDataSet.empty(), E_ERROR, "unifiedDataSet is empty!"); + ctxt->status = napi_create_array_with_length(env, ctxt->unifiedDataSet.size(), &ctxt->output); + ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "napi_create_array_with_length failed!"); + int index = 0; + for (const UnifiedData &data : ctxt->unifiedDataSet) { + std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>(); + unifiedData->SetRecords(data.GetRecords()); + napi_value dataNapi = nullptr; + UnifiedDataNapi::NewInstance(env, unifiedData, dataNapi); + ctxt->status = napi_set_element(env, ctxt->output, index++, dataNapi); + ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "napi_set_element failed!"); + } + result = ctxt->output; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output); +} + +napi_value UDMFNapi::DeleteData(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "DeleteData is called!"); + struct DeleteContext : public ContextBase { + std::string key; + Intention intention; + std::vector<UnifiedData> unifiedDataSet; + }; + std::string intention; + auto ctxt = std::make_shared<DeleteContext>(); + auto input = [env, ctxt, &intention](size_t argc, napi_value *argv) { + // require 1 arguments <options> + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, E_INVALID_PARAMETERS, "invalid arguments!"); + napi_status keyStatus; + napi_status intentionStatus; + napi_value options = argv[0]; + keyStatus = GetNamedProperty(env, options, "key", ctxt->key); + intentionStatus = GetNamedProperty(env, options, "intention", intention); + ASSERT_BUSINESS_ERR(ctxt, + (keyStatus == napi_ok || intentionStatus == napi_ok) + && UnifiedDataUtils::IsValidOptions(ctxt->key, intention), + E_INVALID_PARAMETERS, "invalid arg[0], i.e. invalid options!"); + }; + ctxt->GetCbInfo(env, info, input); + ASSERT_NULL(!ctxt->isThrowError, "Delete Exit"); + ctxt->intention = UnifiedDataUtils::GetIntentionByString(intention); + auto execute = [env, ctxt]() { + QueryOption option = { + .key = ctxt->key, + .intention = ctxt->intention, + }; + auto status = UdmfClient::GetInstance().DeleteData(option, ctxt->unifiedDataSet); + ASSERT_WITH_ERRCODE(ctxt, status == E_OK, status, "DeleteData failed!"); + }; + + auto output = [env, ctxt](napi_value &result) { + ASSERT_WITH_ERRCODE(ctxt, !ctxt->unifiedDataSet.empty(), E_ERROR, "unifiedDataSet is empty!"); + ctxt->status = napi_create_array_with_length(env, ctxt->unifiedDataSet.size(), &ctxt->output); + ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "napi_create_array_with_length failed!"); + int index = 0; + for (const UnifiedData &data : ctxt->unifiedDataSet) { + std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>(); + unifiedData->SetRecords(data.GetRecords()); + napi_value dataNapi = nullptr; + UnifiedDataNapi::NewInstance(env, unifiedData, dataNapi); + ctxt->status = napi_set_element(env, ctxt->output, index++, dataNapi); + ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "napi_set_element failed!"); + } + result = ctxt->output; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output); +} + +napi_status UDMFNapi::GetNamedProperty(napi_env env, napi_value &obj, const std::string &key, std::string &value) +{ + bool hasKey = false; + napi_status status = napi_has_named_property(env, obj, key.c_str(), &hasKey); + if (status != napi_ok) { + LOG_ERROR(UDMF_KITS_NAPI, "napi_has_named_property failed, name = %{public}s", key.c_str()); + return napi_generic_failure; + } + if (!hasKey) { + LOG_ERROR(UDMF_KITS_NAPI, "The property name is non-existent, name: %{public}s", key.c_str()); + return napi_generic_failure; + } + napi_value napiValue = nullptr; + status = napi_get_named_property(env, obj, key.c_str(), &napiValue); + if (status != napi_ok || napiValue == nullptr) { + LOG_ERROR(UDMF_KITS_NAPI, "napi_get_named_property failed, name = %{public}s", key.c_str()); + return napi_generic_failure; + } + if (NapiDataUtils::IsNull(env, napiValue)) { + LOG_ERROR(UDMF_KITS_NAPI, "The property value is null, name = %{public}s", key.c_str()); + return napi_generic_failure; + } + status = NapiDataUtils::GetValue(env, napiValue, value); + if (status != napi_ok) { + LOG_ERROR(UDMF_KITS_NAPI, "NapiDataUtils::GetValue failed, name = %{public}s", key.c_str()); + return status; + } + LOG_DEBUG(UDMF_KITS_NAPI, "Param parse successful, Options.%{public}s = %{public}s", key.c_str(), value.c_str()); + return status; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/unified_data_napi.cpp b/udmf/framework/jskitsimpl/data/unified_data_napi.cpp new file mode 100644 index 00000000..c6ad9771 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/unified_data_napi.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unified_data_napi.h" + +#include "application_defined_record_napi.h" +#include "audio_napi.h" +#include "file_napi.h" +#include "folder_napi.h" +#include "html_napi.h" +#include "image_napi.h" +#include "link_napi.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "plain_text_napi.h" +#include "system_defined_appitem_napi.h" +#include "system_defined_form_napi.h" +#include "system_defined_pixelmap_napi.h" +#include "system_defined_record_napi.h" +#include "text_napi.h" +#include "unified_data.h" +#include "unified_record_napi.h" +#include "video_napi.h" + +namespace OHOS { +namespace UDMF { +napi_value UnifiedDataNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi"); + napi_property_descriptor properties[] = { + /* UnifiedData properties */ + DECLARE_NAPI_FUNCTION("addRecord", AddRecord), + DECLARE_NAPI_FUNCTION("getRecords", GetRecords), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "UnifiedData", properties, count, UnifiedDataNapi::New); +} + +napi_value UnifiedDataNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi"); + UnifiedRecordNapi *uRecord = nullptr; + auto ctxt = std::make_shared<ContextBase>(); + auto input = [env, info, ctxt, &uRecord](size_t argc, napi_value *argv) { + // required 1 arguments :: <UnifiedRecord*> + ASSERT_BUSINESS_ERR(ctxt, argc <= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + if (argc == 1) { + ctxt->status = napi_unwrap(env, *argv, reinterpret_cast<void **>(&uRecord)); + ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok && uRecord != nullptr && uRecord->value_ != nullptr), + Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = UnifiedDataUtils::IsValidType(uRecord->value_->GetType()) ? napi_ok : napi_invalid_arg; + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid type!"); + } + }; + + // Parsing input parameters + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto *uData = new (std::nothrow) UnifiedDataNapi(); + ASSERT_ERR(ctxt->env, uData != nullptr, Status::E_UNKNOWN, "no memory for unified data!"); + uData->value_ = std::make_shared<UnifiedData>(); + if (uRecord) { + uData->value_->AddRecord(uRecord->value_); + } + ASSERT_CALL(env, napi_wrap(env, ctxt->self, uData, Destructor, nullptr, nullptr), uData); + return ctxt->self; +} + +void UnifiedDataNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi finalize."); + auto *uData = static_cast<UnifiedDataNapi *>(data); + ASSERT_VOID(uData != nullptr, "finalize null!"); + delete uData; +} + +void UnifiedDataNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedData> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *unifiedData = new (std::nothrow) UnifiedDataNapi(); + ASSERT_ERR_VOID(env, unifiedData != nullptr, Status::E_UNKNOWN, "no memory for unified data!"); + unifiedData->value_ = in; + ASSERT_CALL_DELETE(env, napi_wrap(env, out, unifiedData, Destructor, nullptr, nullptr), unifiedData); +} + +UnifiedDataNapi *UnifiedDataNapi::GetUnifiedData(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<UnifiedDataNapi *>(ctxt->native); +} + +napi_value UnifiedDataNapi::AddRecord(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi"); + UnifiedRecordNapi *uRecord = nullptr; + auto ctxt = std::make_shared<ContextBase>(); + auto input = [env, info, ctxt, &uRecord](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = napi_unwrap(env, *argv, reinterpret_cast<void **>(&uRecord)); + ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok && uRecord != nullptr && uRecord->value_ != nullptr), + Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = UnifiedDataUtils::IsValidType(uRecord->value_->GetType()) ? napi_ok : napi_invalid_arg; + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid type!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto *uData = static_cast<UnifiedDataNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (uData != nullptr && uData->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + uData->value_->AddRecord(uRecord->value_); + return nullptr; +} + +napi_value UnifiedDataNapi::GetRecords(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto uData = GetUnifiedData(env, info); + ASSERT_ERR( + ctxt->env, (uData != nullptr && uData->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + std::vector<std::shared_ptr<UnifiedRecord>> records = uData->value_->GetRecords(); + napi_status status = napi_create_array_with_length(env, records.size(), &ctxt->output); + ASSERT_ERR(ctxt->env, status == napi_ok, Status::E_ERROR, "init array failed!"); + int index = 0; + for (const std::shared_ptr<UnifiedRecord> &recordPtr : records) { + napi_value recordNapi = nullptr; + GetRecord(env, recordPtr, recordNapi); + ctxt->status = napi_set_element(env, ctxt->output, index++, recordNapi); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, "set element failed!"); + } + return ctxt->output; +} + +void UnifiedDataNapi::GetRecord(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + switch (in->GetType()) { + case TEXT: { + TextNapi::NewInstance(env, in, out); + break; + } + case PLAIN_TEXT: { + PlainTextNapi::NewInstance(env, in, out); + break; + } + case HTML: { + HtmlNapi::NewInstance(env, in, out); + break; + } + case HYPERLINK: { + LinkNapi::NewInstance(env, in, out); + break; + } + case FILE: { + FileNapi::NewInstance(env, in, out); + break; + } + case IMAGE: { + ImageNapi::NewInstance(env, in, out); + break; + } + case VIDEO: { + VideoNapi::NewInstance(env, in, out); + break; + } + case AUDIO: { + AudioNapi::NewInstance(env, in, out); + break; + } + case FOLDER: { + FolderNapi::NewInstance(env, in, out); + break; + } + case SYSTEM_DEFINED_RECORD: { + SystemDefinedRecordNapi::NewInstance(env, in, out); + break; + } + case SYSTEM_DEFINED_APP_ITEM: { + SystemDefinedAppItemNapi::NewInstance(env, in, out); + break; + } + case SYSTEM_DEFINED_FORM: { + SystemDefinedFormNapi::NewInstance(env, in, out); + break; + } + case SYSTEM_DEFINED_PIXEL_MAP: { + SystemDefinedPixelMapNapi::NewInstance(env, in, out); + break; + } + case APPLICATION_DEFINED_RECORD: { + ApplicationDefinedRecordNapi::NewInstance(env, in, out); + break; + } + default: + LOG_INFO(UDMF_KITS_NAPI, "GetRecord default"); + break; + } +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/unified_record_napi.cpp b/udmf/framework/jskitsimpl/data/unified_record_napi.cpp new file mode 100644 index 00000000..35192f56 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/unified_record_napi.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unified_record_napi.h" + +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_record.h" + +namespace OHOS { +namespace UDMF { +napi_value UnifiedRecordNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi"); + napi_property_descriptor properties[] = { + /* UnifiedRecord properties */ + DECLARE_NAPI_FUNCTION("getType", GetType), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "UnifiedRecord", properties, count, UnifiedRecordNapi::New); +} + +napi_value UnifiedRecordNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *udRecord = new (std::nothrow) UnifiedRecordNapi(); + ASSERT_ERR(ctxt->env, udRecord != nullptr, Status::E_UNKNOWN, "no memory for unified record!"); + udRecord->value_ = std::make_shared<UnifiedRecord>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, udRecord, Destructor, nullptr, nullptr), udRecord); + return ctxt->self; +} + +void UnifiedRecordNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi finalize."); + auto *uRecord = static_cast<UnifiedRecordNapi *>(data); + ASSERT_VOID(uRecord != nullptr, "finalize null!"); + delete uRecord; +} + +UnifiedRecordNapi *UnifiedRecordNapi::GetUnifiedRecord( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<UnifiedRecordNapi *>(ctxt->native); +} + +napi_value UnifiedRecordNapi::GetType(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto uRecord = GetUnifiedRecord(env, info, ctxt); + ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_INVALID_PARAMETERS, + "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, UD_TYPE_MAP.at(uRecord->value_->GetType()), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set type failed!"); + return ctxt->output; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/video_napi.cpp b/udmf/framework/jskitsimpl/data/video_napi.cpp new file mode 100644 index 00000000..a9df4142 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/video_napi.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "video_napi.h" + +#include "file_napi.h" +#include "napi_data_utils.h" +#include "napi_error_utils.h" +#include "napi_queue.h" +#include "unified_record_napi.h" +#include "video.h" + +namespace OHOS { +namespace UDMF { +napi_value VideoNapi::Constructor(napi_env env) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "VideoNapi"); + napi_property_descriptor properties[] = { + /* Video extends UnifiedRecord */ + DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), + /* Video extends File */ + DECLARE_NAPI_GETTER_SETTER("details", FileNapi::GetDetails, FileNapi::SetDetails), + DECLARE_NAPI_GETTER_SETTER("uri", FileNapi::GetUri, FileNapi::SetUri), + /* Video properties */ + DECLARE_NAPI_GETTER_SETTER("videoUri", GetVideoUri, SetVideoUri), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + return NapiDataUtils::DefineClass(env, "Video", properties, count, VideoNapi::New); +} + +napi_value VideoNapi::New(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "VideoNapi"); + auto ctxt = std::make_shared<ContextBase>(); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + + auto *video = new (std::nothrow) VideoNapi(); + ASSERT_ERR(ctxt->env, video != nullptr, Status::E_UNKNOWN, "no memory for video!"); + video->value_ = std::make_shared<Video>(); + ASSERT_CALL(env, napi_wrap(env, ctxt->self, video, Destructor, nullptr, nullptr), video); + return ctxt->self; +} + +void VideoNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "VideoNapi"); + ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out)); + auto *video = new (std::nothrow) VideoNapi(); + ASSERT_ERR_VOID(env, video != nullptr, Status::E_UNKNOWN, "no memory for video!"); + video->value_ = std::static_pointer_cast<Video>(in); + ASSERT_CALL_DELETE(env, napi_wrap(env, out, video, Destructor, nullptr, nullptr), video); +} + +void VideoNapi::Destructor(napi_env env, void *data, void *hint) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "VideoNapi finalize."); + auto *video = static_cast<VideoNapi *>(data); + ASSERT_VOID(video != nullptr, "finalize null!"); + delete video; +} + +VideoNapi *VideoNapi::GetVideo(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "VideoNapi"); + ctxt->GetCbInfoSync(env, info); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + return static_cast<VideoNapi *>(ctxt->native); +} + +napi_value VideoNapi::GetVideoUri(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "VideoNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto video = GetVideo(env, info, ctxt); + ASSERT_ERR( + ctxt->env, (video != nullptr && video->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, video->value_->GetUri(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "set video uri failed!"); + return ctxt->output; +} + +napi_value VideoNapi::SetVideoUri(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "VideoNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string uri; + auto input = [env, ctxt, &uri](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + ctxt->status = NapiDataUtils::GetValue(env, argv[0], uri); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_INVALID_PARAMETERS, "invalid arguments!"); + auto video = static_cast<VideoNapi *>(ctxt->native); + ASSERT_ERR( + ctxt->env, (video != nullptr && video->value_ != nullptr), Status::E_INVALID_PARAMETERS, "invalid object!"); + video->value_->SetUri(uri); + return nullptr; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/unittest/BUILD.gn b/udmf/framework/jskitsimpl/unittest/BUILD.gn new file mode 100644 index 00000000..75bf5b11 --- /dev/null +++ b/udmf/framework/jskitsimpl/unittest/BUILD.gn @@ -0,0 +1,30 @@ +# Copyright (C) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") +import("//foundation/distributeddatamgr/udmf/udmf.gni") + +module_output_path = "udmf/jskitsimpl" + +ohos_js_unittest("UDMFJsTest") { + module_out_path = module_output_path + + hap_profile = "./config.json" + + certificate_profile = "${developer_test_path}/signature/openharmony_sx.p7b" +} + +group("unittest") { + testonly = true + deps = [ ":UDMFJsTest" ] +} diff --git a/udmf/framework/jskitsimpl/unittest/UdmfCallbackJsTest.js b/udmf/framework/jskitsimpl/unittest/UdmfCallbackJsTest.js new file mode 100644 index 00000000..50ac19dc --- /dev/null +++ b/udmf/framework/jskitsimpl/unittest/UdmfCallbackJsTest.js @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from 'deccjsunit/index'; +import UDMF from '@ohos.data.UDMF'; + +const TEXT_CONTEXT_01 = 'TextContent01'; +const TEXT_CONTEXT_02 = 'TextContent02'; +const ERROR_PARAMETER = '401'; + +describe('UdmfCallbackJSTest', function () { + + let gPlainText1 = new UDMF.PlainText(); + gPlainText1.textContent = TEXT_CONTEXT_01; + let gPlainText2 = new UDMF.PlainText(); + gPlainText2.textContent = TEXT_CONTEXT_02; + + const optionsValid = { intention: 'DataHub', }; + const optionsInValidIntention = { intention: 'Drag', }; + const optionsInValidKey = { key: 'udmf://drag/com.test.demo/123456789', }; + const optionsInValidAll = { intention: 'DataHub', key: 'udmf://drag/com.test.demo/123456789' }; + const unifiedData01 = new UDMF.UnifiedData(gPlainText1); + const unifiedData02 = new UDMF.UnifiedData(gPlainText2); + const unifiedDataInvalid = new UDMF.UnifiedData(); + + /** + * @tc.name UdmfInsertCallbackInvalidOptionsTest + * @tc.desc Test Js Api insertData with invalid options + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfInsertCallbackInvalidOptionsTest', 0, async function (done) { + const TAG = 'UdmfInsertCallbackInvalidOptionsTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsInValidIntention, unifiedData01, (err, data) => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, `get e. code is ${e.code},message is ${e.message} `); + expect(e.code === ERROR_PARAMETER).assertTrue(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfInsertCallbackInvalidDataTest + * @tc.desc Test Js Api insertData with invalid UnifiedData + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfInsertCallbackInvalidDataTest', 0, async function (done) { + const TAG = 'UdmfInsertCallbackInvalidDataTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsValid, unifiedDataInvalid, (err, data) => { + expect(data).assertUndefined(); + console.error(TAG, `get fail. code is ${err.code},message is ${err.message} `); + expect(err.code === ERROR_PARAMETER).assertTrue(); + done(); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfInsertCallbackSucTest + * @tc.desc Test Js Api insertData successful + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfInsertCallbackSucTest', 0, async function (done) { + const TAG = 'UdmfInsertCallbackSucTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsValid, unifiedData01, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `query start. The options: ${JSON.stringify(options)}`); + UDMF.queryData(options, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, 'query success.'); + console.info(TAG, `data.length = ${data.length}.`); + expect(data.length).assertEqual(1); + let records = data[0].getRecords(); + console.info(TAG, `records.length = ${records.length}.`); + console.info(TAG, `records[0].getType() = ${records[0].getType()}.`); + console.info(TAG, `records[0].textContent = ${records[0].textContent}.`); + expect(records.length).assertEqual(1); + expect(records[0].getType()).assertEqual(UDMF.UnifiedDataType.PLAIN_TEXT); + expect(records[0].textContent).assertEqual(TEXT_CONTEXT_01); + done(); + }); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfUpdateCallbackInvalidOptionsTest + * @tc.desc Test Js Api updateData with invalid options + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfUpdateCallbackInvalidOptionsTest', 0, async function (done) { + const TAG = 'UdmfUpdateCallbackInvalidOptionsTest:'; + console.info(TAG, 'start'); + try { + UDMF.updateData(optionsInValidKey, unifiedData01, (err) => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + }); + done(); + } catch (e) { + console.error(TAG, `get e. code is ${e.code},message is ${e.message} `); + expect(e.code === ERROR_PARAMETER).assertTrue(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfUpdateCallbackInvalidDataTest + * @tc.desc Test Js Api updateData with invalid UnifiedData + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfUpdateCallbackInvalidDataTest', 0, async function (done) { + const TAG = 'UdmfUpdateCallbackInvalidDataTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsValid, unifiedData01, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `update start. The options: ${JSON.stringify(options)}`); + UDMF.updateData(options, unifiedDataInvalid, (err) => { + console.error(TAG, `get fail. code is ${err.code},message is ${err.message} `); + expect(err.code === ERROR_PARAMETER).assertTrue(); + done(); + }); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfUpdateCallbackSucTest + * @tc.desc Test Js Api updateData successful + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfUpdateCallbackSucTest', 0, async function (done) { + const TAG = 'UdmfUpdateCallbackSucTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsValid, unifiedData01, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `update start. The options: ${JSON.stringify(options)}`); + UDMF.updateData(options, unifiedData02, (err) => { + expect(err).assertUndefined(); + console.info(TAG, 'update success.'); + UDMF.queryData(options, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, 'query success.'); + expect(data.length).assertEqual(1); + let records = data[0].getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].getType()).assertEqual(UDMF.UnifiedDataType.PLAIN_TEXT); + expect(records[0].textContent).assertEqual(TEXT_CONTEXT_02); + done(); + }); + }); + }); + + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); + + + /** + * @tc.name UdmfQueryCallbackInvalidOptionsTest + * @tc.desc Test Js Api queryData with invalid options + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfQueryCallbackInvalidOptionsTest', 0, async function (done) { + const TAG = 'UdmfQueryCallbackInvalidOptionsTest:'; + console.info(TAG, 'start'); + try { + UDMF.queryData(optionsInValidAll, (err, data) => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, `get e. code is ${e.code},message is ${e.message} `); + expect(e.code === ERROR_PARAMETER).assertTrue(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfQueryCallbackSucTest + * @tc.desc Test Js Api queryData successful + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfQueryCallbackSucTest', 0, async function (done) { + const TAG = 'UdmfQueryCallbackSucTest:'; + console.info(TAG, 'start'); + try { + UDMF.deleteData(optionsValid, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, 'delete success.'); + UDMF.queryData(optionsValid, (err, data) => { + console.info(TAG, 'query has no data.'); + expect(data).assertUndefined(); + UDMF.insertData(optionsValid, unifiedData01, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, `insert success. The key: ${data}`); + UDMF.insertData(optionsValid, unifiedData02, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, `insert success. The key: ${data}`); + UDMF.queryData(optionsValid, function (err, data) { + expect(err).assertUndefined(); + console.info(TAG, `query success.`); + expect(data.length).assertEqual(2); + done(); + }); + }); + }); + }); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); + + + /** + * @tc.name UdmfDeleteCallbackInvalidOptionsTest + * @tc.desc Test Js Api deleteData with invalid options + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfDeleteCallbackInvalidOptionsTest', 0, async function (done) { + const TAG = 'UdmfDeleteCallbackInvalidOptionsTest:'; + console.info(TAG, 'start'); + try { + UDMF.deleteData(optionsInValidAll, (err, data) => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, `get e. code is ${e.code},message is ${e.message} `); + expect(e.code === ERROR_PARAMETER).assertTrue(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfDeleteCallbackSucTest + * @tc.desc Test Js Api deleteData successful + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfDeleteCallbackSucTest', 0, async function (done) { + const TAG = 'UdmfDeleteCallbackSucTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsValid, unifiedData01, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `query start. The options: ${JSON.stringify(options)}`); + UDMF.queryData(options, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, 'query success.'); + expect(data.length).assertEqual(1); + UDMF.deleteData(options, (err, data) => { + expect(err).assertUndefined(); + console.info(TAG, 'delete success.'); + expect(data.length).assertEqual(1); + let records = data[0].getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].getType()).assertEqual(UDMF.UnifiedDataType.PLAIN_TEXT); + expect(records[0].textContent).assertEqual(TEXT_CONTEXT_01); + UDMF.queryData(options, (err, data) => { + expect(data).assertUndefined(); + console.info(TAG, 'query has no data.'); + done(); + }); + }); + }); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); +}); \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/unittest/UdmfJsTest.js b/udmf/framework/jskitsimpl/unittest/UdmfJsTest.js new file mode 100644 index 00000000..2a88a7b6 --- /dev/null +++ b/udmf/framework/jskitsimpl/unittest/UdmfJsTest.js @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from 'deccjsunit/index'; +import UDMF from '@ohos.data.UDMF'; + +const TEST_BUNDLE_NAME = 'MyBundleName'; +const KEY_TEST_ELEMENT = 'TestKey'; +const VALUE_TEST_ELEMENT = 'TestValue'; +const TEST_ID = 123456; +const TEST_ABILITY_NAME = 'MyAbilityName'; +const TEST_MODULE = 'MyModule'; + +let U8_ARRAY = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + +describe('UdmfJSTest', function () { + + /** + * @tc.name UdmfTextTest + * @tc.desc Test Js Api Text testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfTextTest', 0, function () { + console.info('UdmfTextTest start'); + let text = new UDMF.Text(); + text.details = { + Key: 'text' + KEY_TEST_ELEMENT, + Value: 'text' + VALUE_TEST_ELEMENT, + }; + let unifiedData = new UDMF.UnifiedData(text); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.Key).assertEqual('text' + KEY_TEST_ELEMENT); + expect(records[0].details.Value).assertEqual('text' + VALUE_TEST_ELEMENT); + console.info('UdmfTextTest end'); + }); + + /** + * @tc.name UdmfPlainTextTest + * @tc.desc Test Js Api PlainText testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfPlainTextTest', 0, function () { + console.info('UdmfPlainTextTest start'); + let plainText = new UDMF.PlainText(); + plainText.details = { + Key: 'text' + KEY_TEST_ELEMENT, + Value: 'text' + VALUE_TEST_ELEMENT, + }; + plainText.textContent = 'textContent'; + plainText.abstract = 'abstract'; + let unifiedData = new UDMF.UnifiedData(plainText); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.Key).assertEqual('text' + KEY_TEST_ELEMENT); + expect(records[0].details.Value).assertEqual('text' + VALUE_TEST_ELEMENT); + expect(records[0].textContent).assertEqual('textContent'); + expect(records[0].abstract).assertEqual('abstract'); + console.info('UdmfPlainTextTest end'); + }); + + /** + * @tc.name UdmfHyperlinkTest + * @tc.desc Test Js Api Hyperlink testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfHyperlinkTest', 0, function () { + console.info('UdmfHyperlinkTest start'); + let link = new UDMF.Hyperlink(); + link.details = { + Key: 'link' + KEY_TEST_ELEMENT, + Value: 'link' + VALUE_TEST_ELEMENT, + }; + link.url = 'url'; + link.description = 'description'; + let unifiedData = new UDMF.UnifiedData(link); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.Key).assertEqual('link' + KEY_TEST_ELEMENT); + expect(records[0].details.Value).assertEqual('link' + VALUE_TEST_ELEMENT); + expect(records[0].url).assertEqual('url'); + expect(records[0].description).assertEqual('description'); + console.info('UdmfHyperlinkTest end'); + }); + + /** + * @tc.name UdmfHtmlTest + * @tc.desc Test Js Api HTML testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfHtmlTest', 0, function () { + console.info('UdmfHtmlTest start'); + let html = new UDMF.HTML(); + html.details = { + Key: 'html' + KEY_TEST_ELEMENT, + Value: 'html' + VALUE_TEST_ELEMENT, + }; + html.htmlContent = 'htmlContent'; + html.plainContent = 'plainContent'; + let unifiedData = new UDMF.UnifiedData(html); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.Key).assertEqual('html' + KEY_TEST_ELEMENT); + expect(records[0].details.Value).assertEqual('html' + VALUE_TEST_ELEMENT); + expect(records[0].htmlContent).assertEqual('htmlContent'); + expect(records[0].plainContent).assertEqual('plainContent'); + console.info('UdmfHtmlTest end'); + }); + + /** + * @tc.name UdmfFileTest + * @tc.desc Test Js Api File testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfFileTest', 0, function () { + console.info('UdmfFileTest start'); + let file = new UDMF.File(); + file.details = { + Key: 'file' + KEY_TEST_ELEMENT, + Value: 'file' + VALUE_TEST_ELEMENT, + }; + file.uri = 'uri'; + let unifiedData = new UDMF.UnifiedData(file); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.Key).assertEqual('file' + KEY_TEST_ELEMENT); + expect(records[0].details.Value).assertEqual('file' + VALUE_TEST_ELEMENT); + expect(records[0].uri).assertEqual('uri'); + console.info('UdmfFileTest end'); + }); + + /** + * @tc.name UdmfFolderTest + * @tc.desc Test Js Api Folder testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfFolderTest', 0, function () { + console.info('UdmfFolderTest start'); + let folder = new UDMF.Folder(); + folder.details = { + Key: 'folder' + KEY_TEST_ELEMENT, + Value: 'folder' + VALUE_TEST_ELEMENT, + }; + folder.uri = 'folderUri'; + let unifiedData = new UDMF.UnifiedData(folder); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.Key).assertEqual('folder' + KEY_TEST_ELEMENT); + expect(records[0].details.Value).assertEqual('folder' + VALUE_TEST_ELEMENT); + expect(records[0].uri).assertEqual('folderUri'); + console.info('UdmfFolderTest end'); + }); + + /** + * @tc.name UdmfImageTest + * @tc.desc Test Js Api Image testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfImageTest', 0, function () { + console.info('UdmfImageTest start'); + let image = new UDMF.Image(); + image.details = { + Key: 'image' + KEY_TEST_ELEMENT, + Value: 'image' + VALUE_TEST_ELEMENT, + }; + image.imageUri = 'imageUri'; + let unifiedData = new UDMF.UnifiedData(image); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.Key).assertEqual('image' + KEY_TEST_ELEMENT); + expect(records[0].details.Value).assertEqual('image' + VALUE_TEST_ELEMENT); + expect(records[0].imageUri).assertEqual('imageUri'); + console.info('UdmfImageTest end'); + }); + + /** + * @tc.name UdmfVideoTest + * @tc.desc Test Js Api Video testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfVideoTest', 0, function () { + console.info('UdmfVideoTest start'); + let video = new UDMF.Video(); + video.details = { + Key: 'video' + KEY_TEST_ELEMENT, + Value: 'video' + VALUE_TEST_ELEMENT, + }; + video.videoUri = 'videoUri'; + let unifiedData = new UDMF.UnifiedData(video); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.Key).assertEqual('video' + KEY_TEST_ELEMENT); + expect(records[0].details.Value).assertEqual('video' + VALUE_TEST_ELEMENT); + expect(records[0].videoUri).assertEqual('videoUri'); + console.info('UdmfVideoTest end'); + }); + + /** + * @tc.name UdmfSystemDefinedRecordTest + * @tc.desc Test Js Api SystemDefinedRecord testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfSystemDefinedRecordTest', 0, function () { + console.info('UdmfSystemDefinedRecordTest start'); + let systemDefinedRecord = new UDMF.SystemDefinedRecord(); + systemDefinedRecord.details = { + recordKey1: 'systemDefinedRecord' + KEY_TEST_ELEMENT, + recordKey2: 1, + recordKey3: U8_ARRAY, + }; + let unifiedData = new UDMF.UnifiedData(systemDefinedRecord); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.recordKey1).assertEqual('systemDefinedRecord' + KEY_TEST_ELEMENT); + expect(records[0].details.recordKey2).assertEqual(1); + for (let i = 0; i < U8_ARRAY.length; i++) { + expect(records[0].details.recordKey3[i]).assertEqual(U8_ARRAY[i]); + } + console.info('UdmfSystemDefinedRecordTest end'); + }); + + /** + * @tc.name UdmfSystemDefinedPixelMapTest + * @tc.desc Test Js Api SystemDefinedPixelMap testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfSystemDefinedPixelMapTest', 0, function () { + console.info('UdmfSystemDefinedPixelMapTest start'); + let systemDefinedPixelMap = new UDMF.SystemDefinedPixelMap(); + systemDefinedPixelMap.details = { + recordKey1: 'systemDefinedPixelMap' + KEY_TEST_ELEMENT, + recordKey2: 1, + recordKey3: U8_ARRAY, + }; + systemDefinedPixelMap.rawData = U8_ARRAY; + let unifiedData = new UDMF.UnifiedData(systemDefinedPixelMap); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.recordKey1).assertEqual('systemDefinedPixelMap' + KEY_TEST_ELEMENT); + expect(records[0].details.recordKey2).assertEqual(1); + for (let i = 0; i < U8_ARRAY.length; i++) { + expect(records[0].details.recordKey3[i]).assertEqual(U8_ARRAY[i]); + } + for (let i = 0; i < U8_ARRAY.length; i++) { + expect(records[0].rawData[i]).assertEqual(U8_ARRAY[i]); + } + console.info('UdmfSystemDefinedPixelMapTest end'); + }); + + /** + * @tc.name UdmfSystemDefinedFormTest + * @tc.desc Test Js Api SystemDefinedForm testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfSystemDefinedFormTest', 0, function () { + console.info('UdmfSystemDefinedFormTest start'); + let form = new UDMF.SystemDefinedForm(); + form.formId = TEST_ID; + form.formName = 'MyFormName'; + form.bundleName = TEST_BUNDLE_NAME; + form.abilityName = TEST_ABILITY_NAME; + form.module = TEST_MODULE; + form.details = { + formKey1: 1, + formKey2: 'form' + VALUE_TEST_ELEMENT, + formKey3: U8_ARRAY, + }; + let unifiedData = new UDMF.UnifiedData(form); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.formKey1).assertEqual(1); + expect(records[0].details.formKey2).assertEqual('form' + VALUE_TEST_ELEMENT); + for (let i = 0; i < U8_ARRAY.length; i++) { + expect(records[0].details.formKey3[i]).assertEqual(U8_ARRAY[i]); + } + expect(records[0].formId).assertEqual(TEST_ID); + expect(records[0].formName).assertEqual('MyFormName'); + expect(records[0].bundleName).assertEqual(TEST_BUNDLE_NAME); + expect(records[0].abilityName).assertEqual(TEST_ABILITY_NAME); + expect(records[0].module).assertEqual(TEST_MODULE); + console.info('UdmfSystemDefinedFormTest end'); + }); + + /** + * @tc.name UdmfSystemDefinedAppItemTest + * @tc.desc Test Js Api SystemDefinedAppItem testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfSystemDefinedAppItemTest', 0, function () { + console.info('UdmfSystemDefinedAppItemTest start'); + let appItem = new UDMF.SystemDefinedAppItem(); + appItem.appId = 'MyAppId'; + appItem.appName = 'MyAppName'; + appItem.abilityName = TEST_ABILITY_NAME; + appItem.bundleName = TEST_BUNDLE_NAME; + appItem.appIconId = 'MyAppIconId'; + appItem.appLabelId = 'MyAppLabelId'; + appItem.details = { + appItemKey1: 1, + appItemKey2: 'appItem' + VALUE_TEST_ELEMENT, + appItemKey3: U8_ARRAY, + }; + let unifiedData = new UDMF.UnifiedData(appItem); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].details.appItemKey1).assertEqual(1); + expect(records[0].details.appItemKey2).assertEqual('appItem' + VALUE_TEST_ELEMENT); + for (let i = 0; i < U8_ARRAY.length; i++) { + expect(records[0].details.appItemKey3[i]).assertEqual(U8_ARRAY[i]); + } + expect(records[0].appId).assertEqual('MyAppId'); + expect(records[0].appName).assertEqual('MyAppName'); + expect(records[0].abilityName).assertEqual(TEST_ABILITY_NAME); + expect(records[0].bundleName).assertEqual(TEST_BUNDLE_NAME); + expect(records[0].appIconId).assertEqual('MyAppIconId'); + expect(records[0].appLabelId).assertEqual('MyAppLabelId'); + console.info('UdmfSystemDefinedAppItemTest end'); + }); + + /** + * @tc.name UdmfSystemDefinedFormTest + * @tc.desc Test Js Api ApplicationDefinedRecord testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfApplicationDefinedRecord', 0, function () { + console.info('UdmfApplicationDefinedRecord start'); + let applicationDefinedRecord = new UDMF.ApplicationDefinedRecord(); + applicationDefinedRecord.applicationDefinedType = 'applicationDefinedType'; + applicationDefinedRecord.rawData = U8_ARRAY; + let unifiedData = new UDMF.UnifiedData(applicationDefinedRecord); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].applicationDefinedType).assertEqual('applicationDefinedType'); + for (let i = 0; i < U8_ARRAY.length; i++) { + expect(records[0].rawData[i]).assertEqual(U8_ARRAY[i]); + } + console.info('UdmfApplicationDefinedRecord end'); + }); + + /** + * @tc.name UdmfAllRecordsTest + * @tc.desc Test Js AllRecords testcase + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfAllRecordsTest', 0, function () { + console.info('UdmfAllRecordsTest start'); + let text = new UDMF.Text(); + let unifiedDatas = new UDMF.UnifiedData(text); + let plainText = new UDMF.PlainText(); + unifiedDatas.addRecord(plainText); + let link = new UDMF.Hyperlink(); + unifiedDatas.addRecord(link); + let html = new UDMF.HTML(); + unifiedDatas.addRecord(html); + let file = new UDMF.File(); + unifiedDatas.addRecord(file); + let folder = new UDMF.Folder(); + unifiedDatas.addRecord(folder); + let image = new UDMF.Image(); + unifiedDatas.addRecord(image); + let video = new UDMF.Video(); + unifiedDatas.addRecord(video); + let systemDefinedRecord = new UDMF.SystemDefinedRecord(); + unifiedDatas.addRecord(systemDefinedRecord); + let systemDefinedPixelMap = new UDMF.SystemDefinedPixelMap(); + unifiedDatas.addRecord(systemDefinedPixelMap); + let form = new UDMF.SystemDefinedForm(); + unifiedDatas.addRecord(form); + let appItem = new UDMF.SystemDefinedAppItem(); + unifiedDatas.addRecord(appItem); + let applicationDefinedRecord = new UDMF.ApplicationDefinedRecord(); + unifiedDatas.addRecord(applicationDefinedRecord); + let records = unifiedDatas.getRecords(); + expect(records.length).assertEqual(13); + expect(records[0].getType()).assertEqual(UDMF.UnifiedDataType.TEXT); + expect(records[1].getType()).assertEqual(UDMF.UnifiedDataType.PLAIN_TEXT); + expect(records[2].getType()).assertEqual(UDMF.UnifiedDataType.HYPERLINK); + expect(records[3].getType()).assertEqual(UDMF.UnifiedDataType.HTML); + expect(records[4].getType()).assertEqual(UDMF.UnifiedDataType.FILE); + expect(records[5].getType()).assertEqual(UDMF.UnifiedDataType.FOLDER); + expect(records[6].getType()).assertEqual(UDMF.UnifiedDataType.IMAGE); + expect(records[7].getType()).assertEqual(UDMF.UnifiedDataType.VIDEO); + expect(records[8].getType()).assertEqual(UDMF.UnifiedDataType.SYSTEM_DEFINED_RECORD); + expect(records[9].getType()).assertEqual(UDMF.UnifiedDataType.SYSTEM_DEFINED_PIXEL_MAP); + expect(records[10].getType()).assertEqual(UDMF.UnifiedDataType.SYSTEM_DEFINED_FORM); + expect(records[11].getType()).assertEqual(UDMF.UnifiedDataType.SYSTEM_DEFINED_APP_ITEM); + expect(records[12].getType()).assertEqual(UDMF.UnifiedDataType.APPLICATION_DEFINED_RECORD); + console.info('UdmfAllRecordsTest end'); + }); +}); \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/unittest/UdmfPromiseJsTest.js b/udmf/framework/jskitsimpl/unittest/UdmfPromiseJsTest.js new file mode 100644 index 00000000..d53d47e1 --- /dev/null +++ b/udmf/framework/jskitsimpl/unittest/UdmfPromiseJsTest.js @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from 'deccjsunit/index'; +import UDMF from '@ohos.data.UDMF'; + +const TEXT_CONTEXT_01 = 'TextContent01'; +const TEXT_CONTEXT_02 = 'TextContent02'; +const ERROR_PARAMETER = '401'; + +describe('UdmfPromiseJSTest', function () { + + let gPlainText1 = new UDMF.PlainText(); + gPlainText1.textContent = TEXT_CONTEXT_01; + let gPlainText2 = new UDMF.PlainText(); + gPlainText2.textContent = TEXT_CONTEXT_02; + + const optionsValid = { intention: 'DataHub', }; + const optionsInValidIntention = { intention: 'Drag', }; + const optionsInValidKey = { key: 'udmf://drag/com.test.demo/123456789', }; + const optionsInValidAll = { intention: 'DataHub', key: 'udmf://drag/com.test.demo/123456789' }; + const unifiedData01 = new UDMF.UnifiedData(gPlainText1); + const unifiedData02 = new UDMF.UnifiedData(gPlainText2); + const unifiedDataInvalid = new UDMF.UnifiedData(); + + /** + * @tc.name UdmfInsertPromiseInvalidOptionsTest + * @tc.desc Test Js Api insertData with invalid options + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfInsertPromiseInvalidOptionsTest', 0, async function (done) { + const TAG = 'UdmfInsertPromiseInvalidOptionsTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsInValidIntention, unifiedData01).then(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }).catch(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, `get e. code is ${e.code},message is ${e.message} `); + expect(e.code === ERROR_PARAMETER).assertTrue(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfInsertPromiseInvalidDataTest + * @tc.desc Test Js Api insertData with invalid UnifiedData + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfInsertPromiseInvalidDataTest', 0, async function (done) { + const TAG = 'UdmfInsertPromiseInvalidDataTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsValid, unifiedDataInvalid).then(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }).catch((err) => { + console.error(TAG, `get fail. code is ${err.code},message is ${err.message} `); + expect(err.code === ERROR_PARAMETER).assertTrue(); + done(); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfInsertPromiseSucTest + * @tc.desc Test Js Api insertData successful + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfInsertPromiseSucTest', 0, async function (done) { + const TAG = 'UdmfInsertPromiseSucTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsValid, unifiedData01).then((data) => { + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `query start. The options: ${JSON.stringify(options)}`); + UDMF.queryData(options).then((data) => { + console.info(TAG, 'query success.'); + console.info(TAG, `data.length = ${data.length}.`); + expect(data.length).assertEqual(1); + let records = data[0].getRecords(); + console.info(TAG, `records.length = ${records.length}.`); + console.info(TAG, `records[0].getType() = ${records[0].getType()}.`); + console.info(TAG, `records[0].textContent = ${records[0].textContent}.`); + expect(records.length).assertEqual(1); + expect(records[0].getType()).assertEqual(UDMF.UnifiedDataType.PLAIN_TEXT); + expect(records[0].textContent).assertEqual(TEXT_CONTEXT_01); + done(); + }).catch(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfUpdatePromiseInvalidOptionsTest + * @tc.desc Test Js Api updateData with invalid options + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfUpdatePromiseInvalidOptionsTest', 0, async function (done) { + const TAG = 'UdmfUpdatePromiseInvalidOptionsTest:'; + console.info(TAG, 'start'); + try { + UDMF.updateData(optionsInValidKey, unifiedData01).then(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }).catch(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, `get e. code is ${e.code},message is ${e.message} `); + expect(e.code === ERROR_PARAMETER).assertTrue(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfUpdatePromiseInvalidDataTest + * @tc.desc Test Js Api updateData with invalid UnifiedData + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfUpdatePromiseInvalidDataTest', 0, async function (done) { + const TAG = 'UdmfUpdatePromiseInvalidDataTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsValid, unifiedData01).then((data) => { + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `query start. The options: ${JSON.stringify(options)}`); + UDMF.updateData(options, unifiedDataInvalid).then(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }).catch((err) => { + console.error(TAG, `get fail. code is ${err.code},message is ${err.message} `); + expect(err.code === ERROR_PARAMETER).assertTrue(); + done(); + }); + }).catch(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfUpdatePromiseSucTest + * @tc.desc Test Js Api updateData successful + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfUpdatePromiseSucTest', 0, async function (done) { + const TAG = 'UdmfUpdatePromiseSucTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsValid, unifiedData01).then((data) => { + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `query start. The options: ${JSON.stringify(options)}`); + UDMF.updateData(options, unifiedData02).then((data) => { + console.info(TAG, 'update success.'); + UDMF.queryData(options).then((data) => { + console.info(TAG, 'query success.'); + expect(data.length).assertEqual(1); + let records = data[0].getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].getType()).assertEqual(UDMF.UnifiedDataType.PLAIN_TEXT); + expect(records[0].textContent).assertEqual(TEXT_CONTEXT_02); + done(); + }).catch(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.info(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); + + + /** + * @tc.name UdmfQueryPromiseInvalidOptionsTest + * @tc.desc Test Js Api queryData with invalid options + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfQueryPromiseInvalidOptionsTest', 0, async function (done) { + const TAG = 'UdmfQueryPromiseInvalidOptionsTest:'; + console.info(TAG, 'start'); + try { + UDMF.queryData(optionsInValidAll).then(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, `get e. code is ${e.code},message is ${e.message} `); + expect(e.code === ERROR_PARAMETER).assertTrue(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfQueryPromiseSucTest + * @tc.desc Test Js Api queryData successful + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfQueryPromiseSucTest', 0, async function (done) { + const TAG = 'UdmfQueryPromiseSucTest:'; + console.info(TAG, 'start'); + try { + UDMF.deleteData(optionsValid).then(() => { + console.info(TAG, 'delete success.'); + UDMF.queryData(optionsValid).then(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }).catch((err) => { + console.info(TAG, 'query has no data.'); + UDMF.insertData(optionsValid, unifiedData01).then((data) => { + console.info(TAG, `insert success. The key: ${data}`); + UDMF.insertData(optionsValid, unifiedData01).then((data) => { + console.info(TAG, `insert success. The key: ${data}`); + UDMF.queryData(optionsValid).then((data) => { + console.info(TAG, 'query success.'); + expect(data.length).assertEqual(2); + done(); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); + + + /** + * @tc.name UdmfDeletePromiseInvalidOptionsTest + * @tc.desc Test Js Api deleteData with invalid options + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfDeletePromiseInvalidOptionsTest', 0, async function (done) { + const TAG = 'UdmfDeletePromiseInvalidOptionsTest:'; + console.info(TAG, 'start'); + try { + UDMF.deleteData(optionsInValidAll).then(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, `get e. code is ${e.code},message is ${e.message} `); + expect(e.code === ERROR_PARAMETER).assertTrue(); + done(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfDeletePromiseSucTest + * @tc.desc Test Js Api deleteData successful + * @tc.type: FUNC + * @tc.require: issueNumber + */ + it('UdmfDeletePromiseSucTest', 0, async function (done) { + const TAG = 'UdmfDeletePromiseSucTest:'; + console.info(TAG, 'start'); + try { + UDMF.insertData(optionsValid, unifiedData01).then((data) => { + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `query start. The options: ${JSON.stringify(options)}`); + UDMF.queryData(options).then((data) => { + console.info(TAG, 'query success.'); + expect(data.length).assertEqual(1); + UDMF.deleteData(options).then((data) => { + console.info(TAG, 'delete success.'); + expect(data.length).assertEqual(1); + let records = data[0].getRecords(); + expect(records.length).assertEqual(1); + expect(records[0].getType()).assertEqual(UDMF.UnifiedDataType.PLAIN_TEXT); + expect(records[0].textContent).assertEqual(TEXT_CONTEXT_01); + UDMF.queryData(options).then(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }).catch(() => { + console.info(TAG, 'query has no data.'); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + console.info(TAG, 'end'); + }); +}); \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/unittest/config.json b/udmf/framework/jskitsimpl/unittest/config.json new file mode 100644 index 00000000..8330ee44 --- /dev/null +++ b/udmf/framework/jskitsimpl/unittest/config.json @@ -0,0 +1,62 @@ +{ + "app": { + "bundleName": "com.example.myapplication", + "vendor": "example", + "version": { + "code": 1, + "name": "1.0" + }, + "apiVersion": { + "compatible": 4, + "target": 5 + } + }, + "deviceConfig": {}, + "module": { + "package": "com.example.myapplication", + "name": ".MyApplication", + "deviceType": [ + "default", + "tablet", + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry" + }, + "abilities": [ + { + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "name": "com.example.myapplication.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "label": "MyApplication", + "type": "page", + "launchType": "standard" + } + ], + "js": [ + { + "pages": [ + "pages/index/index" + ], + "name": "default", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } +} \ No newline at end of file diff --git a/udmf/framework/service/distributeddata_udmf_ipc_interface_code.h b/udmf/framework/service/distributeddata_udmf_ipc_interface_code.h new file mode 100644 index 00000000..ed14f6db --- /dev/null +++ b/udmf/framework/service/distributeddata_udmf_ipc_interface_code.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DISTRIBUTEDDATA_UDMF_IPC_INTERFACE_CODE_H +#define DISTRIBUTEDDATA_UDMF_IPC_INTERFACE_CODE_H + +/* SAID:1301 FeatureSystem:udmf_service */ +namespace OHOS::UDMF { +enum class UdmfServiceInterfaceCode : uint32_t { + CODE_HEAD = 0, + SET_DATA = CODE_HEAD, + GET_DATA, + GET_BATCH_DATA, + UPDATE_DATA, + DELETE_DATA, + GET_SUMMARY, + ADD_PRIVILEGE, + SYNC, + CODE_BUTT +}; +} // namespace OHOS::UDMF +#endif // DISTRIBUTEDDATA_UDMF_IPC_INTERFACE_CODE_H \ No newline at end of file diff --git a/udmf/framework/service/udmf_service.h b/udmf/framework/service/udmf_service.h new file mode 100644 index 00000000..1c154657 --- /dev/null +++ b/udmf/framework/service/udmf_service.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SERVICE_H +#define UDMF_SERVICE_H + +#include <string> +#include <vector> + +#include "iremote_broker.h" + +#include "error_code.h" +#include "unified_data.h" +#include "unified_meta.h" +#include "unified_types.h" + +namespace OHOS { +namespace UDMF { +/* + * UDMF service interface + */ +class UdmfService { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.UDMF.UdmfService"); + UdmfService() = default; + virtual ~UdmfService() = default; + + virtual int32_t SetData(CustomOption &option, UnifiedData &unifiedData, std::string &key) = 0; + virtual int32_t GetData(const QueryOption &query, UnifiedData &unifiedData) = 0; + virtual int32_t GetBatchData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) = 0; + virtual int32_t UpdateData(const QueryOption &query, UnifiedData &unifiedData) = 0; + virtual int32_t DeleteData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) = 0; + virtual int32_t GetSummary(const QueryOption &query, Summary &summary) = 0; + virtual int32_t AddPrivilege(const QueryOption &query, Privilege &privilege) = 0; + virtual int32_t Sync(const QueryOption &query, const std::vector<std::string> &devices) = 0; + + static constexpr int32_t MAX_DATA_SIZE = 4 * 1024 * 1024; + static constexpr int32_t MAX_RECORD_SIZE = 2 * 1024 * 1024; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_SERVICE_H \ No newline at end of file diff --git a/udmf/framework/service/udmf_service_client.cpp b/udmf/framework/service/udmf_service_client.cpp new file mode 100644 index 00000000..ecaab7ec --- /dev/null +++ b/udmf/framework/service/udmf_service_client.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "udmf_service_client.h" + +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#include "logger.h" + +namespace OHOS { +namespace UDMF { +std::shared_ptr<UdmfServiceClient> UdmfServiceClient::instance_; +std::mutex UdmfServiceClient::mutex_; +sptr<DistributedKv::IKvStoreDataService> UdmfServiceClient::kvDataServiceProxy_; + +UdmfServiceClient::UdmfServiceClient(const sptr<UdmfServiceProxy> &proxy) : udmfProxy_(proxy) +{ + LOG_INFO(UDMF_SERVICE, "construct"); +} + +std::shared_ptr<UdmfServiceClient> UdmfServiceClient::GetInstance() +{ + std::lock_guard<decltype(mutex_)> lockGuard(mutex_); + if (instance_ != nullptr) { + return instance_; + } + sptr<DistributedKv::IKvStoreDataService> ability = GetDistributedKvDataService(); + if (ability == nullptr) { + return nullptr; + } + sptr<IRemoteObject> service = ability->GetFeatureInterface("udmf"); + if (service == nullptr) { + return nullptr; + } + sptr<UdmfServiceProxy> proxy = iface_cast<UdmfServiceProxy>(service); + if (proxy == nullptr) { + return nullptr; + } + instance_ = std::make_shared<UdmfServiceClient>(proxy); + return instance_; +} + +sptr<DistributedKv::IKvStoreDataService> UdmfServiceClient::GetDistributedKvDataService() +{ + if (kvDataServiceProxy_ != nullptr) { + return kvDataServiceProxy_; + } + LOG_INFO(UDMF_SERVICE, "create remote proxy."); + auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (samgr == nullptr) { + LOG_ERROR(UDMF_SERVICE, "get samgr fail."); + return nullptr; + } + + auto remote = samgr->CheckSystemAbility(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID); + kvDataServiceProxy_ = iface_cast<DistributedKv::IKvStoreDataService>(remote); + if (kvDataServiceProxy_ == nullptr) { + LOG_ERROR(UDMF_SERVICE, "initialize proxy failed."); + return nullptr; + } + return kvDataServiceProxy_; +} + +int32_t UdmfServiceClient::SetData(CustomOption &option, UnifiedData &unifiedData, std::string &key) +{ + LOG_INFO(UDMF_SERVICE, "start"); + return udmfProxy_->SetData(option, unifiedData, key); +} + +int32_t UdmfServiceClient::GetData(const QueryOption &query, UnifiedData &unifiedData) +{ + LOG_INFO(UDMF_SERVICE, "start"); + return udmfProxy_->GetData(query, unifiedData); +} + +int32_t UdmfServiceClient::GetBatchData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) +{ + LOG_INFO(UDMF_SERVICE, "start"); + return udmfProxy_->GetBatchData(query, unifiedDataSet); +} + +int32_t UdmfServiceClient::UpdateData(const QueryOption &query, UnifiedData &unifiedData) +{ + LOG_INFO(UDMF_SERVICE, "start"); + return udmfProxy_->UpdateData(query, unifiedData); +} + +int32_t UdmfServiceClient::DeleteData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) +{ + LOG_INFO(UDMF_SERVICE, "start"); + return udmfProxy_->DeleteData(query, unifiedDataSet); +} + +int32_t UdmfServiceClient::GetSummary(const QueryOption &query, Summary &summary) +{ + LOG_INFO(UDMF_SERVICE, "start"); + return udmfProxy_->GetSummary(query, summary); +} + +int32_t UdmfServiceClient::AddPrivilege(const QueryOption &query, Privilege &privilege) +{ + LOG_INFO(UDMF_SERVICE, "start"); + return udmfProxy_->AddPrivilege(query, privilege); +} + +int32_t UdmfServiceClient::Sync(const QueryOption &query, const std::vector<std::string> &devices) +{ + LOG_INFO(UDMF_SERVICE, "start"); + return udmfProxy_->Sync(query, devices); +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/service/udmf_service_client.h b/udmf/framework/service/udmf_service_client.h new file mode 100644 index 00000000..c61740bb --- /dev/null +++ b/udmf/framework/service/udmf_service_client.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SERVICE_CLIENT_H +#define UDMF_SERVICE_CLIENT_H + +#include <mutex> +#include <string> + +#include "ikvstore_data_service.h" +#include "iremote_broker.h" + +#include "udmf_service.h" +#include "udmf_service_proxy.h" + +namespace OHOS { +namespace UDMF { +class UdmfServiceClient final : public UdmfService { +public: + explicit UdmfServiceClient(const sptr<UdmfServiceProxy> &proxy); + ~UdmfServiceClient() override = default; + static std::shared_ptr<UdmfServiceClient> GetInstance(); + + int32_t SetData(CustomOption &option, UnifiedData &unifiedData, std::string &key) override; + int32_t GetData(const QueryOption &query, UnifiedData &unifiedData) override; + int32_t GetBatchData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) override; + int32_t UpdateData(const QueryOption &query, UnifiedData &unifiedData) override; + int32_t DeleteData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) override; + int32_t GetSummary(const QueryOption &query, Summary &summary) override; + int32_t AddPrivilege(const QueryOption &query, Privilege &privilege) override; + int32_t Sync(const QueryOption &query, const std::vector<std::string> &devices) override; + +private: + static std::shared_ptr<UdmfServiceClient> instance_; + static std::mutex mutex_; + static sptr<DistributedKv::IKvStoreDataService> kvDataServiceProxy_; + static sptr<DistributedKv::IKvStoreDataService> GetDistributedKvDataService(); + sptr<UdmfServiceProxy> udmfProxy_; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_SERVICE_CLIENT_H \ No newline at end of file diff --git a/udmf/framework/service/udmf_service_proxy.cpp b/udmf/framework/service/udmf_service_proxy.cpp new file mode 100644 index 00000000..448c5f3c --- /dev/null +++ b/udmf/framework/service/udmf_service_proxy.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "udmf_service_proxy.h" + +#include "ipc_types.h" + +#include "logger.h" +#include "tlv_util.h" +#include "udmf_types_util.h" + +namespace OHOS { +namespace UDMF { +#define IPC_SEND(code, reply, ...) \ + ({ \ + int32_t __status = E_OK; \ + do { \ + MessageParcel request; \ + if (!request.WriteInterfaceToken(GetDescriptor())) { \ + __status = E_WRITE_PARCEL_ERROR; \ + break; \ + } \ + if (!ITypesUtil::Marshal(request, ##__VA_ARGS__)) { \ + __status = E_WRITE_PARCEL_ERROR; \ + break; \ + } \ + MessageOption option; \ + auto result = SendRequest(code, request, reply, option); \ + if (result != 0) { \ + LOG_ERROR(UDMF_SERVICE, "SendRequest failed, result = %{public}d!", result); \ + __status = E_IPC; \ + break; \ + } \ + \ + ITypesUtil::Unmarshal(reply, __status); \ + } while (0); \ + __status; \ + }) + +UdmfServiceProxy::UdmfServiceProxy(const sptr<IRemoteObject> &object) : IRemoteProxy<IUdmfService>(object) +{ +} + +int32_t UdmfServiceProxy::SetData(CustomOption &option, UnifiedData &unifiedData, std::string &key) +{ + LOG_DEBUG(UDMF_SERVICE, "start, tag: %{public}d", option.intention); + if (!UnifiedDataUtils::IsValidIntention(option.intention)) { + LOG_ERROR(UDMF_SERVICE, "Invalid intention"); + return E_INVALID_PARAMETERS; + } + if (unifiedData.IsEmpty()) { + LOG_ERROR(UDMF_SERVICE, "Empty data without any record!"); + return E_INVALID_PARAMETERS; + } + if (unifiedData.GetSize() > UdmfService::MAX_DATA_SIZE) { + LOG_ERROR(UDMF_SERVICE, "Exceeded the limit!"); + return E_INVALID_PARAMETERS; + } + for (const auto &record : unifiedData.GetRecords()) { + if (record == nullptr) { + LOG_ERROR(UDMF_SERVICE, "record is nullptr!"); + return E_INVALID_PARAMETERS; + } + if (record->GetSize() > UdmfService::MAX_RECORD_SIZE) { + LOG_ERROR(UDMF_SERVICE, "Exceeded record limit!"); + return E_INVALID_PARAMETERS; + } + } + MessageParcel reply; + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::SET_DATA, reply, option, unifiedData); + if (status != E_OK) { + LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x!", status); + return status; + } + if (!ITypesUtil::Unmarshal(reply, key)) { + LOG_ERROR(UDMF_SERVICE, "Unmarshal status failed!"); + return E_READ_PARCEL_ERROR; + } + return status; +} + +int32_t UdmfServiceProxy::GetData(const QueryOption &query, UnifiedData &unifiedData) +{ + LOG_DEBUG(UDMF_SERVICE, "start, tag: %{public}s", query.key.c_str()); + UnifiedKey key(query.key); + if (!key.IsValid()) { + LOG_ERROR(UDMF_SERVICE, "invalid key"); + return E_INVALID_PARAMETERS; + } + MessageParcel reply; + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::GET_DATA, reply, query); + if (status != E_OK) { + LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x, key:%{public}s!", status, query.key.c_str()); + return status; + } + if (!ITypesUtil::Unmarshal(reply, unifiedData)) { + LOG_ERROR(UDMF_SERVICE, "Unmarshal UnifiedData failed!"); + return E_READ_PARCEL_ERROR; + } + return status; +} + +int32_t UdmfServiceProxy::GetBatchData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) +{ + LOG_DEBUG(UDMF_SERVICE, "start, tag: intention = %{public}d, key = %{public}s", query.intention, query.key.c_str()); + auto find = UD_INTENTION_MAP.find(query.intention); + std::string intention = find == UD_INTENTION_MAP.end() ? intention : find->second; + if (!UnifiedDataUtils::IsValidOptions(query.key, intention)) { + LOG_ERROR(UDMF_SERVICE, "invalid option"); + return E_INVALID_PARAMETERS; + } + MessageParcel reply; + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::GET_BATCH_DATA, reply, query); + if (status != E_OK) { + LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x, key:%{public}s, intention:%{public}d!", status, + query.key.c_str(), query.intention); + return status; + } + if (!ITypesUtil::Unmarshal(reply, unifiedDataSet)) { + LOG_ERROR(UDMF_SERVICE, "Unmarshal unifiedDataSet failed!"); + return E_READ_PARCEL_ERROR; + } + return status; +} + +int32_t UdmfServiceProxy::UpdateData(const QueryOption &query, UnifiedData &unifiedData) +{ + LOG_DEBUG(UDMF_SERVICE, "start, tag: %{public}s", query.key.c_str()); + UnifiedKey key(query.key); + if (!key.IsValid() || !UnifiedDataUtils::IsPersist(key.intention)) { + LOG_ERROR(UDMF_SERVICE, "invalid key"); + return E_INVALID_PARAMETERS; + } + if (unifiedData.GetSize() > UdmfService::MAX_DATA_SIZE) { + LOG_ERROR(UDMF_SERVICE, "Exceeded the limit!"); + return E_INVALID_PARAMETERS; + } + if (unifiedData.IsEmpty()) { + LOG_ERROR(UDMF_SERVICE, "Empty data without any record!"); + return E_INVALID_PARAMETERS; + } + for (const auto &record : unifiedData.GetRecords()) { + if (record == nullptr) { + LOG_ERROR(UDMF_SERVICE, "record is nullptr!"); + return E_INVALID_PARAMETERS; + } + if (record->GetSize() > UdmfService::MAX_RECORD_SIZE) { + LOG_ERROR(UDMF_SERVICE, "Exceeded record limit!"); + return E_INVALID_PARAMETERS; + } + } + MessageParcel reply; + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::UPDATE_DATA, reply, query, unifiedData); + if (status != E_OK) { + LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x!", status); + return status; + } + return status; +} + +int32_t UdmfServiceProxy::DeleteData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) +{ + LOG_DEBUG(UDMF_SERVICE, "start, tag: intention = %{public}d, key = %{public}s", query.intention, query.key.c_str()); + auto find = UD_INTENTION_MAP.find(query.intention); + std::string intention = find == UD_INTENTION_MAP.end() ? intention : find->second; + if (!UnifiedDataUtils::IsValidOptions(query.key, intention)) { + LOG_ERROR(UDMF_SERVICE, "invalid option"); + return E_INVALID_PARAMETERS; + } + MessageParcel reply; + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::DELETE_DATA, reply, query); + if (status != E_OK) { + LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x,key: %{public}s, intention:%{public}s", status, query.key.c_str(), + UD_INTENTION_MAP.at(query.intention).c_str()); + return status; + } + if (!ITypesUtil::Unmarshal(reply, unifiedDataSet)) { + LOG_ERROR(UDMF_SERVICE, "Unmarshal unifiedDataSet failed!"); + return E_READ_PARCEL_ERROR; + } + LOG_DEBUG(UDMF_SERVICE, "end."); + return status; +} + +int32_t UdmfServiceProxy::GetSummary(const QueryOption &query, Summary &summary) +{ + LOG_DEBUG(UDMF_SERVICE, "start, tag: %{public}s", query.key.c_str()); + UnifiedKey key(query.key); + if (!key.IsValid()) { + LOG_ERROR(UDMF_SERVICE, "invalid key"); + return E_INVALID_PARAMETERS; + } + MessageParcel reply; + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::GET_SUMMARY, reply, query); + if (status != E_OK) { + LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x, key:%{public}s!", status, query.key.c_str()); + return status; + } + if (!ITypesUtil::Unmarshal(reply, summary)) { + LOG_ERROR(UDMF_SERVICE, "Unmarshal summary failed!"); + return E_READ_PARCEL_ERROR; + } + LOG_DEBUG(UDMF_SERVICE, "end."); + return status; +} + +int32_t UdmfServiceProxy::AddPrivilege(const QueryOption &query, Privilege &privilege) +{ + LOG_DEBUG(UDMF_SERVICE, "start, key: %{public}s", query.key.c_str()); + UnifiedKey key(query.key); + if (!key.IsValid()) { + LOG_ERROR(UDMF_SERVICE, "invalid key"); + return E_INVALID_PARAMETERS; + } + MessageParcel reply; + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::ADD_PRIVILEGE, reply, query, privilege); + if (status != E_OK) { + LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x, key:%{public}s", status, query.key.c_str()); + } + LOG_DEBUG(UDMF_SERVICE, "end."); + return status; +} + +int32_t UdmfServiceProxy::Sync(const QueryOption &query, const std::vector<std::string> &devices) +{ + LOG_DEBUG(UDMF_SERVICE, "start, key: %{public}s", query.key.c_str()); + UnifiedKey key(query.key); + if (!key.IsValid()) { + LOG_ERROR(UDMF_SERVICE, "invalid key"); + return E_INVALID_PARAMETERS; + } + MessageParcel reply; + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::SYNC, reply, query, devices); + if (status != E_OK) { + LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x, key:%{public}s", status, query.key.c_str()); + } + LOG_DEBUG(UDMF_SERVICE, "end."); + return status; +} + +int32_t UdmfServiceProxy::SendRequest(UdmfServiceInterfaceCode code, MessageParcel &data, + MessageParcel &reply, MessageOption &option) +{ + sptr<IRemoteObject> remote = Remote(); + if (remote == nullptr) { + return E_IPC; + } + int err = remote->SendRequest(static_cast<uint32_t>(code), data, reply, option); + LOG_DEBUG(UDMF_SERVICE, "err: %{public}d", err); + return err; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/service/udmf_service_proxy.h b/udmf/framework/service/udmf_service_proxy.h new file mode 100644 index 00000000..b1baf721 --- /dev/null +++ b/udmf/framework/service/udmf_service_proxy.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SERVICE_PROXY_H +#define UDMF_SERVICE_PROXY_H + +#include <string> + +#include "iremote_broker.h" +#include "iremote_proxy.h" + +#include "distributeddata_udmf_ipc_interface_code.h" +#include "udmf_service.h" + +namespace OHOS { +namespace UDMF { +class IUdmfService : public UdmfService, public IRemoteBroker { +public: + using UdmfService::UdmfService; +}; + +class UdmfServiceProxy : public IRemoteProxy<IUdmfService> { +public: + explicit UdmfServiceProxy(const sptr<IRemoteObject> &object); + + int32_t SetData(CustomOption &option, UnifiedData &unifiedData, std::string &key) override; + int32_t GetData(const QueryOption &query, UnifiedData &unifiedData) override; + int32_t GetBatchData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) override; + int32_t UpdateData(const QueryOption &query, UnifiedData &unifiedData) override; + int32_t DeleteData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet) override; + int32_t GetSummary(const QueryOption &query, Summary &summary) override; + int32_t AddPrivilege(const QueryOption &query, Privilege &privilege) override; + int32_t Sync(const QueryOption &query, const std::vector<std::string> &devices) override; + +private: + static inline BrokerDelegator<UdmfServiceProxy> delegator_; + int32_t SendRequest(UdmfServiceInterfaceCode code, MessageParcel &data, + MessageParcel &reply, MessageOption &option); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_SERVICE_PROXY_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/BUILD.gn b/udmf/interfaces/innerkits/BUILD.gn new file mode 100644 index 00000000..09e2d256 --- /dev/null +++ b/udmf/interfaces/innerkits/BUILD.gn @@ -0,0 +1,78 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/udmf/udmf.gni") + +config("udmf_client_config") { + include_dirs = [ + "${udmf_interfaces_path}/innerkits/client", + "${udmf_interfaces_path}/innerkits/common", + "${udmf_interfaces_path}/innerkits/data", + + "${udmf_framework_path}/common", + "${udmf_framework_path}/service", + "${kv_store_path}/frameworks/common", + "//third_party/libuv/include", + "//third_party/node/src", + "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", + "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/src", + "${kv_store_path}/interfaces/innerkits/distributeddata/include", + ] +} + +ohos_shared_library("udmf_client") { + sources = [ + "${udmf_framework_path}/common/tlv_util.cpp", + "${udmf_framework_path}/common/udmf_types_util.cpp", + "${udmf_framework_path}/innerkitsimpl/client/udmf_client.cpp", + "${udmf_framework_path}/innerkitsimpl/common/unified_key.cpp", + "${udmf_framework_path}/innerkitsimpl/common/unified_meta.cpp", + "${udmf_framework_path}/innerkitsimpl/data/application_defined_record.cpp", + "${udmf_framework_path}/innerkitsimpl/data/audio.cpp", + "${udmf_framework_path}/innerkitsimpl/data/file.cpp", + "${udmf_framework_path}/innerkitsimpl/data/folder.cpp", + "${udmf_framework_path}/innerkitsimpl/data/html.cpp", + "${udmf_framework_path}/innerkitsimpl/data/image.cpp", + "${udmf_framework_path}/innerkitsimpl/data/link.cpp", + "${udmf_framework_path}/innerkitsimpl/data/plain_text.cpp", + "${udmf_framework_path}/innerkitsimpl/data/system_defined_appitem.cpp", + "${udmf_framework_path}/innerkitsimpl/data/system_defined_form.cpp", + "${udmf_framework_path}/innerkitsimpl/data/system_defined_pixelmap.cpp", + "${udmf_framework_path}/innerkitsimpl/data/system_defined_record.cpp", + "${udmf_framework_path}/innerkitsimpl/data/text.cpp", + "${udmf_framework_path}/innerkitsimpl/data/unified_data.cpp", + "${udmf_framework_path}/innerkitsimpl/data/unified_record.cpp", + "${udmf_framework_path}/innerkitsimpl/data/video.cpp", + "${udmf_framework_path}/service/udmf_service_client.cpp", + "${udmf_framework_path}/service/udmf_service_proxy.cpp", + ] + + public_configs = [ ":udmf_client_config" ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "hilog:libhilog", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "samgr:samgr_proxy", + ] + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "distributeddatamgr" + + part_name = "udmf" +} diff --git a/udmf/interfaces/innerkits/client/udmf_client.h b/udmf/interfaces/innerkits/client/udmf_client.h new file mode 100644 index 00000000..a6eb010e --- /dev/null +++ b/udmf/interfaces/innerkits/client/udmf_client.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_CLIENT_H +#define UDMF_CLIENT_H + +#include <string> +#include <vector> + +#include "unified_data.h" +#include "error_code.h" +#include "unified_meta.h" +#include "unified_types.h" + +namespace OHOS { +namespace UDMF { +class UdmfClient { +public: + static UdmfClient &GetInstance(); + + Status SetData(CustomOption &option, UnifiedData &unifiedData, std::string &key); + Status GetData(const QueryOption &query, UnifiedData &unifiedData); + Status GetBatchData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet); + Status UpdateData(const QueryOption &query, UnifiedData &unifiedData); + Status DeleteData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet); + Status GetSummary(const QueryOption &query, Summary& summary); + Status AddPrivilege(const QueryOption &query, Privilege &privilege); + Status Sync(const QueryOption &query, const std::vector<std::string> &devices); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_CLIENT_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/common/error_code.h b/udmf/interfaces/innerkits/common/error_code.h new file mode 100644 index 00000000..f50a2518 --- /dev/null +++ b/udmf/interfaces/innerkits/common/error_code.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_ERROR_CODE_H +#define UDMF_ERROR_CODE_H + +#include <cstdint> + +#include <errors.h> + +namespace OHOS { +namespace UDMF { +enum UdmfModule { + UDMF_MODULE_SERVICE_ID = 0x07, +}; + +// UDMF error offset, used only in this file. +constexpr ErrCode UDMF_ERR_OFFSET = ErrCodeOffset(SUBSYS_DISTRIBUTEDDATAMNG, UDMF_MODULE_SERVICE_ID); + +enum Status : int32_t { + E_OK = ERR_OK, + E_WRITE_PARCEL_ERROR = UDMF_ERR_OFFSET, + E_READ_PARCEL_ERROR, + E_IPC, + E_ERROR, + E_NO_PERMISSION, + E_INVALID_PARAMETERS, + E_DB_ERROR, + E_UNKNOWN, + E_BUTT, +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_ERROR_CODE_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/common/unified_key.h b/udmf/interfaces/innerkits/common/unified_key.h new file mode 100644 index 00000000..c39ed841 --- /dev/null +++ b/udmf/interfaces/innerkits/common/unified_key.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_UNIFIED_KEY_H +#define UDMF_UNIFIED_KEY_H + +#include <bitset> +#include <string> + +namespace OHOS { +namespace UDMF { +constexpr int MAX_BIT_SIZE = 128; +struct UnifiedKey { + UnifiedKey() = default; + explicit UnifiedKey(std::string key); + UnifiedKey(std::string intention, std::string bundle, std::string groupId); + std::string key; + std::string intention; + std::string bundleName; + std::string groupId; + std::string GetUnifiedKey(); + bool IsValid(); + void PreliminaryWork(); + bool CheckCharacter(std::string data, std::bitset<MAX_BIT_SIZE> rule); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_UNIFIED_KEY_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/common/unified_meta.h b/udmf/interfaces/innerkits/common/unified_meta.h new file mode 100644 index 00000000..8ea052f5 --- /dev/null +++ b/udmf/interfaces/innerkits/common/unified_meta.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UNIFIED_META_H +#define UNIFIED_META_H + +#include <array> +#include <cstdint> +#include <map> +#include <memory> +#include <string> +#include <unordered_map> +#include <variant> +#include <vector> + +#include "string_ex.h" + +namespace OHOS { +namespace UDMF { +enum UDType : int32_t { + TEXT = 0, + PLAIN_TEXT, + STYLED_TEXT, + HYPERLINK, + HTML, + FILE, + FOLDER, + MEDIA, + IMAGE, + VIDEO, + AUDIO, + OFFICE, + EBOOK, + COMPRESSION, + GENERAL, + SYSTEM_DEFINED_FORM, + SYSTEM_DEFINED_RECORD, + SYSTEM_DEFINED_APP_ITEM, + SYSTEM_DEFINED_PIXEL_MAP, + APPLICATION_DEFINED_RECORD, + UD_BUTT +}; + +static const std::unordered_map<int32_t, std::string> UD_TYPE_MAP { + { TEXT, "Text" }, + { PLAIN_TEXT, "Text.PlainText" }, + { STYLED_TEXT, "Text.StyledText" }, + { HYPERLINK, "Text.Hyperlink" }, + { HTML, "Text.HTML" }, + { FILE, "File" }, + { FOLDER, "File.Folder" }, + { MEDIA, "File.Media" }, + { OFFICE, "File.Office" }, + { EBOOK, "File.Ebook" }, + { COMPRESSION, "File.Compression" }, + { GENERAL, "File.General" }, + { IMAGE, "File.Media.Image" }, + { VIDEO, "File.Media.Video" }, + { AUDIO, "File.Media.Audio" }, + { SYSTEM_DEFINED_RECORD, "SystemDefinedType" }, + { SYSTEM_DEFINED_FORM, "SystemDefinedType.Form" }, + { SYSTEM_DEFINED_APP_ITEM, "SystemDefinedType.AppItem" }, + { SYSTEM_DEFINED_PIXEL_MAP, "SystemDefinedType.PixelMap" }, + { APPLICATION_DEFINED_RECORD, "ApplicationDefinedType" }, + { UD_BUTT, "INVALID" } +}; + +static const std::unordered_map<int32_t, std::string> JS_UD_TYPE_NAME_MAP { + { TEXT, "TEXT" }, + { PLAIN_TEXT, "PLAIN_TEXT" }, + { HYPERLINK, "HYPERLINK" }, + { HTML, "HTML" }, + { FILE, "FILE" }, + { IMAGE, "IMAGE" }, + { VIDEO, "VIDEO" }, + { AUDIO, "AUDIO" }, + { FOLDER, "FOLDER" }, + { SYSTEM_DEFINED_RECORD, "SYSTEM_DEFINED_RECORD" }, + { SYSTEM_DEFINED_FORM, "SYSTEM_DEFINED_FORM" }, + { SYSTEM_DEFINED_APP_ITEM, "SYSTEM_DEFINED_APP_ITEM" }, + { SYSTEM_DEFINED_PIXEL_MAP, "SYSTEM_DEFINED_PIXEL_MAP" }, + { APPLICATION_DEFINED_RECORD, "APPLICATION_DEFINED_RECORD" }, +}; + +/* + * UnifiedData variant definitions. + */ +using UDVariant = std::variant<int32_t, int64_t, bool, double, std::string, std::vector<uint8_t>>; +using UDDetails = std::map<std::string, UDVariant>; + +/* + * UnifiedData Intention. + */ +enum Intention : int32_t { + UD_INTENTION_BASE = 0, + UD_INTENTION_DRAG, + UD_INTENTION_DATA_HUB, + UD_INTENTION_BUTT, +}; + +static const std::unordered_map<int32_t, std::string> UD_INTENTION_MAP { + { UD_INTENTION_DRAG, "drag" }, + { UD_INTENTION_DATA_HUB, "DataHub" }, +}; + +static const std::unordered_map<int32_t, std::string> JS_UD_INTENTION_NAME_MAP { + { UD_INTENTION_DATA_HUB, "DATA_HUB" }, +}; + +class UnifiedDataUtils { +public: + static bool IsValidType(int32_t value); + static bool IsValidIntention(int32_t value); + static size_t GetVariantSize(UDVariant &variant); + static size_t GetDetailsSize(UDDetails &details); + static bool IsPersist(const Intention &intention); + static bool IsPersist(const std::string &intention); + static Intention GetIntentionByString(const std::string &intention); + static bool IsValidOptions(const std::string &key, std::string &intention); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UNIFIED_META_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/common/unified_types.h b/udmf/interfaces/innerkits/common/unified_types.h new file mode 100644 index 00000000..10d6faf7 --- /dev/null +++ b/udmf/interfaces/innerkits/common/unified_types.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_UNIFIED_TYPES_H +#define UDMF_UNIFIED_TYPES_H + +#include <map> +#include <string> + +#include "unified_key.h" +#include "unified_meta.h" + +namespace OHOS { +namespace UDMF { +enum DataStatus : int32_t { + WORKING = 0, + HISTORY, + DELETED, + FADE +}; + +struct Summary { + std::map<std::string, int64_t> summary; + int64_t totalSize; +}; + +struct Privilege { + uint32_t tokenId; + std::string readPermission; + std::string writePermission; +}; + +struct Runtime { + UnifiedKey key; + bool isPrivate {}; + std::vector<Privilege> privileges; + // time when the data is created + time_t createTime {}; + // name of the package for creating data + std::string sourcePackage; + // current data status + DataStatus dataStatus { WORKING }; + // current data version + std::int32_t dataVersion {}; + // time when the data is last modified + time_t lastModifiedTime {}; + // time when data is written to the udmf + std::string createPackage; + // device ID of the data source + std::string deviceId; +}; + +/* + * Options for sharing data through UDMF. + */ +struct CustomOption { + Intention intention {}; + uint32_t tokenId {}; +}; + +/* + * Options for querying data from UDMF. + */ +struct QueryOption { + std::string key; + Intention intention {}; + uint32_t tokenId {}; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_UNIFIED_TYPES_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/common/visibility.h b/udmf/interfaces/innerkits/common/visibility.h new file mode 100644 index 00000000..bce9d126 --- /dev/null +++ b/udmf/interfaces/innerkits/common/visibility.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_VISIBILITY_H +#define UDMF_VISIBILITY_H + +#ifndef API_EXPORT +#define API_EXPORT __attribute__((visibility ("default"))) +#endif + +#endif // UDMF_VISIBILITY_H diff --git a/udmf/interfaces/innerkits/data/application_defined_record.h b/udmf/interfaces/innerkits/data/application_defined_record.h new file mode 100644 index 00000000..47bf2000 --- /dev/null +++ b/udmf/interfaces/innerkits/data/application_defined_record.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_APPLICATION_DEFINED_RECORD_H +#define UDMF_APPLICATION_DEFINED_RECORD_H + +#include "unified_record.h" + +namespace OHOS { +namespace UDMF { +class ApplicationDefinedRecord : public UnifiedRecord { +public: + ApplicationDefinedRecord(); + explicit ApplicationDefinedRecord(std::string type); + explicit ApplicationDefinedRecord(std::string type, std::vector<uint8_t> &data); + + int64_t GetSize() override; + + std::string GetApplicationDefinedType() const; + void SetApplicationDefinedType(const std::string &type); + + std::vector<uint8_t> GetRawData() const; + void SetRawData(const std::vector<uint8_t> &rawData); +protected: + std::string applicationDefinedType; + std::vector<uint8_t> rawData_; +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_APPLICATION_DEFINED_RECORD_H diff --git a/udmf/interfaces/innerkits/data/audio.h b/udmf/interfaces/innerkits/data/audio.h new file mode 100644 index 00000000..00adcde0 --- /dev/null +++ b/udmf/interfaces/innerkits/data/audio.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_AUDIO_H +#define UDMF_AUDIO_H + +#include "file.h" + +namespace OHOS { +namespace UDMF { +class Audio : public File { +public: + Audio(); + explicit Audio(const std::string &uri); +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_AUDIO_H diff --git a/udmf/interfaces/innerkits/data/file.h b/udmf/interfaces/innerkits/data/file.h new file mode 100644 index 00000000..aecd0aa6 --- /dev/null +++ b/udmf/interfaces/innerkits/data/file.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_FILE_H +#define UDMF_FILE_H + +#include "unified_record.h" + +namespace OHOS { +namespace UDMF { +class File : public UnifiedRecord { +public: + File(); + explicit File(const std::string &uri); + int64_t GetSize() override; + + std::string GetUri() const; + void SetUri(const std::string &uri); + + std::string GetRemoteUri() const; + void SetRemoteUri(const std::string &uri); + + void SetDetails(UDDetails &variantMap); + UDDetails GetDetails() const; + +protected: + std::string oriUri_; + std::string remoteUri_; + UDDetails details_; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_FILE_H diff --git a/udmf/interfaces/innerkits/data/folder.h b/udmf/interfaces/innerkits/data/folder.h new file mode 100644 index 00000000..4d9c5dde --- /dev/null +++ b/udmf/interfaces/innerkits/data/folder.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_FOLDER_H +#define UDMF_FOLDER_H + +#include "file.h" + +namespace OHOS { +namespace UDMF { +class Folder : public File { +public: + Folder(); + explicit Folder(const std::string &uri); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_FOLDER_H diff --git a/udmf/interfaces/innerkits/data/html.h b/udmf/interfaces/innerkits/data/html.h new file mode 100644 index 00000000..f696d3ce --- /dev/null +++ b/udmf/interfaces/innerkits/data/html.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_HTML_H +#define UDMF_HTML_H + +#include "text.h" + +namespace OHOS { +namespace UDMF { +class Html : public Text { +public: + Html(); + explicit Html(const std::string &htmlContent, const std::string &plainContent); + + int64_t GetSize() override; + + std::string GetHtmlContent() const; + void SetHtmlContent(const std::string &htmlContent); + std::string GetPlainContent() const; + void SetPlainContent(const std::string &htmlContent); + +private: + std::string htmlContent_; + std::string plainContent_; +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_HTML_H diff --git a/udmf/interfaces/innerkits/data/image.h b/udmf/interfaces/innerkits/data/image.h new file mode 100644 index 00000000..0a07e358 --- /dev/null +++ b/udmf/interfaces/innerkits/data/image.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_IMAGE_H +#define UDMF_IMAGE_H + +#include "file.h" + +namespace OHOS { +namespace UDMF { +class Image : public File { +public: + Image(); + explicit Image(const std::string &uri); +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_IMAGE_H diff --git a/udmf/interfaces/innerkits/data/link.h b/udmf/interfaces/innerkits/data/link.h new file mode 100644 index 00000000..b28cb217 --- /dev/null +++ b/udmf/interfaces/innerkits/data/link.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_LINK_H +#define UDMF_LINK_H + +#include "text.h" + +namespace OHOS { +namespace UDMF { +class Link : public Text { +public: + Link(); + explicit Link(const std::string &url); + explicit Link(const std::string &url, const std::string &description); + + int64_t GetSize() override; + + std::string GetUrl() const; + void SetUrl(const std::string &url); + std::string GetDescription() const; + void SetDescription(const std::string &description); + +private: + std::string url_; + std::string description_; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_LINK_H diff --git a/udmf/interfaces/innerkits/data/plain_text.h b/udmf/interfaces/innerkits/data/plain_text.h new file mode 100644 index 00000000..e6cdfaae --- /dev/null +++ b/udmf/interfaces/innerkits/data/plain_text.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_PLAIN_TEXT_H +#define UDMF_PLAIN_TEXT_H + +#include "text.h" + +namespace OHOS { +namespace UDMF { +class PlainText : public Text { +public: + PlainText(); + explicit PlainText(const std::string &content, const std::string &abstract); + + int64_t GetSize() override; + + std::string GetContent() const; + void SetContent(const std::string &content); + std::string GetAbstract() const; + void SetAbstract(const std::string &abstract); + +private: + std::string content_; + std::string abstract_; +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_PLAIN_TEXT_H diff --git a/udmf/interfaces/innerkits/data/system_defined_appitem.h b/udmf/interfaces/innerkits/data/system_defined_appitem.h new file mode 100644 index 00000000..6cdbb384 --- /dev/null +++ b/udmf/interfaces/innerkits/data/system_defined_appitem.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SYSTEM_DEFINED_APPITEM_H +#define UDMF_SYSTEM_DEFINED_APPITEM_H + +#include "system_defined_record.h" + +namespace OHOS { +namespace UDMF { +class SystemDefinedAppItem : public SystemDefinedRecord { +public: + SystemDefinedAppItem(); + + int64_t GetSize() override; + + std::string GetAppId() const; + void SetAppId(const std::string &appId); + std::string GetAppName() const; + void SetAppName(const std::string &appName); + std::string GetAppIconId() const; + void SetAppIconId(const std::string &appIconId); + std::string GetAppLabelId() const; + void SetAppLabelId(const std::string &appLabelId); + std::string GetBundleName() const; + void SetBundleName(const std::string &bundleName); + std::string GetAbilityName() const; + void SetAbilityName(const std::string &abilityName); + +private: + std::string appId_; + std::string appName_; + std::string appIconId_; + std::string appLabelId_; + std::string bundleName_; + std::string abilityName_; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_SYSTEM_DEFINED_APPITEM_H diff --git a/udmf/interfaces/innerkits/data/system_defined_form.h b/udmf/interfaces/innerkits/data/system_defined_form.h new file mode 100644 index 00000000..f6f3059e --- /dev/null +++ b/udmf/interfaces/innerkits/data/system_defined_form.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SYSTEM_DEFINED_FORM_H +#define UDMF_SYSTEM_DEFINED_FORM_H + +#include "system_defined_record.h" + +namespace OHOS { +namespace UDMF { +class SystemDefinedForm : public SystemDefinedRecord { +public: + SystemDefinedForm(); + + int64_t GetSize() override; + + int32_t GetFormId() const; + void SetFormId(const int32_t &formId); + std::string GetFormName() const; + void SetFormName(const std::string &formName); + std::string GetBundleName() const; + void SetBundleName(const std::string &bundleName); + std::string GetAbilityName() const; + void SetAbilityName(const std::string &abilityName); + std::string GetModule() const; + void SetModule(const std::string &module); + +private: + int32_t formId_; + std::string formName_; + std::string bundleName_; + std::string abilityName_; + std::string module_; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_SYSTEM_DEFINED_FORM_H diff --git a/udmf/interfaces/innerkits/data/system_defined_pixelmap.h b/udmf/interfaces/innerkits/data/system_defined_pixelmap.h new file mode 100644 index 00000000..9d3cc755 --- /dev/null +++ b/udmf/interfaces/innerkits/data/system_defined_pixelmap.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SYSTEM_DEFINED_PIXELMAP_H +#define UDMF_SYSTEM_DEFINED_PIXELMAP_H + +#include "system_defined_record.h" + +namespace OHOS { +namespace UDMF { +class SystemDefinedPixelMap : public SystemDefinedRecord { +public: + SystemDefinedPixelMap(); + explicit SystemDefinedPixelMap(std::vector<uint8_t> &data); + + int64_t GetSize() override; + + std::vector<uint8_t> GetRawData() const; + void SetRawData(const std::vector<uint8_t> &rawData); +private: + std::vector<uint8_t> rawData_; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_SYSTEM_DEFINED_PIXELMAP_H diff --git a/udmf/interfaces/innerkits/data/system_defined_record.h b/udmf/interfaces/innerkits/data/system_defined_record.h new file mode 100644 index 00000000..ecf51c28 --- /dev/null +++ b/udmf/interfaces/innerkits/data/system_defined_record.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SYSTEM_DEFINED_RECORD_H +#define UDMF_SYSTEM_DEFINED_RECORD_H + +#include "unified_record.h" + +namespace OHOS { +namespace UDMF { +class SystemDefinedRecord : public UnifiedRecord { +public: + explicit SystemDefinedRecord(); + + int64_t GetSize() override; + + void AddProperty(const std::string &property, UDVariant &value); + UDVariant GetPropertyByName(const std::string &property) const; + void SetDetails(UDDetails &details); + UDDetails GetDetails() const; + +protected: + UDDetails details_; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_SYSTEM_DEFINED_RECORD_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/data/text.h b/udmf/interfaces/innerkits/data/text.h new file mode 100644 index 00000000..82369c78 --- /dev/null +++ b/udmf/interfaces/innerkits/data/text.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_TEXT_H +#define UDMF_TEXT_H + +#include "unified_record.h" + +namespace OHOS { +namespace UDMF { +constexpr int MAX_TEXT_LEN = 20 * 1024 * 1024; +class Text : public UnifiedRecord { +public: + Text(); + explicit Text(UDDetails &variantMap); + + int64_t GetSize() override; + + void SetDetails(UDDetails &variantMap); + UDDetails GetDetails() const; + +protected: + UDDetails details_; +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_TEXT_H diff --git a/udmf/interfaces/innerkits/data/unified_data.h b/udmf/interfaces/innerkits/data/unified_data.h new file mode 100644 index 00000000..2cc052d5 --- /dev/null +++ b/udmf/interfaces/innerkits/data/unified_data.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_UNIFIED_DATA_H +#define UDMF_UNIFIED_DATA_H + +#include "unified_record.h" + +namespace OHOS { +namespace UDMF { +class UnifiedData { +public: + int64_t GetSize(); + + std::string GetGroupId() const; + + std::shared_ptr<Runtime> GetRuntime() const; + void SetRuntime(Runtime &runtime); + + void AddRecord(const std::shared_ptr<UnifiedRecord> &record); + std::shared_ptr<UnifiedRecord> GetRecordAt(std::size_t index); + void SetRecords(std::vector<std::shared_ptr<UnifiedRecord>> records); + std::vector<std::shared_ptr<UnifiedRecord>> GetRecords() const; + + std::vector<UDType> GetUDTypes(); + + bool IsEmpty() const; + +private: + std::shared_ptr<Runtime> runtime_; + std::vector<std::shared_ptr<UnifiedRecord>> records_; +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_UNIFIED_DATA_H diff --git a/udmf/interfaces/innerkits/data/unified_record.h b/udmf/interfaces/innerkits/data/unified_record.h new file mode 100644 index 00000000..ade232ac --- /dev/null +++ b/udmf/interfaces/innerkits/data/unified_record.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_UNIFIED_RECORD_H +#define UDMF_UNIFIED_RECORD_H + +#include <memory> +#include <string> +#include <variant> +#include <vector> + +#include "unified_types.h" + +namespace OHOS { +namespace UDMF { +class UnifiedRecord { +public: + UnifiedRecord(); + explicit UnifiedRecord(UDType type); + virtual ~UnifiedRecord() = default; + + UDType GetType() const; + void SetType(const UDType &type); + virtual int64_t GetSize(); + + std::string GetUid() const; + void SetUid(const std::string &id); + +protected: + UDType dataType_; + +private: + std::string uid_; // unique identifier +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_UNIFIED_RECORD_H diff --git a/udmf/interfaces/innerkits/data/video.h b/udmf/interfaces/innerkits/data/video.h new file mode 100644 index 00000000..ea80bf81 --- /dev/null +++ b/udmf/interfaces/innerkits/data/video.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_VIDEO_H +#define UDMF_VIDEO_H + +#include "file.h" + +namespace OHOS { +namespace UDMF { +class Video : public File { +public: + Video(); + explicit Video(const std::string &uri); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_VIDEO_H diff --git a/udmf/interfaces/jskits/BUILD.gn b/udmf/interfaces/jskits/BUILD.gn new file mode 100644 index 00000000..a139a9dc --- /dev/null +++ b/udmf/interfaces/jskits/BUILD.gn @@ -0,0 +1,134 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/udmf/udmf.gni") + +config("udmf_napi_config") { + include_dirs = [ + "${udmf_interfaces_path}/innerkits/client", + "${udmf_interfaces_path}/innerkits/common", + "${udmf_interfaces_path}/innerkits/data", + "${udmf_interfaces_path}/jskits/common", + "${udmf_interfaces_path}/jskits/data", + + "${udmf_framework_path}/common", + "${udmf_framework_path}/service", + + "//third_party/libuv/include", + "//third_party/node/src", + + "${aafwk_inner_api_path}/ability_manager/include", + "${aafwk_kits_path}/appkit/native/app/include/", + "${aafwk_kits_path}/ability/native/include", + "${aafwk_napi_path}/inner/napi_common", + "${aafwk_service_path}/abilitymgr/include", + "${aafwk_service_path}/common/include", + ] +} + +ohos_shared_library("udmf_napi") { + sources = [ + "${udmf_framework_path}/jskitsimpl/common/napi_data_utils.cpp", + "${udmf_framework_path}/jskitsimpl/common/napi_error_utils.cpp", + "${udmf_framework_path}/jskitsimpl/common/napi_queue.cpp", + "${udmf_framework_path}/jskitsimpl/data/application_defined_record_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/audio_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/file_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/folder_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/html_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/image_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/link_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/plain_text_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/summary_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/system_defined_appitem_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/system_defined_form_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/system_defined_pixelmap_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/system_defined_record_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/text_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/udmf_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/unified_data_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/unified_record_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/video_napi.cpp", + "${udmf_interfaces_path}/jskits/module/udmf_napi_module.cpp", + ] + public_configs = [ ":udmf_napi_config" ] + + deps = [ + "${third_party_path}/bounds_checking_function:libsec_shared", + "../innerkits:udmf_client", + ] + + external_deps = [ + "ability_base:base", + "ability_runtime:ability_manager", + "ability_runtime:abilitykit_native", + "ability_runtime:napi_base_context", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "napi:ace_napi", + ] + + relative_install_dir = "module/data" + subsystem_name = "distributeddatamgr" + part_name = "udmf" +} + +ohos_shared_library("udmf_data_napi") { + sources = [ + "${udmf_framework_path}/jskitsimpl/common/napi_data_utils.cpp", + "${udmf_framework_path}/jskitsimpl/common/napi_error_utils.cpp", + "${udmf_framework_path}/jskitsimpl/common/napi_queue.cpp", + "${udmf_framework_path}/jskitsimpl/data/application_defined_record_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/audio_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/file_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/folder_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/html_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/image_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/link_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/plain_text_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/summary_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/system_defined_appitem_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/system_defined_form_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/system_defined_pixelmap_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/system_defined_record_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/text_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/udmf_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/unified_data_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/unified_record_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/video_napi.cpp", + "${udmf_interfaces_path}/jskits/module/udmf_napi_module.cpp", + ] + public_configs = [ ":udmf_napi_config" ] + + deps = [ + "${third_party_path}/bounds_checking_function:libsec_shared", + "../innerkits:udmf_client", + ] + + external_deps = [ + "ability_base:base", + "ability_runtime:ability_manager", + "ability_runtime:abilitykit_native", + "ability_runtime:napi_base_context", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "napi:ace_napi", + ] + + subsystem_name = "distributeddatamgr" + part_name = "udmf" +} diff --git a/udmf/interfaces/jskits/common/napi_data_utils.h b/udmf/interfaces/jskits/common/napi_data_utils.h new file mode 100644 index 00000000..bc19dd56 --- /dev/null +++ b/udmf/interfaces/jskits/common/napi_data_utils.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_NAPI_DATA_UTILS_H +#define UDMF_NAPI_DATA_UTILS_H + +#include <cstdint> +#include <map> +#include <memory> +#include <string> +#include <variant> +#include <vector> + +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "napi_common_want.h" +#include "securec.h" + +#include "logger.h" +#include "unified_meta.h" + +namespace OHOS { +namespace UDMF { +class NapiDataUtils { +public: + /* napi_value <-> bool */ + static napi_status GetValue(napi_env env, napi_value in, bool &out); + static napi_status SetValue(napi_env env, const bool &in, napi_value &out); + + /* napi_value <-> int32_t */ + static napi_status GetValue(napi_env env, napi_value in, int32_t &out); + static napi_status SetValue(napi_env env, const int32_t &in, napi_value &out); + + /* napi_value <-> int64_t */ + static napi_status GetValue(napi_env env, napi_value in, int64_t &out); + static napi_status SetValue(napi_env env, const int64_t &in, napi_value &out); + + /* napi_value <-> float */ + static napi_status GetValue(napi_env env, napi_value in, float &out); + static napi_status SetValue(napi_env env, const float &in, napi_value &out); + + /* napi_value <-> double */ + static napi_status GetValue(napi_env env, napi_value in, double &out); + static napi_status SetValue(napi_env env, const double &in, napi_value &out); + + /* napi_value <-> std::string */ + static napi_status GetValue(napi_env env, napi_value in, std::string &out); + static napi_status SetValue(napi_env env, const std::string &in, napi_value &out); + + /* napi_value <-> std::vector<std::string> */ + static napi_status GetValue(napi_env env, napi_value in, std::vector<std::string> &out); + static napi_status SetValue(napi_env env, const std::vector<std::string> &in, napi_value &out); + + /* napi_value <-> std::vector<uint8_t> */ + static napi_status GetValue(napi_env env, napi_value in, std::vector<uint8_t> &out); + static napi_status SetValue(napi_env env, const std::vector<uint8_t> &in, napi_value &out); + + /* napi_value <-> std::map<std::string, int32_t> */ + static napi_status GetValue(napi_env env, napi_value in, std::map<std::string, int32_t> &out); + static napi_status SetValue(napi_env env, const std::map<std::string, int32_t> &in, napi_value &out); + + /* napi_value <-> std::map<std::string, int64_t> */ + static napi_status GetValue(napi_env env, napi_value in, std::map<std::string, int64_t> &out); + static napi_status SetValue(napi_env env, const std::map<std::string, int64_t> &in, napi_value &out); + + /* napi_value <-> UDVariant */ + static napi_status GetValue(napi_env env, napi_value in, UDVariant &out); + static napi_status SetValue(napi_env env, const UDVariant &in, napi_value &out); + + /* napi_value <-> UDDetails */ + static napi_status GetValue(napi_env env, napi_value in, UDDetails &out); + static napi_status SetValue(napi_env env, const UDDetails &in, napi_value &out); + + static bool IsTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType); + + static bool IsNull(napi_env env, napi_value value); + /* napi_define_class wrapper */ + static napi_value DefineClass(napi_env env, const std::string &name, const napi_property_descriptor *properties, + size_t count, napi_callback newcb); + +private: + enum { + /* std::map<key, value> to js::tuple<key, value> */ + TUPLE_KEY = 0, + TUPLE_VALUE, + TUPLE_SIZE + }; +}; + +#define LOG_ERROR_RETURN(condition, message, retVal) \ + do { \ + if (!(condition)) { \ + LOG_ERROR(UDMF_KITS_NAPI, "test (" #condition ") failed: " message); \ + return retVal; \ + } \ + } while (0) + +#define LOG_ERROR_RETURN_VOID(condition, message) \ + do { \ + if (!(condition)) { \ + LOG_ERROR(UDMF_KITS_NAPI, "test (" #condition ") failed: " message); \ + return; \ + } \ + } while (0) +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_NAPI_DATA_UTILS_H diff --git a/udmf/interfaces/jskits/common/napi_error_utils.h b/udmf/interfaces/jskits/common/napi_error_utils.h new file mode 100644 index 00000000..51a52640 --- /dev/null +++ b/udmf/interfaces/jskits/common/napi_error_utils.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_ERROR_UTILS_H +#define UDMF_ERROR_UTILS_H + +#include <map> +#include <optional> +#include <string> + +#include "js_native_api.h" +#include "napi/native_common.h" + +#include "error_code.h" +#include "logger.h" + + +namespace OHOS { +namespace UDMF { +struct NapiErrorCode { + int32_t status; + int32_t jsCode; + const char *message; +}; + +const std::optional<NapiErrorCode> GetErrorCode(int32_t errorCode); +Status GenerateNapiError(Status error, int32_t &errCode, std::string &errMessage); +void ThrowNapiError(napi_env env, int32_t errCode, const std::string &errMessage, bool isParamsCheck = true); +napi_value GenerateErrorMsg(napi_env env, NapiErrorCode jsInfo); + +#define ASSERT_ERR(env, assertion, errorcode, message) \ + do { \ + if (!(assertion)) { \ + ThrowNapiError(env, errorcode, message); \ + return nullptr; \ + } \ + } while (0) + +#define ASSERT_ERR_VOID(env, assertion, errorcode, message) \ + do { \ + if (!(assertion)) { \ + ThrowNapiError(env, errorcode, message); \ + return; \ + } \ + } while (0) + +#define ASSERT_BUSINESS_ERR(ctxt, assertion, errorcode, message) \ + do { \ + if (!(assertion)) { \ + (ctxt)->isThrowError = true; \ + ThrowNapiError((ctxt)->env, errorcode, message); \ + return; \ + } \ + } while (0) + +#define ASSERT_PERMISSION_ERR(ctxt, assertion, errorCode, message) \ + do { \ + if (!(assertion)) { \ + (ctxt)->isThrowError = true; \ + ThrowNapiError((ctxt)->env, errorCode, message, false); \ + return; \ + } \ + } while (0) +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_ERROR_UTILS_H diff --git a/udmf/interfaces/jskits/common/napi_queue.h b/udmf/interfaces/jskits/common/napi_queue.h new file mode 100644 index 00000000..093ef7b5 --- /dev/null +++ b/udmf/interfaces/jskits/common/napi_queue.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_NAPI_QUEUE_H +#define UDMF_NAPI_QUEUE_H + +#include <functional> +#include <memory> +#include <string> + +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "napi_error_utils.h" + +namespace OHOS { +namespace UDMF { +using NapiCbInfoParser = std::function<void(size_t argc, napi_value *argv)>; +using NapiAsyncExecute = std::function<void(void)>; +using NapiAsyncComplete = std::function<void(napi_value &)>; +static constexpr size_t ARGC_MAX = 6; +struct ContextBase { + virtual ~ContextBase(); + void GetCbInfo( + napi_env env, napi_callback_info info, NapiCbInfoParser parse = NapiCbInfoParser(), bool sync = false); + + inline void GetCbInfoSync(napi_env env, napi_callback_info info, const NapiCbInfoParser &parse = NapiCbInfoParser()) + { + /* sync = true, means no callback, not AsyncWork. */ + GetCbInfo(env, info, parse, true); + } + + napi_env env = nullptr; + napi_value output = nullptr; + napi_status status = napi_invalid_arg; + std::string error; + int32_t jsCode = 0; + bool isThrowError = false; + + napi_value self = nullptr; + void *native = nullptr; + +private: + napi_deferred deferred = nullptr; + napi_async_work work = nullptr; + napi_ref callbackRef = nullptr; + napi_ref selfRef = nullptr; + + NapiAsyncExecute execute = nullptr; + NapiAsyncComplete complete = nullptr; + std::shared_ptr<ContextBase> hold; /* cross thread data */ + + friend class NapiQueue; +}; + +/* check condition related to argc/argv, return and logging. */ +#define ASSERT_ARGS(ctxt, condition, message) \ + do { \ + if (!(condition)) { \ + (ctxt)->status = napi_invalid_arg; \ + (ctxt)->error = std::string(message); \ + LOG_ERROR(UDMF_KITS_NAPI, "test (" #condition ") failed: " message); \ + return; \ + } \ + } while (0) + +#define ASSERT_STATUS(ctxt, message) \ + do { \ + if ((ctxt)->status != napi_ok) { \ + (ctxt)->error = std::string(message); \ + LOG_ERROR(UDMF_KITS_NAPI, "test (ctxt->status == napi_ok) failed: " message); \ + return; \ + } \ + } while (0) + +/* check condition, return and logging if condition not true. */ +#define ASSERT(condition, message, retVal) \ + do { \ + if (!(condition)) { \ + LOG_ERROR(UDMF_KITS_NAPI, "test (" #condition ") failed: " message); \ + return retVal; \ + } \ + } while (0) + +#define ASSERT_VOID(condition, message) \ + do { \ + if (!(condition)) { \ + LOG_ERROR(UDMF_KITS_NAPI, "test (" #condition ") failed: " message); \ + return; \ + } \ + } while (0) + +#define ASSERT_FALSE(condition, message) \ + do { \ + if (!(condition)) { \ + LOG_ERROR(UDMF_KITS_NAPI, "test (" #condition ") failed: " message); \ + return false; \ + } \ + } while (0) + +#define ASSERT_NULL(condition, message) ASSERT(condition, message, nullptr) + +#define ASSERT_CALL(env, theCall, object) \ + do { \ + if ((theCall) != napi_ok) { \ + delete (object); \ + GET_AND_THROW_LAST_ERROR((env)); \ + return nullptr; \ + } \ + } while (0) + +#define ASSERT_CALL_DELETE(env, theCall, object) \ + do { \ + if ((theCall) != napi_ok) { \ + delete (object); \ + GET_AND_THROW_LAST_ERROR((env)); \ + return; \ + } \ + } while (0) + +#define ASSERT_CALL_VOID(env, theCall) \ + do { \ + if ((theCall) != napi_ok) { \ + GET_AND_THROW_LAST_ERROR((env)); \ + return; \ + } \ + } while (0) + +#define ASSERT_WITH_ERRCODE(ctxt, condition, errcode, message) \ + do { \ + if (!(condition)) { \ + (ctxt)->status = napi_generic_failure; \ + GenerateNapiError(errcode, (ctxt)->jsCode, (ctxt)->error); \ + LOG_ERROR(UDMF_KITS_NAPI, "test (" #condition ") failed: " message); \ + return; \ + } \ + } while (0) + +class NapiQueue { +public: + static napi_value AsyncWork(napi_env env, std::shared_ptr<ContextBase> ctxt, const std::string &name, + NapiAsyncExecute execute = NapiAsyncExecute(), NapiAsyncComplete complete = NapiAsyncComplete()); + +private: + enum { + /* AsyncCallback / Promise output result index */ + RESULT_ERROR = 0, + RESULT_DATA = 1, + RESULT_ALL = 2 + }; + + static void GenerateOutput(ContextBase *ctxt); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_NAPI_QUEUE_H diff --git a/udmf/interfaces/jskits/data/application_defined_record_napi.h b/udmf/interfaces/jskits/data/application_defined_record_napi.h new file mode 100644 index 00000000..ff12f1c2 --- /dev/null +++ b/udmf/interfaces/jskits/data/application_defined_record_napi.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_APPLICATION_DEFINED_RECORD_NAPI_H +#define UDMF_APPLICATION_DEFINED_RECORD_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class ApplicationDefinedRecord; +class ApplicationDefinedRecordNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<ApplicationDefinedRecord> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static ApplicationDefinedRecordNapi *GetApplicationDefinedRecord( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + + static napi_value GetApplicationDefinedType(napi_env env, napi_callback_info info); + static napi_value SetApplicationDefinedType(napi_env env, napi_callback_info info); + static napi_value GetRawData(napi_env env, napi_callback_info info); + static napi_value SetRawData(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_APPLICATION_DEFINED_RECORD_NAPI_H diff --git a/udmf/interfaces/jskits/data/audio_napi.h b/udmf/interfaces/jskits/data/audio_napi.h new file mode 100644 index 00000000..89b0fc69 --- /dev/null +++ b/udmf/interfaces/jskits/data/audio_napi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_AUDIO_NAPI_H +#define UDMF_AUDIO_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class Audio; +class AudioNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<Audio> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static AudioNapi *GetAudio(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + static napi_value GetAudioUri(napi_env env, napi_callback_info info); + static napi_value SetAudioUri(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_AUDIO_NAPI_H diff --git a/udmf/interfaces/jskits/data/file_napi.h b/udmf/interfaces/jskits/data/file_napi.h new file mode 100644 index 00000000..b76eb679 --- /dev/null +++ b/udmf/interfaces/jskits/data/file_napi.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_FILE_NAPI_H +#define UDMF_FILE_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class File; +class FileNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + static napi_value GetDetails(napi_env env, napi_callback_info info); + static napi_value SetDetails(napi_env env, napi_callback_info info); + static napi_value GetUri(napi_env env, napi_callback_info info); + static napi_value SetUri(napi_env env, napi_callback_info info); + std::shared_ptr<File> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static FileNapi *GetFile(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_FILE_NAPI_H diff --git a/udmf/interfaces/jskits/data/folder_napi.h b/udmf/interfaces/jskits/data/folder_napi.h new file mode 100644 index 00000000..39199115 --- /dev/null +++ b/udmf/interfaces/jskits/data/folder_napi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_FOLDER_NAPI_H +#define UDMF_FOLDER_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class Folder; +class FolderNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<Folder> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static FolderNapi *GetFolder(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + static napi_value GetFolderUri(napi_env env, napi_callback_info info); + static napi_value SetFolderUri(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_FOLDER_NAPI_H diff --git a/udmf/interfaces/jskits/data/html_napi.h b/udmf/interfaces/jskits/data/html_napi.h new file mode 100644 index 00000000..8807a26b --- /dev/null +++ b/udmf/interfaces/jskits/data/html_napi.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_HTML_NAPI_H +#define UDMF_HTML_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class Html; +class HtmlNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<Html> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static HtmlNapi *GetHtml(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + + static napi_value GetHtmlContent(napi_env env, napi_callback_info info); + static napi_value SetHtmlContent(napi_env env, napi_callback_info info); + static napi_value GetPlainContent(napi_env env, napi_callback_info info); + static napi_value SetPlainContent(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_HTML_NAPI_H diff --git a/udmf/interfaces/jskits/data/image_napi.h b/udmf/interfaces/jskits/data/image_napi.h new file mode 100644 index 00000000..fb7589ff --- /dev/null +++ b/udmf/interfaces/jskits/data/image_napi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_IMAGE_NAPI_H +#define UDMF_IMAGE_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class Image; +class ImageNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<Image> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static ImageNapi *GetImage(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + static napi_value GetImageUri(napi_env env, napi_callback_info info); + static napi_value SetImageUri(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_IMAGE_NAPI_H diff --git a/udmf/interfaces/jskits/data/link_napi.h b/udmf/interfaces/jskits/data/link_napi.h new file mode 100644 index 00000000..081457d1 --- /dev/null +++ b/udmf/interfaces/jskits/data/link_napi.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_LINK_NAPI_H +#define UDMF_LINK_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class Link; +class LinkNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<Link> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static LinkNapi *GetLink(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + + static napi_value GetUrl(napi_env env, napi_callback_info info); + static napi_value SetUrl(napi_env env, napi_callback_info info); + + static napi_value GetDescription(napi_env env, napi_callback_info info); + static napi_value SetDescription(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_LINK_NAPI_H diff --git a/udmf/interfaces/jskits/data/plain_text_napi.h b/udmf/interfaces/jskits/data/plain_text_napi.h new file mode 100644 index 00000000..67620600 --- /dev/null +++ b/udmf/interfaces/jskits/data/plain_text_napi.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_PLAIN_TEXT_NAPI_H +#define UDMF_PLAIN_TEXT_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class PlainText; +class PlainTextNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<PlainText> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static PlainTextNapi *GetPlainText(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + + static napi_value GetContent(napi_env env, napi_callback_info info); + static napi_value SetContent(napi_env env, napi_callback_info info); + static napi_value GetAbstract(napi_env env, napi_callback_info info); + static napi_value SetAbstract(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_PLAIN_TEXT_NAPI_H \ No newline at end of file diff --git a/udmf/interfaces/jskits/data/summary_napi.h b/udmf/interfaces/jskits/data/summary_napi.h new file mode 100644 index 00000000..069cabf8 --- /dev/null +++ b/udmf/interfaces/jskits/data/summary_napi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SUMMARY_NAPI_H +#define UDMF_SUMMARY_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +struct Summary; +class SummaryNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<Summary> in, napi_value &out); + std::shared_ptr<Summary> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static SummaryNapi *GetDataSummary(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + + static napi_value GetSummary(napi_env env, napi_callback_info info); + static napi_value GetTotal(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_SUMMARY_NAPI_H \ No newline at end of file diff --git a/udmf/interfaces/jskits/data/system_defined_appitem_napi.h b/udmf/interfaces/jskits/data/system_defined_appitem_napi.h new file mode 100644 index 00000000..deef6081 --- /dev/null +++ b/udmf/interfaces/jskits/data/system_defined_appitem_napi.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SYSTEM_DEFINED_APPITEM_NAPI_H +#define UDMF_SYSTEM_DEFINED_APPITEM_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class SystemDefinedAppItem; +class SystemDefinedAppItemNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<SystemDefinedAppItem> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static SystemDefinedAppItemNapi *GetSystemDefinedAppItem( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + + static napi_value GetAppId(napi_env env, napi_callback_info info); + static napi_value SetAppId(napi_env env, napi_callback_info info); + + static napi_value GetAppName(napi_env env, napi_callback_info info); + static napi_value SetAppName(napi_env env, napi_callback_info info); + + static napi_value GetAppIconId(napi_env env, napi_callback_info info); + static napi_value SetAppIconId(napi_env env, napi_callback_info info); + + static napi_value GetAppLabelId(napi_env env, napi_callback_info info); + static napi_value SetAppLabelId(napi_env env, napi_callback_info info); + + static napi_value GetBundleName(napi_env env, napi_callback_info info); + static napi_value SetBundleName(napi_env env, napi_callback_info info); + + static napi_value GetAbilityName(napi_env env, napi_callback_info info); + static napi_value SetAbilityName(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_SYSTEM_DEFINED_APPITEM_NAPI_H diff --git a/udmf/interfaces/jskits/data/system_defined_form_napi.h b/udmf/interfaces/jskits/data/system_defined_form_napi.h new file mode 100644 index 00000000..191ba59a --- /dev/null +++ b/udmf/interfaces/jskits/data/system_defined_form_napi.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SYSTEM_DEFINED_FORM_NAPI_H +#define UDMF_SYSTEM_DEFINED_FORM_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class SystemDefinedForm; +class SystemDefinedFormNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<SystemDefinedForm> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static SystemDefinedFormNapi *GetSystemDefinedForm( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + + static napi_value GetFormId(napi_env env, napi_callback_info info); + static napi_value SetFormId(napi_env env, napi_callback_info info); + + static napi_value GetFormName(napi_env env, napi_callback_info info); + static napi_value SetFormName(napi_env env, napi_callback_info info); + + static napi_value GetBundleName(napi_env env, napi_callback_info info); + static napi_value SetBundleName(napi_env env, napi_callback_info info); + + static napi_value GetAbilityName(napi_env env, napi_callback_info info); + static napi_value SetAbilityName(napi_env env, napi_callback_info info); + + static napi_value GetModule(napi_env env, napi_callback_info info); + static napi_value SetModule(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_SYSTEM_DEFINED_FORM_NAPI_H diff --git a/udmf/interfaces/jskits/data/system_defined_pixelmap_napi.h b/udmf/interfaces/jskits/data/system_defined_pixelmap_napi.h new file mode 100644 index 00000000..eb64b3ba --- /dev/null +++ b/udmf/interfaces/jskits/data/system_defined_pixelmap_napi.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SYSTEM_DEFINED_PIXELMAP_NAPI_H +#define UDMF_SYSTEM_DEFINED_PIXELMAP_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class SystemDefinedPixelMap; +class SystemDefinedPixelMapNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<SystemDefinedPixelMap> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static SystemDefinedPixelMapNapi *GetSystemDefinedPixelMap( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + + static napi_value GetRawData(napi_env env, napi_callback_info info); + static napi_value SetRawData(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_SYSTEM_DEFINED_PIXELMAP_NAPI_H diff --git a/udmf/interfaces/jskits/data/system_defined_record_napi.h b/udmf/interfaces/jskits/data/system_defined_record_napi.h new file mode 100644 index 00000000..8881c49c --- /dev/null +++ b/udmf/interfaces/jskits/data/system_defined_record_napi.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_SYSTEM_DEFINED_RECORD_NAPI_H +#define UDMF_SYSTEM_DEFINED_RECORD_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class SystemDefinedRecord; +class SystemDefinedRecordNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + static napi_value GetDetails(napi_env env, napi_callback_info info); + static napi_value SetDetails(napi_env env, napi_callback_info info); + std::shared_ptr<SystemDefinedRecord> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static SystemDefinedRecordNapi *GetSystemDefinedRecord( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_SYSTEM_DEFINED_RECORD_NAPI_H \ No newline at end of file diff --git a/udmf/interfaces/jskits/data/text_napi.h b/udmf/interfaces/jskits/data/text_napi.h new file mode 100644 index 00000000..110f12d4 --- /dev/null +++ b/udmf/interfaces/jskits/data/text_napi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_TEXT_NAPI_H +#define UDMF_TEXT_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class Text; +class TextNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + static napi_value GetDetails(napi_env env, napi_callback_info info); + static napi_value SetDetails(napi_env env, napi_callback_info info); + std::shared_ptr<Text> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static TextNapi *GetText(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_TEXT_NAPI_H \ No newline at end of file diff --git a/udmf/interfaces/jskits/data/udmf_napi.h b/udmf/interfaces/jskits/data/udmf_napi.h new file mode 100644 index 00000000..775f270c --- /dev/null +++ b/udmf/interfaces/jskits/data/udmf_napi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_NAPI_H +#define UDMF_NAPI_H + +#include <string> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +class UDMFNapi { +public: + static napi_value UDMFInit(napi_env env, napi_value exports); + +private: + static napi_value CreateUnifiedDataType(napi_env env); + static napi_value CreateIntention(napi_env env); + static napi_status SetNamedProperty( + napi_env env, napi_value &obj, const std::string &name, const std::string &value); + static napi_value InsertData(napi_env env, napi_callback_info info); + static napi_value UpdateData(napi_env env, napi_callback_info info); + static napi_value QueryData(napi_env env, napi_callback_info info); + static napi_value DeleteData(napi_env env, napi_callback_info info); + static napi_status GetNamedProperty(napi_env env, napi_value &obj, const std::string &key, std::string &value); +}; +} // namespace UDMF +} // namespace OHOS + +#endif // UDMF_NAPI_H diff --git a/udmf/interfaces/jskits/data/unified_data_napi.h b/udmf/interfaces/jskits/data/unified_data_napi.h new file mode 100644 index 00000000..f9cd9bed --- /dev/null +++ b/udmf/interfaces/jskits/data/unified_data_napi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_UNIFIED_DATA_NAPI_H +#define UDMF_UNIFIED_DATA_NAPI_H + +#include <memory> + +#include "napi/native_api.h" + +namespace OHOS { +namespace UDMF { +class UnifiedData; +class UnifiedRecord; +class UnifiedDataNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedData> in, napi_value &out); + std::shared_ptr<UnifiedData> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static UnifiedDataNapi *GetUnifiedData(napi_env env, napi_callback_info info); + + static napi_value AddRecord(napi_env env, napi_callback_info info); + static napi_value GetRecords(napi_env env, napi_callback_info info); + static void GetRecord(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_UNIFIED_DATA_NAPI_H diff --git a/udmf/interfaces/jskits/data/unified_record_napi.h b/udmf/interfaces/jskits/data/unified_record_napi.h new file mode 100644 index 00000000..c3833df7 --- /dev/null +++ b/udmf/interfaces/jskits/data/unified_record_napi.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_UNIFIED_RECORD_NAPI_H +#define UDMF_UNIFIED_RECORD_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class UnifiedRecordNapi { +public: + static napi_value Constructor(napi_env env); + static napi_value GetType(napi_env env, napi_callback_info info); + std::shared_ptr<UnifiedRecord> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *nativeObject, void *finalize_hint); + static UnifiedRecordNapi *GetUnifiedRecord( + napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_UNIFIED_RECORD_NAPI_H diff --git a/udmf/interfaces/jskits/data/video_napi.h b/udmf/interfaces/jskits/data/video_napi.h new file mode 100644 index 00000000..a848f04d --- /dev/null +++ b/udmf/interfaces/jskits/data/video_napi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UDMF_VIDEO_NAPI_H +#define UDMF_VIDEO_NAPI_H + +#include <memory> + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace UDMF { +struct ContextBase; +class UnifiedRecord; +class Video; +class VideoNapi { +public: + static napi_value Constructor(napi_env env); + static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); + std::shared_ptr<Video> value_; + +private: + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *data, void *hint); + static VideoNapi *GetVideo(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt); + static napi_value GetVideoUri(napi_env env, napi_callback_info info); + static napi_value SetVideoUri(napi_env env, napi_callback_info info); +}; +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_VIDEO_NAPI_H diff --git a/udmf/interfaces/jskits/module/udmf_napi_module.cpp b/udmf/interfaces/jskits/module/udmf_napi_module.cpp new file mode 100644 index 00000000..fdc5c41d --- /dev/null +++ b/udmf/interfaces/jskits/module/udmf_napi_module.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "application_defined_record_napi.h" +#include "audio_napi.h" +#include "file_napi.h" +#include "folder_napi.h" +#include "html_napi.h" +#include "image_napi.h" +#include "link_napi.h" +#include "logger.h" +#include "plain_text_napi.h" +#include "summary_napi.h" +#include "system_defined_appitem_napi.h" +#include "system_defined_form_napi.h" +#include "system_defined_pixelmap_napi.h" +#include "system_defined_record_napi.h" +#include "text_napi.h" +#include "udmf_napi.h" +#include "unified_data_napi.h" +#include "unified_record_napi.h" +#include "video_napi.h" + +using namespace OHOS::UDMF; + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + OHOS::UDMF::UDMFNapi::UDMFInit(env, exports); + + napi_status status = + napi_set_named_property(env, exports, "UnifiedData", OHOS::UDMF::UnifiedDataNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init UnifiedData %{public}d", status); + status = napi_set_named_property(env, exports, "Summary", OHOS::UDMF::SummaryNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init Summary %{public}d", status); + status = napi_set_named_property(env, exports, "UnifiedRecord", OHOS::UDMF::UnifiedRecordNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init UnifiedRecord %{public}d", status); + status = napi_set_named_property(env, exports, "Text", OHOS::UDMF::TextNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init Text %{public}d", status); + status = napi_set_named_property(env, exports, "PlainText", OHOS::UDMF::PlainTextNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init PlainText %{public}d", status); + status = napi_set_named_property(env, exports, "Hyperlink", OHOS::UDMF::LinkNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init Hyperlink %{public}d", status); + status = napi_set_named_property(env, exports, "HTML", OHOS::UDMF::HtmlNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init HTML %{public}d", status); + status = napi_set_named_property(env, exports, "File", OHOS::UDMF::FileNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init File %{public}d", status); + status = napi_set_named_property(env, exports, "Image", OHOS::UDMF::ImageNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init Image %{public}d", status); + status = napi_set_named_property(env, exports, "Video", OHOS::UDMF::VideoNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init Video %{public}d", status); + status = napi_set_named_property(env, exports, "Audio", OHOS::UDMF::AudioNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init Audio %{public}d", status); + status = napi_set_named_property(env, exports, "Folder", OHOS::UDMF::FolderNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init Folder %{public}d", status); + status = napi_set_named_property( + env, exports, "SystemDefinedRecord", OHOS::UDMF::SystemDefinedRecordNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init SystemDefinedRecord %{public}d", status); + status = napi_set_named_property( + env, exports, "SystemDefinedForm", OHOS::UDMF::SystemDefinedFormNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init SDForm %{public}d", status); + status = napi_set_named_property( + env, exports, "SystemDefinedAppItem", OHOS::UDMF::SystemDefinedAppItemNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init SDAppItem %{public}d", status); + status = napi_set_named_property( + env, exports, "SystemDefinedPixelMap", OHOS::UDMF::SystemDefinedPixelMapNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init SDPixelMap %{public}d", status); + status = napi_set_named_property( + env, exports, "ApplicationDefinedRecord", OHOS::UDMF::ApplicationDefinedRecordNapi::Constructor(env)); + LOG_INFO(UDMF_KITS_NAPI, "init ApplicationDefinedRecord %{public}d", status); + return exports; +} +EXTERN_C_END + +static napi_module _module = { .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "data.UDMF", + .nm_priv = ((void *)0), + .reserved = { 0 } }; + +extern "C" __attribute__((constructor)) void RegisterUDMFUnifiedDataModule(void) +{ + napi_module_register(&_module); +} diff --git a/udmf/udmf.gni b/udmf/udmf.gni new file mode 100644 index 00000000..a38869fa --- /dev/null +++ b/udmf/udmf.gni @@ -0,0 +1,44 @@ +# Copyright (c) 2022-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +third_party_path = "//third_party" + +aafwk_path = "//foundation/ability/ability_runtime" + +aafwk_inner_api_path = "${aafwk_path}/interfaces/inner_api" + +aafwk_kits_path = "${aafwk_path}/frameworks/kits" + +aafwk_napi_path = "${aafwk_path}/frameworks/js/napi" + +aafwk_service_path = "${aafwk_path}/services" + +access_kit_path = "//base/security/access_token" + +arkui_path = "//foundation/arkui" + +ddms_path = "//foundation/distributeddatamgr/datamgr_service" + +file_service_path = "//foundation/filemanagement/app_file_service" + +udmf_root_path = "//foundation/distributeddatamgr/udmf" + +udmf_framework_path = "${udmf_root_path}/framework" + +udmf_interfaces_path = "${udmf_root_path}/interfaces" + +udmf_service_path = "${udmf_root_path}/service" + +kv_store_path = "//foundation/distributeddatamgr/kv_store" + +developer_test_path = "//test/testfwk/developer_test" -- Gitee